X-Git-Url: https://git.ozlabs.org/?p=ppp.git;a=blobdiff_plain;f=pppd%2Flcp.c;h=231b7e4552861ea828cb361e9923bccf83c061d3;hp=dbf100de476c5f8d2004027259f2eddc8eef2414;hb=2c872bc67b83b91ba6390f6e5e72be08e09811a1;hpb=8592783058509b5493a42f3b0432fcbaab55c994 diff --git a/pppd/lcp.c b/pppd/lcp.c index dbf100d..231b7e4 100644 --- a/pppd/lcp.c +++ b/pppd/lcp.c @@ -17,9 +17,7 @@ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. */ -#ifndef lint -static char rcsid[] = "$Id: lcp.c,v 1.39 1999/05/12 06:19:47 paulus Exp $"; -#endif +#define RCSID "$Id: lcp.c,v 1.48 2000/03/27 06:02:59 paulus Exp $"; /* * TODO: @@ -35,6 +33,8 @@ static char rcsid[] = "$Id: lcp.c,v 1.39 1999/05/12 06:19:47 paulus Exp $"; #include "chap.h" #include "magic.h" +static const char rcsid[] = RCSID; + /* * LCP-related command-line options. */ @@ -64,7 +64,7 @@ static option_t lcp_option_list[] = { { "-as", o_uint32, &lcp_wantoptions[0].asyncmap, "Set asyncmap (for received packets)", OPT_OR, &lcp_wantoptions[0].neg_asyncmap }, - { "nomagicnumber", o_bool, &lcp_wantoptions[0].neg_magicnumber, + { "nomagic", o_bool, &lcp_wantoptions[0].neg_magicnumber, "Disable magic number negotiation (looped-back line detection)", OPT_A2COPY, &lcp_allowoptions[0].neg_magicnumber }, { "-mn", o_bool, &lcp_wantoptions[0].neg_magicnumber, @@ -107,6 +107,14 @@ static option_t lcp_option_list[] = { "Set limit on number of LCP configure-naks" }, { "receive-all", o_bool, &lax_recv, "Accept all received control characters", 1 }, +#ifdef HAVE_MULTILINK + { "mpshortseq", o_bool, &lcp_wantoptions[0].neg_ssnhf, + "Use short sequence numbers in multilink headers", + OPT_A2COPY, &lcp_allowoptions[0].neg_ssnhf }, + { "nompshortseq", o_bool, &lcp_wantoptions[0].neg_ssnhf, + "Don't use short sequence numbers in multilink headers", + OPT_A2COPY, &lcp_allowoptions[0].neg_ssnhf }, +#endif /* HAVE_MULTILINK */ {NULL} }; @@ -118,9 +126,9 @@ lcp_options lcp_allowoptions[NUM_PPP]; /* Options we allow peer to request */ lcp_options lcp_hisoptions[NUM_PPP]; /* Options that we ack'd */ u_int32_t xmit_accm[NUM_PPP][8]; /* extended transmit ACCM */ -static u_int32_t lcp_echos_pending = 0; /* Number of outstanding echo msgs */ -static u_int32_t lcp_echo_number = 0; /* ID number of next echo frame */ -static u_int32_t lcp_echo_timer_running = 0; /* set if a timer is running */ +static int lcp_echos_pending = 0; /* Number of outstanding echo msgs */ +static int lcp_echo_number = 0; /* ID number of next echo frame */ +static int lcp_echo_timer_running = 0; /* set if a timer is running */ static u_char nak_buffer[PPP_MRU]; /* where we construct a nak packet */ @@ -209,10 +217,10 @@ int lcp_loopbackfail = DEFLOOPBACKFAIL; */ #define CILEN_VOID 2 #define CILEN_CHAR 3 -#define CILEN_SHORT 4 /* CILEN_VOID + sizeof(short) */ -#define CILEN_CHAP 5 /* CILEN_VOID + sizeof(short) + 1 */ -#define CILEN_LONG 6 /* CILEN_VOID + sizeof(long) */ -#define CILEN_LQR 8 /* CILEN_VOID + sizeof(short) + sizeof(long) */ +#define CILEN_SHORT 4 /* CILEN_VOID + 2 */ +#define CILEN_CHAP 5 /* CILEN_VOID + 2 + 1 */ +#define CILEN_LONG 6 /* CILEN_VOID + 4 */ +#define CILEN_LQR 8 /* CILEN_VOID + 2 + 4 */ #define CILEN_CBCP 3 #define CODENAME(x) ((x) == CONFACK ? "ACK" : \ @@ -336,7 +344,7 @@ lcp_close(unit, reason) fsm *f = &lcp_fsm[unit]; if (phase != PHASE_DEAD) - phase = PHASE_TERMINATE; + new_phase(PHASE_TERMINATE); if (f->state == STOPPED && f->flags & (OPT_PASSIVE|OPT_SILENT)) { /* * This action is not strictly according to the FSM in RFC1548, @@ -457,7 +465,7 @@ lcp_rprotrej(f, inp, len) struct protent *protp; u_short prot; - if (len < sizeof (u_short)) { + if (len < 2) { LCPDEBUG(("lcp_rprotrej: Rcvd short Protocol-Reject packet!")); return; } @@ -530,9 +538,13 @@ static void lcp_resetci(f) fsm *f; { - lcp_wantoptions[f->unit].magicnumber = magic(); - lcp_wantoptions[f->unit].numloops = 0; - lcp_gotoptions[f->unit] = lcp_wantoptions[f->unit]; + lcp_options *wo = &lcp_wantoptions[f->unit]; + + wo->magicnumber = magic(); + wo->numloops = 0; + if (!wo->neg_multilink) + wo->neg_ssnhf = 0; + lcp_gotoptions[f->unit] = *wo; peer_mru[f->unit] = PPP_MRU; auth_reset(f->unit); } @@ -565,7 +577,10 @@ lcp_cilen(f) LENCICBCP(go->neg_cbcp) + LENCILONG(go->neg_magicnumber) + LENCIVOID(go->neg_pcompression) + - LENCIVOID(go->neg_accompression)); + LENCIVOID(go->neg_accompression) + + LENCISHORT(go->neg_multilink) + + LENCIVOID(go->neg_ssnhf) + + (go->neg_endpoint? CILEN_CHAR + go->endp_len: 0)); } @@ -618,6 +633,15 @@ lcp_addci(f, ucp, lenp) PUTCHAR(CILEN_CHAR, ucp); \ PUTCHAR(val, ucp); \ } +#define ADDCIENDP(opt, neg, class, val, len) \ + if (neg) { \ + int i; \ + PUTCHAR(opt, ucp); \ + PUTCHAR(CILEN_CHAR + len, ucp); \ + PUTCHAR(class, ucp); \ + for (i = 0; i < len; ++i) \ + PUTCHAR(val[i], ucp); \ + } ADDCISHORT(CI_MRU, go->neg_mru && go->mru != DEFMRU, go->mru); ADDCILONG(CI_ASYNCMAP, go->neg_asyncmap && go->asyncmap != 0xFFFFFFFF, @@ -629,6 +653,10 @@ lcp_addci(f, ucp, lenp) ADDCILONG(CI_MAGICNUMBER, go->neg_magicnumber, go->magicnumber); ADDCIVOID(CI_PCOMPRESSION, go->neg_pcompression); ADDCIVOID(CI_ACCOMPRESSION, go->neg_accompression); + ADDCISHORT(CI_MRRU, go->neg_multilink, go->mrru); + ADDCIVOID(CI_SSNHF, go->neg_ssnhf); + ADDCIENDP(CI_EPDISC, go->neg_endpoint, go->endp_class, go->endpoint, + go->endp_len); if (ucp - start_ucp != *lenp) { /* this should never happen, because peer_mtu should be 1500 */ @@ -742,6 +770,25 @@ lcp_ackci(f, p, len) if (cilong != val) \ goto bad; \ } +#define ACKCIENDP(opt, neg, class, val, vlen) \ + if (neg) { \ + int i; \ + if ((len -= CILEN_CHAR + vlen) < 0) \ + goto bad; \ + GETCHAR(citype, p); \ + GETCHAR(cilen, p); \ + if (cilen != CILEN_CHAR + vlen || \ + citype != opt) \ + goto bad; \ + GETCHAR(cichar, p); \ + if (cichar != class) \ + goto bad; \ + for (i = 0; i < vlen; ++i) { \ + GETCHAR(cichar, p); \ + if (cichar != val[i]) \ + goto bad; \ + } \ + } ACKCISHORT(CI_MRU, go->neg_mru && go->mru != DEFMRU, go->mru); ACKCILONG(CI_ASYNCMAP, go->neg_asyncmap && go->asyncmap != 0xFFFFFFFF, @@ -753,6 +800,10 @@ lcp_ackci(f, p, len) ACKCILONG(CI_MAGICNUMBER, go->neg_magicnumber, go->magicnumber); ACKCIVOID(CI_PCOMPRESSION, go->neg_pcompression); ACKCIVOID(CI_ACCOMPRESSION, go->neg_accompression); + ACKCISHORT(CI_MRRU, go->neg_multilink, go->mrru); + ACKCIVOID(CI_SSNHF, go->neg_ssnhf); + ACKCIENDP(CI_EPDISC, go->neg_endpoint, go->endp_class, go->endpoint, + go->endp_len); /* * If there are any remaining CIs, then this packet is bad. @@ -799,7 +850,7 @@ lcp_nakci(f, p, len) * Check packet length and CI length at each step. * If we find any deviations, then this packet is bad. */ -#define NAKCIVOID(opt, neg, code) \ +#define NAKCIVOID(opt, neg) \ if (go->neg && \ len >= CILEN_VOID && \ p[1] == CILEN_VOID && \ @@ -807,7 +858,7 @@ lcp_nakci(f, p, len) len -= CILEN_VOID; \ INCPTR(CILEN_VOID, p); \ no.neg = 1; \ - code \ + try.neg = 0; \ } #define NAKCICHAP(opt, neg, code) \ if (go->neg && \ @@ -866,6 +917,17 @@ lcp_nakci(f, p, len) no.neg = 1; \ code \ } +#define NAKCIENDP(opt, neg) \ + if (go->neg && \ + len >= CILEN_CHAR && \ + p[0] == opt && \ + p[1] >= CILEN_CHAR && \ + p[1] <= len) { \ + len -= p[1]; \ + INCPTR(p[1], p); \ + no.neg = 1; \ + try.neg = 0; \ + } /* * We don't care if they want to send us smaller packets than @@ -919,11 +981,18 @@ lcp_nakci(f, p, len) if (go->neg_chap) { /* * We were asking for CHAP/MD5; they must want a different - * algorithm. If they can't do MD5, we'll have to stop + * algorithm. If they can't do MD5, we can ask for M$-CHAP + * if we support it, otherwise we'll have to stop * asking for CHAP. */ - if (cichar != go->chap_mdtype) - try.neg_chap = 0; + if (cichar != go->chap_mdtype) { +#ifdef CHAPMS + if (cichar == CHAP_MICROSOFT) + go->chap_mdtype = CHAP_MICROSOFT; + else +#endif /* CHAPMS */ + try.neg_chap = 0; + } } else { /* * Stop asking for PAP if we were asking for it. @@ -976,12 +1045,31 @@ lcp_nakci(f, p, len) * 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, - try.neg_pcompression = 0; - ); - NAKCIVOID(CI_ACCOMPRESSION, neg_accompression, - try.neg_accompression = 0; - ); + 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_multilink) { + NAKCISHORT(CI_MRRU, neg_multilink, + 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 @@ -1012,8 +1100,10 @@ lcp_nakci(f, p, len) || no.neg_mru || cilen != CILEN_SHORT) goto bad; GETSHORT(cishort, p); - if (cishort < DEFMRU) + if (cishort < DEFMRU) { + try.neg_mru = 1; try.mru = cishort; + } break; case CI_ASYNCMAP: if ((go->neg_asyncmap && go->asyncmap != 0xFFFFFFFF) @@ -1043,6 +1133,19 @@ lcp_nakci(f, p, len) if (go->neg_lqr || no.neg_lqr || cilen != CILEN_LQR) goto bad; break; + case CI_MRRU: + if (go->neg_multilink || no.neg_multilink || 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; } @@ -1056,6 +1159,7 @@ lcp_nakci(f, p, len) if (++try.numloops >= lcp_loopbackfail) { notice("Serial line is looped back."); lcp_close(f->unit, "Loopback detected"); + status = EXIT_LOOPBACK; } } else try.numloops = 0; @@ -1175,6 +1279,24 @@ lcp_rejci(f, p, len) 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(p[1], 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); @@ -1187,6 +1309,10 @@ lcp_rejci(f, p, len) REJCILONG(CI_MAGICNUMBER, neg_magicnumber, go->magicnumber); REJCIVOID(CI_PCOMPRESSION, neg_pcompression); REJCIVOID(CI_ACCOMPRESSION, neg_accompression); + REJCISHORT(CI_MRRU, neg_multilink, go->mrru); + REJCIVOID(CI_SSNHF, neg_ssnhf); + REJCIENDP(CI_EPDISC, neg_endpoint, go->endp_class, go->endpoint, + go->endp_len); /* * If there are any remaining CIs, then this packet is bad. @@ -1323,7 +1449,7 @@ lcp_reqci(f, inp, lenp, reject_if_disagree) GETSHORT(cishort, p); /* - * Authtype must be UPAP or CHAP. + * 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 @@ -1346,6 +1472,8 @@ lcp_reqci(f, inp, lenp, reject_if_disagree) 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; @@ -1467,6 +1595,44 @@ lcp_reqci(f, inp, lenp, reject_if_disagree) ho->neg_accompression = 1; break; + case CI_MRRU: + if (!ao->neg_multilink || + cilen != CILEN_SHORT) { + orc = CONFREJ; + break; + } + + GETSHORT(cishort, p); + /* possibly should insist on a minimum/maximum MRRU here */ + ho->neg_multilink = 1; + ho->mrru = cishort; + break; + + case CI_SSNHF: + if (!ao->neg_ssnhf || + cilen != CILEN_VOID) { + orc = CONFREJ; + break; + } + ho->neg_ssnhf = 1; + break; + + case CI_EPDISC: + if (!ao->neg_endpoint || + cilen < CILEN_CHAR || + cilen > CILEN_CHAR + MAX_ENDP_LEN) { + orc = CONFREJ; + break; + } + GETCHAR(cichar, p); + cilen -= CILEN_CHAR; + ho->neg_endpoint = 1; + ho->endp_class = cichar; + ho->endp_len = cilen; + BCOPY(p, ho->endpoint, cilen); + INCPTR(cilen, p); + break; + default: LCPDEBUG(("lcp_reqci: rcvd unknown option %d", citype)); orc = CONFREJ; @@ -1617,6 +1783,10 @@ static char *lcp_codenames[] = { "EchoReq", "EchoRep", "DiscReq" }; +static char *endp_class_names[] = { + "null", "local", "IP", "MAC", "magic", "phone" +}; + static int lcp_printpkt(p, plen, printer, arg) u_char *p; @@ -1624,8 +1794,9 @@ lcp_printpkt(p, plen, printer, arg) void (*printer) __P((void *, char *, ...)); void *arg; { - int code, id, len, olen; + int code, id, len, olen, i; u_char *pstart, *optend; + u_char cichar; u_short cishort; u_int32_t cilong; @@ -1753,6 +1924,30 @@ lcp_printpkt(p, plen, printer, arg) printer(arg, "accomp"); } break; + case CI_MRRU: + if (olen == CILEN_SHORT) { + p += 2; + GETSHORT(cishort, p); + printer(arg, "mrru %d", cishort); + } + break; + case CI_SSNHF: + if (olen == CILEN_VOID) { + p += 2; + printer(arg, "ssnhf"); + } + break; + case CI_EPDISC: + if (olen >= CILEN_CHAR) { + p += 2; + GETCHAR(cichar, p); + if (cichar <= 5) + printer(arg, "endpoint [%s]:", + endp_class_names[cichar]); + else + printer(arg, "endpoint [%d]:"); + } + break; } while (p < optend) { GETCHAR(code, p); @@ -1785,10 +1980,14 @@ lcp_printpkt(p, plen, printer, arg) } /* print the rest of the bytes in the packet */ - for (; len > 0; --len) { + for (i = 0; i < len && i < 32; ++i) { GETCHAR(code, p); printer(arg, " %.2x", code); } + if (i < len) { + printer(arg, " ..."); + p += len - i; + } return p - pstart; } @@ -1818,6 +2017,8 @@ LcpEchoCheck (f) fsm *f; { LcpSendEchoRequest (f); + if (f->state != OPENED) + return; /* * Start the timer for the next interval. @@ -1849,7 +2050,9 @@ LcpEchoTimeout (arg) static void lcp_received_echo_reply (f, id, inp, len) fsm *f; - int id; u_char *inp; int len; + int id; + u_char *inp; + int len; { u_int32_t magic;