📄 lapb.c
字号:
buffer_release(buffer); else { ls->rxq[woffs].buffer = buffer; ls->rxq[woffs].length = count; ls->rhead = nr; if (ls->rcvnonempty != NULL && woffs == ls->rtail) (*ls->rcvnonempty)(ls->userstate); } return; } else { /* Error; bad address. */ buffer_release(buffer); return; } /* Next, extract the command/response code and sequence. */ DBG(("process input on %p\n",ls)); ns = nr = 0; /* quiet down compiler */ crcode = buffer[1]; ilen = 2; if (IS_U_TYPE(crcode)) { pfbit = (crcode & 0x10)>>4; } else switch (ls->mode) { case MODE_BASIC: ns = (crcode & 0x0E)>>1; pfbit = (crcode & 0x10)>>4; nr = (crcode & 0xE0)>>5; break; case MODE_EXTENDED: if (count < 3) { errbits = 3; goto frmr_handler; } ns = (crcode & 0xFE)>>1; pfbit = buffer[2] & 1; nr = (buffer[2] & 0xFE)>>1; ilen = 3; break; case MODE_SUPER: if (count < 5) { errbits = 3; goto frmr_handler; } ns = ((crcode & 0xFE)>>1) | (buffer[2]<<7); pfbit = buffer[3] & 1; nr = ((buffer[3] & 0xFE)>>1) | (buffer[4]<<7); ilen = 5; break; default: /* This can't happen. */ buffer_release(buffer); return; } if (IS_I_TYPE(crcode)) crcode &= ITYPE_MASK; else if (IS_S_TYPE(crcode)) crcode &= STYPE_MASK; else crcode &= UTYPE_MASK; /* Switch out on type of received frame. */ DBG(("code %d, nr %d, ns %d\n",crcode,nr,ns)); errbits = 0; switch (crcode) { case CRI_I: DBG(("received I frame\n")); /* Still setting up; silent discard. */ if (ls->phase == phInitial) break; if (!iscmd) { errbits = 1; break; } handle_nr(ls,nr); /* * Note: LAP-B assumes that packets cannot be reordered on the * link. For that reason, it is safe to assume that a sequence * number error implies a lost packet. */ if (INWINDOW(ns,ls->vr,ls->rxqsize,ls->rxkval)) { DBG(("inside window; vr is %d\n",ls->vr)); /* Get non-negative window offset. */ woffs = (ls->rtail+ns-ls->vr+ls->rxkval+1) % (ls->rxkval+1); if (ls->rxq[woffs].buffer != NULL) { /* Discard duplicate buffer. */ DBG(("duplicate buffer; discarding.\n")); break; } ls->rxq[woffs].buffer = buffer+ilen; ls->rxq[woffs].length = count-ilen; /* Check for sequence number error. */ if (woffs != ls->rhead) { DBG(("queue offset %d not equal to head %d; need reject.\n", woffs,ls->rhead)); need_transmit(ls,STF_NEEDREJ); } if (++woffs > ls->rxkval) woffs = 0; if (ls->rhead >= ls->rtail) { if (woffs > ls->rhead || woffs < ls->rtail) ls->rhead = woffs; } else { if (woffs > ls->rhead && woffs < ls->rtail) ls->rhead = woffs; } /* While in sequence, send data to application */ if (ls->rcvnonempty != NULL && ls->rxq[ls->rtail].buffer != NULL) (*ls->rcvnonempty)(ls->userstate); /* Don't free queued packets. */ buffer = NULL; } else { DBG(("outside window; vr is %d\n",ls->vr)); } if (pfbit) { need_transmit(ls,STF_NEEDSTATUS | STF_PFBIT); } break; case CRS_RR: case CRS_RNR: if (crcode == CRS_RR) DBG(("received RR frame\n")); else DBG(("received RNR frame\n")); /* Still setting up; silent discard. */ if (ls->phase == phInitial) break; if (count != ilen) { errbits = 3; break; } if (crcode == CRS_RR) ls->flags |= LBF_PEERREADY; else ls->flags &= ~LBF_PEERREADY; handle_nr(ls,nr); if (iscmd && pfbit) { need_transmit(ls,STF_NEEDSTATUS | STF_PFBIT); } break; case CRS_REJ: DBG(("received REJ frame\n")); /* Still setting up; silent discard. */ if (ls->phase == phInitial) break; if (ls->mode == MODE_EXTENDED || (ls->flags & LBF_RXSREJ)) { errbits = 1; break; } if (count != ilen) { errbits = 3; break; } ls->flags |= LBF_PEERREADY; handle_nr(ls,nr); if (iscmd && pfbit) need_transmit(ls,STF_NEEDSTATUS | STF_PFBIT); /* Drop back to sequence N(R) and try again on all. */ DBG(("reject marking retransmit %d to %d\n",nr,ls->vs)); mark_retransmit(ls,nr,ls->vs); break; case CRS_SREJ: DBG(("received SREJ frame\n")); /* Still setting up; silent discard. */ if (ls->phase == phInitial) break; if (ls->mode == MODE_BASIC || iscmd || !(ls->flags & LBF_RXSREJ)) { errbits = 1; break; } if (pfbit) handle_nr(ls,nr); /* Drop back to sequence N(R) and try again on some. */ mark_retransmit(ls,nr,nr); bp = buffer+ilen; count -= ilen; while (count > 0) { nr = *bp++; count--; if (ls->mode == MODE_SUPER) { if (--count < 0) break; nr |= *bp++ << 8; } if ((nr & 1) && count > 0) { woffs = *bp++; if (ls->mode == MODE_SUPER) { if (--count < 0) /* XXX */ break; woffs |= *bp++ << 8; } mark_retransmit(ls,nr>>1,woffs>>1); } else { nr >>= 1; mark_retransmit(ls,nr,nr); } } break; case CRU_SABM: DBG(("received SABM frame\n")); if (ls->flags & LBF_PERMISSIVE) ls->mode = MODE_BASIC; if (ls->mode != MODE_BASIC || !iscmd) { errbits = 1; break; } if (count != 2) { errbits = 3; break; } enter_data_phase: DBG(("received entering data phase\n")); if (ls->statflag & STF_T1RUNNING) { ls->t2ctr = 0; ls->statflag &= ~STF_T1RUNNING; untimeout(t1handler,(void *)ls); } ls->flags |= LBF_PEERREADY; ls->vr = ls->vs = 0; free_all_packets(ls); ls->phase = phData; ls->statflag &= ~STF_UAFBIT; need_transmit(ls,STF_NEEDUA | (pfbit ? STF_UAFBIT : 0)); if (ls->xmthasroom != NULL) (*ls->xmthasroom)(ls->userstate); break; case CRU_SABME: DBG(("received SABME frame\n")); if (ls->flags & LBF_PERMISSIVE) ls->mode = MODE_EXTENDED; if (ls->mode != MODE_EXTENDED || !iscmd) { errbits = 1; break; } if (count != 2) { errbits = 3; break; } goto enter_data_phase; case CRU_SM: DBG(("received SM frame\n")); if (ls->flags & LBF_PERMISSIVE) ls->mode = MODE_SUPER; ilen = (count > 6) ? 6 : count; /* FRMR generation */ if (ls->mode != MODE_SUPER || !iscmd) { errbits = 1; break; } /* Should have one address byte and 5 Set Mode bytes */ if (count != 6 || buffer[2] != 0 || buffer[3] != 0x40 || buffer[4] != 0x80 || buffer[5] != 0x20) { errbits = 3; break; } goto enter_data_phase; case CRU_DISC: DBG(("received DISC frame\n")); if (!iscmd) { errbits = 1; break; } if (count != 2) { errbits = 3; break; } ls->phase = phDisconnected; ls->statflag &= ~STF_UAFBIT; need_transmit(ls,STF_NEEDUA | (pfbit ? STF_UAFBIT : 0)); break; case CRU_DM: DBG(("received DM frame\n")); if (iscmd) { errbits = 1; break; } if (count != 2) { errbits = 3; break; } if (ls->phase != phInitial) ls->phase = phDisconnected; break; case CRU_UA: DBG(("received UA frame\n")); if (iscmd) { errbits = 1; break; } if (count != 2) { errbits = 3; break; } if (ls->phase == phDisconnecting) ls->phase = phDisconnected; ls->flags |= LBF_PEERREADY; break; case CRU_FRMR: DBG(("received FRMR frame\n")); /* Still setting up; silent discard. */ if (ls->phase == phInitial) break; if (iscmd) { /* Rejecting a rejection seems like a bad idea. */ /* errbits = 1; */ break; } break; default: DBG(("received bad frame\n")); /* Error; bad code. */ errbits = 1; break; }frmr_handler: if (errbits && !(ls->txpend.qflags & QF_SENDING)) { /* * We don't assume here that the input buffer is big * enough to hold this error frame. It probably is * (and certainly is with the example AHDLC code), * but better safe than sorry. */ DBG(("Generating FRMR in response\n")); bp = (octet *)buffer_fetch(11); if (bp != NULL) { bp[0] = ls->cmdaddr ^ ls->crabit; bp[1] = CRU_FRMR; bp[3] = bp[4] = bp[5] = 0; memcpy(bp+2,buffer+1,ilen-1); switch (ls->mode) { case MODE_BASIC: bp[3] = (ls->vs<<1) | (iscmd?0:0x10) | (ls->vr<<5); bp[4] = errbits; ilen = 5; break; case MODE_EXTENDED: bp[4] = ls->vs<<1; bp[5] = (iscmd?0:1) | (ls->vr<<1); bp[6] = errbits; ilen = 7; break; case MODE_SUPER: bp[6] = ls->vs<<1; bp[7] = ls->vs>>7; bp[8] = (iscmd?0:1) | (ls->vr<<1); bp[9] = ls->vr>>1; bp[10] = errbits; ilen = 11; break; } ls->txpend.qflags = QF_SEND; ls->txpend.length = ilen; if (ls->txpend.buffer != NULL) buffer_release(ls->txpend.buffer); ls->txpend.buffer = bp; } } if (buffer != NULL) buffer_release(buffer);}/* * This creates a SABM, SABME, or SM message as appropriate for the * configured mode. */static octet *make_set_mode(struct lapb_state *ls, int *lengthp){ octet *bp,ctl; int len; len = 0; bp = (octet *)buffer_fetch(6); if (bp != NULL) { bp[0] = ls->cmdaddr; /* 2.4.4.1 -- DTE sets P bit in set-mode command */ ctl = (ls->flags & LBF_ISDTE) ? 0x10 : 0; switch (ls->mode) { case MODE_BASIC: bp[1] = CRU_SABM | ctl; len = 2; break; case MODE_EXTENDED: bp[1] = CRU_SABME | ctl; len = 2; break; case MODE_SUPER: bp[1] = CRU_SM | ctl; bp[2] = 0; bp[3] = 0x40; bp[4] = 0x80; bp[5] = 0x20; len = 6; break; default: /* This can't happen. */ buffer_release(bp); bp = NULL; } } *lengthp = len; return bp;}/* * This creates a Receive Ready or Receive Not Ready message as * appropriate for the current state and mode. */static octet *make_status(struct lapb_state *ls, int *lengthp){ octet *bp,ctl; int len; if ((bp = (octet *)buffer_fetch(5)) == NULL) return NULL; bp[0] = ls->cmdaddr ^ (0 ? 0 : ls->crabit); ctl = ALLSET(ls->flags,LBF_IMREADY|LBF_USERREADY) ? CRS_RR : CRS_RNR; switch (ls->mode) { case MODE_BASIC: bp[1] = ctl | (ls->statflag & STF_PFBIT ? 0x10 : 0) | (ls->vr<<5); len = 2; break; case MODE_EXTENDED: bp[1] = ctl; bp[2] = (ls->statflag & STF_PFBIT ? 1 : 0) | (ls->vr<<1); len = 3; break; case MODE_SUPER: bp[1] = ctl; bp[2] = 0; bp[3] = (ls->statflag & STF_PFBIT ? 1 : 0) | (ls->vr<<1); bp[4] = ls->vr>>7; len = 5; break; default: /* This can't happen. */ buffer_release(bp); return NULL; } *lengthp = len; return bp;}/* * Generate an unnumbered acknowledgement response. This is used as a * reply to a received SABM/SABME/SM frame. */static octet *make_ua(struct lapb_state *ls, int *lengthp){ octet *bp; if ((bp = (octet *)buffer_fetch(2)) == NULL) return NULL; bp[0] = ls->cmdaddr ^ ls->crabit; bp[1] = CRU_UA | ((ls->statflag & STF_UAFBIT) ? 0x10 : 0); *lengthp = 2; return bp;}/* * Generate a disconnect mode response. */static octet *make_dm(struct lapb_state *ls, int *lengthp){ octet *bp; if ((bp = (octet *)buffer_fetch(2)) == NULL) return NULL; bp[0] = ls->cmdaddr ^ ls->crabit; bp[1] = CRU_DM; *lengthp = 2; return bp;}/* * Generate a disconnect command. */static octet *make_disc(struct lapb_state *ls, int *lengthp){ octet *bp; if ((bp = (octet *)buffer_fetch(2)) == NULL) return NULL; bp[0] = ls->cmdaddr; bp[1] = CRU_DISC | 0x10; *lengthp = 2; return bp;}/* * Make a reject or selective reject command frame as appropriate. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -