root/src/isdn/Q921.c

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

DEFINITIONS

This source file includes following definitions.
  1. Q921State2Name
  2. Q921SendEnquiry
  3. Q921SendEnquiryResponse
  4. Q921ResetExceptionConditions
  5. Q921EstablishDataLink
  6. Q921NrErrorRecovery
  7. Q921InvokeRetransmission
  8. Q921AcknowledgePending
  9. Q921_InitTrunk
  10. Q921Tx21Proc
  11. Q921Tx23Proc
  12. Q921Log
  13. print_hex
  14. Q921LogMesg
  15. Q921GetTime
  16. Q921T200TimerStart
  17. Q921T200TimerStop
  18. Q921T200TimerReset
  19. Q921T203TimerStart
  20. Q921T203TimerStop
  21. Q921T203TimerReset
  22. Q921T202TimerStart
  23. Q921T202TimerStop
  24. Q921T202TimerReset
  25. Q921T201TimerStart
  26. Q921T201TimerStop
  27. Q921T201TimerReset
  28. Q921TM01TimerStart
  29. Q921TM01TimerStop
  30. Q921TM01TimerReset
  31. Q921T200TimerExpire
  32. Q921T203TimerExpire
  33. Q921T202TimerExpire
  34. Q921T201TimerExpire
  35. Q921TM01TimerExpire
  36. Q921TimerTick
  37. Q921SetGetTimeCB
  38. Q921QueueHDLCFrame
  39. Q921EnqueueI
  40. Q921SendQueuedIFrame
  41. Q921SendS
  42. Q921SendU
  43. Q921Rx32
  44. Q921SendRR
  45. Q921SendRNR
  46. Q921SendREJ
  47. Q921SendSABME
  48. Q921Start
  49. Q921Stop
  50. Q921SendDM
  51. Q921SendDISC
  52. Q921SendUA
  53. Q921SendUN
  54. Q921ProcSABME
  55. Q921ProcDM
  56. Q921ProcUA
  57. Q921ProcDISC
  58. Q921ProcRR
  59. Q921ProcREJ
  60. Q921ProcRNR
  61. Q921SetReceiverBusy
  62. Q921ClearReceiverBusy
  63. Q921ProcIFrame
  64. Q921ProcSFrame
  65. Q921ProcUFrame
  66. Q921Rx12
  67. Q921SetLogCB
  68. Q921SetLogLevel
  69. Q921ChangeState
  70. Q921TeiSend
  71. Q921TeiSendAssignRequest
  72. Q921TeiProcAssignResponse
  73. Q921TeiSendVerifyRequest
  74. Q921TeiProcCheckRequest
  75. Q921TeiProcRemoveRequest
  76. Q921TeiProcAssignRequest
  77. Q921TeiSendCheckRequest
  78. Q921TeiProcCheckResponse
  79. Q921TeiProcVerifyRequest
  80. Q921TeiSendDenyResponse
  81. Q921TeiSendAssignedResponse
  82. Q921TeiSendRemoveRequest

   1 /*****************************************************************************
   2 
   3   FileName:     q921.c
   4 
   5   Description:  Contains the implementation of a Q.921 protocol
   6 
   7   Created:      27.dec.2000/JVB
   8 
   9   License/Copyright:
  10 
  11   Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
  12   email:janvb@caselaboratories.com  
  13 
  14   Redistribution and use in source and binary forms, with or without 
  15   modification, are permitted provided that the following conditions are 
  16   met:
  17 
  18     * Redistributions of source code must retain the above copyright notice, 
  19           this list of conditions and the following disclaimer.
  20     * Redistributions in binary form must reproduce the above copyright notice, 
  21           this list of conditions and the following disclaimer in the documentation 
  22           and/or other materials provided with the distribution.
  23     * Neither the name of the Case Labs, Ltd nor the names of its contributors 
  24           may be used to endorse or promote products derived from this software 
  25           without specific prior written permission.
  26 
  27   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
  28   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
  29   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
  30   ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
  31   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
  32   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
  33   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
  34   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
  35   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
  36   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
  37   POSSIBILITY OF SUCH DAMAGE.
  38 
  39 *****************************************************************************/
  40 
  41 /****************************************************************************
  42  * Changes:
  43  *
  44  * - June-August 2008: Stefan Knoblich <s.knoblich@axsentis.de>:
  45  *     Add PTMP TEI management (NT + TE mode)
  46  *     Add timers
  47  *     Add retransmit counters
  48  *     Add logging
  49  *     Various cleanups
  50  *     Queues, retransmission of I frames
  51  *     PTMP NT mode
  52  *
  53  *
  54  * TODO:
  55  *
  56  * - Cleanup queueing, test retransmission
  57  *
  58  * - Q921Start() /-Stop() TEI acquire + release
  59  *   (move everything related into these functions)
  60  *
  61  * - Q.921 '97 Appendix I (and maybe III, IV)
  62  *
  63  * - More complete Appendix II
  64  *
  65  * - Test PTP mode
  66  *
  67  * - PTMP NT mode (in progress)
  68  *
  69  * - NT mode TEI management: (ab)use T202 for TEI Check Request retransmission
  70  *
  71  * - General cleanup (move all non-public declarations into private header file)
  72  *
  73  * - Statistics, per-Frame type debug message filter
  74  *
  75  ****************************************************************************/
  76 
  77 #include <stdlib.h>
  78 #include <stdio.h>
  79 #include <string.h>
  80 #include <stdarg.h>
  81 
  82 #include "freetdm.h"
  83 #include "Q921.h"
  84 #include "Q921priv.h"
  85 #include "mfifo.h"
  86 
  87 #ifdef WIN32
  88 #pragma warning(disable:4100 4244)
  89 #endif
  90 
  91 /******************************************************************************************************
  92  * Actual code below this line
  93  ******************************************************************************************************/
  94 
  95 
  96 /**
  97  * Q921StateNames
  98  * \brief       Static array of state name / value mappings
  99  */
 100 static struct Q921StateName {
 101         Q921State_t value;
 102         const char *name;
 103 } Q921StateNames[10] = {
 104         { Q921_STATE_STOPPED, "Stopped" },
 105         { Q921_STATE_TEI_UNASSIGNED, "TEI Unassigned" },
 106         { Q921_STATE_TEI_AWAITING, "TEI Awaiting Assignment" },
 107         { Q921_STATE_TEI_ESTABLISH, "TEI Awaiting Establishment" },
 108         { Q921_STATE_TEI_ASSIGNED, "TEI Assigned" },
 109         { Q921_STATE_AWAITING_ESTABLISHMENT, "Awaiting Establishment" },
 110         { Q921_STATE_AWAITING_RELEASE, "Awaiting Release" },
 111         { Q921_STATE_MULTIPLE_FRAME_ESTABLISHED, "Multiple Frame Mode Established" },
 112         { Q921_STATE_TIMER_RECOVERY, "Timer Recovery" },
 113         { 0, 0 }
 114 };
 115 
 116 /**
 117  * Q921State2Name
 118  * \brief       Convert state value to name
 119  * \param[in]   state   the state value
 120  * \return      the state name or "Unknown"
 121  *
 122  * \author      Stefan Knoblich
 123  */
 124 static const char *Q921State2Name(Q921State_t state)
 125 {
 126         struct Q921StateName *p = Q921StateNames;
 127 
 128         while(p->name) {
 129                 if(p->value == state)
 130                         return p->name;
 131                 p++;
 132         }
 133 
 134         return "Unknown";
 135 }
 136 
 137 
 138 /**
 139  * Q921SendEnquiry
 140  */
 141 static int Q921SendEnquiry(L2TRUNK trunk, L2UCHAR tei)
 142 {
 143         struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
 144 
 145         /* send enquiry: begin */
 146         if(Q921_CHECK_FLAG(link, Q921_FLAG_RECV_BUSY)) {
 147 
 148                 Q921SendRNR(trunk, trunk->sapi, Q921_COMMAND(trunk), tei, 1);
 149         }
 150         else {
 151                 Q921SendRR(trunk, trunk->sapi, Q921_COMMAND(trunk), tei, 1);
 152         }
 153 
 154         /* clear acknowledge pending */
 155         Q921_CLEAR_FLAG(link, Q921_FLAG_ACK_PENDING);
 156 
 157         /* "Start" T200 */
 158         Q921T200TimerReset(trunk, tei);
 159 
 160         /* send enquiry: end */
 161         return 1;
 162 }
 163 
 164 /**
 165  * Q921SendEnquiryResponse
 166  */
 167 static int Q921SendEnquiryResponse(L2TRUNK trunk, L2UCHAR tei)
 168 {
 169         struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
 170 
 171         /* send enquiry: begin */
 172         if(Q921_CHECK_FLAG(link, Q921_FLAG_RECV_BUSY)) {
 173 
 174                 Q921SendRNR(trunk, trunk->sapi, Q921_RESPONSE(trunk), tei, 1);
 175         }
 176         else {
 177                 Q921SendRR(trunk, trunk->sapi, Q921_RESPONSE(trunk), tei, 1);
 178 
 179                 /* clear acknowledge pending */
 180                 Q921_CLEAR_FLAG(link, Q921_FLAG_ACK_PENDING);
 181         }
 182         /* send enquiry: end */
 183         return 1;
 184 }
 185 
 186 /**
 187  * Q921ResetExceptionConditions
 188  * \brief       Reset Q.921 Exception conditions procedure
 189  * \param       trunk   Q.921 data structure
 190  * \param       tei     TEI
 191  * \todo        Do something
 192  */
 193 static void Q921ResetExceptionConditions(L2TRUNK trunk, L2UCHAR tei)
 194 {
 195         struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
 196 
 197         /* Clear peer receiver busy */
 198         Q921_CLEAR_FLAG(link, Q921_FLAG_PEER_RECV_BUSY);
 199 
 200         /* Clear reject exception */
 201         Q921_CLEAR_FLAG(link, Q921_FLAG_REJECT);
 202 
 203         /* Clear own receiver busy */
 204         Q921_CLEAR_FLAG(link, Q921_FLAG_RECV_BUSY);
 205 
 206         /* Clear acknowledge pending */
 207         Q921_CLEAR_FLAG(link, Q921_FLAG_ACK_PENDING);
 208 
 209         return;
 210 }
 211 
 212 /**
 213  * Q921EstablishDataLink
 214  * \brief       Q.921 Establish data link procedure
 215  * \param       trunk   Q.921 data structure
 216  * \param       tei     TEI
 217  * \return      always 1 (success)
 218  */
 219 static int Q921EstablishDataLink(L2TRUNK trunk, L2UCHAR tei)
 220 {
 221         struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
 222 
 223         /* reset exception conditions */
 224         Q921ResetExceptionConditions(trunk, tei);
 225 
 226         /* RC = 0 */
 227         link->N200 = 0;
 228 
 229         /* Send SABME */
 230         Q921SendSABME(trunk, trunk->sapi, Q921_COMMAND(trunk), tei, 1);
 231 
 232         /* Restart T200, stop T203 */
 233         Q921T200TimerReset(trunk, tei);
 234         Q921T203TimerStop(trunk, tei);
 235 
 236         return 1;
 237 }
 238 
 239 /**
 240  * Q921NrErrorRecovery
 241  * \brief       NR(R) Error recovery procedure
 242  * \param       trunk   Q.921 data structure
 243  * \param       tei     TEI
 244  * \return      always 1 (success)
 245  */
 246 static int Q921NrErrorRecovery(L2TRUNK trunk, L2UCHAR tei)
 247 {
 248         struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
 249 
 250         /* MDL Error indication (J) */
 251 
 252         /* Establish datalink */
 253         Q921EstablishDataLink(trunk, tei);
 254 
 255         /* Clear L3 initiated */
 256         Q921_CLEAR_FLAG(link, Q921_FLAG_L3_INITIATED);
 257 
 258         return 1;
 259 }
 260 
 261 
 262 /**
 263  * Q921InvokeRetransmission
 264  * \brief       I Frame retransmission procedure
 265  * \param       trunk   Q.921 data structure
 266  * \param       tei     TEI
 267  * \param       nr      N(R) for retransmission
 268  * \return      always 1 (success)
 269  */
 270 static int Q921InvokeRetransmission(L2TRUNK trunk, L2UCHAR tei, L2UCHAR nr)
 271 {
 272         struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
 273         L2UCHAR *mes;
 274         L2INT qpos, qnum, size = 0;
 275 
 276         qnum = MFIFOGetMesCount(link->IFrameResendQueue);
 277         qpos = qnum - 1;
 278 
 279         /*
 280          * slightly different than what is shown in the spec
 281          * (Q.921 '97 Annex B, Figure B.9, page 104)
 282          * 
 283          * what the above mentioned figure probably means is:
 284          * "as long as V(S) != N(R), move the pointer marking
 285          *  the first frame to start resending at to the previous
 286          *  frame"
 287          *
 288          * if we actually implemented it as shown in the figure, we'd be
 289          * resending frames in the wrong order (moving backwards in time)
 290          * meaning we'd have to add an incoming queue to reorder the frames
 291          *
 292          */
 293         /*
 294          * TODO: There's a "traditional" off-by-one error hidden in the original
 295          *       mfifo implementation + it's late, i'm tired and being lazy,
 296          *       so i'll probably have added another one :P
 297          *
 298          *       wow, the first while loop sucks and can be removed
 299          */
 300         while(link->vs != nr && qpos > 0) {     /* ???? */
 301                 /* V(S) = V(S) - 1 */
 302                 Q921_DEC_COUNTER(link->vs);     /* huh? backwards? */
 303 
 304                 /* next frame in queue (backtrack along I queue) ??? */
 305                 qpos--;
 306         }
 307 
 308         /*
 309          * being lazy and trying to avoid mod 128 math this way...
 310          */
 311         if(link->vs != nr && !qpos) {
 312                 /* fatal, we don't have enough history to resend all missing frames */
 313                 /* TODO: how to handle this? */
 314         }
 315 
 316         /*
 317          * resend frames in correct order (oldest missing frame first,
 318          * contrary to what the spec figure shows)
 319          */
 320         while(qpos < qnum) {
 321                 /* Grab frame's buffer ptr and size from queue */
 322                 mes = MFIFOGetMesPtrOffset(link->IFrameResendQueue, &size, qpos);
 323                 if(mes) {
 324                         /* requeue frame (TODO: check queue full condition) */
 325                         MFIFOWriteMes(link->IFrameQueue, mes, size);
 326 
 327                         /* set I frame queued */
 328                 }
 329 
 330                 qpos++;
 331         }
 332 
 333         return 1;
 334 }
 335 
 336 
 337 static int Q921AcknowledgePending(L2TRUNK trunk, L2UCHAR tei)
 338 {
 339         struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
 340 
 341         switch(link->state) {
 342         case Q921_STATE_MULTIPLE_FRAME_ESTABLISHED:
 343         case Q921_STATE_TIMER_RECOVERY:
 344                 if(Q921_CHECK_FLAG(link, Q921_FLAG_ACK_PENDING)) {
 345                         /* clear acknowledge pending */
 346                         Q921_CLEAR_FLAG(link, Q921_FLAG_ACK_PENDING);
 347 
 348                         /* send RR */
 349                         Q921SendRR(trunk, trunk->sapi, Q921_COMMAND(trunk), tei, 0);
 350 
 351                         return 1;
 352                 }
 353                 break;
 354 
 355         default:
 356                 break;
 357         }
 358 
 359         return 0;
 360 }
 361 
 362 /*****************************************************************************
 363 
 364   Function:     Q921_InitTrunk
 365 
 366   Decription:   Initialize a Q.921 trunk so it is ready for use. This 
 367                 function MUST be called before you call any other functions.
 368 
 369 *****************************************************************************/
 370 int Q921_InitTrunk(L2TRUNK trunk,
 371                                         L2UCHAR sapi,
 372                                         L2UCHAR tei,
 373                                         Q921NetUser_t NetUser,
 374                                         Q921NetType_t NetType,
 375                                         L2INT hsize,
 376                                         Q921Tx21CB_t cb21,
 377                                         Q921Tx23CB_t cb23,
 378                                         void *priv21,
 379                                         void *priv23)
 380 {
 381         int numlinks = 0;
 382 
 383         trunk->sapi = sapi;
 384         trunk->tei = tei;
 385         trunk->NetUser = NetUser;
 386         trunk->NetType = NetType;
 387         trunk->Q921Tx21Proc = cb21;
 388         trunk->Q921Tx23Proc = cb23;
 389         trunk->PrivateData21 = priv21;
 390         trunk->PrivateData23 = priv23;
 391         trunk->Q921HeaderSpace = hsize;
 392 
 393         numlinks = Q921_IS_PTMP_NT(trunk) ? Q921_TEI_MAX : 1;
 394 
 395         if (trunk->initialized != INITIALIZED_MAGIC) {
 396                 MFIFOCreate(trunk->HDLCInQueue, Q921MAXHDLCSPACE, 10);
 397 
 398                 /*
 399                  * Allocate space for per-link context(s)
 400                  */
 401                 trunk->context = ftdm_malloc(numlinks * sizeof(struct Q921_Link));
 402                 if(!trunk->context)
 403                         return -1;
 404 
 405                 trunk->initialized = INITIALIZED_MAGIC;
 406         }
 407 
 408         /* timeout default values */
 409         trunk->T200Timeout = 1000;      /*   1 second  */
 410         trunk->T203Timeout = 10000;     /*  10 seconds */
 411         trunk->T202Timeout = 2000;      /*   2 seconds */
 412         trunk->T201Timeout = 200000;    /* 200 seconds */
 413         trunk->TM01Timeout = 10000;     /*  10 seconds */
 414 
 415         /* octet / retransmit counter default limits */
 416         trunk->N200Limit   = 3;         /*   3 retransmits */
 417         trunk->N201Limit   = 260;       /* 260 octets      */
 418         trunk->N202Limit   = 3;         /*   3 retransmits */
 419         trunk->k           = 7;         /*   7 outstanding ACKs */
 420 
 421         /* reset counters, timers, etc. */
 422         trunk->T202 = 0;
 423         trunk->N202 = 0;
 424 
 425         /* Reset per-link contexts */
 426         memset(trunk->context, 0, numlinks * sizeof(struct Q921_Link));
 427 
 428         /* clear tei map */
 429         memset(trunk->tei_map, 0, Q921_TEI_MAX + 1);
 430 
 431         if(Q921_IS_PTMP(trunk)) {
 432                 /*
 433                  * We're either the Network side (NT, TEI = 0)
 434                  * or user-side equipment (TE) which will get it's TEI via
 435                  * dynamic assignment
 436                  */
 437                 trunk->tei = 0;
 438         }
 439 
 440         return 0;
 441 }
 442 
 443 
 444 /**
 445  * Q921Tx21Proc
 446  * \brief       Submit frame to layer 1 (for sending)
 447  * \param[in]   trunk   Pointer to trunk struct
 448  * \param[in]   mes     pointer to message buffer
 449  * \param[in]   size    size of message
 450  * \return      > 0 on success; <= 0 on error
 451  */
 452 static int Q921Tx21Proc(L2TRUNK trunk, L2UCHAR *Msg, L2INT size)
 453 {
 454         Q921LogMesg(trunk, Q921_LOG_DEBUG, 0, Msg, size, "Sending frame");
 455 
 456         return trunk->Q921Tx21Proc(trunk->PrivateData21, Msg, size);
 457 }
 458 
 459 
 460 /**
 461  * Q921Tx23Proc
 462  * \brief       Submit frame to layer 3
 463  * \param[in]   trunk   Pointer to trunk struct
 464  * \param[in]   mes     pointer to message buffer
 465  * \param[in]   size    size of message
 466  * \return      > 0 on success; <= 0 on error
 467  */
 468 static int Q921Tx23Proc(L2TRUNK trunk, Q921DLMsg_t ind, L2UCHAR tei, L2UCHAR *Msg, L2INT size)
 469 {
 470         return trunk->Q921Tx23Proc(trunk->PrivateData23, ind, tei, Msg, size);
 471 }
 472 
 473 
 474 /**
 475  * Q921LogProc
 476  * \brief       Used for logging, converts to string and submits to higher level log function via callback
 477  * \param[in]   trunk   Pointer to trunk struct
 478  * \param[in]   level   Q921 Loglevel
 479  * \param[in]   fmt     format of logmessage
 480  * \return      >= 0 on success, < 0 on error
 481  *
 482  * \author      Stefan Knoblich
 483  */
 484 static int Q921Log(L2TRUNK trunk, Q921LogLevel_t level, const char *fmt, ...)
 485 {
 486         char  buf[Q921_LOGBUFSIZE];
 487         L2INT len;
 488         va_list ap;
 489 
 490         if(!trunk->Q921LogProc)
 491                 return 0;
 492 
 493         if(trunk->loglevel < level)
 494                 return 0;
 495 
 496         va_start(ap, fmt);
 497 
 498         len = vsnprintf(buf, sizeof(buf)-1, fmt, ap);
 499         if(len <= 0) {
 500                 /* TODO: error handling */
 501                 return -1;
 502         }
 503         if(len >= sizeof(buf))
 504                 len = sizeof(buf) - 1;
 505 
 506         buf[len] = '\0';
 507 
 508         va_end(ap);
 509 
 510         return trunk->Q921LogProc(trunk->PrivateDataLog, level, buf, len);
 511 }
 512 
 513 
 514 static int print_hex(char *buf, int bsize, const unsigned char *in, const int len)
 515 {
 516         static const char hex[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
 517         int offset = 0;
 518         int pos    = 0;
 519         int nr     = 0;
 520 
 521         buf[pos++] = '[';
 522         bsize -= 3;
 523 
 524         while((bsize - pos) > 0 && offset < len) {
 525                 buf[pos++] = hex[(in[offset] & 0xF0) >> 4];
 526                 buf[pos++] = hex[(in[offset++]   & 0x0F)];
 527 
 528                 if(++nr == 32 && offset < len && (bsize - pos) > 3) {
 529                         nr = 0;
 530                         buf[pos++] = ']';
 531                         buf[pos++] = '\n';
 532                         buf[pos++] = '[';
 533                 }
 534                 else if(offset < len) {
 535                         buf[pos++] = ' ';
 536                 }
 537         }
 538 
 539         buf[pos++] = ']';
 540         buf[pos++] = '\n';
 541         buf[pos]   = '\0';
 542 
 543         return pos;
 544 }
 545 
 546 #define APPEND_MSG(buf, off, lef, fmt, ...)                     \
 547         len = snprintf(buf + off, lef, fmt, ##__VA_ARGS__);     \
 548         if(len > 0) {                                           \
 549                 off += len;                                     \
 550                 lef -= len;                                     \
 551         } else {                                                \
 552                 goto out;                                       \
 553         }
 554 
 555 /**
 556  * Q921LogProcMesg
 557  * \brief       Used for logging, converts to string and submits to higher level log function via callback
 558  * \param[in]   trunk   Pointer to trunk struct
 559  * \param[in]   level   Q921 Loglevel
 560  * \param[in]   received        direction of the message (received = 1, sending = 0)
 561  * \param[in]   mes     pointer to message buffer
 562  * \param[in]   size    size of message
 563  * \param[in]   fmt     format of logmessage
 564  * \return      >= 0 on success, < 0 on error
 565  *
 566  * \author      Stefan Knoblich
 567  */
 568 static int Q921LogMesg(L2TRUNK trunk, Q921LogLevel_t level, L2UCHAR received, L2UCHAR *mes, L2INT size, const char *fmt, ...)
 569 {
 570         char  buf[Q921_LOGBUFSIZE];
 571         size_t len, left;
 572         va_list ap;
 573 
 574         if(!trunk->Q921LogProc)
 575                 return 0;
 576 
 577         if(trunk->loglevel < level)
 578                 return 0;
 579 
 580         if(!mes)
 581                 return 0;
 582 
 583         memset(buf, 0, sizeof(buf));
 584 
 585         left = sizeof(buf) - 1;
 586 
 587         va_start(ap, fmt);
 588 
 589         len = vsnprintf(buf, left, fmt, ap);
 590         if(len > 0)
 591                 left -= len;
 592         else {
 593                 /* TODO: error handling */
 594                 return -1;
 595         }
 596 
 597         va_end(ap);
 598 
 599         if(trunk->loglevel == Q921_LOG_DEBUG) {
 600                 char pbuf[1024];
 601                 size_t pleft, poffset;
 602                 L2UCHAR sapi, tei, cr;
 603                 L2UCHAR *pmes = mes + trunk->Q921HeaderSpace;
 604                 struct Q921_Link *link;
 605 
 606                 memset(pbuf, 0, sizeof(pbuf));
 607 
 608                 pleft   = sizeof(pbuf);
 609                 poffset = 0;
 610 
 611                 /*
 612                  * Decode packet
 613                  */
 614                 sapi = (pmes[0] & 0xfc) >> 2;
 615                 cr   = (pmes[0] & 0x02) >> 1;
 616                 tei  = (pmes[1] & 0xfe) >> 1;
 617                 link  = Q921_LINK_CONTEXT(trunk, tei);
 618 
 619                 /* make cr actually useful */
 620                 cr   = (received) ? Q921_IS_COMMAND(trunk, cr) : Q921_IS_RESPONSE(trunk, cr);
 621 
 622                 /* filter */
 623                 if((pmes[2] & 0x01) == 0x00) {
 624                         ;
 625                 }
 626                 else if((pmes[2] & 0x03) == 0x01) {
 627                         ; //return 0;
 628                 }
 629                 else if((pmes[2] & 0x03) == 0x03) {
 630                         ;
 631                 }
 632 
 633                 APPEND_MSG(pbuf, poffset, pleft, "\n----------------- Q.921 Packet [%s%s] ---------------\n", received ? "Incoming" : "Outgoing",
 634                                                 (tei == link->tei || tei == Q921_TEI_BCAST) ? "" : ", Ignored" );
 635 
 636                 /* common header */
 637                 APPEND_MSG(pbuf, poffset, pleft, "    SAPI: %u, TEI: %u, C/R: %s (%d)\n\n", sapi, tei, (cr) ? "Command" : "Response", (mes[0] & 0x02) >> 1 );
 638 
 639                 /*
 640                  * message specific
 641                  */
 642                 if((pmes[2] & 0x01) == 0x00) {
 643                         /*
 644                          * I frame
 645                          */
 646                         L2UCHAR pf = pmes[3] & 0x01;    /* poll / final flag */
 647                         L2UCHAR nr = pmes[3] >> 1;      /* receive sequence number */
 648                         L2UCHAR ns = pmes[2] >> 1;      /* send sequence number */
 649 
 650                         APPEND_MSG(pbuf, poffset, pleft, "    Type: I Frame\n          P/F: %d, N(S): %d, N(R): %d  [V(A): %d, V(R): %d, V(S): %d]\n", pf, ns, nr,
 651                                                                                                                 link->va, link->vr, link->vs);
 652 
 653                         /* Dump content of I Frames for foreign TEIs */
 654                         if(tei != link->tei) {
 655                                 APPEND_MSG(pbuf, poffset, pleft, "    CONTENT:\n");
 656 
 657                                 len = print_hex(pbuf + poffset, (int)pleft, &pmes[4], size - (trunk->Q921HeaderSpace + 4));
 658                                 poffset += len;
 659                                 pleft   -= len;
 660                         }
 661                 }
 662                 else if((pmes[2] & 0x03) == 0x01) {
 663                         /*
 664                          * S frame
 665                          */
 666                         L2UCHAR sv = (pmes[2] & 0x0c) >> 2;     /* supervisory format id */
 667                         L2UCHAR pf =  pmes[3] & 0x01;           /* poll / final flag */
 668                         L2UCHAR nr =  pmes[3] >> 1;             /* receive sequence number */
 669                         const char *type;
 670 
 671                         switch(sv) {
 672                         case 0x00:      /* RR : Receive Ready */
 673                                 type = "RR (Receive Ready)";
 674                                 break;
 675 
 676                         case 0x02:      /* RNR : Receive Not Ready */
 677                                 type = "RNR (Receiver Not Ready)";
 678                                 break;
 679 
 680                         case 0x04:      /* REJ : Reject */
 681                                 type = "REJ (Reject)";
 682                                 break;
 683 
 684                         default:        /* Invalid / Unknown */
 685                                 type = "Unknown";
 686                                 break;
 687                         }
 688 
 689                         APPEND_MSG(pbuf, poffset, pleft, "    Type: S Frame, SV: %s\n          P/F: %d, N(R): %d  [V(A): %d, V(R): %d, V(S): %d]\n", type, pf, nr,
 690                                                                                                                 link->va, link->vr, link->vs);
 691                 }
 692                 else if((pmes[2] & 0x03) == 0x03) {
 693                         /*
 694                          * U frame
 695                          */
 696                         L2UCHAR m  = (pmes[2] & 0xe0) >> 3 | (pmes[2] & 0x0c) >> 2;     /* modifier function id */
 697                         L2UCHAR pf = (pmes[2] & 0x10) >> 4;                             /* poll / final flag */
 698                         const char *type;
 699 
 700                         switch(m) {
 701                         case 0x00:
 702                                 type = "UI (Unnumbered Information)";
 703                                 break;
 704 
 705                         case 0x03:
 706                                 type = "DM (Disconnected Mode)";
 707                                 break;
 708 
 709                         case 0x08:
 710                                 type = "DISC (Disconnect)";
 711                                 break;
 712 
 713                         case 0x0c:
 714                                 type = "UA (Unnumbered Acknowledgement)";
 715                                 break;
 716 
 717                         case 0x0f:
 718                                 type = "SABME";
 719                                 break;
 720 
 721                         case 0x11:
 722                                 type = "FRMR (Frame Reject)";
 723                                 break;
 724 
 725                         case 0x17:
 726                                 type = "XID (Exchange Identification)";
 727                                 break;
 728 
 729                         default:
 730                                 type = "Unknown";
 731                         }
 732 
 733 
 734                         APPEND_MSG(pbuf, poffset, pleft, "    Type: U Frame (%s)\n          P/F: %d\n", type, pf);
 735 
 736                         if(m == 0x00) {
 737                                 switch(pmes[3]) {
 738                                 case Q921_LAYER_ENT_ID_TEI:
 739                                         type = "TEI Mgmt";
 740                                         break;
 741 
 742                                 case Q921_LAYER_ENT_ID_Q931:
 743                                         type = "Q.931";
 744                                         break;
 745 
 746                                 default:
 747                                         type = "Unknown";
 748                                 }
 749 
 750                                 if(pmes[3] == Q921_LAYER_ENT_ID_TEI) {
 751                                         const char *command = "";
 752 
 753                                         switch(pmes[6]) {
 754                                         case Q921_TEI_ID_REQUEST:
 755                                                 command = "Request";
 756                                                 break;
 757                                         case Q921_TEI_ID_VERIFY:
 758                                                 command = "Verify";
 759                                                 break;
 760                                         case Q921_TEI_ID_CHECKREQ:
 761                                                 command = "Check req";
 762                                                 break;
 763                                         case Q921_TEI_ID_CHECKRESP:
 764                                                 command = "Check resp";
 765                                                 break;
 766                                         case Q921_TEI_ID_REMOVE:
 767                                                 command = "Remove";
 768                                                 break;
 769                                         case Q921_TEI_ID_ASSIGNED:
 770                                                 command = "Assign";
 771                                                 break;
 772                                         case Q921_TEI_ID_DENIED:
 773                                                 command = "Denied";
 774                                                 break;
 775                                         }
 776                                         APPEND_MSG(pbuf, poffset, pleft, "    ENT ID: %d (%s), COMMAND: %d (%s), RI: %#x, AI: %d\n",
 777                                                          pmes[3], type, pmes[6], command, (int)((pmes[4] << 8) | pmes[5]), pmes[7] >> 1);
 778                                 }
 779                                 else {
 780                                         APPEND_MSG(pbuf, poffset, pleft, "    ENT ID: %d (%s), MESSAGE CONTENT:\n", pmes[3], type);
 781 
 782                                         len = print_hex(pbuf + poffset, (int)pleft, &pmes[3], size - (trunk->Q921HeaderSpace + 3));
 783                                         poffset += len;
 784                                         pleft   -= len;
 785                                 }
 786                         }
 787                 }       
 788                 else {
 789                         /*
 790                          * Unknown
 791                          */
 792                         strncat(pbuf + poffset, "  -- unknown frame type --\n", pleft);
 793 
 794                         len = (sizeof(pbuf) - poffset) - strlen(pbuf + poffset);
 795                         if(len > 0) {
 796                                 poffset += len;
 797                                 pleft   -= len;
 798                         } else
 799                                 goto out;
 800                 }
 801 
 802                 APPEND_MSG(pbuf, poffset, pleft, "\n    Q.921 state: \"%s\" (%d) [flags: %c%c%c%c]\n", Q921State2Name(link->state), link->state,
 803                                                                                         Q921_CHECK_FLAG(link, Q921_FLAG_ACK_PENDING) ? 'A' : '-',
 804                                                                                         Q921_CHECK_FLAG(link, Q921_FLAG_REJECT) ? 'R' : '-',
 805                                                                                         Q921_CHECK_FLAG(link, Q921_FLAG_PEER_RECV_BUSY) ? 'P' : '-',
 806                                                                                         Q921_CHECK_FLAG(link, Q921_FLAG_RECV_BUSY) ? 'B' : '-');
 807 
 808                 strncat(pbuf + poffset, "----------------------------------------------\n\n", pleft);
 809 
 810                 len = (sizeof(pbuf) - poffset) - strlen(pbuf + poffset);
 811                 if(len > 0) {
 812                         poffset += len;
 813                         pleft   -= len;
 814                 } else
 815                         goto out;
 816 
 817 
 818                 /* concat buffers together */
 819                 len = strlen(pbuf);
 820                 if(len <= left)
 821                         strncat(buf, pbuf, left);
 822                 else
 823                         strncat(buf, "-- packet truncated --\n", left);
 824         }
 825 
 826 out:
 827         buf[sizeof(buf) - 1] = '\0';
 828 
 829         return trunk->Q921LogProc(trunk->PrivateDataLog, level, buf, (int)strlen(buf));
 830 }
 831 
 832 /*****************************************************************************
 833 
 834   Function:     Q921TimeTick
 835 
 836   Description:  Called periodically from an external source to allow the 
 837                 stack to process and maintain it's own timers.
 838 
 839   Return Value: none
 840 
 841 *****************************************************************************/
 842 static L2ULONG (*Q921GetTimeProc) (void) = NULL; /* callback for func reading time in ms */
 843 static L2ULONG tLast = {0};
 844 
 845 static L2ULONG Q921GetTime(void)
 846 {
 847         L2ULONG tNow = 0;
 848 
 849         if(Q921GetTimeProc)
 850         {
 851                 tNow = Q921GetTimeProc();
 852                 if(tNow < tLast)        /* wrapped */
 853                 {
 854                         /* TODO */
 855                 }
 856                 tLast = tNow;
 857         }
 858         return tNow;
 859 }
 860 
 861 /*
 862  * T200 handling (per-TEI in PTMP NT mode, tei=0 otherwise)
 863  */
 864 static void Q921T200TimerStart(L2TRUNK trunk, L2UCHAR tei)
 865 {
 866         struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
 867 
 868         if (!link->T200) {
 869                 link->T200 = Q921GetTime() + trunk->T200Timeout;
 870 
 871                 Q921Log(trunk, Q921_LOG_DEBUG, "T200 (timeout: %d msecs) started for TEI %d\n", trunk->T200Timeout, tei);
 872         }
 873 }
 874 
 875 static void Q921T200TimerStop(L2TRUNK trunk, L2UCHAR tei)
 876 {
 877         struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
 878 
 879         link->T200 = 0;
 880 
 881         Q921Log(trunk, Q921_LOG_DEBUG, "T200 stopped for TEI %d\n", tei);
 882 }
 883 
 884 static void Q921T200TimerReset(L2TRUNK trunk, L2UCHAR tei)
 885 {
 886         struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
 887 
 888         link->T200 = Q921GetTime() + trunk->T200Timeout;
 889 
 890         Q921Log(trunk, Q921_LOG_DEBUG, "T200 (timeout: %d msecs) restarted for TEI %d\n", trunk->T200Timeout, tei);
 891 }
 892 
 893 /*
 894  * T203 handling (per-TEI in PTMP NT mode, tei=0 otherwise)
 895  */
 896 static void Q921T203TimerStart(L2TRUNK trunk, L2UCHAR tei)
 897 {
 898         struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
 899 
 900         if (!link->T203) {
 901                 link->T203 = Q921GetTime() + trunk->T203Timeout;
 902 
 903                 Q921Log(trunk, Q921_LOG_DEBUG, "T203 (timeout: %d msecs) started for TEI %d\n", trunk->T203Timeout, tei);
 904         }
 905 }
 906 
 907 static void Q921T203TimerStop(L2TRUNK trunk, L2UCHAR tei)
 908 {
 909         struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
 910 
 911         link->T203 = 0;
 912 
 913         Q921Log(trunk, Q921_LOG_DEBUG, "T203 stopped for TEI %d\n", tei);
 914 }
 915 
 916 static void Q921T203TimerReset(L2TRUNK trunk, L2UCHAR tei)
 917 {
 918         struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
 919 
 920         link->T203 = Q921GetTime() + trunk->T203Timeout;
 921 
 922         Q921Log(trunk, Q921_LOG_DEBUG, "T203 (timeout: %d msecs) restarted for TEI %d\n", trunk->T203Timeout, tei);
 923 }
 924 
 925 /*
 926  * T202 handling (TEI message timeout, TE mode only)
 927  */
 928 static void Q921T202TimerStart(L2TRUNK trunk)
 929 {
 930         if (!trunk->T202) {
 931                 trunk->T202 = Q921GetTime() + trunk->T202Timeout;
 932 
 933                 Q921Log(trunk, Q921_LOG_DEBUG, "T202 (timeout: %d msecs) started\n", trunk->T202Timeout);
 934         }
 935 }
 936 
 937 static void Q921T202TimerStop(L2TRUNK trunk)
 938 {
 939         trunk->T202 = 0;
 940 
 941         Q921Log(trunk, Q921_LOG_DEBUG, "T202 stopped\n");
 942 }
 943 
 944 static void Q921T202TimerReset(L2TRUNK trunk)
 945 {
 946         trunk->T202 = Q921GetTime() + trunk->T202Timeout;
 947 
 948         Q921Log(trunk, Q921_LOG_DEBUG, "T202 (timeout: %d msecs) restarted\n", trunk->T202Timeout);
 949 }
 950 
 951 /*
 952  * T201 handling (TEI management (NT side), per-TEI)
 953  */
 954 static void Q921T201TimerStart(L2TRUNK trunk, L2UCHAR tei)
 955 {
 956         struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
 957 
 958         if (!link->T201) {
 959                 link->T201 = Q921GetTime() + trunk->T201Timeout;
 960 
 961                 Q921Log(trunk, Q921_LOG_DEBUG, "T201 (timeout: %d msecs) started for TEI %d\n", trunk->T201Timeout, tei);
 962         }       
 963 }
 964 
 965 static void Q921T201TimerStop(L2TRUNK trunk, L2UCHAR tei)
 966 {
 967         struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
 968 
 969         link->T201 = 0;
 970 
 971         Q921Log(trunk, Q921_LOG_DEBUG, "T201 stopped for TEI %d\n", tei);
 972 }
 973 
 974 #ifdef __UNUSED_FOR_NOW__
 975 static void Q921T201TimerReset(L2TRUNK trunk, L2UCHAR tei)
 976 {
 977         struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
 978 
 979         link->T201 = Q921GetTime() + trunk->T201Timeout;
 980 
 981         Q921Log(trunk, Q921_LOG_DEBUG, "T201 (timeout: %d msecs) restarted for TEI %d\n", trunk->T201Timeout, tei);
 982 }
 983 #endif
 984 
 985 /*
 986  * TM01 handling (Datalink inactivity shutdown timer)
 987  */
 988 static void Q921TM01TimerStart(L2TRUNK trunk, L2UCHAR tei)
 989 {
 990         struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
 991 
 992         if (!link->TM01) {
 993                 link->TM01 = Q921GetTime() + trunk->TM01Timeout;
 994 
 995                 Q921Log(trunk, Q921_LOG_DEBUG, "TM01 (timeout: %d msecs) started for TEI %d\n", trunk->TM01Timeout, tei);
 996         }
 997 }
 998 
 999 #ifdef __UNUSED_FOR_NOW__
1000 static void Q921TM01TimerStop(L2TRUNK trunk, L2UCHAR tei)
1001 {
1002         struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
1003 
1004         link->TM01 = 0;
1005 
1006         Q921Log(trunk, Q921_LOG_DEBUG, "TM01 stopped for TEI %d\n", tei);
1007 }
1008 #endif
1009 
1010 static void Q921TM01TimerReset(L2TRUNK trunk, L2UCHAR tei)
1011 {
1012         struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
1013 
1014         link->TM01 = Q921GetTime() + trunk->TM01Timeout;
1015 
1016         Q921Log(trunk, Q921_LOG_DEBUG, "TM01 (timeout: %d msecs) restarted for TEI %d\n", trunk->TM01Timeout, tei);
1017 }
1018 
1019 /*
1020  * Expiry callbacks
1021  */
1022 static void Q921T200TimerExpire(L2TRUNK trunk, L2UCHAR tei)
1023 {
1024         struct Q921_Link *link   = Q921_LINK_CONTEXT(trunk, tei);
1025         struct Q921_Link *trlink = Q921_TRUNK_CONTEXT(trunk);
1026 
1027         Q921Log(trunk, Q921_LOG_DEBUG, "T200 expired for TEI %d (trunk TEI %d)\n", tei, trlink->tei);
1028 
1029         /* Stop timer first */
1030         Q921T200TimerStop(trunk, tei);
1031 
1032         switch(link->state) {
1033         case Q921_STATE_AWAITING_ESTABLISHMENT:
1034                 if(link->N200 >= trunk->N200Limit) {
1035                         /* Discard I queue */
1036                         MFIFOClear(link->IFrameQueue);
1037 
1038                         /* MDL-Error indication (G) */
1039                         Q921Log(trunk, Q921_LOG_ERROR, "Failed to establish Q.921 link in %d retries\n", link->N200);
1040 
1041                         /* DL-Release indication */
1042                         Q921Tx23Proc(trunk, Q921_DL_RELEASE, tei, NULL, 0);
1043 
1044                         /* change state (no action) */
1045                         Q921ChangeState(trunk, Q921_STATE_TEI_ASSIGNED, tei);
1046                 } else {
1047                         /* Increment retry counter */
1048                         link->N200++;
1049 
1050                         /* Send SABME */
1051                         Q921SendSABME(trunk,
1052                                         trunk->sapi,
1053                                         Q921_COMMAND(trunk),
1054                                         tei,
1055                                         1);
1056 
1057                         /* Start T200 */
1058                         Q921T200TimerStart(trunk, tei);
1059                 }
1060                 break;
1061 
1062         case Q921_STATE_MULTIPLE_FRAME_ESTABLISHED:
1063                 link->N200 = 0;
1064 
1065                 if(!Q921_CHECK_FLAG(link, Q921_FLAG_PEER_RECV_BUSY)) {
1066                         /* get last transmitted I frame */
1067 
1068                         /* V(S) = V(S) - 1 */
1069                         Q921_DEC_COUNTER(link->vs);
1070 
1071                         /* retransmit I frame */
1072 
1073                         /* V(S) = V(S) + 1 (done by Q921SendI() ) */
1074                         //Q921_INC_COUNTER(link->vs);
1075 
1076                         /* clear acknowledge pending */
1077                         Q921_CLEAR_FLAG(link, Q921_FLAG_ACK_PENDING);
1078 
1079                         /* Start T200 */
1080                         Q921T200TimerStart(trunk, tei);
1081                 } else {
1082                         /* transmit enquiry */
1083                         Q921SendEnquiry(trunk, tei);
1084                 }
1085 
1086                 /* increment counter */
1087                 link->N200++;
1088 
1089                 /* change state (no action) */
1090                 Q921ChangeState(trunk, Q921_STATE_TIMER_RECOVERY, tei);
1091                 break;
1092 
1093         case Q921_STATE_TIMER_RECOVERY:
1094                 if(link->N200 == trunk->N200Limit) {
1095                         /* MDL Error indication (I) */
1096 
1097                         /* Establish data link */
1098                         Q921EstablishDataLink(trunk, tei);
1099 
1100                         /* Clear L3 initiated */
1101                         Q921_CLEAR_FLAG(link, Q921_FLAG_L3_INITIATED);
1102 
1103                         /* change state (no action) */
1104                         Q921ChangeState(trunk, Q921_STATE_AWAITING_ESTABLISHMENT, tei);
1105                 } else {
1106                         if(link->vs == link->va) {
1107                                 /* transmit enquiry */
1108                                 Q921SendEnquiry(trunk, tei);
1109 
1110                         } else if(!Q921_CHECK_FLAG(link, Q921_FLAG_PEER_RECV_BUSY)) {
1111                                 /* get last transmitted frame */
1112 
1113                                 /* V(S) = V(S) - 1 */
1114                                 Q921_DEC_COUNTER(link->vs);
1115 
1116                                 /* retrans frame */
1117 
1118                                 /* V(S) = V(S) + 1 (done by Q921SendI() ) */
1119                                 //Q921_INC_COUNTER(link->vs);
1120 
1121                                 /* clear acknowledge pending */
1122                                 Q921_CLEAR_FLAG(link, Q921_FLAG_ACK_PENDING);
1123 
1124                                 /* Start T200 */
1125                                 Q921T200TimerStart(trunk, tei);
1126                         }
1127 
1128                         /* increment counter */
1129                         link->N200++;
1130 
1131                         /* no state change */
1132                 }
1133                 break;
1134 
1135         default:
1136                 break;
1137         }
1138 }
1139 
1140 static void Q921T203TimerExpire(L2TRUNK trunk, L2UCHAR tei)
1141 {
1142         struct Q921_Link *link   = Q921_LINK_CONTEXT(trunk, tei);
1143         struct Q921_Link *trlink = Q921_TRUNK_CONTEXT(trunk);
1144 
1145         Q921Log(trunk, Q921_LOG_DEBUG, "T203 expired for TEI %d (trunk TEI %d)\n", tei, trlink->tei);
1146 
1147         /* Stop Timer first */
1148         Q921T203TimerStop(trunk, tei);
1149 
1150         switch(link->state) {
1151         case Q921_STATE_MULTIPLE_FRAME_ESTABLISHED:
1152                 /* Send Enquiry */
1153                 Q921SendEnquiry(trunk, tei);
1154 
1155                 /* RC = 0 */
1156                 link->N200 = 0;
1157 
1158                 /* no state change */
1159                 break;
1160 
1161         default:
1162                 break;
1163         }
1164 }
1165 
1166 static void Q921T202TimerExpire(L2TRUNK trunk)
1167 {
1168         struct Q921_Link *link = Q921_TRUNK_CONTEXT(trunk);
1169 
1170         Q921T202TimerReset(trunk);
1171 
1172         Q921Log(trunk, Q921_LOG_DEBUG, "T202 expired for Q.921 trunk with TEI %d\n", link->tei);
1173 
1174         /* todo: implement resend counter */
1175 
1176         switch(link->state) {
1177         case Q921_STATE_TEI_ASSIGNED:   /* Tei identity verify timeout */
1178                 Q921TeiSendVerifyRequest(trunk);
1179                 break;
1180 
1181         default:                        /* Tei assignment request timeout (TODO: refine) */
1182 
1183                 if(trunk->N202 >= trunk->N202Limit) {
1184                         /* Too many retransmits, reset counter, stop timer and handle case (TODO) */
1185                         trunk->N202 = 0;
1186 
1187                         Q921T202TimerStop(trunk);
1188 
1189                         return;
1190                 }
1191                 Q921TeiSendAssignRequest(trunk);
1192 
1193                 trunk->N202++;
1194         }
1195 }
1196 
1197 static void Q921T201TimerExpire(L2TRUNK trunk, L2UCHAR tei)
1198 {
1199         struct Q921_Link *link   = Q921_LINK_CONTEXT(trunk, tei);
1200         struct Q921_Link *trlink = Q921_TRUNK_CONTEXT(trunk);
1201 
1202         Q921Log(trunk, Q921_LOG_DEBUG, "T201 expired for TEI %d (trunk TEI: %d)\n", tei, trlink->tei);
1203 
1204         Q921T201TimerStop(trunk, tei);
1205 
1206         /* NOTE: abusing N202 for this */
1207         if(link->N202 < trunk->N202Limit) {
1208                 /* send check request */
1209                 Q921TeiSendCheckRequest(trunk, tei);
1210 
1211                 /* increment counter */
1212                 link->N202++;
1213         } else {
1214                 /* put context in STOPPED state */
1215                 Q921ChangeState(trunk, Q921_STATE_STOPPED, tei);
1216 
1217                 /* NOTE: should we clear the link too? */
1218                 memset(link, 0, sizeof(struct Q921_Link));
1219 
1220                 /* mark TEI free */
1221                 trunk->tei_map[tei] = 0;
1222         }
1223 }
1224 
1225 #ifdef __UNUSED_FOR_NOW__
1226 static void Q921TM01TimerExpire(L2TRUNK trunk, L2UCHAR tei)
1227 {
1228         struct Q921_Link *link   = Q921_LINK_CONTEXT(trunk, tei);
1229         struct Q921_Link *trlink = Q921_TRUNK_CONTEXT(trunk);
1230 
1231         Q921Log(trunk, Q921_LOG_DEBUG, "TM01 expired for TEI %d (trunk TEI: %d)\n", tei, trlink->tei);
1232 
1233         /* Restart TM01 */
1234         Q921TM01TimerReset(trunk, tei);
1235 
1236         switch(link->state) {
1237         case Q921_STATE_MULTIPLE_FRAME_ESTABLISHED:
1238         case Q921_STATE_TIMER_RECOVERY:
1239 /*
1240  * NT-only, needs more support from L3
1241  */
1242 #if 0
1243                 /* No activity, shutdown link */
1244                 Q921SendDISC(trunk, trunk->sapi, Q921_COMMAND(trunk), tei, 1);
1245 
1246                 /* clear I queue */
1247                 MFIFOClear(link->IFrameQueue);
1248 
1249                 /* change state */
1250                 Q921ChangeState(trunk, Q921_STATE_AWAITING_RELEASE, tei);
1251 #endif
1252                 break;
1253 
1254         default:
1255                 break;
1256         }
1257 }
1258 #endif
1259 
1260 /*
1261  * Timer Tick function
1262  */
1263 void Q921TimerTick(L2TRUNK trunk)
1264 {
1265         struct Q921_Link *link;
1266         L2ULONG tNow = Q921GetTime();
1267         int numlinks = Q921_IS_PTMP_NT(trunk) ? Q921_TEI_MAX : 1;
1268         int x;
1269 
1270         for(x = 0; x <= numlinks; x++) {
1271                 link = Q921_LINK_CONTEXT(trunk, x);
1272 
1273                 /* TODO: check if TEI is assigned and skip check if not (speedup!) */
1274                 if(link->state == Q921_STATE_STOPPED)
1275                         continue;
1276 
1277                 if (link->T200 && tNow > link->T200) {
1278                         Q921T200TimerExpire(trunk, link->tei);
1279                 }
1280                 if (link->T203 && tNow > link->T203) {
1281                         Q921T203TimerExpire(trunk, link->tei);          
1282                 }
1283 
1284                 if(Q921_IS_PTMP_NT(trunk) && link->tei) {
1285                         if (link->T201 && tNow > link->T201) {
1286                                 Q921T201TimerExpire(trunk, link->tei);
1287                         }
1288                 }
1289 
1290                 if(!Q921_IS_PTMP_NT(trunk)) {
1291                         if (trunk->T202 && tNow > trunk->T202) {
1292                                 Q921T202TimerExpire(trunk);
1293                         }
1294                 }
1295 
1296                 /* Send enqueued I frame, if available */
1297                 Q921SendQueuedIFrame(trunk, link->tei);
1298 
1299                 /* Send ack if pending */
1300                 Q921AcknowledgePending(trunk, link->tei);
1301         }
1302 
1303 }
1304 
1305 void Q921SetGetTimeCB(L2ULONG (*callback)(void))
1306 {
1307     Q921GetTimeProc = callback;
1308 }
1309 
1310 /*****************************************************************************
1311 
1312   Function:     Q921QueueHDLCFrame
1313 
1314   Description:  Called to receive and queue an incoming HDLC frame. Will
1315                 queue this in Q921HDLCInQueue. The called must either call
1316                 Q921Rx12 directly afterwards or signal Q921Rx12 to be called
1317                 later. Q921Rx12 will read from the same queue and process
1318                 the frame.
1319 
1320                 This function assumes that the message contains header 
1321                 space. This is removed for internal Q921 processing, but 
1322                 must be keept for I frames.
1323 
1324   Parameters:   trunk   trunk #
1325                 b       ptr to frame;
1326                 size    size of frame in bytes
1327 
1328 *****************************************************************************/
1329 int Q921QueueHDLCFrame(L2TRUNK trunk, L2UCHAR *b, L2INT size)
1330 {
1331     return MFIFOWriteMes(trunk->HDLCInQueue, b, size);
1332 }
1333 
1334 /**
1335  * Q921EnqueueI
1336  * \brief       Put I frame into transmit queue
1337  *
1338  */
1339 static int Q921EnqueueI(L2TRUNK trunk, L2UCHAR Sapi, char cr, L2UCHAR Tei, char pf, L2UCHAR *mes, L2INT size)
1340 {
1341         struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, Tei);
1342 
1343         /* I frame header */
1344         mes[trunk->Q921HeaderSpace+0] = ((Sapi << 2) & 0xfc) | ((cr << 1) & 0x02);
1345         mes[trunk->Q921HeaderSpace+1] = (Tei << 1) | 0x01;
1346         mes[trunk->Q921HeaderSpace+2] = 0x00;
1347         mes[trunk->Q921HeaderSpace+3] = (pf & 0x01);
1348 
1349         Q921Log(trunk, Q921_LOG_DEBUG, "Enqueueing I frame for TEI %d [%d]\n", link->tei, Tei);
1350 
1351         /* transmit queue, (TODO: check for full condition!) */
1352         MFIFOWriteMes(link->IFrameQueue, mes, size);
1353 
1354         /* try to send queued frame */
1355         Q921SendQueuedIFrame(trunk, link->tei);
1356 
1357         return 1;
1358 }
1359 
1360 /**
1361  * Q921SendQueuedIFrame
1362  * \brief       Try to transmit queued I frame (if available)
1363  */
1364 static int Q921SendQueuedIFrame(L2TRUNK trunk, L2UCHAR tei)
1365 {
1366         struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
1367 
1368         L2INT size = 0;
1369         L2UCHAR *mes;
1370 
1371         if(MFIFOGetMesCount(link->IFrameQueue) == 0) {
1372                 return 0;
1373         }
1374 
1375         /* Link ready? */
1376         if(link->state != Q921_STATE_MULTIPLE_FRAME_ESTABLISHED) {
1377                 return 0;
1378         }
1379 
1380         /* peer receiver busy? */
1381         if(Q921_CHECK_FLAG(link, Q921_FLAG_PEER_RECV_BUSY)) {
1382                 return 0;
1383         }
1384 
1385         /* V(S) = V(A) + k? */
1386         if(link->vs == ((link->va + trunk->k) % 128)) {
1387                 Q921Log(trunk, Q921_LOG_WARNING, "Maximum number (%d) of outstanding I frames reached for TEI %d\n", trunk->k, tei);
1388                 return 0;
1389         }
1390 
1391         mes = MFIFOGetMesPtr(link->IFrameQueue, &size);
1392         if(mes) {
1393                 /* Fill in + update counter values */
1394                 mes[trunk->Q921HeaderSpace+2]  = link->vs << 1;
1395                 mes[trunk->Q921HeaderSpace+3] |= link->vr << 1;
1396 
1397                 if(MFIFOGetMesCount(link->IFrameQueue) == 0) {
1398                         /* clear I frame queued */
1399                 }
1400 
1401                 /* Send I frame */
1402                 Q921Tx21Proc(trunk, mes, size);
1403 
1404                 /* V(S) = V(S) + 1 */
1405                 Q921_INC_COUNTER(link->vs);
1406 
1407                 /* clear acknowledge pending */
1408                 Q921_CLEAR_FLAG(link, Q921_FLAG_ACK_PENDING);
1409 
1410                 /* T200 running? */
1411                 if(!link->T200) {
1412                         /* Stop T203, Start T200 */
1413                         Q921T200TimerStart(trunk, tei);
1414                         Q921T203TimerStop(trunk, tei);
1415                 }
1416 
1417                 /* put frame into resend queue */
1418                 MFIFOWriteMesOverwrite(link->IFrameResendQueue, mes, size);
1419 
1420                 /* dequeue frame */
1421                 MFIFOKillNext(link->IFrameQueue);
1422 
1423                 /* Restart TM01 */
1424                 if(Q921_IS_NT(trunk)) {
1425                         Q921TM01TimerReset(trunk, tei);
1426                 }
1427 
1428                 /* no state change */
1429                 return 1;
1430         }
1431 
1432         return 0;
1433 }
1434 
1435 /**
1436  * Q921SendS
1437  * \brief       Prepare and send S frame
1438  */
1439 static int Q921SendS(L2TRUNK trunk, L2UCHAR Sapi, char cr, L2UCHAR Tei, char pf, L2UCHAR sv, L2UCHAR *mes, L2INT size)
1440 {
1441         struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, Tei);
1442 
1443         if(!Q921_IS_READY(link)) {
1444                 /* don't even bother trying */
1445                 Q921Log(trunk, Q921_LOG_DEBUG, "Link not ready, discarding S frame for TEI %d\n", Tei);
1446                 return 0;
1447         }
1448 
1449         /* S frame header */
1450         mes[trunk->Q921HeaderSpace+0] = ((Sapi << 2) & 0xfc) | ((cr << 1) & 0x02);
1451         mes[trunk->Q921HeaderSpace+1] = (Tei << 1) | 0x01;
1452         mes[trunk->Q921HeaderSpace+2] = ((sv << 2) & 0x0c) | 0x01;
1453         mes[trunk->Q921HeaderSpace+3] = (link->vr << 1) | (pf & 0x01);
1454 
1455         return Q921Tx21Proc(trunk, mes, size);
1456 }
1457 
1458 
1459 /**
1460  * Q921SendU
1461  * \brief       Prepare and send U frame
1462  */
1463 static int Q921SendU(L2TRUNK trunk, L2UCHAR Sapi, char cr, L2UCHAR Tei, char pf, L2UCHAR m, L2UCHAR *mes, L2INT size)
1464 {
1465         struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, Tei);
1466 
1467         /* U frame header */
1468         mes[trunk->Q921HeaderSpace+0] = ((Sapi << 2) & 0xfc) | ((cr << 1) & 0x02);
1469         mes[trunk->Q921HeaderSpace+1] = (Tei << 1) | 0x01;
1470         mes[trunk->Q921HeaderSpace+2] = ((m << 3) & 0xe0) | ((pf << 4) & 0x10) | ((m << 2) & 0x0c) | 0x03;
1471 
1472         /* link not ready? enqueue non-TEI-mgmt UI (DL-UNIT DATA) frames */
1473         if(m == 0x00 && Sapi != Q921_SAPI_TEI && link->state < Q921_STATE_TEI_ASSIGNED) {
1474 
1475                 /* write frame to queue */
1476                 MFIFOWriteMes(link->UIFrameQueue, mes, size);
1477 
1478                 Q921Log(trunk, Q921_LOG_DEBUG, "Link not ready, UI Frame of size %d bytes queued for TEI %d\n", size, Tei);
1479                 return 1;
1480         }
1481 
1482         return Q921Tx21Proc(trunk, mes, size);
1483 }
1484 
1485 /**
1486  * TODO: NT mode handling? Need a way to get Link context from Q.931
1487  */
1488 int Q921Rx32(L2TRUNK trunk, Q921DLMsg_t ind, L2UCHAR tei, L2UCHAR * Mes, L2INT Size)
1489 {
1490         struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei); /* TODO: need real link tei for NT mode */
1491         L2INT res = 0;
1492 
1493         Q921Log(trunk, Q921_LOG_DEBUG, "Got frame from Q.931, type: %d, tei: %d, size: %d\n", ind, tei, Size);
1494 
1495         switch(ind) {
1496         case Q921_DL_ESTABLISH:
1497                 /*
1498                  * Hmm...
1499                  */
1500                 switch(link->state) {
1501                 case Q921_STATE_TEI_ASSIGNED:
1502                         if(!Q921_IS_NT(trunk)) {
1503                                 /* establish data link */
1504                                 Q921EstablishDataLink(trunk, link->tei);
1505 
1506                                 /* Set layer 3 initiated */
1507                                 Q921_SET_FLAG(link, Q921_FLAG_L3_INITIATED);
1508 
1509                                 /* change state (no action) */
1510                                 Q921ChangeState(trunk, Q921_STATE_AWAITING_ESTABLISHMENT, link->tei);
1511                         }
1512                         break;
1513 
1514                 case Q921_STATE_AWAITING_ESTABLISHMENT:
1515                         if(!Q921_IS_NT(trunk)) {
1516                                 /* Discard I queue */
1517                                 MFIFOClear(link->IFrameQueue);
1518 
1519                                 /* Set layer 3 initiated */
1520                                 Q921_SET_FLAG(link, Q921_FLAG_L3_INITIATED);
1521                         }
1522                         break;
1523 
1524                 case Q921_STATE_MULTIPLE_FRAME_ESTABLISHED:
1525                 case Q921_STATE_TIMER_RECOVERY:
1526                         if(!Q921_IS_NT(trunk)) {
1527                                 /* Discard I queue */
1528                                 MFIFOClear(link->IFrameQueue);
1529 
1530                                 /* establish data link */
1531                                 Q921EstablishDataLink(trunk, link->tei);
1532 
1533                                 /* Set layer 3 initiated */
1534                                 Q921_SET_FLAG(link, Q921_FLAG_L3_INITIATED);
1535 
1536                                 /* change state (no action) */
1537                                 Q921ChangeState(trunk, Q921_STATE_AWAITING_ESTABLISHMENT, link->tei);
1538                         }
1539                         break;
1540 
1541                 default:
1542                         break;
1543                 }
1544                 break;
1545 
1546         case Q921_DL_RELEASE:
1547                 switch(link->state) {
1548                 case Q921_STATE_TEI_ASSIGNED:
1549                         /* send DL-RELEASE confirm */
1550                         Q921Tx23Proc(trunk, Q921_DL_RELEASE, tei, NULL, 0);
1551                         break;
1552 
1553                 case Q921_STATE_MULTIPLE_FRAME_ESTABLISHED:
1554                 case Q921_STATE_TIMER_RECOVERY:
1555                         if(!Q921_IS_NT(trunk)) {
1556                                 /* Discard I queue */
1557                                 MFIFOClear(link->IFrameQueue);
1558 
1559                                 /* RC = 0 */
1560                                 link->N200 = 0;
1561 
1562                                 /* send DISC command */
1563                                 Q921SendDISC(trunk, trunk->sapi, Q921_COMMAND(trunk), link->tei, 1);
1564 
1565                                 /* Stop T203, restart T200 */
1566                                 if(link->state == Q921_STATE_MULTIPLE_FRAME_ESTABLISHED) {
1567                                         Q921T203TimerStop(trunk, link->tei);
1568                                 }
1569                                 Q921T200TimerReset(trunk, link->tei);
1570 
1571                                 /* change state */
1572                                 Q921ChangeState(trunk, Q921_STATE_AWAITING_RELEASE, link->tei);
1573                         }
1574                         break;
1575 
1576                 default:
1577                         break;
1578                 }
1579                 break;
1580 
1581         case Q921_DL_DATA:      /* DL-DATA request */
1582                 res = Q921EnqueueI(trunk, 
1583                                 trunk->sapi, 
1584                                 Q921_COMMAND(trunk),
1585                                 link->tei,
1586                                 0, 
1587                                 Mes, 
1588                                 Size);
1589 
1590                 if(link->state < Q921_STATE_MULTIPLE_FRAME_ESTABLISHED) {
1591                         /* Treat as implicit DL-ESTABLISH request */
1592 
1593                         /* establish data link */
1594                         Q921EstablishDataLink(trunk, link->tei);
1595 
1596                         /* Set layer 3 initiated */
1597                         Q921_SET_FLAG(link, Q921_FLAG_L3_INITIATED);
1598 
1599                         /* change state (no action) */
1600                         Q921ChangeState(trunk, Q921_STATE_AWAITING_ESTABLISHMENT, link->tei);
1601                 }
1602                 break;
1603 
1604         case Q921_DL_UNIT_DATA:         /* DL-UNIT DATA request */
1605                 res = Q921SendUN(trunk,
1606                                 trunk->sapi,
1607                                 Q921_COMMAND(trunk),
1608                                 Q921_TEI_BCAST,
1609                                 0,
1610                                 Mes,
1611                                 Size);
1612                 /* NOTE: Let the other side initiate link establishment */
1613                 break;
1614 
1615         default:
1616                 break;
1617         }
1618 
1619         return res;
1620 }
1621 /*****************************************************************************
1622 
1623   Function:     Q921SendRR
1624 
1625   Description:  Compose and send Receive Ready.
1626 
1627   Parameters:   trunk       trunk #
1628                 Sapi        Sapi
1629                 cr          C/R field.
1630                 Tei         Tei.
1631                 pf          P/F fiels octet 5
1632 
1633   Return Value: 0 if failed, 1 if Send.
1634 
1635 *****************************************************************************/
1636 
1637 static int Q921SendRR(L2TRUNK trunk, int Sapi, int cr, int Tei, int pf)
1638 {
1639         L2UCHAR mes[25];
1640 
1641         return Q921SendS(trunk, Sapi, cr, Tei, pf, 0x00, mes, trunk->Q921HeaderSpace+4);
1642 }
1643 
1644 /*****************************************************************************
1645 
1646   Function:     Q921SendRNR
1647 
1648   Description:  Compose and send Receive Nor Ready
1649 
1650   Parameters:   trunk       trunk #
1651                 Sapi        Sapi
1652                 cr          C/R field.
1653                 Tei         Tei.
1654                 pf          P/F fiels octet 5
1655 
1656   Return Value: 0 if failed, 1 if Send.
1657 
1658 *****************************************************************************/
1659 static int Q921SendRNR(L2TRUNK trunk, int Sapi, int cr, int Tei, int pf)
1660 {
1661         L2UCHAR mes[25];
1662 
1663         return Q921SendS(trunk, Sapi, cr, Tei, pf, 0x01, mes, trunk->Q921HeaderSpace+4);
1664 }
1665 
1666 /*****************************************************************************
1667 
1668   Function:     Q921SendREJ
1669 
1670   Description:  Compose and Send Reject.
1671 
1672   Parameters:   trunk       trunk #
1673                 Sapi        Sapi
1674                 cr          C/R field.
1675                 Tei         Tei.
1676                 pf          P/F fiels octet 5
1677 
1678   Return Value: 0 if failed, 1 if Send.
1679 
1680 *****************************************************************************/
1681 static int Q921SendREJ(L2TRUNK trunk, int Sapi, int cr, int Tei, int pf)
1682 {
1683         L2UCHAR mes[25];
1684 
1685         return Q921SendS(trunk, Sapi, cr, Tei, pf, 0x03, mes, trunk->Q921HeaderSpace+4);
1686 }
1687 
1688 /*****************************************************************************
1689 
1690   Function:     Q921SendSABME
1691 
1692   Description:  Compose and send SABME
1693 
1694   Parameters:   trunk       trunk #
1695                 Sapi        Sapi
1696                 cr          C/R field.
1697                 Tei         Tei.
1698                 pf          P fiels octet 4
1699 
1700   Return Value: 0 if failed, 1 if Send.
1701 
1702 *****************************************************************************/
1703 static int Q921SendSABME(L2TRUNK trunk, int Sapi, int cr, int Tei, int pf)
1704 {
1705         L2UCHAR mes[25];
1706 
1707         return Q921SendU(trunk, Sapi, cr, Tei, pf, 0x0f, mes, trunk->Q921HeaderSpace+3);
1708 }
1709 
1710 
1711 /**
1712  * Q921Start
1713  * \brief       Start trunk
1714  * \param[in]   trunk   pointer to Q921 data struct
1715  * \return      > 0 on success; <= 0 on error
1716  */
1717 int Q921Start(L2TRUNK trunk)
1718 {
1719         int x, numlinks = Q921_IS_PTMP_NT(trunk) ? Q921_TEI_MAX : 1;
1720         struct Q921_Link *link = Q921_TRUNK_CONTEXT(trunk);
1721 
1722         if(trunk->initialized != INITIALIZED_MAGIC)
1723                 return 0;
1724 
1725         memset(trunk->context, 0, numlinks * sizeof(struct Q921_Link));
1726 
1727         /* Common init part */
1728         for(x = 0; x <= numlinks; x++) {
1729                 link = Q921_LINK_CONTEXT(trunk, x);
1730 
1731                 link->state = Q921_STATE_TEI_UNASSIGNED;
1732                 link->tei   = 0;
1733 
1734                 /* Initialize per-TEI I + UI queues */
1735                 MFIFOCreate(link->UIFrameQueue, Q921MAXHDLCSPACE, 10);
1736                 MFIFOCreate(link->IFrameQueue,  Q921MAXHDLCSPACE, 10);
1737                 MFIFOCreate(link->IFrameResendQueue, Q921MAXHDLCSPACE, 10);
1738         }
1739 
1740         if(Q921_IS_PTMP_TE(trunk)) {
1741                 link->state = Q921_STATE_TEI_UNASSIGNED;
1742                 link->tei   = 0;
1743         }
1744         else if(Q921_IS_PTMP_NT(trunk)) {
1745                 link = Q921_TRUNK_CONTEXT(trunk);
1746 
1747                 link->state = Q921_STATE_TEI_ASSIGNED;
1748                 link->tei   = trunk->tei;
1749 
1750                 /* clear tei map */
1751                 memset(trunk->tei_map, 0, Q921_TEI_MAX + 1);
1752         }
1753         else {
1754                 link->state = Q921_STATE_TEI_ASSIGNED;
1755                 link->tei   = trunk->tei;
1756         }
1757 
1758         Q921Log(trunk, Q921_LOG_DEBUG, "Starting trunk %p (sapi: %d, tei: %d, mode: %s %s)\n",
1759                                  trunk,
1760                                  trunk->sapi,
1761                                  link->tei,
1762                                  Q921_IS_PTMP(trunk) ? "PTMP" : "PTP",
1763                                  Q921_IS_TE(trunk) ? "TE" : "NT");
1764 
1765         if(Q921_IS_PTP(trunk)) {
1766                 Q921Log(trunk, Q921_LOG_DEBUG, "Sending SABME\n");
1767 
1768                 return Q921SendSABME(trunk, 
1769                                         trunk->sapi, 
1770                                         Q921_COMMAND(trunk),
1771                                         link->tei, 
1772                                         1);
1773 
1774         } else if(Q921_IS_PTMP_NT(trunk)) {
1775 
1776                 Q921Log(trunk, Q921_LOG_DEBUG, "Revoking all TEIs\n");
1777 
1778                 return Q921TeiSendRemoveRequest(trunk, Q921_TEI_BCAST); /* Revoke all TEIs in use */
1779         } else {
1780 
1781                 Q921Log(trunk, Q921_LOG_DEBUG, "Requesting TEI\n");
1782 
1783                 return Q921TeiSendAssignRequest(trunk);
1784         }
1785 }
1786 
1787 
1788 /**
1789  * Q921Stop
1790  * \brief       Stop trunk
1791  * \param[in]   trunk   pointer to Q921 data struct
1792  * \return      > 0 on success; <= 0 on error
1793  *
1794  * \author      Stefan Knoblich
1795  */
1796 int Q921Stop(L2TRUNK trunk)
1797 {
1798         struct Q921_Link *link;
1799         int x, numlinks;
1800 
1801         if(!trunk)
1802                 return -1;
1803 
1804         link = Q921_TRUNK_CONTEXT(trunk);
1805         numlinks = Q921_IS_PTMP_NT(trunk) ? Q921_TEI_MAX : 1;
1806 
1807         if(Q921_IS_STOPPED(link))
1808                 return 0;
1809 
1810         /* Release TEI */
1811         if(Q921_IS_PTMP_TE(trunk)) {
1812                 /* send verify request */
1813                 Q921TeiSendVerifyRequest(trunk);
1814 
1815                 /* drop TEI */
1816                 link->tei  = 0;
1817         }
1818 
1819         /* Stop timers, stop link, flush queues */
1820         for(x = 0; x <= numlinks; x++) {
1821                 Q921T200TimerStop(trunk, x);
1822                 Q921T203TimerStop(trunk, x);
1823                 Q921T201TimerStop(trunk, x);
1824 
1825                 /* Change state (no action) */
1826                 Q921ChangeState(trunk, Q921_STATE_STOPPED, x);
1827 
1828                 /* Flush per-tei I/UI queues */
1829                 MFIFOClear(link->UIFrameQueue);
1830                 MFIFOClear(link->IFrameQueue);
1831                 MFIFOClear(link->IFrameResendQueue);
1832         }
1833         Q921T202TimerStop(trunk);
1834 
1835         /* Flush HDLC queue */
1836         MFIFOClear(trunk->HDLCInQueue);
1837 
1838         return 0;
1839 }
1840 
1841 
1842 /*****************************************************************************
1843 
1844   Function:     Q921SendDM
1845 
1846   Description:  Compose and Send DM (Disconnected Mode)
1847 
1848   Parameters:   trunk       trunk #
1849                 Sapi        Sapi
1850                 cr          C/R field.
1851                 Tei         Tei.
1852                 pf          F fiels octet 4
1853 
1854   Return Value: 0 if failed, 1 if Send.
1855 
1856 *****************************************************************************/
1857 static int Q921SendDM(L2TRUNK trunk, int Sapi, int cr, int Tei, int pf)
1858 {
1859         L2UCHAR mes[25];
1860 
1861         return Q921SendU(trunk, Sapi, cr, Tei, pf, 0x03, mes, trunk->Q921HeaderSpace+3);
1862 }
1863 
1864 /*****************************************************************************
1865 
1866   Function:     Q921SendDISC
1867 
1868   Description:  Compose and Send Disconnect
1869 
1870   Parameters:   trunk       trunk #
1871                 Sapi        Sapi
1872                 cr          C/R field.
1873                 Tei         Tei.
1874                 pf          P fiels octet 4
1875 
1876   Return Value: 0 if failed, 1 if Send.
1877 
1878 *****************************************************************************/
1879 static int Q921SendDISC(L2TRUNK trunk, int Sapi, int cr, int Tei, int pf)
1880 {
1881         L2UCHAR mes[25];
1882 
1883         return Q921SendU(trunk, Sapi, cr, Tei, pf, 0x08, mes, trunk->Q921HeaderSpace+3);
1884 }
1885 
1886 /*****************************************************************************
1887 
1888   Function:     Q921SendUA
1889 
1890   Description:  Compose and Send UA
1891 
1892   Parameters:   trunk       trunk #
1893                 Sapi        Sapi
1894                 cr          C/R field.
1895                 Tei         Tei.
1896                 pf          F fiels octet 4
1897 
1898   Return Value: 0 if failed, 1 if Send.
1899 
1900 *****************************************************************************/
1901 static int Q921SendUA(L2TRUNK trunk, int Sapi, int cr, int Tei, int pf)
1902 {
1903         L2UCHAR mes[25];
1904 
1905         return Q921SendU(trunk, Sapi, cr, Tei, pf, 0x0c, mes, trunk->Q921HeaderSpace+3);
1906 }
1907 
1908 static int Q921SendUN(L2TRUNK trunk, int Sapi, int cr, int Tei, int pf, L2UCHAR *mes, L2INT size)
1909 {
1910         return Q921SendU(trunk, Sapi, cr, Tei, pf, 0x00, mes, size+trunk->Q921HeaderSpace+3);
1911 }
1912 
1913 
1914 /**
1915  * Q921ProcSABME
1916  * \brief       Handle incoming SABME
1917  * \param[in]   trunk   pointer to Q921 data struct
1918  * \param[in]   mes     pointer to message buffer
1919  * \param[in]   size    size of message
1920  * \return      > 0 on success, <= 0 on error
1921  */
1922 static int Q921ProcSABME(L2TRUNK trunk, L2UCHAR *mes, L2INT size)
1923 {
1924         L2UCHAR pf = (mes[2] & 0x10) >> 4;                              /* poll / final flag */
1925         L2UCHAR tei = (mes[1] & 0xfe) >> 1;
1926         struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
1927 
1928         switch(link->state) {
1929         case Q921_STATE_TEI_ASSIGNED:
1930                 /* send UA */
1931                 Q921SendUA(trunk,
1932                                 trunk->sapi,
1933                                 Q921_RESPONSE(trunk),   /* or command? */
1934                                 tei, pf);
1935 
1936                 /* clear counters */
1937                 link->vr=0;
1938                 link->vs=0;
1939                 link->va=0;
1940 
1941                 /* TODO: send DL-Establish indication to Q.931 */
1942                 Q921Tx23Proc(trunk, Q921_DL_ESTABLISH, tei, NULL, 0);
1943 
1944                 /* start T203 */
1945                 Q921T203TimerStart(trunk, tei);
1946 
1947                 /* change state (no action) */
1948                 Q921ChangeState(trunk, Q921_STATE_MULTIPLE_FRAME_ESTABLISHED, tei);
1949                 break;
1950 
1951         case Q921_STATE_AWAITING_ESTABLISHMENT:
1952                 /* send UA */
1953                 Q921SendUA(trunk,
1954                                 trunk->sapi,
1955                                 Q921_RESPONSE(trunk),
1956                                 tei, pf);
1957 
1958                 /* no state change */
1959                 break;
1960 
1961         case Q921_STATE_AWAITING_RELEASE:
1962                 /* send DM */
1963                 Q921SendDM(trunk,
1964                                 trunk->sapi,
1965                                 Q921_RESPONSE(trunk),
1966                                 tei, pf);
1967 
1968                 /* no state change */
1969                 break;
1970 
1971         case Q921_STATE_MULTIPLE_FRAME_ESTABLISHED:
1972         case Q921_STATE_TIMER_RECOVERY:
1973                 /* send UA */
1974                 Q921SendUA(trunk,
1975                                 trunk->sapi,
1976                                 Q921_RESPONSE(trunk),
1977                                 tei, pf);
1978 
1979                 /* clear exception conditions */
1980                 Q921ResetExceptionConditions(trunk, tei);
1981 
1982                 /* send MDL-Error indication */
1983 
1984                 /* V(S) == V(A) ? */
1985                 if(link->vs != link->va) {
1986                         /* clear I queue */
1987                         MFIFOClear(link->IFrameQueue);
1988 
1989                         /* DL-Establish indication */
1990                         Q921Tx23Proc(trunk, Q921_DL_ESTABLISH, tei, NULL, 0);
1991                 }
1992 
1993                 /* clear counters */
1994                 link->vr=0;
1995                 link->vs=0;
1996                 link->va=0;
1997 
1998                 /* Stop T200, start T203 */
1999                 Q921T200TimerStop(trunk, tei);
2000                 Q921T203TimerStart(trunk, tei);
2001 
2002                 /* state change only if in TIMER_RECOVERY state */
2003                 if(link->state == Q921_STATE_TIMER_RECOVERY)
2004                         Q921ChangeState(trunk, Q921_STATE_MULTIPLE_FRAME_ESTABLISHED, tei);
2005                 break;
2006 
2007         default:
2008                 break;
2009         }
2010 
2011         return 1;
2012 }
2013 
2014 
2015 /**
2016  * Q921ProcDM
2017  * \brief       Handle incoming DM
2018  * \param[in]   trunk   pointer to Q921 data struct
2019  * \param[in]   mes     pointer to message buffer
2020  * \param[in]   size    size of message
2021  * \return      > 0 on success, <= 0 on error
2022  */
2023 static int Q921ProcDM(L2TRUNK trunk, L2UCHAR *mes, L2INT size)
2024 {
2025         L2UCHAR pf = (mes[2] & 0x10) >> 4;                              /* poll / final flag */
2026         L2UCHAR tei = (mes[1] & 0xfe) >> 1;
2027         struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
2028 
2029         switch(link->state) {
2030         case Q921_STATE_TEI_ASSIGNED:
2031                 if(!pf) {
2032                         /* to next state (no action) */
2033                         Q921ChangeState(trunk, Q921_STATE_AWAITING_ESTABLISHMENT, tei);
2034                 }
2035                 break;
2036 
2037         case Q921_STATE_AWAITING_ESTABLISHMENT:
2038         case Q921_STATE_AWAITING_RELEASE:
2039                 if(pf) {
2040                         if(link->state == Q921_STATE_AWAITING_ESTABLISHMENT) {
2041                                 /* Discard I queue */
2042                                 MFIFOClear(link->IFrameQueue);
2043                         }
2044 
2045                         /* Send DL-Release indication to Q.931 */
2046                         Q921Tx23Proc(trunk, Q921_DL_RELEASE, tei, NULL, 0);
2047 
2048                         /* Stop T200 */
2049                         Q921T200TimerStop(trunk, tei);
2050 
2051                         /* Change state (no action) */
2052                         Q921ChangeState(trunk, Q921_STATE_TEI_ASSIGNED, tei);
2053                 }
2054                 break;
2055 
2056         case Q921_STATE_MULTIPLE_FRAME_ESTABLISHED:
2057                 if(pf) {
2058                         /* MDL-Error indication (B) */
2059 
2060                         /* no state change */
2061                 } else {
2062                         /* MDL-Error indication (E) */
2063 
2064                         /* establish data link */
2065                         Q921EstablishDataLink(trunk, tei);
2066 
2067                         /* clear L3 initiated */
2068                         Q921_CLEAR_FLAG(link, Q921_FLAG_L3_INITIATED);
2069 
2070                         /* change state (no action?) */
2071                         Q921ChangeState(trunk, Q921_STATE_AWAITING_ESTABLISHMENT, tei);
2072                 }
2073                 break;
2074 
2075         case Q921_STATE_TIMER_RECOVERY:
2076                 if(pf) {
2077                         /* MDL Error indication (B) */
2078                 } else {
2079                         /* MDL Error indication (E) */
2080                 }
2081 
2082                 /* establish data link */
2083                 Q921EstablishDataLink(trunk, tei);
2084 
2085                 /* clear layer 3 initiated */
2086                 Q921_CLEAR_FLAG(link, Q921_FLAG_L3_INITIATED);
2087 
2088                 /* change state */
2089                 Q921ChangeState(trunk, Q921_STATE_AWAITING_ESTABLISHMENT, tei);
2090                 break;
2091 
2092         default:
2093                 break;
2094         }
2095 
2096         return 1;
2097 }
2098 
2099 /**
2100  * Q921ProcUA
2101  * \brief       Handle incoming UA
2102  * \param[in]   trunk   pointer to Q921 data struct
2103  * \param[in]   mes     pointer to message buffer
2104  * \param[in]   size    size of message
2105  * \return      > 0 on success, <= 0 on error
2106  */
2107 static int Q921ProcUA(L2TRUNK trunk, L2UCHAR *mes, L2INT size)
2108 {
2109         L2UCHAR pf = (mes[2] & 0x10) >> 4;                              /* poll / final flag */
2110         L2UCHAR tei = (mes[1] & 0xfe) >> 1;
2111         struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
2112 
2113         switch(link->state) {
2114         case Q921_STATE_TEI_ASSIGNED:
2115         case Q921_STATE_TIMER_RECOVERY:
2116                 /* MDL Error indication (C, D) */
2117                 Q921Log(trunk, Q921_LOG_ERROR, "Received UA frame in invalid state\n");
2118                 break;
2119 
2120         case Q921_STATE_AWAITING_ESTABLISHMENT:
2121                 if(pf) {
2122                         /* TODO: other fancy stuff (see docs) */
2123                         if(Q921_CHECK_FLAG(link, Q921_FLAG_L3_INITIATED)) {     /* layer3 initiated */
2124                                 link->vr = 0;
2125 
2126                                 /* DL-Establish confirm */
2127                                 Q921Tx23Proc(trunk, Q921_DL_ESTABLISH_CONFIRM, tei, NULL, 0);
2128 
2129                         } else if(link->vs != link->va) {
2130 
2131                                 /* discard I queue */
2132                                 MFIFOClear(link->IFrameQueue);
2133 
2134                                 /* DL-Establish indication */
2135                                 Q921Tx23Proc(trunk, Q921_DL_ESTABLISH, tei, NULL, 0);
2136                         }
2137 
2138                         /* Stop T200, start T203 */
2139                         Q921T200TimerStop(trunk, tei);
2140                         Q921T203TimerStart(trunk, tei);
2141 
2142                         link->vs = 0;
2143                         link->va = 0;
2144 
2145                         /* change state (no action) */
2146                         Q921ChangeState(trunk, Q921_STATE_MULTIPLE_FRAME_ESTABLISHED, tei);
2147                 } else {
2148                         /* MDL Error indication (C, D) */
2149                         Q921Log(trunk, Q921_LOG_ERROR, "Received UA frame is not a response to a request\n");
2150 
2151                         /* no state change */
2152                 }
2153                 break;
2154 
2155         case Q921_STATE_AWAITING_RELEASE:
2156                 if(pf) {
2157                         /* DL Release confirm */
2158                         Q921Tx23Proc(trunk, Q921_DL_RELEASE_CONFIRM, tei, NULL, 0);
2159 
2160                         /* Stop T200 */
2161                         Q921T200TimerStop(trunk, tei);
2162 
2163                         /* change state (no action) */
2164                         Q921ChangeState(trunk, Q921_STATE_TEI_ASSIGNED, tei);
2165                 } else {
2166                         /* MDL Error indication (D) */
2167                         Q921Log(trunk, Q921_LOG_ERROR, "Received UA frame is not a response to a request\n");
2168 
2169                         /* no state change */
2170                 }
2171                 break;
2172 
2173         case Q921_STATE_MULTIPLE_FRAME_ESTABLISHED:
2174                 /* MDL Error indication (C, D) */
2175                 Q921Log(trunk, Q921_LOG_ERROR, "Received UA frame in invalid state\n");
2176 
2177                 /* no state change */
2178                 break;
2179 
2180         default:
2181                 break;
2182         }
2183 
2184         return 1;
2185 }
2186 
2187 
2188 /**
2189  * Q921ProcDISC
2190  * \brief       Handle incoming DISC
2191  * \param[in]   trunk   pointer to Q921 data struct
2192  * \param[in]   mes     pointer to message buffer
2193  * \param[in]   size    size of message
2194  * \return      > 0 on success, <= 0 on error
2195  */
2196 static int Q921ProcDISC(L2TRUNK trunk, L2UCHAR *mes, L2INT size)
2197 {
2198         L2UCHAR pf  = (mes[2] & 0x10) >> 4;                             /* poll / final flag */
2199         L2UCHAR tei = (mes[1] & 0xfe) >> 1;
2200         struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
2201 
2202         switch(link->state) {
2203         case Q921_STATE_TEI_ASSIGNED:
2204         case Q921_STATE_AWAITING_ESTABLISHMENT:
2205                 /* Send DM */
2206                 Q921SendDM(trunk,
2207                                 trunk->sapi,
2208                                 Q921_RESPONSE(trunk),
2209                                 tei, pf);
2210 
2211                 /* no state change */
2212                 break;
2213 
2214         case Q921_STATE_AWAITING_RELEASE:
2215                 Q921SendUA(trunk,
2216                                 trunk->sapi,
2217                                 Q921_RESPONSE(trunk),
2218                                 tei, pf);
2219 
2220                 /* no state change */
2221                 break;
2222 
2223         case Q921_STATE_MULTIPLE_FRAME_ESTABLISHED:
2224         case Q921_STATE_TIMER_RECOVERY:
2225                 /* Discard I queue */
2226                 MFIFOClear(link->IFrameQueue);
2227 
2228                 /* send UA */
2229                 Q921SendUA(trunk,
2230                                 trunk->sapi,
2231                                 Q921_RESPONSE(trunk),
2232                                 tei, pf);
2233                 
2234                 /* DL Release indication */
2235                 Q921Tx23Proc(trunk, Q921_DL_RELEASE, tei, NULL, 0);
2236 
2237                 /* Stop T200 */
2238                 Q921T200TimerStop(trunk, tei);
2239 
2240                 if(link->state == Q921_STATE_MULTIPLE_FRAME_ESTABLISHED) {
2241                         /* Stop T203 */
2242                         Q921T203TimerStop(trunk, tei);
2243                 }
2244 
2245                 /* change state (no action) */
2246                 Q921ChangeState(trunk, Q921_STATE_TEI_ASSIGNED, tei);
2247                 break;
2248 
2249         default:
2250                 Q921Log(trunk, Q921_LOG_ERROR, "Invalid DISC received in state \"%s\" (%d)", Q921State2Name(link->state), link->state);
2251                 break;
2252         }
2253 
2254         return 1;
2255 }
2256 
2257 
2258 /**
2259  * Q921ProcRR
2260  * \brief       Handle incoming RR
2261  * \param[in]   trunk   pointer to Q921 data struct
2262  * \param[in]   mes     pointer to message buffer
2263  * \param[in]   size    size of message
2264  * \return      > 0 on success, <= 0 on error
2265  */
2266 static int Q921ProcRR(L2TRUNK trunk, L2UCHAR *mes, L2INT size)
2267 {
2268         L2UCHAR cr = (mes[0] & 0x02) >> 1;
2269         L2UCHAR pf =  mes[3] & 0x01;            /* poll / final flag */
2270         L2UCHAR nr = (mes[3] >> 1);
2271 //      L2UCHAR sapi = (mes[0] & 0xfc) >> 2;
2272         L2UCHAR tei  = (mes[1] & 0xfe) >> 1;
2273         struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
2274 
2275         switch(link->state) {
2276         case Q921_STATE_MULTIPLE_FRAME_ESTABLISHED:
2277                 /* clear receiver peer busy */
2278                 Q921_CLEAR_FLAG(link, Q921_FLAG_PEER_RECV_BUSY);
2279 
2280                 if (Q921_IS_COMMAND(trunk, cr)) { /* if this is a command */
2281                         if(pf) {
2282                                 /* Enquiry response */
2283                                 Q921SendEnquiryResponse(trunk, tei);
2284                         }
2285                 } else {
2286                         if(pf) {
2287                                 /* MDL Error indication */
2288                         }
2289                 }
2290 
2291                 /* */
2292                 if(link->va <= nr && nr <= link->vs) {
2293 
2294                         if(nr == link->vs) {
2295                                 /* V(A) = N(R) */
2296                                 link->va = nr;
2297 
2298                                 /* Stop T200, restart T203 */
2299                                 Q921T200TimerStop(trunk, tei);
2300                                 Q921T203TimerReset(trunk, tei);
2301 
2302                         } else if(nr == link->va) {
2303 
2304                                 /* do nothing */
2305 
2306                         } else {
2307                                 /* V(A) = N(R) */
2308                                 link->va = nr;
2309 
2310                                 /* Restart T200 */
2311                                 Q921T200TimerReset(trunk, tei);
2312                         }
2313                         /* no state change */
2314 
2315                 } else {
2316                         /* N(R) Error recovery */
2317                         Q921NrErrorRecovery(trunk, tei);
2318 
2319                         /* change state (no action) */
2320                         Q921ChangeState(trunk, Q921_STATE_AWAITING_ESTABLISHMENT, tei);
2321                 }
2322                 break;
2323 
2324         case Q921_STATE_TIMER_RECOVERY:
2325                 /* clear receiver peer busy */
2326                 Q921_CLEAR_FLAG(link, Q921_FLAG_PEER_RECV_BUSY);
2327 
2328                 /* command + P? */
2329                 if(Q921_IS_COMMAND(trunk, cr) && pf) {
2330                         /* Enquiry response */
2331                         Q921SendEnquiryResponse(trunk, tei);
2332                 }
2333 
2334                 /* */
2335                 if(link->va <= nr && nr <= link->vs) {
2336                         /* V(A) = N(R) */
2337                         link->va = nr;
2338 
2339                         if(!Q921_IS_COMMAND(trunk, cr) && pf) {
2340                                 /* Stop T200, start T203 */
2341                                 Q921T200TimerStop(trunk, tei);
2342                                 Q921T203TimerStart(trunk, tei);
2343 
2344                                 /* Invoke retransmission */
2345                                 Q921InvokeRetransmission(trunk, tei, nr);
2346 
2347                                 /* change state (no action) */
2348                                 Q921ChangeState(trunk, Q921_STATE_MULTIPLE_FRAME_ESTABLISHED, tei);
2349                         }
2350                         /* no state change otherwise */
2351                 } else {
2352                         /* N(R) Error recovery */
2353                         Q921NrErrorRecovery(trunk, tei);
2354 
2355                         /* change state (no action) */
2356                         Q921ChangeState(trunk, Q921_STATE_AWAITING_ESTABLISHMENT, tei);
2357                 }
2358                 break;
2359 
2360         default:
2361                 break;
2362         }
2363         return 1;
2364 }
2365 
2366 
2367 /**
2368  * Q921ProcREJ
2369  * \brief       Handle incoming REJ
2370  * \param[in]   trunk   pointer to Q921 data struct
2371  * \param[in]   mes     pointer to message buffer
2372  * \param[in]   size    size of message
2373  * \return      > 0 on success, <= 0 on error
2374  */
2375 static int Q921ProcREJ(L2TRUNK trunk, L2UCHAR *mes, L2INT size)
2376 {
2377         L2UCHAR cr = (mes[0] & 0x02) >> 1;
2378         L2UCHAR pf =  mes[3] & 0x01;            /* poll / final flag */
2379         L2UCHAR nr = (mes[3] >> 1);
2380 //      L2UCHAR sapi = (mes[0] & 0xfc) >> 2;
2381         L2UCHAR tei  = (mes[1] & 0xfe) >> 1;
2382         struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
2383 
2384         switch(link->state) {
2385         case Q921_STATE_MULTIPLE_FRAME_ESTABLISHED:
2386                 /* clear receiver peer busy */
2387                 Q921_CLEAR_FLAG(link, Q921_FLAG_PEER_RECV_BUSY);
2388 
2389                 /* command? */
2390                 if(Q921_IS_COMMAND(trunk, cr)) {
2391                         if(pf) {
2392                                 /* Enquiry response */
2393                                 Q921SendEnquiryResponse(trunk, tei);
2394                         }
2395                 } else {
2396                         if(pf) {
2397                                 /* MDL Error indication (A) */
2398                         }
2399                 }
2400 
2401                 /* */
2402                 if(link->va <= nr && nr <= link->vs) {
2403 
2404                         /* V(A) = N(R) */
2405                         link->va = nr;
2406 
2407                         /* Stop T200, start T203 */
2408                         Q921T200TimerStop(trunk, tei);
2409                         Q921T203TimerStart(trunk, tei);
2410 
2411                         /* Invoke retransmission of frame >N(R)  (?) */
2412                         Q921InvokeRetransmission(trunk, tei, nr);
2413 
2414                         /* no state change */
2415                 } else {
2416                         /* N(R) Error recovery */
2417                         Q921NrErrorRecovery(trunk, tei);
2418 
2419                         /* change state (no action) */
2420                         Q921ChangeState(trunk, Q921_STATE_AWAITING_ESTABLISHMENT, tei);
2421                 }
2422                 break;
2423 
2424         case Q921_STATE_TIMER_RECOVERY:
2425                 /* clear receiver peer busy */
2426                 Q921_CLEAR_FLAG(link, Q921_FLAG_PEER_RECV_BUSY);
2427 
2428                 /* command + P ? */
2429                 if(Q921_IS_COMMAND(trunk, cr) && pf) {
2430                         /* Enquiry response */
2431                         Q921SendEnquiryResponse(trunk, tei);
2432                 }
2433 
2434                 /* */
2435                 if(link->va <= nr && nr <= link->vs) {
2436 
2437                         /* V(A) = N(R) */
2438                         link->va = nr;
2439 
2440                         if(!Q921_IS_COMMAND(trunk, cr) && pf) {
2441                                 /* Stop T200, start T203 */
2442                                 Q921T200TimerStop(trunk, tei);
2443                                 Q921T203TimerStart(trunk, tei);
2444 
2445                                 /* Invoke retransmission */
2446                                 Q921InvokeRetransmission(trunk, tei, nr);
2447 
2448                                 /* change state (no action) */
2449                                 Q921ChangeState(trunk, Q921_STATE_MULTIPLE_FRAME_ESTABLISHED, tei);
2450                         }
2451                         /* no state change otherwise */
2452                 } else {
2453                         /* N(R) Error recovery */
2454                         Q921NrErrorRecovery(trunk, tei);
2455 
2456                         /* change state (no action) */
2457                         Q921ChangeState(trunk, Q921_STATE_AWAITING_ESTABLISHMENT, tei);
2458                 }
2459                 break;
2460 
2461         default:
2462                 break;
2463         }
2464 
2465         return 1;
2466 }
2467 
2468 
2469 /**
2470  * Q921ProcRNR
2471  * \brief       Handle incoming RNR
2472  * \param[in]   trunk   pointer to Q921 data struct
2473  * \param[in]   mes     pointer to message buffer
2474  * \param[in]   size    size of message
2475  * \return      > 0 on success, <= 0 on error
2476  */
2477 static int Q921ProcRNR(L2TRUNK trunk, L2UCHAR *mes, L2INT size)
2478 {
2479         L2UCHAR cr = (mes[0] & 0x02) >> 1;
2480         L2UCHAR pf =  mes[3] & 0x01;            /* poll / final flag */
2481         L2UCHAR nr = (mes[3] >> 1);
2482 //      L2UCHAR sapi = (mes[0] & 0xfc) >> 2;
2483         L2UCHAR tei  = (mes[1] & 0xfe) >> 1;
2484         struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
2485 
2486         switch(link->state) {
2487         case Q921_STATE_MULTIPLE_FRAME_ESTABLISHED:
2488                 /* set peer receiver busy */
2489                 Q921_SET_FLAG(link, Q921_FLAG_PEER_RECV_BUSY);
2490 
2491                 /* command? */
2492                 if(Q921_IS_COMMAND(trunk, cr)) {
2493                         if(pf) {
2494                                 /* Enquiry response */
2495                                 Q921SendEnquiryResponse(trunk, tei);
2496                         }
2497                 } else {
2498                         if(pf) {
2499                                 /* MDL Error indication (A) */
2500                         }
2501                 }
2502 
2503                 /* */
2504                 if(link->va <= nr && nr <= link->vs) {
2505 
2506                         /* V(A) = N(R) */
2507                         link->va = nr;
2508 
2509                         /* Stop T203, restart T200 */
2510                         Q921T200TimerReset(trunk, tei);
2511                         Q921T203TimerStop(trunk, tei);
2512 
2513                         /* no state change */
2514                 } else {
2515                         /* N(R) Error recovery */
2516                         Q921NrErrorRecovery(trunk, tei);
2517 
2518                         /* change state (no action) */
2519                         Q921ChangeState(trunk, Q921_STATE_AWAITING_ESTABLISHMENT, tei);
2520                 }
2521                 break;
2522 
2523         case Q921_STATE_TIMER_RECOVERY:
2524                 /* set peer receiver busy */
2525                 Q921_SET_FLAG(link, Q921_FLAG_PEER_RECV_BUSY);
2526 
2527                 /* command + P? */
2528                 if(Q921_IS_COMMAND(trunk, cr) && pf) {
2529                         /* Enquiry response */
2530                         Q921SendEnquiryResponse(trunk, tei);
2531                 }
2532 
2533                 /* */
2534                 if(link->va <= nr && nr <= link->vs) {
2535 
2536                         /* V(A) = N(R) */
2537                         link->va = nr;
2538 
2539                         if(!Q921_IS_COMMAND(trunk, cr) && pf) {
2540                                 /* Restart T200 */
2541                                 Q921T200TimerReset(trunk, tei);
2542 
2543                                 /* Invoke retransmission */
2544                                 Q921InvokeRetransmission(trunk, tei, nr);
2545 
2546                                 /* change state (no action) */
2547                                 Q921ChangeState(trunk, Q921_STATE_MULTIPLE_FRAME_ESTABLISHED, tei);
2548                         }
2549                         /* no state change otherwise */
2550                 } else {
2551                         /* N(R) Error recovery */
2552                         Q921NrErrorRecovery(trunk, tei);
2553 
2554                         /* change state (no action) */
2555                         Q921ChangeState(trunk, Q921_STATE_AWAITING_ESTABLISHMENT, tei);
2556                 }
2557                 break;
2558 
2559         default:
2560                 break;
2561         }
2562 
2563         return 1;
2564 }
2565 
2566 #if 0
2567 static int Q921SetReceiverBusy(L2TRUNK trunk)
2568 {
2569         struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
2570 
2571         switch(link->state) {
2572         case Q921_STATE_MULTIPLE_FRAME_ESTABLISHED:
2573                 if(!Q921_CHECK_FLAG(link, Q921_FLAG_RECV_BUSY)) {
2574                         /* set own receiver busy */
2575                         Q921_SET_FLAG(link, Q921_FLAG_RECV_BUSY);
2576 
2577                         /* send RR response */
2578                         Q921SendRR(trunk, trunk->sapi, Q921_RESPONSE(trunk), link->tei, 0);
2579 
2580                         /* clear ack pending */
2581                         Q921_CLEAR_FLAG(link, Q921_FLAG_ACK_PENDING);
2582                 }
2583                 break;
2584 
2585         case Q921_STATE_TIMER_RECOVERY:
2586                 if(!Q921_CHECK_FLAG(link, Q921_FLAG_RECV_BUSY)) {
2587                         /* set own receiver busy */
2588                         Q921_SET_FLAG(link, Q921_FLAG_RECV_BUSY);
2589 
2590                         /* send RNR response */
2591                         Q921SendRNR(trunk, trunk->sapi, Q921_RESPONSE(trunk), link->tei, 0);
2592 
2593                         /* clear ack pending */
2594                         Q921_CLEAR_FLAG(link, Q921_FLAG_ACK_PENDING);
2595                 }
2596                 break;
2597 
2598         default:
2599                 break;
2600         }
2601 
2602         return 0;
2603 }
2604 
2605 static int Q921ClearReceiverBusy(L2TRUNK trunk)
2606 {
2607         struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
2608 
2609         switch(link->state) {
2610         case Q921_STATE_MULTIPLE_FRAME_ESTABLISHED:
2611         case Q921_STATE_TIMER_RECOVERY:
2612                 if(Q921_CHECK_FLAG(link, Q921_FLAG_RECV_BUSY)) {
2613                         /* clear own receiver busy */
2614                         Q921_CLEAR_FLAG(link, Q921_FLAG_RECV_BUSY);
2615 
2616                         /* send RNR response */
2617                         Q921SendRNR(trunk, trunk->sapi, Q921_RESPONSE(trunk), link->tei, 0);
2618 
2619                         /* clear ack pending */
2620                         Q921_CLEAR_FLAG(link, Q921_FLAG_ACK_PENDING);
2621                 }
2622                 break;
2623 
2624         default:
2625                 break;
2626         }
2627 
2628         return 0;
2629 }
2630 #endif
2631 
2632 static int Q921ProcIFrame(L2TRUNK trunk, L2UCHAR *mes, L2INT size)
2633 {
2634         /* common fields: get sapi, tei and cr */
2635 //      L2UCHAR sapi = (mes[0] & 0xfc) >> 2;
2636 //      L2UCHAR cr   = (mes[0] & 0x02) >> 1;
2637         L2UCHAR tei  = (mes[1] & 0xfe) >> 1;
2638         L2UCHAR pf   =  mes[3] & 0x01;          /* poll / final flag */
2639         L2UCHAR nr   =  mes[3] >> 1;            /* receive sequence number */
2640         L2UCHAR ns   =  mes[2] >> 1;            /* send sequence number */
2641         L2UCHAR discard = 0;
2642         struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
2643 
2644         /* Ignore I frames in earlier states */
2645         if(link->state < Q921_STATE_MULTIPLE_FRAME_ESTABLISHED) {
2646                 Q921Log(trunk, Q921_LOG_NOTICE, "I frame in invalid state ignored\n");
2647                 return 0;
2648         }
2649 
2650         /* Receiver busy? */
2651         if(Q921_CHECK_FLAG(link, Q921_FLAG_RECV_BUSY)) {
2652                 /* discard information */
2653                 discard = 1;
2654 
2655                 if(pf) {
2656                         /* send RNR Response */
2657                         Q921SendRNR(trunk, trunk->sapi, Q921_RESPONSE(trunk), tei, 1);
2658 
2659                         /* Clear ack pending */
2660                         Q921_CLEAR_FLAG(link, Q921_FLAG_ACK_PENDING);
2661                 }
2662         }
2663         else {
2664                 if(ns != link->vr) {
2665                         /* discard information */
2666                         discard = 1;
2667 
2668                         if(Q921_CHECK_FLAG(link, Q921_FLAG_REJECT) && pf) {
2669 
2670                                 /* Send RR response */
2671                                 Q921SendRR(trunk, trunk->sapi, Q921_RESPONSE(trunk), tei, 1);
2672 
2673                                 /* clear ack pending */
2674                                 Q921_CLEAR_FLAG(link, Q921_FLAG_ACK_PENDING);
2675                         }
2676                         else if(!Q921_CHECK_FLAG(link, Q921_FLAG_REJECT)){
2677 
2678                                 /* set reject exception */
2679                                 Q921_SET_FLAG(link, Q921_FLAG_REJECT);
2680 
2681                                 /* Send REJ response */
2682                                 Q921SendREJ(trunk, trunk->sapi, Q921_RESPONSE(trunk), tei, pf);
2683 
2684                                 /* clear ack pending */
2685                                 Q921_CLEAR_FLAG(link, Q921_FLAG_ACK_PENDING);
2686                         }
2687                 }
2688                 else {
2689                         /* V(R) = V(R) + 1 */
2690                         Q921_INC_COUNTER(link->vr);
2691 
2692                         /* clear reject exception */
2693                         Q921_CLEAR_FLAG(link, Q921_FLAG_REJECT);
2694 
2695                         /* DL-Data indication */
2696                         Q921Tx23Proc(trunk, Q921_DL_DATA, tei, mes, size);
2697 
2698                         if(pf) {
2699                                 /* Send RR response */
2700                                 Q921SendRR(trunk, trunk->sapi, Q921_RESPONSE(trunk), tei, 1);
2701 
2702                                 /* clear ack pending */
2703                                 Q921_CLEAR_FLAG(link, Q921_FLAG_ACK_PENDING);
2704                         }
2705                         else if(!Q921_CHECK_FLAG(link, Q921_FLAG_ACK_PENDING)) {
2706                                 /* ack pending */
2707 
2708                                 /* Send RR response */
2709                                 Q921SendRR(trunk, trunk->sapi, Q921_RESPONSE(trunk), tei, 0);
2710                                 
2711                                 /* set ack pending*/
2712                                 Q921_SET_FLAG(link, Q921_FLAG_ACK_PENDING);
2713                         }
2714                 }
2715         }
2716 
2717 
2718         switch(link->state) {
2719         case Q921_STATE_MULTIPLE_FRAME_ESTABLISHED:
2720                 if(link->va <= nr && nr <= link->vs) {
2721                         if(Q921_CHECK_FLAG(link, Q921_FLAG_PEER_RECV_BUSY)) {
2722                                 link->va = nr;
2723                         }
2724                         else if(nr == link->vs) {
2725                                 /* V(A) = N(R) */
2726                                 link->va = nr;
2727 
2728                                 /* stop t200, restart t203 */
2729                                 Q921T200TimerStop(trunk, tei);
2730                                 Q921T203TimerReset(trunk, tei);
2731                         }
2732                         else if(nr != link->va) {
2733                                 /* V(A) = N(R) */
2734                                 link->va = nr;
2735 
2736                                 /* restart T200 */
2737                                 Q921T200TimerReset(trunk, tei);
2738                         }
2739 
2740                         /* Restart TM01 */
2741                         if(Q921_IS_NT(trunk)) {
2742                                 Q921TM01TimerReset(trunk, tei);
2743                         }
2744                 }
2745                 else {
2746                         /* N(R) error recovery */
2747                         Q921NrErrorRecovery(trunk, tei);
2748 
2749                         /* change state (no action) */
2750                         Q921ChangeState(trunk, Q921_STATE_AWAITING_ESTABLISHMENT, tei);
2751                 }
2752                 break;
2753 
2754         case Q921_STATE_TIMER_RECOVERY:
2755                 if(link->va <= nr && nr <= link->vs) {
2756                         /* V(A) = N(R) */
2757                         link->va = nr;
2758 
2759                         /* Restart TM01 */
2760                         if(Q921_IS_NT(trunk)) {
2761                                 Q921TM01TimerReset(trunk, tei);
2762                         }
2763                 }
2764                 else {
2765                         /* N(R) error recovery */
2766                         Q921NrErrorRecovery(trunk, tei);
2767 
2768                         /* change state (no action) */
2769                         Q921ChangeState(trunk, Q921_STATE_AWAITING_ESTABLISHMENT, tei);
2770                 }
2771                 break;
2772 
2773         default:
2774                 break;
2775         }
2776 
2777         return 0;
2778 }
2779 
2780 
2781 static int Q921ProcSFrame(L2TRUNK trunk, L2UCHAR *mes, L2INT size)
2782 {
2783         L2UCHAR sv = (mes[2] & 0x0c) >> 2;      /* supervisory format id */
2784         //L2UCHAR pf = mes[3] & 0x01;           /* poll / final flag */
2785         //L2UCHAR nr = mes[3] >> 1;             /* receive sequence number */
2786         L2INT res = -1;
2787 
2788         switch(sv) {
2789         case 0x00:      /* RR : Receive Ready */
2790                 res = Q921ProcRR(trunk, mes, size);
2791                 break;
2792 
2793         case 0x02:      /* RNR : Receive Not Ready */
2794                 res = Q921ProcRNR(trunk, mes, size);
2795                 break;
2796 
2797         case 0x04:      /* REJ : Reject */
2798                 res = Q921ProcREJ(trunk, mes, size);
2799                 break;
2800 
2801         default:        /* Invalid / Unknown */
2802                 Q921Log(trunk, Q921_LOG_ERROR, "Invalid S frame type %d\n", sv);
2803                 break;
2804         }
2805 
2806         return res;
2807 }
2808 
2809 
2810 
2811 static int Q921ProcUFrame(L2TRUNK trunk, L2UCHAR *mes, L2INT size) 
2812 {
2813         L2UCHAR m  = (mes[2] & 0xe0) >> 3 | (mes[2] & 0x0c) >> 2;       /* modifier function id */
2814 //      L2UCHAR pf = (mes[2] & 0x10) >> 4;                              /* poll / final flag */
2815         L2INT res = -1;
2816 
2817         switch(m) {
2818         case 0x00:      /* UN : Unnumbered Information */
2819                 if(mes[3] == Q921_LAYER_ENT_ID_TEI)
2820                 {
2821                         if(!Q921_IS_PTMP(trunk)) {
2822                                 /* wtf? nice try */
2823                                 return res;
2824                         }
2825 
2826                         switch(mes[6]) {
2827                         case Q921_TEI_ID_REQUEST:       /* (TE ->) NT */
2828                                 res = Q921TeiProcAssignRequest(trunk, mes, size);
2829                                 break;
2830 
2831                         case Q921_TEI_ID_ASSIGNED:      /* (NT ->) TE */
2832                         case Q921_TEI_ID_DENIED:
2833                                 res = Q921TeiProcAssignResponse(trunk, mes, size);
2834                                 break;
2835 
2836                         case Q921_TEI_ID_CHECKREQ:      /* (NT ->) TE */
2837                                 res = Q921TeiProcCheckRequest(trunk, mes, size);
2838                                 break;
2839 
2840                         case Q921_TEI_ID_CHECKRESP:     /* (TE ->) NT */
2841                                 res = Q921TeiProcCheckResponse(trunk, mes, size);
2842                                 break;
2843 
2844                         case Q921_TEI_ID_REMOVE:        /* (NT ->) TE */
2845                                 res = Q921TeiProcRemoveRequest(trunk, mes, size);
2846                                 break;
2847 
2848                         case Q921_TEI_ID_VERIFY:        /* (TE ->) NT */
2849                                 res = Q921TeiProcVerifyRequest(trunk, mes, size);
2850                                 break;
2851 
2852                         default:                        /* Invalid / Unknown */
2853                                 Q921Log(trunk, Q921_LOG_ERROR, "Invalid UN message from TEI management/endpoint\n");
2854                                 break;
2855                         }
2856                 }
2857                 else if(mes[3] == Q921_LAYER_ENT_ID_Q931) {
2858 
2859                         Q921Log(trunk, Q921_LOG_DEBUG, "UI Frame for Layer 3 received\n");
2860 
2861                         res = Q921Tx23Proc(trunk, Q921_DL_UNIT_DATA, 0, mes, size);
2862                 }
2863                 break;
2864 
2865         case 0x03:      /* DM : Disconnect Mode */
2866                 res = Q921ProcDM(trunk, mes, size);
2867                 break;
2868 
2869         case 0x08:      /* DISC : Disconnect */
2870                 res = Q921ProcDISC(trunk, mes, size);
2871                 break;
2872 
2873         case 0x0c:      /* UA : Unnumbered Acknowledgement */
2874                 res = Q921ProcUA(trunk, mes, size);
2875                 break;
2876 
2877         case 0x0f:      /* SABME  : Set Asynchronous Balanced Mode Extend */
2878                 res = Q921ProcSABME(trunk, mes, size);
2879                 break;
2880 
2881         case 0x11:      /* FRMR : Frame Reject */
2882         case 0x17:      /* XID : Exchange Identification */
2883                 res = 0;
2884                 break;
2885 
2886         default:        /* Unknown / Invalid */
2887                 Q921Log(trunk, Q921_LOG_ERROR, "Invalid U frame type: %d\n", m);
2888                 break;
2889         }
2890 
2891         return res;
2892 }
2893 
2894 
2895 /*****************************************************************************
2896 
2897   Function:     Q921Rx12
2898 
2899   Description:  Called to process a message frame from layer 1. Will 
2900                 identify the message and call the proper 'processor' for
2901                 layer 2 messages and forward I frames to the layer 3 entity.
2902 
2903                 Q921Rx12 will check the input fifo for a message, and if a 
2904                 message exist process one message before it exits. The caller
2905                 must either call Q921Rx12 polling or keep track on # 
2906                 messages in the queue.
2907 
2908   Parameters:   trunk       trunk #.
2909 
2910   Return Value: # messages processed (always 1 or 0).
2911 
2912 *****************************************************************************/
2913 int Q921Rx12(L2TRUNK trunk)
2914 {
2915         L2INT size;     /* receive size & Q921 frame size*/
2916         L2UCHAR *smes = MFIFOGetMesPtr(trunk->HDLCInQueue, &size);
2917 
2918         if(smes)
2919         {
2920                 struct Q921_Link *link;
2921                 L2UCHAR sapi, tei;
2922                 L2UCHAR *mes;
2923                 L2INT rs;
2924 
2925                 rs  = size - trunk->Q921HeaderSpace;
2926                 mes = &smes[trunk->Q921HeaderSpace];
2927 
2928                 Q921LogMesg(trunk, Q921_LOG_DEBUG, 1, mes, rs, "New packet received (%d bytes)", rs);
2929 
2930                 /* common fields: get sapi, tei and cr */
2931                 sapi = (mes[0] & 0xfc) >> 2;
2932                 tei  = (mes[1] & 0xfe) >> 1;
2933                 link  = Q921_LINK_CONTEXT(trunk, tei);
2934 
2935                 if(Q921_IS_PTMP_TE(trunk) && (
2936                          (link->state >= Q921_STATE_TEI_ASSIGNED && tei != link->tei && tei != Q921_TEI_BCAST) ||                       /* Assigned TEI: Only BCAST and directed */
2937                          (link->state == Q921_STATE_TEI_UNASSIGNED && tei != Q921_TEI_BCAST)))                                  /* No assigned TEI: Only BCAST */
2938                 {
2939                         /* Ignore Messages with foreign TEIs */
2940                         goto out;
2941                 }
2942 
2943                 if((mes[2] & 0x01) == 0x00) {           /* I frame */
2944                         Q921ProcIFrame(trunk, mes, rs);
2945                 }
2946                 else if((mes[2] & 0x03) == 0x01) {      /* S frame */
2947                         Q921ProcSFrame(trunk, mes, rs);
2948                 }
2949                 else if((mes[2] & 0x03) == 0x03) {      /* U frame */
2950                         Q921ProcUFrame(trunk, mes, rs);
2951                 }
2952                 else {
2953                         Q921Log(trunk, Q921_LOG_ERROR, "Invalid frame type: %d\n", (int)(mes[2] & 0x03));
2954                         /* TODO: send FRMR or REJ */
2955                 }
2956 
2957 out:
2958                 MFIFOKillNext(trunk->HDLCInQueue);
2959 
2960                 return 1;
2961         }
2962 
2963         return 0;
2964 }
2965 
2966 /*
2967  * Misc
2968  */
2969 /**
2970  * Q921SetLogCB
2971  * \brief       Set logging callback
2972  * \param[in]   trunk   pointer to Q921 data struct
2973  * \param[in]   func    pointer to logging callback function
2974  * \param[in]   priv    pointer to private data
2975  *
2976  * \author      Stefan Knoblich
2977  */
2978 void Q921SetLogCB(L2TRUNK trunk, Q921LogCB_t func, void *priv)
2979 {
2980         if(!trunk)
2981                 return;
2982 
2983         trunk->Q921LogProc = func;
2984         trunk->PrivateDataLog = priv;
2985 }
2986 
2987 /**
2988  * Q921SetLogLevel
2989  * \brief       Set loglevel of Q.921 logging functions
2990  * \param[in]   trunk   pointer to Q921 data struct
2991  * \param[in]   level   new loglevel
2992  *
2993  * \author      Stefan Knoblich
2994  */
2995 void Q921SetLogLevel(L2TRUNK trunk, Q921LogLevel_t level)
2996 {
2997         if(!trunk)
2998                 return;
2999 
3000     if (level < Q921_LOG_NONE) {
3001         level = Q921_LOG_NONE;
3002     } else if (level > Q921_LOG_DEBUG) {
3003         level = Q921_LOG_DEBUG;
3004     }
3005 
3006         trunk->loglevel = level;
3007 }
3008 
3009 
3010 /**
3011  * Q921ChangeState
3012  * \brief       Change state, invoke neccessary actions
3013  * \param[in]   trunk   pointer to Q921 data struct
3014  * \param[in]   state   state to change to
3015  * \return      > 0 on success; <= 0 on error
3016  *
3017  * \author      Stefan Knoblich
3018  */
3019 static int Q921ChangeState(L2TRUNK trunk, Q921State_t state, L2UCHAR tei)
3020 {
3021         struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
3022         Q921State_t oldstate = link->state;
3023         int res = 0;
3024 
3025         Q921Log(trunk, Q921_LOG_DEBUG, "Changing state from \"%s\" (%d) to \"%s\" (%d) for TEI %d\n",
3026                                 Q921State2Name(oldstate), oldstate,
3027                                 Q921State2Name(state), state,
3028                                 tei);
3029 
3030         /*
3031          * generic actions (depending on the target state only)
3032          */
3033         switch(state) {
3034         case Q921_STATE_MULTIPLE_FRAME_ESTABLISHED:
3035                 /* Start TM01 */
3036                 if(Q921_IS_NT(trunk)) {
3037                         Q921TM01TimerStart(trunk, tei);
3038                 }
3039                 break;
3040 
3041         default:
3042                 break;
3043         }
3044 
3045         /*
3046          * actions that depend on type of the old -> new state transition
3047          */
3048         switch(oldstate) {
3049         case Q921_STATE_STOPPED:
3050 
3051                 switch(state) {
3052                 case Q921_STATE_TEI_UNASSIGNED:
3053                         if(Q921_IS_PTMP_TE(trunk)) {
3054                                 res = Q921TeiSendAssignRequest(trunk);
3055                         }
3056                         break;
3057 
3058                 case Q921_STATE_TEI_ASSIGNED:
3059                         if(Q921_IS_PTMP_NT(trunk)) {
3060                                 res = Q921TeiSendRemoveRequest(trunk, Q921_TEI_BCAST);
3061                         }
3062                         break;
3063 
3064                 default:
3065                         break;
3066                 }
3067                 break;
3068 
3069         default:
3070                 break;
3071         }
3072 
3073         link->state = state;
3074 
3075         Q921Log(trunk, Q921_LOG_DEBUG, "Q921ChangeState() returns %d, new state is \"%s\" (%d) for TEI %d\n", res, Q921State2Name(state), state, tei);
3076 
3077         return res;
3078 }
3079 
3080 /*
3081  * TEI Management functions
3082  * \note        All TEI-mgmt UN frames are sent with cr = command!
3083  */
3084 static int Q921TeiSend(L2TRUNK trunk, L2UCHAR type, L2USHORT ri, L2UCHAR ai)
3085 {
3086         L2UCHAR mes[10];
3087         L2UCHAR offset = Q921_UFRAME_DATA_OFFSET(trunk);
3088 
3089         mes[offset++] = Q921_LAYER_ENT_ID_TEI;  /* layer management entity identifier */
3090         mes[offset++] = (ri & 0xff00) >> 8;     /* reference number upper part */
3091         mes[offset++] =  ri & 0xff;             /* reference number lower part */
3092         mes[offset++] = type;                   /* message type: Identity Request */
3093         mes[offset++] = ai << 1 | 0x01;         /* action indicator: TEI */
3094 
3095         return Q921SendU(trunk, Q921_SAPI_TEI, Q921_COMMAND(trunk), Q921_TEI_BCAST, 0, 0x00, mes, offset);
3096 }
3097 
3098 
3099 /**
3100  * Q921TeiSendAssignRequest
3101  * \brief       Ask for new TEI (TE mode only)
3102  * \param[in]   trunk   pointer to Q921 data struct
3103  * \return      > 0 on success, <= 0 on error
3104  *
3105  * \author      Stefan Knoblich
3106  */
3107 static int Q921TeiSendAssignRequest(L2TRUNK trunk)
3108 {
3109         struct Q921_Link *link = Q921_TRUNK_CONTEXT(trunk);
3110         L2INT res;
3111 
3112         if (!Q921_IS_PTMP_TE(trunk))    /* only ptmp te mode*/
3113                 return 0;
3114 
3115 #ifndef WIN32
3116                 link->ri = (L2USHORT)(random() % 0xffff);
3117 #else
3118                 link->ri = (L2USHORT)(rand() % 0xffff); //todo
3119 #endif
3120 
3121         /* send TEI assign request */
3122         res = Q921TeiSend(trunk, Q921_TEI_ID_REQUEST, link->ri, Q921_TEI_BCAST);
3123 
3124         /* start T202 */
3125         Q921T202TimerStart(trunk);
3126 
3127         return res;
3128 }
3129 
3130 
3131 /**
3132  * Q921TeiProcessAssignResponse
3133  * \brief       Process assign response (TE mode only)
3134  * \param[in]   trunk   pointer to Q921 data struct
3135  * \param[in]   mes     pointer to message buffer
3136  * \param[in]   size    size of message
3137  * \return      > 0 on success; <= 0 on error
3138  *
3139  * \author      Stefan Knoblich
3140  */
3141 static int Q921TeiProcAssignResponse(L2TRUNK trunk, L2UCHAR *mes, L2INT size)
3142 {
3143         struct Q921_Link *link = Q921_TRUNK_CONTEXT(trunk);
3144         L2UCHAR offset = Q921_UFRAME_DATA_OFFSET(trunk);
3145         L2USHORT ri = 0;
3146 
3147         if (!Q921_IS_PTMP_TE(trunk))    /* PTMP TE only */
3148                 return 0;
3149 
3150         ri = (mes[offset + 1] << 8) | mes[offset + 2];
3151 
3152         if(ri != link->ri) {
3153                 /* hmmm ..., not our response i guess */
3154                 return 0;
3155         }
3156 
3157         switch(mes[offset + 3]) {
3158         case Q921_TEI_ID_ASSIGNED:
3159                 /* Yay, use the new TEI and change state to assigned */
3160                 link->tei      = mes[offset + 4] >> 1;
3161 
3162                 Q921Log(trunk, Q921_LOG_DEBUG, "Assigned TEI %d, setting state to TEI_ASSIGNED\n", link->tei);
3163 
3164                 Q921ChangeState(trunk, Q921_STATE_TEI_ASSIGNED, link->tei);
3165                 break;
3166 
3167         case Q921_TEI_ID_DENIED:
3168                 /* oops, what to do now? */
3169                 if ((mes[offset + 4] >> 1) == Q921_TEI_BCAST) {
3170                         /* No more free TEIs? this is bad */
3171 
3172                         //Q921TeiSendVerifyRequest(trunk, Q921_TEI_BCAST); /* TODO: does this work ?? */
3173                 } else {
3174                         /* other reason, this is fatal, shutdown link */
3175                 }
3176 
3177                 Q921Log(trunk, Q921_LOG_DEBUG, "TEI assignment has been denied, reason: %s\n",
3178                          ((mes[offset +4] >> 1) == Q921_TEI_BCAST) ? "No free TEIs available" : "Unknown");
3179 
3180                 Q921ChangeState(trunk, Q921_STATE_TEI_UNASSIGNED, link->tei);
3181                 break;
3182 
3183         default:
3184                 return 0;
3185         }
3186 
3187         /* stop T202 */
3188         Q921T202TimerStop(trunk);
3189 
3190         return 1;
3191 }
3192 
3193 
3194 /**
3195  * Q921TeiSendVerifyRequest
3196  * \brief       Verify TEI (TE mode only)
3197  * \param[in]   trunk   pointer to Q921 data struct
3198  * \return      > 0 on success; <= 0 on error
3199  *
3200  * \author      Stefan Knoblich
3201  */
3202 static int Q921TeiSendVerifyRequest(L2TRUNK trunk)
3203 {
3204         struct Q921_Link *link = Q921_TRUNK_CONTEXT(trunk);
3205         L2INT res;
3206 
3207         if (!Q921_IS_PTMP_TE(trunk))    /* only ptmp te mode*/
3208                 return 0;
3209 
3210         /* Request running? */
3211         if (trunk->T202)
3212                 return 0;
3213 
3214         /* Send TEI verify request */
3215         res = Q921TeiSend(trunk, Q921_TEI_ID_VERIFY, link->ri, link->tei);
3216 
3217         /* start T202 */
3218         Q921T202TimerStart(trunk);
3219 
3220         return res;
3221 }
3222 
3223 
3224 /**
3225  * Q921TeiProcCheckRequest
3226  * \brief       Process Check Request (TE mode only)
3227  * \param[in]   trunk   pointer to Q921 data struct
3228  * \param[in]   mes     pointer to message buffer
3229  * \param[in]   size    size of message
3230  * \return      > 0 on success; <= 0 on error
3231  *
3232  * \author      Stefan Knoblich
3233  */
3234 static int Q921TeiProcCheckRequest(L2TRUNK trunk, L2UCHAR *mes, L2INT size)
3235 {
3236         struct Q921_Link *link = Q921_TRUNK_CONTEXT(trunk);
3237         L2UCHAR offset = Q921_UFRAME_DATA_OFFSET(trunk);
3238         L2UCHAR tei = (mes[offset + 4] >> 1);           /* action indicator => tei */
3239         L2INT res = 0;
3240 
3241         if (!Q921_IS_PTMP_TE(trunk))    /* ptmp te mode only */
3242                 return 0;
3243 
3244         Q921Log(trunk, Q921_LOG_DEBUG, "Received TEI Check request for TEI %d\n", tei);
3245 
3246         if (tei == Q921_TEI_BCAST || tei == link->tei) {
3247                 /*
3248                  * Broadcast TEI check or for our assigned TEI
3249                  */
3250 
3251                 /* send TEI check reponse */
3252                 res = Q921TeiSend(trunk, Q921_TEI_ID_CHECKRESP, link->ri, link->tei);
3253 
3254                 Q921T202TimerStop(trunk);
3255         }
3256 
3257         return res;
3258 }
3259 
3260 
3261 /**
3262  * Q921TeiProcRemoveRequest
3263  * \brief       Process remove Request (TE mode only)
3264  * \param[in]   trunk   pointer to Q921 data struct
3265  * \param[in]   mes     pointer to message buffer
3266  * \param[in]   size    size of message
3267  * \return      > 0 on success; <= 0 on error
3268  *
3269  * \author      Stefan Knoblich
3270  */
3271 static int Q921TeiProcRemoveRequest(L2TRUNK trunk, L2UCHAR *mes, L2INT size)
3272 {
3273         struct Q921_Link *link = Q921_TRUNK_CONTEXT(trunk);
3274         L2UCHAR offset = Q921_UFRAME_DATA_OFFSET(trunk);
3275         L2UCHAR tei = (mes[offset + 4] >> 1);           /* action indicator => tei */
3276         L2INT res = 0;
3277 
3278         if (!Q921_IS_PTMP_TE(trunk))    /* ptmp te mode only */
3279                 return 0;
3280 
3281         Q921Log(trunk, Q921_LOG_DEBUG, "Received TEI Remove request for TEI %d\n", tei);
3282 
3283         if (tei == Q921_TEI_BCAST || tei == link->tei) {
3284                 /*
3285                  * Broadcast TEI remove or for our assigned TEI
3286                  */
3287 
3288                 /* reset tei */
3289                 link->tei  = 0;
3290 
3291                 /* change state (no action) */
3292                 Q921ChangeState(trunk, Q921_STATE_TEI_UNASSIGNED, link->tei);
3293 
3294                 /* TODO: hmm, request new one ? */
3295                 res = Q921TeiSendAssignRequest(trunk);
3296         }
3297         return res;
3298 }
3299 
3300 
3301 /**
3302  * Q921TeiProcAssignRequest
3303  * \brief       Process assign request from peer (NT mode only)
3304  * \param[in]   trunk   pointer to Q921 data struct
3305  * \param[in]   mes     pointer to message buffer
3306  * \param[in]   size    size of message
3307  * \return      > 0 on success; <= 0 on error
3308  *
3309  * \author      Stefan Knoblich
3310  */
3311 static int Q921TeiProcAssignRequest(L2TRUNK trunk, L2UCHAR *mes, L2INT size)
3312 {
3313         L2UCHAR offset = Q921_UFRAME_DATA_OFFSET(trunk);
3314         L2USHORT ri = 0;
3315         L2UCHAR tei = 0;
3316 
3317         if (!Q921_IS_PTMP_NT(trunk))    /* PTMP NT only */
3318                 return 0;
3319 
3320         ri  = (mes[offset + 1] << 8) | mes[offset + 2];
3321         tei =  mes[offset + 4] >> 1;
3322 
3323         if(tei == Q921_TEI_BCAST) {
3324                 int x;
3325 
3326                 /* dynamically allocate TEI */
3327                 for(x = Q921_TEI_DYN_MIN, tei = 0; x <= Q921_TEI_MAX; x++) {
3328                         if(!trunk->tei_map[x]) {
3329                                 tei = x;
3330                                 break;
3331                         }
3332                 }
3333         }
3334         else if(!(tei > 0 && tei < Q921_TEI_DYN_MIN)) {
3335                 /* reject TEIs that are not in the static area */
3336                 Q921TeiSendDenyResponse(trunk, 0, ri);
3337 
3338                 return 0;
3339         }
3340 
3341         if(!tei) {
3342                 /* no free TEI found */
3343                 Q921TeiSendDenyResponse(trunk, Q921_TEI_BCAST, ri);
3344         }
3345         else {
3346                 struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
3347 
3348                 /* mark used */
3349                 trunk->tei_map[tei] = 1;
3350 
3351                 /* assign tei */
3352                 link->tei = tei;
3353 
3354                 /* put context in TEI ASSIGNED state */
3355                 Q921ChangeState(trunk, Q921_STATE_TEI_ASSIGNED, tei);
3356 
3357                 /* send assign response */
3358                 Q921TeiSendAssignedResponse(trunk, tei, ri);
3359 
3360                 /* Start T201 */
3361                 Q921T201TimerStart(trunk, tei);
3362         }
3363         return 0;
3364 }
3365 
3366 /**
3367  * Q921TeiSendCheckRequest
3368  * \brief       Send check request (NT mode only)
3369  * \param[in]   trunk   pointer to Q921 data struct
3370  * \param[in]   tei     TEI to check
3371  * \return      > 0 on success; <= 0 on error
3372  *
3373  * \author      Stefan Knoblich
3374  */
3375 static int Q921TeiSendCheckRequest(L2TRUNK trunk, L2UCHAR tei)
3376 {
3377         L2INT res = 0;
3378 
3379         if (!Q921_IS_PTMP_NT(trunk))    /* PTMP NT only */
3380                 return 0;
3381 
3382         /* send TEI check request */
3383         res = Q921TeiSend(trunk, Q921_TEI_ID_CHECKREQ, 0, tei);
3384 
3385         /* (Re-)Start T201 timer */
3386         Q921T201TimerStart(trunk, tei);
3387 
3388         return res;
3389 }
3390 
3391 /**
3392  * Q921TeiProcCheckResponse
3393  * \brief       Process Check Response (NT mode only)
3394  * \param[in]   trunk   pointer to Q921 data struct
3395  * \param[in]   mes     pointer to message buffer
3396  * \param[in]   size    size of message
3397  * \return      > 0 on success; <= 0 on error
3398  *
3399  * \author      Stefan Knoblich
3400  */
3401 static int Q921TeiProcCheckResponse(L2TRUNK trunk, L2UCHAR *mes, L2INT size)
3402 {
3403         struct Q921_Link *link;
3404         L2UCHAR offset = Q921_UFRAME_DATA_OFFSET(trunk);
3405         L2USHORT ri = 0;
3406         L2UCHAR tei = 0;
3407 
3408         if (!Q921_IS_PTMP_NT(trunk))    /* PTMP NT mode only */
3409                 return 0;
3410 
3411         ri  = (mes[offset + 1] << 8) | mes[offset + 2];
3412         tei =  mes[offset + 4] >> 1;
3413 
3414         /* restart T201 */
3415         Q921T201TimerStop(trunk, tei);
3416 
3417         /* reset counter */
3418         link       = Q921_LINK_CONTEXT(trunk, tei);
3419         link->N202 = 0;
3420 
3421         if(!(tei > 0 && tei < Q921_TEI_MAX) || !trunk->tei_map[tei]) {
3422                 /* TODO: Should we send a DISC first? */
3423 
3424                 /* TEI not assigned? Invalid TEI? */
3425                 Q921TeiSendRemoveRequest(trunk, tei);
3426 
3427                 /* change state */
3428                 Q921ChangeState(trunk, Q921_STATE_STOPPED, tei);
3429 
3430                 /* clear */
3431                 memset(link, 0, sizeof(struct Q921_Link));
3432         } else {
3433                 /* Start T201 */
3434                 Q921T201TimerStart(trunk, tei);
3435         }
3436 
3437         return 0;
3438 }
3439 
3440 
3441 /**
3442  * Q921TeiProcVerifyRequest
3443  * \brief       Process Verify Request (NT mode only)
3444  * \param[in]   trunk   pointer to Q921 data struct
3445  * \param[in]   mes     pointer to message buffer
3446  * \param[in]   size    size of message
3447  * \return      > 0 on success; <= 0 on error
3448  *
3449  * \author      Stefan Knoblich
3450  */
3451 static int Q921TeiProcVerifyRequest(L2TRUNK trunk, L2UCHAR *mes, L2INT size)
3452 {
3453         L2UCHAR resp[25];
3454         L2UCHAR offset = Q921_UFRAME_DATA_OFFSET(trunk);
3455         L2UCHAR tei = 0;
3456 
3457         if (!Q921_IS_PTMP_NT(trunk))    /* PTMP NT mode only */
3458                 return 0;
3459 
3460         tei = mes[offset + 4] >> 1;
3461 
3462         /* todo: handle response... verify assigned TEI */
3463         resp[offset + 0] = 0;
3464 
3465         return 0;
3466 }
3467 
3468 /**
3469  * Q921TeiSendDenyResponse
3470  * \brief       Send Deny Response (NT mode only)
3471  * \param[in]   trunk   pointer to Q921 data struct
3472  * \return      > 0 on success; <= 0 on error
3473  *
3474  * \author      Stefan Knoblich
3475  */
3476 static int Q921TeiSendDenyResponse(L2TRUNK trunk, L2UCHAR tei, L2USHORT ri)
3477 {
3478         if (!Q921_IS_PTMP_NT(trunk))    /* PTMP NT only */
3479                 return 0;
3480 
3481         return Q921TeiSend(trunk, Q921_TEI_ID_DENIED, ri, tei);
3482 }
3483 
3484 
3485 /**
3486  * Q921TeiSendAssignedResponse
3487  * \brief       Send Assigned Response (NT mode only)
3488  * \param[in]   trunk   pointer to Q921 data struct
3489  * \param[in]   tei     TEI to assign
3490  * \param[in]   ri      RI of request
3491  * \return      > 0 on success; <= 0 on error
3492  *
3493  * \author      Stefan Knoblich
3494  */
3495 static int Q921TeiSendAssignedResponse(L2TRUNK trunk, L2UCHAR tei, L2USHORT ri)
3496 {
3497         if (!Q921_IS_PTMP_NT(trunk))    /* PTMP NT only */
3498                 return 0;
3499 
3500         return Q921TeiSend(trunk, Q921_TEI_ID_ASSIGNED, ri, tei);
3501 }
3502 
3503 /**
3504  * Q921TeiSendRemoveRequest
3505  * \brief       Send Remove Request (NT mode only)
3506  * \param[in]   trunk   pointer to Q921 data struct
3507  * \param[in]   tei     TEI to remove
3508  * \return      > 0 on success; <= 0 on error
3509  *
3510  * \author      Stefan Knoblich
3511  */
3512 static int Q921TeiSendRemoveRequest(L2TRUNK trunk, L2UCHAR tei)
3513 {
3514         if (!Q921_IS_PTMP_NT(trunk))    /* PTMP NT only */
3515                 return 0;
3516 
3517         return Q921TeiSend(trunk, Q921_TEI_ID_REMOVE, 0, tei);
3518 }

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