home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / sys / netccitt / hd_input.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-05-29  |  17.1 KB  |  670 lines

  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. }
  670.