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