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

📄 lapb.c

📁 ppp协议实现源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
static octet *make_reject(struct lapb_state *ls, int *lengthp){    octet *bp,*buffer;    int rtail,nrej,slen,rfirst,vrnum;    /* Count up entries needed in information field. */    rtail = ls->rtail;    slen = nrej = 0;    rfirst = -1;    while (rtail != ls->rhead) {	if (ls->rxq[rtail].buffer == NULL) {	    if (rfirst < 0)		rfirst = rtail;	    if (ls->flags & LBF_TXSREJ) {		slen++;	    } else {		nrej++;		break;	    }	} else if (slen > 0) {	    if (slen > 1)		nrej += 2;	    else		nrej++;	    slen = 0;	}	if (++rtail > ls->rxkval)	    rtail = 0;    }    if (slen > 0) {	if (slen > 1)	    nrej += 2;	else	    nrej++;    }    if (nrej == 0) {	ls->statflag &= ~STF_NEEDREJ;	return NULL;    }    /* Calculate approximate message size. */    if (ls->mode == MODE_SUPER) {	nrej *= 2;	nrej += 5;    } else {	nrej += 3;    }    if ((bp = buffer = (octet *)buffer_fetch(nrej)) == NULL)	return NULL;    /* Construct the message */    *bp++ = ls->cmdaddr ^ ls->crabit;    nrej = (ls->flags & LBF_TXSREJ) ? CRS_SREJ : CRS_REJ;    vrnum = (ls->rxkval+1+rfirst-ls->rtail)%(ls->rxkval+1);    vrnum = (vrnum+ls->vr)%ls->rxqsize;    switch (ls->mode) {    case MODE_BASIC:	*bp++ = nrej | (vrnum<<5);	break;    case MODE_EXTENDED:	*bp++ = nrej;	*bp++ = (vrnum<<1) | ((ls->flags & LBF_TXSREJ) ? 1 : 0);	break;    case MODE_SUPER:	*bp++ = nrej;	*bp++ = 0;	*bp++ = (vrnum<<1) | ((ls->flags & LBF_TXSREJ) ? 1 : 0);	*bp++ = vrnum>>7;	break;    }    rtail = rfirst;    slen = 0;    if (ls->flags & LBF_TXSREJ) {	/* Build up the span list for selective reject. */	while (rtail != ls->rhead) {	    if (ls->rxq[rtail].buffer == NULL) {		if (++slen == 1) {		    *bp++ = vrnum<<1;		    if (ls->mode == MODE_SUPER)			*bp++ = vrnum>>7;		}	    } else if (slen > 0) {		if (slen > 1) {		    if ((slen = vrnum) == 0)			slen = ls->rxqsize;		    slen--;		    bp[(ls->mode == MODE_SUPER) ? -2 : -1] |= 1;		    *bp++ = (slen<<1) | 1;		    if (ls->mode == MODE_SUPER)			*bp++ = slen>>7;		}		slen = 0;	    }	    if (++rtail > ls->rxkval)		rtail = 0;	    if (++vrnum >= ls->rxqsize)		vrnum = 0;	}    }    *lengthp = bp-buffer;    ls->statflag &= ~STF_NEEDREJ;    return buffer;}/* * Called when timer T1 should be enabled. */static voidset_timer_t1(struct lapb_state *ls){    if (!(ls->statflag & STF_T1RUNNING)) {	ls->statflag |= STF_T1RUNNING;	timeout(t1handler,(void *)ls,ls->t1period);    }}/* * This routine is handed over to the HDLC framer, which should call * when it needs a new packet to transmit. */voidlapb_transmit(void *statep, octet **bufferp, int *lengthp){    struct lapb_state *ls = (struct lapb_state *)statep;    octet *bp;    int len,tptr;    if (statep == NULL || bufferp == NULL || lengthp == NULL)	return;    *bufferp = NULL;    *lengthp = 0;    DBG(("transmit handler for %p.\n",ls));    /* Check for completed frames to free up. */    if (ls->txpend.qflags & QF_SENDING) {	DBG(("done with pended packet.\n"));	if (ls->txpend.buffer != NULL)	    buffer_release(ls->txpend.buffer);	ls->txpend.buffer = NULL;	ls->txpend.qflags = 0;    }    if (ls->discarding != NULL) {	buffer_release(ls->discarding);	ls->discarding = NULL;    }    /* We are done sending the current frame; mark or free it. */    tptr = ls->tsending;    if (ls->txq[tptr].qflags & QF_SENDING) {	/*	 * Timing note: we may get an reject in before we finish	 * transmitting the frame being rejected.  Don't free the	 * frame in this case.	 */	if ((ls->txq[tptr].qflags&(QF_ACKED|QF_SEND)) == QF_ACKED) {	    DBG(("done with acked packet.\n"));	    buffer_release(ls->txq[tptr].buffer);	    ls->txq[tptr].buffer = NULL;	    ls->txq[tptr].qflags = 0;	    if (tptr == ls->ttail && ls->phase <= phQueueDrain) {		if (++tptr > ls->txkval)		    tptr = 0;		ls->ttail = tptr;		if (ls->statflag & STF_XMITFULL) {		    ls->statflag &= ~STF_XMITFULL;		    if (ls->phase == phQueue && ls->xmthasroom != NULL)			(*ls->xmthasroom)(ls->userstate);		}	    }	} else	    ls->txq[tptr].qflags &= ~QF_SENDING;    }    /* If no pending frame, then find one to do. */    if (ls->txpend.buffer == NULL && ls->phase >= phInitial) {	if (ls->statflag & STF_NEEDDM) {	    if ((ls->txpend.buffer = make_dm(ls,&len)) != NULL) {		DBG(("pended DM packet.\n"));		ls->statflag &= ~STF_NEEDDM;		ls->txpend.length = len;	    }	/* Check for SABM frame. */	} else if (ls->statflag & STF_NEEDSABM) {	    if ((ls->txpend.buffer = make_set_mode(ls,&len)) != NULL) {		DBG(("pended SABM packet.\n"));		ls->statflag &= ~STF_NEEDSABM;		ls->txpend.length = len;		set_timer_t1(ls);	    }	} else if (ls->statflag & STF_NEEDDISC) {	    if ((ls->txpend.buffer = make_disc(ls,&len)) != NULL) {		DBG(("pended DISC packet.\n"));		ls->statflag &= ~STF_NEEDDISC;		ls->txpend.length = len;		set_timer_t1(ls);	    }	/* Check for UA frame. */	} else if (ls->statflag & STF_NEEDUA) {	    if ((ls->txpend.buffer = make_ua(ls,&len)) != NULL) {		DBG(("pended UA packet.\n"));		ls->statflag &= ~STF_NEEDUA & ~STF_UAFBIT;		ls->txpend.length = len;	    }	/* Check for status with PF bit. */	} else if (ALLSET(ls->statflag,STF_NEEDSTATUS|STF_PFBIT)) {	    if ((ls->txpend.buffer = make_status(ls,&len)) != NULL) {		DBG(("pended RR/RNR with PF bit.\n"));		ls->statflag &= ~STF_NEEDSTATUS & ~STF_PFBIT;		ls->txpend.length = len;	    }	/* Check for reject frame. */	} else if (ls->statflag & STF_NEEDREJ) {	    if ((ls->txpend.buffer = make_reject(ls,&len)) != NULL) {		DBG(("pended REJ/SREJ frame.\n"));		ls->txpend.length = len;		set_timer_t1(ls);	    }	}    }    /* If we now have something pending, then do it. */    if (ls->txpend.buffer != NULL) {	DBG(("sending pended packet.\n"));	ls->txpend.qflags = QF_SENDING;	*bufferp = ls->txpend.buffer;	*lengthp = ls->txpend.length;	ls->statflag |= STF_XMITRUN;	return;    }    /* Skip over any frames that don't need to be sent. */    tptr = ls->tnext;    if (tptr != ls->thead) {	while (tptr != ls->thead && !(ls->txq[tptr].qflags & QF_SEND)) {	    if (++tptr > ls->txkval)		tptr = 0;	}	ls->tnext = tptr;    }    /* Check for new I frame to transmit */    if (tptr != ls->thead) {	DBG(("sending from transmit queue location %d on %p\n",tptr,ls));	bp = ls->txq[tptr].buffer;	len = ls->txq[tptr].length;	ls->txq[tptr].qflags = 	    (ls->txq[tptr].qflags & ~QF_SEND) | QF_SENDING;	assert(bp != NULL);	ls->tsending = tptr;	if (ls->phase == phData) {	    /* Insert current VR number now. */	    ls->statflag &= ~STF_NEEDVR;	    switch (ls->mode) {	    case MODE_BASIC:		DBG(("sending basic I frame; ns %d nr %d.\n",		     (bp[1]>>1)&7,ls->vr));		bp[1] = (bp[1] & 0x1F) | (ls->vr<<5);		break;	    case MODE_EXTENDED:		DBG(("sending extended I frame; ns %d nr %d.\n",		     (bp[1]>>1)&0x7F,ls->vr));		bp[2] = (bp[2] & 1) | (ls->vr<<1);		break;	    case MODE_SUPER:		DBG(("sending super I frame; ns %d nr %d.\n",		     ((bp[1]>>1)&0x7F)|(bp[2]<<7),ls->vr));		bp[3] = (bp[3]&1) | (ls->vr<<1);		bp[4] = ls->vr>>7;		break;	    }	    set_timer_t1(ls);	} else {	    DBG(("sending queued frame.\n"));	    ls->txq[tptr].qflags |= QF_ACKED;	}	tptr++;	if (tptr > ls->txkval)	    tptr = 0;	ls->tnext = tptr;	/* Complete switch into LAP-B mode. */	if (tptr == ls->thead && ls->phase == phQueueDrain) {	    DBG(("drained; switching to LAP-B.\n"));	    ls->phase = phInitial;	    ls->statflag |= STF_NEEDSABM;	}	*bufferp = bp;	*lengthp = len;	ls->statflag |= STF_XMITRUN;	return;    }    /* Check for plain status frame to transmit */    if ((ls->statflag & (STF_NEEDSTATUS|STF_NEEDVR)) != 0 &&	ls->phase >= phInitial) {	if ((ls->txpend.buffer = make_status(ls,&len)) != NULL) {	    DBG(("plain RR/RNR frame to send.\n"));	    ls->statflag = (ls->statflag & ~STF_NEEDSTATUS & ~STF_NEEDVR &			    ~STF_PFBIT) | STF_XMITRUN;	    *lengthp = ls->txpend.length = len;	    *bufferp = ls->txpend.buffer;	    ls->txpend.qflags = QF_SENDING;	    return;	}    }    /* Nothing left to send. */    ls->statflag &= ~STF_XMITRUN;}/* * User function to fetch data from receive queue.  Returns pointer * to data and length. */intlapb_receive(void *statep, octet **bufferp){    struct lapb_state *ls = (struct lapb_state *)statep;    int rptr,len;    if (ls == NULL || bufferp == NULL)	return -1;    rptr = ls->rtail;    /* Check for empty buffer. */    if (rptr == ls->rhead) {	DBG(("empty receive queue on %p\n",ls));	*bufferp = NULL;	return 0;    }    /* Check if next packet in window hasn't been received yet. */    if ((*bufferp = ls->rxq[rptr].buffer) == NULL) {	DBG(("out-of-order; sequence not received yet.\n"));	return 0;    }    len = ls->rxq[rptr].length;    ls->rxq[rptr].buffer = NULL;    rptr++;    if (rptr > ls->rxkval)	rptr = 0;    ls->rtail = rptr;    ls->vr = (ls->vr + 1) % ls->rxqsize;    DBG(("buffer received by application; bumping vr to %d\n",ls->vr));    ls->flags |= LBF_IMREADY;    ls->statflag |= STF_NEEDVR;    need_transmit(ls,STF_NEEDVR);    return len;}/* * User function to send data to transmit queue.  Returns non-zero if * queue is now full.  (xmthasroom callback will be made when room is * again available.) * * It is assumed that the buffer given has enough room to prepend a * header.  This is 2 octets for basic mode, 3 for extended, and 5 for * super. */intlapb_send(void *statep, octet *buffer, int length){    struct lapb_state *ls = (struct lapb_state *)statep;    int tptr,tnxt;    if (ls == NULL || buffer == NULL)	return -1;    tptr = ls->thead;    tnxt = tptr+1;    if (tnxt > ls->txkval)	tnxt = 0;    if (tnxt == ls->ttail || (ls->phase != phQueue && ls->phase != phData)) {	/* User error; queue is already full. */	DBG(("send error on %p; %s\n",ls,	     (tnxt == ls->ttail) ? "queue is full" : "wrong phase"));	buffer_release(buffer);	ls->statflag |= STF_XMITFULL;	return -1;    }    if (ls->phase >= phData) {	/* VR is inserted when the frame is actually sent. */	switch (ls->mode) {	case MODE_BASIC:	    *--buffer = CRI_I | (ls->vs<<1);	    length += 2;	    break;	case MODE_EXTENDED:	    *--buffer = 0;	    *--buffer = CRI_I | (ls->vs<<1);	    length += 3;	    break;	case MODE_SUPER:	    *--buffer = 0;	    *--buffer = 0;	    *--buffer = ls->vs>>7;	    *--buffer = CRI_I | (ls->vs<<1);	    length += 5;	    break;	}	*--buffer = ls->cmdaddr;	ls->vs = (ls->vs + 1) % ls->txqsize;    }    DBG(("set transmit queue location %d on %p\n",tptr,ls));    ls->txq[tptr].buffer = buffer;    ls->txq[tptr].length = length;    ls->txq[tptr].qflags = QF_SEND;    tptr = (tptr == ls->ttail);    ls->thead = tnxt;    if (tptr && !(ls->statflag & STF_XMITRUN)) {	ls->statflag |= STF_XMITRUN;	enable_transmit();    }    if (ls->phase == phQueueDrain) {	DBG(("in queue drain phase; marking full flag.\n"));	ls->statflag |= STF_XMITFULL;	return 1;    }    tnxt++;    if (tnxt > ls->txkval)	tnxt = 0;    if (tnxt == ls->ttail) {	DBG(("transmit queue is full.\n"));	ls->statflag |= STF_XMITFULL;	return 1;    }    return 0;}/* * User function to enable and disable LAP-B operation. */voidlapb_control(void *statep, int onoff){    struct lapb_state *ls = (struct lapb_state *)statep;    if (ls == NULL)	return;    if (onoff) {	if (ls->phase == phQueue) {	    if (ls->tnext != ls->thead)		ls->phase = phQueueDrain;	    else {		ls->phase = phInitial;		need_transmit(ls,STF_NEEDSABM);	    }	}    } else {	if (ls->phase == phQueueDrain || ls->phase == phDisconnected)	    ls->phase = phQueue;	else if (ls->phase >= phInitial) {	    ls->phase = phDisconnecting;	    need_transmit(ls,STF_NEEDDISC);	}    }}/* * Change LAP-B parameters.  Should be called by LCP negotiation. */voidlapb_change(void *statep, int mode, int txkval, int rxkval,	    int t1period, int t2max, int flags){    struct lapb_state *ls = (struct lapb_state *)statep;    int len;    struct lapb_queue *qp;    if (ls == NULL || mode < MODE_BASIC || mode > MODE_PERMISSIVE)	return;    len = mode_modulus[mode];    if (txkval >= len || rxkval >= len)	return;    if ((mode != ls->mode && mode != MODE_PERMISSIVE) ||	(mode == MODE_PERMISSIVE && !(ls->flags & LBF_PERMISSIVE)) ||	txkval != ls->txkval || rxkval != ls->rxkval) {	if (ls->phase >= phInitial)	    free_all_packets(ls);	if (txkval != ls->txkval || rxkval != ls->rxkval) {	    len = (txkval+rxkval+2)*sizeof(struct lapb_queue);	    qp = (struct lapb_queue *)realloc(ls->rxq,len);	    if (qp == NULL)		return;	    init_values(ls,qp,mode,txkval,rxkval,flags);	}    }    if (t1period <= 0)	t1period = DEF_T1PERIOD;    ls->t1period = t1period;    if (t2max <= 0)	t2max = DEF_T2MAX;    ls->t2max = t2max;}

⌨️ 快捷键说明

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