?? nr4.c
字號:
/* net/rom level 4 (transport) protocol implementation
*/
#include <stdio.h>
#include "global.h"
#include "mbuf.h"
#include "timer.h"
#include "ax25.h"
#include "lapb.h"
#include "netrom.h"
#include "nr4.h"
#include <ctype.h>
#undef NR4DEBUG
/* Globals: */
/* The circuit table */
struct nr4circp Nr4circuits[NR4MAXCIRC];
/* Various limits */
unsigned short Nr4window = 4; /* Max window to negotiate */
unsigned short Nr4retries = 10; /* Max retries */
unsigned short Nr4qlimit = 2048; /* Max bytes on receive queue */
/* Timers */
int32 Nr4irtt = 15000; /* Initial round trip time */
int32 Nr4acktime = 3000; /* ACK delay timer */
int32 Nr4choketime = 180000; /* CHOKEd state timeout */
static void nr4ackours(struct nr4cb *, unsigned, int);
static void nr4choke(struct nr4cb *);
static void nr4gotnak(struct nr4cb *, unsigned);
static void nr4rframe(struct nr4cb *, unsigned, struct mbuf **);
/* This function is called when a net/rom layer four frame */
/* is discovered inside a datagram addressed to us */
void
nr4input(hdr,bpp)
struct nr4hdr *hdr;
struct mbuf **bpp;
{
struct nr4hdr rhdr;
struct nr4cb *cb, *cb2;
int op;
unsigned window;
int acceptc; /* indicates that connection should be accepted */
int newconn; /* indicates that this is a new incoming */
/* connection. You'll see. */
int gotchoke; /* The choke flag was set in this packet */
int i;
op = hdr->opcode & NR4OPCODE; /* Mask off flags */
if(op == NR4OPCONRQ){ /* process connect request first */
acceptc = 1;
newconn = 0;
/* These fields are sent regardless of success */
rhdr.yourindex = hdr->u.conreq.myindex;
rhdr.yourid = hdr->u.conreq.myid;
/* Check to see if we have already received a connect */
/* request for this circuit. */
if((cb = match_n4circ(hdr->u.conreq.myindex,
hdr->u.conreq.myid,hdr->u.conreq.user,hdr->u.conreq.node))
== NULL){ /* No existing circuit if NULL */
/* Try to get a new circuit */
if((cb = new_n4circ()) == NULL)
acceptc = 0;
/* See if we have any listening sockets */
for(i = 0; i < NR4MAXCIRC; i++){
if((cb2 = Nr4circuits[i].ccb) == NULL)
continue;/* not an open circuit */
if(cb2->state == NR4STLISTEN)
/* A listener was found */
break;
}
if(i == NR4MAXCIRC){ /* We are refusing connects */
acceptc = 0;
free_n4circ(cb);
}
if(acceptc){
/* Load the listeners settings */
cb->clone = cb2->clone;
cb->user = cb2->user;
cb->t_upcall = cb2->t_upcall;
cb->s_upcall = cb2->s_upcall;
cb->r_upcall = cb2->r_upcall;
ASSIGN(cb->local,cb2->local);
/* Window is set to min of the offered
* and local windows
*/
window = hdr->u.conreq.window > Nr4window ?
Nr4window : hdr->u.conreq.window;
if(init_nr4window(cb, window) == -1){
free_n4circ(cb);
acceptc = 0;
} else {
/* Set up control block */
cb->yournum = hdr->u.conreq.myindex;
cb->yourid = hdr->u.conreq.myid;
memcpy(cb->remote.user,
hdr->u.conreq.user,AXALEN);
memcpy(cb->remote.node,
hdr->u.conreq.node,AXALEN);
/* Default round trip time */
cb->srtt = Nr4irtt;
/* set up timers, window pointers */
nr4defaults(cb);
cb->state = NR4STDISC;
newconn = 1;
} /* End if window successfully allocated */
} /* End if new circuit available */
} /* End if no existing circuit matching parameters */
/* Now set up response */
if(!acceptc){
rhdr.opcode = NR4OPCONAK | NR4CHOKE;/* choke means reject */
rhdr.u.conack.myindex = 0;
rhdr.u.conack.myid = 0;
rhdr.u.conack.window = 0;
} else {
rhdr.opcode = NR4OPCONAK;
rhdr.u.conack.myindex = cb->mynum;
rhdr.u.conack.myid = cb->myid;
rhdr.u.conack.window = cb->window;
}
nr4sframe(hdr->u.conreq.node, &rhdr, NULL);
/* Why, you ask, do we wait until now for the state change
* upcall? Well, it's like this: if the state change triggers
* something like the mailbox to send its banner, the banner
* would have gone out *before* the conn ack if we'd done this
* in the code above. This is what happens when you don't plan
* too well. Learn from my mistakes :-)
*/
if(newconn)
nr4state(cb, NR4STCON);/* connected (no 3-way handshake) */
free_p(bpp);
return;
} /* end connect request code */
/* validate circuit number */
if((cb = get_n4circ(hdr->yourindex, hdr->yourid)) == NULL){
free_p(bpp);
return;
}
/* Check for choke flag */
if(hdr->opcode & NR4CHOKE)
gotchoke = 1;
else
gotchoke = 0;
/* Here's where the interesting stuff gets done */
switch(cb->state){
case NR4STCPEND:
switch(op){
case NR4OPCONAK:
/* Save the round trip time for later use */
i = dur_timer(&cb->tcd) - read_timer(&cb->tcd);
stop_timer(&cb->tcd);
if(gotchoke){ /* connect rejected */
cb->dreason = NR4RREFUSED;
nr4state(cb, NR4STDISC);
break;
}
cb->yournum = hdr->u.conack.myindex;
cb->yourid = hdr->u.conack.myid;
window = hdr->u.conack.window > Nr4window ?
Nr4window : hdr->u.conack.window;
if(init_nr4window(cb, window) == -1){
cb->dreason = NR4RRESET;
nr4state(cb, NR4STDISC);
} else {
nr4defaults(cb); /* set up timers, window pointers */
if(cb->cdtries == 1) /* No retries */
/* Use measured rtt */
cb->srtt = i;
else
/* else use default */
cb->srtt = Nr4irtt;
nr4state(cb, NR4STCON);
nr4output(cb); /* start sending anything on the txq */
}
break;
default:
/* We can't respond to anything else without
* Their ID and index
*/
free_p(bpp);
return;
}
break;
case NR4STCON:
switch(op){
case NR4OPDISRQ:
/* format reply packet */
rhdr.opcode = NR4OPDISAK;
rhdr.yourindex = cb->yournum;
rhdr.yourid = cb->yourid;
nr4sframe(cb->remote.node,&rhdr,NULL);
cb->dreason = NR4RREMOTE;
nr4state(cb, NR4STDISC);
break;
case NR4OPINFO:
/* Do receive frame processing */
nr4rframe(cb, hdr->u.info.txseq, bpp);
/* Reset the choke flag if no longer choked. Processing
* the ACK will kick things off again.
*/
if(cb->choked && !gotchoke){
stop_timer(&cb->tchoke);
cb->choked = 0;
}
/* We delay processing the receive sequence number until
* now, because the ACK might pull more off the txq and send
* it, and we want the implied ACK in those frames to be right
*
* Only process NAKs if the choke flag is off. It appears
* that NAKs should never be sent with choke on, by the way,
* but you never know, considering that there is no official
* standard for this protocol
*/
if(hdr->opcode & NR4NAK && !gotchoke)
nr4gotnak(cb, hdr->u.info.rxseq);
/* We always do ACK processing, too, since the NAK of one
* packet may be the implied ACK of another. The gotchoke
* flag is used to prevent sending any new frames, since
* we are just going to purge them next anyway if this is
* the first time we've seen the choke flag. If we are
* already choked, this call will return immediately.
*/
nr4ackours(cb, hdr->u.info.rxseq, gotchoke);
/* If we haven't seen the choke flag before, purge the
* send window and set the timer and the flag.
*/
if(!cb->choked && gotchoke)
nr4choke(cb);
break;
case NR4OPACK:
if(cb->choked && !gotchoke){
/* clear choke if appropriate */
stop_timer(&cb->tchoke);
cb->choked = 0;
}
if(hdr->opcode & NR4NAK && !gotchoke)
nr4gotnak(cb, hdr->u.ack.rxseq); /* process NAKs */
nr4ackours(cb, hdr->u.ack.rxseq, gotchoke); /* and ACKs */
if(!cb->choked && gotchoke) /* First choke seen */
nr4choke(cb); /* Set choke status */
break;
}
break;
case NR4STDPEND:
switch(op){
case NR4OPDISAK:
cb->dreason = NR4RNORMAL;
nr4state(cb, NR4STDISC);
break;
case NR4OPINFO:
/* We can still do receive frame processing until
* the disconnect acknowledge arrives, but we won't
* bother to process ACKs, since we've flushed our
* transmit buffers and queue already.
*/
nr4rframe(cb, hdr->u.info.txseq, bpp);
break;
}
} /* End switch(state) */
}
/* Send a net/rom layer 4 frame. *bpp should be NULL unless the frame
* type is info.
*/
void
nr4sframe(
uint8 *dest,
struct nr4hdr *hdr,
struct mbuf **bpp
){
struct mbuf *n4b;
if((n4b = htonnr4(hdr)) == NULL){
free_p(bpp);
return;
} else {
append(&n4b, bpp);
nr3output(dest, &n4b);
}
}
/* Receive frame processing */
static void
nr4rframe(
struct nr4cb *cb,
unsigned rxseq,
struct mbuf **bpp
){
struct nr4hdr rhdr;
unsigned window = cb->window;
unsigned rxbuf = rxseq % window;
unsigned newdata = 0; /* whether to upcall */
#ifdef NR4DEBUG
printf("Processing received info\n");
#endif
/* If we're choked, just reset the ACK timer to blast out
* another CHOKE indication after the ackdelay
*/
if(cb->qfull){
start_timer(&cb->tack);
return;
}
/* If frame is out of sequence, it is either due to a lost frame
* or a retransmission of one seen earlier. We do not want to NAK
* the latter, as the far end would see this as a requirement to
* retransmit the expected frame, which is probably already in the
* pipeline. This in turn would cause another out-of-sequence
* condition, another NAK, and the process would repeat indefinitely.
* Therefore, if the frame is out-of-sequence, but within the last
* 'n' frames by sequence number ('n' being the window size), just
* accept it and discard it. Else, NAK it if we haven't already.
* (Modified by Rob Stampfli, kd8wk, 9 Jan 1990)
*/
if(rxseq != cb->rxpected && !cb->naksent){
#ifdef NR4DEBUG
printf("Frame out of sequence -- expected %u, got %u.\n",
cb->rxpected, rxseq);
#endif
if(nr4between(cb->rxpected,
(rxseq + window) & NR4SEQMASK, cb->rxpastwin))
/* just a repeat of old frame -- queue ack for
* expected frame
*/
start_timer(&cb->tack);
else { /* really bogus -- a NAKable frame */
rhdr.opcode = NR4OPACK | NR4NAK;
rhdr.yourindex = cb->yournum;
rhdr.yourid = cb->yourid;
rhdr.u.ack.rxseq = cb->rxpected;
nr4sframe(cb->remote.node,&rhdr,NULL);
/* Now make sure we don't send any more of these until
* we see some good data. Otherwise full window
* retransmissions would result in a flurry of NAKs
*/
cb->naksent = 1;
}
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -