X-Git-Url: https://git.ozlabs.org/?p=ppp.git;a=blobdiff_plain;f=pppd%2Flcp.c;h=d7ea47106376cc3e3a43a6c7d55ed40a137994c2;hp=e44a78125dde573b62bad33c87b966dfcfdca78a;hb=e7ee3ad1743d34cb6fdf0773e6a73e9d8bf15216;hpb=cb67581446e926290c6147634f7f467f48c806b5 diff --git a/pppd/lcp.c b/pppd/lcp.c index e44a781..d7ea471 100644 --- a/pppd/lcp.c +++ b/pppd/lcp.c @@ -40,7 +40,7 @@ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#define RCSID "$Id: lcp.c,v 1.65 2003/03/03 05:11:46 paulus Exp $" +#define RCSID "$Id: lcp.c,v 1.76 2006/05/22 00:04:07 paulus Exp $" /* * TODO: @@ -53,10 +53,9 @@ #include "pppd.h" #include "fsm.h" #include "lcp.h" -#include "chap.h" +#include "chap-new.h" #include "magic.h" -static const char rcsid[] = RCSID; /* * When the link comes up we want to be able to wait for a short while, @@ -73,6 +72,7 @@ static void lcp_delayed_up __P((void *)); */ int lcp_echo_interval = 0; /* Interval between LCP echo-requests */ int lcp_echo_fails = 0; /* Tolerance to unanswered echo-requests */ +bool lcp_echo_adaptive = 0; /* request echo only if the link was idle */ bool lax_recv = 0; /* accept control chars in asyncmap */ bool noendpoint = 0; /* don't send/accept endpoint discriminator */ @@ -151,6 +151,8 @@ static option_t lcp_option_list[] = { OPT_PRIO }, { "lcp-echo-interval", o_int, &lcp_echo_interval, "Set time in seconds between LCP echo requests", OPT_PRIO }, + { "lcp-echo-adaptive", o_bool, &lcp_echo_adaptive, + "Suppress LCP echo requests if traffic was received", 1 }, { "lcp-restart", o_int, &lcp_fsm[0].timeouttime, "Set time in seconds between LCP retransmissions", OPT_PRIO }, { "lcp-max-terminate", o_int, &lcp_fsm[0].maxtermtransmits, @@ -206,7 +208,7 @@ static void lcp_resetci __P((fsm *)); /* Reset our CI */ static int lcp_cilen __P((fsm *)); /* Return length of our CI */ static void lcp_addci __P((fsm *, u_char *, int *)); /* Add our CI to pkt */ static int lcp_ackci __P((fsm *, u_char *, int)); /* Peer ack'd our CI */ -static int lcp_nakci __P((fsm *, u_char *, int)); /* Peer nak'd our CI */ +static int lcp_nakci __P((fsm *, u_char *, int, int)); /* Peer nak'd our CI */ static int lcp_rejci __P((fsm *, u_char *, int)); /* Peer rej'd our CI */ static int lcp_reqci __P((fsm *, u_char *, int *, int)); /* Rcv peer CI */ static void lcp_up __P((fsm *)); /* We're UP */ @@ -359,15 +361,12 @@ lcp_init(unit) ao->mru = MAXMRU; ao->neg_asyncmap = 1; ao->neg_chap = 1; - ao->chap_mdtype = MDTYPE_ALL; + ao->chap_mdtype = chap_mdtype_all; ao->neg_upap = 1; ao->neg_eap = 1; ao->neg_magicnumber = 1; ao->neg_pcompression = 1; ao->neg_accompression = 1; -#ifdef CBCP_SUPPORT - ao->neg_cbcp = 1; -#endif ao->neg_endpoint = 1; } @@ -400,21 +399,29 @@ lcp_close(unit, reason) char *reason; { fsm *f = &lcp_fsm[unit]; + int oldstate; - if (phase != PHASE_DEAD) + if (phase != PHASE_DEAD && phase != PHASE_MASTER) new_phase(PHASE_TERMINATE); - if (f->state == STOPPED && f->flags & (OPT_PASSIVE|OPT_SILENT)) { + + if (f->flags & DELAYED_UP) { + untimeout(lcp_delayed_up, f); + f->state = STOPPED; + } + oldstate = f->state; + + fsm_close(f, reason); + if (oldstate == STOPPED && f->flags & (OPT_PASSIVE|OPT_SILENT|DELAYED_UP)) { /* * This action is not strictly according to the FSM in RFC1548, * but it does mean that the program terminates if you do a - * lcp_close() in passive/silent mode when a connection hasn't - * been established. + * lcp_close() when a connection hasn't been established + * because we are in passive/silent mode or because we have + * delayed the fsm_lowerup() call and it hasn't happened yet. */ - f->state = CLOSED; + f->flags &= ~DELAYED_UP; lcp_finished(f); - - } else - fsm_close(&lcp_fsm[unit], reason); + } } @@ -456,9 +463,10 @@ lcp_lowerdown(unit) { fsm *f = &lcp_fsm[unit]; - if (f->flags & DELAYED_UP) + if (f->flags & DELAYED_UP) { f->flags &= ~DELAYED_UP; - else + untimeout(lcp_delayed_up, f); + } else fsm_lowerdown(&lcp_fsm[unit]); } @@ -492,12 +500,12 @@ lcp_input(unit, p, len) if (f->flags & DELAYED_UP) { f->flags &= ~DELAYED_UP; + untimeout(lcp_delayed_up, f); fsm_lowerup(f); } fsm_input(f, p, len); } - /* * lcp_extcode - Handle a LCP-specific code. */ @@ -528,6 +536,8 @@ lcp_extcode(f, code, id, inp, len) break; case DISCREQ: + case IDENTIF: + case TIMEREM: break; default: @@ -551,6 +561,7 @@ lcp_rprotrej(f, inp, len) int i; struct protent *protp; u_short prot; + const char *pname; if (len < 2) { LCPDEBUG(("lcp_rprotrej: Rcvd short Protocol-Reject packet!")); @@ -568,16 +579,27 @@ lcp_rprotrej(f, inp, len) return; } + pname = protocol_name(prot); + /* * Upcall the proper Protocol-Reject routine. */ for (i = 0; (protp = protocols[i]) != NULL; ++i) if (protp->protocol == prot && protp->enabled_flag) { + if (pname == NULL) + dbglog("Protocol-Reject for 0x%x received", prot); + else + dbglog("Protocol-Reject for '%s' (0x%x) received", pname, + prot); (*protp->protrej)(f->unit); return; } - warn("Protocol-Reject for unsupported protocol 0x%x", prot); + if (pname == NULL) + warn("Protocol-Reject for unsupported protocol 0x%x", prot); + else + warn("Protocol-Reject for unsupported protocol '%s' (0x%x)", pname, + prot); } @@ -927,10 +949,11 @@ bad: * 1 - Nak was good. */ static int -lcp_nakci(f, p, len) +lcp_nakci(f, p, len, treat_as_reject) fsm *f; u_char *p; int len; + int treat_as_reject; { lcp_options *go = &lcp_gotoptions[f->unit]; lcp_options *wo = &lcp_wantoptions[f->unit]; @@ -1029,6 +1052,10 @@ lcp_nakci(f, p, len) try.neg = 0; \ } + /* + * NOTE! There must be no assignments to individual fields of *go in + * the code below. Any such assignment is a BUG! + */ /* * 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, @@ -1089,7 +1116,7 @@ lcp_nakci(f, p, len) try.neg_eap = 0; /* Try to set up to use their suggestion, if possible */ if (CHAP_CANDIGEST(go->chap_mdtype, cichar)) - go->chap_mdtype = CHAP_MDTYPE_D(cichar); + try.chap_mdtype = CHAP_MDTYPE_D(cichar); } else if (go->neg_chap) { /* * We were asking for our preferred algorithm, they must @@ -1098,7 +1125,7 @@ lcp_nakci(f, p, len) if (cichar != CHAP_DIGEST(go->chap_mdtype)) { if (CHAP_CANDIGEST(go->chap_mdtype, cichar)) { /* Use their suggestion if we support it ... */ - go->chap_mdtype = CHAP_MDTYPE_D(cichar); + try.chap_mdtype = CHAP_MDTYPE_D(cichar); } else { /* ... otherwise, try our next-preferred algorithm. */ try.chap_mdtype &= ~(CHAP_MDTYPE(try.chap_mdtype)); @@ -1183,7 +1210,9 @@ lcp_nakci(f, p, len) */ if (go->neg_mrru) { NAKCISHORT(CI_MRRU, neg_mrru, - if (cishort <= wo->mrru) + if (treat_as_reject) + try.neg_mrru = 0; + else if (cishort <= wo->mrru) try.mrru = cishort; ); } @@ -1216,7 +1245,7 @@ lcp_nakci(f, p, len) * 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) { + while (len >= CILEN_VOID) { GETCHAR(citype, p); GETCHAR(cilen, p); if (cilen < CILEN_VOID || (len -= cilen) < 0) @@ -1288,8 +1317,8 @@ lcp_nakci(f, p, len) if (looped_back) { if (++try.numloops >= lcp_loopbackfail) { notice("Serial line is looped back."); - lcp_close(f->unit, "Loopback detected"); status = EXIT_LOOPBACK; + lcp_close(f->unit, "Loopback detected"); } } else try.numloops = 0; @@ -1603,11 +1632,11 @@ lcp_reqci(f, inp, lenp, reject_if_disagree) } if (!ao->neg_upap) { /* we don't want to do PAP */ orc = CONFNAK; /* NAK it and suggest CHAP or EAP */ + PUTCHAR(CI_AUTHTYPE, nakp); if (ao->neg_eap) { PUTCHAR(CILEN_SHORT, nakp); PUTSHORT(PPP_EAP, nakp); } else { - PUTCHAR(CI_AUTHTYPE, nakp); PUTCHAR(CILEN_CHAP, nakp); PUTSHORT(PPP_CHAP, nakp); PUTCHAR(CHAP_DIGEST(ao->chap_mdtype), nakp); @@ -1666,7 +1695,7 @@ lcp_reqci(f, inp, lenp, reject_if_disagree) if (ao->neg_chap) { PUTCHAR(CILEN_CHAP, nakp); PUTSHORT(PPP_CHAP, nakp); - PUTCHAR(ao->chap_mdtype, nakp); + PUTCHAR(CHAP_DIGEST(ao->chap_mdtype), nakp); } else { PUTCHAR(CILEN_SHORT, nakp); PUTSHORT(PPP_PAP, nakp); @@ -1960,7 +1989,8 @@ lcp_finished(f) static char *lcp_codenames[] = { "ConfReq", "ConfAck", "ConfNak", "ConfRej", "TermReq", "TermAck", "CodeRej", "ProtRej", - "EchoReq", "EchoRep", "DiscReq" + "EchoReq", "EchoRep", "DiscReq", "Ident", + "TimeRem" }; static int @@ -2034,11 +2064,10 @@ lcp_printpkt(p, plen, printer, arg) printer(arg, "chap"); if (p < optend) { switch (*p) { - case CHAP_DIGEST_MD5: + case CHAP_MD5: printer(arg, " MD5"); ++p; break; -#ifdef CHAPMS case CHAP_MICROSOFT: printer(arg, " MS"); ++p; @@ -2048,7 +2077,6 @@ lcp_printpkt(p, plen, printer, arg) printer(arg, " MS-v2"); ++p; break; -#endif } } break; @@ -2164,10 +2192,31 @@ lcp_printpkt(p, plen, printer, arg) if (len >= 4) { GETLONG(cilong, p); printer(arg, " magic=0x%x", cilong); - p += 4; len -= 4; } break; + + case IDENTIF: + case TIMEREM: + if (len >= 4) { + GETLONG(cilong, p); + printer(arg, " magic=0x%x", cilong); + len -= 4; + } + if (code == TIMEREM) { + if (len < 4) + break; + GETLONG(cilong, p); + printer(arg, " seconds=%u", cilong); + len -= 4; + } + if (len > 0) { + printer(arg, " "); + print_string((char *)p, len, printer, arg); + p += len; + len = 0; + } + break; } /* print the rest of the bytes in the packet */ @@ -2194,8 +2243,8 @@ void LcpLinkFailure (f) if (f->state == OPENED) { info("No response to %d echo-requests", lcp_echos_pending); notice("Serial link appears to be disconnected."); - lcp_close(f->unit, "Peer not responding"); status = EXIT_PEER_DEAD; + lcp_close(f->unit, "Peer not responding"); } } @@ -2284,6 +2333,20 @@ LcpSendEchoRequest (f) } } + /* + * If adaptive echos have been enabled, only send the echo request if + * no traffic was received since the last one. + */ + if (lcp_echo_adaptive) { + static unsigned int last_pkts_in = 0; + struct pppd_stats cur_stats; + + if (get_ppp_stats(f->unit, &cur_stats) && cur_stats.pkts_in != last_pkts_in) { + last_pkts_in = cur_stats.pkts_in; + return; + } + } + /* * Make and send the echo request frame. */