root/src/isdn/Q931.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. Q931SetL4HeaderSpace
  2. Q931SetL2HeaderSpace
  3. Q931ProcDummy
  4. Q931UmesDummy
  5. Q931UieDummy
  6. Q931PmesDummy
  7. Q931PieDummy
  8. Q931TxDummy
  9. Q931ErrorDummy
  10. Q931Initialize
  11. Q931TimerTick
  12. Q931Rx23
  13. Q931Tx34
  14. Q931Rx43
  15. Q931Tx32Data
  16. Q931SetError
  17. Q931SetDefaultErrorCB
  18. Q931CreateCRV
  19. Q931ReleaseCRV
  20. Q931AllocateCRV
  21. Q931GetCallState
  22. Q931StartTimer
  23. Q931StopTimer
  24. Q931SetState
  25. Q931GetTime
  26. Q931SetGetTimeCB
  27. Q931FindCRV
  28. Q931AddDialect
  29. Q931AddStateEntry
  30. Q931IsEventLegal
  31. q931_error_to_name
  32. Q931Log
  33. Q931SetLogCB
  34. Q931SetLogLevel
  35. Q931TimeoutDummy

   1 /*****************************************************************************
   2 
   3   FileName:      Q931.c
   4 
   5   Contents:      Implementation of Q.931 stack main interface functions. 
   6                                 See q931.h for description. 
   7 
   8   License/Copyright:
   9 
  10   Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
  11   email:janvb@caselaboratories.com  
  12 
  13   Redistribution and use in source and binary forms, with or without 
  14   modification, are permitted provided that the following conditions are 
  15   met:
  16 
  17         * Redistributions of source code must retain the above copyright notice, 
  18           this list of conditions and the following disclaimer.
  19         * Redistributions in binary form must reproduce the above copyright notice, 
  20           this list of conditions and the following disclaimer in the documentation 
  21           and/or other materials provided with the distribution.
  22         * Neither the name of the Case Labs, Ltd nor the names of its contributors 
  23           may be used to endorse or promote products derived from this software 
  24           without specific prior written permission.
  25 
  26   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
  27   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
  28   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
  29   ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
  30   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
  31   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
  32   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
  33   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
  34   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
  35   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
  36   POSSIBILITY OF SUCH DAMAGE.
  37 *****************************************************************************/
  38 
  39 #include "Q921.h"
  40 #include "Q931.h"
  41 #include "national.h"
  42 #include "DMS.h"
  43 #include "5ESS.h"
  44 
  45 
  46 /*****************************************************************************
  47 
  48   Dialect function pointers tables.
  49 
  50   The following function pointer arrays define pack/unpack functions and 
  51   processing furnctions for the different Q.931 based dialects.
  52 
  53   The arrays are initialized with pointers to dummy functions and later
  54   overrided with pointers to actual functions as new dialects are added.
  55 
  56   The initial Q.931 will as an example define 2 dialects as it treats User
  57   and Network mode as separate ISDN dialects.
  58 
  59   The API messages Q931AddProc, Q931AddMes, Q931AddIE are used to initialize
  60   these table entries during system inititialization of a stack.
  61 
  62 *****************************************************************************/
  63 q931proc_func_t *Q931Proc[Q931MAXDLCT][Q931MAXMES];
  64 
  65 q931umes_func_t *Q931Umes[Q931MAXDLCT][Q931MAXMES];
  66 q931pmes_func_t *Q931Pmes[Q931MAXDLCT][Q931MAXMES];
  67 
  68 q931uie_func_t *Q931Uie[Q931MAXDLCT][Q931MAXIE];
  69 q931pie_func_t *Q931Pie[Q931MAXDLCT][Q931MAXIE];
  70 
  71 q931timeout_func_t *Q931Timeout[Q931MAXDLCT][Q931MAXTIMER];
  72 q931timer_t         Q931Timer[Q931MAXDLCT][Q931MAXTIMER];
  73 
  74 void (*Q931CreateDialectCB[Q931MAXDLCT])(L3UCHAR iDialect) = { NULL, NULL };
  75 
  76 Q931State Q931st[Q931MAXSTATE];
  77 
  78 /*****************************************************************************
  79 
  80   Core system tables and variables.
  81 
  82 *****************************************************************************/
  83 
  84 L3INT Q931L4HeaderSpace = {0};  /* header space to be ignoder/inserted */
  85                                 /* at head of each message. */
  86 
  87 L3INT Q931L2HeaderSpace = {4};  /* Q921 header space, sapi, tei etc */
  88 
  89 /*****************************************************************************
  90 
  91   Main interface callback functions. 
  92 
  93 *****************************************************************************/
  94 
  95 Q931ErrorCB_t Q931ErrorProc;                    /* callback for error messages. */
  96 L3ULONG (*Q931GetTimeProc) (void) = NULL;       /* callback for func reading time in ms */
  97 
  98 /*****************************************************************************
  99 
 100   Function:      Q931SetL4HeaderSpace
 101 
 102   Description:  Set the # of bytes to be inserted/ignored at the head of
 103                 each message. Q931 will issue a message with space for header
 104                 and the user will use this to fill in whatever header info
 105                 is required to support the architecture used.
 106 
 107 *****************************************************************************/
 108 void Q931SetL4HeaderSpace(L3INT space)
 109 {
 110         Q931L4HeaderSpace = space;
 111 }
 112 
 113 /*****************************************************************************
 114 
 115   Function:      Q931SetL2HeaderSpace
 116 
 117   Description:  Set the # of bytes to be inserted/ignored at the head of
 118                 each message. Q931 will issue a message with space for header
 119                 and the user will use this to fill in whatever header info
 120                 is required to support the architecture used.
 121 
 122 *****************************************************************************/
 123 void Q931SetL2HeaderSpace(L3INT space)
 124 {
 125         Q931L2HeaderSpace = space;
 126 }
 127 
 128 /*****************************************************************************
 129 
 130   Function:      Q931ProcDummy
 131 
 132   Description:  Dummy function for message processing.
 133 
 134 *****************************************************************************/
 135 L3INT Q931ProcDummy(Q931_TrunkInfo_t *pTrunk, L3UCHAR * b,L3INT c)
 136 {
 137         return Q931E_INTERNAL;
 138 }
 139 
 140 /*****************************************************************************
 141 
 142   Function:      Q931UmesDummy
 143 
 144   Description:  Dummy function for message processing
 145 
 146 *****************************************************************************/
 147 L3INT Q931UmesDummy(Q931_TrunkInfo_t *pTrunk,L3UCHAR *IBuf, Q931mes_Generic *OBuf, L3INT IOff, L3INT Size)
 148 {
 149         return Q931E_UNKNOWN_MESSAGE;
 150 }
 151 
 152 /*****************************************************************************
 153 
 154   Function:      Q931UieDummy
 155 
 156   Description:  Dummy function for message processing
 157 
 158 *****************************************************************************/
 159 L3INT Q931UieDummy(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *pMsg, L3UCHAR * IBuf, L3UCHAR * OBuf, L3INT *IOff, L3INT *OOff)
 160 {
 161         return Q931E_UNKNOWN_IE;
 162 }
 163 
 164 /*****************************************************************************
 165 
 166   Function:      Q931PmesDummy
 167 
 168   Description:  Dummy function for message processing
 169 
 170 *****************************************************************************/
 171 L3INT Q931PmesDummy(Q931_TrunkInfo_t *pTrunk, Q931mes_Generic *IBuf, L3INT ISize, L3UCHAR *OBuf, L3INT *OSize)
 172 {
 173         return Q931E_UNKNOWN_MESSAGE;
 174 }
 175 
 176 /*****************************************************************************
 177 
 178   Function:      Q931PieDummy
 179 
 180   Description:  Dummy function for message processing
 181 
 182 *****************************************************************************/
 183 L3INT Q931PieDummy(Q931_TrunkInfo_t *pTrunk,L3UCHAR *IBuf, L3UCHAR *OBuf, L3INT *Octet)
 184 {
 185         return Q931E_UNKNOWN_IE;
 186 }
 187 
 188 /*****************************************************************************
 189 
 190   Function:      Q931TxDummy
 191 
 192   Description:  Dummy function for message processing
 193 
 194 *****************************************************************************/
 195 L3INT Q931TxDummy(Q931_TrunkInfo_t *pTrunk, L3UCHAR * b, L3INT n)
 196 {
 197         return Q931E_MISSING_CB;
 198 }
 199 
 200 /*****************************************************************************
 201 
 202   Function:      Q931ErrorDummy
 203 
 204   Description:  Dummy function for error processing
 205 
 206 *****************************************************************************/
 207 L3INT Q931ErrorDummy(void *priv, L3INT a, L3INT b, L3INT c)
 208 {
 209         return 0;
 210 }
 211 
 212 /*****************************************************************************
 213 
 214   Function:      Q931Initialize
 215 
 216   Description:  This function Initialize the stack. 
 217   
 218                 Will set up the trunk array, channel
 219                 arrays and initialize Q931 function arrays before it finally
 220                 set up EuroISDN processing with User as dialect 0 and 
 221                 Network as dialect 1.
 222 
 223   Note:          Initialization of other stacks should be inserted after
 224                 the initialization of EuroISDN.
 225 
 226 *****************************************************************************/
 227 void Q931Initialize()
 228 {
 229         L3INT x,y;
 230 
 231         /* Secure the callbacks to default procs */
 232         Q931ErrorProc = Q931ErrorDummy;
 233 
 234         /* The user will only add the message handlers and IE handlers he need,
 235          * so we need to initialize every single entry to a default function
 236          * that will throw an appropriate error if they are ever called.
 237          */
 238         for (x = 0; x < Q931MAXDLCT; x++) {
 239                 for (y = 0; y < Q931MAXMES; y++) {
 240                         Q931Proc[x][y] = Q931ProcDummy;
 241                         Q931Umes[x][y] = Q931UmesDummy;
 242                         Q931Pmes[x][y] = Q931PmesDummy;
 243                 }
 244                 for (y = 0; y < Q931MAXIE; y++) {
 245                         Q931Pie[x][y] = Q931PieDummy;
 246                         Q931Uie[x][y] = Q931UieDummy;
 247                 }
 248                 for (y = 0; y < Q931MAXTIMER; y++) {
 249                         Q931Timeout[x][y] = Q931TimeoutDummy;
 250                         Q931Timer[x][y]   = 0;
 251                 }
 252         }
 253 
 254         if (Q931CreateDialectCB[Q931_Dialect_Q931 + Q931_TE] == NULL)
 255                 Q931AddDialect(Q931_Dialect_Q931 + Q931_TE, Q931CreateTE);
 256 
 257         if (Q931CreateDialectCB[Q931_Dialect_Q931 + Q931_NT] == NULL)
 258                 Q931AddDialect(Q931_Dialect_Q931 + Q931_NT, Q931CreateNT);
 259 
 260         if (Q931CreateDialectCB[Q931_Dialect_National + Q931_TE] == NULL)
 261                 Q931AddDialect(Q931_Dialect_National + Q931_TE, nationalCreateTE);
 262 
 263         if (Q931CreateDialectCB[Q931_Dialect_National + Q931_NT] == NULL)
 264                 Q931AddDialect(Q931_Dialect_National + Q931_NT, nationalCreateNT);
 265 
 266         if (Q931CreateDialectCB[Q931_Dialect_DMS + Q931_TE] == NULL)
 267                 Q931AddDialect(Q931_Dialect_DMS + Q931_TE, DMSCreateTE);
 268 
 269         if (Q931CreateDialectCB[Q931_Dialect_DMS + Q931_NT] == NULL)
 270                 Q931AddDialect(Q931_Dialect_DMS + Q931_NT, DMSCreateNT);
 271 
 272         if (Q931CreateDialectCB[Q931_Dialect_5ESS + Q931_TE] == NULL)
 273                 Q931AddDialect(Q931_Dialect_5ESS + Q931_TE, ATT5ESSCreateTE);
 274 
 275         if (Q931CreateDialectCB[Q931_Dialect_5ESS + Q931_NT] == NULL)
 276                 Q931AddDialect(Q931_Dialect_5ESS + Q931_NT, ATT5ESSCreateNT);
 277 
 278         /* The last step we do is to call the callbacks to create the dialects  */
 279         for (x = 0; x < Q931MAXDLCT; x++) {
 280                 if (Q931CreateDialectCB[x] != NULL) {
 281                         Q931CreateDialectCB[x]((L3UCHAR)x);
 282                 }   
 283         }
 284 }
 285 
 286 /**
 287  * Q931TimerTick
 288  * \brief       Periodically called to update and check for expired timers
 289  * \param       pTrunk  Q.931 trunk
 290  */
 291 void Q931TimerTick(Q931_TrunkInfo_t *pTrunk)
 292 {
 293         struct Q931_Call *call = NULL;
 294         L3ULONG now = 0;
 295         L3INT x;
 296 
 297         /* TODO: Loop through all active calls, check timers and call timout procs
 298          * if timers are expired.
 299          * Implement a function array so each dialect can deal with their own
 300          * timeouts.
 301          */
 302         now = Q931GetTime();
 303 
 304         for (x = 0; x < Q931MAXCALLPERTRUNK; x++) {
 305                 call = &pTrunk->call[x];
 306 
 307                 if (!call->InUse || !call->Timer || !call->TimerID)
 308                         continue;
 309 
 310                 if (call->Timer <= now) {
 311                         /* Stop Timer */
 312                         Q931StopTimer(pTrunk, x, call->TimerID);
 313 
 314                         /* Invoke dialect timeout callback */
 315                         Q931Timeout[pTrunk->Dialect][call->TimerID](pTrunk, x);
 316                 }
 317         }
 318 }
 319 
 320 /*****************************************************************************
 321 
 322   Function:      Q931Rx23
 323 
 324   Description:  Receive message from layer 2 (LAPD). Receiving a message 
 325                                 is always done in 2 steps. First the message must be 
 326                                 interpreted and translated to a static struct. Secondly
 327                                 the message is processed and responded to.
 328 
 329                                 The Q.931 message contains a static header that is 
 330                                 interpreted in this function. The rest is interpreted
 331                                 in a sub function according to mestype.
 332 
 333   Parameters:   pTrunk  [IN]    Ptr to trunk info.
 334                                 buf      [IN]   Ptr to buffer containing message.
 335                                 Size    [IN]    Size of message.
 336 
 337   Return Value: Error Code. 0 = No Error, < 0 :error, > 0 : Warning
 338                                 see q931errors.h for details.
 339 
 340 *****************************************************************************/
 341 L3INT Q931Rx23(Q931_TrunkInfo_t *pTrunk, L3INT ind, L3UCHAR tei, L3UCHAR * buf, L3INT Size)
 342 {
 343         L3UCHAR *Mes = NULL;
 344         L3INT RetCode = Q931E_NO_ERROR;
 345         Q931mes_Generic *m = (Q931mes_Generic *) pTrunk->L3Buf;
 346         L3INT ISize;
 347         L3INT IOff = 0;
 348         L3INT L2HSize = Q931L2HeaderSpace;
 349 
 350         switch (ind) {
 351         case Q921_DL_UNIT_DATA:         /* DL-UNITDATA indication (UI frame, 3 byte header) */
 352                 L2HSize = 3;
 353 
 354         case Q921_DL_DATA:              /* DL-DATA indication (I frame, 4 byte header) */
 355                 /* Reset our decode buffer */
 356                 memset(pTrunk->L3Buf, 0, sizeof(pTrunk->L3Buf));
 357 
 358                 /* L2 Header Offset */
 359                 Mes = &buf[L2HSize];
 360 
 361                 /* Protocol Discriminator */
 362                 m->ProtDisc = Mes[IOff++];
 363 
 364                 /* CRV */
 365                 m->CRVFlag = (Mes[IOff + 1] >> 7) & 0x01;
 366                 m->CRV = Q931Uie_CRV(pTrunk, Mes, m->buf, &IOff, &ISize);
 367 
 368                 /* Message Type */
 369                 m->MesType = Mes[IOff++];
 370 
 371                 /* Store tei */
 372                 m->Tei = tei;
 373 
 374                 /* d'oh a little ugly but this saves us from:
 375                  *      a) doing Q.921 work in the lower levels (extracting the TEI ourselves)
 376                  *      b) adding a tei parameter to _all_ Proc functions
 377                  */
 378                 if (tei) {
 379                         L3INT callIndex = 0;
 380 
 381                         /* Find the call using CRV */
 382                         RetCode = Q931FindCRV(pTrunk, m->CRV, &callIndex);
 383                         if (RetCode == Q931E_NO_ERROR && !pTrunk->call[callIndex].Tei) {
 384                                 pTrunk->call[callIndex].Tei = tei;
 385                         }
 386                 }
 387 
 388                 Q931Log(pTrunk, Q931_LOG_DEBUG, "Received message from Q.921 (ind %d, tei %d, size %d)\nMesType: %d, CRVFlag %d (%s), CRV %d (Dialect: %d)\n", ind, m->Tei, Size,
 389                                                  m->MesType, m->CRVFlag, m->CRVFlag ? "Terminator" : "Originator", m->CRV, pTrunk->Dialect);
 390 
 391                 RetCode = Q931Umes[pTrunk->Dialect][m->MesType](pTrunk, Mes, (Q931mes_Generic *)pTrunk->L3Buf, IOff, Size - L2HSize);
 392                 if (RetCode >= Q931E_NO_ERROR) {
 393                         RetCode = Q931Proc[pTrunk->Dialect][m->MesType](pTrunk, pTrunk->L3Buf, 2);
 394                 }
 395                 break;
 396 
 397         default:
 398                 break;
 399         }
 400 
 401         return RetCode;
 402 }
 403 
 404 /*****************************************************************************
 405 
 406   Function:      Q931Tx34
 407 
 408   Description:  Called from the stack to send a message to layer 4.
 409 
 410   Parameters:   Mes[IN]  Ptr to message buffer.
 411                 Size[IN]        Message size in bytes.
 412 
 413   Return Value: Error Code. 0 = No Error, < 0 :error, > 0 : Warning
 414                 see q931errors.h for details.
 415 
 416 *****************************************************************************/
 417 L3INT Q931Tx34(Q931_TrunkInfo_t *pTrunk, L3UCHAR * Mes, L3INT Size)
 418 {
 419         Q931Log(pTrunk, Q931_LOG_DEBUG, "Sending message to Layer4 (size: %d)\n", Size);
 420 
 421         if (pTrunk->Q931Tx34CBProc) {
 422                 return pTrunk->Q931Tx34CBProc(pTrunk->PrivateData34, Mes, Size);
 423         }
 424         return Q931E_MISSING_CB;        
 425 }
 426 
 427 /*****************************************************************************
 428 
 429   Function:      Q931Rx43
 430 
 431   Description:  Receive message from Layer 4 (application).
 432 
 433   Parameters:   pTrunk[IN]  Trunk #.
 434                 buf[IN]  Message Pointer.
 435                 Size[IN]        Message size in bytes.
 436 
 437   Return Value: Error Code. 0 = No Error, < 0 :error, > 0 : Warning
 438                 see q931errors.h for details.
 439 
 440 *****************************************************************************/
 441 L3INT Q931Rx43(Q931_TrunkInfo_t *pTrunk,L3UCHAR * buf, L3INT Size)
 442 {
 443         Q931mes_Header *ptr = (Q931mes_Header*)&buf[Q931L4HeaderSpace];
 444         L3INT RetCode = Q931E_NO_ERROR;
 445 
 446         Q931Log(pTrunk, Q931_LOG_DEBUG, "Receiving message from Layer4 (size: %d, type: %d)\n", Size, ptr->MesType);
 447 
 448         RetCode = Q931Proc[pTrunk->Dialect][ptr->MesType](pTrunk, buf, 4);
 449 
 450         Q931Log(pTrunk, Q931_LOG_DEBUG, "Q931Rx43 return code: %d\n", RetCode);
 451 
 452         return RetCode;
 453 }
 454 
 455 /*****************************************************************************
 456 
 457   Function:      Q931Tx32
 458 
 459   Description:  Called from the stack to send a message to L2. The input is 
 460                                 always a non-packed message so it will first make a proper
 461                                 call to create a packed message before it transmits that
 462                                 message to layer 2.
 463 
 464   Parameters:   pTrunk[IN]  Trunk #  
 465                                 buf[IN]  Ptr to message buffer.
 466                                 Size[IN]        Message size in bytes.
 467 
 468   Return Value: Error Code. 0 = No Error, < 0 :error, > 0 : Warning
 469                                 see q931errors.h for details.
 470 
 471 *****************************************************************************/
 472 L3INT Q931Tx32Data(Q931_TrunkInfo_t *pTrunk, L3UCHAR bcast, L3UCHAR * Mes, L3INT Size)
 473 {
 474         Q931mes_Generic *ptr = (Q931mes_Generic*)Mes;
 475         L3INT RetCode = Q931E_NO_ERROR;
 476         L3INT iDialect = pTrunk->Dialect;
 477         L3INT Offset = bcast ? (Q931L2HeaderSpace - 1) : Q931L2HeaderSpace;
 478         L3INT OSize;
 479 
 480         Q931Log(pTrunk, Q931_LOG_DEBUG, "Sending message to Q.921 (size: %d)\n", Size);
 481 
 482         memset(pTrunk->L2Buf, 0, sizeof(pTrunk->L2Buf));
 483 
 484         /* Call pack function through table. */
 485         RetCode = Q931Pmes[iDialect][ptr->MesType](pTrunk, (Q931mes_Generic *)Mes, Size, &pTrunk->L2Buf[Offset], &OSize);
 486         if (RetCode >= Q931E_NO_ERROR) {
 487                 L3INT callIndex;
 488                 L3UCHAR tei = 0;
 489 
 490                 if (ptr->CRV) {
 491                         /* Find the call using CRV */
 492                         RetCode = Q931FindCRV(pTrunk, ptr->CRV, &callIndex);
 493                         if (RetCode != Q931E_NO_ERROR)
 494                                 return RetCode;
 495 
 496                         tei = pTrunk->call[callIndex].Tei;
 497                 }
 498 
 499                 if (pTrunk->Q931Tx32CBProc) {
 500                         RetCode = pTrunk->Q931Tx32CBProc(pTrunk->PrivateData32, bcast ? Q921_DL_UNIT_DATA : Q921_DL_DATA, tei, pTrunk->L2Buf, OSize + Offset);
 501                 } else {
 502                         RetCode = Q931E_MISSING_CB;
 503                 }
 504         }
 505 
 506         return RetCode;
 507 }
 508 
 509 
 510 /*****************************************************************************
 511 
 512   Function:      Q931SetError
 513 
 514   Description:  Called from the stack to indicate an error. 
 515 
 516   Parameters:   ErrID      ID of ie or message causing error.
 517                 ErrPar1  Error parameter 1
 518                 ErrPar2  Error parameter 2.
 519 
 520 
 521 *****************************************************************************/
 522 void Q931SetError(Q931_TrunkInfo_t *pTrunk,L3INT ErrID, L3INT ErrPar1, L3INT ErrPar2)
 523 {
 524         if (pTrunk->Q931ErrorCBProc) {
 525                 pTrunk->Q931ErrorCBProc(pTrunk->PrivateData34, ErrID, ErrPar1, ErrPar2);
 526         } else {
 527                 Q931ErrorProc(pTrunk->PrivateData34, ErrID, ErrPar1, ErrPar2);
 528         }
 529 }
 530 
 531 void Q931SetDefaultErrorCB(Q931ErrorCB_t Q931ErrorPar)
 532 {
 533         Q931ErrorProc = Q931ErrorPar;
 534 }
 535 
 536 /*****************************************************************************
 537 
 538   Function:      Q931CreateCRV
 539 
 540   Description:  Create a CRV entry and return it's index. The function will 
 541                 locate a free entry in the call tables allocate it and 
 542                 allocate a unique CRV value attached to it.
 543 
 544   Parameters:   pTrunk    [IN]  Trunk number
 545                 callindex   [OUT]   return call table index.
 546 
 547   Return Value: Error Code. 0 = No Error, < 0 :error, > 0 : Warning
 548                 see q931errors.h for details.
 549 ****************************************************************************/
 550 L3INT Q931CreateCRV(Q931_TrunkInfo_t *pTrunk, L3INT * callIndex)
 551 {
 552         L3INT CRV = Q931GetUniqueCRV(pTrunk);
 553 
 554         return Q931AllocateCRV(pTrunk, CRV, callIndex);
 555 }
 556 
 557 
 558 L3INT Q931ReleaseCRV(Q931_TrunkInfo_t *pTrunk, L3INT CRV)
 559 {
 560         int callIndex;
 561         
 562         if ((Q931FindCRV(pTrunk, CRV, &callIndex)) == Q931E_NO_ERROR) {
 563                 pTrunk->call[callIndex].InUse = 0;
 564                 return Q931E_NO_ERROR;
 565         }
 566 
 567         return Q931E_INVALID_CRV;
 568 }
 569 
 570 /*****************************************************************************
 571 
 572   Function:      Q931AllocateCRV
 573 
 574   Description:  Allocate a call table entry and assigns the given CRV value
 575                 to it.
 576 
 577   Parameters:   pTrunk    [IN]  Trunk number
 578                 iCRV            [IN]    Call Reference Value.
 579                 callindex   [OUT]   return call table index.
 580 
 581   Return Value: Error Code. 0 = No Error, < 0 :error, > 0 : Warning
 582                 see q931errors.h for details.
 583 
 584 *****************************************************************************/
 585 L3INT Q931AllocateCRV(Q931_TrunkInfo_t *pTrunk, L3INT iCRV, L3INT * callIndex)
 586 {
 587         L3INT x;
 588         for (x = 0; x < Q931MAXCALLPERTRUNK; x++) {
 589                 if (!pTrunk->call[x].InUse) {
 590                         pTrunk->call[x].CRV     = iCRV;
 591                         pTrunk->call[x].BChan   = 255;
 592                         pTrunk->call[x].State   = 0;    /* null state - idle */
 593                         pTrunk->call[x].TimerID = 0;    /* no timer running */
 594                         pTrunk->call[x].Timer   = 0;
 595                         pTrunk->call[x].InUse   = 1;    /* mark as used */
 596                         *callIndex = x;
 597                         return Q931E_NO_ERROR;
 598                 }
 599         }
 600         return Q931E_TOMANYCALLS;
 601 }
 602 
 603 /*****************************************************************************
 604 
 605   Function:      Q931GetCallState
 606 
 607   Description:  Look up CRV and return current call state. A non existing
 608                                 CRV is the same as state zero (0).
 609 
 610   Parameters:   pTrunk  [IN]    Trunk number.
 611                                 iCRV    [IN]    CRV
 612 
 613   Return Value: Call State.
 614 
 615 *****************************************************************************/
 616 L3INT Q931GetCallState(Q931_TrunkInfo_t *pTrunk, L3INT iCRV)
 617 {
 618         L3INT x;
 619         for (x = 0; x < Q931MAXCALLPERTRUNK; x++) {
 620                 if (pTrunk->call[x].InUse) {
 621                         if (pTrunk->call[x].CRV == iCRV) {
 622                                 return pTrunk->call[x].State;
 623                         }
 624                 }
 625         }
 626         return 0; /* assume state zero for non existing CRV's */
 627 }
 628 
 629 /**
 630  * Q931StartTimer
 631  * \brief       Start a timer
 632  * \param       pTrunk          Q.931 trunk
 633  * \param       callindex       Index of the call
 634  * \param       iTimerID        ID of timer
 635  * \return      always 0
 636  */
 637 L3INT Q931StartTimer(Q931_TrunkInfo_t *pTrunk, L3INT callIndex, L3USHORT iTimerID)
 638 {
 639 #if 0
 640         L3ULONG duration = Q931Timer[pTrunk->Dialect][iTimerID];
 641 
 642         if (duration) {
 643                 pTrunk->call[callIndex].Timer   = Q931GetTime() + duration;
 644                 pTrunk->call[callIndex].TimerID = iTimerID;
 645         }
 646 #endif
 647         return 0;
 648 }
 649 
 650 /**
 651  * Q931StopTimer
 652  * \brief       Stop a timer
 653  * \param       pTrunk          Q.931 trunk
 654  * \param       callindex       Index of the call
 655  * \param       iTimerID        ID of timer
 656  * \return      always 0
 657  */
 658 L3INT Q931StopTimer(Q931_TrunkInfo_t *pTrunk, L3INT callindex, L3USHORT iTimerID)
 659 {
 660         if (pTrunk->call[callindex].TimerID == iTimerID)
 661                 pTrunk->call[callindex].TimerID = 0;
 662 
 663         return 0;
 664 }
 665 
 666 L3INT Q931SetState(Q931_TrunkInfo_t *pTrunk, L3INT callIndex, L3INT iState)
 667 {
 668         pTrunk->call[callIndex].State = iState;
 669 
 670         return 0;
 671 }
 672 
 673 L3ULONG Q931GetTime()
 674 {
 675         L3ULONG tNow = 0;
 676         static L3ULONG tLast = 0;
 677 
 678         if (Q931GetTimeProc != NULL) {
 679                 tNow = Q931GetTimeProc();
 680                 if (tNow < tLast) {     /* wrapped */
 681                         /* TODO */
 682                 }
 683                 tLast = tNow;
 684         }
 685         return tNow;
 686 }
 687 
 688 void Q931SetGetTimeCB(L3ULONG (*callback)(void))
 689 {
 690         Q931GetTimeProc = callback;
 691 }
 692 
 693 L3INT Q931FindCRV(Q931_TrunkInfo_t *pTrunk, L3INT crv, L3INT *callindex)
 694 {
 695         L3INT x;
 696         for (x = 0; x < Q931MAXCALLPERTRUNK; x++) {
 697                 if (pTrunk->call[x].InUse) {
 698                         if (pTrunk->call[x].CRV == crv) {
 699                                 *callindex = x;
 700                                 return Q931E_NO_ERROR;
 701                         }
 702                 }
 703         }
 704         return Q931E_INVALID_CRV;
 705 }
 706 
 707 
 708 void Q931AddDialect(L3UCHAR i, void (*callback)(L3UCHAR iD ))
 709 {
 710         if (i < Q931MAXDLCT) {
 711                 Q931CreateDialectCB[i] = callback;
 712         }
 713 }
 714 
 715 /*****************************************************************************
 716   Function:      Q931AddStateEntry
 717 
 718   Description:  Find an empty entry in the dialects state table and add this
 719                                 entry.
 720 *****************************************************************************/
 721 void Q931AddStateEntry(L3UCHAR iD, L3INT iState,    L3INT iMes,    L3UCHAR cDir)
 722 {
 723         int x;
 724         for (x = 0; x < Q931MAXSTATE; x++) {
 725                 if (Q931st[x].Message == 0) {
 726                         Q931st[x].State     = iState;
 727                         Q931st[x].Message   = iMes;
 728                         Q931st[x].Direction = cDir;
 729                         /* TODO Sort table and use bsearch */
 730                         return;
 731                 }
 732         }
 733 }
 734 
 735 /*****************************************************************************
 736   Function:      Q931IsEventLegal
 737 
 738   Description:  Check state table for matching criteria to indicate if this
 739                                 Message is legal in this state or not.
 740 
 741   Note:          Someone write a bsearch or invent something smart here
 742                                 please - sequential is ok for now.
 743 *****************************************************************************/
 744 L3BOOL Q931IsEventLegal(L3UCHAR iD, L3INT iState, L3INT iMes, L3UCHAR cDir)
 745 {
 746         int x;
 747         /* TODO Sort table and use bsearch */
 748         for (x = 0; x < Q931MAXSTATE; x++) {
 749                 if (Q931st[x].State == iState && Q931st[x].Message == iMes &&
 750                     Q931st[x].Direction == cDir) {
 751                         return L3TRUE;
 752                 }
 753         }
 754         return L3FALSE;
 755 }
 756 
 757 /*****************************************************************************
 758   Function:      q931_error_to_name()
 759 
 760   Description:  Check state table for matching criteria to indicate if this
 761                                 Message is legal in this state or not.
 762 
 763   Note:          Someone write a bsearch or invent something smart here
 764                                 please - sequential is ok for now.
 765 *****************************************************************************/
 766 static const char *q931_error_names[] = {
 767         "Q931E_NO_ERROR",                       /* 0 */
 768 
 769         "Q931E_UNKNOWN_MESSAGE",                /* -3001 */
 770         "Q931E_ILLEGAL_IE",                     /* -3002 */
 771         "Q931E_UNKNOWN_IE",                     /* -3003 */
 772         "Q931E_BEARERCAP",                      /* -3004 */
 773         "Q931E_HLCOMP",                         /* -3005 */
 774         "Q931E_LLCOMP",                         /* -3006 */
 775         "Q931E_INTERNAL",                       /* -3007 */
 776         "Q931E_MISSING_CB",                     /* -3008 */
 777         "Q931E_UNEXPECTED_MESSAGE",             /* -3009 */
 778         "Q931E_ILLEGAL_MESSAGE",                /* -3010 */
 779         "Q931E_TOMANYCALLS",                    /* -3011 */
 780         "Q931E_INVALID_CRV",                    /* -3012 */
 781         "Q931E_CALLID",                         /* -3013 */
 782         "Q931E_CALLSTATE",                      /* -3014 */
 783         "Q931E_CALLEDSUB",                      /* -3015 */
 784         "Q931E_CALLEDNUM",                      /* -3016 */
 785         "Q931E_CALLINGNUM",                     /* -3017 */
 786         "Q931E_CALLINGSUB",                     /* -3018 */
 787         "Q931E_CAUSE",                          /* -3019 */
 788         "Q931E_CHANID",                         /* -3020 */
 789         "Q931E_DATETIME",                       /* -3021 */
 790         "Q931E_DISPLAY",                        /* -3022 */
 791         "Q931E_KEYPADFAC",                      /* -3023 */
 792         "Q931E_NETFAC",                         /* -3024 */
 793         "Q931E_NOTIFIND",                       /* -3025 */
 794         "Q931E_PROGIND",                        /* -3026 */
 795         "Q931E_RESTARTIND",                     /* -3027 */
 796         "Q931E_SEGMENT",                        /* -3028 */
 797         "Q931E_SIGNAL",                         /* -3029 */
 798         "Q931E_GENERIC_DIGITS"                  /* -3030 */
 799 
 800 };
 801 
 802 #define Q931_MAX_ERROR 30
 803 
 804 const char *q931_error_to_name(q931_error_t error)
 805 {
 806         int index = 0;
 807         if ((int)error < 0) {
 808                 index = (((int)error * -1) -3000);
 809         }
 810         if (index < 0 || index > Q931_MAX_ERROR) {
 811                 return "";
 812         }
 813         return q931_error_names[index];
 814 }
 815 /*
 816  * Logging
 817  */
 818 #include <stdarg.h>
 819 
 820 L3INT Q931Log(Q931_TrunkInfo_t *trunk, Q931LogLevel_t level, const char *fmt, ...)
 821 {
 822         char buf[Q931_LOGBUFSIZE];
 823         L3INT len;
 824         va_list ap;
 825 
 826         if (!trunk->Q931LogCBProc)
 827                 return 0;
 828 
 829         if (trunk->loglevel < level)
 830                 return 0;
 831 
 832         va_start(ap, fmt);
 833 
 834         len = vsnprintf(buf, sizeof(buf)-1, fmt, ap);
 835         if (len <= 0) {
 836                 /* TODO: error handling */
 837                 return -1;
 838         }
 839         if (len >= sizeof(buf))
 840                 len = sizeof(buf) - 1;
 841 
 842         buf[len] = '\0';
 843 
 844         va_end(ap);
 845 
 846         return trunk->Q931LogCBProc(trunk->PrivateDataLog, level, buf, len);
 847 }
 848 
 849 /**
 850  * Q921SetLogCB
 851  * \brief       Set Logging callback function and private data
 852  */
 853 void Q931SetLogCB(Q931_TrunkInfo_t *trunk, Q931LogCB_t func, void *priv)
 854 {
 855         trunk->Q931LogCBProc  = func;
 856         trunk->PrivateDataLog = priv;
 857 }
 858 
 859 /**
 860  * Q921SetLogLevel
 861  * \brief       Set Loglevel
 862  */
 863 void Q931SetLogLevel(Q931_TrunkInfo_t *trunk, Q931LogLevel_t level)
 864 {
 865     if(!trunk)
 866         return;
 867 
 868     if (level < Q931_LOG_NONE) {
 869         level = Q931_LOG_NONE;
 870     } else if (level > Q931_LOG_DEBUG) {
 871         level = Q931_LOG_DEBUG;
 872     }
 873 
 874         trunk->loglevel = level;
 875 }
 876 
 877 /**
 878  * Q931TimeoutDummy
 879  * \brief       Dummy handler for timeouts
 880  * \param       pTrunk          Q.931 trunk
 881  * \param       callIndex       Index of call
 882  */
 883 L3INT Q931TimeoutDummy(Q931_TrunkInfo_t *pTrunk, L3INT callIndex)
 884 {
 885         Q931Log(pTrunk, Q931_LOG_DEBUG, "Timer %d of call %d (CRV: %d) timed out\n", pTrunk->call[callIndex].TimerID, callIndex, pTrunk->call[callIndex].CRV);
 886 
 887         return 0;
 888 }

/* [<][>][^][v][top][bottom][index][help] */