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 <stdlib.h>
00078 #include <stdio.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 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 APPEND_MSG(buf, off, lef, fmt, ...)                     \
00543         len = snprintf(buf + off, lef, fmt, ##__VA_ARGS__);     \
00544         if(len > 0) {                                           \
00545                 off += len;                                     \
00546                 lef -= len;                                     \
00547         } else {                                                \
00548                 goto out;                                       \
00549         }
00550 
00564 static int Q921LogMesg(L2TRUNK trunk, Q921LogLevel_t level, L2UCHAR received, L2UCHAR *mes, L2INT size, const char *fmt, ...)
00565 {
00566         char  buf[Q921_LOGBUFSIZE];
00567         size_t len, left;
00568         va_list ap;
00569 
00570         if(!trunk->Q921LogProc)
00571                 return 0;
00572 
00573         if(trunk->loglevel < level)
00574                 return 0;
00575 
00576         if(!mes)
00577                 return 0;
00578 
00579         memset(buf, 0, sizeof(buf));
00580 
00581         left = sizeof(buf) - 1;
00582 
00583         va_start(ap, fmt);
00584 
00585         len = vsnprintf(buf, left, fmt, ap);
00586         if(len > 0)
00587                 left -= len;
00588         else {
00589                 /* TODO: error handling */
00590                 return -1;
00591         }
00592 
00593         va_end(ap);
00594 
00595         if(trunk->loglevel == Q921_LOG_DEBUG) {
00596                 char pbuf[1024];
00597                 size_t pleft, poffset;
00598                 L2UCHAR sapi, tei, cr;
00599                 L2UCHAR *pmes = mes + trunk->Q921HeaderSpace;
00600                 struct Q921_Link *link;
00601 
00602                 memset(pbuf, 0, sizeof(pbuf));
00603 
00604                 pleft   = sizeof(pbuf);
00605                 poffset = 0;
00606 
00607                 /*
00608                  * Decode packet
00609                  */
00610                 sapi = (pmes[0] & 0xfc) >> 2;
00611                 cr   = (pmes[0] & 0x02) >> 1;
00612                 tei  = (pmes[1] & 0xfe) >> 1;
00613                 link  = Q921_LINK_CONTEXT(trunk, tei);
00614 
00615                 /* make cr actually useful */
00616                 cr   = (received) ? Q921_IS_COMMAND(trunk, cr) : Q921_IS_RESPONSE(trunk, cr);
00617 
00618                 /* filter */
00619                 if((pmes[2] & 0x01) == 0x00) {
00620                         ;
00621                 }
00622                 else if((pmes[2] & 0x03) == 0x01) {
00623                         ; //return 0;
00624                 }
00625                 else if((pmes[2] & 0x03) == 0x03) {
00626                         ;
00627                 }
00628 
00629                 APPEND_MSG(pbuf, poffset, pleft, "\n----------------- Q.921 Packet [%s%s] ---------------\n", received ? "Incoming" : "Outgoing",
00630                                                 (tei == link->tei || tei == Q921_TEI_BCAST) ? "" : ", Ignored" );
00631 
00632                 /* common header */
00633                 APPEND_MSG(pbuf, poffset, pleft, "    SAPI: %u, TEI: %u, C/R: %s (%d)\n\n", sapi, tei, (cr) ? "Command" : "Response", (mes[0] & 0x02) >> 1 );
00634 
00635                 /*
00636                  * message specific
00637                  */
00638                 if((pmes[2] & 0x01) == 0x00) {
00639                         /*
00640                          * I frame
00641                          */
00642                         L2UCHAR pf = pmes[3] & 0x01;    /* poll / final flag */
00643                         L2UCHAR nr = pmes[3] >> 1;      /* receive sequence number */
00644                         L2UCHAR ns = pmes[2] >> 1;      /* send sequence number */
00645 
00646                         APPEND_MSG(pbuf, poffset, pleft, "    Type: I Frame\n          P/F: %d, N(S): %d, N(R): %d  [V(A): %d, V(R): %d, V(S): %d]\n", pf, ns, nr,
00647                                                                                                                 link->va, link->vr, link->vs);
00648 
00649                         /* Dump content of I Frames for foreign TEIs */
00650                         if(tei != link->tei) {
00651                                 APPEND_MSG(pbuf, poffset, pleft, "    CONTENT:\n");
00652 
00653                                 len = print_hex(pbuf + poffset, pleft, &pmes[4], size - (trunk->Q921HeaderSpace + 4));
00654                                 poffset += len;
00655                                 pleft   -= len;
00656                         }
00657                 }
00658                 else if((pmes[2] & 0x03) == 0x01) {
00659                         /*
00660                          * S frame
00661                          */
00662                         L2UCHAR sv = (pmes[2] & 0x0c) >> 2;     /* supervisory format id */
00663                         L2UCHAR pf =  pmes[3] & 0x01;           /* poll / final flag */
00664                         L2UCHAR nr =  pmes[3] >> 1;             /* receive sequence number */
00665                         const char *type;
00666 
00667                         switch(sv) {
00668                         case 0x00:      /* RR : Receive Ready */
00669                                 type = "RR (Receive Ready)";
00670                                 break;
00671 
00672                         case 0x02:      /* RNR : Receive Not Ready */
00673                                 type = "RNR (Receiver Not Ready)";
00674                                 break;
00675 
00676                         case 0x04:      /* REJ : Reject */
00677                                 type = "REJ (Reject)";
00678                                 break;
00679 
00680                         default:        /* Invalid / Unknown */
00681                                 type = "Unknown";
00682                                 break;
00683                         }
00684 
00685                         APPEND_MSG(pbuf, poffset, pleft, "    Type: S Frame, SV: %s\n          P/F: %d, N(R): %d  [V(A): %d, V(R): %d, V(S): %d]\n", type, pf, nr,
00686                                                                                                                 link->va, link->vr, link->vs);
00687                 }
00688                 else if((pmes[2] & 0x03) == 0x03) {
00689                         /*
00690                          * U frame
00691                          */
00692                         L2UCHAR m  = (pmes[2] & 0xe0) >> 3 | (pmes[2] & 0x0c) >> 2;     /* modifier function id */
00693                         L2UCHAR pf = (pmes[2] & 0x10) >> 4;                             /* poll / final flag */
00694                         const char *type;
00695 
00696                         switch(m) {
00697                         case 0x00:
00698                                 type = "UI (Unnumbered Information)";
00699                                 break;
00700 
00701                         case 0x03:
00702                                 type = "DM (Disconnected Mode)";
00703                                 break;
00704 
00705                         case 0x08:
00706                                 type = "DISC (Disconnect)";
00707                                 break;
00708 
00709                         case 0x0c:
00710                                 type = "UA (Unnumbered Acknowledgement)";
00711                                 break;
00712 
00713                         case 0x0f:
00714                                 type = "SABME";
00715                                 break;
00716 
00717                         case 0x11:
00718                                 type = "FRMR (Frame Reject)";
00719                                 break;
00720 
00721                         case 0x17:
00722                                 type = "XID (Exchange Identification)";
00723                                 break;
00724 
00725                         default:
00726                                 type = "Unknown";
00727                         }
00728 
00729 
00730                         APPEND_MSG(pbuf, poffset, pleft, "    Type: U Frame (%s)\n          P/F: %d\n", type, pf);
00731 
00732                         if(m == 0x00) {
00733                                 switch(pmes[3]) {
00734                                 case Q921_LAYER_ENT_ID_TEI:
00735                                         type = "TEI Mgmt";
00736                                         break;
00737 
00738                                 case Q921_LAYER_ENT_ID_Q931:
00739                                         type = "Q.931";
00740                                         break;
00741 
00742                                 default:
00743                                         type = "Unknown";
00744                                 }
00745 
00746                                 if(pmes[3] == Q921_LAYER_ENT_ID_TEI) {
00747                                         const char *command = "";
00748 
00749                                         switch(pmes[6]) {
00750                                         case Q921_TEI_ID_REQUEST:
00751                                                 command = "Request";
00752                                                 break;
00753                                         case Q921_TEI_ID_VERIFY:
00754                                                 command = "Verify";
00755                                                 break;
00756                                         case Q921_TEI_ID_CHECKREQ:
00757                                                 command = "Check req";
00758                                                 break;
00759                                         case Q921_TEI_ID_CHECKRESP:
00760                                                 command = "Check resp";
00761                                                 break;
00762                                         case Q921_TEI_ID_REMOVE:
00763                                                 command = "Remove";
00764                                                 break;
00765                                         case Q921_TEI_ID_ASSIGNED:
00766                                                 command = "Assign";
00767                                                 break;
00768                                         case Q921_TEI_ID_DENIED:
00769                                                 command = "Denied";
00770                                                 break;
00771                                         }
00772                                         APPEND_MSG(pbuf, poffset, pleft, "    ENT ID: %d (%s), COMMAND: %d (%s), RI: %#x, AI: %d\n",
00773                                                          pmes[3], type, pmes[6], command, (int)((pmes[4] << 8) | pmes[5]), pmes[7] >> 1);
00774                                 }
00775                                 else {
00776                                         APPEND_MSG(pbuf, poffset, pleft, "    ENT ID: %d (%s), MESSAGE CONTENT:\n", pmes[3], type);
00777 
00778                                         len = print_hex(pbuf + poffset, pleft, &pmes[3], size - (trunk->Q921HeaderSpace + 3));
00779                                         poffset += len;
00780                                         pleft   -= len;
00781                                 }
00782                         }
00783                 }       
00784                 else {
00785                         /*
00786                          * Unknown
00787                          */
00788                         strncat(pbuf + poffset, "  -- unknown frame type --\n", pleft);
00789 
00790                         len = (sizeof(pbuf) - poffset) - strlen(pbuf + poffset);
00791                         if(len > 0) {
00792                                 poffset += len;
00793                                 pleft   -= len;
00794                         } else
00795                                 goto out;
00796                 }
00797 
00798                 APPEND_MSG(pbuf, poffset, pleft, "\n    Q.921 state: \"%s\" (%d) [flags: %c%c%c%c]\n", Q921State2Name(link->state), link->state,
00799                                                                                         Q921_CHECK_FLAG(link, Q921_FLAG_ACK_PENDING) ? 'A' : '-',
00800                                                                                         Q921_CHECK_FLAG(link, Q921_FLAG_REJECT) ? 'R' : '-',
00801                                                                                         Q921_CHECK_FLAG(link, Q921_FLAG_PEER_RECV_BUSY) ? 'P' : '-',
00802                                                                                         Q921_CHECK_FLAG(link, Q921_FLAG_RECV_BUSY) ? 'B' : '-');
00803 
00804                 strncat(pbuf + poffset, "----------------------------------------------\n\n", pleft);
00805 
00806                 len = (sizeof(pbuf) - poffset) - strlen(pbuf + poffset);
00807                 if(len > 0) {
00808                         poffset += len;
00809                         pleft   -= len;
00810                 } else
00811                         goto out;
00812 
00813 
00814                 /* concat buffers together */
00815                 len = strlen(pbuf);
00816                 if(len <= left)
00817                         strncat(buf, pbuf, left);
00818                 else
00819                         strncat(buf, "-- packet truncated --\n", left);
00820         }
00821 
00822 out:
00823         buf[sizeof(buf) - 1] = '\0';
00824 
00825         return trunk->Q921LogProc(trunk->PrivateDataLog, level, buf, strlen(buf));
00826 }
00827 
00828 /*****************************************************************************
00829 
00830   Function:     Q921TimeTick
00831 
00832   Description:  Called periodically from an external source to allow the 
00833                 stack to process and maintain it's own timers.
00834 
00835   Return Value: none
00836 
00837 *****************************************************************************/
00838 static L2ULONG (*Q921GetTimeProc) (void) = NULL; /* callback for func reading time in ms */
00839 static L2ULONG tLast = {0};
00840 
00841 static L2ULONG Q921GetTime(void)
00842 {
00843         L2ULONG tNow = 0;
00844 
00845         if(Q921GetTimeProc)
00846         {
00847                 tNow = Q921GetTimeProc();
00848                 if(tNow < tLast)        /* wrapped */
00849                 {
00850                         /* TODO */
00851                 }
00852                 tLast = tNow;
00853         }
00854         return tNow;
00855 }
00856 
00857 /*
00858  * T200 handling (per-TEI in PTMP NT mode, tei=0 otherwise)
00859  */
00860 static void Q921T200TimerStart(L2TRUNK trunk, L2UCHAR tei)
00861 {
00862         struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
00863 
00864         if (!link->T200) {
00865                 link->T200 = Q921GetTime() + trunk->T200Timeout;
00866 
00867                 Q921Log(trunk, Q921_LOG_DEBUG, "T200 (timeout: %d msecs) started for TEI %d\n", trunk->T200Timeout, tei);
00868         }
00869 }
00870 
00871 static void Q921T200TimerStop(L2TRUNK trunk, L2UCHAR tei)
00872 {
00873         struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
00874 
00875         link->T200 = 0;
00876 
00877         Q921Log(trunk, Q921_LOG_DEBUG, "T200 stopped for TEI %d\n", tei);
00878 }
00879 
00880 static void Q921T200TimerReset(L2TRUNK trunk, L2UCHAR tei)
00881 {
00882         struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
00883 
00884         link->T200 = Q921GetTime() + trunk->T200Timeout;
00885 
00886         Q921Log(trunk, Q921_LOG_DEBUG, "T200 (timeout: %d msecs) restarted for TEI %d\n", trunk->T200Timeout, tei);
00887 }
00888 
00889 /*
00890  * T203 handling (per-TEI in PTMP NT mode, tei=0 otherwise)
00891  */
00892 static void Q921T203TimerStart(L2TRUNK trunk, L2UCHAR tei)
00893 {
00894         struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
00895 
00896         if (!link->T203) {
00897                 link->T203 = Q921GetTime() + trunk->T203Timeout;
00898 
00899                 Q921Log(trunk, Q921_LOG_DEBUG, "T203 (timeout: %d msecs) started for TEI %d\n", trunk->T203Timeout, tei);
00900         }
00901 }
00902 
00903 static void Q921T203TimerStop(L2TRUNK trunk, L2UCHAR tei)
00904 {
00905         struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
00906 
00907         link->T203 = 0;
00908 
00909         Q921Log(trunk, Q921_LOG_DEBUG, "T203 stopped for TEI %d\n", tei);
00910 }
00911 
00912 static void Q921T203TimerReset(L2TRUNK trunk, L2UCHAR tei)
00913 {
00914         struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
00915 
00916         link->T203 = Q921GetTime() + trunk->T203Timeout;
00917 
00918         Q921Log(trunk, Q921_LOG_DEBUG, "T203 (timeout: %d msecs) restarted for TEI %d\n", trunk->T203Timeout, tei);
00919 }
00920 
00921 /*
00922  * T202 handling (TEI message timeout, TE mode only)
00923  */
00924 static void Q921T202TimerStart(L2TRUNK trunk)
00925 {
00926         if (!trunk->T202) {
00927                 trunk->T202 = Q921GetTime() + trunk->T202Timeout;
00928 
00929                 Q921Log(trunk, Q921_LOG_DEBUG, "T202 (timeout: %d msecs) started\n", trunk->T202Timeout);
00930         }
00931 }
00932 
00933 static void Q921T202TimerStop(L2TRUNK trunk)
00934 {
00935         trunk->T202 = 0;
00936 
00937         Q921Log(trunk, Q921_LOG_DEBUG, "T202 stopped\n");
00938 }
00939 
00940 static void Q921T202TimerReset(L2TRUNK trunk)
00941 {
00942         trunk->T202 = Q921GetTime() + trunk->T202Timeout;
00943 
00944         Q921Log(trunk, Q921_LOG_DEBUG, "T202 (timeout: %d msecs) restarted\n", trunk->T202Timeout);
00945 }
00946 
00947 /*
00948  * T201 handling (TEI management (NT side), per-TEI)
00949  */
00950 static void Q921T201TimerStart(L2TRUNK trunk, L2UCHAR tei)
00951 {
00952         struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
00953 
00954         if (!link->T201) {
00955                 link->T201 = Q921GetTime() + trunk->T201Timeout;
00956 
00957                 Q921Log(trunk, Q921_LOG_DEBUG, "T201 (timeout: %d msecs) started for TEI %d\n", trunk->T201Timeout, tei);
00958         }       
00959 }
00960 
00961 static void Q921T201TimerStop(L2TRUNK trunk, L2UCHAR tei)
00962 {
00963         struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
00964 
00965         link->T201 = 0;
00966 
00967         Q921Log(trunk, Q921_LOG_DEBUG, "T201 stopped for TEI %d\n", tei);
00968 }
00969 
00970 #ifdef __UNUSED_FOR_NOW__
00971 static void Q921T201TimerReset(L2TRUNK trunk, L2UCHAR tei)
00972 {
00973         struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
00974 
00975         link->T201 = Q921GetTime() + trunk->T201Timeout;
00976 
00977         Q921Log(trunk, Q921_LOG_DEBUG, "T201 (timeout: %d msecs) restarted for TEI %d\n", trunk->T201Timeout, tei);
00978 }
00979 #endif
00980 
00981 /*
00982  * TM01 handling (Datalink inactivity shutdown timer)
00983  */
00984 static void Q921TM01TimerStart(L2TRUNK trunk, L2UCHAR tei)
00985 {
00986         struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
00987 
00988         if (!link->TM01) {
00989                 link->TM01 = Q921GetTime() + trunk->TM01Timeout;
00990 
00991                 Q921Log(trunk, Q921_LOG_DEBUG, "TM01 (timeout: %d msecs) started for TEI %d\n", trunk->TM01Timeout, tei);
00992         }
00993 }
00994 
00995 #ifdef __UNUSED_FOR_NOW__
00996 static void Q921TM01TimerStop(L2TRUNK trunk, L2UCHAR tei)
00997 {
00998         struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
00999 
01000         link->TM01 = 0;
01001 
01002         Q921Log(trunk, Q921_LOG_DEBUG, "TM01 stopped for TEI %d\n", tei);
01003 }
01004 #endif
01005 
01006 static void Q921TM01TimerReset(L2TRUNK trunk, L2UCHAR tei)
01007 {
01008         struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
01009 
01010         link->TM01 = Q921GetTime() + trunk->TM01Timeout;
01011 
01012         Q921Log(trunk, Q921_LOG_DEBUG, "TM01 (timeout: %d msecs) restarted for TEI %d\n", trunk->TM01Timeout, tei);
01013 }
01014 
01015 /*
01016  * Expiry callbacks
01017  */
01018 static void Q921T200TimerExpire(L2TRUNK trunk, L2UCHAR tei)
01019 {
01020         struct Q921_Link *link   = Q921_LINK_CONTEXT(trunk, tei);
01021         struct Q921_Link *trlink = Q921_TRUNK_CONTEXT(trunk);
01022 
01023         Q921Log(trunk, Q921_LOG_DEBUG, "T200 expired for TEI %d (trunk TEI %d)\n", tei, trlink->tei);
01024 
01025         /* Stop timer first */
01026         Q921T200TimerStop(trunk, tei);
01027 
01028         switch(link->state) {
01029         case Q921_STATE_AWAITING_ESTABLISHMENT:
01030                 if(link->N200 >= trunk->N200Limit) {
01031                         /* Discard I queue */
01032                         MFIFOClear(link->IFrameQueue);
01033 
01034                         /* MDL-Error indication (G) */
01035                         Q921Log(trunk, Q921_LOG_ERROR, "Failed to establish Q.921 link in %d retries\n", link->N200);
01036 
01037                         /* DL-Release indication */
01038                         Q921Tx23Proc(trunk, Q921_DL_RELEASE, tei, NULL, 0);
01039 
01040                         /* change state (no action) */
01041                         Q921ChangeState(trunk, Q921_STATE_TEI_ASSIGNED, tei);
01042 
01043 #ifdef Q921_STATISTICS
01044                         /* update counter */
01045                         Q921StatsIncrementCounter(link, Q921_STATS_N200);
01046 #endif
01047                 } else {
01048                         /* Increment retry counter */
01049                         link->N200++;
01050 
01051                         /* Send SABME */
01052                         Q921SendSABME(trunk,
01053                                         trunk->sapi,
01054                                         Q921_COMMAND(trunk),
01055                                         tei,
01056                                         1);
01057 
01058                         /* Start T200 */
01059                         Q921T200TimerStart(trunk, tei);
01060                 }
01061                 break;
01062 
01063         case Q921_STATE_MULTIPLE_FRAME_ESTABLISHED:
01064                 link->N200 = 0;
01065 
01066                 if(!Q921_CHECK_FLAG(link, Q921_FLAG_PEER_RECV_BUSY)) {
01067                         /* get last transmitted I frame */
01068 
01069                         /* V(S) = V(S) - 1 */
01070                         Q921_DEC_COUNTER(link->vs);
01071 
01072                         /* retransmit I frame */
01073 
01074                         /* V(S) = V(S) + 1 (done by Q921SendI() ) */
01075                         //Q921_INC_COUNTER(link->vs);
01076 
01077                         /* clear acknowledge pending */
01078                         Q921_CLEAR_FLAG(link, Q921_FLAG_ACK_PENDING);
01079 
01080                         /* Start T200 */
01081                         Q921T200TimerStart(trunk, tei);
01082                 } else {
01083                         /* transmit enquiry */
01084                         Q921SendEnquiry(trunk, tei);
01085                 }
01086 
01087                 /* increment counter */
01088                 link->N200++;
01089 
01090                 /* change state (no action) */
01091                 Q921ChangeState(trunk, Q921_STATE_TIMER_RECOVERY, tei);
01092                 break;
01093 
01094         case Q921_STATE_TIMER_RECOVERY:
01095                 if(link->N200 == trunk->N200Limit) {
01096                         /* MDL Error indication (I) */
01097 
01098                         /* Establish data link */
01099                         Q921EstablishDataLink(trunk, tei);
01100 
01101                         /* Clear L3 initiated */
01102                         Q921_CLEAR_FLAG(link, Q921_FLAG_L3_INITIATED);
01103 
01104                         /* change state (no action) */
01105                         Q921ChangeState(trunk, Q921_STATE_AWAITING_ESTABLISHMENT, tei);
01106 
01107 #ifdef Q921_STATISTICS
01108                         /* update counter */
01109                         Q921StatsIncrementCounter(link, Q921_STATS_N200);
01110 #endif
01111                 } else {
01112                         if(link->vs == link->va) {
01113                                 /* transmit enquiry */
01114                                 Q921SendEnquiry(trunk, tei);
01115 
01116                         } else if(!Q921_CHECK_FLAG(link, Q921_FLAG_PEER_RECV_BUSY)) {
01117                                 /* get last transmitted frame */
01118 
01119                                 /* V(S) = V(S) - 1 */
01120                                 Q921_DEC_COUNTER(link->vs);
01121 
01122                                 /* retrans frame */
01123 
01124                                 /* V(S) = V(S) + 1 (done by Q921SendI() ) */
01125                                 //Q921_INC_COUNTER(link->vs);
01126 
01127                                 /* clear acknowledge pending */
01128                                 Q921_CLEAR_FLAG(link, Q921_FLAG_ACK_PENDING);
01129 
01130                                 /* Start T200 */
01131                                 Q921T200TimerStart(trunk, tei);
01132                         }
01133 
01134                         /* increment counter */
01135                         link->N200++;
01136 
01137                         /* no state change */
01138                 }
01139                 break;
01140 
01141         default:
01142                 break;
01143         }
01144 
01145 #ifdef Q921_STATISTICS
01146         /* update counter*/
01147         Q921StatsIncrementCounter(link, Q921_STATS_T200);
01148 #endif
01149 }
01150 
01151 static void Q921T203TimerExpire(L2TRUNK trunk, L2UCHAR tei)
01152 {
01153         struct Q921_Link *link   = Q921_LINK_CONTEXT(trunk, tei);
01154         struct Q921_Link *trlink = Q921_TRUNK_CONTEXT(trunk);
01155 
01156         Q921Log(trunk, Q921_LOG_DEBUG, "T203 expired for TEI %d (trunk TEI %d)\n", tei, trlink->tei);
01157 
01158         /* Stop Timer first */
01159         Q921T203TimerStop(trunk, tei);
01160 
01161         switch(link->state) {
01162         case Q921_STATE_MULTIPLE_FRAME_ESTABLISHED:
01163                 /* Send Enquiry */
01164                 Q921SendEnquiry(trunk, tei);
01165 
01166                 /* RC = 0 */
01167                 link->N200 = 0;
01168 
01169                 /* no state change */
01170                 break;
01171 
01172         default:
01173                 break;
01174         }
01175 
01176 #ifdef Q921_STATISTICS
01177         /* update counter*/
01178         Q921StatsIncrementCounter(link, Q921_STATS_T203);
01179 #endif
01180 }
01181 
01182 static void Q921T202TimerExpire(L2TRUNK trunk)
01183 {
01184         struct Q921_Link *link = Q921_TRUNK_CONTEXT(trunk);
01185 
01186         Q921T202TimerReset(trunk);
01187 
01188         Q921Log(trunk, Q921_LOG_DEBUG, "T202 expired for Q.921 trunk with TEI %d\n", link->tei);
01189 
01190         /* todo: implement resend counter */
01191 
01192         switch(link->state) {
01193         case Q921_STATE_TEI_ASSIGNED:   /* Tei identity verify timeout */
01194                 Q921TeiSendVerifyRequest(trunk);
01195                 break;
01196 
01197         default:                        /* Tei assignment request timeout (TODO: refine) */
01198 
01199                 if(trunk->N202 >= trunk->N202Limit) {
01200                         /* Too many retransmits, reset counter, stop timer and handle case (TODO) */
01201                         trunk->N202 = 0;
01202 
01203                         Q921T202TimerStop(trunk);
01204 
01205 #ifdef Q921_STATISTICS
01206                         /* update counter */
01207                         Q921StatsIncrementCounter(link, Q921_STATS_N202);
01208 #endif
01209                         return;
01210                 }
01211                 Q921TeiSendAssignRequest(trunk);
01212 
01213                 trunk->N202++;
01214         }
01215 
01216 #ifdef Q921_STATISTICS
01217         /* update counter */
01218         Q921StatsIncrementCounter(link, Q921_STATS_T202);
01219 #endif
01220 }
01221 
01222 static void Q921T201TimerExpire(L2TRUNK trunk, L2UCHAR tei)
01223 {
01224         struct Q921_Link *link   = Q921_LINK_CONTEXT(trunk, tei);
01225         struct Q921_Link *trlink = Q921_TRUNK_CONTEXT(trunk);
01226 
01227         Q921Log(trunk, Q921_LOG_DEBUG, "T201 expired for TEI %d (trunk TEI: %d)\n", tei, trlink->tei);
01228 
01229         Q921T201TimerStop(trunk, tei);
01230 
01231         /* NOTE: abusing N202 for this */
01232         if(link->N202 < trunk->N202Limit) {
01233                 /* send check request */
01234                 Q921TeiSendCheckRequest(trunk, tei);
01235 
01236                 /* increment counter */
01237                 link->N202++;
01238         } else {
01239                 /* put context in STOPPED state */
01240                 Q921ChangeState(trunk, Q921_STATE_STOPPED, tei);
01241 
01242                 /* NOTE: should we clear the link too? */
01243                 memset(link, 0, sizeof(struct Q921_Link));
01244 
01245                 /* mark TEI free */
01246                 trunk->tei_map[tei] = 0;
01247 
01248 #ifdef Q921_STATISTICS
01249                 /* update counter */
01250                 Q921StatsIncrementCounter(link, Q921_STATS_N202);
01251 #endif
01252         }
01253 #ifdef Q921_STATISTICS
01254         /* update counter */
01255         Q921StatsIncrementCounter(trlink, Q921_STATS_T201);
01256 #endif
01257 }
01258 
01259 #ifdef __UNUSED_FOR_NOW__
01260 static void Q921TM01TimerExpire(L2TRUNK trunk, L2UCHAR tei)
01261 {
01262         struct Q921_Link *link   = Q921_LINK_CONTEXT(trunk, tei);
01263         struct Q921_Link *trlink = Q921_TRUNK_CONTEXT(trunk);
01264 
01265         Q921Log(trunk, Q921_LOG_DEBUG, "TM01 expired for TEI %d (trunk TEI: %d)\n", tei, trlink->tei);
01266 
01267         /* Restart TM01 */
01268         Q921TM01TimerReset(trunk, tei);
01269 
01270         switch(link->state) {
01271         case Q921_STATE_MULTIPLE_FRAME_ESTABLISHED:
01272         case Q921_STATE_TIMER_RECOVERY:
01273 /*
01274  * NT-only, needs more support from L3
01275  */
01276 #if 0
01277                 /* No activity, shutdown link */
01278                 Q921SendDISC(trunk, trunk->sapi, Q921_COMMAND(trunk), tei, 1);
01279 
01280                 /* clear I queue */
01281                 MFIFOClear(link->IFrameQueue);
01282 
01283                 /* change state */
01284                 Q921ChangeState(trunk, Q921_STATE_AWAITING_RELEASE, tei);
01285 #endif
01286                 break;
01287 
01288         default:
01289                 break;
01290         }
01291 
01292 #ifdef Q921_STATISTICS
01293         /* update counter */
01294         Q921StatsIncrementCounter(link, Q921_STATS_TM01);
01295 #endif
01296 }
01297 #endif
01298 
01299 /*
01300  * Timer Tick function
01301  */
01302 void Q921TimerTick(L2TRUNK trunk)
01303 {
01304         struct Q921_Link *link;
01305         L2ULONG tNow = Q921GetTime();
01306         int numlinks = Q921_IS_PTMP_NT(trunk) ? Q921_TEI_MAX : 1;
01307         int x;
01308 
01309         for(x = 0; x <= numlinks; x++) {
01310                 link = Q921_LINK_CONTEXT(trunk, x);
01311 
01312                 /* TODO: check if TEI is assigned and skip check if not (speedup!) */
01313                 if(link->state == Q921_STATE_STOPPED)
01314                         continue;
01315 
01316                 if (link->T200 && tNow > link->T200) {
01317                         Q921T200TimerExpire(trunk, link->tei);
01318                 }
01319                 if (link->T203 && tNow > link->T203) {
01320                         Q921T203TimerExpire(trunk, link->tei);          
01321                 }
01322 
01323                 if(Q921_IS_PTMP_NT(trunk) && link->tei) {
01324                         if (link->T201 && tNow > link->T201) {
01325                                 Q921T201TimerExpire(trunk, link->tei);
01326                         }
01327                 }
01328 
01329                 if(!Q921_IS_PTMP_NT(trunk)) {
01330                         if (trunk->T202 && tNow > trunk->T202) {
01331                                 Q921T202TimerExpire(trunk);
01332                         }
01333                 }
01334 
01335                 /* Send enqueued I frame, if available */
01336                 Q921SendQueuedIFrame(trunk, link->tei);
01337 
01338                 /* Send ack if pending */
01339                 Q921AcknowledgePending(trunk, link->tei);
01340         }
01341 
01342 }
01343 
01344 void Q921SetGetTimeCB(L2ULONG (*callback)(void))
01345 {
01346     Q921GetTimeProc = callback;
01347 }
01348 
01349 /*****************************************************************************
01350 
01351   Function:     Q921QueueHDLCFrame
01352 
01353   Description:  Called to receive and queue an incoming HDLC frame. Will
01354                 queue this in Q921HDLCInQueue. The called must either call
01355                 Q921Rx12 directly afterwards or signal Q921Rx12 to be called
01356                 later. Q921Rx12 will read from the same queue and process
01357                 the frame.
01358 
01359                 This function assumes that the message contains header 
01360                 space. This is removed for internal Q921 processing, but 
01361                 must be keept for I frames.
01362 
01363   Parameters:   trunk   trunk #
01364                 b       ptr to frame;
01365                 size    size of frame in bytes
01366 
01367 *****************************************************************************/
01368 int Q921QueueHDLCFrame(L2TRUNK trunk, L2UCHAR *b, L2INT size)
01369 {
01370     return MFIFOWriteMes(trunk->HDLCInQueue, b, size);
01371 }
01372 
01378 static int Q921EnqueueI(L2TRUNK trunk, L2UCHAR Sapi, char cr, L2UCHAR Tei, char pf, L2UCHAR *mes, L2INT size)
01379 {
01380         struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, Tei);
01381 
01382         /* I frame header */
01383         mes[trunk->Q921HeaderSpace+0] = ((Sapi << 2) & 0xfc) | ((cr << 1) & 0x02);
01384         mes[trunk->Q921HeaderSpace+1] = (Tei << 1) | 0x01;
01385         mes[trunk->Q921HeaderSpace+2] = 0x00;
01386         mes[trunk->Q921HeaderSpace+3] = (pf & 0x01);
01387 
01388         Q921Log(trunk, Q921_LOG_DEBUG, "Enqueueing I frame for TEI %d [%d]\n", link->tei, Tei);
01389 
01390         /* transmit queue, (TODO: check for full condition!) */
01391         MFIFOWriteMes(link->IFrameQueue, mes, size);
01392 
01393         /* try to send queued frame */
01394         Q921SendQueuedIFrame(trunk, link->tei);
01395 
01396         return 1;
01397 }
01398 
01403 static int Q921SendQueuedIFrame(L2TRUNK trunk, L2UCHAR tei)
01404 {
01405         struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
01406 
01407         L2INT size = 0;
01408         L2UCHAR *mes;
01409 
01410         if(MFIFOGetMesCount(link->IFrameQueue) == 0) {
01411                 return 0;
01412         }
01413 
01414         /* Link ready? */
01415         if(link->state != Q921_STATE_MULTIPLE_FRAME_ESTABLISHED) {
01416                 return 0;
01417         }
01418 
01419         /* peer receiver busy? */
01420         if(Q921_CHECK_FLAG(link, Q921_FLAG_PEER_RECV_BUSY)) {
01421                 return 0;
01422         }
01423 
01424         /* V(S) = V(A) + k? */
01425         if(link->vs == ((link->va + trunk->k) % 128)) {
01426                 Q921Log(trunk, Q921_LOG_WARNING, "Maximum number (%d) of outstanding I frames reached for TEI %d\n", trunk->k, tei);
01427                 return 0;
01428         }
01429 
01430         mes = MFIFOGetMesPtr(link->IFrameQueue, &size);
01431         if(mes) {
01432                 /* Fill in + update counter values */
01433                 mes[trunk->Q921HeaderSpace+2]  = link->vs << 1;
01434                 mes[trunk->Q921HeaderSpace+3] |= link->vr << 1;
01435 
01436                 if(MFIFOGetMesCount(link->IFrameQueue) == 0) {
01437                         /* clear I frame queued */
01438                 }
01439 
01440 #ifdef Q921_STATISTICS_VERBOSE
01441                 Q921StatsIncrementCounter(link, Q921_STATS_SEND_I);
01442 #endif
01443                 /* Send I frame */
01444                 Q921Tx21Proc(trunk, mes, size);
01445 
01446                 /* V(S) = V(S) + 1 */
01447                 Q921_INC_COUNTER(link->vs);
01448 
01449                 /* clear acknowledge pending */
01450                 Q921_CLEAR_FLAG(link, Q921_FLAG_ACK_PENDING);
01451 
01452                 /* T200 running? */
01453                 if(!link->T200) {
01454                         /* Stop T203, Start T200 */
01455                         Q921T200TimerStart(trunk, tei);
01456                         Q921T203TimerStop(trunk, tei);
01457                 }
01458 
01459                 /* put frame into resend queue */
01460                 MFIFOWriteMesOverwrite(link->IFrameResendQueue, mes, size);
01461 
01462                 /* dequeue frame */
01463                 MFIFOKillNext(link->IFrameQueue);
01464 
01465                 /* Restart TM01 */
01466                 if(Q921_IS_NT(trunk)) {
01467                         Q921TM01TimerReset(trunk, tei);
01468                 }
01469 
01470                 /* no state change */
01471                 return 1;
01472         }
01473 
01474         return 0;
01475 }
01476 
01481 static int Q921SendS(L2TRUNK trunk, L2UCHAR Sapi, char cr, L2UCHAR Tei, char pf, L2UCHAR sv, L2UCHAR *mes, L2INT size)
01482 {
01483         struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, Tei);
01484 
01485         if(!Q921_IS_READY(link)) {
01486                 /* don't even bother trying */
01487                 Q921Log(trunk, Q921_LOG_DEBUG, "Link not ready, discarding S frame for TEI %d\n", Tei);
01488                 return 0;
01489         }
01490 
01491         /* S frame header */
01492         mes[trunk->Q921HeaderSpace+0] = ((Sapi << 2) & 0xfc) | ((cr << 1) & 0x02);
01493         mes[trunk->Q921HeaderSpace+1] = (Tei << 1) | 0x01;
01494         mes[trunk->Q921HeaderSpace+2] = ((sv << 2) & 0x0c) | 0x01;
01495         mes[trunk->Q921HeaderSpace+3] = (link->vr << 1) | (pf & 0x01);
01496 
01497 #ifdef Q921_STATISTICS_VERBOSE
01498         Q921StatsIncrementCounter(link, Q921_STATS_SEND_S);
01499 #endif
01500         return Q921Tx21Proc(trunk, mes, size);
01501 }
01502 
01503 
01508 static int Q921SendU(L2TRUNK trunk, L2UCHAR Sapi, char cr, L2UCHAR Tei, char pf, L2UCHAR m, L2UCHAR *mes, L2INT size)
01509 {
01510         struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, Tei);
01511 
01512         /* U frame header */
01513         mes[trunk->Q921HeaderSpace+0] = ((Sapi << 2) & 0xfc) | ((cr << 1) & 0x02);
01514         mes[trunk->Q921HeaderSpace+1] = (Tei << 1) | 0x01;
01515         mes[trunk->Q921HeaderSpace+2] = ((m << 3) & 0xe0) | ((pf << 4) & 0x10) | ((m << 2) & 0x0c) | 0x03;
01516 
01517         /* link not ready? enqueue non-TEI-mgmt UI (DL-UNIT DATA) frames */
01518         if(m == 0x00 && Sapi != Q921_SAPI_TEI && link->state < Q921_STATE_TEI_ASSIGNED) {
01519 
01520                 /* write frame to queue */
01521                 MFIFOWriteMes(link->UIFrameQueue, mes, size);
01522 
01523                 Q921Log(trunk, Q921_LOG_DEBUG, "Link not ready, UI Frame of size %d bytes queued for TEI %d\n", size, Tei);
01524                 return 1;
01525         }
01526 
01527 #ifdef Q921_STATISTICS_VERBOSE
01528         Q921StatsIncrementCounter(link, Q921_STATS_SEND_U);
01529 #endif
01530         return Q921Tx21Proc(trunk, mes, size);
01531 }
01532 
01536 int Q921Rx32(L2TRUNK trunk, Q921DLMsg_t ind, L2UCHAR tei, L2UCHAR * Mes, L2INT Size)
01537 {
01538         struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei); /* TODO: need real link tei for NT mode */
01539         L2INT res = 0;
01540 
01541         Q921Log(trunk, Q921_LOG_DEBUG, "Got frame from Q.931, type: %d, tei: %d, size: %d\n", ind, tei, Size);
01542 
01543         switch(ind) {
01544         case Q921_DL_ESTABLISH:
01545                 /*
01546                  * Hmm...
01547                  */
01548                 switch(link->state) {
01549                 case Q921_STATE_TEI_ASSIGNED:
01550                         if(!Q921_IS_NT(trunk)) {
01551                                 /* establish data link */
01552                                 Q921EstablishDataLink(trunk, link->tei);
01553 
01554                                 /* Set layer 3 initiated */
01555                                 Q921_SET_FLAG(link, Q921_FLAG_L3_INITIATED);
01556 
01557                                 /* change state (no action) */
01558                                 Q921ChangeState(trunk, Q921_STATE_AWAITING_ESTABLISHMENT, link->tei);
01559                         }
01560                         break;
01561 
01562                 case Q921_STATE_AWAITING_ESTABLISHMENT:
01563                         if(!Q921_IS_NT(trunk)) {
01564                                 /* Discard I queue */
01565                                 MFIFOClear(link->IFrameQueue);
01566 
01567                                 /* Set layer 3 initiated */
01568                                 Q921_SET_FLAG(link, Q921_FLAG_L3_INITIATED);
01569                         }
01570                         break;
01571 
01572                 case Q921_STATE_MULTIPLE_FRAME_ESTABLISHED:
01573                 case Q921_STATE_TIMER_RECOVERY:
01574                         if(!Q921_IS_NT(trunk)) {
01575                                 /* Discard I queue */
01576                                 MFIFOClear(link->IFrameQueue);
01577 
01578                                 /* establish data link */
01579                                 Q921EstablishDataLink(trunk, link->tei);
01580 
01581                                 /* Set layer 3 initiated */
01582                                 Q921_SET_FLAG(link, Q921_FLAG_L3_INITIATED);
01583 
01584                                 /* change state (no action) */
01585                                 Q921ChangeState(trunk, Q921_STATE_AWAITING_ESTABLISHMENT, link->tei);
01586                         }
01587                         break;
01588 
01589                 default:
01590                         break;
01591                 }
01592                 break;
01593 
01594         case Q921_DL_RELEASE:
01595                 switch(link->state) {
01596                 case Q921_STATE_TEI_ASSIGNED:
01597                         /* send DL-RELEASE confirm */
01598                         Q921Tx23Proc(trunk, Q921_DL_RELEASE, tei, NULL, 0);
01599                         break;
01600 
01601                 case Q921_STATE_MULTIPLE_FRAME_ESTABLISHED:
01602                 case Q921_STATE_TIMER_RECOVERY:
01603                         if(!Q921_IS_NT(trunk)) {
01604                                 /* Discard I queue */
01605                                 MFIFOClear(link->IFrameQueue);
01606 
01607                                 /* RC = 0 */
01608                                 link->N200 = 0;
01609 
01610                                 /* send DISC command */
01611                                 Q921SendDISC(trunk, trunk->sapi, Q921_COMMAND(trunk), link->tei, 1);
01612 
01613                                 /* Stop T203, restart T200 */
01614                                 if(link->state == Q921_STATE_MULTIPLE_FRAME_ESTABLISHED) {
01615                                         Q921T203TimerStop(trunk, link->tei);
01616                                 }
01617                                 Q921T200TimerReset(trunk, link->tei);
01618 
01619                                 /* change state */
01620                                 Q921ChangeState(trunk, Q921_STATE_AWAITING_RELEASE, link->tei);
01621                         }
01622                         break;
01623 
01624                 default:
01625                         break;
01626                 }
01627                 break;
01628 
01629         case Q921_DL_DATA:      /* DL-DATA request */
01630                 res = Q921EnqueueI(trunk, 
01631                                 trunk->sapi, 
01632                                 Q921_COMMAND(trunk),
01633                                 link->tei,
01634                                 0, 
01635                                 Mes, 
01636                                 Size);
01637 
01638                 if(link->state < Q921_STATE_MULTIPLE_FRAME_ESTABLISHED) {
01639                         /* Treat as implicit DL-ESTABLISH request */
01640 
01641                         /* establish data link */
01642                         Q921EstablishDataLink(trunk, link->tei);
01643 
01644                         /* Set layer 3 initiated */
01645                         Q921_SET_FLAG(link, Q921_FLAG_L3_INITIATED);
01646 
01647                         /* change state (no action) */
01648                         Q921ChangeState(trunk, Q921_STATE_AWAITING_ESTABLISHMENT, link->tei);
01649                 }
01650                 break;
01651 
01652         case Q921_DL_UNIT_DATA:         /* DL-UNIT DATA request */
01653                 res = Q921SendUN(trunk,
01654                                 trunk->sapi,
01655                                 Q921_COMMAND(trunk),
01656                                 Q921_TEI_BCAST,
01657                                 0,
01658                                 Mes,
01659                                 Size);
01660                 /* NOTE: Let the other side initiate link establishment */
01661                 break;
01662 
01663         default:
01664                 break;
01665         }
01666 
01667         return res;
01668 }
01669 /*****************************************************************************
01670 
01671   Function:     Q921SendRR
01672 
01673   Description:  Compose and send Receive Ready.
01674 
01675   Parameters:   trunk       trunk #
01676                 Sapi        Sapi
01677                 cr          C/R field.
01678                 Tei         Tei.
01679                 pf          P/F fiels octet 5
01680 
01681   Return Value: 0 if failed, 1 if Send.
01682 
01683 *****************************************************************************/
01684 
01685 static int Q921SendRR(L2TRUNK trunk, int Sapi, int cr, int Tei, int pf)
01686 {
01687         L2UCHAR mes[25];
01688 
01689 #ifdef Q921_STATISTICS_VERBOSE
01690         Q921StatsIncrementCounter(Q921_LINK_CONTEXT(trunk, Tei), Q921_STATS_SEND_RR);
01691 #endif
01692         return Q921SendS(trunk, Sapi, cr, Tei, pf, 0x00, mes, trunk->Q921HeaderSpace+4);
01693 }
01694 
01695 /*****************************************************************************
01696 
01697   Function:     Q921SendRNR
01698 
01699   Description:  Compose and send Receive Nor Ready
01700 
01701   Parameters:   trunk       trunk #
01702                 Sapi        Sapi
01703                 cr          C/R field.
01704                 Tei         Tei.
01705                 pf          P/F fiels octet 5
01706 
01707   Return Value: 0 if failed, 1 if Send.
01708 
01709 *****************************************************************************/
01710 static int Q921SendRNR(L2TRUNK trunk, int Sapi, int cr, int Tei, int pf)
01711 {
01712         L2UCHAR mes[25];
01713 
01714 #ifdef Q921_STATISTICS_VERBOSE
01715         Q921StatsIncrementCounter(Q921_LINK_CONTEXT(trunk, Tei), Q921_STATS_SEND_RNR);
01716 #endif
01717         return Q921SendS(trunk, Sapi, cr, Tei, pf, 0x01, mes, trunk->Q921HeaderSpace+4);
01718 }
01719 
01720 /*****************************************************************************
01721 
01722   Function:     Q921SendREJ
01723 
01724   Description:  Compose and Send Reject.
01725 
01726   Parameters:   trunk       trunk #
01727                 Sapi        Sapi
01728                 cr          C/R field.
01729                 Tei         Tei.
01730                 pf          P/F fiels octet 5
01731 
01732   Return Value: 0 if failed, 1 if Send.
01733 
01734 *****************************************************************************/
01735 static int Q921SendREJ(L2TRUNK trunk, int Sapi, int cr, int Tei, int pf)
01736 {
01737         L2UCHAR mes[25];
01738 
01739 #ifdef Q921_STATISTICS_VERBOSE
01740         Q921StatsIncrementCounter(Q921_LINK_CONTEXT(trunk, Tei), Q921_STATS_SEND_REJ);
01741 #endif
01742         return Q921SendS(trunk, Sapi, cr, Tei, pf, 0x03, mes, trunk->Q921HeaderSpace+4);
01743 }
01744 
01745 /*****************************************************************************
01746 
01747   Function:     Q921SendSABME
01748 
01749   Description:  Compose and send SABME
01750 
01751   Parameters:   trunk       trunk #
01752                 Sapi        Sapi
01753                 cr          C/R field.
01754                 Tei         Tei.
01755                 pf          P fiels octet 4
01756 
01757   Return Value: 0 if failed, 1 if Send.
01758 
01759 *****************************************************************************/
01760 static int Q921SendSABME(L2TRUNK trunk, int Sapi, int cr, int Tei, int pf)
01761 {
01762         L2UCHAR mes[25];
01763 
01764 #ifdef Q921_STATISTICS_VERBOSE
01765         Q921StatsIncrementCounter(Q921_LINK_CONTEXT(trunk, Tei), Q921_STATS_SEND_SABME);
01766 #endif
01767         return Q921SendU(trunk, Sapi, cr, Tei, pf, 0x0f, mes, trunk->Q921HeaderSpace+3);
01768 }
01769 
01770 
01777 int Q921Start(L2TRUNK trunk)
01778 {
01779         int x, numlinks = Q921_IS_PTMP_NT(trunk) ? Q921_TEI_MAX : 1;
01780         struct Q921_Link *link = Q921_TRUNK_CONTEXT(trunk);
01781 
01782         if(trunk->initialized != INITIALIZED_MAGIC)
01783                 return 0;
01784 
01785         memset(trunk->context, 0, numlinks * sizeof(struct Q921_Link));
01786 
01787         /* Common init part */
01788         for(x = 0; x <= numlinks; x++) {
01789                 link = Q921_LINK_CONTEXT(trunk, x);
01790 
01791                 link->state = Q921_STATE_TEI_UNASSIGNED;
01792                 link->tei   = 0;
01793 
01794                 /* Initialize per-TEI I + UI queues */
01795                 MFIFOCreate(link->UIFrameQueue, Q921MAXHDLCSPACE, 10);
01796                 MFIFOCreate(link->IFrameQueue,  Q921MAXHDLCSPACE, 10);
01797                 MFIFOCreate(link->IFrameResendQueue, Q921MAXHDLCSPACE, 10);
01798         }
01799 
01800         if(Q921_IS_PTMP_TE(trunk)) {
01801                 link->state = Q921_STATE_TEI_UNASSIGNED;
01802                 link->tei   = 0;
01803         }
01804         else if(Q921_IS_PTMP_NT(trunk)) {
01805                 link = Q921_TRUNK_CONTEXT(trunk);
01806 
01807                 link->state = Q921_STATE_TEI_ASSIGNED;
01808                 link->tei   = trunk->tei;
01809 
01810                 /* clear tei map */
01811                 memset(trunk->tei_map, 0, Q921_TEI_MAX + 1);
01812         }
01813         else {
01814                 link->state = Q921_STATE_TEI_ASSIGNED;
01815                 link->tei   = trunk->tei;
01816         }
01817 
01818         Q921Log(trunk, Q921_LOG_DEBUG, "Starting trunk %p (sapi: %d, tei: %d, mode: %s %s)\n",
01819                                  trunk,
01820                                  trunk->sapi,
01821                                  link->tei,
01822                                  Q921_IS_PTMP(trunk) ? "PTMP" : "PTP",
01823                                  Q921_IS_TE(trunk) ? "TE" : "NT");
01824 
01825         if(Q921_IS_PTP(trunk)) {
01826                 Q921Log(trunk, Q921_LOG_DEBUG, "Sending SABME\n");
01827 
01828                 return Q921SendSABME(trunk, 
01829                                         trunk->sapi, 
01830                                         Q921_COMMAND(trunk),
01831                                         link->tei, 
01832                                         1);
01833 
01834         } else if(Q921_IS_PTMP_NT(trunk)) {
01835 
01836                 Q921Log(trunk, Q921_LOG_DEBUG, "Revoking all TEIs\n");
01837 
01838                 return Q921TeiSendRemoveRequest(trunk, Q921_TEI_BCAST); /* Revoke all TEIs in use */
01839         } else {
01840 
01841                 Q921Log(trunk, Q921_LOG_DEBUG, "Requesting TEI\n");
01842 
01843                 return Q921TeiSendAssignRequest(trunk);
01844         }
01845 }
01846 
01847 
01856 int Q921Stop(L2TRUNK trunk)
01857 {
01858         struct Q921_Link *link;
01859         int x, numlinks;
01860 
01861         if(!trunk)
01862                 return -1;
01863 
01864         link = Q921_TRUNK_CONTEXT(trunk);
01865         numlinks = Q921_IS_PTMP_NT(trunk) ? Q921_TEI_MAX : 1;
01866 
01867         if(Q921_IS_STOPPED(link))
01868                 return 0;
01869 
01870         /* Release TEI */
01871         if(Q921_IS_PTMP_TE(trunk)) {
01872                 /* send verify request */
01873                 Q921TeiSendVerifyRequest(trunk);
01874 
01875                 /* drop TEI */
01876                 link->tei  = 0;
01877         }
01878 
01879         /* Stop timers, stop link, flush queues */
01880         for(x = 0; x <= numlinks; x++) {
01881                 Q921T200TimerStop(trunk, x);
01882                 Q921T203TimerStop(trunk, x);
01883                 Q921T201TimerStop(trunk, x);
01884 
01885                 /* Change state (no action) */
01886                 Q921ChangeState(trunk, Q921_STATE_STOPPED, x);
01887 
01888                 /* Flush per-tei I/UI queues */
01889                 MFIFOClear(link->UIFrameQueue);
01890                 MFIFOClear(link->IFrameQueue);
01891                 MFIFOClear(link->IFrameResendQueue);
01892         }
01893         Q921T202TimerStop(trunk);
01894 
01895         /* Flush HDLC queue */
01896         MFIFOClear(trunk->HDLCInQueue);
01897 
01898         return 0;
01899 }
01900 
01901 
01902 /*****************************************************************************
01903 
01904   Function:     Q921SendDM
01905 
01906   Description:  Compose and Send DM (Disconnected Mode)
01907 
01908   Parameters:   trunk       trunk #
01909                 Sapi        Sapi
01910                 cr          C/R field.
01911                 Tei         Tei.
01912                 pf          F fiels octet 4
01913 
01914   Return Value: 0 if failed, 1 if Send.
01915 
01916 *****************************************************************************/
01917 static int Q921SendDM(L2TRUNK trunk, int Sapi, int cr, int Tei, int pf)
01918 {
01919         L2UCHAR mes[25];
01920 
01921 #ifdef Q921_STATISTICS_VERBOSE
01922         Q921StatsIncrementCounter(Q921_LINK_CONTEXT(trunk, Tei), Q921_STATS_SEND_DM);
01923 #endif
01924         return Q921SendU(trunk, Sapi, cr, Tei, pf, 0x03, mes, trunk->Q921HeaderSpace+3);
01925 }
01926 
01927 /*****************************************************************************
01928 
01929   Function:     Q921SendDISC
01930 
01931   Description:  Compose and Send Disconnect
01932 
01933   Parameters:   trunk       trunk #
01934                 Sapi        Sapi
01935                 cr          C/R field.
01936                 Tei         Tei.
01937                 pf          P fiels octet 4
01938 
01939   Return Value: 0 if failed, 1 if Send.
01940 
01941 *****************************************************************************/
01942 static int Q921SendDISC(L2TRUNK trunk, int Sapi, int cr, int Tei, int pf)
01943 {
01944         L2UCHAR mes[25];
01945 
01946 #ifdef Q921_STATISTICS_VERBOSE
01947         Q921StatsIncrementCounter(Q921_LINK_CONTEXT(trunk, Tei), Q921_STATS_SEND_DISC);
01948 #endif
01949         return Q921SendU(trunk, Sapi, cr, Tei, pf, 0x08, mes, trunk->Q921HeaderSpace+3);
01950 }
01951 
01952 /*****************************************************************************
01953 
01954   Function:     Q921SendUA
01955 
01956   Description:  Compose and Send UA
01957 
01958   Parameters:   trunk       trunk #
01959                 Sapi        Sapi
01960                 cr          C/R field.
01961                 Tei         Tei.
01962                 pf          F fiels octet 4
01963 
01964   Return Value: 0 if failed, 1 if Send.
01965 
01966 *****************************************************************************/
01967 static int Q921SendUA(L2TRUNK trunk, int Sapi, int cr, int Tei, int pf)
01968 {
01969         L2UCHAR mes[25];
01970 
01971 #ifdef Q921_STATISTICS_VERBOSE
01972         Q921StatsIncrementCounter(Q921_LINK_CONTEXT(trunk, Tei), Q921_STATS_SEND_UA);
01973 #endif
01974         return Q921SendU(trunk, Sapi, cr, Tei, pf, 0x0c, mes, trunk->Q921HeaderSpace+3);
01975 }
01976 
01977 static int Q921SendUN(L2TRUNK trunk, int Sapi, int cr, int Tei, int pf, L2UCHAR *mes, L2INT size)
01978 {
01979 #ifdef Q921_STATISTICS_VERBOSE
01980         Q921StatsIncrementCounter(Q921_LINK_CONTEXT(trunk, Tei), Q921_STATS_SEND_UN);
01981 #endif
01982         return Q921SendU(trunk, Sapi, cr, Tei, pf, 0x00, mes, size+trunk->Q921HeaderSpace+3);
01983 }
01984 
01985 
01994 static int Q921ProcSABME(L2TRUNK trunk, L2UCHAR *mes, L2INT size)
01995 {
01996         L2UCHAR pf = (mes[2] & 0x10) >> 4;                              /* poll / final flag */
01997         L2UCHAR tei = (mes[1] & 0xfe) >> 1;
01998         struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
01999 
02000         switch(link->state) {
02001         case Q921_STATE_TEI_ASSIGNED:
02002                 /* send UA */
02003                 Q921SendUA(trunk,
02004                                 trunk->sapi,
02005                                 Q921_RESPONSE(trunk),   /* or command? */
02006                                 tei, pf);
02007 
02008                 /* clear counters */
02009                 link->vr=0;
02010                 link->vs=0;
02011                 link->va=0;
02012 
02013                 /* TODO: send DL-Establish indication to Q.931 */
02014                 Q921Tx23Proc(trunk, Q921_DL_ESTABLISH, tei, NULL, 0);
02015 
02016                 /* start T203 */
02017                 Q921T203TimerStart(trunk, tei);
02018 
02019                 /* change state (no action) */
02020                 Q921ChangeState(trunk, Q921_STATE_MULTIPLE_FRAME_ESTABLISHED, tei);
02021                 break;
02022 
02023         case Q921_STATE_AWAITING_ESTABLISHMENT:
02024                 /* send UA */
02025                 Q921SendUA(trunk,
02026                                 trunk->sapi,
02027                                 Q921_RESPONSE(trunk),
02028                                 tei, pf);
02029 
02030                 /* no state change */
02031                 break;
02032 
02033         case Q921_STATE_AWAITING_RELEASE:
02034                 /* send DM */
02035                 Q921SendDM(trunk,
02036                                 trunk->sapi,
02037                                 Q921_RESPONSE(trunk),
02038                                 tei, pf);
02039 
02040                 /* no state change */
02041                 break;
02042 
02043         case Q921_STATE_MULTIPLE_FRAME_ESTABLISHED:
02044         case Q921_STATE_TIMER_RECOVERY:
02045                 /* send UA */
02046                 Q921SendUA(trunk,
02047                                 trunk->sapi,
02048                                 Q921_RESPONSE(trunk),
02049                                 tei, pf);
02050 
02051                 /* clear exception conditions */
02052                 Q921ResetExceptionConditions(trunk, tei);
02053 
02054                 /* send MDL-Error indication */
02055 
02056                 /* V(S) == V(A) ? */
02057                 if(link->vs != link->va) {
02058                         /* clear I queue */
02059                         MFIFOClear(link->IFrameQueue);
02060 
02061                         /* DL-Establish indication */
02062                         Q921Tx23Proc(trunk, Q921_DL_ESTABLISH, tei, NULL, 0);
02063                 }
02064 
02065                 /* clear counters */
02066                 link->vr=0;
02067                 link->vs=0;
02068                 link->va=0;
02069 
02070                 /* Stop T200, start T203 */
02071                 Q921T200TimerStop(trunk, tei);
02072                 Q921T203TimerStart(trunk, tei);
02073 
02074                 /* state change only if in TIMER_RECOVERY state */
02075                 if(link->state == Q921_STATE_TIMER_RECOVERY)
02076                         Q921ChangeState(trunk, Q921_STATE_MULTIPLE_FRAME_ESTABLISHED, tei);
02077                 break;
02078 
02079         default:
02080                 break;
02081         }
02082 
02083         return 1;
02084 }
02085 
02086 
02095 static int Q921ProcDM(L2TRUNK trunk, L2UCHAR *mes, L2INT size)
02096 {
02097         L2UCHAR pf = (mes[2] & 0x10) >> 4;                              /* poll / final flag */
02098         L2UCHAR tei = (mes[1] & 0xfe) >> 1;
02099         struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
02100 
02101         switch(link->state) {
02102         case Q921_STATE_TEI_ASSIGNED:
02103                 if(!pf) {
02104                         /* to next state (no action) */
02105                         Q921ChangeState(trunk, Q921_STATE_AWAITING_ESTABLISHMENT, tei);
02106                 }
02107                 break;
02108 
02109         case Q921_STATE_AWAITING_ESTABLISHMENT:
02110         case Q921_STATE_AWAITING_RELEASE:
02111                 if(pf) {
02112                         if(link->state == Q921_STATE_AWAITING_ESTABLISHMENT) {
02113                                 /* Discard I queue */
02114                                 MFIFOClear(link->IFrameQueue);
02115                         }
02116 
02117                         /* Send DL-Release indication to Q.931 */
02118                         Q921Tx23Proc(trunk, Q921_DL_RELEASE, tei, NULL, 0);
02119 
02120                         /* Stop T200 */
02121                         Q921T200TimerStop(trunk, tei);
02122 
02123                         /* Change state (no action) */
02124                         Q921ChangeState(trunk, Q921_STATE_TEI_ASSIGNED, tei);
02125                 }
02126                 break;
02127 
02128         case Q921_STATE_MULTIPLE_FRAME_ESTABLISHED:
02129                 if(pf) {
02130                         /* MDL-Error indication (B) */
02131 
02132                         /* no state change */
02133                 } else {
02134                         /* MDL-Error indication (E) */
02135 
02136                         /* establish data link */
02137                         Q921EstablishDataLink(trunk, tei);
02138 
02139                         /* clear L3 initiated */
02140                         Q921_CLEAR_FLAG(link, Q921_FLAG_L3_INITIATED);
02141 
02142                         /* change state (no action?) */
02143                         Q921ChangeState(trunk, Q921_STATE_AWAITING_ESTABLISHMENT, tei);
02144                 }
02145                 break;
02146 
02147         case Q921_STATE_TIMER_RECOVERY:
02148                 if(pf) {
02149                         /* MDL Error indication (B) */
02150                 } else {
02151                         /* MDL Error indication (E) */
02152                 }
02153 
02154                 /* establish data link */
02155                 Q921EstablishDataLink(trunk, tei);
02156 
02157                 /* clear layer 3 initiated */
02158                 Q921_CLEAR_FLAG(link, Q921_FLAG_L3_INITIATED);
02159 
02160                 /* change state */
02161                 Q921ChangeState(trunk, Q921_STATE_AWAITING_ESTABLISHMENT, tei);
02162                 break;
02163 
02164         default:
02165                 break;
02166         }
02167 
02168         return 1;
02169 }
02170 
02179 static int Q921ProcUA(L2TRUNK trunk, L2UCHAR *mes, L2INT size)
02180 {
02181         L2UCHAR pf = (mes[2] & 0x10) >> 4;                              /* poll / final flag */
02182         L2UCHAR tei = (mes[1] & 0xfe) >> 1;
02183         struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
02184 
02185         switch(link->state) {
02186         case Q921_STATE_TEI_ASSIGNED:
02187         case Q921_STATE_TIMER_RECOVERY:
02188                 /* MDL Error indication (C, D) */
02189                 Q921Log(trunk, Q921_LOG_ERROR, "Received UA frame in invalid state\n");
02190                 break;
02191 
02192         case Q921_STATE_AWAITING_ESTABLISHMENT:
02193                 if(pf) {
02194                         /* TODO: other fancy stuff (see docs) */
02195                         if(Q921_CHECK_FLAG(link, Q921_FLAG_L3_INITIATED)) {     /* layer3 initiated */
02196                                 link->vr = 0;
02197 
02198                                 /* DL-Establish confirm */
02199                                 Q921Tx23Proc(trunk, Q921_DL_ESTABLISH_CONFIRM, tei, NULL, 0);
02200 
02201                         } else if(link->vs != link->va) {
02202 
02203                                 /* discard I queue */
02204                                 MFIFOClear(link->IFrameQueue);
02205 
02206                                 /* DL-Establish indication */
02207                                 Q921Tx23Proc(trunk, Q921_DL_ESTABLISH, tei, NULL, 0);
02208                         }
02209 
02210                         /* Stop T200, start T203 */
02211                         Q921T200TimerStop(trunk, tei);
02212                         Q921T203TimerStart(trunk, tei);
02213 
02214                         link->vs = 0;
02215                         link->va = 0;
02216 
02217                         /* change state (no action) */
02218                         Q921ChangeState(trunk, Q921_STATE_MULTIPLE_FRAME_ESTABLISHED, tei);
02219                 } else {
02220                         /* MDL Error indication (C, D) */
02221                         Q921Log(trunk, Q921_LOG_ERROR, "Received UA frame is not a response to a request\n");
02222 
02223                         /* no state change */
02224                 }
02225                 break;
02226 
02227         case Q921_STATE_AWAITING_RELEASE:
02228                 if(pf) {
02229                         /* DL Release confirm */
02230                         Q921Tx23Proc(trunk, Q921_DL_RELEASE_CONFIRM, tei, NULL, 0);
02231 
02232                         /* Stop T200 */
02233                         Q921T200TimerStop(trunk, tei);
02234 
02235                         /* change state (no action) */
02236                         Q921ChangeState(trunk, Q921_STATE_TEI_ASSIGNED, tei);
02237                 } else {
02238                         /* MDL Error indication (D) */
02239                         Q921Log(trunk, Q921_LOG_ERROR, "Received UA frame is not a response to a request\n");
02240 
02241                         /* no state change */
02242                 }
02243                 break;
02244 
02245         case Q921_STATE_MULTIPLE_FRAME_ESTABLISHED:
02246                 /* MDL Error indication (C, D) */
02247                 Q921Log(trunk, Q921_LOG_ERROR, "Received UA frame in invalid state\n");
02248 
02249                 /* no state change */
02250                 break;
02251 
02252         default:
02253                 break;
02254         }
02255 
02256         return 1;
02257 }
02258 
02259 
02268 static int Q921ProcDISC(L2TRUNK trunk, L2UCHAR *mes, L2INT size)
02269 {
02270         L2UCHAR pf  = (mes[2] & 0x10) >> 4;                             /* poll / final flag */
02271         L2UCHAR tei = (mes[1] & 0xfe) >> 1;
02272         struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
02273 
02274         switch(link->state) {
02275         case Q921_STATE_TEI_ASSIGNED:
02276         case Q921_STATE_AWAITING_ESTABLISHMENT:
02277                 /* Send DM */
02278                 Q921SendDM(trunk,
02279                                 trunk->sapi,
02280                                 Q921_RESPONSE(trunk),
02281                                 tei, pf);
02282 
02283                 /* no state change */
02284                 break;
02285 
02286         case Q921_STATE_AWAITING_RELEASE:
02287                 Q921SendUA(trunk,
02288                                 trunk->sapi,
02289                                 Q921_RESPONSE(trunk),
02290                                 tei, pf);
02291 
02292                 /* no state change */
02293                 break;
02294 
02295         case Q921_STATE_MULTIPLE_FRAME_ESTABLISHED:
02296         case Q921_STATE_TIMER_RECOVERY:
02297                 /* Discard I queue */
02298                 MFIFOClear(link->IFrameQueue);
02299 
02300                 /* send UA */
02301                 Q921SendUA(trunk,
02302                                 trunk->sapi,
02303                                 Q921_RESPONSE(trunk),
02304                                 tei, pf);
02305                 
02306                 /* DL Release indication */
02307                 Q921Tx23Proc(trunk, Q921_DL_RELEASE, tei, NULL, 0);
02308 
02309                 /* Stop T200 */
02310                 Q921T200TimerStop(trunk, tei);
02311 
02312                 if(link->state == Q921_STATE_MULTIPLE_FRAME_ESTABLISHED) {
02313                         /* Stop T203 */
02314                         Q921T203TimerStop(trunk, tei);
02315                 }
02316 
02317                 /* change state (no action) */
02318                 Q921ChangeState(trunk, Q921_STATE_TEI_ASSIGNED, tei);
02319                 break;
02320 
02321         default:
02322                 Q921Log(trunk, Q921_LOG_ERROR, "Invalid DISC received in state \"%s\" (%d)", Q921State2Name(link->state), link->state);
02323                 break;
02324         }
02325 
02326         return 1;
02327 }
02328 
02329 
02338 static int Q921ProcRR(L2TRUNK trunk, L2UCHAR *mes, L2INT size)
02339 {
02340         L2UCHAR cr = (mes[0] & 0x02) >> 1;
02341         L2UCHAR pf =  mes[3] & 0x01;            /* poll / final flag */
02342         L2UCHAR nr = (mes[3] >> 1);
02343 //      L2UCHAR sapi = (mes[0] & 0xfc) >> 2;
02344         L2UCHAR tei  = (mes[1] & 0xfe) >> 1;
02345         struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
02346 
02347         switch(link->state) {
02348         case Q921_STATE_MULTIPLE_FRAME_ESTABLISHED:
02349                 /* clear receiver peer busy */
02350                 Q921_CLEAR_FLAG(link, Q921_FLAG_PEER_RECV_BUSY);
02351 
02352                 if (Q921_IS_COMMAND(trunk, cr)) { /* if this is a command */
02353                         if(pf) {
02354                                 /* Enquiry response */
02355                                 Q921SendEnquiryResponse(trunk, tei);
02356                         }
02357                 } else {
02358                         if(pf) {
02359                                 /* MDL Error indication */
02360                         }
02361                 }
02362 
02363                 /* */
02364                 if(link->va <= nr && nr <= link->vs) {
02365 
02366                         if(nr == link->vs) {
02367                                 /* V(A) = N(R) */
02368                                 link->va = nr;
02369 
02370                                 /* Stop T200, restart T203 */
02371                                 Q921T200TimerStop(trunk, tei);
02372                                 Q921T203TimerReset(trunk, tei);
02373 
02374                         } else if(nr == link->va) {
02375 
02376                                 /* do nothing */
02377 
02378                         } else {
02379                                 /* V(A) = N(R) */
02380                                 link->va = nr;
02381 
02382                                 /* Restart T200 */
02383                                 Q921T200TimerReset(trunk, tei);
02384                         }
02385                         /* no state change */
02386 
02387                 } else {
02388                         /* N(R) Error recovery */
02389                         Q921NrErrorRecovery(trunk, tei);
02390 
02391                         /* change state (no action) */
02392                         Q921ChangeState(trunk, Q921_STATE_AWAITING_ESTABLISHMENT, tei);
02393                 }
02394                 break;
02395 
02396         case Q921_STATE_TIMER_RECOVERY:
02397                 /* clear receiver peer busy */
02398                 Q921_CLEAR_FLAG(link, Q921_FLAG_PEER_RECV_BUSY);
02399 
02400                 /* command + P? */
02401                 if(Q921_IS_COMMAND(trunk, cr) && pf) {
02402                         /* Enquiry response */
02403                         Q921SendEnquiryResponse(trunk, tei);
02404                 }
02405 
02406                 /* */
02407                 if(link->va <= nr && nr <= link->vs) {
02408                         /* V(A) = N(R) */
02409                         link->va = nr;
02410 
02411                         if(!Q921_IS_COMMAND(trunk, cr) && pf) {
02412                                 /* Stop T200, start T203 */
02413                                 Q921T200TimerStop(trunk, tei);
02414                                 Q921T203TimerStart(trunk, tei);
02415 
02416                                 /* Invoke retransmission */
02417                                 Q921InvokeRetransmission(trunk, tei, nr);
02418 
02419                                 /* change state (no action) */
02420                                 Q921ChangeState(trunk, Q921_STATE_MULTIPLE_FRAME_ESTABLISHED, tei);
02421                         }
02422                         /* no state change otherwise */
02423                 } else {
02424                         /* N(R) Error recovery */
02425                         Q921NrErrorRecovery(trunk, tei);
02426 
02427                         /* change state (no action) */
02428                         Q921ChangeState(trunk, Q921_STATE_AWAITING_ESTABLISHMENT, tei);
02429                 }
02430                 break;
02431 
02432         default:
02433                 break;
02434         }
02435         return 1;
02436 }
02437 
02438 
02447 static int Q921ProcREJ(L2TRUNK trunk, L2UCHAR *mes, L2INT size)
02448 {
02449         L2UCHAR cr = (mes[0] & 0x02) >> 1;
02450         L2UCHAR pf =  mes[3] & 0x01;            /* poll / final flag */
02451         L2UCHAR nr = (mes[3] >> 1);
02452 //      L2UCHAR sapi = (mes[0] & 0xfc) >> 2;
02453         L2UCHAR tei  = (mes[1] & 0xfe) >> 1;
02454         struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
02455 
02456         switch(link->state) {
02457         case Q921_STATE_MULTIPLE_FRAME_ESTABLISHED:
02458                 /* clear receiver peer busy */
02459                 Q921_CLEAR_FLAG(link, Q921_FLAG_PEER_RECV_BUSY);
02460 
02461                 /* command? */
02462                 if(Q921_IS_COMMAND(trunk, cr)) {
02463                         if(pf) {
02464                                 /* Enquiry response */
02465                                 Q921SendEnquiryResponse(trunk, tei);
02466                         }
02467                 } else {
02468                         if(pf) {
02469                                 /* MDL Error indication (A) */
02470                         }
02471                 }
02472 
02473                 /* */
02474                 if(link->va <= nr && nr <= link->vs) {
02475 
02476                         /* V(A) = N(R) */
02477                         link->va = nr;
02478 
02479                         /* Stop T200, start T203 */
02480                         Q921T200TimerStop(trunk, tei);
02481                         Q921T203TimerStart(trunk, tei);
02482 
02483                         /* Invoke retransmission of frame >N(R)  (?) */
02484                         Q921InvokeRetransmission(trunk, tei, nr);
02485 
02486                         /* no state change */
02487                 } else {
02488                         /* N(R) Error recovery */
02489                         Q921NrErrorRecovery(trunk, tei);
02490 
02491                         /* change state (no action) */
02492                         Q921ChangeState(trunk, Q921_STATE_AWAITING_ESTABLISHMENT, tei);
02493                 }
02494                 break;
02495 
02496         case Q921_STATE_TIMER_RECOVERY:
02497                 /* clear receiver peer busy */
02498                 Q921_CLEAR_FLAG(link, Q921_FLAG_PEER_RECV_BUSY);
02499 
02500                 /* command + P ? */
02501                 if(Q921_IS_COMMAND(trunk, cr) && pf) {
02502                         /* Enquiry response */
02503                         Q921SendEnquiryResponse(trunk, tei);
02504                 }
02505 
02506                 /* */
02507                 if(link->va <= nr && nr <= link->vs) {
02508 
02509                         /* V(A) = N(R) */
02510                         link->va = nr;
02511 
02512                         if(!Q921_IS_COMMAND(trunk, cr) && pf) {
02513                                 /* Stop T200, start T203 */
02514                                 Q921T200TimerStop(trunk, tei);
02515                                 Q921T203TimerStart(trunk, tei);
02516 
02517                                 /* Invoke retransmission */
02518                                 Q921InvokeRetransmission(trunk, tei, nr);
02519 
02520                                 /* change state (no action) */
02521                                 Q921ChangeState(trunk, Q921_STATE_MULTIPLE_FRAME_ESTABLISHED, tei);
02522                         }
02523                         /* no state change otherwise */
02524                 } else {
02525                         /* N(R) Error recovery */
02526                         Q921NrErrorRecovery(trunk, tei);
02527 
02528                         /* change state (no action) */
02529                         Q921ChangeState(trunk, Q921_STATE_AWAITING_ESTABLISHMENT, tei);
02530                 }
02531                 break;
02532 
02533         default:
02534                 break;
02535         }
02536 
02537         return 1;
02538 }
02539 
02540 
02549 static int Q921ProcRNR(L2TRUNK trunk, L2UCHAR *mes, L2INT size)
02550 {
02551         L2UCHAR cr = (mes[0] & 0x02) >> 1;
02552         L2UCHAR pf =  mes[3] & 0x01;            /* poll / final flag */
02553         L2UCHAR nr = (mes[3] >> 1);
02554 //      L2UCHAR sapi = (mes[0] & 0xfc) >> 2;
02555         L2UCHAR tei  = (mes[1] & 0xfe) >> 1;
02556         struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
02557 
02558         switch(link->state) {
02559         case Q921_STATE_MULTIPLE_FRAME_ESTABLISHED:
02560                 /* set peer receiver busy */
02561                 Q921_SET_FLAG(link, Q921_FLAG_PEER_RECV_BUSY);
02562 
02563                 /* command? */
02564                 if(Q921_IS_COMMAND(trunk, cr)) {
02565                         if(pf) {
02566                                 /* Enquiry response */
02567                                 Q921SendEnquiryResponse(trunk, tei);
02568                         }
02569                 } else {
02570                         if(pf) {
02571                                 /* MDL Error indication (A) */
02572                         }
02573                 }
02574 
02575                 /* */
02576                 if(link->va <= nr && nr <= link->vs) {
02577 
02578                         /* V(A) = N(R) */
02579                         link->va = nr;
02580 
02581                         /* Stop T203, restart T200 */
02582                         Q921T200TimerReset(trunk, tei);
02583                         Q921T203TimerStop(trunk, tei);
02584 
02585                         /* no state change */
02586                 } else {
02587                         /* N(R) Error recovery */
02588                         Q921NrErrorRecovery(trunk, tei);
02589 
02590                         /* change state (no action) */
02591                         Q921ChangeState(trunk, Q921_STATE_AWAITING_ESTABLISHMENT, tei);
02592                 }
02593                 break;
02594 
02595         case Q921_STATE_TIMER_RECOVERY:
02596                 /* set peer receiver busy */
02597                 Q921_SET_FLAG(link, Q921_FLAG_PEER_RECV_BUSY);
02598 
02599                 /* command + P? */
02600                 if(Q921_IS_COMMAND(trunk, cr) && pf) {
02601                         /* Enquiry response */
02602                         Q921SendEnquiryResponse(trunk, tei);
02603                 }
02604 
02605                 /* */
02606                 if(link->va <= nr && nr <= link->vs) {
02607 
02608                         /* V(A) = N(R) */
02609                         link->va = nr;
02610 
02611                         if(!Q921_IS_COMMAND(trunk, cr) && pf) {
02612                                 /* Restart T200 */
02613                                 Q921T200TimerReset(trunk, tei);
02614 
02615                                 /* Invoke retransmission */
02616                                 Q921InvokeRetransmission(trunk, tei, nr);
02617 
02618                                 /* change state (no action) */
02619                                 Q921ChangeState(trunk, Q921_STATE_MULTIPLE_FRAME_ESTABLISHED, tei);
02620                         }
02621                         /* no state change otherwise */
02622                 } else {
02623                         /* N(R) Error recovery */
02624                         Q921NrErrorRecovery(trunk, tei);
02625 
02626                         /* change state (no action) */
02627                         Q921ChangeState(trunk, Q921_STATE_AWAITING_ESTABLISHMENT, tei);
02628                 }
02629                 break;
02630 
02631         default:
02632                 break;
02633         }
02634 
02635         return 1;
02636 }
02637 
02638 #if 0
02639 static int Q921SetReceiverBusy(L2TRUNK trunk)
02640 {
02641         struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
02642 
02643         switch(link->state) {
02644         case Q921_STATE_MULTIPLE_FRAME_ESTABLISHED:
02645                 if(!Q921_CHECK_FLAG(link, Q921_FLAG_RECV_BUSY)) {
02646                         /* set own receiver busy */
02647                         Q921_SET_FLAG(link, Q921_FLAG_RECV_BUSY);
02648 
02649                         /* send RR response */
02650                         Q921SendRR(trunk, trunk->sapi, Q921_RESPONSE(trunk), link->tei, 0);
02651 
02652                         /* clear ack pending */
02653                         Q921_CLEAR_FLAG(link, Q921_FLAG_ACK_PENDING);
02654                 }
02655                 break;
02656 
02657         case Q921_STATE_TIMER_RECOVERY:
02658                 if(!Q921_CHECK_FLAG(link, Q921_FLAG_RECV_BUSY)) {
02659                         /* set own receiver busy */
02660                         Q921_SET_FLAG(link, Q921_FLAG_RECV_BUSY);
02661 
02662                         /* send RNR response */
02663                         Q921SendRNR(trunk, trunk->sapi, Q921_RESPONSE(trunk), link->tei, 0);
02664 
02665                         /* clear ack pending */
02666                         Q921_CLEAR_FLAG(link, Q921_FLAG_ACK_PENDING);
02667                 }
02668                 break;
02669 
02670         default:
02671                 break;
02672         }
02673 
02674         return 0;
02675 }
02676 
02677 static int Q921ClearReceiverBusy(L2TRUNK trunk)
02678 {
02679         struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
02680 
02681         switch(link->state) {
02682         case Q921_STATE_MULTIPLE_FRAME_ESTABLISHED:
02683         case Q921_STATE_TIMER_RECOVERY:
02684                 if(Q921_CHECK_FLAG(link, Q921_FLAG_RECV_BUSY)) {
02685                         /* clear own receiver busy */
02686                         Q921_CLEAR_FLAG(link, Q921_FLAG_RECV_BUSY);
02687 
02688                         /* send RNR response */
02689                         Q921SendRNR(trunk, trunk->sapi, Q921_RESPONSE(trunk), link->tei, 0);
02690 
02691                         /* clear ack pending */
02692                         Q921_CLEAR_FLAG(link, Q921_FLAG_ACK_PENDING);
02693                 }
02694                 break;
02695 
02696         default:
02697                 break;
02698         }
02699 
02700         return 0;
02701 }
02702 #endif
02703 
02704 static int Q921ProcIFrame(L2TRUNK trunk, L2UCHAR *mes, L2INT size)
02705 {
02706         /* common fields: get sapi, tei and cr */
02707 //      L2UCHAR sapi = (mes[0] & 0xfc) >> 2;
02708 //      L2UCHAR cr   = (mes[0] & 0x02) >> 1;
02709         L2UCHAR tei  = (mes[1] & 0xfe) >> 1;
02710         L2UCHAR pf   =  mes[3] & 0x01;          /* poll / final flag */
02711         L2UCHAR nr   =  mes[3] >> 1;            /* receive sequence number */
02712         L2UCHAR ns   =  mes[2] >> 1;            /* send sequence number */
02713         L2UCHAR discard = 0;
02714         struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
02715 
02716         /* Ignore I frames in earlier states */
02717         if(link->state < Q921_STATE_MULTIPLE_FRAME_ESTABLISHED) {
02718                 Q921Log(trunk, Q921_LOG_NOTICE, "I frame in invalid state ignored\n");
02719                 return 0;
02720         }
02721 
02722 #ifdef Q921_STATISTICS_VERBOSE
02723         Q921StatsIncrementCounter(link, Q921_STATS_RECV_I);
02724 #endif
02725 
02726         /* Receiver busy? */
02727         if(Q921_CHECK_FLAG(link, Q921_FLAG_RECV_BUSY)) {
02728                 /* discard information */
02729                 discard = 1;
02730 
02731                 if(pf) {
02732                         /* send RNR Response */
02733                         Q921SendRNR(trunk, trunk->sapi, Q921_RESPONSE(trunk), tei, 1);
02734 
02735                         /* Clear ack pending */
02736                         Q921_CLEAR_FLAG(link, Q921_FLAG_ACK_PENDING);
02737                 }
02738         }
02739         else {
02740                 if(ns != link->vr) {
02741                         /* discard information */
02742                         discard = 1;
02743 
02744                         if(Q921_CHECK_FLAG(link, Q921_FLAG_REJECT) && pf) {
02745 
02746                                 /* Send RR response */
02747                                 Q921SendRR(trunk, trunk->sapi, Q921_RESPONSE(trunk), tei, 1);
02748 
02749                                 /* clear ack pending */
02750                                 Q921_CLEAR_FLAG(link, Q921_FLAG_ACK_PENDING);
02751                         }
02752                         else if(!Q921_CHECK_FLAG(link, Q921_FLAG_REJECT)){
02753 
02754                                 /* set reject exception */
02755                                 Q921_SET_FLAG(link, Q921_FLAG_REJECT);
02756 
02757                                 /* Send REJ response */
02758                                 Q921SendREJ(trunk, trunk->sapi, Q921_RESPONSE(trunk), tei, pf);
02759 
02760                                 /* clear ack pending */
02761                                 Q921_CLEAR_FLAG(link, Q921_FLAG_ACK_PENDING);
02762                         }
02763                 }
02764                 else {
02765                         /* V(R) = V(R) + 1 */
02766                         Q921_INC_COUNTER(link->vr);
02767 
02768                         /* clear reject exception */
02769                         Q921_CLEAR_FLAG(link, Q921_FLAG_REJECT);
02770 
02771                         /* DL-Data indication */
02772                         Q921Tx23Proc(trunk, Q921_DL_DATA, tei, mes, size);
02773 
02774                         if(pf) {
02775                                 /* Send RR response */
02776                                 Q921SendRR(trunk, trunk->sapi, Q921_RESPONSE(trunk), tei, 1);
02777 
02778                                 /* clear ack pending */
02779                                 Q921_CLEAR_FLAG(link, Q921_FLAG_ACK_PENDING);
02780                         }
02781                         else if(!Q921_CHECK_FLAG(link, Q921_FLAG_ACK_PENDING)) {
02782                                 /* ack pending */
02783 
02784                                 /* Send RR response */
02785                                 Q921SendRR(trunk, trunk->sapi, Q921_RESPONSE(trunk), tei, 0);
02786                                 
02787                                 /* set ack pending*/
02788                                 Q921_SET_FLAG(link, Q921_FLAG_ACK_PENDING);
02789                         }
02790                 }
02791         }
02792 
02793 
02794         switch(link->state) {
02795         case Q921_STATE_MULTIPLE_FRAME_ESTABLISHED:
02796                 if(link->va <= nr && nr <= link->vs) {
02797                         if(Q921_CHECK_FLAG(link, Q921_FLAG_PEER_RECV_BUSY)) {
02798                                 link->va = nr;
02799                         }
02800                         else if(nr == link->vs) {
02801                                 /* V(A) = N(R) */
02802                                 link->va = nr;
02803 
02804                                 /* stop t200, restart t203 */
02805                                 Q921T200TimerStop(trunk, tei);
02806                                 Q921T203TimerReset(trunk, tei);
02807                         }
02808                         else if(nr != link->va) {
02809                                 /* V(A) = N(R) */
02810                                 link->va = nr;
02811 
02812                                 /* restart T200 */
02813                                 Q921T200TimerReset(trunk, tei);
02814                         }
02815 
02816                         /* Restart TM01 */
02817                         if(Q921_IS_NT(trunk)) {
02818                                 Q921TM01TimerReset(trunk, tei);
02819                         }
02820                 }
02821                 else {
02822                         /* N(R) error recovery */
02823                         Q921NrErrorRecovery(trunk, tei);
02824 
02825                         /* change state (no action) */
02826                         Q921ChangeState(trunk, Q921_STATE_AWAITING_ESTABLISHMENT, tei);
02827                 }
02828                 break;
02829 
02830         case Q921_STATE_TIMER_RECOVERY:
02831                 if(link->va <= nr && nr <= link->vs) {
02832                         /* V(A) = N(R) */
02833                         link->va = nr;
02834 
02835                         /* Restart TM01 */
02836                         if(Q921_IS_NT(trunk)) {
02837                                 Q921TM01TimerReset(trunk, tei);
02838                         }
02839                 }
02840                 else {
02841                         /* N(R) error recovery */
02842                         Q921NrErrorRecovery(trunk, tei);
02843 
02844                         /* change state (no action) */
02845                         Q921ChangeState(trunk, Q921_STATE_AWAITING_ESTABLISHMENT, tei);
02846                 }
02847                 break;
02848 
02849         default:
02850                 break;
02851         }
02852 
02853         return 0;
02854 }
02855 
02856 
02857 static int Q921ProcSFrame(L2TRUNK trunk, L2UCHAR *mes, L2INT size)
02858 {
02859         L2UCHAR sv = (mes[2] & 0x0c) >> 2;      /* supervisory format id */
02860         //L2UCHAR pf = mes[3] & 0x01;           /* poll / final flag */
02861         //L2UCHAR nr = mes[3] >> 1;             /* receive sequence number */
02862         L2INT res = -1;
02863 #ifdef Q921_STATISTICS_VERBOSE
02864         L2UCHAR tei  = (mes[1] & 0xfe) >> 1;
02865 
02866         Q921StatsIncrementCounter(Q921_LINK_CONTEXT(trunk, tei), Q921_STATS_RECV_S);
02867 #endif
02868 
02869         switch(sv) {
02870         case 0x00:      /* RR : Receive Ready */
02871                 res = Q921ProcRR(trunk, mes, size);
02872                 break;
02873 
02874         case 0x02:      /* RNR : Receive Not Ready */
02875                 res = Q921ProcRNR(trunk, mes, size);
02876                 break;
02877 
02878         case 0x04:      /* REJ : Reject */
02879                 res = Q921ProcREJ(trunk, mes, size);
02880                 break;
02881 
02882         default:        /* Invalid / Unknown */
02883 #ifdef Q921_STATISTICS_VERBOSE
02884                 Q921StatsIncrementCounter(Q921_LINK_CONTEXT(trunk, tei), Q921_STATS_RECV_INVALID_S);
02885 #endif
02886                 Q921Log(trunk, Q921_LOG_ERROR, "Invalid S frame type %d\n", sv);
02887                 break;
02888         }
02889 
02890         return res;
02891 }
02892 
02893 
02894 
02895 static int Q921ProcUFrame(L2TRUNK trunk, L2UCHAR *mes, L2INT size) 
02896 {
02897         L2UCHAR m  = (mes[2] & 0xe0) >> 3 | (mes[2] & 0x0c) >> 2;       /* modifier function id */
02898 //      L2UCHAR pf = (mes[2] & 0x10) >> 4;                              /* poll / final flag */
02899         L2INT res = -1;
02900 #ifdef Q921_STATISTICS_VERBOSE
02901         L2UCHAR tei  = (mes[1] & 0xfe) >> 1;
02902 
02903         Q921StatsIncrementCounter(Q921_LINK_CONTEXT(trunk, tei), Q921_STATS_RECV_U);
02904 #endif
02905 
02906         switch(m) {
02907         case 0x00:      /* UN : Unnumbered Information */
02908                 if(mes[3] == Q921_LAYER_ENT_ID_TEI)
02909                 {
02910                         if(!Q921_IS_PTMP(trunk)) {
02911                                 /* wtf? nice try */
02912                                 return res;
02913                         }
02914 
02915                         switch(mes[6]) {
02916                         case Q921_TEI_ID_REQUEST:       /* (TE ->) NT */
02917                                 res = Q921TeiProcAssignRequest(trunk, mes, size);
02918                                 break;
02919 
02920                         case Q921_TEI_ID_ASSIGNED:      /* (NT ->) TE */
02921                         case Q921_TEI_ID_DENIED:
02922                                 res = Q921TeiProcAssignResponse(trunk, mes, size);
02923                                 break;
02924 
02925                         case Q921_TEI_ID_CHECKREQ:      /* (NT ->) TE */
02926                                 res = Q921TeiProcCheckRequest(trunk, mes, size);
02927                                 break;
02928 
02929                         case Q921_TEI_ID_CHECKRESP:     /* (TE ->) NT */
02930                                 res = Q921TeiProcCheckResponse(trunk, mes, size);
02931                                 break;
02932 
02933                         case Q921_TEI_ID_REMOVE:        /* (NT ->) TE */
02934                                 res = Q921TeiProcRemoveRequest(trunk, mes, size);
02935                                 break;
02936 
02937                         case Q921_TEI_ID_VERIFY:        /* (TE ->) NT */
02938                                 res = Q921TeiProcVerifyRequest(trunk, mes, size);
02939                                 break;
02940 
02941                         default:                        /* Invalid / Unknown */
02942                                 Q921Log(trunk, Q921_LOG_ERROR, "Invalid UN message from TEI management/endpoint\n");
02943                                 break;
02944                         }
02945                 }
02946                 else if(mes[3] == Q921_LAYER_ENT_ID_Q931) {
02947 
02948                         Q921Log(trunk, Q921_LOG_DEBUG, "UI Frame for Layer 3 received\n");
02949 
02950                         res = Q921Tx23Proc(trunk, Q921_DL_UNIT_DATA, 0, mes, size);
02951                 }
02952                 break;
02953 
02954         case 0x03:      /* DM : Disconnect Mode */
02955                 res = Q921ProcDM(trunk, mes, size);
02956                 break;
02957 
02958         case 0x08:      /* DISC : Disconnect */
02959                 res = Q921ProcDISC(trunk, mes, size);
02960                 break;
02961 
02962         case 0x0c:      /* UA : Unnumbered Acknowledgement */
02963                 res = Q921ProcUA(trunk, mes, size);
02964                 break;
02965 
02966         case 0x0f:      /* SABME  : Set Asynchronous Balanced Mode Extend */
02967                 res = Q921ProcSABME(trunk, mes, size);
02968                 break;
02969 
02970         case 0x11:      /* FRMR : Frame Reject */
02971         case 0x17:      /* XID : Exchange Identification */
02972                 res = 0;
02973                 break;
02974 
02975         default:        /* Unknown / Invalid */
02976 #ifdef Q921_STATISTICS_VERBOSE
02977                 Q921StatsIncrementCounter(Q921_LINK_CONTEXT(trunk, tei), Q921_STATS_RECV_INVALID_U);
02978 #endif
02979                 Q921Log(trunk, Q921_LOG_ERROR, "Invalid U frame type: %d\n", m);
02980                 break;
02981         }
02982 
02983         return res;
02984 }
02985 
02986 
02987 /*****************************************************************************
02988 
02989   Function:     Q921Rx12
02990 
02991   Description:  Called to process a message frame from layer 1. Will 
02992                 identify the message and call the proper 'processor' for
02993                 layer 2 messages and forward I frames to the layer 3 entity.
02994 
02995                 Q921Rx12 will check the input fifo for a message, and if a 
02996                 message exist process one message before it exits. The caller
02997                 must either call Q921Rx12 polling or keep track on # 
02998                 messages in the queue.
02999 
03000   Parameters:   trunk       trunk #.
03001 
03002   Return Value: # messages processed (always 1 or 0).
03003 
03004 *****************************************************************************/
03005 int Q921Rx12(L2TRUNK trunk)
03006 {
03007         L2INT size;     /* receive size & Q921 frame size*/
03008         L2UCHAR *smes = MFIFOGetMesPtr(trunk->HDLCInQueue, &size);
03009 
03010         if(smes)
03011         {
03012                 struct Q921_Link *link;
03013                 L2UCHAR sapi, tei;
03014                 L2UCHAR *mes;
03015                 L2INT rs;
03016 
03017                 rs  = size - trunk->Q921HeaderSpace;
03018                 mes = &smes[trunk->Q921HeaderSpace];
03019 
03020                 Q921LogMesg(trunk, Q921_LOG_DEBUG, 1, mes, rs, "New packet received (%d bytes)", rs);
03021 
03022                 /* common fields: get sapi, tei and cr */
03023                 sapi = (mes[0] & 0xfc) >> 2;
03024                 tei  = (mes[1] & 0xfe) >> 1;
03025                 link  = Q921_LINK_CONTEXT(trunk, tei);
03026 
03027                 if(Q921_IS_PTMP_TE(trunk) && (
03028                          (link->state >= Q921_STATE_TEI_ASSIGNED && tei != link->tei && tei != Q921_TEI_BCAST) ||                       /* Assigned TEI: Only BCAST and directed */
03029                          (link->state == Q921_STATE_TEI_UNASSIGNED && tei != Q921_TEI_BCAST)))                                  /* No assigned TEI: Only BCAST */
03030                 {
03031                         /* Ignore Messages with foreign TEIs */
03032                         goto out;
03033                 }
03034 
03035                 if((mes[2] & 0x01) == 0x00) {           /* I frame */
03036                         Q921ProcIFrame(trunk, mes, rs);
03037                 }
03038                 else if((mes[2] & 0x03) == 0x01) {      /* S frame */
03039                         Q921ProcSFrame(trunk, mes, rs);
03040                 }
03041                 else if((mes[2] & 0x03) == 0x03) {      /* U frame */
03042                         Q921ProcUFrame(trunk, mes, rs);
03043                 }
03044                 else {
03045                         Q921Log(trunk, Q921_LOG_ERROR, "Invalid frame type: %d\n", (int)(mes[2] & 0x03));
03046                         /* TODO: send FRMR or REJ */
03047                 }
03048 
03049 out:
03050                 MFIFOKillNext(trunk->HDLCInQueue);
03051 
03052                 return 1;
03053         }
03054 
03055         return 0;
03056 }
03057 
03058 /*
03059  * Misc
03060  */
03070 void Q921SetLogCB(L2TRUNK trunk, Q921LogCB_t func, void *priv)
03071 {
03072         if(!trunk)
03073                 return;
03074 
03075         trunk->Q921LogProc = func;
03076         trunk->PrivateDataLog = priv;
03077 }
03078 
03087 void Q921SetLogLevel(L2TRUNK trunk, Q921LogLevel_t level)
03088 {
03089         if(!trunk)
03090                 return;
03091 
03092     if (level < Q921_LOG_NONE) {
03093         level = Q921_LOG_NONE;
03094     } else if (level > Q921_LOG_DEBUG) {
03095         level = Q921_LOG_DEBUG;
03096     }
03097 
03098         trunk->loglevel = level;
03099 }
03100 
03101 
03111 static int Q921ChangeState(L2TRUNK trunk, Q921State_t state, L2UCHAR tei)
03112 {
03113         struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
03114         Q921State_t oldstate = link->state;
03115         int res = 0;
03116 
03117         Q921Log(trunk, Q921_LOG_DEBUG, "Changing state from \"%s\" (%d) to \"%s\" (%d) for TEI %d\n",
03118                                 Q921State2Name(oldstate), oldstate,
03119                                 Q921State2Name(state), state,
03120                                 tei);
03121 
03122         /*
03123          * generic actions (depending on the target state only)
03124          */
03125         switch(state) {
03126         case Q921_STATE_MULTIPLE_FRAME_ESTABLISHED:
03127                 /* Start TM01 */
03128                 if(Q921_IS_NT(trunk)) {
03129                         Q921TM01TimerStart(trunk, tei);
03130                 }
03131                 break;
03132 
03133         default:
03134                 break;
03135         }
03136 
03137         /*
03138          * actions that depend on type of the old -> new state transition
03139          */
03140         switch(oldstate) {
03141         case Q921_STATE_STOPPED:
03142 
03143                 switch(state) {
03144                 case Q921_STATE_TEI_UNASSIGNED:
03145                         if(Q921_IS_PTMP_TE(trunk)) {
03146                                 res = Q921TeiSendAssignRequest(trunk);
03147                         }
03148                         break;
03149 
03150                 case Q921_STATE_TEI_ASSIGNED:
03151                         if(Q921_IS_PTMP_NT(trunk)) {
03152                                 res = Q921TeiSendRemoveRequest(trunk, Q921_TEI_BCAST);
03153                         }
03154                         break;
03155 
03156                 default:
03157                         break;
03158                 }
03159                 break;
03160 
03161         default:
03162                 break;
03163         }
03164 
03165         link->state = state;
03166 
03167         Q921Log(trunk, Q921_LOG_DEBUG, "Q921ChangeState() returns %d, new state is \"%s\" (%d) for TEI %d\n", res, Q921State2Name(state), state, tei);
03168 
03169 #ifdef Q921_STATISTICS
03170         /* update counter, states map 1:1 to counter IDs */
03171         Q921StatsIncrementCounter(link, state);
03172 #endif
03173         return res;
03174 }
03175 
03176 /*
03177  * TEI Management functions
03178  * \note        All TEI-mgmt UN frames are sent with cr = command!
03179  */
03180 static int Q921TeiSend(L2TRUNK trunk, L2UCHAR type, L2USHORT ri, L2UCHAR ai)
03181 {
03182         L2UCHAR mes[10];
03183         L2UCHAR offset = Q921_UFRAME_DATA_OFFSET(trunk);
03184 
03185         mes[offset++] = Q921_LAYER_ENT_ID_TEI;  /* layer management entity identifier */
03186         mes[offset++] = (ri & 0xff00) >> 8;     /* reference number upper part */
03187         mes[offset++] =  ri & 0xff;             /* reference number lower part */
03188         mes[offset++] = type;                   /* message type: Identity Request */
03189         mes[offset++] = ai << 1 | 0x01;         /* action indicator: TEI */
03190 
03191 #ifdef Q921_STATISTICS_VERBOSE
03192 /* TODO:        Q921StatsIncrementCounter(Q921_TRUNK_CONTEXT(trunk), Q921_STATS_SEND_I); */
03193 #endif
03194 
03195         return Q921SendU(trunk, Q921_SAPI_TEI, Q921_COMMAND(trunk), Q921_TEI_BCAST, 0, 0x00, mes, offset);
03196 }
03197 
03198 
03207 static int Q921TeiSendAssignRequest(L2TRUNK trunk)
03208 {
03209         struct Q921_Link *link = Q921_TRUNK_CONTEXT(trunk);
03210         L2INT res;
03211 
03212         if (!Q921_IS_PTMP_TE(trunk))    /* only ptmp te mode*/
03213                 return 0;
03214 
03215         link->ri = (L2USHORT)(random() % 0xffff);
03216 
03217         /* send TEI assign request */
03218         res = Q921TeiSend(trunk, Q921_TEI_ID_REQUEST, link->ri, Q921_TEI_BCAST);
03219 
03220         /* start T202 */
03221         Q921T202TimerStart(trunk);
03222 
03223         return res;
03224 }
03225 
03226 
03237 static int Q921TeiProcAssignResponse(L2TRUNK trunk, L2UCHAR *mes, L2INT size)
03238 {
03239         struct Q921_Link *link = Q921_TRUNK_CONTEXT(trunk);
03240         L2UCHAR offset = Q921_UFRAME_DATA_OFFSET(trunk);
03241         L2USHORT ri = 0;
03242 
03243         if (!Q921_IS_PTMP_TE(trunk))    /* PTMP TE only */
03244                 return 0;
03245 
03246         ri = (mes[offset + 1] << 8) | mes[offset + 2];
03247 
03248         if(ri != link->ri) {
03249                 /* hmmm ..., not our response i guess */
03250                 return 0;
03251         }
03252 
03253         switch(mes[offset + 3]) {
03254         case Q921_TEI_ID_ASSIGNED:
03255                 /* Yay, use the new TEI and change state to assigned */
03256                 link->tei      = mes[offset + 4] >> 1;
03257 
03258                 Q921Log(trunk, Q921_LOG_DEBUG, "Assigned TEI %d, setting state to TEI_ASSIGNED\n", link->tei);
03259 
03260                 Q921ChangeState(trunk, Q921_STATE_TEI_ASSIGNED, link->tei);
03261                 break;
03262 
03263         case Q921_TEI_ID_DENIED:
03264                 /* oops, what to do now? */
03265                 if ((mes[offset + 4] >> 1) == Q921_TEI_BCAST) {
03266                         /* No more free TEIs? this is bad */
03267 
03268                         //Q921TeiSendVerifyRequest(trunk, Q921_TEI_BCAST); /* TODO: does this work ?? */
03269                 } else {
03270                         /* other reason, this is fatal, shutdown link */
03271                 }
03272 
03273                 Q921Log(trunk, Q921_LOG_DEBUG, "TEI assignment has been denied, reason: %s\n",
03274                          ((mes[offset +4] >> 1) == Q921_TEI_BCAST) ? "No free TEIs available" : "Unknown");
03275 
03276                 Q921ChangeState(trunk, Q921_STATE_TEI_UNASSIGNED, link->tei);
03277                 break;
03278 
03279         default:
03280                 return 0;
03281         }
03282 
03283         /* stop T202 */
03284         Q921T202TimerStop(trunk);
03285 
03286         return 1;
03287 }
03288 
03289 
03298 static int Q921TeiSendVerifyRequest(L2TRUNK trunk)
03299 {
03300         struct Q921_Link *link = Q921_TRUNK_CONTEXT(trunk);
03301         L2INT res;
03302 
03303         if (!Q921_IS_PTMP_TE(trunk))    /* only ptmp te mode*/
03304                 return 0;
03305 
03306         /* Request running? */
03307         if (trunk->T202)
03308                 return 0;
03309 
03310         /* Send TEI verify request */
03311         res = Q921TeiSend(trunk, Q921_TEI_ID_VERIFY, link->ri, link->tei);
03312 
03313         /* start T202 */
03314         Q921T202TimerStart(trunk);
03315 
03316         return res;
03317 }
03318 
03319 
03330 static int Q921TeiProcCheckRequest(L2TRUNK trunk, L2UCHAR *mes, L2INT size)
03331 {
03332         struct Q921_Link *link = Q921_TRUNK_CONTEXT(trunk);
03333         L2UCHAR offset = Q921_UFRAME_DATA_OFFSET(trunk);
03334         L2UCHAR tei = (mes[offset + 4] >> 1);           /* action indicator => tei */
03335         L2INT res = 0;
03336 
03337         if (!Q921_IS_PTMP_TE(trunk))    /* ptmp te mode only */
03338                 return 0;
03339 
03340         Q921Log(trunk, Q921_LOG_DEBUG, "Received TEI Check request for TEI %d\n", tei);
03341 
03342         if (tei == Q921_TEI_BCAST || tei == link->tei) {
03343                 /*
03344                  * Broadcast TEI check or for our assigned TEI
03345                  */
03346 
03347                 /* send TEI check reponse */
03348                 res = Q921TeiSend(trunk, Q921_TEI_ID_CHECKRESP, link->ri, link->tei);
03349 
03350                 Q921T202TimerStop(trunk);
03351         }
03352 
03353         return res;
03354 }
03355 
03356 
03367 static int Q921TeiProcRemoveRequest(L2TRUNK trunk, L2UCHAR *mes, L2INT size)
03368 {
03369         struct Q921_Link *link = Q921_TRUNK_CONTEXT(trunk);
03370         L2UCHAR offset = Q921_UFRAME_DATA_OFFSET(trunk);
03371         L2UCHAR tei = (mes[offset + 4] >> 1);           /* action indicator => tei */
03372         L2INT res = 0;
03373 
03374         if (!Q921_IS_PTMP_TE(trunk))    /* ptmp te mode only */
03375                 return 0;
03376 
03377         Q921Log(trunk, Q921_LOG_DEBUG, "Received TEI Remove request for TEI %d\n", tei);
03378 
03379         if (tei == Q921_TEI_BCAST || tei == link->tei) {
03380                 /*
03381                  * Broadcast TEI remove or for our assigned TEI
03382                  */
03383 
03384                 /* reset tei */
03385                 link->tei  = 0;
03386 
03387                 /* change state (no action) */
03388                 Q921ChangeState(trunk, Q921_STATE_TEI_UNASSIGNED, link->tei);
03389 
03390                 /* TODO: hmm, request new one ? */
03391                 res = Q921TeiSendAssignRequest(trunk);
03392         }
03393         return res;
03394 }
03395 
03396 
03407 static int Q921TeiProcAssignRequest(L2TRUNK trunk, L2UCHAR *mes, L2INT size)
03408 {
03409         L2UCHAR offset = Q921_UFRAME_DATA_OFFSET(trunk);
03410         L2USHORT ri = 0;
03411         L2UCHAR tei = 0;
03412 
03413         if (!Q921_IS_PTMP_NT(trunk))    /* PTMP NT only */
03414                 return 0;
03415 
03416         ri  = (mes[offset + 1] << 8) | mes[offset + 2];
03417         tei =  mes[offset + 4] >> 1;
03418 
03419         if(tei == Q921_TEI_BCAST) {
03420                 int x;
03421 
03422                 /* dynamically allocate TEI */
03423                 for(x = Q921_TEI_DYN_MIN, tei = 0; x <= Q921_TEI_MAX; x++) {
03424                         if(!trunk->tei_map[x]) {
03425                                 tei = x;
03426                                 break;
03427                         }
03428                 }
03429         }
03430         else if(!(tei > 0 && tei < Q921_TEI_DYN_MIN)) {
03431                 /* reject TEIs that are not in the static area */
03432                 Q921TeiSendDenyResponse(trunk, 0, ri);
03433 
03434                 return 0;
03435         }
03436 
03437         if(!tei) {
03438                 /* no free TEI found */
03439                 Q921TeiSendDenyResponse(trunk, Q921_TEI_BCAST, ri);
03440         }
03441         else {
03442                 struct Q921_Link *link = Q921_LINK_CONTEXT(trunk, tei);
03443 
03444                 /* mark used */
03445                 trunk->tei_map[tei] = 1;
03446 
03447                 /* assign tei */
03448                 link->tei = tei;
03449 
03450                 /* put context in TEI ASSIGNED state */
03451                 Q921ChangeState(trunk, Q921_STATE_TEI_ASSIGNED, tei);
03452 
03453                 /* send assign response */
03454                 Q921TeiSendAssignedResponse(trunk, tei, ri);
03455 
03456                 /* Start T201 */
03457                 Q921T201TimerStart(trunk, tei);
03458         }
03459         return 0;
03460 }
03461 
03471 static int Q921TeiSendCheckRequest(L2TRUNK trunk, L2UCHAR tei)
03472 {
03473         L2INT res = 0;
03474 
03475         if (!Q921_IS_PTMP_NT(trunk))    /* PTMP NT only */
03476                 return 0;
03477 
03478         /* send TEI check request */
03479         res = Q921TeiSend(trunk, Q921_TEI_ID_CHECKREQ, 0, tei);
03480 
03481         /* (Re-)Start T201 timer */
03482         Q921T201TimerStart(trunk, tei);
03483 
03484         return res;
03485 }
03486 
03497 static int Q921TeiProcCheckResponse(L2TRUNK trunk, L2UCHAR *mes, L2INT size)
03498 {
03499         struct Q921_Link *link;
03500         L2UCHAR offset = Q921_UFRAME_DATA_OFFSET(trunk);
03501         L2USHORT ri = 0;
03502         L2UCHAR tei = 0;
03503 
03504         if (!Q921_IS_PTMP_NT(trunk))    /* PTMP NT mode only */
03505                 return 0;
03506 
03507         ri  = (mes[offset + 1] << 8) | mes[offset + 2];
03508         tei =  mes[offset + 4] >> 1;
03509 
03510         /* restart T201 */
03511         Q921T201TimerStop(trunk, tei);
03512 
03513         /* reset counter */
03514         link       = Q921_LINK_CONTEXT(trunk, tei);
03515         link->N202 = 0;
03516 
03517         if(!(tei > 0 && tei < Q921_TEI_MAX) || !trunk->tei_map[tei]) {
03518                 /* TODO: Should we send a DISC first? */
03519 
03520                 /* TEI not assigned? Invalid TEI? */
03521                 Q921TeiSendRemoveRequest(trunk, tei);
03522 
03523                 /* change state */
03524                 Q921ChangeState(trunk, Q921_STATE_STOPPED, tei);
03525 
03526                 /* clear */
03527                 memset(link, 0, sizeof(struct Q921_Link));
03528         } else {
03529                 /* Start T201 */
03530                 Q921T201TimerStart(trunk, tei);
03531         }
03532 
03533         return 0;
03534 }
03535 
03536 
03547 static int Q921TeiProcVerifyRequest(L2TRUNK trunk, L2UCHAR *mes, L2INT size)
03548 {
03549         L2UCHAR resp[25];
03550         L2UCHAR offset = Q921_UFRAME_DATA_OFFSET(trunk);
03551         L2UCHAR tei = 0;
03552 
03553         if (!Q921_IS_PTMP_NT(trunk))    /* PTMP NT mode only */
03554                 return 0;
03555 
03556         tei = mes[offset + 4] >> 1;
03557 
03558         /* todo: handle response... verify assigned TEI */
03559         resp[offset + 0] = 0;
03560 
03561         return 0;
03562 }
03563 
03572 static int Q921TeiSendDenyResponse(L2TRUNK trunk, L2UCHAR tei, L2USHORT ri)
03573 {
03574         if (!Q921_IS_PTMP_NT(trunk))    /* PTMP NT only */
03575                 return 0;
03576 
03577         return Q921TeiSend(trunk, Q921_TEI_ID_DENIED, ri, tei);
03578 }
03579 
03580 
03591 static int Q921TeiSendAssignedResponse(L2TRUNK trunk, L2UCHAR tei, L2USHORT ri)
03592 {
03593         if (!Q921_IS_PTMP_NT(trunk))    /* PTMP NT only */
03594                 return 0;
03595 
03596         return Q921TeiSend(trunk, Q921_TEI_ID_ASSIGNED, ri, tei);
03597 }
03598 
03608 static int Q921TeiSendRemoveRequest(L2TRUNK trunk, L2UCHAR tei)
03609 {
03610         if (!Q921_IS_PTMP_NT(trunk))    /* PTMP NT only */
03611                 return 0;
03612 
03613         return Q921TeiSend(trunk, Q921_TEI_ID_REMOVE, 0, tei);
03614 }
03615 
03616 
03617 #ifdef Q921_STATISTICS
03618 
03621 static struct Q921StatsCounter
03622 {
03623         const int id;
03624         const char *name;
03625         const char *desc;
03626 } Q921StatsCounters[] = {
03627         /* State changes */
03628         { Q921_STATS_ST01, "ST01", "State: TEI Unassigned" },
03629         { Q921_STATS_ST02, "ST02", "State: TEI Awaiting" },
03630         { Q921_STATS_ST03, "ST03", "State: TEI Establish" },
03631         { Q921_STATS_ST04, "ST04", "State: TEI Assigned" },
03632         { Q921_STATS_ST05, "ST05", "State: Awaiting Establishment" },
03633         { Q921_STATS_ST06, "ST06", "State: Awaiting Release" },
03634         { Q921_STATS_ST07, "ST07", "State: Multiple Frame Established" },
03635         { Q921_STATS_ST08, "ST08", "State: Timer Recovery" },
03636 
03637         /* Event counters */
03638         { Q921_STATS_T200, "T200", "Timer: T200 Timeouts" },
03639         { Q921_STATS_T201, "T201", "Timer: T201 Timeouts" },
03640         { Q921_STATS_T202, "T202", "Timer: T202 Timeouts" },
03641         { Q921_STATS_T203, "T203", "Timer: T203 Timeouts" },
03642 
03643         { Q921_STATS_TM01, "TM01", "Timer: TM01 Timeouts" },
03644 
03645         { Q921_STATS_N200, "N200", "" },
03646         { Q921_STATS_N201, "N201", "" },
03647         { Q921_STATS_N202, "N202", "" },
03648 
03649 #ifdef Q921_STATISTICS_VERBOSE
03650         /* TODO: Packet counters */
03651         { Q921_STATS_SEND_S, "S", "TX: S frame" },
03652         { Q921_STATS_SEND_U, "U", "TX: U frame" },
03653         { Q921_STATS_SEND_I, "I", "TX: I frame" },
03654 
03655         { Q921_STATS_SEND_RR,    "RR",    "TX: Receiver-Ready" },
03656         { Q921_STATS_SEND_RNR,   "RNR",   "TX: Receiver-Not-Ready" },
03657         { Q921_STATS_SEND_REJ,   "REJ",   "TX: Reject" },
03658         { Q921_STATS_SEND_SABME, "SABME", "TX: SABME" },
03659         { Q921_STATS_SEND_DM,    "DM",    "TX: Disconnected-Mode" },
03660         { Q921_STATS_SEND_DISC,  "DISC",  "TX: Disconnect" },
03661         { Q921_STATS_SEND_UA,    "UA",    "TX: UA" },
03662         { Q921_STATS_SEND_UN,    "UN",    "TX: UN" },
03663 
03664         /* packet receive counters */
03665         { Q921_STATS_RECV_S, "S", "RX: S frame" },
03666         { Q921_STATS_RECV_U, "U", "RX: U frame" },
03667         { Q921_STATS_RECV_I, "I", "RX: I frame" },
03668 
03669         { Q921_STATS_RECV_INVALID_S, "Invalid S", "RX: Invalid S frame" },
03670         { Q921_STATS_RECV_INVALID_U, "Invalid U", "RX: Invalid U frame" },
03671         { Q921_STATS_RECV_INVALID_I, "Invalid I", "RX: Invalid I frame" },
03672 
03673         { Q921_STATS_RECV_SABME, "SABME", "RX: SABME" },
03674         { Q921_STATS_RECV_DM,    "DM",    "RX: Disconnected-Mode" },
03675         { Q921_STATS_RECV_UA,    "UA",    "RX: UA" },
03676         { Q921_STATS_RECV_DISC,  "DISC",  "RX: Disconnect" },
03677         { Q921_STATS_RECV_RR,    "RR",    "RX: Receiver-Ready" },
03678         { Q921_STATS_RECV_REJ,   "REJ",   "RX: Reject" },
03679         { Q921_STATS_RECV_RNR,   "RNR",   "RX: Receiver-Not-Ready" },
03680 #endif
03681 
03682         /* don't touch */
03683         { 0, NULL, NULL }
03684 };
03685 
03686 int Q921StatsCounterIsGlobal(const int id)
03687 {
03688         switch (id) {
03689         case Q921_STATS_T202:
03690         case Q921_STATS_N201:
03691                 return 1;
03692         default:
03693                 return 0;
03694         }
03695 }
03696 
03697 const char *Q921StatsCounterGetDescription(const int id)
03698 {
03699         struct Q921StatsCounter *info = Q921StatsCounters;
03700 
03701         if (id <= Q921_STATS_NONE || id >= Q921_STATS_MAX)
03702                 return "invalid";
03703 
03704         while (info->id) {
03705                 if (info->id == id)
03706                         return info->desc;
03707                 info++;
03708         }
03709         return "";
03710 }
03711 
03712 const char *Q921StatsCounterGetName(const int id)
03713 {
03714         struct Q921StatsCounter *info = Q921StatsCounters;
03715 
03716         if (id <= Q921_STATS_NONE || id >= Q921_STATS_MAX)
03717                 return "invalid";
03718 
03719         while (info->id) {
03720                 if (info->id == id)
03721                         return info->name;
03722                 info++;
03723         }
03724         return "";
03725 }
03726 
03737 unsigned int Q921StatsGetCounter(const L2TRUNK trunk, const int id, const int tei)
03738 {
03739         struct Q921_Link *link = NULL;
03740 
03741         if (!trunk)
03742                 return 0;
03743 
03744         if (id <= Q921_STATS_NONE || id >= Q921_STATS_MAX)
03745                 return 0;
03746 
03747         if (Q921StatsCounterIsGlobal(id)) {
03748                 link = Q921_TRUNK_CONTEXT(trunk);
03749 
03750         } else if (tei == Q921_TEI_BCAST) {
03751                 unsigned int sum = 0;
03752                 int i;
03753 
03754                 link = Q921_TRUNK_CONTEXT(trunk);
03755 
03756                 sum += link->stats.counter[id];
03757 
03758                 if (Q921_IS_PTMP(trunk)) {
03759                         for (i = 1; i < Q921_TEI_BCAST; i++) {
03760                                 link = Q921_LINK_CONTEXT(trunk, i);
03761 
03762                                 sum += link->stats.counter[id];
03763                         }
03764                 }
03765 
03766                 return sum;
03767         } else {
03768                 link = Q921_LINK_CONTEXT(trunk, tei);
03769         }
03770 
03771         return link->stats.counter[id];
03772 }
03773 
03781 void Q921StatsResetCounters(L2TRUNK trunk)
03782 {
03783         int x, nlinks;
03784 
03785         if (!trunk)
03786                 return;
03787 
03788         nlinks = Q921_IS_PTMP(trunk) ? Q921_TEI_MAX : 1;
03789 
03790         /* reset link counters */
03791         for (x = 0; x < nlinks; x++) {
03792                 memset(&trunk->context[x].stats, 0, sizeof(Q921Stats_t));
03793         }
03794 }
03795 
03796 static void Q921StatsIncrementCounter(struct Q921_Link *link, const int id)
03797 {
03798         if (!link)
03799                 return;
03800 
03801         if (id <= Q921_STATS_NONE || id >= Q921_STATS_MAX)
03802                 return;
03803 
03804         link->stats.counter[id]++;
03805 }
03806 
03807 /* convenience debug function */
03808 int Q921StatsReport(const L2TRUNK trunk, const int tei)
03809 {
03810         struct Q921StatsCounter *info = Q921StatsCounters;
03811         char buf[Q921_LOGBUFSIZE];
03812         size_t len  = Q921_LOGBUFSIZE - 1;
03813         size_t left = len;
03814         size_t offset = 0;
03815 
03816         memset(buf, 0, sizeof(buf));
03817 
03818         APPEND_MSG(buf, offset, left, "\n================== TEI: %3d ===============\n", tei)
03819 
03820         while (info->id) {
03821                 APPEND_MSG(buf, offset, left, "%-10s:\t%6d\t[%s]\n",
03822                                                 info->name,
03823                                                 Q921StatsGetCounter(trunk, info->id, tei),
03824                                                 info->desc ? info->desc : "");
03825                 info++;
03826         }
03827 
03828         APPEND_MSG(buf, offset, left, "===========================================\n")
03829 out:
03830         buf[sizeof(buf) - 1] = '\0';
03831 
03832         return trunk->Q921LogProc(trunk->PrivateDataLog, Q921_LOG_INFO, buf, strlen(buf));
03833 }
03834 #endif

Generated on Tue Apr 7 17:38:19 2009 for mod_ssh by  doxygen 1.5.4