|
|
1.1 ! root 1: /* ! 2: * Copyright (c) University of British Columbia, 1984 ! 3: * Copyright (c) 1990 The Regents of the University of California. ! 4: * All rights reserved. ! 5: * ! 6: * This code is derived from software contributed to Berkeley by ! 7: * the Laboratory for Computation Vision and the Computer Science Department ! 8: * of the University of British Columbia. ! 9: * ! 10: * Redistribution and use in source and binary forms, with or without ! 11: * modification, are permitted provided that the following conditions ! 12: * are met: ! 13: * 1. Redistributions of source code must retain the above copyright ! 14: * notice, this list of conditions and the following disclaimer. ! 15: * 2. Redistributions in binary form must reproduce the above copyright ! 16: * notice, this list of conditions and the following disclaimer in the ! 17: * documentation and/or other materials provided with the distribution. ! 18: * 3. All advertising materials mentioning features or use of this software ! 19: * must display the following acknowledgement: ! 20: * This product includes software developed by the University of ! 21: * California, Berkeley and its contributors. ! 22: * 4. Neither the name of the University nor the names of its contributors ! 23: * may be used to endorse or promote products derived from this software ! 24: * without specific prior written permission. ! 25: * ! 26: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ! 27: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ! 28: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ! 29: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE ! 30: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ! 31: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ! 32: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ! 33: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ! 34: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ! 35: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ! 36: * SUCH DAMAGE. ! 37: * ! 38: * @(#)hd_input.c 7.7 (Berkeley) 5/29/91 ! 39: */ ! 40: ! 41: #include "param.h" ! 42: #include "systm.h" ! 43: #include "mbuf.h" ! 44: #include "domain.h" ! 45: #include "socket.h" ! 46: #include "protosw.h" ! 47: #include "errno.h" ! 48: #include "time.h" ! 49: #include "kernel.h" ! 50: ! 51: #include "../net/if.h" ! 52: ! 53: #include "hdlc.h" ! 54: #include "hd_var.h" ! 55: #include "x25.h" ! 56: ! 57: /* ! 58: * HDLC INPUT INTERFACE ! 59: * ! 60: * This routine is called when the HDLC physical device has ! 61: * completed reading a frame. ! 62: */ ! 63: ! 64: hdintr () ! 65: { ! 66: register struct mbuf *m; ! 67: register struct hdcb *hdp; ! 68: register struct ifnet *ifp; ! 69: register int s; ! 70: extern struct ifqueue pkintrq; ! 71: static struct ifnet *lastifp; ! 72: static struct hdcb *lasthdp; ! 73: ! 74: for (;;) { ! 75: s = splimp (); ! 76: IF_DEQUEUE (&hdintrq, m); ! 77: splx (s); ! 78: if (m == 0) ! 79: break; ! 80: if (m->m_len < HDHEADERLN) { ! 81: printf ("hdintr: packet too short (len=%d)\n", ! 82: m->m_len); ! 83: m_freem (m); ! 84: continue; ! 85: } ! 86: if ((m->m_flags & M_PKTHDR) == 0) ! 87: panic("hdintr"); ! 88: ifp = m->m_pkthdr.rcvif; ! 89: ! 90: /* ! 91: * look up the appropriate hdlc control block ! 92: */ ! 93: ! 94: if (ifp == lastifp) ! 95: hdp = lasthdp; ! 96: else { ! 97: for (hdp = hdcbhead; hdp; hdp = hdp->hd_next) ! 98: if (hdp->hd_ifp == ifp) ! 99: break; ! 100: if (hdp == 0) { ! 101: printf ("hdintr: unknown interface %x\n", ifp); ! 102: m_freem (m); ! 103: continue; ! 104: } ! 105: lastifp = ifp; ! 106: lasthdp = hdp; ! 107: } ! 108: ! 109: /* Process_rxframe returns FALSE if the frame was NOT queued ! 110: for the next higher layers. */ ! 111: if (process_rxframe (hdp, m) == FALSE) ! 112: m_freem (m); ! 113: } ! 114: if (pkintrq.ifq_len) ! 115: pkintr (); ! 116: } ! 117: ! 118: process_rxframe (hdp, fbuf) ! 119: register struct hdcb *hdp; ! 120: register struct mbuf *fbuf; ! 121: { ! 122: register int queued = FALSE, frametype, pf; ! 123: register struct Hdlc_frame *frame; ! 124: ! 125: frame = mtod (fbuf, struct Hdlc_frame *); ! 126: pf = ((struct Hdlc_iframe *) frame) -> pf; ! 127: ! 128: hd_trace (hdp, RX, frame); ! 129: if (frame -> address != ADDRESS_A && frame -> address != ADDRESS_B) ! 130: return (queued); ! 131: ! 132: switch ((frametype = hd_decode (hdp, frame)) + hdp->hd_state) { ! 133: case DM + DISC_SENT: ! 134: case UA + DISC_SENT: ! 135: /* ! 136: * Link now closed. Leave timer running ! 137: * so hd_timer() can periodically check the ! 138: * status of interface driver flag bit IFF_UP. ! 139: */ ! 140: hdp->hd_state = DISCONNECTED; ! 141: break; ! 142: ! 143: case DM + INIT: ! 144: case UA + INIT: ! 145: /* ! 146: * This is a non-standard state change needed for DCEs ! 147: * that do dynamic link selection. We can't go into the ! 148: * usual "SEND DM" state because a DM is a SARM in LAP. ! 149: */ ! 150: hd_writeinternal (hdp, SABM, POLLOFF); ! 151: hdp->hd_state = SABM_SENT; ! 152: SET_TIMER (hdp); ! 153: break; ! 154: ! 155: case SABM + DM_SENT: ! 156: case SABM + WAIT_SABM: ! 157: hd_writeinternal (hdp, UA, pf); ! 158: case UA + SABM_SENT: ! 159: case UA + WAIT_UA: ! 160: KILL_TIMER (hdp); ! 161: hd_initvars (hdp); ! 162: hdp->hd_state = ABM; ! 163: hd_message (hdp, "Link level operational"); ! 164: /* Notify the packet level - to send RESTART. */ ! 165: (void) pk_ctlinput (PRC_LINKUP, hdp->hd_pkp); ! 166: break; ! 167: ! 168: case SABM + SABM_SENT: ! 169: /* Got a SABM collision. Acknowledge the remote's SABM ! 170: via UA but still wait for UA. */ ! 171: hd_writeinternal (hdp, UA, pf); ! 172: break; ! 173: ! 174: case SABM + ABM: ! 175: /* Request to reset the link from the remote. */ ! 176: KILL_TIMER (hdp); ! 177: hd_message (hdp, "Link reset"); ! 178: #ifdef HDLCDEBUG ! 179: hd_dumptrace (hdp); ! 180: #endif ! 181: hd_flush (hdp->hd_ifp); ! 182: hd_writeinternal (hdp, UA, pf); ! 183: hd_initvars (hdp); ! 184: (void) pk_ctlinput (PRC_LINKRESET, hdp->hd_pkp); ! 185: hdp->hd_resets++; ! 186: break; ! 187: ! 188: case SABM + WAIT_UA: ! 189: hd_writeinternal (hdp, UA, pf); ! 190: break; ! 191: ! 192: case DM + ABM: ! 193: hd_message (hdp, "DM received: link down"); ! 194: #ifdef HDLCDEBUG ! 195: hd_dumptrace (hdp); ! 196: #endif ! 197: (void) pk_ctlinput (PRC_LINKDOWN, hdp->hd_pkp); ! 198: hd_flush (hdp->hd_ifp); ! 199: case DM + DM_SENT: ! 200: case DM + WAIT_SABM: ! 201: case DM + WAIT_UA: ! 202: hd_writeinternal (hdp, SABM, pf); ! 203: hdp->hd_state = SABM_SENT; ! 204: SET_TIMER (hdp); ! 205: break; ! 206: ! 207: case DISC + INIT: ! 208: case DISC + DM_SENT: ! 209: case DISC + SABM_SENT: ! 210: /* Note: This is a non-standard state change. */ ! 211: hd_writeinternal (hdp, UA, pf); ! 212: hd_writeinternal (hdp, SABM, POLLOFF); ! 213: hdp->hd_state = SABM_SENT; ! 214: SET_TIMER (hdp); ! 215: break; ! 216: ! 217: case DISC + WAIT_UA: ! 218: hd_writeinternal (hdp, DM, pf); ! 219: SET_TIMER (hdp); ! 220: hdp->hd_state = DM_SENT; ! 221: break; ! 222: ! 223: case DISC + ABM: ! 224: hd_message (hdp, "DISC received: link down"); ! 225: (void) pk_ctlinput (PRC_LINKDOWN, hdp->hd_pkp); ! 226: case DISC + WAIT_SABM: ! 227: hd_writeinternal (hdp, UA, pf); ! 228: hdp->hd_state = DM_SENT; ! 229: SET_TIMER (hdp); ! 230: break; ! 231: ! 232: case UA + ABM: ! 233: hd_message (hdp, "UA received: link down"); ! 234: (void) pk_ctlinput (PRC_LINKDOWN, hdp->hd_pkp); ! 235: case UA + WAIT_SABM: ! 236: hd_writeinternal (hdp, DM, pf); ! 237: hdp->hd_state = DM_SENT; ! 238: SET_TIMER (hdp); ! 239: break; ! 240: ! 241: case FRMR + DM_SENT: ! 242: hd_writeinternal (hdp, SABM, pf); ! 243: hdp->hd_state = SABM_SENT; ! 244: SET_TIMER (hdp); ! 245: break; ! 246: ! 247: case FRMR + WAIT_SABM: ! 248: hd_writeinternal (hdp, DM, pf); ! 249: hdp->hd_state = DM_SENT; ! 250: SET_TIMER (hdp); ! 251: break; ! 252: ! 253: case FRMR + ABM: ! 254: hd_message (hdp, "FRMR received: link down"); ! 255: (void) pk_ctlinput (PRC_LINKDOWN, hdp->hd_pkp); ! 256: #ifdef HDLCDEBUG ! 257: hd_dumptrace (hdp); ! 258: #endif ! 259: hd_flush (hdp->hd_ifp); ! 260: hd_writeinternal (hdp, SABM, pf); ! 261: hdp->hd_state = WAIT_UA; ! 262: SET_TIMER (hdp); ! 263: break; ! 264: ! 265: case RR + ABM: ! 266: case RNR + ABM: ! 267: case REJ + ABM: ! 268: process_sframe (hdp, (struct Hdlc_sframe *)frame, frametype); ! 269: break; ! 270: ! 271: case IFRAME + ABM: ! 272: queued = process_iframe (hdp, fbuf, (struct Hdlc_iframe *)frame); ! 273: break; ! 274: ! 275: case IFRAME + SABM_SENT: ! 276: case RR + SABM_SENT: ! 277: case RNR + SABM_SENT: ! 278: case REJ + SABM_SENT: ! 279: hd_writeinternal (hdp, DM, POLLON); ! 280: hdp->hd_state = DM_SENT; ! 281: SET_TIMER (hdp); ! 282: break; ! 283: ! 284: case IFRAME + WAIT_SABM: ! 285: case RR + WAIT_SABM: ! 286: case RNR + WAIT_SABM: ! 287: case REJ + WAIT_SABM: ! 288: hd_writeinternal (hdp, FRMR, POLLOFF); ! 289: SET_TIMER (hdp); ! 290: break; ! 291: ! 292: case ILLEGAL + SABM_SENT: ! 293: hdp->hd_unknown++; ! 294: hd_writeinternal (hdp, DM, POLLOFF); ! 295: hdp->hd_state = DM_SENT; ! 296: SET_TIMER (hdp); ! 297: break; ! 298: ! 299: case ILLEGAL + ABM: ! 300: hd_message (hdp, "Unknown frame received: link down"); ! 301: (void) pk_ctlinput (PRC_LINKDOWN, hdp->hd_pkp); ! 302: case ILLEGAL + WAIT_SABM: ! 303: hdp->hd_unknown++; ! 304: #ifdef HDLCDEBUG ! 305: hd_dumptrace (hdp); ! 306: #endif ! 307: hd_writeinternal (hdp, FRMR, POLLOFF); ! 308: hdp->hd_state = WAIT_SABM; ! 309: SET_TIMER (hdp); ! 310: break; ! 311: } ! 312: ! 313: return (queued); ! 314: } ! 315: ! 316: process_iframe (hdp, fbuf, frame) ! 317: register struct hdcb *hdp; ! 318: struct mbuf *fbuf; ! 319: register struct Hdlc_iframe *frame; ! 320: { ! 321: register int nr = frame -> nr, ! 322: ns = frame -> ns, ! 323: pf = frame -> pf; ! 324: register int queued = FALSE; ! 325: ! 326: /* ! 327: * Validate the iframe's N(R) value. It's N(R) value must be in ! 328: * sync with our V(S) value and our "last received nr". ! 329: */ ! 330: ! 331: if (valid_nr (hdp, nr, FALSE) == FALSE) { ! 332: frame_reject (hdp, Z, frame); ! 333: return (queued); ! 334: } ! 335: ! 336: ! 337: /* ! 338: * This section tests the IFRAME for proper sequence. That is, it's ! 339: * sequence number N(S) MUST be equal to V(S). ! 340: */ ! 341: ! 342: if (ns != hdp->hd_vr) { ! 343: hdp->hd_invalid_ns++; ! 344: if (pf || (hdp->hd_condition & REJ_CONDITION) == 0) { ! 345: hdp->hd_condition |= REJ_CONDITION; ! 346: /* ! 347: * Flush the transmit queue. This is ugly but we ! 348: * have no choice. A reject response must be ! 349: * immediately sent to the DCE. Failure to do so ! 350: * may result in another out of sequence iframe ! 351: * arriving (and thus sending another reject) ! 352: * before the first reject is transmitted. This ! 353: * will cause the DCE to receive two or more ! 354: * rejects back to back, which must never happen. ! 355: */ ! 356: hd_flush (hdp->hd_ifp); ! 357: hd_writeinternal (hdp, REJ, pf); ! 358: } ! 359: return (queued); ! 360: } ! 361: hdp->hd_condition &= ~REJ_CONDITION; ! 362: ! 363: /* ! 364: * This section finally tests the IFRAME's sequence number against ! 365: * the window size (K) and the sequence number of the last frame ! 366: * we have acknowledged. If the IFRAME is completely correct then ! 367: * it is queued for the packet level. ! 368: */ ! 369: ! 370: if (ns != (hdp -> hd_lasttxnr + hdp -> hd_xcp -> xc_lwsize) % MODULUS) { ! 371: hdp -> hd_vr = (hdp -> hd_vr + 1) % MODULUS; ! 372: if (pf == 1) { ! 373: /* Must generate a RR or RNR with final bit on. */ ! 374: hd_writeinternal (hdp, RR, POLLON); ! 375: } else ! 376: /* ! 377: * Hopefully we can piggyback the RR, if not we will generate ! 378: * a RR when T3 timer expires. ! 379: */ ! 380: if (hdp -> hd_rrtimer == 0) ! 381: hdp->hd_rrtimer = hd_t3; ! 382: ! 383: /* Forward iframe to packet level of X.25. */ ! 384: fbuf -> m_data += HDHEADERLN; ! 385: fbuf -> m_len -= HDHEADERLN; ! 386: fbuf -> m_pkthdr.len -= HDHEADERLN; ! 387: fbuf -> m_pkthdr.rcvif = (struct ifnet *)hdp -> hd_pkp; ! 388: #ifdef BSD4_3 ! 389: fbuf->m_act = 0; /* probably not necessary */ ! 390: #else ! 391: { ! 392: register struct mbuf *m; ! 393: ! 394: for (m = fbuf; m -> m_next; m = m -> m_next) ! 395: m -> m_act = (struct mbuf *) 0; ! 396: m -> m_act = (struct mbuf *) 1; ! 397: } ! 398: #endif ! 399: pk_input (fbuf); ! 400: queued = TRUE; ! 401: hd_start (hdp); ! 402: } else { ! 403: /* ! 404: * Here if the remote station has transmitted more iframes then ! 405: * the number which have been acknowledged plus K. ! 406: */ ! 407: hdp->hd_invalid_ns++; ! 408: frame_reject (hdp, W, frame); ! 409: } ! 410: return (queued); ! 411: } ! 412: ! 413: /* ! 414: * This routine is used to determine if a value (the middle parameter) ! 415: * is between two other values. The low value is the first parameter ! 416: * the high value is the last parameter. The routine checks the middle ! 417: * value to see if it is within the range of the first and last values. ! 418: * The reason we need this routine is the values are modulo some base ! 419: * hence a simple test for greater or less than is not sufficient. ! 420: */ ! 421: ! 422: bool ! 423: range_check (rear, value, front) ! 424: int rear, ! 425: value, ! 426: front; ! 427: { ! 428: register bool result = FALSE; ! 429: ! 430: if (front > rear) ! 431: result = (rear <= value) && (value <= front); ! 432: else ! 433: result = (rear <= value) || (value <= front); ! 434: ! 435: return (result); ! 436: } ! 437: ! 438: /* ! 439: * This routine handles all the frame reject conditions which can ! 440: * arise as a result of secondary processing. The frame reject ! 441: * condition Y (frame length error) are handled elsewhere. ! 442: */ ! 443: ! 444: static ! 445: frame_reject (hdp, rejectcode, frame) ! 446: struct hdcb *hdp; ! 447: struct Hdlc_iframe *frame; ! 448: { ! 449: register struct Frmr_frame *frmr = &hd_frmr; ! 450: ! 451: frmr -> frmr_control = ((struct Hdlc_frame *) frame) -> control; ! 452: ! 453: frmr -> frmr_ns = frame -> ns; ! 454: frmr -> frmr_f1_0 = 0; ! 455: frmr -> frmr_nr = frame -> nr; ! 456: frmr -> frmr_f2_0 = 0; ! 457: ! 458: frmr -> frmr_0000 = 0; ! 459: frmr -> frmr_w = frmr -> frmr_x = frmr -> frmr_y = ! 460: frmr -> frmr_z = 0; ! 461: switch (rejectcode) { ! 462: case Z: ! 463: frmr -> frmr_z = 1;/* invalid N(R). */ ! 464: break; ! 465: ! 466: case Y: ! 467: frmr -> frmr_y = 1;/* iframe length error. */ ! 468: break; ! 469: ! 470: case X: ! 471: frmr -> frmr_x = 1;/* invalid information field. */ ! 472: frmr -> frmr_w = 1; ! 473: break; ! 474: ! 475: case W: ! 476: frmr -> frmr_w = 1;/* invalid N(S). */ ! 477: } ! 478: ! 479: hd_writeinternal (hdp, FRMR, POLLOFF); ! 480: ! 481: hdp->hd_state = WAIT_SABM; ! 482: SET_TIMER (hdp); ! 483: } ! 484: ! 485: /* ! 486: * This procedure is invoked when ever we receive a supervisor ! 487: * frame such as RR, RNR and REJ. All processing for these ! 488: * frames is done here. ! 489: */ ! 490: ! 491: process_sframe (hdp, frame, frametype) ! 492: register struct hdcb *hdp; ! 493: register struct Hdlc_sframe *frame; ! 494: int frametype; ! 495: { ! 496: register int nr = frame -> nr, pf = frame -> pf, pollbit = 0; ! 497: ! 498: if (valid_nr (hdp, nr, pf) == TRUE) { ! 499: switch (frametype) { ! 500: case RR: ! 501: hdp->hd_condition &= ~REMOTE_RNR_CONDITION; ! 502: break; ! 503: ! 504: case RNR: ! 505: hdp->hd_condition |= REMOTE_RNR_CONDITION; ! 506: hdp->hd_retxcnt = 0; ! 507: break; ! 508: ! 509: case REJ: ! 510: hdp->hd_condition &= ~REMOTE_RNR_CONDITION; ! 511: rej_routine (hdp, nr); ! 512: } ! 513: ! 514: if (pf == 1) { ! 515: hdp->hd_retxcnt = 0; ! 516: hdp->hd_condition &= ~TIMER_RECOVERY_CONDITION; ! 517: ! 518: if (frametype == RR && hdp->hd_lastrxnr == hdp->hd_vs ! 519: && hdp->hd_timer == 0 && hdp->hd_txq.head == 0) ! 520: hd_writeinternal(hdp, RR, pf); ! 521: else ! 522: /* If any iframes have been queued because of the ! 523: timer condition, transmit then now. */ ! 524: if (hdp->hd_condition & REMOTE_RNR_CONDITION) { ! 525: /* Remote is busy or timer condition, so only ! 526: send one. */ ! 527: if (hdp->hd_vs != hdp->hd_retxqi) ! 528: hd_send_iframe (hdp, hdp->hd_retxq[hdp->hd_vs], pollbit); ! 529: } ! 530: else /* Flush the retransmit list first. */ ! 531: while (hdp->hd_vs != hdp->hd_retxqi) ! 532: hd_send_iframe (hdp, hdp->hd_retxq[hdp->hd_vs], POLLOFF); ! 533: } ! 534: ! 535: hd_start (hdp); ! 536: } else ! 537: frame_reject (hdp, Z, (struct Hdlc_iframe *)frame); /* Invalid N(R). */ ! 538: } ! 539: ! 540: /* ! 541: * This routine tests the validity of the N(R) which we have received. ! 542: * If it is ok, then all the iframes which it acknowledges (if any) ! 543: * will be freed. ! 544: */ ! 545: ! 546: bool ! 547: valid_nr (hdp, nr, finalbit) ! 548: register struct hdcb *hdp; ! 549: register int finalbit; ! 550: { ! 551: /* Make sure it really does acknowledge something. */ ! 552: if (hdp->hd_lastrxnr == nr) ! 553: return (TRUE); ! 554: ! 555: /* ! 556: * This section validates the frame's N(R) value. It's N(R) value ! 557: * must be in syncronization with our V(S) value and our "last ! 558: * received nr" variable. If it is correct then we are able to send ! 559: * more IFRAME's, else frame reject condition is entered. ! 560: */ ! 561: ! 562: if (range_check (hdp->hd_lastrxnr, nr, hdp->hd_vs) == FALSE) { ! 563: if ((hdp->hd_condition & TIMER_RECOVERY_CONDITION) && ! 564: range_check (hdp->hd_vs, nr, hdp->hd_xx) == TRUE) ! 565: hdp->hd_vs = nr; ! 566: ! 567: else { ! 568: hdp->hd_invalid_nr++; ! 569: return (FALSE); ! 570: } ! 571: } ! 572: ! 573: /* ! 574: * If we get to here, we do have a valid frame but it might be out ! 575: * of sequence. However, we should still accept the receive state ! 576: * number N(R) since it has already passed our previous test and it ! 577: * does acknowledge frames which we are sending. ! 578: */ ! 579: ! 580: KILL_TIMER (hdp); ! 581: free_iframes (hdp, &nr, finalbit);/* Free all acknowledged iframes */ ! 582: if (nr != hdp->hd_vs) ! 583: SET_TIMER (hdp); ! 584: ! 585: return (TRUE); ! 586: } ! 587: ! 588: /* ! 589: * This routine determines how many iframes need to be retransmitted. ! 590: * It then resets the Send State Variable V(S) to accomplish this. ! 591: */ ! 592: ! 593: static ! 594: rej_routine (hdp, rejnr) ! 595: register struct hdcb *hdp; ! 596: register int rejnr; ! 597: { ! 598: register int anchor; ! 599: ! 600: /* ! 601: * Flush the output queue. Any iframes queued for ! 602: * transmission will be out of sequence. ! 603: */ ! 604: ! 605: hd_flush (hdp->hd_ifp); ! 606: ! 607: /* ! 608: * Determine how many frames should be re-transmitted. In the case ! 609: * of a normal REJ this should be 1 to K. In the case of a timer ! 610: * recovery REJ (ie. a REJ with the Final Bit on) this could be 0. ! 611: */ ! 612: ! 613: anchor = hdp->hd_vs; ! 614: if (hdp->hd_condition & TIMER_RECOVERY_CONDITION) ! 615: anchor = hdp->hd_xx; ! 616: ! 617: anchor = (anchor - rejnr + 8) % MODULUS; ! 618: ! 619: if (anchor > 0) { ! 620: ! 621: /* There is at least one iframe to retransmit. */ ! 622: KILL_TIMER (hdp); ! 623: hdp->hd_vs = rejnr; ! 624: ! 625: while (hdp->hd_vs != hdp->hd_retxqi) ! 626: hd_send_iframe (hdp, hdp->hd_retxq[hdp->hd_vs], POLLOFF); ! 627: ! 628: } ! 629: hd_start (hdp); ! 630: } ! 631: ! 632: /* ! 633: * This routine frees iframes from the retransmit queue. It is called ! 634: * when a previously written iframe is acknowledged. ! 635: */ ! 636: ! 637: static ! 638: free_iframes (hdp, nr, finalbit) ! 639: register struct hdcb *hdp; ! 640: int *nr; ! 641: register int finalbit; ! 642: ! 643: { ! 644: register int i, k; ! 645: ! 646: /* ! 647: * We need to do the following because of a funny quirk in the ! 648: * protocol. This case occures when in Timer recovery condition ! 649: * we get a N(R) which acknowledges all the outstanding iframes ! 650: * but with the Final Bit off. In this case we need to save the last ! 651: * iframe for possible retransmission even though it has already been ! 652: * acknowledged! ! 653: */ ! 654: ! 655: if ((hdp->hd_condition & TIMER_RECOVERY_CONDITION) && *nr == hdp->hd_xx && finalbit == 0) { ! 656: *nr = (*nr - 1 + 8) % MODULUS; ! 657: /* printf ("QUIRK\n"); */ ! 658: } ! 659: ! 660: k = (*nr - hdp->hd_lastrxnr + 8) % MODULUS; ! 661: ! 662: /* Loop here freeing all acknowledged iframes. */ ! 663: for (i = 0; i < k; ++i) { ! 664: m_freem (hdp->hd_retxq[hdp->hd_lastrxnr]); ! 665: hdp->hd_retxq[hdp->hd_lastrxnr] = 0; ! 666: hdp->hd_lastrxnr = (hdp->hd_lastrxnr + 1) % MODULUS; ! 667: } ! 668: ! 669: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.