The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/netccitt/hd_input.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: ff4b370e2bde3802c053d888e9fec29d


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.