📄 lcp.c
字号:
ACKCISHORT(CI_MRU, go->neg_mru, go->mru); ACKCILONG(CI_ASYNCMAP, go->neg_asyncmap, go->asyncmap); ACKCICHAP(CI_AUTHTYPE, go->neg_chap, CHAP, go->chap_mdtype); ACKCISHORT(CI_AUTHTYPE, !go->neg_chap && go->neg_upap, UPAP); ACKCILQR(CI_QUALITY, go->neg_lqr, go->lqr_period); ACKCILONG(CI_MAGICNUMBER, go->neg_magicnumber, go->magicnumber); ACKCIVOID(CI_PCOMPRESSION, go->neg_pcompression); ACKCIVOID(CI_ACCOMPRESSION, go->neg_accompression); /* * If there are any remaining CIs, then this packet is bad. */ if (len != 0) goto bad; return (1);bad: LCPDEBUG((LOG_WARNING, "lcp_acki: received bad Ack!")); return (0);}/* * lcp_nakci - Peer has sent a NAK for some of our CIs. * This should not modify any state if the Nak is bad * or if LCP is in the OPENED state. * * Returns: * 0 - Nak was bad. * 1 - Nak was good. */static intlcp_nakci(f, p, len) fsm *f; u_char *p; int len;{ lcp_options *go = &ppp_if[f->unit]->lcp_gotoptions; lcp_options *wo = &ppp_if[f->unit]->lcp_wantoptions; u_char cilen, citype, cichar, *next; u_short cishort = 0; u_long cilong; lcp_options no; /* options we've seen Naks for */ lcp_options try; /* options to request next time */ int looped_back = 0; BZERO((char *)&no, sizeof(no)); try = *go; /* * Any Nak'd 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 NAKCIVOID(opt, neg, code) \ if (go->neg && \ len >= CILEN_VOID && \ p[1] == CILEN_VOID && \ p[0] == opt) { \ len -= CILEN_VOID; \ INCPTR(CILEN_VOID, p); \ no.neg = 1; \ code \ }#define NAKCICHAP(opt, neg, code) \ 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); \ no.neg = 1; \ code \ }#define NAKCISHORT(opt, neg, code) \ if (go->neg && \ len >= CILEN_SHORT && \ p[1] == CILEN_SHORT && \ p[0] == opt) { \ len -= CILEN_SHORT; \ INCPTR(2, p); \ GETSHORT(cishort, p); \ no.neg = 1; \ code \ }#define NAKCILONG(opt, neg, code) \ if (go->neg && \ len >= CILEN_LONG && \ p[1] == CILEN_LONG && \ p[0] == opt) { \ len -= CILEN_LONG; \ INCPTR(2, p); \ GETLONG(cilong, p); \ no.neg = 1; \ code \ }#define NAKCILQR(opt, neg, code) \ 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); \ no.neg = 1; \ code \ } /* * We don't care if they want to send us smaller packets than * we want. Therefore, accept any MRU less than what we asked for, * but then ignore the new value when setting the MRU in the kernel. * If they send us a bigger MRU than what we asked, accept it, up to * the limit of the default MRU we'd get if we didn't negotiate. */ NAKCISHORT(CI_MRU, neg_mru, if (cishort <= wo->mru || cishort < DEFMRU) try.mru = cishort; ); /* * Add any characters they want to our (receive-side) asyncmap. */ NAKCILONG(CI_ASYNCMAP, neg_asyncmap, try.asyncmap = go->asyncmap | cilong; ); /* * If they can't cope with our CHAP hash algorithm, we'll have * to stop asking for CHAP. We haven't got any other algorithm. */ NAKCICHAP(CI_AUTHTYPE, neg_chap, try.neg_chap = 0; ); /* * Peer shouldn't send Nak for UPAP, protocol compression or * address/control compression requests; they should send * a Reject instead. If they send a Nak, treat it as a Reject. */ if (!go->neg_chap ){ NAKCISHORT(CI_AUTHTYPE, neg_upap, try.neg_upap = 0; ); } /* * If they can't cope with our link quality protocol, we'll have * to stop asking for LQR. We haven't got any other protocol. * If they Nak the reporting period, take their value XXX ? */ NAKCILQR(CI_QUALITY, neg_lqr, if (cishort != LQR) try.neg_lqr = 0; else try.lqr_period = cilong; ); /* * Check for a looped-back line. */ NAKCILONG(CI_MAGICNUMBER, neg_magicnumber, try.magicnumber = magic(); ++try.numloops; looped_back = 1; ); NAKCIVOID(CI_PCOMPRESSION, neg_pcompression, try.neg_pcompression = 0; ); NAKCIVOID(CI_ACCOMPRESSION, neg_accompression, try.neg_accompression = 0; ); /* * 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. */ while (len > CILEN_VOID) { GETCHAR(citype, p); GETCHAR(cilen, p); if( (len -= cilen) < 0 ) goto bad; next = p + cilen - 2; switch (citype) { case CI_MRU: if (go->neg_mru || no.neg_mru || cilen != CILEN_SHORT) goto bad; break; case CI_ASYNCMAP: if (go->neg_asyncmap || 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; default: goto bad; } p = next; } /* If there is still anything left, this packet is bad. */ if (len != 0) goto bad; /* * OK, the Nak is good. Now we can update state. */ if (f->state != OPENED) { *go = try; if (looped_back && try.numloops % lcp_warnloops == 0) LCPDEBUG((LOG_INFO, "The line appears to be looped back.")); } return 1;bad: LCPDEBUG((LOG_WARNING, "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 = &ppp_if[f->unit]->lcp_gotoptions; u_char cichar = 0; u_short cishort; u_long cilong;#ifdef DEBUGLCP u_char *start = p; int plen = len;#endif /* DEBUGLCP */ 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; \ LCPDEBUG((LOG_INFO, "lcp_rejci rejected void opt %d", opt)); \ }#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 != (u_short)val) \ goto bad; \ try.neg = 0; \ LCPDEBUG((LOG_INFO,"lcp_rejci rejected short opt %d", opt)); \ }#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 != (u_short)val || cichar != (u_char)digest) \ goto bad; \ try.neg = 0; \ LCPDEBUG((LOG_INFO,"lcp_rejci rejected chap opt %d", opt)); \ }#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 != (u_long)val) \ goto bad; \ try.neg = 0; \ LCPDEBUG((LOG_INFO,"lcp_rejci rejected long opt %d", opt)); \ }#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 != LQR || cilong != val) \ goto bad; \ try.neg = 0; \ LCPDEBUG((LOG_INFO,"lcp_rejci rejected LQR opt %d", opt)); \ } REJCISHORT(CI_MRU, neg_mru, go->mru); REJCILONG(CI_ASYNCMAP, neg_asyncmap, go->asyncmap); REJCICHAP(CI_AUTHTYPE, neg_chap, CHAP, go->chap_mdtype); if (!go->neg_chap) { REJCISHORT(CI_AUTHTYPE, neg_upap, UPAP); } REJCILQR(CI_QUALITY, neg_lqr, go->lqr_period); REJCILONG(CI_MAGICNUMBER, neg_magicnumber, go->magicnumber); REJCIVOID(CI_PCOMPRESSION, neg_pcompression); REJCIVOID(CI_ACCOMPRESSION, neg_accompression); /* * 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((LOG_WARNING, "lcp_rejci: received bad Reject!")); LCPDEBUG((LOG_WARNING, "lcp_rejci: plen %d len %d off %d", plen, len, p - start)); 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 = &ppp_if[f->unit]->lcp_gotoptions; lcp_options *ho = &ppp_if[f->unit]->lcp_hisoptions; lcp_options *ao = &ppp_if[f->unit]->lcp_allowoptions; u_char *cip, *next; /* Pointer to current and next CIs */ u_char cilen, citype = 0, cichar;/* Parsed len, type, char value */ u_short cishort; /* Parsed short value */ u_long 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((char *)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((LOG_WARNING, "lcp_reqci: bad CI length!")); orc = CONFREJ; /* Reject bad CI */ cilen = l; /* Reject till end of packet */ l = 0; /* Don't loop again */ 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: LCPDEBUG((LOG_INFO, "lcp_reqci: rcvd MRU")); if (!ao->neg_mru || /* Allow option? */ cilen != CILEN_SHORT) { /* Check CI length */ orc = CONFREJ; /* Reject CI */ break; } GETSHORT(cishort, p); /* Parse MRU */ LCPDEBUG((LOG_INFO, "(%d)", cishort)); /* * 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 */ if( !reject_if_disagree ){ DECPTR(sizeof (short), p); /* Backup */ PUTSHORT(MINMRU, p); /* Give him a hint */ } break; } ho->neg_mru = 1; /* Remember he sent MRU */ ho->mru = cishort; /* And remember value */ break; case CI_ASYNCMAP: LCPDEBUG((LOG_INFO, "lcp_reqci: rcvd ASYNCMAP")); if (!ao->neg_asyncmap || cilen != CILEN_LONG) { orc = CONFREJ; break; } GETLONG(cilong, p); LCPDEBUG((LOG_INFO, "(%lx)", cilong)); /* * Asyncmap must have set at least the bits * which are set in lcp_allowoptions[unit].asyncmap. */ if ((ao->asyncmap & ~cilong) != 0) { orc = CONFNAK; if( !reject_if_disagree ){ DECPTR(sizeof (long), p); PUTLONG(ao->asyncmap | cilong, p); } break; } ho->neg_asyncmap = 1; ho->asyncmap = cilong; break; case CI_AUTHTYPE: LCPDEBUG((LOG_INFO, "lcp_reqci: rcvd AUTHTYPE")); if (cilen < CILEN_SHORT || !(ao->neg_upap || ao->neg_chap)) { orc = CONFREJ; if (!ao->neg_upap && !ao->neg_chap) LCPDEBUG((LOG_INFO, " we're not willing to authenticate")); else LCPDEBUG((LOG_INFO, " cilen is too short!")); break; } GETSHORT(cishort, p); LCPDEBUG((LOG_INFO, "(%x)", cishort)); /* * Authtype must be UPAP 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 == UPAP) { if (ho->neg_chap || /* we've already accepted CHAP */ cilen != CILEN_SHORT) { LCPDEBUG((LOG_WARNING, "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(CHAP, nakp); PUTCHAR(ao->chap_mdtype, nakp); break; } ho->neg_upap = 1; break; } if (cishort == CHAP) { if (ho->neg_upap || /* we've already accepted PAP */ cilen != CILEN_CHAP) { LCPDEBUG((LOG_INFO, "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(UPAP, nakp); break; } GETCHAR(cichar, p); /* get digest type*/ if (cichar != (u_char)ao->chap_mdtype) { orc = CONFNAK; PUTCHAR(CI_AUTHTYPE, nakp); PUTCHAR(CILEN_CHAP, nakp); PUTSHORT(CHAP, nakp); PUTCHAR(ao->chap_mdtype, nakp); break; } ho->chap_mdtype = cichar; /* save md type */ ho->neg_chap = 1; break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -