home *** CD-ROM | disk | FTP | other *** search
/ HAM Radio 3 / hamradioversion3.0examsandprograms1992.iso / misc / 9q920411 / nr4.c < prev    next >
C/C++ Source or Header  |  1990-12-09  |  21KB  |  746 lines

  1. /* net/rom level 4 (transport) protocol implementation
  2.  * Copyright 1989 by Daniel M. Frank, W9NK.  Permission granted for
  3.  * non-commercial distribution only.
  4.  * Ported to NOS by SM0RGV, 890525.
  5.  */
  6.  
  7. #include <stdio.h>
  8. #include "global.h"
  9. #include "mbuf.h"
  10. #include "timer.h"
  11. #include "ax25.h"
  12. #include "lapb.h"
  13. #include "netrom.h"
  14. #include "nr4.h"
  15. #include <ctype.h>
  16.  
  17. #undef NR4DEBUG
  18.  
  19. /* Globals: */
  20.  
  21. /* The circuit table */
  22.  
  23. struct nr4circp Nr4circuits[NR4MAXCIRC];
  24.  
  25. /* Various limits */
  26.  
  27. unsigned short Nr4window = 4;        /* Max window to negotiate */
  28. unsigned short Nr4retries = 10;    /* Max retries */
  29. unsigned short Nr4qlimit = 2048;    /* Max bytes on receive queue */
  30.  
  31. /* Timers */
  32.  
  33. int32 Nr4irtt = 15000;            /* Initial round trip time */
  34. int32 Nr4acktime = 3000;        /* ACK delay timer */
  35. int32 Nr4choketime = 180000;        /* CHOKEd state timeout */
  36.  
  37. static void nr4ackours __ARGS((struct nr4cb *, unsigned, int));
  38. static void nr4choke __ARGS((struct nr4cb *));
  39. static void nr4gotnak __ARGS((struct nr4cb *, unsigned));
  40. static void nr4rframe __ARGS((struct nr4cb *, unsigned, struct mbuf *));
  41.  
  42. /* This function is called when a net/rom layer four frame */
  43. /* is discovered inside a datagram addressed to us */
  44.  
  45. void
  46. nr4input(hdr,bp)
  47. struct nr4hdr *hdr;
  48. struct mbuf *bp;
  49. {
  50.     struct nr4hdr rhdr;
  51.     struct nr4cb *cb, *cb2;
  52.     int op;
  53.     unsigned window;
  54.     int acceptc;        /* indicates that connection should be accepted */
  55.     int newconn;        /* indicates that this is a new incoming */
  56.                         /* connection.  You'll see. */
  57.     int gotchoke;        /* The choke flag was set in this packet */        
  58.     int i;
  59.     
  60.     op = hdr->opcode & NR4OPCODE;    /* Mask off flags */
  61.     
  62.     if(op == NR4OPCONRQ){            /* process connect request first */
  63.         acceptc = 1;
  64.         newconn = 0;
  65.  
  66.         /* These fields are sent regardless of success */
  67.         rhdr.yourindex = hdr->u.conreq.myindex;
  68.         rhdr.yourid = hdr->u.conreq.myid;
  69.  
  70.         /* Check to see if we have already received a connect */
  71.         /* request for this circuit. */
  72.         if((cb = match_n4circ(hdr->u.conreq.myindex,
  73.          hdr->u.conreq.myid,hdr->u.conreq.user,hdr->u.conreq.node))
  74.          == NULLNR4CB){    /* No existing circuit if NULL */
  75.  
  76.             /* Try to get a new circuit */
  77.             if((cb = new_n4circ()) == NULLNR4CB)
  78.                 acceptc = 0;
  79.             /* See if we have any listening sockets */
  80.             for(i = 0; i < NR4MAXCIRC; i++){
  81.                 if((cb2 = Nr4circuits[i].ccb) == NULLNR4CB)
  82.                 continue;/* not an open circuit */
  83.                 if(cb2->state == NR4STLISTEN)
  84.                     /* A listener was found */
  85.                     break;
  86.             }
  87.             if(i == NR4MAXCIRC){ /* We are refusing connects */
  88.                 acceptc = 0;
  89.                 free_n4circ(cb);
  90.             }
  91.             if(acceptc){
  92.                 /* Load the listeners settings */
  93.                 cb->clone = cb2->clone;
  94.                 cb->user = cb2->user;
  95.                 cb->t_upcall = cb2->t_upcall;
  96.                 cb->s_upcall = cb2->s_upcall;
  97.                 cb->r_upcall = cb2->r_upcall;
  98.                 ASSIGN(cb->local,cb2->local);
  99.  
  100.                 /* Window is set to min of the offered
  101.                  * and local windows
  102.                  */
  103.                 window = hdr->u.conreq.window > Nr4window ?
  104.                          Nr4window : hdr->u.conreq.window;
  105.  
  106.                 if(init_nr4window(cb, window) == -1){
  107.                     free_n4circ(cb);
  108.                     acceptc = 0;
  109.                 } else {
  110.                     /* Set up control block */
  111.                     cb->yournum = hdr->u.conreq.myindex;
  112.                     cb->yourid = hdr->u.conreq.myid;
  113.                     memcpy(cb->remote.user,
  114.                            hdr->u.conreq.user,AXALEN);
  115.                     memcpy(cb->remote.node,
  116.                            hdr->u.conreq.node,AXALEN);
  117.                     /* Default round trip time */
  118.                     cb->srtt = Nr4irtt;
  119.                     /* set up timers, window pointers */
  120.                     nr4defaults(cb);
  121.                     cb->state = NR4STDISC;
  122.                     newconn = 1;
  123.                 } /* End if window successfully allocated */
  124.             }    /* End if new circuit available */
  125.          } /* End if no existing circuit matching parameters */
  126.  
  127.         /* Now set up response */
  128.         if(!acceptc){
  129.             rhdr.opcode = NR4OPCONAK | NR4CHOKE;/* choke means reject */
  130.             rhdr.u.conack.myindex = 0;
  131.             rhdr.u.conack.myid = 0;
  132.             rhdr.u.conack.window = 0;
  133.         } else {
  134.             rhdr.opcode = NR4OPCONAK;
  135.             rhdr.u.conack.myindex = cb->mynum;
  136.             rhdr.u.conack.myid = cb->myid;
  137.             rhdr.u.conack.window = cb->window;
  138.         }
  139.         nr4sframe(hdr->u.conreq.node, &rhdr, NULLBUF);
  140.  
  141.         /* Why, you ask, do we wait until now for the state change
  142.          * upcall?  Well, it's like this:  if the state change triggers
  143.          * something like the mailbox to send its banner, the banner
  144.          * would have gone out *before* the conn ack if we'd done this
  145.          * in the code above.  This is what happens when you don't plan
  146.          * too well.  Learn from my mistakes :-)
  147.          */
  148.         if(newconn)
  149.             nr4state(cb, NR4STCON);/* connected (no 3-way handshake) */
  150.             
  151.         free_p(bp);
  152.         return;
  153.     } /* end connect request code */
  154.  
  155.     /* validate circuit number */
  156.     if((cb = get_n4circ(hdr->yourindex, hdr->yourid)) == NULLNR4CB){
  157.         free_p(bp);
  158.         return;
  159.     }
  160.  
  161.     /* Check for choke flag */
  162.     if(hdr->opcode & NR4CHOKE)
  163.         gotchoke = 1;
  164.     else
  165.         gotchoke = 0;
  166.     
  167.     /* Here's where the interesting stuff gets done */
  168.     switch(cb->state){
  169.     case NR4STCPEND:
  170.         switch(op){
  171.         case NR4OPCONAK:
  172.             /* Save the round trip time for later use */
  173.             i = dur_timer(&cb->tcd) - read_timer(&cb->tcd);
  174.             stop_timer(&cb->tcd);
  175.             if(gotchoke){        /* connect rejected */
  176.                 cb->dreason = NR4RREFUSED;
  177.                 nr4state(cb, NR4STDISC);
  178.                 break;
  179.             }
  180.             cb->yournum = hdr->u.conack.myindex;
  181.             cb->yourid = hdr->u.conack.myid;
  182.             window = hdr->u.conack.window > Nr4window ?
  183.                      Nr4window : hdr->u.conack.window;
  184.  
  185.             if(init_nr4window(cb, window) == -1){
  186.                 cb->dreason = NR4RRESET;
  187.                 nr4state(cb, NR4STDISC);
  188.             } else {
  189.                 nr4defaults(cb);    /* set up timers, window pointers */
  190.                 
  191.                 if(cb->cdtries == 1)    /* No retries */
  192.                     /* Use measured rtt */
  193.                     cb->srtt = i;
  194.                 else
  195.                     /* else use default */
  196.                     cb->srtt = Nr4irtt;
  197.                     
  198.                 nr4state(cb, NR4STCON);
  199.                 nr4output(cb);        /* start sending anything on the txq */
  200.             }
  201.             break;
  202.         default:
  203.             /* We can't respond to anything else without
  204.              * Their ID and index
  205.              */
  206.               free_p(bp);
  207.             return;
  208.         }
  209.         break;
  210.     case NR4STCON:
  211.         switch(op){
  212.         case NR4OPDISRQ:
  213.             /* format reply packet */
  214.             rhdr.opcode = NR4OPDISAK;
  215.             rhdr.yourindex = cb->yournum;
  216.             rhdr.yourid = cb->yourid;
  217.             nr4sframe(cb->remote.node,&rhdr,NULLBUF);
  218.             cb->dreason = NR4RREMOTE;
  219.             nr4state(cb, NR4STDISC);
  220.             break;
  221.           case NR4OPINFO:
  222.             /* Do receive frame processing */
  223.               nr4rframe(cb, hdr->u.info.txseq, bp);
  224.  
  225.             /* Reset the choke flag if no longer choked.  Processing
  226.              * the ACK will kick things off again.
  227.              */
  228.             if(cb->choked && !gotchoke){
  229.                 stop_timer(&cb->tchoke);
  230.                 cb->choked = 0;
  231.             }
  232.                 
  233.             /* We delay processing the receive sequence number until
  234.              * now, because the ACK might pull more off the txq and send
  235.              * it, and we want the implied ACK in those frames to be right
  236.              *
  237.              * Only process NAKs if the choke flag is off.  It appears
  238.              * that NAKs should never be sent with choke on, by the way,
  239.              * but you never know, considering that there is no official
  240.              * standard for this protocol
  241.              */
  242.             if(hdr->opcode & NR4NAK && !gotchoke)
  243.                 nr4gotnak(cb, hdr->u.info.rxseq);
  244.  
  245.             /* We always do ACK processing, too, since the NAK of one
  246.              * packet may be the implied ACK of another.  The gotchoke
  247.              * flag is used to prevent sending any new frames, since
  248.              * we are just going to purge them next anyway if this is
  249.              * the first time we've seen the choke flag.  If we are
  250.              * already choked, this call will return immediately.
  251.              */
  252.             nr4ackours(cb, hdr->u.info.rxseq, gotchoke);
  253.  
  254.             /* If we haven't seen the choke flag before, purge the
  255.              * send window and set the timer and the flag.
  256.              */
  257.             if(!cb->choked && gotchoke)
  258.                 nr4choke(cb);
  259.             break;
  260.           case NR4OPACK:
  261.             if(cb->choked && !gotchoke){
  262.                 /* clear choke if appropriate */
  263.                 stop_timer(&cb->tchoke);
  264.                 cb->choked = 0;
  265.             }    
  266.               if(hdr->opcode & NR4NAK && !gotchoke)
  267.                 nr4gotnak(cb, hdr->u.ack.rxseq);    /* process NAKs */
  268.                 
  269.               nr4ackours(cb, hdr->u.ack.rxseq, gotchoke); /* and ACKs */
  270.  
  271.             if(!cb->choked && gotchoke)    /* First choke seen */
  272.                 nr4choke(cb);        /* Set choke status */
  273.  
  274.             break;
  275.         }
  276.         break;
  277.     case NR4STDPEND:
  278.         switch(op){
  279.         case NR4OPDISAK:
  280.               cb->dreason = NR4RNORMAL;
  281.             nr4state(cb, NR4STDISC);
  282.             break;
  283.         case NR4OPINFO:
  284.             /* We can still do receive frame processing until
  285.              * the disconnect acknowledge arrives, but we won't
  286.              * bother to process ACKs, since we've flushed our
  287.              * transmit buffers and queue already.
  288.              */
  289.               nr4rframe(cb, hdr->u.info.txseq, bp);
  290.             break;
  291.         }
  292.     }    /* End switch(state) */
  293. }
  294.  
  295.  
  296. /* Send a net/rom layer 4 frame.  bp should be NULLBUF unless the frame
  297.  * type is info.
  298.  */
  299. void
  300. nr4sframe(dest, hdr, bp)
  301. char *dest;
  302. struct nr4hdr *hdr;
  303. struct mbuf *bp;
  304. {
  305.     struct mbuf *n4b;
  306.  
  307.     if((n4b = htonnr4(hdr)) == NULLBUF){
  308.         free_p(bp);
  309.         return;
  310.     } else {
  311.         append(&n4b, bp);
  312.         nr3output(dest, n4b);
  313.     }
  314. }
  315.  
  316. /* Receive frame processing */
  317. static void
  318. nr4rframe(cb, rxseq, bp)
  319. struct nr4cb *cb;
  320. unsigned rxseq;
  321. struct mbuf *bp;
  322. {
  323.     struct nr4hdr rhdr;
  324.     unsigned window = cb->window;
  325.     unsigned rxbuf = rxseq % window;
  326.     unsigned newdata = 0;        /* whether to upcall */
  327.  
  328. #ifdef NR4DEBUG
  329.     printf("Processing received info\n");
  330. #endif
  331.  
  332.     /* If we're choked, just reset the ACK timer to blast out
  333.      * another CHOKE indication after the ackdelay
  334.      */
  335.     if(cb->qfull){
  336.         start_timer(&cb->tack);
  337.         return;
  338.     }
  339.     
  340.     /* If frame is out of sequence, it is either due to a lost frame
  341.      * or a retransmission of one seen earlier.  We do not want to NAK
  342.      * the latter, as the far end would see this as a requirement to
  343.      * retransmit the expected frame, which is probably already in the
  344.      * pipeline.  This in turn would cause another out-of-sequence
  345.      * condition, another NAK, and the process would repeat indefinitely.
  346.      * Therefore, if the frame is out-of-sequence, but within the last
  347.      * 'n' frames by sequence number ('n' being the window size), just
  348.      * accept it and discard it.  Else, NAK it if we haven't already.
  349.      *    (Modified by Rob Stampfli, kd8wk, 9 Jan 1990)
  350.      */
  351.     if(rxseq != cb->rxpected && !cb->naksent){
  352. #ifdef NR4DEBUG
  353.         printf("Frame out of sequence -- expected %u, got %u.\n",
  354.                cb->rxpected, rxseq);
  355. #endif                
  356.         if(nr4between(cb->rxpected,
  357.            (rxseq + window) & NR4SEQMASK, cb->rxpastwin))
  358.             /* just a repeat of old frame -- queue ack for
  359.              * expected frame
  360.              */
  361.             start_timer(&cb->tack);
  362.         else {            /* really bogus -- a NAKable frame */
  363.             rhdr.opcode = NR4OPACK | NR4NAK;
  364.             rhdr.yourindex = cb->yournum;
  365.             rhdr.yourid = cb->yourid;
  366.             rhdr.u.ack.rxseq = cb->rxpected;
  367.             nr4sframe(cb->remote.node,&rhdr,NULLBUF);
  368.         
  369.             /* Now make sure we don't send any more of these until
  370.              * we see some good data.  Otherwise full window
  371.              * retransmissions would result in a flurry of NAKs
  372.              */
  373.         
  374.             cb->naksent = 1;
  375.         }
  376.     }
  377.             
  378.     /* If this is a new frame, within the window, buffer it,
  379.      * then see what we can deliver
  380.      */
  381.     if(nr4between(cb->rxpected,rxseq,cb->rxpastwin)
  382.         && !cb->rxbufs[rxbuf].occupied){
  383. #ifdef NR4DEBUG
  384.         printf("Frame within window\n");
  385. #endif
  386.         cb->rxbufs[rxbuf].occupied = 1;
  387.         cb->rxbufs[rxbuf].data = bp;
  388.                 
  389.         for(rxbuf = cb->rxpected % window; cb->rxbufs[rxbuf].occupied;
  390.              rxbuf = cb->rxpected % window){
  391. #ifdef NR4DEBUG
  392.             printf("Removing frame from buffer %d\n", rxbuf);
  393. #endif
  394.             newdata = 1;
  395.             cb->rxbufs[rxbuf].occupied = 0;
  396.             append(&cb->rxq,cb->rxbufs[rxbuf].data);
  397.             cb->rxbufs[rxbuf].data = NULLBUF;
  398.             cb->rxpected = (cb->rxpected + 1) & NR4SEQMASK;
  399.             cb->rxpastwin = (cb->rxpastwin + 1) & NR4SEQMASK;
  400.         }
  401.         if(newdata){
  402.             cb->naksent = 0;    /* OK to send NAKs again */
  403.             if(cb->r_upcall != NULLVFP)
  404.                 (*cb->r_upcall)(cb,len_p(cb->rxq));
  405.  
  406.             /* Now that our upcall has had a shot at the queue, */
  407.             /* see if it's past the queue length limit.  If so, */
  408.             /* go into choked mode (i.e. flow controlled). */
  409.  
  410.             if(len_p(cb->rxq) > Nr4qlimit){
  411.                 cb->qfull = 1;
  412.                 nr4ackit((void *)cb);    /* Tell `em right away */
  413.             } else
  414.                 start_timer(&cb->tack);
  415.         }
  416.     } else     /* It's out of the window or we've seen it already */
  417.         free_p(bp);
  418. }
  419.  
  420.  
  421. /* Send the transmit buffer whose sequence number is seq */
  422. void
  423. nr4sbuf(cb, seq)
  424. struct nr4cb *cb;
  425. unsigned seq;
  426. {
  427.     struct nr4hdr hdr;
  428.     struct mbuf *bufbp, *bp;
  429.     unsigned bufnum = seq % cb->window;
  430.     struct timer *t;
  431.     
  432.     /* sanity check */
  433.     if(bufnum >= cb->window){
  434. #ifdef NRDEBUG
  435.         printf("sbuf: buffer number %u beyond window\n",bufnum);
  436. #endif
  437.         return;
  438.     }
  439.  
  440.     /* Stop the ACK timer, since our sending of the frame is
  441.      * an implied ACK.
  442.      */
  443.     stop_timer(&cb->tack);
  444.     
  445.     /* Duplicate the mbuf, since we have to keep it around
  446.      * until it is acknowledged
  447.      */
  448.     bufbp = cb->txbufs[bufnum].data;
  449.  
  450.     /* Notice that we use copy_p instead of dup_p.  This is because
  451.      * a frame can still be sitting on the AX.25 send queue when it
  452.      * get acknowledged, and we don't want to deallocate its data
  453.      * before it gets sent!
  454.      */
  455.     if((bp = copy_p(bufbp, len_p(bufbp))) == NULLBUF){
  456.         free_mbuf(bp);
  457.         return;
  458.     }
  459.  
  460.     /* Prepare the header */
  461.     if(cb->qfull)                /* are we choked? */
  462.         hdr.opcode = NR4OPINFO | NR4CHOKE;
  463.     else
  464.         hdr.opcode = NR4OPINFO;
  465.     hdr.yourindex = cb->yournum;
  466.     hdr.yourid = cb->yourid;
  467.     hdr.u.info.txseq = (unsigned char)(seq & NR4SEQMASK);
  468.     hdr.u.info.rxseq = cb->rxpected;
  469.     
  470.     /* Send the frame, then set and start the timer */
  471.     nr4sframe(cb->remote.node, &hdr, bp);
  472.  
  473.     t = &cb->txbufs[bufnum].tretry;
  474.     set_timer(t, (1 << cb->blevel) * (4 * cb->mdev + cb->srtt));
  475.     start_timer(t);
  476. }
  477.  
  478. /* Check to see if any of our frames have been ACKed */
  479.  
  480. static void
  481. nr4ackours(cb, seq, gotchoke)
  482. struct nr4cb *cb;
  483. unsigned seq;
  484. int gotchoke;    /* The choke flag is set in the received frame */
  485. {
  486.     unsigned txbuf;
  487.     struct timer *t;
  488.     
  489.     /* If we are choked, there is nothing in the send window
  490.      * by definition, so we can just return.
  491.      */
  492.     if(cb->choked)
  493.         return;
  494.         
  495.     /* Adjust seq to point to the frame being ACK'd, not the one
  496.      * beyond it, which is how it arrives.
  497.      */
  498.     seq = (seq - 1) & NR4SEQMASK;
  499.  
  500.     /* Free up all the ack'd frames, and adjust the round trip
  501.      * timing stuff
  502.      */
  503.     while (nr4between(cb->ackxpected, seq, cb->nextosend)){
  504. #ifdef NR4DEBUG
  505.         printf("Sequence # %u acknowledged\n", seq);
  506. #endif
  507.         cb->nbuffered--;
  508.         txbuf = cb->ackxpected % cb->window;
  509.         free_mbuf(cb->txbufs[txbuf].data);
  510.         cb->txbufs[txbuf].data = NULLBUF;
  511.         cb->ackxpected = (cb->ackxpected + 1) & NR4SEQMASK;
  512.  
  513.         /* Round trip time estimation, cribbed from TCP */
  514.         if(cb->txbufs[txbuf].retries == 0){
  515.             /* We only sent this one once */
  516.             int32 rtt;
  517.             int32 abserr;
  518.  
  519.             t = &cb->txbufs[txbuf].tretry;
  520.             /* get our rtt in msec */
  521.             rtt = dur_timer(t) - read_timer(t);
  522.             abserr = (rtt > cb->srtt) ? rtt - cb->srtt : cb->srtt - rtt;
  523.             cb->srtt = (cb->srtt * 7 + rtt) >> 3;
  524.             cb->mdev = (cb->mdev * 3 + abserr) >> 2;
  525.  
  526.             /* Reset the backoff level */
  527.             cb->blevel = 0;
  528.         }
  529.         stop_timer(&cb->txbufs[txbuf].tretry);
  530.     }    
  531.     /* Now we recalculate tmax, the maximum number of retries for
  532.      * any frame in the window.  tmax is used as a baseline to
  533.      * determine when the window has reached a new high in retries.
  534.      * We don't want to increment blevel for every frame that times
  535.      * out, since that would lead to us backing off too fast when
  536.      * all the frame timers expired at around the same time.
  537.      */
  538.     cb->txmax = 0;
  539.     
  540.     for(seq = cb->ackxpected;
  541.          nr4between(cb->ackxpected, seq, cb->nextosend);
  542.          seq = (seq + 1) & NR4SEQMASK)
  543.         if(cb->txbufs[seq % cb->window].retries > cb->txmax)
  544.             cb->txmax = cb->txbufs[seq % cb->window].retries;
  545.  
  546.     /* This is kind of a hack.  This function is called under
  547.      * three different conditions:  either we are choked, in
  548.      * which case we return immediately, or we are not choked,
  549.      * in which case we proceed normally to keep the send
  550.      * window full, or we have seen the choke flag for the first
  551.      * time.  In the last case, gotchoke is true while cb->choked
  552.      * is false.  We want to process any acknowledgments of existing
  553.      * frames in the send window before we purge it, while at the
  554.      * same time we don't want to take anything else off the txq
  555.      * or send it out.  So, in the third case we listed, we return
  556.      * now since we've processed the ACK.
  557.      */
  558.     
  559.     if(gotchoke)
  560.         return;
  561.         
  562.     nr4output(cb);            /* yank stuff off txq and send it */
  563.  
  564.     /* At this point, either the send window is full, or
  565.      * nr4output() didn't find enough on the txq to fill it.
  566.      * If the window is not full, then the txq must be empty,
  567.      * and we'll make a tx upcall
  568.      */
  569.     if(cb->nbuffered < cb->window && cb->t_upcall != NULLVFP)
  570.         (*cb->t_upcall)(cb, (int16)((cb->window - cb->nbuffered) * NR4MAXINFO));
  571.  
  572. }
  573.  
  574.  
  575. /* If the send window is open and there are frames on the txq,
  576.  * move as many as possible to the transmit buffers and send them.
  577.  * Return the number of frames sent.
  578.  */
  579. int
  580. nr4output(cb)
  581. struct nr4cb *cb;
  582. {
  583.     int numq, i;
  584.     struct mbuf *bp;
  585.     struct nr4txbuf *tp;
  586.  
  587.     /* Are we in the proper state? */
  588.     if(cb->state != NR4STCON || cb->choked)
  589.         return 0;        /* No sending if not connected */
  590.                     /* or if choked */
  591.         
  592.     /* See if the window is open */
  593.     if(cb->nbuffered >= cb->window)
  594.         return 0;
  595.  
  596.     numq = len_q(cb->txq);
  597.     
  598. #ifdef NR4DEBUG
  599.     printf("nr4output: %d packets on txq\n", numq);
  600. #endif
  601.     
  602.     for(i = 0; i < numq; i++){
  603.         bp = dequeue(&cb->txq);
  604. #ifdef NR4DEBUG
  605.         if(len_p(bp) > NR4MAXINFO){    /* should be checked higher up */
  606.             printf("Upper layers queued too big a buffer\n");
  607.             continue;
  608.         }
  609. #endif
  610.         /* Set up and send buffer */
  611.         tp = &cb->txbufs[cb->nextosend % cb->window];
  612.         tp->retries = 0;
  613.         tp->data = bp;
  614.         nr4sbuf(cb, cb->nextosend);
  615.  
  616.         /* Update window and buffered count */
  617.         cb->nextosend = (cb->nextosend + 1) & NR4SEQMASK;
  618.         if(++cb->nbuffered >= cb->window)
  619.             break;
  620.     }
  621.     return i;        
  622. }
  623.  
  624. void
  625. nr4state(cb, newstate)
  626. struct nr4cb *cb;
  627. int newstate;
  628. {
  629.     int i;
  630.     int oldstate = cb->state;
  631.     
  632.     cb->state = newstate;
  633.  
  634.     switch(cb->state){
  635.     case NR4STDPEND:
  636.         stop_timer(&cb->tchoke);
  637.  
  638.         /* When we request a disconnect, we lose the contents of
  639.          * our transmit queue and buffers, but we retain our ability
  640.          * to receive any packets in transit until a disconnect
  641.          * acknowledge arrives
  642.          */
  643.         free_q(&cb->txq);
  644.         
  645.         for(i = 0; i < cb->window; i++){
  646.             free_mbuf(cb->txbufs[i].data);
  647.             cb->txbufs[i].data = NULLBUF;
  648.             stop_timer(&cb->txbufs[i].tretry);
  649.         }
  650.         
  651.         /* Tidy up stats: roll the top window pointer back
  652.          * and reset nbuffered to reflect this.  Not really
  653.          * necessary, but leads to a bit more truth telling
  654.          * in the status displays.
  655.          */
  656.         cb->nextosend = cb->ackxpected;
  657.         cb->nbuffered = 0;
  658.         break;
  659.       case NR4STDISC:
  660.         stop_timer(&cb->tchoke);
  661.         stop_timer(&cb->tack);
  662.         stop_timer(&cb->tcd);
  663.  
  664.         /* We don't clear the rxq, since the state change upcall
  665.          * may pull something off of it at the last minute.
  666.          */
  667.         free_q(&cb->txq);
  668.  
  669.         /* The following loop will only be executed if the
  670.          * window was set, since when the control block is
  671.          * calloc'd the window field gets a 0 in it.  This
  672.          * protects us from dereferencing an unallocated
  673.          * window buffer pointer
  674.          */
  675.         for(i = 0; i < cb->window; i++){
  676.             free_mbuf(cb->rxbufs[i].data);
  677.             cb->rxbufs[i].data = NULLBUF;
  678.             free_mbuf(cb->txbufs[i].data);
  679.             cb->txbufs[i].data = NULLBUF;
  680.             stop_timer(&cb->txbufs[i].tretry);
  681.         }
  682.         break;
  683.     }
  684.  
  685.     if(oldstate != newstate && cb->s_upcall != NULLVFP)
  686.         (*cb->s_upcall)(cb, oldstate, newstate);
  687.  
  688.     /* We take responsibility for deleting the circuit
  689.      * descriptor.  Don't do this anywhere else!
  690.      */
  691.     if(newstate == NR4STDISC)
  692.         free_n4circ(cb);
  693. }
  694.  
  695. /* Process NAKs.  seq indicates the next frame expected by the
  696.  * NAK'ing station.
  697.  */
  698.  
  699. static void
  700. nr4gotnak(cb, seq)
  701. struct nr4cb *cb;
  702. unsigned seq;
  703. {
  704.     if(nr4between(cb->ackxpected, seq, cb->nextosend))
  705.         nr4sbuf(cb, seq);
  706. }
  707.  
  708.  
  709. /* This is called when we first get a CHOKE indication from the
  710.  * remote.  It purges the send window and sets the choke timer.
  711.  */
  712.  
  713. static void
  714. nr4choke(cb)
  715. struct nr4cb *cb;
  716. {
  717.     unsigned seq;
  718.     struct mbuf *q, *bp;
  719.     struct nr4txbuf *t;
  720.  
  721.     q = cb->txq;
  722.  
  723.     /* We purge the send window, returning the buffers to the
  724.      * txq in the proper order.
  725.      */
  726.     for(seq = (cb->nextosend - 1) & NR4SEQMASK;
  727.          nr4between(cb->ackxpected, seq, cb->nextosend);
  728.          seq = (seq - 1) & NR4SEQMASK){
  729.  
  730.         t = &cb->txbufs[seq % cb->window];
  731.         stop_timer(&t->tretry);
  732.         bp = t->data;
  733.         t->data = NULLBUF;
  734.         enqueue(&bp, q);    /* prepend this packet to the queue */
  735.         q = bp;
  736.      }
  737.  
  738.     cb->nextosend = cb->ackxpected;    /* close the window */
  739.     cb->nbuffered = 0;        /* nothing in the window */
  740.     cb->txq = q;            /* Replace the txq with the one that has */
  741.                     /* the purged packets prepended */
  742.     cb->choked = 1;        /* Set the choked flag */
  743.  
  744.     start_timer(&cb->tchoke);
  745. }
  746.