?? nr4.c
字號:
}
/* If this is a new frame, within the window, buffer it,
* then see what we can deliver
*/
if(nr4between(cb->rxpected,rxseq,cb->rxpastwin)
&& !cb->rxbufs[rxbuf].occupied){
#ifdef NR4DEBUG
printf("Frame within window\n");
#endif
cb->rxbufs[rxbuf].occupied = 1;
cb->rxbufs[rxbuf].data = *bpp;
*bpp = NULL;
for(rxbuf = cb->rxpected % window; cb->rxbufs[rxbuf].occupied;
rxbuf = cb->rxpected % window){
#ifdef NR4DEBUG
printf("Removing frame from buffer %d\n", rxbuf);
#endif
newdata = 1;
cb->rxbufs[rxbuf].occupied = 0;
append(&cb->rxq,&cb->rxbufs[rxbuf].data);
cb->rxbufs[rxbuf].data = NULL;
cb->rxpected = (cb->rxpected + 1) & NR4SEQMASK;
cb->rxpastwin = (cb->rxpastwin + 1) & NR4SEQMASK;
}
if(newdata){
cb->naksent = 0; /* OK to send NAKs again */
if(cb->r_upcall != NULL)
(*cb->r_upcall)(cb,len_p(cb->rxq));
/* Now that our upcall has had a shot at the queue, */
/* see if it's past the queue length limit. If so, */
/* go into choked mode (i.e. flow controlled). */
if(len_p(cb->rxq) > Nr4qlimit){
cb->qfull = 1;
nr4ackit((void *)cb); /* Tell `em right away */
} else
start_timer(&cb->tack);
}
} else /* It's out of the window or we've seen it already */
free_p(bpp);
}
/* Send the transmit buffer whose sequence number is seq */
void
nr4sbuf(cb, seq)
struct nr4cb *cb;
unsigned seq;
{
struct nr4hdr hdr;
struct mbuf *bufbp, *bp;
unsigned bufnum = seq % cb->window;
struct timer *t;
/* sanity check */
if(bufnum >= cb->window){
#ifdef NRDEBUG
printf("sbuf: buffer number %u beyond window\n",bufnum);
#endif
return;
}
/* Stop the ACK timer, since our sending of the frame is
* an implied ACK.
*/
stop_timer(&cb->tack);
/* Duplicate the mbuf, since we have to keep it around
* until it is acknowledged
*/
bufbp = cb->txbufs[bufnum].data;
/* Notice that we use copy_p instead of dup_p. This is because
* a frame can still be sitting on the AX.25 send queue when it
* get acknowledged, and we don't want to deallocate its data
* before it gets sent!
*/
if((bp = copy_p(bufbp, len_p(bufbp))) == NULL){
free_mbuf(&bp);
return;
}
/* Prepare the header */
if(cb->qfull) /* are we choked? */
hdr.opcode = NR4OPINFO | NR4CHOKE;
else
hdr.opcode = NR4OPINFO;
hdr.yourindex = cb->yournum;
hdr.yourid = cb->yourid;
hdr.u.info.txseq = (unsigned char)(seq & NR4SEQMASK);
hdr.u.info.rxseq = cb->rxpected;
/* Send the frame, then set and start the timer */
nr4sframe(cb->remote.node, &hdr, &bp);
t = &cb->txbufs[bufnum].tretry;
set_timer(t, (1 << cb->blevel) * (4 * cb->mdev + cb->srtt));
start_timer(t);
}
/* Check to see if any of our frames have been ACKed */
static void
nr4ackours(cb, seq, gotchoke)
struct nr4cb *cb;
unsigned seq;
int gotchoke; /* The choke flag is set in the received frame */
{
unsigned txbuf;
struct timer *t;
/* If we are choked, there is nothing in the send window
* by definition, so we can just return.
*/
if(cb->choked)
return;
/* Adjust seq to point to the frame being ACK'd, not the one
* beyond it, which is how it arrives.
*/
seq = (seq - 1) & NR4SEQMASK;
/* Free up all the ack'd frames, and adjust the round trip
* timing stuff
*/
while (nr4between(cb->ackxpected, seq, cb->nextosend)){
#ifdef NR4DEBUG
printf("Sequence # %u acknowledged\n", seq);
#endif
cb->nbuffered--;
txbuf = cb->ackxpected % cb->window;
free_mbuf(&cb->txbufs[txbuf].data);
cb->txbufs[txbuf].data = NULL;
cb->ackxpected = (cb->ackxpected + 1) & NR4SEQMASK;
/* Round trip time estimation, cribbed from TCP */
if(cb->txbufs[txbuf].retries == 0){
/* We only sent this one once */
int32 rtt;
int32 abserr;
t = &cb->txbufs[txbuf].tretry;
/* get our rtt in msec */
rtt = dur_timer(t) - read_timer(t);
abserr = (rtt > cb->srtt) ? rtt - cb->srtt : cb->srtt - rtt;
cb->srtt = (cb->srtt * 7 + rtt) >> 3;
cb->mdev = (cb->mdev * 3 + abserr) >> 2;
/* Reset the backoff level */
cb->blevel = 0;
}
stop_timer(&cb->txbufs[txbuf].tretry);
}
/* Now we recalculate tmax, the maximum number of retries for
* any frame in the window. tmax is used as a baseline to
* determine when the window has reached a new high in retries.
* We don't want to increment blevel for every frame that times
* out, since that would lead to us backing off too fast when
* all the frame timers expired at around the same time.
*/
cb->txmax = 0;
for(seq = cb->ackxpected;
nr4between(cb->ackxpected, seq, cb->nextosend);
seq = (seq + 1) & NR4SEQMASK)
if(cb->txbufs[seq % cb->window].retries > cb->txmax)
cb->txmax = cb->txbufs[seq % cb->window].retries;
/* This is kind of a hack. This function is called under
* three different conditions: either we are choked, in
* which case we return immediately, or we are not choked,
* in which case we proceed normally to keep the send
* window full, or we have seen the choke flag for the first
* time. In the last case, gotchoke is true while cb->choked
* is false. We want to process any acknowledgments of existing
* frames in the send window before we purge it, while at the
* same time we don't want to take anything else off the txq
* or send it out. So, in the third case we listed, we return
* now since we've processed the ACK.
*/
if(gotchoke)
return;
nr4output(cb); /* yank stuff off txq and send it */
/* At this point, either the send window is full, or
* nr4output() didn't find enough on the txq to fill it.
* If the window is not full, then the txq must be empty,
* and we'll make a tx upcall
*/
if(cb->nbuffered < cb->window && cb->t_upcall != NULL)
(*cb->t_upcall)(cb, (uint16)((cb->window - cb->nbuffered) * NR4MAXINFO));
}
/* If the send window is open and there are frames on the txq,
* move as many as possible to the transmit buffers and send them.
* Return the number of frames sent.
*/
int
nr4output(cb)
struct nr4cb *cb;
{
int numq, i;
struct mbuf *bp;
struct nr4txbuf *tp;
/* Are we in the proper state? */
if(cb->state != NR4STCON || cb->choked)
return 0; /* No sending if not connected */
/* or if choked */
/* See if the window is open */
if(cb->nbuffered >= cb->window)
return 0;
numq = len_q(cb->txq);
#ifdef NR4DEBUG
printf("nr4output: %d packets on txq\n", numq);
#endif
for(i = 0; i < numq; i++){
bp = dequeue(&cb->txq);
#ifdef NR4DEBUG
if(len_p(bp) > NR4MAXINFO){ /* should be checked higher up */
printf("Upper layers queued too big a buffer\n");
continue;
}
#endif
/* Set up and send buffer */
tp = &cb->txbufs[cb->nextosend % cb->window];
tp->retries = 0;
tp->data = bp;
nr4sbuf(cb, cb->nextosend);
/* Update window and buffered count */
cb->nextosend = (cb->nextosend + 1) & NR4SEQMASK;
if(++cb->nbuffered >= cb->window)
break;
}
return i;
}
void
nr4state(cb, newstate)
struct nr4cb *cb;
int newstate;
{
int i;
int oldstate = cb->state;
cb->state = newstate;
switch(cb->state){
case NR4STDPEND:
stop_timer(&cb->tchoke);
/* When we request a disconnect, we lose the contents of
* our transmit queue and buffers, but we retain our ability
* to receive any packets in transit until a disconnect
* acknowledge arrives
*/
free_q(&cb->txq);
for(i = 0; i < cb->window; i++){
free_mbuf(&cb->txbufs[i].data);
cb->txbufs[i].data = NULL;
stop_timer(&cb->txbufs[i].tretry);
}
/* Tidy up stats: roll the top window pointer back
* and reset nbuffered to reflect this. Not really
* necessary, but leads to a bit more truth telling
* in the status displays.
*/
cb->nextosend = cb->ackxpected;
cb->nbuffered = 0;
break;
case NR4STDISC:
stop_timer(&cb->tchoke);
stop_timer(&cb->tack);
stop_timer(&cb->tcd);
/* We don't clear the rxq, since the state change upcall
* may pull something off of it at the last minute.
*/
free_q(&cb->txq);
/* The following loop will only be executed if the
* window was set, since when the control block is
* calloc'd the window field gets a 0 in it. This
* protects us from dereferencing an unallocated
* window buffer pointer
*/
for(i = 0; i < cb->window; i++){
free_mbuf(&cb->rxbufs[i].data);
cb->rxbufs[i].data = NULL;
free_mbuf(&cb->txbufs[i].data);
cb->txbufs[i].data = NULL;
stop_timer(&cb->txbufs[i].tretry);
}
break;
}
if(oldstate != newstate && cb->s_upcall != NULL)
(*cb->s_upcall)(cb, oldstate, newstate);
/* We take responsibility for deleting the circuit
* descriptor. Don't do this anywhere else!
*/
if(newstate == NR4STDISC)
free_n4circ(cb);
}
/* Process NAKs. seq indicates the next frame expected by the
* NAK'ing station.
*/
static void
nr4gotnak(cb, seq)
struct nr4cb *cb;
unsigned seq;
{
if(nr4between(cb->ackxpected, seq, cb->nextosend))
nr4sbuf(cb, seq);
}
/* This is called when we first get a CHOKE indication from the
* remote. It purges the send window and sets the choke timer.
*/
static void
nr4choke(cb)
struct nr4cb *cb;
{
unsigned seq;
struct mbuf *q, *bp;
struct nr4txbuf *t;
q = cb->txq;
/* We purge the send window, returning the buffers to the
* txq in the proper order.
*/
for(seq = (cb->nextosend - 1) & NR4SEQMASK;
nr4between(cb->ackxpected, seq, cb->nextosend);
seq = (seq - 1) & NR4SEQMASK){
t = &cb->txbufs[seq % cb->window];
stop_timer(&t->tretry);
bp = t->data;
t->data = NULL;
enqueue(&bp, &q); /* prepend this packet to the queue */
q = bp;
}
cb->nextosend = cb->ackxpected; /* close the window */
cb->nbuffered = 0; /* nothing in the window */
cb->txq = q; /* Replace the txq with the one that has */
/* the purged packets prepended */
cb->choked = 1; /* Set the choked flag */
start_timer(&cb->tchoke);
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -