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