📄 lcp.c
字号:
* address/control compression requests; they should send * a Reject instead. If they send a Nak, treat it as a Reject. */ NAKCIVOID(CI_PCOMPRESSION, neg_pcompression); NAKCIVOID(CI_ACCOMPRESSION, neg_accompression); /* * Nak for MRRU option - accept their value if it is smaller * than the one we want. */ if (go->neg_mrru) { NAKCISHORT(CI_MRRU, neg_mrru, if (cishort <= wo->mrru) try.mrru = cishort; ); } /* * Nak for short sequence numbers shouldn't be sent, treat it * like a reject. */ NAKCIVOID(CI_SSNHF, neg_ssnhf); /* * Nak of the endpoint discriminator option is not permitted, * treat it like a reject. */ NAKCIENDP(CI_EPDISC, neg_endpoint); /* * There may be remaining CIs, if the peer is requesting negotiation * on an option that we didn't include in our request packet. * If we see an option that we requested, or one we've already seen * in this packet, then this packet is bad. * If we wanted to respond by starting to negotiate on the requested * option(s), we could, but we don't, because except for the * authentication type and quality protocol, if we are not negotiating * an option, it is because we were told not to. * For the authentication type, the Nak from the peer means * `let me authenticate myself with you' which is a bit pointless. * For the quality protocol, the Nak means `ask me to send you quality * reports', but if we didn't ask for them, we don't want them. * An option we don't recognize represents the peer asking to * negotiate some option we don't support, so ignore it. */ while (len > CILEN_VOID) { GETCHAR(citype, p); GETCHAR(cilen, p); if (cilen < CILEN_VOID || (len -= cilen) < 0) goto bad; next = p + cilen - 2; switch (citype) { case CI_MRU: if ((go->neg_mru && go->mru != DEFMRU) || no.neg_mru || cilen != CILEN_SHORT) goto bad; GETSHORT(cishort, p); if (cishort < DEFMRU) { try.neg_mru = 1; try.mru = cishort; } break; case CI_ASYNCMAP: if ((go->neg_asyncmap && go->asyncmap != 0xFFFFFFFF) || no.neg_asyncmap || cilen != CILEN_LONG) goto bad; break; case CI_AUTHTYPE: if (go->neg_chap || no.neg_chap || go->neg_upap || no.neg_upap) goto bad; break; case CI_MAGICNUMBER: if (go->neg_magicnumber || no.neg_magicnumber || cilen != CILEN_LONG) goto bad; break; case CI_PCOMPRESSION: if (go->neg_pcompression || no.neg_pcompression || cilen != CILEN_VOID) goto bad; break; case CI_ACCOMPRESSION: if (go->neg_accompression || no.neg_accompression || cilen != CILEN_VOID) goto bad; break; case CI_QUALITY: if (go->neg_lqr || no.neg_lqr || cilen != CILEN_LQR) goto bad; break; case CI_MRRU: if (go->neg_mrru || no.neg_mrru || cilen != CILEN_SHORT) goto bad; break; case CI_SSNHF: if (go->neg_ssnhf || no.neg_ssnhf || cilen != CILEN_VOID) goto bad; try.neg_ssnhf = 1; break; case CI_EPDISC: if (go->neg_endpoint || no.neg_endpoint || cilen < CILEN_CHAR) goto bad; break; } p = next; } /* * OK, the Nak is good. Now we can update state. * If there are any options left we ignore them. */ if (f->state != OPENED) { if (looped_back) { if (++try.numloops >= lcp_loopbackfail) { notice("Serial line is looped back."); lcp_close(f->unit, "Loopback detected"); status = EXIT_LOOPBACK; } } else try.numloops = 0; *go = try; } return 1;bad: LCPDEBUG(("lcp_nakci: received bad Nak!")); return 0;}/* * lcp_rejci - Peer has Rejected some of our CIs. * This should not modify any state if the Reject is bad * or if LCP is in the OPENED state. * * Returns: * 0 - Reject was bad. * 1 - Reject was good. */static intlcp_rejci(f, p, len) fsm *f; u_char *p; int len;{ lcp_options *go = &lcp_gotoptions[f->unit]; u_char cichar; u_short cishort; u_int32_t cilong; lcp_options try; /* options to request next time */ try = *go; /* * Any Rejected CIs must be in exactly the same order that we sent. * Check packet length and CI length at each step. * If we find any deviations, then this packet is bad. */#define REJCIVOID(opt, neg) \ if (go->neg && \ len >= CILEN_VOID && \ p[1] == CILEN_VOID && \ p[0] == opt) { \ len -= CILEN_VOID; \ INCPTR(CILEN_VOID, p); \ try.neg = 0; \ }#define REJCISHORT(opt, neg, val) \ if (go->neg && \ len >= CILEN_SHORT && \ p[1] == CILEN_SHORT && \ p[0] == opt) { \ len -= CILEN_SHORT; \ INCPTR(2, p); \ GETSHORT(cishort, p); \ /* Check rejected value. */ \ if (cishort != val) \ goto bad; \ try.neg = 0; \ }#define REJCICHAP(opt, neg, val, digest) \ if (go->neg && \ len >= CILEN_CHAP && \ p[1] == CILEN_CHAP && \ p[0] == opt) { \ len -= CILEN_CHAP; \ INCPTR(2, p); \ GETSHORT(cishort, p); \ GETCHAR(cichar, p); \ /* Check rejected value. */ \ if (cishort != val || cichar != digest) \ goto bad; \ try.neg = 0; \ try.neg_upap = 0; \ }#define REJCILONG(opt, neg, val) \ if (go->neg && \ len >= CILEN_LONG && \ p[1] == CILEN_LONG && \ p[0] == opt) { \ len -= CILEN_LONG; \ INCPTR(2, p); \ GETLONG(cilong, p); \ /* Check rejected value. */ \ if (cilong != val) \ goto bad; \ try.neg = 0; \ }#define REJCILQR(opt, neg, val) \ if (go->neg && \ len >= CILEN_LQR && \ p[1] == CILEN_LQR && \ p[0] == opt) { \ len -= CILEN_LQR; \ INCPTR(2, p); \ GETSHORT(cishort, p); \ GETLONG(cilong, p); \ /* Check rejected value. */ \ if (cishort != PPP_LQR || cilong != val) \ goto bad; \ try.neg = 0; \ }#define REJCICBCP(opt, neg, val) \ if (go->neg && \ len >= CILEN_CBCP && \ p[1] == CILEN_CBCP && \ p[0] == opt) { \ len -= CILEN_CBCP; \ INCPTR(2, p); \ GETCHAR(cichar, p); \ /* Check rejected value. */ \ if (cichar != val) \ goto bad; \ try.neg = 0; \ }#define REJCIENDP(opt, neg, class, val, vlen) \ if (go->neg && \ len >= CILEN_CHAR + vlen && \ p[0] == opt && \ p[1] == CILEN_CHAR + vlen) { \ int i; \ len -= CILEN_CHAR + vlen; \ INCPTR(2, p); \ GETCHAR(cichar, p); \ if (cichar != class) \ goto bad; \ for (i = 0; i < vlen; ++i) { \ GETCHAR(cichar, p); \ if (cichar != val[i]) \ goto bad; \ } \ try.neg = 0; \ } REJCISHORT(CI_MRU, neg_mru, go->mru); REJCILONG(CI_ASYNCMAP, neg_asyncmap, go->asyncmap); REJCICHAP(CI_AUTHTYPE, neg_chap, PPP_CHAP, go->chap_mdtype); if (!go->neg_chap) { REJCISHORT(CI_AUTHTYPE, neg_upap, PPP_PAP); } REJCILQR(CI_QUALITY, neg_lqr, go->lqr_period); REJCICBCP(CI_CALLBACK, neg_cbcp, CBCP_OPT); REJCILONG(CI_MAGICNUMBER, neg_magicnumber, go->magicnumber); REJCIVOID(CI_PCOMPRESSION, neg_pcompression); REJCIVOID(CI_ACCOMPRESSION, neg_accompression); REJCISHORT(CI_MRRU, neg_mrru, go->mrru); REJCIVOID(CI_SSNHF, neg_ssnhf); REJCIENDP(CI_EPDISC, neg_endpoint, go->endpoint.class, go->endpoint.value, go->endpoint.length); /* * If there are any remaining CIs, then this packet is bad. */ if (len != 0) goto bad; /* * Now we can update state. */ if (f->state != OPENED) *go = try; return 1;bad: LCPDEBUG(("lcp_rejci: received bad Reject!")); return 0;}/* * lcp_reqci - Check the peer's requested CIs and send appropriate response. * * Returns: CONFACK, CONFNAK or CONFREJ and input packet modified * appropriately. If reject_if_disagree is non-zero, doesn't return * CONFNAK; returns CONFREJ if it can't return CONFACK. */static intlcp_reqci(f, inp, lenp, reject_if_disagree) fsm *f; u_char *inp; /* Requested CIs */ int *lenp; /* Length of requested CIs */ int reject_if_disagree;{ lcp_options *go = &lcp_gotoptions[f->unit]; lcp_options *ho = &lcp_hisoptions[f->unit]; lcp_options *ao = &lcp_allowoptions[f->unit]; u_char *cip, *next; /* Pointer to current and next CIs */ int cilen, citype, cichar; /* Parsed len, type, char value */ u_short cishort; /* Parsed short value */ u_int32_t cilong; /* Parse long value */ int rc = CONFACK; /* Final packet return code */ int orc; /* Individual option return code */ u_char *p; /* Pointer to next char to parse */ u_char *rejp; /* Pointer to next char in reject frame */ u_char *nakp; /* Pointer to next char in Nak frame */ int l = *lenp; /* Length left */ /* * Reset all his options. */ BZERO(ho, sizeof(*ho)); /* * Process all his options. */ next = inp; nakp = nak_buffer; rejp = inp; while (l) { orc = CONFACK; /* Assume success */ cip = p = next; /* Remember begining of CI */ if (l < 2 || /* Not enough data for CI header or */ p[1] < 2 || /* CI length too small or */ p[1] > l) { /* CI length too big? */ LCPDEBUG(("lcp_reqci: bad CI length!")); orc = CONFREJ; /* Reject bad CI */ cilen = l; /* Reject till end of packet */ l = 0; /* Don't loop again */ citype = 0; goto endswitch; } GETCHAR(citype, p); /* Parse CI type */ GETCHAR(cilen, p); /* Parse CI length */ l -= cilen; /* Adjust remaining length */ next += cilen; /* Step to next CI */ switch (citype) { /* Check CI type */ case CI_MRU: if (!ao->neg_mru || /* Allow option? */ cilen != CILEN_SHORT) { /* Check CI length */ orc = CONFREJ; /* Reject CI */ break; } GETSHORT(cishort, p); /* Parse MRU */ /* * He must be able to receive at least our minimum. * No need to check a maximum. If he sends a large number, * we'll just ignore it. */ if (cishort < MINMRU) { orc = CONFNAK; /* Nak CI */ PUTCHAR(CI_MRU, nakp); PUTCHAR(CILEN_SHORT, nakp); PUTSHORT(MINMRU, nakp); /* Give him a hint */ break; } ho->neg_mru = 1; /* Remember he sent MRU */ ho->mru = cishort; /* And remember value */ break; case CI_ASYNCMAP: if (!ao->neg_asyncmap || cilen != CILEN_LONG) { orc = CONFREJ; break; } GETLONG(cilong, p); /* * Asyncmap must have set at least the bits * which are set in lcp_allowoptions[unit].asyncmap. */ if ((ao->asyncmap & ~cilong) != 0) { orc = CONFNAK; PUTCHAR(CI_ASYNCMAP, nakp); PUTCHAR(CILEN_LONG, nakp); PUTLONG(ao->asyncmap | cilong, nakp); break; } ho->neg_asyncmap = 1; ho->asyncmap = cilong; break; case CI_AUTHTYPE: if (cilen < CILEN_SHORT || !(ao->neg_upap || ao->neg_chap)) { /* * Reject the option if we're not willing to authenticate. */ orc = CONFREJ; break; } GETSHORT(cishort, p); /* * Authtype must be PAP or CHAP. * * Note: if both ao->neg_upap and ao->neg_chap are set, * and the peer sends a Configure-Request with two * authenticate-protocol requests, one for CHAP and one * for UPAP, then we will reject the second request. * Whether we end up doing CHAP or UPAP depends then on * the ordering of the CIs in the peer's Configure-Request. */ if (cishort == PPP_PAP) { if (ho->neg_chap || /* we've already accepted CHAP */ cilen != CILEN_SHORT) { LCPDEBUG(("lcp_reqci: rcvd AUTHTYPE PAP, rejecting...")); orc = CONFREJ; break; } if (!ao->neg_upap) { /* we don't want to do PAP */ orc = CONFNAK; /* NAK it and suggest CHAP */ PUTCHAR(CI_AUTHTYPE, nakp); PUTCHAR(CILEN_CHAP, nakp); PUTSHORT(PPP_CHAP, nakp); PUTCHAR(ao->chap_mdtype, nakp); /* XXX if we can do CHAP_MICROSOFT as well, we should probably put in another option saying so */ break; } ho->neg_upap = 1; break; } if (cishort == PPP_CHAP) { if (ho->neg_upap || /* we've already accepted PAP */ cilen != CILEN_CHAP) { LCPDEBUG(("lcp_reqci: rcvd AUTHTYPE CHAP, rejecting...")); orc = CONFREJ; break; } if (!ao->neg_chap) { /* we don't want to do CHAP */ orc = CONFNAK; /* NAK it and suggest PAP */ PUTCHAR(CI_AUTHTYPE, nakp); PUTCHAR(CILEN_SHORT, nakp); PUTSHORT(PPP_PAP, nakp); break; } GETCHAR(cichar, p); /* get digest type*/ if (cichar != CHAP_DIGEST_MD5#ifdef CHAPMS && cichar != CHAP_MICROSOFT#endif ) { orc = CONFNAK; PUTCHAR(CI_AUTHTYPE, nakp); PUTCHAR(CILEN_CHAP, nakp); PUTSHORT(PPP_CHAP, nakp); PUTCHAR(ao->chap_mdtype, nakp); break; } ho->chap_mdtype = cichar; /* save md type */ ho->neg_chap = 1; break; } /* * We don't recognize the protocol they're asking for. * Nak it with something we're willing to do. * (At this point we know ao->neg_upap || ao->neg_chap.) */ orc = CONFNAK; PUTCHAR(CI_AUTHTYPE, nakp); if (ao->neg_chap) { PUTCHAR(CILEN_CHAP, nakp); PUTSHORT(PPP_CHAP, nakp); PUTCHAR(ao->chap_mdtype, nakp); } else { PUTCHAR(CILEN_SHORT, nakp); PUTSHORT(PPP_PAP, nakp); } break; case CI_QUALITY: if (!ao->neg_lqr || cilen != CILEN_LQR) { orc = CONFREJ; break; } GETSHORT(cishort, p); GETLONG(cilong, p); /* * Check the protocol and the reporting period. * XXX When should we Nak this, and what with? */ if (cishort != PPP_LQR) { orc = CONFNAK; PUTCHAR(CI_QUALITY, nakp); PUTCHAR(CILEN_LQR, nakp); PUTSHORT(PPP_LQR, nakp); PUTLONG(ao->lqr_period, nakp); break; } break; case CI_MAGICNUMBER: if (!(ao->neg_magicnumber || go->neg_magicnumber) || cilen != CILEN_LONG) { orc = CONFREJ; break; } GETLONG(cilong, p); /* * He must have a different magic number. */ if (go->neg_magicnumber && cilong == go->magicnumber) { cilong = magic(); /* Don't put magic() inside macro! */ orc = CONFNAK; PUTCHAR(CI_MAGICNUMBER, nakp); PUTCHAR(CILEN_LONG, nakp); PUTLONG(cilong, nakp); break; } ho->neg_magicnumber = 1; ho->magicnumber = cilong; break; case CI_PCOMPRESSION: if (!ao->neg_pcompression || cilen != CILEN_VOID) { orc = CONFREJ; break; } ho->neg_pcompression = 1; break; case CI_ACCOMPRESSION: if (!ao->neg_accompression || cilen != CILEN_VOID) { orc = CONFREJ; break; } ho->neg_accompression = 1; break; case CI_MRRU: if (!ao->neg_mrru || !multilink || cilen != CILEN_SHORT) { orc = CONFREJ;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -