⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 nr4.c

📁 uCLinux下的一个TCP/IP协议栈源码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* 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;
		}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -