libisdn
Q921.c
Go to the documentation of this file.
00001 /*****************************************************************************
00002 
00003   FileName:     q921.c
00004 
00005   Description:  Contains the implementation of a Q.921 protocol
00006 
00007   Created:      27.dec.2000/JVB
00008 
00009   License/Copyright:
00010 
00011   Copyright (c) 2007, Jan Vidar Berger, Case Labs, Ltd. All rights reserved.
00012   email:janvb@caselaboratories.com
00013 
00014   Redistribution and use in source and binary forms, with or without
00015   modification, are permitted provided that the following conditions are
00016   met:
00017 
00018     * Redistributions of source code must retain the above copyright notice,
00019           this list of conditions and the following disclaimer.
00020     * Redistributions in binary form must reproduce the above copyright notice,
00021           this list of conditions and the following disclaimer in the documentation
00022           and/or other materials provided with the distribution.
00023     * Neither the name of the Case Labs, Ltd nor the names of its contributors
00024           may be used to endorse or promote products derived from this software
00025           without specific prior written permission.
00026 
00027   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00028   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00029   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00030   ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
00031   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00032   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00033   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00034   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00035   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00036   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00037   POSSIBILITY OF SUCH DAMAGE.
00038 
00039 *****************************************************************************/
00040 
00041 /****************************************************************************
00042  * Changes:
00043  *
00044  * - June-August 2008: Stefan Knoblich <s.knoblich@axsentis.de>:
00045  *     Add PTMP TEI management (NT + TE mode)
00046  *     Add timers
00047  *     Add retransmit counters
00048  *     Add logging
00049  *     Various cleanups
00050  *     Queues, retransmission of I frames
00051  *     PTMP NT mode
00052  *
00053  *
00054  * TODO:
00055  *
00056  * - Cleanup queueing, test retransmission
00057  *
00058  * - Q921Start() /-Stop() TEI acquire + release
00059  *   (move everything related into these functions)
00060  *
00061  * - Q.921 '97 Appendix I (and maybe III, IV)
00062  *
00063  * - More complete Appendix II
00064  *
00065  * - Test PTP mode
00066  *
00067  * - PTMP NT mode (in progress)
00068  *
00069  * - NT mode TEI management: (ab)use T202 for TEI Check Request retransmission
00070  *
00071  * - General cleanup (move all non-public declarations into private header file)
00072  *
00073  * - Statistics, per-Frame type debug message filter
00074  *
00075  ****************************************************************************/
00076 
00077 #include <stdio.h>
00078 #include <stdlib.h>
00079 #include <string.h>
00080 #include <stdarg.h>
00081 
00082 #include "Q921.h"
00083 #include "Q921priv.h"
00084 #include "mfifo.h"
00085 
00086 
00087 /******************************************************************************************************
00088  * Actual code below this line
00089  ******************************************************************************************************/
00090 
00091 
00096 static struct Q921StateName {
00097         Q921State_t value;
00098         const char *name;
00099 } Q921StateNames[10] = {
00100         { Q921_STATE_STOPPED, "Stopped" },
00101         { Q921_STATE_TEI_UNASSIGNED, "TEI Unassigned" },
00102         { Q921_STATE_TEI_AWAITING, "TEI Awaiting Assignment" },
00103         { Q921_STATE_TEI_ESTABLISH, "TEI Awaiting Establishment" },
00104         { Q921_STATE_TEI_ASSIGNED, "TEI Assigned" },
00105         { Q921_STATE_AWAITING_ESTABLISHMENT, "Awaiting Establishment" },
00106         { Q921_STATE_AWAITING_RELEASE, "Awaiting Release" },
00107         { Q921_STATE_MULTIPLE_FRAME_ESTABLISHED, "Multiple Frame Mode Established" },
00108         { Q921_STATE_TIMER_RECOVERY, "Timer Recovery" },
00109         { 0, 0 }
00110 };
00111 
00120 static const char *Q921State2Name(Q921State_t state)
00121 {
00122         struct Q921StateName *p = Q921StateNames;
00123 
00124         while (p->name) {
00125                 if (p->value == state)
00126                         return p->name;
00127                 p++;
00128         }
00129 
00130         return "Unknown";
00131 }
00132 
00133 
00137 static int Q921SendEnquiry(L2TRUNK trunk, L2UCHAR tei)
00138 {
00139         struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
00140 
00141         /* send enquiry: begin */
00142         if (Q921_CHECK_FLAG(link, Q921_FLAG_RECV_BUSY)) {
00143 
00144                 Q921SendRNR(trunk, trunk->sapi, Q921_COMMAND(trunk), tei, 1);
00145         }
00146         else {
00147                 Q921SendRR(trunk, trunk->sapi, Q921_COMMAND(trunk), tei, 1);
00148         }
00149 
00150         /* clear acknowledge pending */
00151         Q921_CLEAR_FLAG(link, Q921_FLAG_ACK_PENDING);
00152 
00153         /* "Start" T200 */
00154         Q921T200TimerReset(trunk, tei);
00155 
00156         /* send enquiry: end */
00157         return 1;
00158 }
00159 
00163 static int Q921SendEnquiryResponse(L2TRUNK trunk, L2UCHAR tei)
00164 {
00165         struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
00166 
00167         /* send enquiry: begin */
00168         if (Q921_CHECK_FLAG(link, Q921_FLAG_RECV_BUSY)) {
00169 
00170                 Q921SendRNR(trunk, trunk->sapi, Q921_RESPONSE(trunk), tei, 1);
00171         }
00172         else {
00173                 Q921SendRR(trunk, trunk->sapi, Q921_RESPONSE(trunk), tei, 1);
00174 
00175                 /* clear acknowledge pending */
00176                 Q921_CLEAR_FLAG(link, Q921_FLAG_ACK_PENDING);
00177         }
00178         /* send enquiry: end */
00179         return 1;
00180 }
00181 
00189 static void Q921ResetExceptionConditions(L2TRUNK trunk, L2UCHAR tei)
00190 {
00191         struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
00192 
00193         /* Clear peer receiver busy */
00194         Q921_CLEAR_FLAG(link, Q921_FLAG_PEER_RECV_BUSY);
00195 
00196         /* Clear reject exception */
00197         Q921_CLEAR_FLAG(link, Q921_FLAG_REJECT);
00198 
00199         /* Clear own receiver busy */
00200         Q921_CLEAR_FLAG(link, Q921_FLAG_RECV_BUSY);
00201 
00202         /* Clear acknowledge pending */
00203         Q921_CLEAR_FLAG(link, Q921_FLAG_ACK_PENDING);
00204 
00205         return;
00206 }
00207 
00215 static int Q921EstablishDataLink(L2TRUNK trunk, L2UCHAR tei)
00216 {
00217         struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
00218 
00219         /* reset exception conditions */
00220         Q921ResetExceptionConditions(trunk, tei);
00221 
00222         /* RC = 0 */
00223         link->N200 = 0;
00224 
00225         /* Send SABME */
00226         Q921SendSABME(trunk, trunk->sapi, Q921_COMMAND(trunk), tei, 1);
00227 
00228         /* Restart T200, stop T203 */
00229         Q921T200TimerReset(trunk, tei);
00230         Q921T203TimerStop(trunk, tei);
00231 
00232         return 1;
00233 }
00234 
00242 static int Q921NrErrorRecovery(L2TRUNK trunk, L2UCHAR tei)
00243 {
00244         struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
00245 
00246         /* MDL Error indication (J) */
00247 
00248         /* Establish datalink */
00249         Q921EstablishDataLink(trunk, tei);
00250 
00251         /* Clear L3 initiated */
00252         Q921_CLEAR_FLAG(link, Q921_FLAG_L3_INITIATED);
00253 
00254         return 1;
00255 }
00256 
00257 
00266 static int Q921InvokeRetransmission(L2TRUNK trunk, L2UCHAR tei, L2UCHAR nr)
00267 {
00268         struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
00269         L2UCHAR *mes;
00270         L2INT qpos, qnum, size = 0;
00271 
00272         qnum = MFIFOGetMesCount(link->IFrameResendQueue);
00273         qpos = qnum - 1;
00274 
00275         /*
00276          * slightly different than what is shown in the spec
00277          * (Q.921 '97 Annex B, Figure B.9, page 104)
00278          *
00279          * what the above mentioned figure probably means is:
00280          * "as long as V(S) != N(R), move the pointer marking
00281          *  the first frame to start resending at to the previous
00282          *  frame"
00283          *
00284          * if we actually implemented it as shown in the figure, we'd be
00285          * resending frames in the wrong order (moving backwards in time)
00286          * meaning we'd have to add an incoming queue to reorder the frames
00287          *
00288          */
00289         /*
00290          * TODO: There's a "traditional" off-by-one error hidden in the original
00291          *       mfifo implementation + it's late, i'm tired and being lazy,
00292          *       so i'll probably have added another one :P
00293          *
00294          *       wow, the first while loop sucks and can be removed
00295          */
00296         while (link->vs != nr && qpos > 0) {    /* ???? */
00297                 /* V(S) = V(S) - 1 */
00298                 Q921_DEC_COUNTER(link->vs);     /* huh? backwards? */
00299 
00300                 /* next frame in queue (backtrack along I queue) ??? */
00301                 qpos--;
00302         }
00303 
00304         /*
00305          * being lazy and trying to avoid mod 128 math this way...
00306          */
00307         if (link->vs != nr && !qpos) {
00308                 /* fatal, we don't have enough history to resend all missing frames */
00309                 /* TODO: how to handle this? */
00310         }
00311 
00312         /*
00313          * resend frames in correct order (oldest missing frame first,
00314          * contrary to what the spec figure shows)
00315          */
00316         while (qpos < qnum) {
00317                 /* Grab frame's buffer ptr and size from queue */
00318                 mes = MFIFOGetMesPtrOffset(link->IFrameResendQueue, &size, qpos);
00319                 if (mes) {
00320                         /* requeue frame (TODO: check queue full condition) */
00321                         MFIFOWriteMes(link->IFrameQueue, mes, size);
00322 
00323                         /* set I frame queued */
00324                 }
00325 
00326                 qpos++;
00327         }
00328 
00329         return 1;
00330 }
00331 
00332 
00333 static int Q921AcknowledgePending(L2TRUNK trunk, L2UCHAR tei)
00334 {
00335         struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
00336 
00337         switch (link->state) {
00338         case Q921_STATE_MULTIPLE_FRAME_ESTABLISHED:
00339         case Q921_STATE_TIMER_RECOVERY:
00340                 if (Q921_CHECK_FLAG(link, Q921_FLAG_ACK_PENDING)) {
00341                         /* clear acknowledge pending */
00342                         Q921_CLEAR_FLAG(link, Q921_FLAG_ACK_PENDING);
00343 
00344                         /* send RR */
00345                         Q921SendRR(trunk, trunk->sapi, Q921_COMMAND(trunk), tei, 0);
00346 
00347                         return 1;
00348                 }
00349                 break;
00350 
00351         default:
00352                 break;
00353         }
00354 
00355         return 0;
00356 }
00357 
00358 /*****************************************************************************
00359 
00360   Function:     Q921_InitTrunk
00361 
00362   Decription:   Initialize a Q.921 trunk so it is ready for use. This
00363                 function MUST be called before you call any other functions.
00364 
00365 *****************************************************************************/
00366 Q921_API int Q921_InitTrunk(L2TRUNK trunk,
00367                                         L2UCHAR sapi,
00368                                         L2UCHAR tei,
00369                                         Q921NetUser_t NetUser,
00370                                         Q921NetType_t NetType,
00371                                         L2INT hsize,
00372                                         Q921Tx21CB_t cb21,
00373                                         Q921Tx23CB_t cb23,
00374                                         void *priv21,
00375                                         void *priv23)
00376 {
00377         int numlinks = 0;
00378 
00379         trunk->sapi = sapi;
00380         trunk->tei = tei;
00381         trunk->NetUser = NetUser;
00382         trunk->NetType = NetType;
00383         trunk->Q921Tx21Proc = cb21;
00384         trunk->Q921Tx23Proc = cb23;
00385         trunk->PrivateData21 = priv21;
00386         trunk->PrivateData23 = priv23;
00387         trunk->Q921HeaderSpace = hsize;
00388 
00389         numlinks = Q921_IS_PTMP_NT(trunk) ? Q921_TEI_MAX : 1;
00390 
00391         if (trunk->initialized != INITIALIZED_MAGIC) {
00392                 MFIFOCreate(trunk->HDLCInQueue, Q921MAXHDLCSPACE, 10);
00393 
00394                 /*
00395                  * Allocate space for per-link context(s)
00396                  */
00397                 trunk->context = malloc(numlinks * sizeof(struct Q921_Link));
00398                 if (!trunk->context)
00399                         return -1;
00400 
00401                 trunk->initialized = INITIALIZED_MAGIC;
00402         }
00403 
00404         /* timeout default values */
00405         trunk->T200Timeout = 1000;      /*   1 second  */
00406         trunk->T203Timeout = 10000;     /*  10 seconds */
00407         trunk->T202Timeout = 2000;      /*   2 seconds */
00408         trunk->T201Timeout = 200000;    /* 200 seconds */
00409         trunk->TM01Timeout = 10000;     /*  10 seconds */
00410 
00411         /* octet / retransmit counter default limits */
00412         trunk->N200Limit   = 3;         /*   3 retransmits */
00413         trunk->N201Limit   = 260;       /* 260 octets      */
00414         trunk->N202Limit   = 3;         /*   3 retransmits */
00415         trunk->k           = 7;         /*   7 outstanding ACKs */
00416 
00417         /* reset counters, timers, etc. */
00418         trunk->T202 = 0;
00419         trunk->N202 = 0;
00420 
00421         /* Reset per-link contexts */
00422         memset(trunk->context, 0, numlinks * sizeof(struct Q921_Link));
00423 
00424         /* clear tei map */
00425         memset(trunk->tei_map, 0, Q921_TEI_MAX + 1);
00426 
00427         if (Q921_IS_PTMP(trunk)) {
00428                 /*
00429                  * We're either the Network side (NT, TEI = 0)
00430                  * or user-side equipment (TE) which will get it's TEI via
00431                  * dynamic assignment
00432                  */
00433                 trunk->tei = 0;
00434         }
00435 
00436         return 0;
00437 }
00438 
00439 
00448 static int Q921Tx21Proc(L2TRUNK trunk, L2UCHAR *Msg, L2INT size)
00449 {
00450         Q921LogMesg(trunk, Q921_LOG_DEBUG, 0, Msg, size, "Sending frame");
00451 
00452         return trunk->Q921Tx21Proc(trunk->PrivateData21, Msg, size);
00453 }
00454 
00455 
00464 static int Q921Tx23Proc(L2TRUNK trunk, Q921DLMsg_t ind, L2UCHAR tei, L2UCHAR *Msg, L2INT size)
00465 {
00466         return trunk->Q921Tx23Proc(trunk->PrivateData23, ind, tei, Msg, size);
00467 }
00468 
00469 
00480 static int Q921Log(L2TRUNK trunk, Q921LogLevel_t level, const char *fmt, ...)
00481 {
00482         char  buf[Q921_LOGBUFSIZE];
00483         L2INT len;
00484         va_list ap;
00485 
00486         if (!trunk->Q921LogProc)
00487                 return 0;
00488 
00489         if (trunk->loglevel < level)
00490                 return 0;
00491 
00492         va_start(ap, fmt);
00493 
00494         len = vsnprintf(buf, sizeof(buf)-1, fmt, ap);
00495         if (len <= 0) {
00496                 /* TODO: error handling */
00497                 return -1;
00498         }
00499         if (len >= sizeof(buf))
00500                 len = sizeof(buf) - 1;
00501 
00502         buf[len] = '\0';
00503 
00504         va_end(ap);
00505 
00506         return trunk->Q921LogProc(trunk->PrivateDataLog, level, buf, len);
00507 }
00508 
00509 
00510 static int print_hex(char *buf, int bsize, const unsigned char *in, const int len)
00511 {
00512         static const char hex[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
00513         int offset = 0;
00514         int pos    = 0;
00515         int nr     = 0;
00516 
00517         buf[pos++] = '[';
00518         bsize -= 3;
00519 
00520         while ((bsize - pos) > 0 && offset < len) {
00521                 buf[pos++] = hex[(in[offset] & 0xF0) >> 4];
00522                 buf[pos++] = hex[(in[offset++]   & 0x0F)];
00523 
00524                 if (++nr == 32 && offset < len && (bsize - pos) > 3) {
00525                         nr = 0;
00526                         buf[pos++] = ']';
00527                         buf[pos++] = '\n';
00528                         buf[pos++] = '[';
00529                 }
00530                 else if (offset < len) {
00531                         buf[pos++] = ' ';
00532                 }
00533         }
00534 
00535         buf[pos++] = ']';
00536         buf[pos++] = '\n';
00537         buf[pos]   = '\0';
00538 
00539         return pos;
00540 }
00541 
00542 #define MSG_PUTS(buf, off, lef, fmt)            \
00543         strncat(buf + off, fmt, lef - 1);       \
00544         len = strlen(buf + off);                \
00545         off += len;                             \
00546         lef -= len;                             \
00547         if (lef <= 0) {                         \
00548                 goto out;                       \
00549         }
00550 
00551 #define MSG_SPRINTF(buf, off, lef, fmt, ...)                    \
00552         len = snprintf(buf + off, lef, fmt, ##__VA_ARGS__);     \
00553         if (len > 0) {                                          \
00554                 off += len;                                     \
00555                 lef -= len;                                     \
00556         } else {                                                \
00557                 goto out;                                       \
00558         }
00559 
00573 static int Q921LogMesg(L2TRUNK trunk, Q921LogLevel_t level, L2UCHAR received, L2UCHAR *mes, L2INT size, const char *fmt, ...)
00574 {
00575         char  buf[Q921_LOGBUFSIZE];
00576         size_t len, left;
00577         va_list ap;
00578 
00579         if (!trunk->Q921LogProc)
00580                 return 0;
00581 
00582         if (trunk->loglevel < level)
00583                 return 0;
00584 
00585         if (!mes)
00586                 return 0;
00587 
00588         memset(buf, 0, sizeof(buf));
00589 
00590         left = sizeof(buf) - 1;
00591 
00592         va_start(ap, fmt);
00593 
00594         len = vsnprintf(buf, left, fmt, ap);
00595         if (len > 0)
00596                 left -= len;
00597         else {
00598                 /* TODO: error handling */
00599                 return -1;
00600         }
00601 
00602         va_end(ap);
00603 
00604         if (trunk->loglevel == Q921_LOG_DEBUG) {
00605                 char pbuf[1024];
00606                 size_t pleft, poffset;
00607                 L2UCHAR sapi, tei, cr;
00608                 L2UCHAR *pmes = mes + trunk->Q921HeaderSpace;
00609                 struct Q921_Link *link;
00610 
00611                 memset(pbuf, 0, sizeof(pbuf));
00612 
00613                 pleft   = sizeof(pbuf);
00614                 poffset = 0;
00615 
00616                 /*
00617                  * Decode packet
00618                  */
00619                 sapi = (pmes[0] & 0xfc) >> 2;
00620                 cr   = (pmes[0] & 0x02) >> 1;
00621                 tei  = (pmes[1] & 0xfe) >> 1;
00622                 link  = Q921_LINK_CONTEXT(trunk, tei);
00623 
00624                 /* make cr actually useful */
00625                 cr   = (received) ? Q921_IS_COMMAND(trunk, cr) : Q921_IS_RESPONSE(trunk, cr);
00626 
00627                 /* filter */
00628                 if ((pmes[2] & 0x01) == 0x00) {
00629                         ;
00630                 }
00631                 else if ((pmes[2] & 0x03) == 0x01) {
00632                         ; //return 0;
00633                 }
00634                 else if ((pmes[2] & 0x03) == 0x03) {
00635                         ;
00636                 }
00637 
00638                 MSG_SPRINTF(pbuf, poffset, pleft, "\n----------------- Q.921 Packet [%s%s] ---------------\n", received ? "Incoming" : "Outgoing",
00639                                                 (tei == link->tei || tei == Q921_TEI_BCAST) ? "" : ", Ignored" );
00640 
00641                 /* common header */
00642                 MSG_SPRINTF(pbuf, poffset, pleft, "    SAPI: %u, TEI: %u, C/R: %s (%d)\n\n", sapi, tei, (cr) ? "Command" : "Response", (mes[0] & 0x02) >> 1 );
00643 
00644                 /*
00645                  * message specific
00646                  */
00647                 if ((pmes[2] & 0x01) == 0x00) {
00648                         /*
00649                          * I frame
00650                          */
00651                         L2UCHAR pf = pmes[3] & 0x01;    /* poll / final flag */
00652                         L2UCHAR nr = pmes[3] >> 1;      /* receive sequence number */
00653                         L2UCHAR ns = pmes[2] >> 1;      /* send sequence number */
00654 
00655                         MSG_SPRINTF(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,
00656                                                                                                                 link->va, link->vr, link->vs);
00657 
00658                         /* Dump content of I Frames for foreign TEIs */
00659                         if (tei != link->tei) {
00660                                 MSG_PUTS(pbuf, poffset, pleft, "    CONTENT:\n");
00661 
00662                                 len = print_hex(pbuf + poffset, pleft, &pmes[4], size - (trunk->Q921HeaderSpace + 4));
00663                                 poffset += len;
00664                                 pleft   -= len;
00665                         }
00666                 }
00667                 else if ((pmes[2] & 0x03) == 0x01) {
00668                         /*
00669                          * S frame
00670                          */
00671                         L2UCHAR sv = (pmes[2] & 0x0c) >> 2;     /* supervisory format id */
00672                         L2UCHAR pf =  pmes[3] & 0x01;           /* poll / final flag */
00673                         L2UCHAR nr =  pmes[3] >> 1;             /* receive sequence number */
00674                         const char *type;
00675 
00676                         switch (sv) {
00677                         case 0x00:      /* RR : Receive Ready */
00678                                 type = "RR (Receive Ready)";
00679                                 break;
00680 
00681                         case 0x02:      /* RNR : Receive Not Ready */
00682                                 type = "RNR (Receiver Not Ready)";
00683                                 break;
00684 
00685                         case 0x04:      /* REJ : Reject */
00686                                 type = "REJ (Reject)";
00687                                 break;
00688 
00689                         default:        /* Invalid / Unknown */
00690                                 type = "Unknown";
00691                                 break;
00692                         }
00693 
00694                         MSG_SPRINTF(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,
00695                                                                                                                 link->va, link->vr, link->vs);
00696                 }
00697                 else if ((pmes[2] & 0x03) == 0x03) {
00698                         /*
00699                          * U frame
00700                          */
00701                         L2UCHAR m  = (pmes[2] & 0xe0) >> 3 | (pmes[2] & 0x0c) >> 2;     /* modifier function id */
00702                         L2UCHAR pf = (pmes[2] & 0x10) >> 4;                             /* poll / final flag */
00703                         const char *type;
00704 
00705                         switch (m) {
00706                         case 0x00:
00707                                 type = "UI (Unnumbered Information)";
00708                                 break;
00709 
00710                         case 0x03:
00711                                 type = "DM (Disconnected Mode)";
00712                                 break;
00713 
00714                         case 0x08:
00715                                 type = "DISC (Disconnect)";
00716                                 break;
00717 
00718                         case 0x0c:
00719                                 type = "UA (Unnumbered Acknowledgement)";
00720                                 break;
00721 
00722                         case 0x0f:
00723                                 type = "SABME";
00724                                 break;
00725 
00726                         case 0x11:
00727                                 type = "FRMR (Frame Reject)";
00728                                 break;
00729 
00730                         case 0x17:
00731                                 type = "XID (Exchange Identification)";
00732                                 break;
00733 
00734                         default:
00735                                 type = "Unknown";
00736                         }
00737 
00738 
00739                         MSG_SPRINTF(pbuf, poffset, pleft, "    Type: U Frame (%s)\n          P/F: %d\n", type, pf);
00740 
00741                         if (m == 0x00) {
00742                                 switch (pmes[3]) {
00743                                 case Q921_LAYER_ENT_ID_TEI:
00744                                         type = "TEI Mgmt";
00745                                         break;
00746 
00747                                 case Q921_LAYER_ENT_ID_Q931:
00748                                         type = "Q.931";
00749                                         break;
00750 
00751                                 default:
00752                                         type = "Unknown";
00753                                 }
00754 
00755                                 if (pmes[3] == Q921_LAYER_ENT_ID_TEI) {
00756                                         const char *command = "";
00757 
00758                                         switch (pmes[6]) {
00759                                         case Q921_TEI_ID_REQUEST:
00760                                                 command = "Request";
00761                                                 break;
00762                                         case Q921_TEI_ID_VERIFY:
00763                                                 command = "Verify";
00764                                                 break;
00765                                         case Q921_TEI_ID_CHECKREQ:
00766                                                 command = "Check req";
00767                                                 break;
00768                                         case Q921_TEI_ID_CHECKRESP:
00769                                                 command = "Check resp";
00770                                                 break;
00771                                         case Q921_TEI_ID_REMOVE:
00772                                                 command = "Remove";
00773                                                 break;
00774                                         case Q921_TEI_ID_ASSIGNED:
00775                                                 command = "Assign";
00776                                                 break;
00777                                         case Q921_TEI_ID_DENIED:
00778                                                 command = "Denied";
00779                                                 break;
00780                                         }
00781                                         MSG_SPRINTF(pbuf, poffset, pleft, "    ENT ID: %d (%s), COMMAND: %d (%s), RI: %#x, AI: %d\n",
00782                                                          pmes[3], type, pmes[6], command, (int)((pmes[4] << 8) | pmes[5]), pmes[7] >> 1);
00783                                 }
00784                                 else {
00785                                         MSG_SPRINTF(pbuf, poffset, pleft, "    ENT ID: %d (%s), MESSAGE CONTENT:\n", pmes[3], type);
00786 
00787                                         len = print_hex(pbuf + poffset, pleft, &pmes[3], size - (trunk->Q921HeaderSpace + 3));
00788                                         poffset += len;
00789                                         pleft   -= len;
00790                                 }
00791                         }
00792                 }
00793                 else {
00794                         /*
00795                          * Unknown
00796                          */
00797                         strncat(pbuf + poffset, "  -- unknown frame type --\n", pleft);
00798 
00799                         len = (sizeof(pbuf) - poffset) - strlen(pbuf + poffset);
00800                         if (len > 0) {
00801                                 poffset += len;
00802                                 pleft   -= len;
00803                         } else
00804                                 goto out;
00805                 }
00806 
00807                 MSG_SPRINTF(pbuf, poffset, pleft, "\n    Q.921 state: \"%s\" (%d) [flags: %c%c%c%c]\n", Q921State2Name(link->state), link->state,
00808                                                                                         Q921_CHECK_FLAG(link, Q921_FLAG_ACK_PENDING) ? 'A' : '-',
00809                                                                                         Q921_CHECK_FLAG(link, Q921_FLAG_REJECT) ? 'R' : '-',
00810                                                                                         Q921_CHECK_FLAG(link, Q921_FLAG_PEER_RECV_BUSY) ? 'P' : '-',
00811                                                                                         Q921_CHECK_FLAG(link, Q921_FLAG_RECV_BUSY) ? 'B' : '-');
00812 
00813                 strncat(pbuf + poffset, "----------------------------------------------\n\n", pleft);
00814 
00815                 len = (sizeof(pbuf) - poffset) - strlen(pbuf + poffset);
00816                 if (len > 0) {
00817                         poffset += len;
00818                         pleft   -= len;
00819                 } else
00820                         goto out;
00821 
00822 
00823                 /* concat buffers together */
00824                 len = strlen(pbuf);
00825                 if (len <= left)
00826                         strncat(buf, pbuf, left);
00827                 else
00828                         strncat(buf, "-- packet truncated --\n", left);
00829         }
00830 
00831 out:
00832         buf[sizeof(buf) - 1] = '\0';
00833 
00834         return trunk->Q921LogProc(trunk->PrivateDataLog, level, buf, strlen(buf));
00835 }
00836 
00837 /*****************************************************************************
00838 
00839   Function:     Q921TimeTick
00840 
00841   Description:  Called periodically from an external source to allow the
00842                 stack to process and maintain it's own timers.
00843 
00844   Return Value: none
00845 
00846 *****************************************************************************/
00847 static L2ULONG (*Q921GetTimeProc) (void) = NULL; /* callback for func reading time in ms */
00848 static L2ULONG tLast = {0};
00849 
00850 static L2ULONG Q921GetTime(void)
00851 {
00852         L2ULONG tNow = 0;
00853 
00854         if (Q921GetTimeProc)
00855         {
00856                 tNow = Q921GetTimeProc();
00857                 if (tNow < tLast)       /* wrapped */
00858                 {
00859                         /* TODO */
00860                 }
00861                 tLast = tNow;
00862         }
00863         return tNow;
00864 }
00865 
00866 /*
00867  * T200 handling (per-TEI in PTMP NT mode, tei=0 otherwise)
00868  */
00869 static void Q921T200TimerStart(L2TRUNK trunk, L2UCHAR tei)
00870 {
00871         struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
00872 
00873         if (!link->T200) {
00874                 link->T200 = Q921GetTime() + trunk->T200Timeout;
00875 
00876                 Q921Log(trunk, Q921_LOG_DEBUG, "T200 (timeout: %d msecs) started for TEI %d\n", trunk->T200Timeout, tei);
00877         }
00878 }
00879 
00880 static void Q921T200TimerStop(L2TRUNK trunk, L2UCHAR tei)
00881 {
00882         struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
00883 
00884         link->T200 = 0;
00885 
00886         Q921Log(trunk, Q921_LOG_DEBUG, "T200 stopped for TEI %d\n", tei);
00887 }
00888 
00889 static void Q921T200TimerReset(L2TRUNK trunk, L2UCHAR tei)
00890 {
00891         struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
00892 
00893         link->T200 = Q921GetTime() + trunk->T200Timeout;
00894 
00895         Q921Log(trunk, Q921_LOG_DEBUG, "T200 (timeout: %d msecs) restarted for TEI %d\n", trunk->T200Timeout, tei);
00896 }
00897 
00898 /*
00899  * T203 handling (per-TEI in PTMP NT mode, tei=0 otherwise)
00900  */
00901 static void Q921T203TimerStart(L2TRUNK trunk, L2UCHAR tei)
00902 {
00903         struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
00904 
00905         if (!link->T203) {
00906                 link->T203 = Q921GetTime() + trunk->T203Timeout;
00907 
00908                 Q921Log(trunk, Q921_LOG_DEBUG, "T203 (timeout: %d msecs) started for TEI %d\n", trunk->T203Timeout, tei);
00909         }
00910 }
00911 
00912 static void Q921T203TimerStop(L2TRUNK trunk, L2UCHAR tei)
00913 {
00914         struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
00915 
00916         link->T203 = 0;
00917 
00918         Q921Log(trunk, Q921_LOG_DEBUG, "T203 stopped for TEI %d\n", tei);
00919 }
00920 
00921 static void Q921T203TimerReset(L2TRUNK trunk, L2UCHAR tei)
00922 {
00923         struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
00924 
00925         link->T203 = Q921GetTime() + trunk->T203Timeout;
00926 
00927         Q921Log(trunk, Q921_LOG_DEBUG, "T203 (timeout: %d msecs) restarted for TEI %d\n", trunk->T203Timeout, tei);
00928 }
00929 
00930 /*
00931  * T202 handling (TEI message timeout, TE mode only)
00932  */
00933 static void Q921T202TimerStart(L2TRUNK trunk)
00934 {
00935         if (!trunk->T202) {
00936                 trunk->T202 = Q921GetTime() + trunk->T202Timeout;
00937 
00938                 Q921Log(trunk, Q921_LOG_DEBUG, "T202 (timeout: %d msecs) started\n", trunk->T202Timeout);
00939         }
00940 }
00941 
00942 static void Q921T202TimerStop(L2TRUNK trunk)
00943 {
00944         trunk->T202 = 0;
00945 
00946         Q921Log(trunk, Q921_LOG_DEBUG, "T202 stopped\n");
00947 }
00948 
00949 static void Q921T202TimerReset(L2TRUNK trunk)
00950 {
00951         trunk->T202 = Q921GetTime() + trunk->T202Timeout;
00952 
00953         Q921Log(trunk, Q921_LOG_DEBUG, "T202 (timeout: %d msecs) restarted\n", trunk->T202Timeout);
00954 }
00955 
00956 /*
00957  * T201 handling (TEI management (NT side), per-TEI)
00958  */
00959 static void Q921T201TimerStart(L2TRUNK trunk, L2UCHAR tei)
00960 {
00961         struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
00962 
00963         if (!link->T201) {
00964                 link->T201 = Q921GetTime() + trunk->T201Timeout;
00965 
00966                 Q921Log(trunk, Q921_LOG_DEBUG, "T201 (timeout: %d msecs) started for TEI %d\n", trunk->T201Timeout, tei);
00967         }
00968 }
00969 
00970 static void Q921T201TimerStop(L2TRUNK trunk, L2UCHAR tei)
00971 {
00972         struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
00973 
00974         link->T201 = 0;
00975 
00976         Q921Log(trunk, Q921_LOG_DEBUG, "T201 stopped for TEI %d\n", tei);
00977 }
00978 
00979 #ifdef __UNUSED_FOR_NOW__
00980 static void Q921T201TimerReset(L2TRUNK trunk, L2UCHAR tei)
00981 {
00982         struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
00983 
00984         link->T201 = Q921GetTime() + trunk->T201Timeout;
00985 
00986         Q921Log(trunk, Q921_LOG_DEBUG, "T201 (timeout: %d msecs) restarted for TEI %d\n", trunk->T201Timeout, tei);
00987 }
00988 #endif
00989 
00990 /*
00991  * TM01 handling (Datalink inactivity shutdown timer)
00992  */
00993 static void Q921TM01TimerStart(L2TRUNK trunk, L2UCHAR tei)
00994 {
00995         struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
00996 
00997         if (!link->TM01) {
00998                 link->TM01 = Q921GetTime() + trunk->TM01Timeout;
00999 
01000                 Q921Log(trunk, Q921_LOG_DEBUG, "TM01 (timeout: %d msecs) started for TEI %d\n", trunk->TM01Timeout, tei);
01001         }
01002 }
01003 
01004 #ifdef __UNUSED_FOR_NOW__
01005 static void Q921TM01TimerStop(L2TRUNK trunk, L2UCHAR tei)
01006 {
01007         struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
01008 
01009         link->TM01 = 0;
01010 
01011         Q921Log(trunk, Q921_LOG_DEBUG, "TM01 stopped for TEI %d\n", tei);
01012 }
01013 #endif
01014 
01015 static void Q921TM01TimerReset(L2TRUNK trunk, L2UCHAR tei)
01016 {
01017         struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
01018 
01019         link->TM01 = Q921GetTime() + trunk->TM01Timeout;
01020 
01021         Q921Log(trunk, Q921_LOG_DEBUG, "TM01 (timeout: %d msecs) restarted for TEI %d\n", trunk->TM01Timeout, tei);
01022 }
01023 
01024 /*
01025  * Expiry callbacks
01026  */
01027 static void Q921T200TimerExpire(L2TRUNK trunk, L2UCHAR tei)
01028 {
01029         struct Q921_Link *link   = Q921_LINK_CONTEXT(trunk, tei);
01030         struct Q921_Link *trlink = Q921_TRUNK_CONTEXT(trunk);
01031 
01032         Q921Log(trunk, Q921_LOG_DEBUG, "T200 expired for TEI %d (trunk TEI %d)\n", tei, trlink->tei);
01033 
01034         /* Stop timer first */
01035         Q921T200TimerStop(trunk, tei);
01036 
01037         switch (link->state) {
01038         case Q921_STATE_AWAITING_ESTABLISHMENT:
01039                 if (link->N200 >= trunk->N200Limit) {
01040                         /* Discard I queue */
01041                         MFIFOClear(link->IFrameQueue);
01042 
01043                         /* MDL-Error indication (G) */
01044                         Q921Log(trunk, Q921_LOG_ERROR, "Failed to establish Q.921 link in %d retries\n", link->N200);
01045 
01046                         /* DL-Release indication */
01047                         Q921Tx23Proc(trunk, Q921_DL_RELEASE, tei, NULL, 0);
01048 
01049                         /* change state (no action) */
01050                         Q921ChangeState(trunk, Q921_STATE_TEI_ASSIGNED, tei);
01051 
01052 #ifdef Q921_STATISTICS
01053                         /* update counter */
01054                         Q921StatsIncrementCounter(link, Q921_STATS_N200);
01055 #endif
01056                 } else {
01057                         /* Increment retry counter */
01058                         link->N200++;
01059 
01060                         /* Send SABME */
01061                         Q921SendSABME(trunk,
01062                                         trunk->sapi,
01063                                         Q921_COMMAND(trunk),
01064                                         tei,
01065                                         1);
01066 
01067                         /* Start T200 */
01068                         Q921T200TimerStart(trunk, tei);
01069                 }
01070                 break;
01071 
01072         case Q921_STATE_MULTIPLE_FRAME_ESTABLISHED:
01073                 link->N200 = 0;
01074 
01075                 if (!Q921_CHECK_FLAG(link, Q921_FLAG_PEER_RECV_BUSY)) {
01076                         /* get last transmitted I frame */
01077 
01078                         /* V(S) = V(S) - 1 */
01079                         Q921_DEC_COUNTER(link->vs);
01080 
01081                         /* retransmit I frame */
01082 
01083                         /* V(S) = V(S) + 1 (done by Q921SendI() ) */
01084                         //Q921_INC_COUNTER(link->vs);
01085 
01086                         /* clear acknowledge pending */
01087                         Q921_CLEAR_FLAG(link, Q921_FLAG_ACK_PENDING);
01088 
01089                         /* Start T200 */
01090                         Q921T200TimerStart(trunk, tei);
01091                 } else {
01092                         /* transmit enquiry */
01093                         Q921SendEnquiry(trunk, tei);
01094                 }
01095 
01096                 /* increment counter */
01097                 link->N200++;
01098 
01099                 /* change state (no action) */
01100                 Q921ChangeState(trunk, Q921_STATE_TIMER_RECOVERY, tei);
01101                 break;
01102 
01103         case Q921_STATE_TIMER_RECOVERY:
01104                 if (link->N200 == trunk->N200Limit) {
01105                         /* MDL Error indication (I) */
01106 
01107                         /* Establish data link */
01108                         Q921EstablishDataLink(trunk, tei);
01109 
01110                         /* Clear L3 initiated */
01111                         Q921_CLEAR_FLAG(link, Q921_FLAG_L3_INITIATED);
01112 
01113                         /* change state (no action) */
01114                         Q921ChangeState(trunk, Q921_STATE_AWAITING_ESTABLISHMENT, tei);
01115 
01116 #ifdef Q921_STATISTICS
01117                         /* update counter */
01118                         Q921StatsIncrementCounter(link, Q921_STATS_N200);
01119 #endif
01120                 } else {
01121                         if (link->vs == link->va) {
01122                                 /* transmit enquiry */
01123                                 Q921SendEnquiry(trunk, tei);
01124 
01125                         } else if (!Q921_CHECK_FLAG(link, Q921_FLAG_PEER_RECV_BUSY)) {
01126                                 /* get last transmitted frame */
01127 
01128                                 /* V(S) = V(S) - 1 */
01129                                 Q921_DEC_COUNTER(link->vs);
01130 
01131                                 /* retrans frame */
01132 
01133                                 /* V(S) = V(S) + 1 (done by Q921SendI() ) */
01134                                 //Q921_INC_COUNTER(link->vs);
01135 
01136                                 /* clear acknowledge pending */
01137                                 Q921_CLEAR_FLAG(link, Q921_FLAG_ACK_PENDING);
01138 
01139                                 /* Start T200 */
01140                                 Q921T200TimerStart(trunk, tei);
01141                         }
01142 
01143                         /* increment counter */
01144                         link->N200++;
01145 
01146                         /* no state change */
01147                 }
01148                 break;
01149 
01150         default:
01151                 break;
01152         }
01153 
01154 #ifdef Q921_STATISTICS
01155         /* update counter*/
01156         Q921StatsIncrementCounter(link, Q921_STATS_T200);
01157 #endif
01158 }
01159 
01160 static void Q921T203TimerExpire(L2TRUNK trunk, L2UCHAR tei)
01161 {
01162         struct Q921_Link *link   = Q921_LINK_CONTEXT(trunk, tei);
01163         struct Q921_Link *trlink = Q921_TRUNK_CONTEXT(trunk);
01164 
01165         Q921Log(trunk, Q921_LOG_DEBUG, "T203 expired for TEI %d (trunk TEI %d)\n", tei, trlink->tei);
01166 
01167         /* Stop Timer first */
01168         Q921T203TimerStop(trunk, tei);
01169 
01170         switch (link->state) {
01171         case Q921_STATE_MULTIPLE_FRAME_ESTABLISHED:
01172                 /* Send Enquiry */
01173                 Q921SendEnquiry(trunk, tei);
01174 
01175                 /* RC = 0 */
01176                 link->N200 = 0;
01177 
01178                 /* no state change */
01179                 break;
01180 
01181         default:
01182                 break;
01183         }
01184 
01185 #ifdef Q921_STATISTICS
01186         /* update counter*/
01187         Q921StatsIncrementCounter(link, Q921_STATS_T203);
01188 #endif
01189 }
01190 
01191 static void Q921T202TimerExpire(L2TRUNK trunk)
01192 {
01193         struct Q921_Link *link = Q921_TRUNK_CONTEXT(trunk);
01194 
01195         Q921T202TimerReset(trunk);
01196 
01197         Q921Log(trunk, Q921_LOG_DEBUG, "T202 expired for Q.921 trunk with TEI %d\n", link->tei);
01198 
01199         /* todo: implement resend counter */
01200 
01201         switch (link->state) {
01202         case Q921_STATE_TEI_ASSIGNED:   /* Tei identity verify timeout */
01203                 Q921TeiSendVerifyRequest(trunk);
01204                 break;
01205 
01206         default:                        /* Tei assignment request timeout (TODO: refine) */
01207 
01208                 if (trunk->N202 >= trunk->N202Limit) {
01209                         /* Too many retransmits, reset counter, stop timer and handle case (TODO) */
01210                         trunk->N202 = 0;
01211 
01212                         Q921T202TimerStop(trunk);
01213 
01214 #ifdef Q921_STATISTICS
01215                         /* update counter */
01216                         Q921StatsIncrementCounter(link, Q921_STATS_N202);
01217 #endif
01218                         return;
01219                 }
01220                 Q921TeiSendAssignRequest(trunk);
01221 
01222                 trunk->N202++;
01223         }
01224 
01225 #ifdef Q921_STATISTICS
01226         /* update counter */
01227         Q921StatsIncrementCounter(link, Q921_STATS_T202);
01228 #endif
01229 }
01230 
01231 static void Q921T201TimerExpire(L2TRUNK trunk, L2UCHAR tei)
01232 {
01233         struct Q921_Link *link   = Q921_LINK_CONTEXT(trunk, tei);
01234         struct Q921_Link *trlink = Q921_TRUNK_CONTEXT(trunk);
01235 
01236         Q921Log(trunk, Q921_LOG_DEBUG, "T201 expired for TEI %d (trunk TEI: %d)\n", tei, trlink->tei);
01237 
01238         Q921T201TimerStop(trunk, tei);
01239 
01240         /* NOTE: abusing N202 for this */
01241         if (link->N202 < trunk->N202Limit) {
01242                 /* send check request */
01243                 Q921TeiSendCheckRequest(trunk, tei);
01244 
01245                 /* increment counter */
01246                 link->N202++;
01247         } else {
01248                 /* put context in STOPPED state */
01249                 Q921ChangeState(trunk, Q921_STATE_STOPPED, tei);
01250 
01251                 /* NOTE: should we clear the link too? */
01252                 memset(link, 0, sizeof(struct Q921_Link));
01253 
01254                 /* mark TEI free */
01255                 trunk->tei_map[tei] = 0;
01256 
01257 #ifdef Q921_STATISTICS
01258                 /* update counter */
01259                 Q921StatsIncrementCounter(link, Q921_STATS_N202);
01260 #endif
01261         }
01262 #ifdef Q921_STATISTICS
01263         /* update counter */
01264         Q921StatsIncrementCounter(trlink, Q921_STATS_T201);
01265 #endif
01266 }
01267 
01268 #ifdef __UNUSED_FOR_NOW__
01269 static void Q921TM01TimerExpire(L2TRUNK trunk, L2UCHAR tei)
01270 {
01271         struct Q921_Link *link   = Q921_LINK_CONTEXT(trunk, tei);
01272         struct Q921_Link *trlink = Q921_TRUNK_CONTEXT(trunk);
01273 
01274         Q921Log(trunk, Q921_LOG_DEBUG, "TM01 expired for TEI %d (trunk TEI: %d)\n", tei, trlink->tei);
01275 
01276         /* Restart TM01 */
01277         Q921TM01TimerReset(trunk, tei);
01278 
01279         switch (link->state) {
01280         case Q921_STATE_MULTIPLE_FRAME_ESTABLISHED:
01281         case Q921_STATE_TIMER_RECOVERY:
01282 /*
01283  * NT-only, needs more support from L3
01284  */
01285 #if 0
01286                 /* No activity, shutdown link */
01287                 Q921SendDISC(trunk, trunk->sapi, Q921_COMMAND(trunk), tei, 1);
01288 
01289                 /* clear I queue */
01290                 MFIFOClear(link->IFrameQueue);
01291 
01292                 /* change state */
01293                 Q921ChangeState(trunk, Q921_STATE_AWAITING_RELEASE, tei);
01294 #endif
01295                 break;
01296 
01297         default:
01298                 break;
01299         }
01300 
01301 #ifdef Q921_STATISTICS
01302         /* update counter */
01303         Q921StatsIncrementCounter(link, Q921_STATS_TM01);
01304 #endif
01305 }
01306 #endif
01307 
01308 /*
01309  * Timer Tick function
01310  */
01311 Q921_API void Q921TimerTick(L2TRUNK trunk)
01312 {
01313         struct Q921_Link *link;
01314         L2ULONG tNow = Q921GetTime();
01315         int numlinks = Q921_IS_PTMP_NT(trunk) ? Q921_TEI_MAX : 1;
01316         int x;
01317 
01318         for (x = 0; x <= numlinks; x++) {
01319                 link = Q921_LINK_CONTEXT(trunk, x);
01320 
01321                 /* TODO: check if TEI is assigned and skip check if not (speedup!) */
01322                 if (link->state == Q921_STATE_STOPPED)
01323                         continue;
01324 
01325                 if (link->T200 && tNow > link->T200) {
01326                         Q921T200TimerExpire(trunk, link->tei);
01327                 }
01328                 if (link->T203 && tNow > link->T203) {
01329                         Q921T203TimerExpire(trunk, link->tei);
01330                 }
01331 
01332                 if (Q921_IS_PTMP_NT(trunk) && link->tei) {
01333                         if (link->T201 && tNow > link->T201) {
01334                                 Q921T201TimerExpire(trunk, link->tei);
01335                         }
01336                 }
01337 
01338                 if (!Q921_IS_PTMP_NT(trunk)) {
01339                         if (trunk->T202 && tNow > trunk->T202) {
01340                                 Q921T202TimerExpire(trunk);
01341                         }
01342                 }
01343 
01344                 /* Send enqueued I frame, if available */
01345                 Q921SendQueuedIFrame(trunk, link->tei);
01346 
01347                 /* Send ack if pending */
01348                 Q921AcknowledgePending(trunk, link->tei);
01349         }
01350 
01351 }
01352 
01353 Q921_API void Q921SetGetTimeCB(L2ULONG (*callback)(void))
01354 {
01355     Q921GetTimeProc = callback;
01356 }
01357 
01358 /*****************************************************************************
01359 
01360   Function:     Q921QueueHDLCFrame
01361 
01362   Description:  Called to receive and queue an incoming HDLC frame. Will
01363                 queue this in Q921HDLCInQueue. The called must either call
01364                 Q921Rx12 directly afterwards or signal Q921Rx12 to be called
01365                 later. Q921Rx12 will read from the same queue and process
01366                 the frame.
01367 
01368                 This function assumes that the message contains header
01369                 space. This is removed for internal Q921 processing, but
01370                 must be keept for I frames.
01371 
01372   Parameters:   trunk   trunk #
01373                 b       ptr to frame;
01374                 size    size of frame in bytes
01375 
01376 *****************************************************************************/
01377 Q921_API int Q921QueueHDLCFrame(L2TRUNK trunk, L2UCHAR *b, L2INT size)
01378 {
01379     return MFIFOWriteMes(trunk->HDLCInQueue, b, size);
01380 }
01381 
01387 static int Q921EnqueueI(L2TRUNK trunk, L2UCHAR Sapi, char cr, L2UCHAR Tei, char pf, L2UCHAR *mes, L2INT size)
01388 {
01389         struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, Tei);
01390 
01391         /* I frame header */
01392         mes[trunk->Q921HeaderSpace+0] = ((Sapi << 2) & 0xfc) | ((cr << 1) & 0x02);
01393         mes[trunk->Q921HeaderSpace+1] = (Tei << 1) | 0x01;
01394         mes[trunk->Q921HeaderSpace+2] = 0x00;
01395         mes[trunk->Q921HeaderSpace+3] = (pf & 0x01);
01396 
01397         Q921Log(trunk, Q921_LOG_DEBUG, "Enqueueing I frame for TEI %d [%d]\n", link->tei, Tei);
01398 
01399         /* transmit queue, (TODO: check for full condition!) */
01400         MFIFOWriteMes(link->IFrameQueue, mes, size);
01401 
01402         /* try to send queued frame */
01403         Q921SendQueuedIFrame(trunk, link->tei);
01404 
01405         return 1;
01406 }
01407 
01412 static int Q921SendQueuedIFrame(L2TRUNK trunk, L2UCHAR tei)
01413 {
01414         struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
01415 
01416         L2INT size = 0;
01417         L2UCHAR *mes;
01418 
01419         if (MFIFOGetMesCount(link->IFrameQueue) == 0) {
01420                 return 0;
01421         }
01422 
01423         /* Link ready? */
01424         if (link->state != Q921_STATE_MULTIPLE_FRAME_ESTABLISHED) {
01425                 return 0;
01426         }
01427 
01428         /* peer receiver busy? */
01429         if (Q921_CHECK_FLAG(link, Q921_FLAG_PEER_RECV_BUSY)) {
01430                 return 0;
01431         }
01432 
01433         /* V(S) = V(A) + k? */
01434         if (link->vs == ((link->va + trunk->k) % 128)) {
01435                 Q921Log(trunk, Q921_LOG_WARNING, "Maximum number (%d) of outstanding I frames reached for TEI %d\n", trunk->k, tei);
01436                 return 0;
01437         }
01438 
01439         mes = MFIFOGetMesPtr(link->IFrameQueue, &size);
01440         if (mes) {
01441                 /* Fill in + update counter values */
01442                 mes[trunk->Q921HeaderSpace+2]  = link->vs << 1;
01443                 mes[trunk->Q921HeaderSpace+3] |= link->vr << 1;
01444 
01445                 /* Set TEI (may have changed) */
01446                 mes[trunk->Q921HeaderSpace+1] = (link->tei << 1) | 0x01;
01447 
01448                 if (MFIFOGetMesCount(link->IFrameQueue) == 0) {
01449                         /* clear I frame queued */
01450                 }
01451 
01452 #ifdef Q921_STATISTICS_EXTENDED
01453                 Q921StatsIncrementCounter(link, Q921_STATS_SEND_I);
01454 #endif
01455                 /* Send I frame */
01456                 Q921Tx21Proc(trunk, mes, size);
01457 
01458                 /* V(S) = V(S) + 1 */
01459                 Q921_INC_COUNTER(link->vs);
01460 
01461                 /* clear acknowledge pending */
01462                 Q921_CLEAR_FLAG(link, Q921_FLAG_ACK_PENDING);
01463 
01464                 /* T200 running? */
01465                 if (!link->T200) {
01466                         /* Stop T203, Start T200 */
01467                         Q921T200TimerStart(trunk, tei);
01468                         Q921T203TimerStop(trunk, tei);
01469                 }
01470 
01471                 /* put frame into resend queue */
01472                 MFIFOWriteMesOverwrite(link->IFrameResendQueue, mes, size);
01473 
01474                 /* dequeue frame */
01475                 MFIFOKillNext(link->IFrameQueue);
01476 
01477                 /* Restart TM01 */
01478                 if (Q921_IS_NT(trunk)) {
01479                         Q921TM01TimerReset(trunk, tei);
01480                 }
01481 
01482                 /* no state change */
01483                 return 1;
01484         }
01485 
01486         return 0;
01487 }
01488 
01489 
01494 static int Q921SendQueuedUIFrame(L2TRUNK trunk, L2UCHAR tei)
01495 {
01496         struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
01497 
01498         L2INT size = 0;
01499         L2UCHAR *mes;
01500 
01501         if (MFIFOGetMesCount(link->UIFrameQueue) == 0) {
01502                 return 0;
01503         }
01504 
01505         /* Link ready? */
01506         if (link->state < Q921_STATE_TEI_ASSIGNED) {
01507                 return 0;
01508         }
01509 
01510         mes = MFIFOGetMesPtr(link->UIFrameQueue, &size);
01511         if (mes) {
01512                 /* Get modifier function id */
01513                 L2UCHAR m  = (mes[trunk->Q921HeaderSpace+2] & 0xe0) >> 3 | (mes[trunk->Q921HeaderSpace+2] & 0x0c) >> 2;
01514 
01515                 /* Set TEI (may have changed) */
01516                 mes[trunk->Q921HeaderSpace+1] = (link->tei << 1) | 0x01;
01517 
01518 
01519                 if (MFIFOGetMesCount(link->UIFrameQueue) == 0) {
01520                         /* clear UI frame queued */
01521                 }
01522 
01523 #ifdef Q921_STATISTICS_EXTENDED
01524                 Q921StatsIncrementCounter(link, Q921_STATS_SEND_U);
01525 #endif
01526                 /* Send UI frame */
01527                 Q921Tx21Proc(trunk, mes, size);
01528 
01529                 /* dequeue frame */
01530                 MFIFOKillNext(link->UIFrameQueue);
01531 
01532                 /* handle SABME */
01533                 switch (link->state) {
01534                 case Q921_STATE_TEI_ASSIGNED:
01535                         if (m == 0x0f) {        /* Queued SABME */
01536                                 Q921ChangeState(trunk, Q921_STATE_AWAITING_ESTABLISHMENT, link->tei);
01537                         }
01538                         break;
01539                 default:
01540                         /* no state change */
01541                         break;
01542                 }
01543                 return 1;
01544         }
01545 
01546         return 0;
01547 }
01548 
01549 
01554 static int Q921SendS(L2TRUNK trunk, L2UCHAR Sapi, char cr, L2UCHAR Tei, char pf, L2UCHAR sv, L2UCHAR *mes, L2INT size)
01555 {
01556         struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, Tei);
01557 
01558         if (!Q921_IS_READY(link)) {
01559                 /* don't even bother trying */
01560                 Q921Log(trunk, Q921_LOG_DEBUG, "Link not ready, discarding S frame for TEI %d\n", Tei);
01561                 return 0;
01562         }
01563 
01564         /* S frame header */
01565         mes[trunk->Q921HeaderSpace+0] = ((Sapi << 2) & 0xfc) | ((cr << 1) & 0x02);
01566         mes[trunk->Q921HeaderSpace+1] = (Tei << 1) | 0x01;
01567         mes[trunk->Q921HeaderSpace+2] = ((sv << 2) & 0x0c) | 0x01;
01568         mes[trunk->Q921HeaderSpace+3] = (link->vr << 1) | (pf & 0x01);
01569 
01570 #ifdef Q921_STATISTICS_EXTENDED
01571         Q921StatsIncrementCounter(link, Q921_STATS_SEND_S);
01572 #endif
01573         return Q921Tx21Proc(trunk, mes, size);
01574 }
01575 
01576 
01581 static int Q921SendU(L2TRUNK trunk, L2UCHAR Sapi, char cr, L2UCHAR Tei, char pf, L2UCHAR m, L2UCHAR *mes, L2INT size)
01582 {
01583         struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, Tei);
01584 
01585         /* U frame header */
01586         mes[trunk->Q921HeaderSpace+0] = ((Sapi << 2) & 0xfc) | ((cr << 1) & 0x02);
01587         mes[trunk->Q921HeaderSpace+1] = (Tei << 1) | 0x01;
01588         mes[trunk->Q921HeaderSpace+2] = ((m << 3) & 0xe0) | ((pf << 4) & 0x10) | ((m << 2) & 0x0c) | 0x03;
01589 
01590         /* link not ready? enqueue non-TEI-mgmt UI (DL-UNIT DATA) frames */
01591         if ((m == 0x00 || m == 0x0f) && Sapi != Q921_SAPI_TEI && link->state < Q921_STATE_TEI_ASSIGNED) {
01592 
01593                 /* write frame to queue */
01594                 MFIFOWriteMes(link->UIFrameQueue, mes, size);
01595 
01596                 Q921Log(trunk, Q921_LOG_DEBUG, "Link not ready, UI Frame of size %d bytes queued for TEI %d\n", size, Tei);
01597                 return 1;
01598         }
01599 
01600 #ifdef Q921_STATISTICS_EXTENDED
01601         Q921StatsIncrementCounter(link, Q921_STATS_SEND_U);
01602 #endif
01603         return Q921Tx21Proc(trunk, mes, size);
01604 }
01605 
01606 Q921_API int Q921IsEstablished(L2TRUNK trunk, L2UCHAR tei)
01607 {
01608         struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei); /* TODO: need real link tei for NT mode */
01609 
01610         return (link->state >= Q921_STATE_MULTIPLE_FRAME_ESTABLISHED);
01611 }
01612 
01613 Q921_API int Q921Establish(L2TRUNK trunk, L2UCHAR tei)
01614 {
01615         struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei); /* TODO: need real link tei for NT mode */
01616         int res = 0;
01617 
01618         Q921Log(trunk, Q921_LOG_DEBUG, "DL_ESTABLISH from Q.931, tei: %d, size: %d\n", tei);
01619 
01620         /*
01621          * Hmm...
01622          */
01623         switch (link->state) {
01624         case Q921_STATE_TEI_ASSIGNED:
01625                 if (!Q921_IS_NT(trunk)) {
01626                         /* establish data link */
01627                         Q921EstablishDataLink(trunk, link->tei);
01628 
01629                         /* Set layer 3 initiated */
01630                         Q921_SET_FLAG(link, Q921_FLAG_L3_INITIATED);
01631 
01632                         /* change state (no action) */
01633                         Q921ChangeState(trunk, Q921_STATE_AWAITING_ESTABLISHMENT, link->tei);
01634                 }
01635                 break;
01636         case Q921_STATE_AWAITING_ESTABLISHMENT:
01637                 if (!Q921_IS_NT(trunk)) {
01638                         /* Discard I queue */
01639                         MFIFOClear(link->IFrameQueue);
01640 
01641                         /* Set layer 3 initiated */
01642                         Q921_SET_FLAG(link, Q921_FLAG_L3_INITIATED);
01643                 }
01644                 break;
01645         case Q921_STATE_MULTIPLE_FRAME_ESTABLISHED:
01646         case Q921_STATE_TIMER_RECOVERY:
01647                 if (!Q921_IS_NT(trunk)) {
01648                         /* Discard I queue */
01649                         MFIFOClear(link->IFrameQueue);
01650 
01651                         /* establish data link */
01652                         Q921EstablishDataLink(trunk, link->tei);
01653 
01654                         /* Set layer 3 initiated */
01655                         Q921_SET_FLAG(link, Q921_FLAG_L3_INITIATED);
01656 
01657                         /* change state (no action) */
01658                         Q921ChangeState(trunk, Q921_STATE_AWAITING_ESTABLISHMENT, link->tei);
01659                 }
01660                 break;
01661         default:
01662                 break;
01663         }
01664         return res;
01665 }
01666 
01667 Q921_API int Q921Release(L2TRUNK trunk, L2UCHAR tei)
01668 {
01669         struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei); /* TODO: need real link tei for NT mode */
01670         int res = 0;
01671 
01672         Q921Log(trunk, Q921_LOG_DEBUG, "DL_RELEASE from Q.931, tei: %d, size: %d\n", tei);
01673 
01674         switch (link->state) {
01675         case Q921_STATE_TEI_ASSIGNED:
01676                 /* send DL-RELEASE confirm */
01677                 Q921Tx23Proc(trunk, Q921_DL_RELEASE, tei, NULL, 0);
01678                 break;
01679         case Q921_STATE_MULTIPLE_FRAME_ESTABLISHED:
01680         case Q921_STATE_TIMER_RECOVERY:
01681                 if (!Q921_IS_NT(trunk)) {
01682                         /* Discard I queue */
01683                         MFIFOClear(link->IFrameQueue);
01684 
01685                         /* RC = 0 */
01686                         link->N200 = 0;
01687 
01688                         /* send DISC command */
01689                         Q921SendDISC(trunk, trunk->sapi, Q921_COMMAND(trunk), link->tei, 1);
01690 
01691                         /* Stop T203, restart T200 */
01692                         if (link->state == Q921_STATE_MULTIPLE_FRAME_ESTABLISHED) {
01693                                 Q921T203TimerStop(trunk, link->tei);
01694                         }
01695                         Q921T200TimerReset(trunk, link->tei);
01696 
01697                         /* change state */
01698                         Q921ChangeState(trunk, Q921_STATE_AWAITING_RELEASE, link->tei);
01699                 }
01700                 break;
01701         default:
01702                 break;
01703         }
01704         return res;
01705 }
01706 
01710 Q921_API int Q921Rx32(L2TRUNK trunk, Q921DLMsg_t ind, L2UCHAR tei, L2UCHAR * Mes, L2INT Size)
01711 {
01712         struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei); /* TODO: need real link tei for NT mode */
01713         L2INT res = 0;
01714 
01715         Q921Log(trunk, Q921_LOG_DEBUG, "Got frame from Q.931, type: %d, tei: %d, size: %d\n", ind, tei, Size);
01716 
01717         switch (ind) {
01718         case Q921_DL_ESTABLISH:
01719                 return Q921Establish(trunk, tei);
01720 #if 0
01721                 /*
01722                  * Hmm...
01723                  */
01724                 switch (link->state) {
01725                 case Q921_STATE_TEI_ASSIGNED:
01726                         if (!Q921_IS_NT(trunk)) {
01727                                 /* establish data link */
01728                                 Q921EstablishDataLink(trunk, link->tei);
01729 
01730                                 /* Set layer 3 initiated */
01731                                 Q921_SET_FLAG(link, Q921_FLAG_L3_INITIATED);
01732 
01733                                 /* change state (no action) */
01734                                 Q921ChangeState(trunk, Q921_STATE_AWAITING_ESTABLISHMENT, link->tei);
01735                         }
01736                         break;
01737 
01738                 case Q921_STATE_AWAITING_ESTABLISHMENT:
01739                         if (!Q921_IS_NT(trunk)) {
01740                                 /* Discard I queue */
01741                                 MFIFOClear(link->IFrameQueue);
01742 
01743                                 /* Set layer 3 initiated */
01744                                 Q921_SET_FLAG(link, Q921_FLAG_L3_INITIATED);
01745                         }
01746                         break;
01747 
01748                 case Q921_STATE_MULTIPLE_FRAME_ESTABLISHED:
01749                 case Q921_STATE_TIMER_RECOVERY:
01750                         if (!Q921_IS_NT(trunk)) {
01751                                 /* Discard I queue */
01752                                 MFIFOClear(link->IFrameQueue);
01753 
01754                                 /* establish data link */
01755                                 Q921EstablishDataLink(trunk, link->tei);
01756 
01757                                 /* Set layer 3 initiated */
01758                                 Q921_SET_FLAG(link, Q921_FLAG_L3_INITIATED);
01759 
01760                                 /* change state (no action) */
01761                                 Q921ChangeState(trunk, Q921_STATE_AWAITING_ESTABLISHMENT, link->tei);
01762                         }
01763                         break;
01764 
01765                 default:
01766                         break;
01767                 }
01768                 break;
01769 #endif
01770         case Q921_DL_RELEASE:
01771                 return Q921Release(trunk, tei);
01772 #if 0
01773                 switch (link->state) {
01774                 case Q921_STATE_TEI_ASSIGNED:
01775                         /* send DL-RELEASE confirm */
01776                         Q921Tx23Proc(trunk, Q921_DL_RELEASE, tei, NULL, 0);
01777                         break;
01778 
01779                 case Q921_STATE_MULTIPLE_FRAME_ESTABLISHED:
01780                 case Q921_STATE_TIMER_RECOVERY:
01781                         if (!Q921_IS_NT(trunk)) {
01782                                 /* Discard I queue */
01783                                 MFIFOClear(link->IFrameQueue);
01784 
01785                                 /* RC = 0 */
01786                                 link->N200 = 0;
01787 
01788                                 /* send DISC command */
01789                                 Q921SendDISC(trunk, trunk->sapi, Q921_COMMAND(trunk), link->tei, 1);
01790 
01791                                 /* Stop T203, restart T200 */
01792                                 if (link->state == Q921_STATE_MULTIPLE_FRAME_ESTABLISHED) {
01793                                         Q921T203TimerStop(trunk, link->tei);
01794                                 }
01795                                 Q921T200TimerReset(trunk, link->tei);
01796 
01797                                 /* change state */
01798                                 Q921ChangeState(trunk, Q921_STATE_AWAITING_RELEASE, link->tei);
01799                         }
01800                         break;
01801 
01802                 default:
01803                         break;
01804                 }
01805                 break;
01806 #endif
01807         case Q921_DL_DATA:      /* DL-DATA request */
01808                 res = Q921EnqueueI(trunk,
01809                                 trunk->sapi,
01810                                 Q921_COMMAND(trunk),
01811                                 link->tei,
01812                                 0,
01813                                 Mes,
01814                                 Size);
01815 
01816                 if (link->state < Q921_STATE_TEI_ASSIGNED) {
01817                         /* Implicit DL-ESTABLISH request */
01818 
01819                         /* establish data link */
01820                         Q921EstablishDataLink(trunk, link->tei);
01821 
01822                         /* Set layer 3 initiated */
01823                         Q921_SET_FLAG(link, Q921_FLAG_L3_INITIATED);
01824                 }
01825                 else if (link->state < Q921_STATE_MULTIPLE_FRAME_ESTABLISHED) {
01826                         /* Treat as implicit DL-ESTABLISH request */
01827 
01828                         /* establish data link */
01829                         Q921EstablishDataLink(trunk, link->tei);
01830 
01831                         /* Set layer 3 initiated */
01832                         Q921_SET_FLAG(link, Q921_FLAG_L3_INITIATED);
01833 
01834                         /* change state (no action) */
01835                         Q921ChangeState(trunk, Q921_STATE_AWAITING_ESTABLISHMENT, link->tei);
01836                 }
01837                 break;
01838 
01839         case Q921_DL_UNIT_DATA:         /* DL-UNIT DATA request */
01840                 res = Q921SendUN(trunk,
01841                                 trunk->sapi,
01842                                 Q921_COMMAND(trunk),
01843                                 Q921_TEI_BCAST,
01844                                 0,
01845                                 Mes,
01846                                 Size);
01847                 /* NOTE: Let the other side initiate link establishment */
01848                 break;
01849 
01850         default:
01851                 break;
01852         }
01853 
01854         return res;
01855 }
01856 /*****************************************************************************
01857 
01858   Function:     Q921SendRR
01859 
01860   Description:  Compose and send Receive Ready.
01861 
01862   Parameters:   trunk       trunk #
01863                 Sapi        Sapi
01864                 cr          C/R field.
01865                 Tei         Tei.
01866                 pf          P/F fiels octet 5
01867 
01868   Return Value: 0 if failed, 1 if Send.
01869 
01870 *****************************************************************************/
01871 
01872 static int Q921SendRR(L2TRUNK trunk, int Sapi, int cr, int Tei, int pf)
01873 {
01874         L2UCHAR mes[25];
01875 
01876 #ifdef Q921_STATISTICS_EXTENDED
01877         Q921StatsIncrementCounter(Q921_LINK_CONTEXT(trunk, Tei), Q921_STATS_SEND_RR);
01878 #endif
01879         return Q921SendS(trunk, Sapi, cr, Tei, pf, 0x00, mes, trunk->Q921HeaderSpace+4);
01880 }
01881 
01882 /*****************************************************************************
01883 
01884   Function:     Q921SendRNR
01885 
01886   Description:  Compose and send Receive Nor Ready
01887 
01888   Parameters:   trunk       trunk #
01889                 Sapi        Sapi
01890                 cr          C/R field.
01891                 Tei         Tei.
01892                 pf          P/F fiels octet 5
01893 
01894   Return Value: 0 if failed, 1 if Send.
01895 
01896 *****************************************************************************/
01897 static int Q921SendRNR(L2TRUNK trunk, int Sapi, int cr, int Tei, int pf)
01898 {
01899         L2UCHAR mes[25];
01900 
01901 #ifdef Q921_STATISTICS_EXTENDED
01902         Q921StatsIncrementCounter(Q921_LINK_CONTEXT(trunk, Tei), Q921_STATS_SEND_RNR);
01903 #endif
01904         return Q921SendS(trunk, Sapi, cr, Tei, pf, 0x01, mes, trunk->Q921HeaderSpace+4);
01905 }
01906 
01907 /*****************************************************************************
01908 
01909   Function:     Q921SendREJ
01910 
01911   Description:  Compose and Send Reject.
01912 
01913   Parameters:   trunk       trunk #
01914                 Sapi        Sapi
01915                 cr          C/R field.
01916                 Tei         Tei.
01917                 pf          P/F fiels octet 5
01918 
01919   Return Value: 0 if failed, 1 if Send.
01920 
01921 *****************************************************************************/
01922 static int Q921SendREJ(L2TRUNK trunk, int Sapi, int cr, int Tei, int pf)
01923 {
01924         L2UCHAR mes[25];
01925 
01926 #ifdef Q921_STATISTICS_EXTENDED
01927         Q921StatsIncrementCounter(Q921_LINK_CONTEXT(trunk, Tei), Q921_STATS_SEND_REJ);
01928 #endif
01929         return Q921SendS(trunk, Sapi, cr, Tei, pf, 0x03, mes, trunk->Q921HeaderSpace+4);
01930 }
01931 
01932 /*****************************************************************************
01933 
01934   Function:     Q921SendSABME
01935 
01936   Description:  Compose and send SABME
01937 
01938   Parameters:   trunk       trunk #
01939                 Sapi        Sapi
01940                 cr          C/R field.
01941                 Tei         Tei.
01942                 pf          P fiels octet 4
01943 
01944   Return Value: 0 if failed, 1 if Send.
01945 
01946 *****************************************************************************/
01947 static int Q921SendSABME(L2TRUNK trunk, int Sapi, int cr, int Tei, int pf)
01948 {
01949         L2UCHAR mes[25];
01950 
01951 #ifdef Q921_STATISTICS_EXTENDED
01952         Q921StatsIncrementCounter(Q921_LINK_CONTEXT(trunk, Tei), Q921_STATS_SEND_SABME);
01953 #endif
01954         return Q921SendU(trunk, Sapi, cr, Tei, pf, 0x0f, mes, trunk->Q921HeaderSpace+3);
01955 }
01956 
01957 
01964 Q921_API int Q921Start(L2TRUNK trunk)
01965 {
01966         int x, numlinks = Q921_IS_PTMP_NT(trunk) ? Q921_TEI_MAX : 1;
01967         struct Q921_Link *link = Q921_TRUNK_CONTEXT(trunk);
01968 
01969         if (trunk->initialized != INITIALIZED_MAGIC)
01970                 return 0;
01971 
01972         memset(trunk->context, 0, numlinks * sizeof(struct Q921_Link));
01973 
01974         /* Common init part */
01975         for (x = 0; x <= numlinks; x++) {
01976                 link = Q921_LINK_CONTEXT(trunk, x);
01977 
01978                 link->state = Q921_STATE_TEI_UNASSIGNED;
01979                 link->tei   = 0;
01980 
01981                 /* Initialize per-TEI I + UI queues */
01982                 MFIFOCreate(link->UIFrameQueue, Q921MAXHDLCSPACE, 10);
01983                 MFIFOCreate(link->IFrameQueue,  Q921MAXHDLCSPACE, 10);
01984                 MFIFOCreate(link->IFrameResendQueue, Q921MAXHDLCSPACE, 10);
01985         }
01986 
01987         if (Q921_IS_PTMP_TE(trunk)) {
01988                 link->state = Q921_STATE_TEI_UNASSIGNED;
01989                 link->tei   = 0;
01990         }
01991         else if (Q921_IS_PTMP_NT(trunk)) {
01992                 link = Q921_TRUNK_CONTEXT(trunk);
01993 
01994                 link->state = Q921_STATE_TEI_ASSIGNED;
01995                 link->tei   = trunk->tei;
01996 
01997                 /* clear tei map */
01998                 memset(trunk->tei_map, 0, Q921_TEI_MAX + 1);
01999         }
02000         else {
02001                 link->state = Q921_STATE_TEI_ASSIGNED;
02002                 link->tei   = trunk->tei;
02003         }
02004 
02005         Q921Log(trunk, Q921_LOG_DEBUG, "Starting trunk %p (sapi: %d, tei: %d, mode: %s %s)\n",
02006                                  trunk,
02007                                  trunk->sapi,
02008                                  link->tei,
02009                                  Q921_IS_PTMP(trunk) ? "PTMP" : "PTP",
02010                                  Q921_IS_TE(trunk) ? "TE" : "NT");
02011 
02012         if (Q921_IS_PTP(trunk)) {
02013                 Q921Log(trunk, Q921_LOG_DEBUG, "Sending SABME\n");
02014 
02015                 return Q921SendSABME(trunk,
02016                                         trunk->sapi,
02017                                         Q921_COMMAND(trunk),
02018                                         link->tei,
02019                                         1);
02020 
02021         } else if (Q921_IS_PTMP_NT(trunk)) {
02022 
02023                 Q921Log(trunk, Q921_LOG_DEBUG, "Revoking all TEIs\n");
02024 
02025                 return Q921TeiSendRemoveRequest(trunk, Q921_TEI_BCAST); /* Revoke all TEIs in use */
02026         } else {
02027 
02028                 Q921Log(trunk, Q921_LOG_DEBUG, "Requesting TEI\n");
02029 
02030                 return Q921TeiSendAssignRequest(trunk);
02031         }
02032 }
02033 
02034 
02043 Q921_API int Q921Stop(L2TRUNK trunk)
02044 {
02045         struct Q921_Link *link;
02046         int x, numlinks;
02047 
02048         if (!trunk)
02049                 return -1;
02050 
02051         link = Q921_TRUNK_CONTEXT(trunk);
02052         numlinks = Q921_IS_PTMP_NT(trunk) ? Q921_TEI_MAX : 1;
02053 
02054         if (Q921_IS_STOPPED(link))
02055                 return 0;
02056 
02057         /* Release TEI */
02058         if (Q921_IS_PTMP_TE(trunk)) {
02059                 /* send verify request */
02060                 Q921TeiSendVerifyRequest(trunk);
02061 
02062                 /* drop TEI */
02063                 link->tei  = 0;
02064         }
02065 
02066         /* Stop timers, stop link, flush queues */
02067         for (x = 0; x <= numlinks; x++) {
02068                 Q921T200TimerStop(trunk, x);
02069                 Q921T203TimerStop(trunk, x);
02070                 Q921T201TimerStop(trunk, x);
02071 
02072                 /* Change state (no action) */
02073                 Q921ChangeState(trunk, Q921_STATE_STOPPED, x);
02074 
02075                 /* Flush per-tei I/UI queues */
02076                 MFIFOClear(link->UIFrameQueue);
02077                 MFIFOClear(link->IFrameQueue);
02078                 MFIFOClear(link->IFrameResendQueue);
02079         }
02080         Q921T202TimerStop(trunk);
02081 
02082         /* Flush HDLC queue */
02083         MFIFOClear(trunk->HDLCInQueue);
02084 
02085         return 0;
02086 }
02087 
02088 
02089 /*****************************************************************************
02090 
02091   Function:     Q921SendDM
02092 
02093   Description:  Compose and Send DM (Disconnected Mode)
02094 
02095   Parameters:   trunk       trunk #
02096                 Sapi        Sapi
02097                 cr          C/R field.
02098                 Tei         Tei.
02099                 pf          F fiels octet 4
02100 
02101   Return Value: 0 if failed, 1 if Send.
02102 
02103 *****************************************************************************/
02104 static int Q921SendDM(L2TRUNK trunk, int Sapi, int cr, int Tei, int pf)
02105 {
02106         L2UCHAR mes[25];
02107 
02108 #ifdef Q921_STATISTICS_EXTENDED
02109         Q921StatsIncrementCounter(Q921_LINK_CONTEXT(trunk, Tei), Q921_STATS_SEND_DM);
02110 #endif
02111         return Q921SendU(trunk, Sapi, cr, Tei, pf, 0x03, mes, trunk->Q921HeaderSpace+3);
02112 }
02113 
02114 /*****************************************************************************
02115 
02116   Function:     Q921SendDISC
02117 
02118   Description:  Compose and Send Disconnect
02119 
02120   Parameters:   trunk       trunk #
02121                 Sapi        Sapi
02122                 cr          C/R field.
02123                 Tei         Tei.
02124                 pf          P fiels octet 4
02125 
02126   Return Value: 0 if failed, 1 if Send.
02127 
02128 *****************************************************************************/
02129 static int Q921SendDISC(L2TRUNK trunk, int Sapi, int cr, int Tei, int pf)
02130 {
02131         L2UCHAR mes[25];
02132 
02133 #ifdef Q921_STATISTICS_EXTENDED
02134         Q921StatsIncrementCounter(Q921_LINK_CONTEXT(trunk, Tei), Q921_STATS_SEND_DISC);
02135 #endif
02136         return Q921SendU(trunk, Sapi, cr, Tei, pf, 0x08, mes, trunk->Q921HeaderSpace+3);
02137 }
02138 
02139 /*****************************************************************************
02140 
02141   Function:     Q921SendUA
02142 
02143   Description:  Compose and Send UA
02144 
02145   Parameters:   trunk       trunk #
02146                 Sapi        Sapi
02147                 cr          C/R field.
02148                 Tei         Tei.
02149                 pf          F fiels octet 4
02150 
02151   Return Value: 0 if failed, 1 if Send.
02152 
02153 *****************************************************************************/
02154 static int Q921SendUA(L2TRUNK trunk, int Sapi, int cr, int Tei, int pf)
02155 {
02156         L2UCHAR mes[25];
02157 
02158 #ifdef Q921_STATISTICS_EXTENDED
02159         Q921StatsIncrementCounter(Q921_LINK_CONTEXT(trunk, Tei), Q921_STATS_SEND_UA);
02160 #endif
02161         return Q921SendU(trunk, Sapi, cr, Tei, pf, 0x0c, mes, trunk->Q921HeaderSpace+3);
02162 }
02163 
02164 static int Q921SendUN(L2TRUNK trunk, int Sapi, int cr, int Tei, int pf, L2UCHAR *mes, L2INT size)
02165 {
02166 #ifdef Q921_STATISTICS_EXTENDED
02167         Q921StatsIncrementCounter(Q921_LINK_CONTEXT(trunk, Tei), Q921_STATS_SEND_UN);
02168 #endif
02169         return Q921SendU(trunk, Sapi, cr, Tei, pf, 0x00, mes, size+trunk->Q921HeaderSpace+3);
02170 }
02171 
02172 
02181 static int Q921ProcSABME(L2TRUNK trunk, L2UCHAR *mes, L2INT size)
02182 {
02183         L2UCHAR pf = (mes[2] & 0x10) >> 4;                              /* poll / final flag */
02184         L2UCHAR tei = (mes[1] & 0xfe) >> 1;
02185         struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
02186 
02187 #ifdef Q921_STATISTICS_EXTENDED
02188         Q921StatsIncrementCounter(link, Q921_STATS_RECV_SABME);
02189 #endif
02190 
02191         switch (link->state) {
02192         case Q921_STATE_TEI_ASSIGNED:
02193                 /* send UA */
02194                 Q921SendUA(trunk,
02195                                 trunk->sapi,
02196                                 Q921_RESPONSE(trunk),   /* or command? */
02197                                 tei, pf);
02198 
02199                 /* clear counters */
02200                 link->vr=0;
02201                 link->vs=0;
02202                 link->va=0;
02203 
02204                 /* TODO: send DL-Establish indication to Q.931 */
02205                 Q921Tx23Proc(trunk, Q921_DL_ESTABLISH, tei, NULL, 0);
02206 
02207                 /* start T203 */
02208                 Q921T203TimerStart(trunk, tei);
02209 
02210                 /* change state (no action) */
02211                 Q921ChangeState(trunk, Q921_STATE_MULTIPLE_FRAME_ESTABLISHED, tei);
02212                 break;
02213 
02214         case Q921_STATE_AWAITING_ESTABLISHMENT:
02215                 /* send UA */
02216                 Q921SendUA(trunk,
02217                                 trunk->sapi,
02218                                 Q921_RESPONSE(trunk),
02219                                 tei, pf);
02220 
02221                 /* no state change */
02222                 break;
02223 
02224         case Q921_STATE_AWAITING_RELEASE:
02225                 /* send DM */
02226                 Q921SendDM(trunk,
02227                                 trunk->sapi,
02228                                 Q921_RESPONSE(trunk),
02229                                 tei, pf);
02230 
02231                 /* no state change */
02232                 break;
02233 
02234         case Q921_STATE_MULTIPLE_FRAME_ESTABLISHED:
02235         case Q921_STATE_TIMER_RECOVERY:
02236                 /* send UA */
02237                 Q921SendUA(trunk,
02238                                 trunk->sapi,
02239                                 Q921_RESPONSE(trunk),
02240                                 tei, pf);
02241 
02242                 /* clear exception conditions */
02243                 Q921ResetExceptionConditions(trunk, tei);
02244 
02245                 /* send MDL-Error indication */
02246 
02247                 /* V(S) == V(A) ? */
02248                 if (link->vs != link->va) {
02249                         /* clear I queue */
02250                         MFIFOClear(link->IFrameQueue);
02251 
02252                         /* DL-Establish indication */
02253                         Q921Tx23Proc(trunk, Q921_DL_ESTABLISH, tei, NULL, 0);
02254                 }
02255 
02256                 /* clear counters */
02257                 link->vr=0;
02258                 link->vs=0;
02259                 link->va=0;
02260 
02261                 /* Stop T200, start T203 */
02262                 Q921T200TimerStop(trunk, tei);
02263                 Q921T203TimerStart(trunk, tei);
02264 
02265                 /* state change only if in TIMER_RECOVERY state */
02266                 if (link->state == Q921_STATE_TIMER_RECOVERY)
02267                         Q921ChangeState(trunk, Q921_STATE_MULTIPLE_FRAME_ESTABLISHED, tei);
02268                 break;
02269 
02270         default:
02271                 break;
02272         }
02273 
02274         return 1;
02275 }
02276 
02277 
02286 static int Q921ProcDM(L2TRUNK trunk, L2UCHAR *mes, L2INT size)
02287 {
02288         L2UCHAR pf = (mes[2] & 0x10) >> 4;                              /* poll / final flag */
02289         L2UCHAR tei = (mes[1] & 0xfe) >> 1;
02290         struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
02291 
02292 #ifdef Q921_STATISTICS_EXTENDED
02293         Q921StatsIncrementCounter(link, Q921_STATS_RECV_DM);
02294 #endif
02295 
02296         switch (link->state) {
02297         case Q921_STATE_TEI_ASSIGNED:
02298                 if (!pf) {
02299                         /* to next state (no action) */
02300                         Q921ChangeState(trunk, Q921_STATE_AWAITING_ESTABLISHMENT, tei);
02301                 }
02302                 break;
02303 
02304         case Q921_STATE_AWAITING_ESTABLISHMENT:
02305         case Q921_STATE_AWAITING_RELEASE:
02306                 if (pf) {
02307                         if (link->state == Q921_STATE_AWAITING_ESTABLISHMENT) {
02308                                 /* Discard I queue */
02309                                 MFIFOClear(link->IFrameQueue);
02310                         }
02311 
02312                         /* Send DL-Release indication to Q.931 */
02313                         Q921Tx23Proc(trunk, Q921_DL_RELEASE, tei, NULL, 0);
02314 
02315                         /* Stop T200 */
02316                         Q921T200TimerStop(trunk, tei);
02317 
02318                         /* Change state (no action) */
02319                         Q921ChangeState(trunk, Q921_STATE_TEI_ASSIGNED, tei);
02320                 }
02321                 break;
02322 
02323         case Q921_STATE_MULTIPLE_FRAME_ESTABLISHED:
02324                 if (pf) {
02325                         /* MDL-Error indication (B) */
02326 
02327                         /* no state change */
02328                 } else {
02329                         /* MDL-Error indication (E) */
02330 
02331                         /* establish data link */
02332                         Q921EstablishDataLink(trunk, tei);
02333 
02334                         /* clear L3 initiated */
02335                         Q921_CLEAR_FLAG(link, Q921_FLAG_L3_INITIATED);
02336 
02337                         /* change state (no action?) */
02338                         Q921ChangeState(trunk, Q921_STATE_AWAITING_ESTABLISHMENT, tei);
02339                 }
02340                 break;
02341 
02342         case Q921_STATE_TIMER_RECOVERY:
02343                 if (pf) {
02344                         /* MDL Error indication (B) */
02345                 } else {
02346                         /* MDL Error indication (E) */
02347                 }
02348 
02349                 /* establish data link */
02350                 Q921EstablishDataLink(trunk, tei);
02351 
02352                 /* clear layer 3 initiated */
02353                 Q921_CLEAR_FLAG(link, Q921_FLAG_L3_INITIATED);
02354 
02355                 /* change state */
02356                 Q921ChangeState(trunk, Q921_STATE_AWAITING_ESTABLISHMENT, tei);
02357                 break;
02358 
02359         default:
02360                 break;
02361         }
02362 
02363         return 1;
02364 }
02365 
02374 static int Q921ProcUA(L2TRUNK trunk, L2UCHAR *mes, L2INT size)
02375 {
02376         L2UCHAR pf = (mes[2] & 0x10) >> 4;                              /* poll / final flag */
02377         L2UCHAR tei = (mes[1] & 0xfe) >> 1;
02378         struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
02379 
02380 #ifdef Q921_STATISTICS_EXTENDED
02381         Q921StatsIncrementCounter(link, Q921_STATS_RECV_UA);
02382 #endif
02383 
02384         switch (link->state) {
02385         case Q921_STATE_TEI_ASSIGNED:
02386         case Q921_STATE_TIMER_RECOVERY:
02387                 /* MDL Error indication (C, D) */
02388                 Q921Log(trunk, Q921_LOG_ERROR, "Received UA frame in invalid state\n");
02389                 break;
02390 
02391         case Q921_STATE_AWAITING_ESTABLISHMENT:
02392                 if (pf) {
02393                         /* TODO: other fancy stuff (see docs) */
02394                         if (Q921_CHECK_FLAG(link, Q921_FLAG_L3_INITIATED)) {    /* layer3 initiated */
02395                                 /* DL-Establish confirm */
02396                                 Q921Tx23Proc(trunk, Q921_DL_ESTABLISH_CONFIRM, tei, NULL, 0);
02397 
02398                         } else if (link->vs != link->va) {
02399 
02400                                 /* discard I queue */
02401                                 MFIFOClear(link->IFrameQueue);
02402 
02403                                 /* DL-Establish indication */
02404                                 Q921Tx23Proc(trunk, Q921_DL_ESTABLISH, tei, NULL, 0);
02405                         }
02406 
02407                         /* Stop T200, start T203 */
02408                         Q921T200TimerStop(trunk, tei);
02409                         Q921T203TimerStart(trunk, tei);
02410 
02411                         link->vr = 0;
02412                         link->vs = 0;
02413                         link->va = 0;
02414 
02415                         /* change state (no action) */
02416                         Q921ChangeState(trunk, Q921_STATE_MULTIPLE_FRAME_ESTABLISHED, tei);
02417                 } else {
02418                         /* MDL Error indication (C, D) */
02419                         Q921Log(trunk, Q921_LOG_ERROR, "Received UA frame is not a response to a request\n");
02420 
02421                         /* no state change */
02422                 }
02423                 break;
02424 
02425         case Q921_STATE_AWAITING_RELEASE:
02426                 if (pf) {
02427                         /* DL Release confirm */
02428                         Q921Tx23Proc(trunk, Q921_DL_RELEASE_CONFIRM, tei, NULL, 0);
02429 
02430                         /* Stop T200 */
02431                         Q921T200TimerStop(trunk, tei);
02432 
02433                         /* change state (no action) */
02434                         Q921ChangeState(trunk, Q921_STATE_TEI_ASSIGNED, tei);
02435                 } else {
02436                         /* MDL Error indication (D) */
02437                         Q921Log(trunk, Q921_LOG_ERROR, "Received UA frame is not a response to a request\n");
02438 
02439                         /* no state change */
02440                 }
02441                 break;
02442 
02443         case Q921_STATE_MULTIPLE_FRAME_ESTABLISHED:
02444                 /* MDL Error indication (C, D) */
02445                 Q921Log(trunk, Q921_LOG_ERROR, "Received UA frame in invalid state\n");
02446 
02447                 /* no state change */
02448                 break;
02449 
02450         default:
02451                 break;
02452         }
02453 
02454         return 1;
02455 }
02456 
02457 
02466 static int Q921ProcDISC(L2TRUNK trunk, L2UCHAR *mes, L2INT size)
02467 {
02468         L2UCHAR pf  = (mes[2] & 0x10) >> 4;                             /* poll / final flag */
02469         L2UCHAR tei = (mes[1] & 0xfe) >> 1;
02470         struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
02471 
02472 #ifdef Q921_STATISTICS_EXTENDED
02473         Q921StatsIncrementCounter(link, Q921_STATS_RECV_DISC);
02474 #endif
02475 
02476         switch (link->state) {
02477         case Q921_STATE_TEI_ASSIGNED:
02478         case Q921_STATE_AWAITING_ESTABLISHMENT:
02479                 /* Send DM */
02480                 Q921SendDM(trunk,
02481                                 trunk->sapi,
02482                                 Q921_RESPONSE(trunk),
02483                                 tei, pf);
02484 
02485                 /* no state change */
02486                 break;
02487 
02488         case Q921_STATE_AWAITING_RELEASE:
02489                 Q921SendUA(trunk,
02490                                 trunk->sapi,
02491                                 Q921_RESPONSE(trunk),
02492                                 tei, pf);
02493 
02494                 /* no state change */
02495                 break;
02496 
02497         case Q921_STATE_MULTIPLE_FRAME_ESTABLISHED:
02498         case Q921_STATE_TIMER_RECOVERY:
02499                 /* Discard I queue */
02500                 MFIFOClear(link->IFrameQueue);
02501 
02502                 /* send UA */
02503                 Q921SendUA(trunk,
02504                                 trunk->sapi,
02505                                 Q921_RESPONSE(trunk),
02506                                 tei, pf);
02507 
02508                 /* DL Release indication */
02509                 Q921Tx23Proc(trunk, Q921_DL_RELEASE, tei, NULL, 0);
02510 
02511                 /* Stop T200 */
02512                 Q921T200TimerStop(trunk, tei);
02513 
02514                 if (link->state == Q921_STATE_MULTIPLE_FRAME_ESTABLISHED) {
02515                         /* Stop T203 */
02516                         Q921T203TimerStop(trunk, tei);
02517                 }
02518 
02519                 /* change state (no action) */
02520                 Q921ChangeState(trunk, Q921_STATE_TEI_ASSIGNED, tei);
02521                 break;
02522 
02523         default:
02524                 Q921Log(trunk, Q921_LOG_ERROR, "Invalid DISC received in state \"%s\" (%d)", Q921State2Name(link->state), link->state);
02525                 break;
02526         }
02527 
02528         return 1;
02529 }
02530 
02531 
02540 static int Q921ProcRR(L2TRUNK trunk, L2UCHAR *mes, L2INT size)
02541 {
02542         L2UCHAR cr = (mes[0] & 0x02) >> 1;
02543         L2UCHAR pf =  mes[3] & 0x01;            /* poll / final flag */
02544         L2UCHAR nr = (mes[3] >> 1);
02545 //      L2UCHAR sapi = (mes[0] & 0xfc) >> 2;
02546         L2UCHAR tei  = (mes[1] & 0xfe) >> 1;
02547         struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
02548 
02549 #ifdef Q921_STATISTICS_EXTENDED
02550         Q921StatsIncrementCounter(link, Q921_STATS_RECV_RR);
02551 #endif
02552 
02553         switch (link->state) {
02554         case Q921_STATE_MULTIPLE_FRAME_ESTABLISHED:
02555                 /* clear receiver peer busy */
02556                 Q921_CLEAR_FLAG(link, Q921_FLAG_PEER_RECV_BUSY);
02557 
02558                 if (Q921_IS_COMMAND(trunk, cr)) { /* if this is a command */
02559                         if (pf) {
02560                                 /* Enquiry response */
02561                                 Q921SendEnquiryResponse(trunk, tei);
02562                         }
02563                 } else {
02564                         if (pf) {
02565                                 /* MDL Error indication */
02566                         }
02567                 }
02568 
02569                 /* */
02570                 if (link->va <= nr && nr <= link->vs) {
02571 
02572                         if (nr == link->vs) {
02573                                 /* V(A) = N(R) */
02574                                 link->va = nr;
02575 
02576                                 /* Stop T200, restart T203 */
02577                                 Q921T200TimerStop(trunk, tei);
02578                                 Q921T203TimerReset(trunk, tei);
02579 
02580                         } else if (nr == link->va) {
02581 
02582                                 /* do nothing */
02583 
02584                         } else {
02585                                 /* V(A) = N(R) */
02586                                 link->va = nr;
02587 
02588                                 /* Restart T200 */
02589                                 Q921T200TimerReset(trunk, tei);
02590                         }
02591                         /* no state change */
02592 
02593                 } else {
02594                         /* N(R) Error recovery */
02595                         Q921NrErrorRecovery(trunk, tei);
02596 
02597                         /* change state (no action) */
02598                         Q921ChangeState(trunk, Q921_STATE_AWAITING_ESTABLISHMENT, tei);
02599                 }
02600                 break;
02601 
02602         case Q921_STATE_TIMER_RECOVERY:
02603                 /* clear receiver peer busy */
02604                 Q921_CLEAR_FLAG(link, Q921_FLAG_PEER_RECV_BUSY);
02605 
02606                 /* command + P? */
02607                 if (Q921_IS_COMMAND(trunk, cr) && pf) {
02608                         /* Enquiry response */
02609                         Q921SendEnquiryResponse(trunk, tei);
02610                 }
02611 
02612                 /* */
02613                 if (link->va <= nr && nr <= link->vs) {
02614                         /* V(A) = N(R) */
02615                         link->va = nr;
02616 
02617                         if (!Q921_IS_COMMAND(trunk, cr) && pf) {
02618                                 /* Stop T200, start T203 */
02619                                 Q921T200TimerStop(trunk, tei);
02620                                 Q921T203TimerStart(trunk, tei);
02621 
02622                                 /* Invoke retransmission */
02623                                 Q921InvokeRetransmission(trunk, tei, nr);
02624 
02625                                 /* change state (no action) */
02626                                 Q921ChangeState(trunk, Q921_STATE_MULTIPLE_FRAME_ESTABLISHED, tei);
02627                         }
02628                         /* no state change otherwise */
02629                 } else {
02630                         /* N(R) Error recovery */
02631                         Q921NrErrorRecovery(trunk, tei);
02632 
02633                         /* change state (no action) */
02634                         Q921ChangeState(trunk, Q921_STATE_AWAITING_ESTABLISHMENT, tei);
02635                 }
02636                 break;
02637 
02638         default:
02639                 break;
02640         }
02641         return 1;
02642 }
02643 
02644 
02653 static int Q921ProcREJ(L2TRUNK trunk, L2UCHAR *mes, L2INT size)
02654 {
02655         L2UCHAR cr = (mes[0] & 0x02) >> 1;
02656         L2UCHAR pf =  mes[3] & 0x01;            /* poll / final flag */
02657         L2UCHAR nr = (mes[3] >> 1);
02658 //      L2UCHAR sapi = (mes[0] & 0xfc) >> 2;
02659         L2UCHAR tei  = (mes[1] & 0xfe) >> 1;
02660         struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
02661 
02662 #ifdef Q921_STATISTICS_EXTENDED
02663         Q921StatsIncrementCounter(link, Q921_STATS_RECV_REJ);
02664 #endif
02665 
02666         switch (link->state) {
02667         case Q921_STATE_MULTIPLE_FRAME_ESTABLISHED:
02668                 /* clear receiver peer busy */
02669                 Q921_CLEAR_FLAG(link, Q921_FLAG_PEER_RECV_BUSY);
02670 
02671                 /* command? */
02672                 if (Q921_IS_COMMAND(trunk, cr)) {
02673                         if (pf) {
02674                                 /* Enquiry response */
02675                                 Q921SendEnquiryResponse(trunk, tei);
02676                         }
02677                 } else {
02678                         if (pf) {
02679                                 /* MDL Error indication (A) */
02680                         }
02681                 }
02682 
02683                 /* */
02684                 if (link->va <= nr && nr <= link->vs) {
02685 
02686                         /* V(A) = N(R) */
02687                         link->va = nr;
02688 
02689                         /* Stop T200, start T203 */
02690                         Q921T200TimerStop(trunk, tei);
02691                         Q921T203TimerStart(trunk, tei);
02692 
02693                         /* Invoke retransmission of frame >N(R)  (?) */
02694                         Q921InvokeRetransmission(trunk, tei, nr);
02695 
02696                         /* no state change */
02697                 } else {
02698                         /* N(R) Error recovery */
02699                         Q921NrErrorRecovery(trunk, tei);
02700 
02701                         /* change state (no action) */
02702                         Q921ChangeState(trunk, Q921_STATE_AWAITING_ESTABLISHMENT, tei);
02703                 }
02704                 break;
02705 
02706         case Q921_STATE_TIMER_RECOVERY:
02707                 /* clear receiver peer busy */
02708                 Q921_CLEAR_FLAG(link, Q921_FLAG_PEER_RECV_BUSY);
02709 
02710                 /* command + P ? */
02711                 if (Q921_IS_COMMAND(trunk, cr) && pf) {
02712                         /* Enquiry response */
02713                         Q921SendEnquiryResponse(trunk, tei);
02714                 }
02715 
02716                 /* */
02717                 if (link->va <= nr && nr <= link->vs) {
02718 
02719                         /* V(A) = N(R) */
02720                         link->va = nr;
02721 
02722                         if (!Q921_IS_COMMAND(trunk, cr) && pf) {
02723                                 /* Stop T200, start T203 */
02724                                 Q921T200TimerStop(trunk, tei);
02725                                 Q921T203TimerStart(trunk, tei);
02726 
02727                                 /* Invoke retransmission */
02728                                 Q921InvokeRetransmission(trunk, tei, nr);
02729 
02730                                 /* change state (no action) */
02731                                 Q921ChangeState(trunk, Q921_STATE_MULTIPLE_FRAME_ESTABLISHED, tei);
02732                         }
02733                         /* no state change otherwise */
02734                 } else {
02735                         /* N(R) Error recovery */
02736                         Q921NrErrorRecovery(trunk, tei);
02737 
02738                         /* change state (no action) */
02739                         Q921ChangeState(trunk, Q921_STATE_AWAITING_ESTABLISHMENT, tei);
02740                 }
02741                 break;
02742 
02743         default:
02744                 break;
02745         }
02746 
02747         return 1;
02748 }
02749 
02750 
02759 static int Q921ProcRNR(L2TRUNK trunk, L2UCHAR *mes, L2INT size)
02760 {
02761         L2UCHAR cr = (mes[0] & 0x02) >> 1;
02762         L2UCHAR pf =  mes[3] & 0x01;            /* poll / final flag */
02763         L2UCHAR nr = (mes[3] >> 1);
02764 //      L2UCHAR sapi = (mes[0] & 0xfc) >> 2;
02765         L2UCHAR tei  = (mes[1] & 0xfe) >> 1;
02766         struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
02767 
02768 #ifdef Q921_STATISTICS_EXTENDED
02769         Q921StatsIncrementCounter(link, Q921_STATS_RECV_RNR);
02770 #endif
02771 
02772         switch (link->state) {
02773         case Q921_STATE_MULTIPLE_FRAME_ESTABLISHED:
02774                 /* set peer receiver busy */
02775                 Q921_SET_FLAG(link, Q921_FLAG_PEER_RECV_BUSY);
02776 
02777                 /* command? */
02778                 if (Q921_IS_COMMAND(trunk, cr)) {
02779                         if (pf) {
02780                                 /* Enquiry response */
02781                                 Q921SendEnquiryResponse(trunk, tei);
02782                         }
02783                 } else {
02784                         if (pf) {
02785                                 /* MDL Error indication (A) */
02786                         }
02787                 }
02788 
02789                 /* */
02790                 if (link->va <= nr && nr <= link->vs) {
02791 
02792                         /* V(A) = N(R) */
02793                         link->va = nr;
02794 
02795                         /* Stop T203, restart T200 */
02796                         Q921T200TimerReset(trunk, tei);
02797                         Q921T203TimerStop(trunk, tei);
02798 
02799                         /* no state change */
02800                 } else {
02801                         /* N(R) Error recovery */
02802                         Q921NrErrorRecovery(trunk, tei);
02803 
02804                         /* change state (no action) */
02805                         Q921ChangeState(trunk, Q921_STATE_AWAITING_ESTABLISHMENT, tei);
02806                 }
02807                 break;
02808 
02809         case Q921_STATE_TIMER_RECOVERY:
02810                 /* set peer receiver busy */
02811                 Q921_SET_FLAG(link, Q921_FLAG_PEER_RECV_BUSY);
02812 
02813                 /* command + P? */
02814                 if (Q921_IS_COMMAND(trunk, cr) && pf) {
02815                         /* Enquiry response */
02816                         Q921SendEnquiryResponse(trunk, tei);
02817                 }
02818 
02819                 /* */
02820                 if (link->va <= nr && nr <= link->vs) {
02821 
02822                         /* V(A) = N(R) */
02823                         link->va = nr;
02824 
02825                         if (!Q921_IS_COMMAND(trunk, cr) && pf) {
02826                                 /* Restart T200 */
02827                                 Q921T200TimerReset(trunk, tei);
02828 
02829                                 /* Invoke retransmission */
02830                                 Q921InvokeRetransmission(trunk, tei, nr);
02831 
02832                                 /* change state (no action) */
02833                                 Q921ChangeState(trunk, Q921_STATE_MULTIPLE_FRAME_ESTABLISHED, tei);
02834                         }
02835                         /* no state change otherwise */
02836                 } else {
02837                         /* N(R) Error recovery */
02838                         Q921NrErrorRecovery(trunk, tei);
02839 
02840                         /* change state (no action) */
02841                         Q921ChangeState(trunk, Q921_STATE_AWAITING_ESTABLISHMENT, tei);
02842                 }
02843                 break;
02844 
02845         default:
02846                 break;
02847         }
02848 
02849         return 1;
02850 }
02851 
02852 #if 0
02853 static int Q921SetReceiverBusy(L2TRUNK trunk)
02854 {
02855         struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
02856 
02857         switch (link->state) {
02858         case Q921_STATE_MULTIPLE_FRAME_ESTABLISHED:
02859                 if (!Q921_CHECK_FLAG(link, Q921_FLAG_RECV_BUSY)) {
02860                         /* set own receiver busy */
02861                         Q921_SET_FLAG(link, Q921_FLAG_RECV_BUSY);
02862 
02863                         /* send RR response */
02864                         Q921SendRR(trunk, trunk->sapi, Q921_RESPONSE(trunk), link->tei, 0);
02865 
02866                         /* clear ack pending */
02867                         Q921_CLEAR_FLAG(link, Q921_FLAG_ACK_PENDING);
02868                 }
02869                 break;
02870 
02871         case Q921_STATE_TIMER_RECOVERY:
02872                 if (!Q921_CHECK_FLAG(link, Q921_FLAG_RECV_BUSY)) {
02873                         /* set own receiver busy */
02874                         Q921_SET_FLAG(link, Q921_FLAG_RECV_BUSY);
02875 
02876                         /* send RNR response */
02877                         Q921SendRNR(trunk, trunk->sapi, Q921_RESPONSE(trunk), link->tei, 0);
02878 
02879                         /* clear ack pending */
02880                         Q921_CLEAR_FLAG(link, Q921_FLAG_ACK_PENDING);
02881                 }
02882                 break;
02883 
02884         default:
02885                 break;
02886         }
02887 
02888         return 0;
02889 }
02890 
02891 static int Q921ClearReceiverBusy(L2TRUNK trunk)
02892 {
02893         struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
02894 
02895         switch (link->state) {
02896         case Q921_STATE_MULTIPLE_FRAME_ESTABLISHED:
02897         case Q921_STATE_TIMER_RECOVERY:
02898                 if (Q921_CHECK_FLAG(link, Q921_FLAG_RECV_BUSY)) {
02899                         /* clear own receiver busy */
02900                         Q921_CLEAR_FLAG(link, Q921_FLAG_RECV_BUSY);
02901 
02902                         /* send RNR response */
02903                         Q921SendRNR(trunk, trunk->sapi, Q921_RESPONSE(trunk), link->tei, 0);
02904 
02905                         /* clear ack pending */
02906                         Q921_CLEAR_FLAG(link, Q921_FLAG_ACK_PENDING);
02907                 }
02908                 break;
02909 
02910         default:
02911                 break;
02912         }
02913 
02914         return 0;
02915 }
02916 #endif
02917 
02918 static int Q921ProcIFrame(L2TRUNK trunk, L2UCHAR *mes, L2INT size)
02919 {
02920         /* common fields: get sapi, tei and cr */
02921 //      L2UCHAR sapi = (mes[0] & 0xfc) >> 2;
02922 //      L2UCHAR cr   = (mes[0] & 0x02) >> 1;
02923         L2UCHAR tei  = (mes[1] & 0xfe) >> 1;
02924         L2UCHAR pf   =  mes[3] & 0x01;          /* poll / final flag */
02925         L2UCHAR nr   =  mes[3] >> 1;            /* receive sequence number */
02926         L2UCHAR ns   =  mes[2] >> 1;            /* send sequence number */
02927         L2UCHAR discard = 0;
02928         struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
02929 
02930         /* Ignore I frames in earlier states */
02931         if (link->state < Q921_STATE_MULTIPLE_FRAME_ESTABLISHED) {
02932                 Q921Log(trunk, Q921_LOG_NOTICE, "I frame in invalid state ignored\n");
02933                 return 0;
02934         }
02935 
02936 #ifdef Q921_STATISTICS_EXTENDED
02937         Q921StatsIncrementCounter(link, Q921_STATS_RECV_I);
02938 #endif
02939 
02940         /* Receiver busy? */
02941         if (Q921_CHECK_FLAG(link, Q921_FLAG_RECV_BUSY)) {
02942                 /* discard information */
02943                 discard = 1;
02944 
02945                 if (pf) {
02946                         /* send RNR Response */
02947                         Q921SendRNR(trunk, trunk->sapi, Q921_RESPONSE(trunk), tei, 1);
02948 
02949                         /* Clear ack pending */
02950                         Q921_CLEAR_FLAG(link, Q921_FLAG_ACK_PENDING);
02951                 }
02952         }
02953         else {
02954                 if (ns != link->vr) {
02955                         /* discard information */
02956                         discard = 1;
02957 
02958                         if (Q921_CHECK_FLAG(link, Q921_FLAG_REJECT) && pf) {
02959 
02960                                 /* Send RR response */
02961                                 Q921SendRR(trunk, trunk->sapi, Q921_RESPONSE(trunk), tei, 1);
02962 
02963                                 /* clear ack pending */
02964                                 Q921_CLEAR_FLAG(link, Q921_FLAG_ACK_PENDING);
02965                         }
02966                         else if (!Q921_CHECK_FLAG(link, Q921_FLAG_REJECT)){
02967 
02968                                 /* set reject exception */
02969                                 Q921_SET_FLAG(link, Q921_FLAG_REJECT);
02970 
02971                                 /* Send REJ response */
02972                                 Q921SendREJ(trunk, trunk->sapi, Q921_RESPONSE(trunk), tei, pf);
02973 
02974                                 /* clear ack pending */
02975                                 Q921_CLEAR_FLAG(link, Q921_FLAG_ACK_PENDING);
02976                         }
02977                 }
02978                 else {
02979                         /* V(R) = V(R) + 1 */
02980                         Q921_INC_COUNTER(link->vr);
02981 
02982                         /* clear reject exception */
02983                         Q921_CLEAR_FLAG(link, Q921_FLAG_REJECT);
02984 
02985                         /* DL-Data indication */
02986                         Q921Tx23Proc(trunk, Q921_DL_DATA, tei, mes, size);
02987 
02988                         if (pf) {
02989                                 /* Send RR response */
02990                                 Q921SendRR(trunk, trunk->sapi, Q921_RESPONSE(trunk), tei, 1);
02991 
02992                                 /* clear ack pending */
02993                                 Q921_CLEAR_FLAG(link, Q921_FLAG_ACK_PENDING);
02994                         }
02995                         else if (!Q921_CHECK_FLAG(link, Q921_FLAG_ACK_PENDING)) {
02996                                 /* ack pending */
02997 
02998                                 /* Send RR response */
02999                                 Q921SendRR(trunk, trunk->sapi, Q921_RESPONSE(trunk), tei, 0);
03000 
03001                                 /* set ack pending*/
03002                                 Q921_SET_FLAG(link, Q921_FLAG_ACK_PENDING);
03003                         }
03004                 }
03005         }
03006 
03007 
03008         switch (link->state) {
03009         case Q921_STATE_MULTIPLE_FRAME_ESTABLISHED:
03010                 if (link->va <= nr && nr <= link->vs) {
03011                         if (Q921_CHECK_FLAG(link, Q921_FLAG_PEER_RECV_BUSY)) {
03012                                 link->va = nr;
03013                         }
03014                         else if (nr == link->vs) {
03015                                 /* V(A) = N(R) */
03016                                 link->va = nr;
03017 
03018                                 /* stop t200, restart t203 */
03019                                 Q921T200TimerStop(trunk, tei);
03020                                 Q921T203TimerReset(trunk, tei);
03021                         }
03022                         else if (nr != link->va) {
03023                                 /* V(A) = N(R) */
03024                                 link->va = nr;
03025 
03026                                 /* restart T200 */
03027                                 Q921T200TimerReset(trunk, tei);
03028                         }
03029 
03030                         /* Restart TM01 */
03031                         if (Q921_IS_NT(trunk)) {
03032                                 Q921TM01TimerReset(trunk, tei);
03033                         }
03034                 }
03035                 else {
03036                         /* N(R) error recovery */
03037                         Q921NrErrorRecovery(trunk, tei);
03038 
03039                         /* change state (no action) */
03040                         Q921ChangeState(trunk, Q921_STATE_AWAITING_ESTABLISHMENT, tei);
03041                 }
03042                 break;
03043 
03044         case Q921_STATE_TIMER_RECOVERY:
03045                 if (link->va <= nr && nr <= link->vs) {
03046                         /* V(A) = N(R) */
03047                         link->va = nr;
03048 
03049                         /* Restart TM01 */
03050                         if (Q921_IS_NT(trunk)) {
03051                                 Q921TM01TimerReset(trunk, tei);
03052                         }
03053                 }
03054                 else {
03055                         /* N(R) error recovery */
03056                         Q921NrErrorRecovery(trunk, tei);
03057 
03058                         /* change state (no action) */
03059                         Q921ChangeState(trunk, Q921_STATE_AWAITING_ESTABLISHMENT, tei);
03060                 }
03061                 break;
03062 
03063         default:
03064                 break;
03065         }
03066 
03067         return 0;
03068 }
03069 
03070 
03071 static int Q921ProcSFrame(L2TRUNK trunk, L2UCHAR *mes, L2INT size)
03072 {
03073         L2UCHAR sv = (mes[2] & 0x0c) >> 2;      /* supervisory format id */
03074         //L2UCHAR pf = mes[3] & 0x01;           /* poll / final flag */
03075         //L2UCHAR nr = mes[3] >> 1;             /* receive sequence number */
03076         L2INT res = -1;
03077 #ifdef Q921_STATISTICS_EXTENDED
03078         L2UCHAR tei  = (mes[1] & 0xfe) >> 1;
03079 
03080         Q921StatsIncrementCounter(Q921_LINK_CONTEXT(trunk, tei), Q921_STATS_RECV_S);
03081 #endif
03082 
03083         switch (sv) {
03084         case 0x00:      /* RR : Receive Ready */
03085                 res = Q921ProcRR(trunk, mes, size);
03086                 break;
03087 
03088         case 0x02:      /* RNR : Receive Not Ready */
03089                 res = Q921ProcRNR(trunk, mes, size);
03090                 break;
03091 
03092         case 0x04:      /* REJ : Reject */
03093                 res = Q921ProcREJ(trunk, mes, size);
03094                 break;
03095 
03096         default:        /* Invalid / Unknown */
03097 #ifdef Q921_STATISTICS_EXTENDED
03098                 Q921StatsIncrementCounter(Q921_LINK_CONTEXT(trunk, tei), Q921_STATS_RECV_INVALID_S);
03099 #endif
03100                 Q921Log(trunk, Q921_LOG_ERROR, "Invalid S frame type %d\n", sv);
03101                 break;
03102         }
03103 
03104         return res;
03105 }
03106 
03107 
03108 
03109 static int Q921ProcUFrame(L2TRUNK trunk, L2UCHAR *mes, L2INT size)
03110 {
03111         L2UCHAR m  = (mes[2] & 0xe0) >> 3 | (mes[2] & 0x0c) >> 2;       /* modifier function id */
03112 //      L2UCHAR pf = (mes[2] & 0x10) >> 4;                              /* poll / final flag */
03113         L2INT res = -1;
03114 #ifdef Q921_STATISTICS_EXTENDED
03115         L2UCHAR tei  = (mes[1] & 0xfe) >> 1;
03116 
03117         Q921StatsIncrementCounter(Q921_LINK_CONTEXT(trunk, tei), Q921_STATS_RECV_U);
03118 #endif
03119 
03120         switch (m) {
03121         case 0x00:      /* UN : Unnumbered Information */
03122 #ifdef Q921_STATISTICS_EXTENDED
03123                 Q921StatsIncrementCounter(Q921_LINK_CONTEXT(trunk, tei), Q921_STATS_RECV_UN);
03124 #endif
03125                 if (mes[3] == Q921_LAYER_ENT_ID_TEI)
03126                 {
03127                         if (!Q921_IS_PTMP(trunk)) {
03128                                 /* wtf? nice try */
03129                                 return res;
03130                         }
03131 
03132                         switch (mes[6]) {
03133                         case Q921_TEI_ID_REQUEST:       /* (TE ->) NT */
03134                                 res = Q921TeiProcAssignRequest(trunk, mes, size);
03135                                 break;
03136 
03137                         case Q921_TEI_ID_ASSIGNED:      /* (NT ->) TE */
03138                         case Q921_TEI_ID_DENIED:
03139                                 res = Q921TeiProcAssignResponse(trunk, mes, size);
03140                                 break;
03141 
03142                         case Q921_TEI_ID_CHECKREQ:      /* (NT ->) TE */
03143                                 res = Q921TeiProcCheckRequest(trunk, mes, size);
03144                                 break;
03145 
03146                         case Q921_TEI_ID_CHECKRESP:     /* (TE ->) NT */
03147                                 res = Q921TeiProcCheckResponse(trunk, mes, size);
03148                                 break;
03149 
03150                         case Q921_TEI_ID_REMOVE:        /* (NT ->) TE */
03151                                 res = Q921TeiProcRemoveRequest(trunk, mes, size);
03152                                 break;
03153 
03154                         case Q921_TEI_ID_VERIFY:        /* (TE ->) NT */
03155                                 res = Q921TeiProcVerifyRequest(trunk, mes, size);
03156                                 break;
03157 
03158                         default:                        /* Invalid / Unknown */
03159                                 Q921Log(trunk, Q921_LOG_ERROR, "Invalid UN message from TEI management/endpoint\n");
03160                                 break;
03161                         }
03162                 }
03163                 else if (mes[3] == Q921_LAYER_ENT_ID_Q931) {
03164 
03165                         Q921Log(trunk, Q921_LOG_DEBUG, "UI Frame for Layer 3 received\n");
03166 
03167                         res = Q921Tx23Proc(trunk, Q921_DL_UNIT_DATA, 0, mes, size);
03168                 }
03169                 break;
03170 
03171         case 0x03:      /* DM : Disconnect Mode */
03172                 res = Q921ProcDM(trunk, mes, size);
03173                 break;
03174 
03175         case 0x08:      /* DISC : Disconnect */
03176                 res = Q921ProcDISC(trunk, mes, size);
03177                 break;
03178 
03179         case 0x0c:      /* UA : Unnumbered Acknowledgement */
03180                 res = Q921ProcUA(trunk, mes, size);
03181                 break;
03182 
03183         case 0x0f:      /* SABME  : Set Asynchronous Balanced Mode Extend */
03184                 res = Q921ProcSABME(trunk, mes, size);
03185                 break;
03186 
03187         case 0x11:      /* FRMR : Frame Reject */
03188         case 0x17:      /* XID : Exchange Identification */
03189                 res = 0;
03190                 break;
03191 
03192         default:        /* Unknown / Invalid */
03193 #ifdef Q921_STATISTICS_EXTENDED
03194                 Q921StatsIncrementCounter(Q921_LINK_CONTEXT(trunk, tei), Q921_STATS_RECV_INVALID_U);
03195 #endif
03196                 Q921Log(trunk, Q921_LOG_ERROR, "Invalid U frame type: %d\n", m);
03197                 break;
03198         }
03199 
03200         return res;
03201 }
03202 
03203 
03204 /*****************************************************************************
03205 
03206   Function:     Q921Rx12
03207 
03208   Description:  Called to process a message frame from layer 1. Will
03209                 identify the message and call the proper 'processor' for
03210                 layer 2 messages and forward I frames to the layer 3 entity.
03211 
03212                 Q921Rx12 will check the input fifo for a message, and if a
03213                 message exist process one message before it exits. The caller
03214                 must either call Q921Rx12 polling or keep track on #
03215                 messages in the queue.
03216 
03217   Parameters:   trunk       trunk #.
03218 
03219   Return Value: # messages processed (always 1 or 0).
03220 
03221 *****************************************************************************/
03222 int Q921Rx12(L2TRUNK trunk)
03223 {
03224         L2INT size;     /* receive size & Q921 frame size*/
03225         L2UCHAR *smes = MFIFOGetMesPtr(trunk->HDLCInQueue, &size);
03226 
03227         if (smes)
03228         {
03229                 struct Q921_Link *link;
03230                 L2UCHAR sapi, tei;
03231                 L2UCHAR *mes;
03232                 L2INT rs;
03233 
03234                 rs  = size - trunk->Q921HeaderSpace;
03235                 mes = &smes[trunk->Q921HeaderSpace];
03236 
03237                 Q921LogMesg(trunk, Q921_LOG_DEBUG, 1, mes, rs, "New packet received (%d bytes)\n", rs);
03238 
03239                 /* common fields: get sapi, tei and cr */
03240                 sapi = (mes[0] & 0xfc) >> 2;
03241                 tei  = (mes[1] & 0xfe) >> 1;
03242                 link  = Q921_LINK_CONTEXT(trunk, tei);
03243 
03244                 if (Q921_IS_PTMP_TE(trunk) && (
03245                          (link->state >= Q921_STATE_TEI_ASSIGNED && tei != link->tei && tei != Q921_TEI_BCAST) ||                       /* Assigned TEI: Only BCAST and directed */
03246                          (link->state == Q921_STATE_TEI_UNASSIGNED && tei != Q921_TEI_BCAST)))                                  /* No assigned TEI: Only BCAST */
03247                 {
03248                         /* Ignore Messages with foreign TEIs */
03249                         Q921Log(trunk, Q921_LOG_DEBUG, "Frame with foreign TEI %hhu ignored\n", tei);
03250                         goto out;
03251                 }
03252 
03253                 if ((mes[2] & 0x01) == 0x00) {          /* I frame */
03254                         Q921ProcIFrame(trunk, mes, rs);
03255                 }
03256                 else if ((mes[2] & 0x03) == 0x01) {     /* S frame */
03257                         Q921ProcSFrame(trunk, mes, rs);
03258                 }
03259                 else if ((mes[2] & 0x03) == 0x03) {     /* U frame */
03260                         Q921ProcUFrame(trunk, mes, rs);
03261                 }
03262                 else {
03263                         Q921Log(trunk, Q921_LOG_ERROR, "Invalid frame type: %d\n", (int)(mes[2] & 0x03));
03264                         /* TODO: send FRMR or REJ */
03265                 }
03266 
03267 out:
03268                 MFIFOKillNext(trunk->HDLCInQueue);
03269 
03270                 return 1;
03271         }
03272 
03273         return 0;
03274 }
03275 
03276 /*
03277  * Misc
03278  */
03288 void Q921SetLogCB(L2TRUNK trunk, Q921LogCB_t func, void *priv)
03289 {
03290         if (!trunk)
03291                 return;
03292 
03293         trunk->Q921LogProc = func;
03294         trunk->PrivateDataLog = priv;
03295 }
03296 
03305 void Q921SetLogLevel(L2TRUNK trunk, Q921LogLevel_t level)
03306 {
03307         if (!trunk)
03308                 return;
03309 
03310         if (level < Q921_LOG_NONE) {
03311                 level = Q921_LOG_NONE;
03312         } else if (level > Q921_LOG_DEBUG) {
03313                 level = Q921_LOG_DEBUG;
03314         }
03315 
03316         trunk->loglevel = level;
03317 }
03318 
03319 
03328 Q921_API Q921LogLevel_t Q921GetLogLevel(L2TRUNK trunk)
03329 {
03330         if (!trunk) {
03331                 return Q921_LOG_NONE;
03332         }
03333         return trunk->loglevel;
03334 }
03335 
03336 
03337 static const char *loglevel_names[] = {
03338         [Q921_LOG_DEBUG]   = "debug",
03339         [Q921_LOG_INFO]    = "info",
03340         [Q921_LOG_NOTICE]  = "notice",
03341         [Q921_LOG_WARNING] = "warning",
03342         [Q921_LOG_ERROR]   = "error",
03343         [Q921_LOG_ALERT]   = "alert",
03344         [Q921_LOG_CRIT]    = "critical",
03345         [Q921_LOG_EMERG]   = "emergency"
03346 };
03347 
03356 Q921_API const char * Q921GetLogLevelName(L2TRUNK trunk)
03357 {
03358         if (!trunk) {
03359                 return "unknown";
03360         }
03361         if (trunk->loglevel == Q921_LOG_NONE) {
03362                 return "none";
03363         }
03364         return loglevel_names[trunk->loglevel];
03365 }
03366 
03376 static int Q921ChangeState(L2TRUNK trunk, Q921State_t state, L2UCHAR tei)
03377 {
03378         struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
03379         Q921State_t oldstate = link->state;
03380         int res = 0;
03381 
03382         Q921Log(trunk, Q921_LOG_DEBUG, "Changing state from \"%s\" (%d) to \"%s\" (%d) for TEI %d\n",
03383                                 Q921State2Name(oldstate), oldstate,
03384                                 Q921State2Name(state), state,
03385                                 tei);
03386 
03387         /*
03388          * generic actions (depending on the target state only)
03389          */
03390         switch (state) {
03391         case Q921_STATE_MULTIPLE_FRAME_ESTABLISHED:
03392                 /* Start TM01 */
03393                 if (Q921_IS_NT(trunk)) {
03394                         Q921TM01TimerStart(trunk, tei);
03395                 }
03396                 break;
03397 
03398         default:
03399                 break;
03400         }
03401 
03402         /*
03403          * actions that depend on type of the old -> new state transition
03404          */
03405         switch (oldstate) {
03406         case Q921_STATE_STOPPED:
03407 
03408                 switch (state) {
03409                 case Q921_STATE_TEI_UNASSIGNED:
03410                         if (Q921_IS_PTMP_TE(trunk)) {
03411                                 res = Q921TeiSendAssignRequest(trunk);
03412                         }
03413                         break;
03414 
03415                 case Q921_STATE_TEI_ASSIGNED:
03416                         if (Q921_IS_PTMP_NT(trunk)) {
03417                                 res = Q921TeiSendRemoveRequest(trunk, Q921_TEI_BCAST);
03418                         }
03419                         break;
03420 
03421                 default:
03422                         break;
03423                 }
03424                 break;
03425 
03426         default:
03427                 break;
03428         }
03429 
03430         link->state = state;
03431 
03432         Q921Log(trunk, Q921_LOG_DEBUG, "Q921ChangeState() returns %d, new state is \"%s\" (%d) for TEI %d\n", res, Q921State2Name(state), state, tei);
03433 
03434 #ifdef Q921_STATISTICS
03435         /* update counter, states map 1:1 to counter IDs */
03436         Q921StatsIncrementCounter(link, state);
03437 #endif
03438 
03439         /*
03440          * Flush UI Queue
03441          */
03442         if (state >= Q921_STATE_TEI_ASSIGNED && MFIFOGetMesCount(link->UIFrameQueue) > 0) {
03443                 Q921Log(trunk, Q921_LOG_DEBUG, "Q921ChangeState() flushing UI-Frame queue for TEI %d\n", tei);
03444                 Q921SendQueuedUIFrame(trunk, tei);
03445         }
03446         return res;
03447 }
03448 
03449 /*
03450  * TEI Management functions
03451  * \note        All TEI-mgmt UN frames are sent with cr = command!
03452  */
03453 static int Q921TeiSend(L2TRUNK trunk, L2UCHAR type, L2USHORT ri, L2UCHAR ai)
03454 {
03455         L2UCHAR mes[10];
03456         L2UCHAR offset = Q921_UFRAME_DATA_OFFSET(trunk);
03457 
03458         mes[offset++] = Q921_LAYER_ENT_ID_TEI;  /* layer management entity identifier */
03459         mes[offset++] = (ri & 0xff00) >> 8;     /* reference number upper part */
03460         mes[offset++] =  ri & 0xff;             /* reference number lower part */
03461         mes[offset++] = type;                   /* message type: Identity Request */
03462         mes[offset++] = ai << 1 | 0x01;         /* action indicator: TEI */
03463 
03464 #ifdef Q921_STATISTICS_EXTENDED
03465 /* TODO:        Q921StatsIncrementCounter(Q921_TRUNK_CONTEXT(trunk), Q921_STATS_SEND_I); */
03466 #endif
03467 
03468         return Q921SendU(trunk, Q921_SAPI_TEI, Q921_COMMAND(trunk), Q921_TEI_BCAST, 0, 0x00, mes, offset);
03469 }
03470 
03471 
03480 static int Q921TeiSendAssignRequest(L2TRUNK trunk)
03481 {
03482         struct Q921_Link *link = Q921_TRUNK_CONTEXT(trunk);
03483         L2INT res;
03484 
03485         if (!Q921_IS_PTMP_TE(trunk))    /* only ptmp te mode*/
03486                 return 0;
03487 
03488 #if defined(HAVE_RANDOM)
03489         link->ri = (L2USHORT)(random() % 0xffff);
03490 #elif defined(HAVE_RAND)
03491         link->ri = (L2USHORT)(rand() % 0xffff);
03492 #else
03493 #error "Neither rand() nor random() available"
03494 #endif
03495 
03496         /* send TEI assign request */
03497         res = Q921TeiSend(trunk, Q921_TEI_ID_REQUEST, link->ri, Q921_TEI_BCAST);
03498 
03499         /* start T202 */
03500         Q921T202TimerStart(trunk);
03501 
03502 #ifdef Q921_STATISTICS_EXTENDED
03503         Q921StatsIncrementCounter(link, Q921_STATS_TEI_SEND_AR);
03504 #endif
03505         return res;
03506 }
03507 
03508 
03519 static int Q921TeiProcAssignResponse(L2TRUNK trunk, L2UCHAR *mes, L2INT size)
03520 {
03521         struct Q921_Link *link = Q921_TRUNK_CONTEXT(trunk);
03522         L2UCHAR offset = Q921_UFRAME_DATA_OFFSET(trunk);
03523         L2USHORT ri = 0;
03524 
03525         if (!Q921_IS_PTMP_TE(trunk))    /* PTMP TE only */
03526                 return 0;
03527 
03528         ri = (mes[offset + 1] << 8) | mes[offset + 2];
03529 
03530         if (ri != link->ri) {
03531                 /* hmmm ..., not our response i guess */
03532                 return 0;
03533         }
03534 
03535 #ifdef Q921_STATISTICS_EXTENDED
03536         Q921StatsIncrementCounter(link, Q921_STATS_TEI_RECV_AS);
03537 #endif
03538         switch (mes[offset + 3]) {
03539         case Q921_TEI_ID_ASSIGNED:
03540                 /* Yay, use the new TEI and change state to assigned */
03541                 link->tei      = mes[offset + 4] >> 1;
03542 
03543                 Q921Log(trunk, Q921_LOG_DEBUG, "Assigned TEI %d, setting state to TEI_ASSIGNED\n", link->tei);
03544 
03545                 Q921ChangeState(trunk, Q921_STATE_TEI_ASSIGNED, link->tei);
03546                 break;
03547 
03548         case Q921_TEI_ID_DENIED:
03549                 /* oops, what to do now? */
03550                 if ((mes[offset + 4] >> 1) == Q921_TEI_BCAST) {
03551                         /* No more free TEIs? this is bad */
03552 
03553                         //Q921TeiSendVerifyRequest(trunk, Q921_TEI_BCAST); /* TODO: does this work ?? */
03554                 } else {
03555                         /* other reason, this is fatal, shutdown link */
03556                 }
03557 
03558                 Q921Log(trunk, Q921_LOG_DEBUG, "TEI assignment has been denied, reason: %s\n",
03559                          ((mes[offset +4] >> 1) == Q921_TEI_BCAST) ? "No free TEIs available" : "Unknown");
03560 
03561                 Q921ChangeState(trunk, Q921_STATE_TEI_UNASSIGNED, link->tei);
03562                 break;
03563 
03564         default:
03565                 return 0;
03566         }
03567 
03568         /* stop T202 */
03569         Q921T202TimerStop(trunk);
03570 
03571         return 1;
03572 }
03573 
03574 
03583 static int Q921TeiSendVerifyRequest(L2TRUNK trunk)
03584 {
03585         struct Q921_Link *link = Q921_TRUNK_CONTEXT(trunk);
03586         L2INT res;
03587 
03588         if (!Q921_IS_PTMP_TE(trunk))    /* only ptmp te mode*/
03589                 return 0;
03590 
03591         /* Request running? */
03592         if (trunk->T202)
03593                 return 0;
03594 
03595         /* Send TEI verify request */
03596         res = Q921TeiSend(trunk, Q921_TEI_ID_VERIFY, link->ri, link->tei);
03597 
03598         /* start T202 */
03599         Q921T202TimerStart(trunk);
03600 
03601 #ifdef Q921_STATISTICS_EXTENDED
03602         Q921StatsIncrementCounter(link, Q921_STATS_TEI_SEND_VR);
03603 #endif
03604         return res;
03605 }
03606 
03607 
03618 static int Q921TeiProcCheckRequest(L2TRUNK trunk, L2UCHAR *mes, L2INT size)
03619 {
03620         struct Q921_Link *link = Q921_TRUNK_CONTEXT(trunk);
03621         L2UCHAR offset = Q921_UFRAME_DATA_OFFSET(trunk);
03622         L2UCHAR tei = (mes[offset + 4] >> 1);           /* action indicator => tei */
03623         L2INT res = 0;
03624 
03625         if (!Q921_IS_PTMP_TE(trunk))    /* ptmp te mode only */
03626                 return 0;
03627 
03628         Q921Log(trunk, Q921_LOG_DEBUG, "Received TEI Check request for TEI %d\n", tei);
03629 
03630 #ifdef Q921_STATISTICS_EXTENDED
03631         Q921StatsIncrementCounter(link, Q921_STATS_TEI_RECV_CR);
03632 #endif
03633         if (tei == Q921_TEI_BCAST || tei == link->tei) {
03634                 /*
03635                  * Broadcast TEI check or for our assigned TEI
03636                  */
03637 
03638                 /* send TEI check reponse */
03639                 res = Q921TeiSend(trunk, Q921_TEI_ID_CHECKRESP, link->ri, link->tei);
03640 
03641                 Q921T202TimerStop(trunk);
03642 
03643 #ifdef Q921_STATISTICS_EXTENDED
03644                 Q921StatsIncrementCounter(link, Q921_STATS_TEI_SEND_CS);
03645 #endif
03646         }
03647 
03648         return res;
03649 }
03650 
03651 
03662 static int Q921TeiProcRemoveRequest(L2TRUNK trunk, L2UCHAR *mes, L2INT size)
03663 {
03664         struct Q921_Link *link = Q921_TRUNK_CONTEXT(trunk);
03665         L2UCHAR offset = Q921_UFRAME_DATA_OFFSET(trunk);
03666         L2UCHAR tei = (mes[offset + 4] >> 1);           /* action indicator => tei */
03667         L2INT res = 0;
03668 
03669         if (!Q921_IS_PTMP_TE(trunk))    /* ptmp te mode only */
03670                 return 0;
03671 
03672         Q921Log(trunk, Q921_LOG_DEBUG, "Received TEI Remove request for TEI %d\n", tei);
03673 
03674 #ifdef Q921_STATISTICS_EXTENDED
03675         Q921StatsIncrementCounter(link, Q921_STATS_TEI_RECV_RR);
03676 #endif
03677         if (tei == Q921_TEI_BCAST || tei == link->tei) {
03678                 /*
03679                  * Broadcast TEI remove or for our assigned TEI
03680                  */
03681 
03682                 /* reset tei */
03683                 link->tei  = 0;
03684 
03685                 /* change state (no action) */
03686                 Q921ChangeState(trunk, Q921_STATE_TEI_UNASSIGNED, link->tei);
03687 
03688                 /* TODO: hmm, request new one ? */
03689                 res = Q921TeiSendAssignRequest(trunk);
03690         }
03691         return res;
03692 }
03693 
03694 
03705 static int Q921TeiProcAssignRequest(L2TRUNK trunk, L2UCHAR *mes, L2INT size)
03706 {
03707         L2UCHAR offset = Q921_UFRAME_DATA_OFFSET(trunk);
03708         L2USHORT ri = 0;
03709         L2UCHAR tei = 0;
03710 
03711         if (!Q921_IS_PTMP_NT(trunk))    /* PTMP NT only */
03712                 return 0;
03713 
03714         ri  = (mes[offset + 1] << 8) | mes[offset + 2];
03715         tei =  mes[offset + 4] >> 1;
03716 
03717         if (tei == Q921_TEI_BCAST) {
03718                 int x;
03719 
03720                 /* dynamically allocate TEI */
03721                 for (x = Q921_TEI_DYN_MIN, tei = 0; x <= Q921_TEI_MAX; x++) {
03722                         if (!trunk->tei_map[x]) {
03723                                 tei = x;
03724                                 break;
03725                         }
03726                 }
03727         }
03728         else if (!(tei > 0 && tei < Q921_TEI_DYN_MIN)) {
03729                 /* reject TEIs that are not in the static area */
03730                 Q921TeiSendDenyResponse(trunk, 0, ri);
03731 
03732                 return 0;
03733         }
03734 
03735         if (!tei) {
03736                 /* no free TEI found */
03737                 Q921TeiSendDenyResponse(trunk, Q921_TEI_BCAST, ri);
03738         }
03739         else {
03740                 struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
03741 
03742                 /* mark used */
03743                 trunk->tei_map[tei] = 1;
03744 
03745                 /* assign tei */
03746                 link->tei = tei;
03747 
03748                 /* put context in TEI ASSIGNED state */
03749                 Q921ChangeState(trunk, Q921_STATE_TEI_ASSIGNED, tei);
03750 
03751                 /* send assign response */
03752                 Q921TeiSendAssignedResponse(trunk, tei, ri);
03753 
03754                 /* Start T201 */
03755                 Q921T201TimerStart(trunk, tei);
03756 
03757 #ifdef Q921_STATISTICS_EXTENDED
03758                 Q921StatsIncrementCounter(link, Q921_STATS_TEI_RECV_AR);
03759 #endif
03760         }
03761         return 0;
03762 }
03763 
03773 static int Q921TeiSendCheckRequest(L2TRUNK trunk, L2UCHAR tei)
03774 {
03775         L2INT res = 0;
03776 
03777         if (!Q921_IS_PTMP_NT(trunk))    /* PTMP NT only */
03778                 return 0;
03779 
03780         /* send TEI check request */
03781         res = Q921TeiSend(trunk, Q921_TEI_ID_CHECKREQ, 0, tei);
03782 
03783         /* (Re-)Start T201 timer */
03784         Q921T201TimerStart(trunk, tei);
03785 
03786 #ifdef Q921_STATISTICS_EXTENDED
03787         Q921StatsIncrementCounter(Q921_LINK_CONTEXT(trunk, tei), Q921_STATS_TEI_SEND_CR);
03788 #endif
03789         return res;
03790 }
03791 
03802 static int Q921TeiProcCheckResponse(L2TRUNK trunk, L2UCHAR *mes, L2INT size)
03803 {
03804         struct Q921_Link *link;
03805         L2UCHAR offset = Q921_UFRAME_DATA_OFFSET(trunk);
03806         L2USHORT ri = 0;
03807         L2UCHAR tei = 0;
03808 
03809         if (!Q921_IS_PTMP_NT(trunk))    /* PTMP NT mode only */
03810                 return 0;
03811 
03812         ri  = (mes[offset + 1] << 8) | mes[offset + 2];
03813         tei =  mes[offset + 4] >> 1;
03814 
03815         /* restart T201 */
03816         Q921T201TimerStop(trunk, tei);
03817 
03818         /* reset counter */
03819         link       = Q921_LINK_CONTEXT(trunk, tei);
03820         link->N202 = 0;
03821 
03822         if (!(tei > 0 && tei < Q921_TEI_MAX) || !trunk->tei_map[tei]) {
03823                 /* TODO: Should we send a DISC first? */
03824 
03825                 /* TEI not assigned? Invalid TEI? */
03826                 Q921TeiSendRemoveRequest(trunk, tei);
03827 
03828                 /* change state */
03829                 Q921ChangeState(trunk, Q921_STATE_STOPPED, tei);
03830 
03831                 /* clear */
03832                 memset(link, 0, sizeof(struct Q921_Link));
03833         } else {
03834                 /* Start T201 */
03835                 Q921T201TimerStart(trunk, tei);
03836         }
03837 
03838 #ifdef Q921_STATISTICS_EXTENDED
03839         Q921StatsIncrementCounter(link, Q921_STATS_TEI_RECV_CS);
03840 #endif
03841         return 0;
03842 }
03843 
03844 
03855 static int Q921TeiProcVerifyRequest(L2TRUNK trunk, L2UCHAR *mes, L2INT size)
03856 {
03857         L2UCHAR resp[25];
03858         L2UCHAR offset = Q921_UFRAME_DATA_OFFSET(trunk);
03859         L2UCHAR tei = 0;
03860 
03861         if (!Q921_IS_PTMP_NT(trunk))    /* PTMP NT mode only */
03862                 return 0;
03863 
03864         tei = mes[offset + 4] >> 1;
03865 
03866         /* todo: handle response... verify assigned TEI */
03867         resp[offset + 0] = 0;
03868 
03869 #ifdef Q921_STATISTICS_EXTENDED
03870         Q921StatsIncrementCounter(Q921_LINK_CONTEXT(trunk, tei), Q921_STATS_TEI_RECV_VR);
03871 #endif
03872         return 0;
03873 }
03874 
03883 static int Q921TeiSendDenyResponse(L2TRUNK trunk, L2UCHAR tei, L2USHORT ri)
03884 {
03885         if (!Q921_IS_PTMP_NT(trunk))    /* PTMP NT only */
03886                 return 0;
03887 
03888 #ifdef Q921_STATISTICS_EXTENDED
03889         Q921StatsIncrementCounter(Q921_LINK_CONTEXT(trunk, tei), Q921_STATS_TEI_SEND_DS);
03890 #endif
03891         return Q921TeiSend(trunk, Q921_TEI_ID_DENIED, ri, tei);
03892 }
03893 
03894 
03905 static int Q921TeiSendAssignedResponse(L2TRUNK trunk, L2UCHAR tei, L2USHORT ri)
03906 {
03907         if (!Q921_IS_PTMP_NT(trunk))    /* PTMP NT only */
03908                 return 0;
03909 
03910 #ifdef Q921_STATISTICS_EXTENDED
03911         Q921StatsIncrementCounter(Q921_LINK_CONTEXT(trunk, tei), Q921_STATS_TEI_SEND_AS);
03912 #endif
03913         return Q921TeiSend(trunk, Q921_TEI_ID_ASSIGNED, ri, tei);
03914 }
03915 
03925 static int Q921TeiSendRemoveRequest(L2TRUNK trunk, L2UCHAR tei)
03926 {
03927         if (!Q921_IS_PTMP_NT(trunk))    /* PTMP NT only */
03928                 return 0;
03929 
03930 #ifdef Q921_STATISTICS_EXTENDED
03931         Q921StatsIncrementCounter(Q921_LINK_CONTEXT(trunk, tei), Q921_STATS_TEI_SEND_RR);
03932 #endif
03933         return Q921TeiSend(trunk, Q921_TEI_ID_REMOVE, 0, tei);
03934 }
03935 
03936 
03937 #ifdef Q921_STATISTICS
03938 
03941 static struct Q921StatsCounter Q921StatsCounters[] = {
03942         /* State changes */
03943         { Q921_STATS_ST01, "ST01", "State: changed to TEI Unassigned" },
03944         { Q921_STATS_ST02, "ST02", "State: changed to TEI Awaiting" },
03945         { Q921_STATS_ST03, "ST03", "State: changed to TEI Establish" },
03946         { Q921_STATS_ST04, "ST04", "State: changed to TEI Assigned" },
03947         { Q921_STATS_ST05, "ST05", "State: changed to Awaiting Establishment" },
03948         { Q921_STATS_ST06, "ST06", "State: changed to Awaiting Release" },
03949         { Q921_STATS_ST07, "ST07", "State: changed to Multiple Frame Established" },
03950         { Q921_STATS_ST08, "ST08", "State: changed to Timer Recovery" },
03951 
03952         /* Event counters */
03953         { Q921_STATS_T200, "T200", "Timer: T200 Timeouts" },
03954         { Q921_STATS_T201, "T201", "Timer: T201 Timeouts" },
03955         { Q921_STATS_T202, "T202", "Timer: T202 Timeouts" },
03956         { Q921_STATS_T203, "T203", "Timer: T203 Timeouts" },
03957 
03958         { Q921_STATS_TM01, "TM01", "Timer: TM01 Timeouts" },
03959 
03960         { Q921_STATS_N200, "N200", "Limit: Max. retransmit exceeded" },
03961         { Q921_STATS_N201, "N201", "Limit: Max. frame size exceeded" },
03962         { Q921_STATS_N202, "N202", "Limit: Max. PtMP TE retransmit exceeded" },
03963 
03964 #ifdef Q921_STATISTICS_EXTENDED
03965         /* packet transmit counter */
03966         { Q921_STATS_SEND_S, "TX-S", "TX: S frames sent" },
03967         { Q921_STATS_SEND_U, "TX-U", "TX: U frames sent" },
03968         { Q921_STATS_SEND_I, "TX-I", "TX: I frames sent" },
03969 
03970         { Q921_STATS_SEND_DISC,  "TX-DISC",  "TX: Disconnect" },
03971         { Q921_STATS_SEND_DM,    "TX-DM",    "TX: Disconnected-Mode" },
03972         { Q921_STATS_SEND_REJ,   "TX-REJ",   "TX: Reject" },
03973         { Q921_STATS_SEND_RR,    "TX-RR",    "TX: Receiver-Ready" },
03974         { Q921_STATS_SEND_RNR,   "TX-RNR",   "TX: Receiver-Not-Ready" },
03975         { Q921_STATS_SEND_SABME, "TX-SABME", "TX: Set Asynchronous Balanced Mode Extended" },
03976         { Q921_STATS_SEND_UA,    "TX-UA",    "TX: Unnumbered Acknowledgement" },
03977         { Q921_STATS_SEND_UN,    "TX-UN",    "TX: Unnumbered Information" },
03978 
03979         /* packet receive counter */
03980         { Q921_STATS_RECV_S, "RX-S", "RX: S frames received" },
03981         { Q921_STATS_RECV_U, "RX-U", "RX: U frames received" },
03982         { Q921_STATS_RECV_I, "RX-I", "RX: I frames received" },
03983 
03984         { Q921_STATS_RECV_DISC,  "RX-DISC",  "RX: Disconnect" },
03985         { Q921_STATS_RECV_DM,    "RX-DM",    "RX: Disconnected-Mode" },
03986         { Q921_STATS_RECV_REJ,   "RX-REJ",   "RX: Reject" },
03987         { Q921_STATS_RECV_RR,    "RX-RR",    "RX: Receiver-Ready" },
03988         { Q921_STATS_RECV_RNR,   "RX-RNR",   "RX: Receiver-Not-Ready" },
03989         { Q921_STATS_RECV_SABME, "RX-SABME", "RX: Set Asynchronous Balanced Mode Extended" },
03990         { Q921_STATS_RECV_UA,    "RX-UA",    "RX: Unnumbered Acknowledgement" },
03991         { Q921_STATS_RECV_UN,    "RX-UN",    "RX: Unnumbered Information" },
03992 
03993         { Q921_STATS_RECV_INVALID_S, "RX-INV-S", "RX: Invalid S frames received" },
03994         { Q921_STATS_RECV_INVALID_U, "RX-INV-U", "RX: Invalid U frames received" },
03995         { Q921_STATS_RECV_INVALID_I, "RX-INV-I", "RX: Invalid I frames received" },
03996 
03997         /* TEI-management */
03998         { Q921_STATS_TEI_SEND_AR, "TEI-AR", "TEI TX: Assign-Request sent" },
03999         { Q921_STATS_TEI_SEND_AS, "TEI-AS", "TEI TX: Assigned Response sent" },
04000         { Q921_STATS_TEI_SEND_CR, "TEI-CR", "TEI TX: Check-Request sent" },
04001         { Q921_STATS_TEI_SEND_CS, "TEI-CS", "TEI TX: Check Response sent" },
04002         { Q921_STATS_TEI_SEND_DS, "TEI-DS", "TEI TX: Deny Response sent" },
04003         { Q921_STATS_TEI_SEND_RR, "TEI-RR", "TEI TX: Remove-Request sent" },
04004         { Q921_STATS_TEI_SEND_VR, "TEI-VR", "TEI TX: Verify-Request sent" },
04005 
04006         { Q921_STATS_TEI_RECV_AR, "TEI-AR", "TEI RX: Assign-Request received" },
04007         { Q921_STATS_TEI_RECV_AS, "TEI-AS", "TEI RX: Assign Response received" },
04008         { Q921_STATS_TEI_RECV_CR, "TEI-CR", "TEI RX: Check-Request received" },
04009         { Q921_STATS_TEI_RECV_CS, "TEI-CS", "TEI RX: Check Response received" },
04010         { Q921_STATS_TEI_RECV_RR, "TEI-RR", "TEI RX: Remove-Request received" },
04011         { Q921_STATS_TEI_RECV_VR, "TEI-VR", "TEI RX: Verify-Request received" },
04012 #endif
04013 
04014         /* don't touch */
04015         { 0, NULL, NULL }
04016 };
04017 
04018 Q921_API int Q921StatsCounterIsGlobal(const struct Q921StatsCounter *counter)
04019 {
04020         switch (counter->id) {
04021         case Q921_STATS_T202:
04022         case Q921_STATS_N201:
04023                 return 1;
04024         default:
04025                 return 0;
04026         }
04027 }
04028 
04029 Q921_API int Q921StatsCounterIsError(const struct Q921StatsCounter *counter)
04030 {
04031         switch (counter->id) {
04032         /* error states */
04033         case Q921_STATS_ST08:
04034         /* limit errors */
04035         case Q921_STATS_N200:
04036         case Q921_STATS_N201:
04037         case Q921_STATS_N202:
04038         /* frame errors */
04039         case Q921_STATS_SEND_REJ:
04040         case Q921_STATS_RECV_REJ:
04041         case Q921_STATS_RECV_INVALID_S:
04042         case Q921_STATS_RECV_INVALID_I:
04043         case Q921_STATS_RECV_INVALID_U:
04044         /* TEI-management errors */
04045         case Q921_STATS_TEI_SEND_DS:
04046                 return 1;
04047         default:
04048                 return 0;
04049         }
04050 }
04051 
04052 Q921_API int Q921StatsCounterIsAvailable(const L2TRUNK trunk, const struct Q921StatsCounter *counter)
04053 {
04054         if (Q921_IS_PTP(trunk)) {
04055                 /* no TEI management on PRI */
04056                 if (counter->id >= Q921_STATS_ST01 && counter->id <= Q921_STATS_ST03)
04057                         return 0;
04058                 /* no TEI management on PRI */
04059                 if (counter->id >= Q921_STATS_TEI_SEND_AR && counter->id <= Q921_STATS_TEI_RECV_VR)
04060                         return 0;
04061         }
04062         return 1;
04063 }
04064 
04065 Q921_API struct Q921StatsCounter *Q921StatsCounterGet(const int id)
04066 {
04067         struct Q921StatsCounter *info = Q921StatsCounters;
04068 
04069         if (id <= Q921_STATS_NONE || id >= Q921_STATS_MAX)
04070                 return NULL;
04071 
04072         while (info->id) {
04073                 if (info->id == id)
04074                         return info;
04075                 info++;
04076         }
04077         return NULL;
04078 }
04079 
04080 Q921_API const char * Q921StatsCounterGetDescription(const int id)
04081 {
04082         struct Q921StatsCounter *info = Q921StatsCounterGet(id);
04083         return (info) ? info->desc : "invalid";
04084 }
04085 
04086 Q921_API const char * Q921StatsCounterGetName(const int id)
04087 {
04088         struct Q921StatsCounter *info = Q921StatsCounterGet(id);
04089         return (info) ? info->name : "invalid";
04090 }
04091 
04092 Q921_API int Q921StatsCounterGetIsGlobal(const int id)
04093 {
04094         struct Q921StatsCounter *info = Q921StatsCounterGet(id);
04095         return Q921StatsCounterIsGlobal(info);
04096 }
04097 
04098 Q921_API unsigned int Q921StatsCounterGetValue(const L2TRUNK trunk, const int id, const int tei)
04099 {
04100         struct Q921StatsCounter *info = Q921StatsCounterGet(id);
04101         return Q921StatsCounterValue(trunk, info, tei);
04102 }
04103 
04104 /*** Iteration helpers ***/
04105 
04109 Q921_API const struct Q921StatsCounter *Q921StatsCounterFirst(void)
04110 {
04111         return Q921StatsCounterGet(1);
04112 }
04113 
04114 Q921_API const struct Q921StatsCounter *Q921StatsCounterNext(const struct Q921StatsCounter *counter)
04115 {
04116         int id = counter->id + 1;
04117 
04118         if (id <= Q921_STATS_NONE || id >= Q921_STATS_MAX)
04119                 return NULL;
04120 
04121         return Q921StatsCounterGet(id);
04122 }
04123 
04124 Q921_API unsigned int Q921StatsCounterValue(const L2TRUNK trunk, const struct Q921StatsCounter *counter, const int tei)
04125 {
04126         struct Q921_Link *link = NULL;
04127 
04128         if (!trunk || !counter)
04129                 return 0;
04130 
04131         if (counter->id <= Q921_STATS_NONE || counter->id >= Q921_STATS_MAX)
04132                 return 0;
04133 
04134         if (Q921StatsCounterIsGlobal(counter)) {
04135                 link = Q921_TRUNK_CONTEXT(trunk);
04136 
04137         } else if (tei == Q921_TEI_BCAST) {
04138                 unsigned int sum = 0;
04139                 int i;
04140 
04141                 link = Q921_TRUNK_CONTEXT(trunk);
04142 
04143                 sum += link->stats.counter[counter->id];
04144 
04145                 if (Q921_IS_PTMP(trunk)) {
04146                         for (i = 1; i < Q921_TEI_BCAST; i++) {
04147                                 link = Q921_LINK_CONTEXT(trunk, i);
04148 
04149                                 sum += link->stats.counter[counter->id];
04150                         }
04151                 }
04152 
04153                 return sum;
04154         } else {
04155                 link = Q921_LINK_CONTEXT(trunk, tei);
04156         }
04157 
04158         return link->stats.counter[counter->id];
04159 }
04160 
04161 Q921_API int Q921StatsCounterID(const struct Q921StatsCounter *counter)
04162 {
04163         return counter->id;
04164 }
04165 
04166 Q921_API const char *Q921StatsCounterName(const struct Q921StatsCounter *counter)
04167 {
04168         return counter->name;
04169 }
04170 
04171 Q921_API const char *Q921StatsCounterDescription(const struct Q921StatsCounter *counter)
04172 {
04173         return counter->desc;
04174 }
04175 
04176 Q921_API void Q921StatsCounterResetAll(L2TRUNK trunk, const int tei)
04177 {
04178         if (!trunk)
04179                 return;
04180 
04181         if (tei < 0 || tei > Q921_TEI_MAX)
04182                 return;
04183 
04184         if (tei == Q921_TEI_MAX) {
04185                 int nlinks = Q921_IS_PTMP(trunk) ? Q921_TEI_MAX : 1;
04186 
04187                 /* reset link counters */
04188                 for (int x = 0; x < nlinks; x++) {
04189                         memset(&trunk->context[x].stats, 0, sizeof(Q921Stats_t));
04190                 }
04191         } else if (Q921_IS_PTMP(trunk)) {
04192                 memset(&trunk->context[tei].stats, 0, sizeof(Q921Stats_t));
04193         } else {
04194                 memset(&trunk->context[0].stats, 0, sizeof(Q921Stats_t));
04195         }
04196 }
04197 
04198 Q921_API void Q921StatsCounterReset(L2TRUNK trunk, const int id, const int tei)
04199 {
04200         if (!trunk)
04201                 return;
04202 
04203         if (tei < 0 || tei > Q921_TEI_MAX)
04204                 return;
04205 
04206         if (id <= Q921_STATS_NONE || id >= Q921_STATS_MAX)
04207                 return;
04208 
04209         if (tei == Q921_TEI_MAX) {
04210                 int nlinks = Q921_IS_PTMP(trunk) ? Q921_TEI_MAX : 1;
04211 
04212                 /* reset link counters */
04213                 for (int x = 0; x < nlinks; x++) {
04214                         trunk->context[x].stats.counter[id] =  0;
04215                 }
04216         } else if (Q921_IS_PTMP(trunk)) {
04217                 trunk->context[tei].stats.counter[id] = 0;
04218         } else {
04219                 trunk->context[0].stats.counter[id] = 0;
04220         }
04221 }
04222 
04229 static void Q921StatsIncrementCounter(struct Q921_Link *link, const int id)
04230 {
04231         if (!link)
04232                 return;
04233 
04234         if (id <= Q921_STATS_NONE || id >= Q921_STATS_MAX)
04235                 return;
04236 
04237         link->stats.counter[id]++;
04238 }
04239 #endif