📄 lapb.c
字号:
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 + -