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

📄 lapb.c

📁 嵌入式TCP/IP协议栈。 C 源码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* Link Access Procedures Balanced (LAPB), the upper sublayer of
 * AX.25 Level 2.
 */
#include "global.h"
#include "mbuf.h"
#include "timer.h"
#include "ax25.h"
#include "lapb.h"
#include "ip.h"
#include "netrom.h"

static void handleit(struct ax25_cb *axp,int pid,struct mbuf **bp);
static void procdata(struct ax25_cb *axp,struct mbuf **bp);
static int ackours(struct ax25_cb *axp,uint16 n);
static void clr_ex(struct ax25_cb *axp);
static void enq_resp(struct ax25_cb *axp);
static void inv_rex(struct ax25_cb *axp);

/* Process incoming frames */
int
lapb_input(
struct ax25_cb *axp,		/* Link control structure */
int cmdrsp,			/* Command/response flag */
struct mbuf **bpp		/* Rest of frame, starting with ctl */
){
	int control;
	int class;		/* General class (I/S/U) of frame */
	uint16 type;		/* Specific type (I/RR/RNR/etc) of frame */
	char pf;		/* extracted poll/final bit */
	char poll = 0;
	char final = 0;
	uint16 nr;		/* ACK number of incoming frame */
	uint16 ns;		/* Seq number of incoming frame */
	uint16 tmp;

	if(bpp == NULL || *bpp == NULL || axp == NULL){
		free_p(bpp);
		return -1;
	}

	/* Extract the various parts of the control field for easy use */
	if((control = PULLCHAR(bpp)) == -1){
		free_p(bpp);	/* Probably not necessary */
		return -1;
	}
	type = ftype(control);
	class = type & 0x3;
	pf = control & PF;
	/* Check for polls and finals */
	if(pf){
		switch(cmdrsp){
		case LAPB_COMMAND:
			poll = YES;
			break;
		case LAPB_RESPONSE:
			final = YES;
			break;
		}
	}
	/* Extract sequence numbers, if present */
	switch(class){
	case I:
	case I+2:
		ns = (control >> 1) & MMASK;
	case S:	/* Note fall-thru */
		nr = (control >> 5) & MMASK;
		break;
	}
	/* This section follows the SDL diagrams by K3NA fairly closely */
	switch(axp->state){
	case LAPB_DISCONNECTED:
		switch(type){
		case SABM:	/* Initialize or reset link */
			sendctl(axp,LAPB_RESPONSE,UA|pf);	/* Always accept */
			clr_ex(axp);
			axp->unack = axp->vr = axp->vs = 0;
			lapbstate(axp,LAPB_CONNECTED);/* Resets state counters */
			axp->srt = Axirtt;
			axp->mdev = 0;
			set_timer(&axp->t1,2*axp->srt);
			start_timer(&axp->t3);
			break;
		case DM:	/* Ignore to avoid infinite loops */
			break;
		default:	/* All others get DM */
			if(poll)
				sendctl(axp,LAPB_RESPONSE,DM|pf);
			break;
		}
		break;
	case LAPB_SETUP:
		switch(type){
		case SABM:	/* Simultaneous open */
			sendctl(axp,LAPB_RESPONSE,UA|pf);
			break;
		case DISC:
			sendctl(axp,LAPB_RESPONSE,DM|pf);
			break;
		case UA:	/* Connection accepted */
			/* Note: xmit queue not cleared */
			stop_timer(&axp->t1);
			start_timer(&axp->t3);
			axp->unack = axp->vr = axp->vs = 0;
			lapbstate(axp,LAPB_CONNECTED);
			break;			
		case DM:	/* Connection refused */
			free_q(&axp->txq);
			stop_timer(&axp->t1);
			axp->reason = LB_DM;
			lapbstate(axp,LAPB_DISCONNECTED);
			break;
		default:	/* All other frames ignored */
			break;
		}
		break;
	case LAPB_DISCPENDING:
		switch(type){
		case SABM:
			sendctl(axp,LAPB_RESPONSE,DM|pf);
			break;
		case DISC:
			sendctl(axp,LAPB_RESPONSE,UA|pf);
			break;
		case UA:
		case DM:
			stop_timer(&axp->t1);
			lapbstate(axp,LAPB_DISCONNECTED);
			break;
		default:	/* Respond with DM only to command polls */
			if(poll)
				sendctl(axp,LAPB_RESPONSE,DM|pf);
			break;
		}
		break;
	case LAPB_CONNECTED:
		switch(type){
		case SABM:
			sendctl(axp,LAPB_RESPONSE,UA|pf);
			clr_ex(axp);
			free_q(&axp->txq);
			stop_timer(&axp->t1);
			start_timer(&axp->t3);
			axp->unack = axp->vr = axp->vs = 0;
			lapbstate(axp,LAPB_CONNECTED); /* Purge queues */
			break;
		case DISC:
			free_q(&axp->txq);
			sendctl(axp,LAPB_RESPONSE,UA|pf);
			stop_timer(&axp->t1);
			stop_timer(&axp->t3);
			axp->reason = LB_NORMAL;
			lapbstate(axp,LAPB_DISCONNECTED);
			break;
		case DM:
			axp->reason = LB_DM;
			lapbstate(axp,LAPB_DISCONNECTED);
			break;
		case UA:
			est_link(axp);
			lapbstate(axp,LAPB_SETUP);	/* Re-establish */	
			break;			
		case FRMR:
			est_link(axp);
			lapbstate(axp,LAPB_SETUP);	/* Re-establish link */
			break;
		case RR:
		case RNR:
			axp->flags.remotebusy = (control == RNR) ? YES : NO;
			if(poll)
				enq_resp(axp);
			ackours(axp,nr);
			break;
		case REJ:
			axp->flags.remotebusy = NO;
			if(poll)
				enq_resp(axp);
			ackours(axp,nr);
			stop_timer(&axp->t1);
			start_timer(&axp->t3);
			/* This may or may not actually invoke transmission,
			 * depending on whether this REJ was caused by
			 * our losing his prior ACK.
			 */
			inv_rex(axp);
			break;	
		case I:
			ackours(axp,nr); /** == -1) */
			if(len_p(axp->rxq) >= axp->window){
				/* Too bad he didn't listen to us; he'll
				 * have to resend the frame later. This
				 * drastic action is necessary to avoid
				 * deadlock.
				 */
				if(poll)
					sendctl(axp,LAPB_RESPONSE,RNR|pf);
				free_p(bpp);
				break;
			}
			/* Reject or ignore I-frames with receive sequence number errors */
			if(ns != axp->vr){
				if(axp->proto == V1 || !axp->flags.rejsent){
					axp->flags.rejsent = YES;
					sendctl(axp,LAPB_RESPONSE,REJ | pf);
				} else if(poll)
					enq_resp(axp);
				axp->response = 0;
				break;
			}
			axp->flags.rejsent = NO;
			axp->vr = (axp->vr+1) & MMASK;
			tmp = len_p(axp->rxq) >= axp->window ? RNR : RR;
			if(poll){
				sendctl(axp,LAPB_RESPONSE,tmp|PF);
			} else {
				axp->response = tmp;
			}
			procdata(axp,bpp);
			break;
		default:	/* All others ignored */
			break;
		}
		break;
	case LAPB_RECOVERY:
		switch(type){
		case SABM:
			sendctl(axp,LAPB_RESPONSE,UA|pf);
			clr_ex(axp);
			stop_timer(&axp->t1);
			start_timer(&axp->t3);
			axp->unack = axp->vr = axp->vs = 0;
			lapbstate(axp,LAPB_CONNECTED); /* Purge queues */
			break;
		case DISC:
			free_q(&axp->txq);
			sendctl(axp,LAPB_RESPONSE,UA|pf);
			stop_timer(&axp->t1);
			stop_timer(&axp->t3);
			axp->response = UA;
			axp->reason = LB_NORMAL;
			lapbstate(axp,LAPB_DISCONNECTED);
			break;
		case DM:
			axp->reason = LB_DM;
			lapbstate(axp,LAPB_DISCONNECTED);
			break;
		case UA:
			est_link(axp);
			lapbstate(axp,LAPB_SETUP);	/* Re-establish */	
			break;
		case FRMR:
			est_link(axp);
			lapbstate(axp,LAPB_SETUP);	/* Re-establish link */
			break;
		case RR:
		case RNR:
			axp->flags.remotebusy = (control == RNR) ? YES : NO;
			if(axp->proto == V1 || final){
				stop_timer(&axp->t1);
				ackours(axp,nr);
				if(axp->unack != 0){
					inv_rex(axp);
				} else {
					start_timer(&axp->t3);
					lapbstate(axp,LAPB_CONNECTED);
				}
			} else {
				if(poll)
					enq_resp(axp);
				ackours(axp,nr);
				/* Keep timer running even if all frames
				 * were acked, since we must see a Final
				 */
				if(!run_timer(&axp->t1))
					start_timer(&axp->t1);
			}
			break;
		case REJ:
			axp->flags.remotebusy = NO;
			/* Don't insist on a Final response from the old proto */
			if(axp->proto == V1 || final){
				stop_timer(&axp->t1);
				ackours(axp,nr);
				if(axp->unack != 0){
					inv_rex(axp);
				} else {
					start_timer(&axp->t3);
					lapbstate(axp,LAPB_CONNECTED);
				}
			} else {
				if(poll)
					enq_resp(axp);
				ackours(axp,nr);
				if(axp->unack != 0){
					/* This is certain to trigger output */
					inv_rex(axp);
				}
				/* A REJ that acks everything but doesn't
				 * have the F bit set can cause a deadlock.
				 * So make sure the timer is running.
				 */
				if(!run_timer(&axp->t1))
					start_timer(&axp->t1);
			}
			break;
		case I:
			ackours(axp,nr); /** == -1) */
			/* Make sure timer is running, since an I frame
			 * cannot satisfy a poll
			 */
			if(!run_timer(&axp->t1))
				start_timer(&axp->t1);
			if(len_p(axp->rxq) >= axp->window){
				/* Too bad he didn't listen to us; he'll
				 * have to resend the frame later. This
				 * drastic action is necessary to avoid
				 * memory deadlock.
				 */
				sendctl(axp,LAPB_RESPONSE,RNR | pf);
				free_p(bpp);
				break;
			}
			/* Reject or ignore I-frames with receive sequence number errors */
			if(ns != axp->vr){
				if(axp->proto == V1 || !axp->flags.rejsent){
					axp->flags.rejsent = YES;
					sendctl(axp,LAPB_RESPONSE,REJ | pf);
				} else if(poll)
					enq_resp(axp);

				axp->response = 0;
				break;
			}
			axp->flags.rejsent = NO;
			axp->vr = (axp->vr+1) & MMASK;
			tmp = len_p(axp->rxq) >= axp->window ? RNR : RR;
			if(poll){
				sendctl(axp,LAPB_RESPONSE,tmp|PF);
			} else {
				axp->response = tmp;
			}
			procdata(axp,bpp);
			break;
		default:
			break;		/* Ignored */
		}
		break;
	}
	free_p(bpp);	/* In case anything's left */

⌨️ 快捷键说明

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