* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
-#define RCSID "$Id: lcp.c,v 1.50 2000/04/05 00:58:28 paulus Exp $";
+#define RCSID "$Id: lcp.c,v 1.60 2002/04/02 13:54:59 dfs Exp $"
/*
* TODO:
static const char rcsid[] = RCSID;
+/*
+ * When the link comes up we want to be able to wait for a short while,
+ * or until seeing some input from the peer, before starting to send
+ * configure-requests. We do this by delaying the fsm_lowerup call.
+ */
+/* steal a bit in fsm flags word */
+#define DELAYED_UP 0x100
+
+static void lcp_delayed_up __P((void *));
+
/*
* LCP-related command-line options.
*/
int lcp_echo_interval = 0; /* Interval between LCP echo-requests */
int lcp_echo_fails = 0; /* Tolerance to unanswered echo-requests */
bool lax_recv = 0; /* accept control chars in asyncmap */
+bool noendpoint = 0; /* don't send/accept endpoint discriminator */
-static int setescape __P((char **));
+static int noopt __P((char **));
#ifdef HAVE_MULTILINK
-bool noendpoint = 0; /* don't send/accept endpoint discriminator */
static int setendpoint __P((char **));
+static void printendpoint __P((option_t *, void (*)(void *, char *, ...),
+ void *));
#endif /* HAVE_MULTILINK */
static option_t lcp_option_list[] = {
/* LCP options */
+ { "-all", o_special_noarg, (void *)noopt,
+ "Don't request/allow any LCP options" },
+
{ "noaccomp", o_bool, &lcp_wantoptions[0].neg_accompression,
"Disable address/control compression",
- OPT_A2COPY, &lcp_allowoptions[0].neg_accompression },
+ OPT_A2CLR, &lcp_allowoptions[0].neg_accompression },
{ "-ac", o_bool, &lcp_wantoptions[0].neg_accompression,
"Disable address/control compression",
- OPT_A2COPY, &lcp_allowoptions[0].neg_accompression },
- { "default-asyncmap", o_bool, &lcp_wantoptions[0].neg_asyncmap,
- "Disable asyncmap negotiation",
- OPT_A2COPY, &lcp_allowoptions[0].neg_asyncmap },
- { "-am", o_bool, &lcp_wantoptions[0].neg_asyncmap,
- "Disable asyncmap negotiation",
- OPT_A2COPY, &lcp_allowoptions[0].neg_asyncmap },
+ OPT_ALIAS | OPT_A2CLR, &lcp_allowoptions[0].neg_accompression },
+
{ "asyncmap", o_uint32, &lcp_wantoptions[0].asyncmap,
"Set asyncmap (for received packets)",
OPT_OR, &lcp_wantoptions[0].neg_asyncmap },
{ "-as", o_uint32, &lcp_wantoptions[0].asyncmap,
"Set asyncmap (for received packets)",
- OPT_OR, &lcp_wantoptions[0].neg_asyncmap },
+ OPT_ALIAS | OPT_OR, &lcp_wantoptions[0].neg_asyncmap },
+ { "default-asyncmap", o_uint32, &lcp_wantoptions[0].asyncmap,
+ "Disable asyncmap negotiation",
+ OPT_OR | OPT_NOARG | OPT_VAL(~0U) | OPT_A2CLR,
+ &lcp_allowoptions[0].neg_asyncmap },
+ { "-am", o_uint32, &lcp_wantoptions[0].asyncmap,
+ "Disable asyncmap negotiation",
+ OPT_ALIAS | OPT_OR | OPT_NOARG | OPT_VAL(~0U) | OPT_A2CLR,
+ &lcp_allowoptions[0].neg_asyncmap },
+
{ "nomagic", o_bool, &lcp_wantoptions[0].neg_magicnumber,
"Disable magic number negotiation (looped-back line detection)",
- OPT_A2COPY, &lcp_allowoptions[0].neg_magicnumber },
+ OPT_A2CLR, &lcp_allowoptions[0].neg_magicnumber },
{ "-mn", o_bool, &lcp_wantoptions[0].neg_magicnumber,
"Disable magic number negotiation (looped-back line detection)",
- OPT_A2COPY, &lcp_allowoptions[0].neg_magicnumber },
+ OPT_ALIAS | OPT_A2CLR, &lcp_allowoptions[0].neg_magicnumber },
+
+ { "mru", o_int, &lcp_wantoptions[0].mru,
+ "Set MRU (maximum received packet size) for negotiation",
+ OPT_PRIO, &lcp_wantoptions[0].neg_mru },
{ "default-mru", o_bool, &lcp_wantoptions[0].neg_mru,
"Disable MRU negotiation (use default 1500)",
- OPT_A2COPY, &lcp_allowoptions[0].neg_mru },
+ OPT_PRIOSUB | OPT_A2CLR, &lcp_allowoptions[0].neg_mru },
{ "-mru", o_bool, &lcp_wantoptions[0].neg_mru,
"Disable MRU negotiation (use default 1500)",
- OPT_A2COPY, &lcp_allowoptions[0].neg_mru },
- { "mru", o_int, &lcp_wantoptions[0].mru,
- "Set MRU (maximum received packet size) for negotiation",
- 0, &lcp_wantoptions[0].neg_mru },
+ OPT_ALIAS | OPT_PRIOSUB | OPT_A2CLR, &lcp_allowoptions[0].neg_mru },
+
+ { "mtu", o_int, &lcp_allowoptions[0].mru,
+ "Set our MTU", OPT_LIMITS, NULL, MAXMRU, MINMRU },
+
{ "nopcomp", o_bool, &lcp_wantoptions[0].neg_pcompression,
"Disable protocol field compression",
- OPT_A2COPY, &lcp_allowoptions[0].neg_pcompression },
+ OPT_A2CLR, &lcp_allowoptions[0].neg_pcompression },
{ "-pc", o_bool, &lcp_wantoptions[0].neg_pcompression,
"Disable protocol field compression",
- OPT_A2COPY, &lcp_allowoptions[0].neg_pcompression },
- { "-p", o_bool, &lcp_wantoptions[0].passive,
- "Set passive mode", 1 },
+ OPT_ALIAS | OPT_A2CLR, &lcp_allowoptions[0].neg_pcompression },
+
{ "passive", o_bool, &lcp_wantoptions[0].passive,
"Set passive mode", 1 },
+ { "-p", o_bool, &lcp_wantoptions[0].passive,
+ "Set passive mode", OPT_ALIAS | 1 },
+
{ "silent", o_bool, &lcp_wantoptions[0].silent,
"Set silent mode", 1 },
- { "escape", o_special, setescape,
- "List of character codes to escape on transmission" },
+
{ "lcp-echo-failure", o_int, &lcp_echo_fails,
- "Set number of consecutive echo failures to indicate link failure" },
+ "Set number of consecutive echo failures to indicate link failure",
+ OPT_PRIO },
{ "lcp-echo-interval", o_int, &lcp_echo_interval,
- "Set time in seconds between LCP echo requests" },
+ "Set time in seconds between LCP echo requests", OPT_PRIO },
{ "lcp-restart", o_int, &lcp_fsm[0].timeouttime,
- "Set time in seconds between LCP retransmissions" },
+ "Set time in seconds between LCP retransmissions", OPT_PRIO },
{ "lcp-max-terminate", o_int, &lcp_fsm[0].maxtermtransmits,
- "Set maximum number of LCP terminate-request transmissions" },
+ "Set maximum number of LCP terminate-request transmissions", OPT_PRIO },
{ "lcp-max-configure", o_int, &lcp_fsm[0].maxconfreqtransmits,
- "Set maximum number of LCP configure-request transmissions" },
+ "Set maximum number of LCP configure-request transmissions", OPT_PRIO },
{ "lcp-max-failure", o_int, &lcp_fsm[0].maxnakloops,
- "Set limit on number of LCP configure-naks" },
+ "Set limit on number of LCP configure-naks", OPT_PRIO },
+
{ "receive-all", o_bool, &lax_recv,
"Accept all received control characters", 1 },
+
#ifdef HAVE_MULTILINK
{ "mrru", o_int, &lcp_wantoptions[0].mrru,
"Maximum received packet size for multilink bundle",
- 0, &lcp_wantoptions[0].neg_mrru },
+ OPT_PRIO, &lcp_wantoptions[0].neg_mrru },
+
{ "mpshortseq", o_bool, &lcp_wantoptions[0].neg_ssnhf,
"Use short sequence numbers in multilink headers",
- OPT_A2COPY | 1, &lcp_allowoptions[0].neg_ssnhf },
+ OPT_PRIO | 1, &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 },
- { "endpoint", o_special, setendpoint,
- "Endpoint discriminator for multilink" },
+ OPT_PRIOSUB | OPT_A2CLR, &lcp_allowoptions[0].neg_ssnhf },
+
+ { "endpoint", o_special, (void *) setendpoint,
+ "Endpoint discriminator for multilink",
+ OPT_PRIO | OPT_A2PRINTER, (void *) printendpoint },
+#endif /* HAVE_MULTILINK */
+
{ "noendpoint", o_bool, &noendpoint,
"Don't send or accept multilink endpoint discriminator", 1 },
-#endif /* HAVE_MULTILINK */
+
{NULL}
};
lcp_options lcp_gotoptions[NUM_PPP]; /* Options that peer ack'd */
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 int lcp_echos_pending = 0; /* Number of outstanding echo msgs */
static int lcp_echo_number = 0; /* ID number of next echo frame */
#define CODENAME(x) ((x) == CONFACK ? "ACK" : \
(x) == CONFNAK ? "NAK" : "REJ")
-
/*
- * setescape - add chars to the set we escape on transmission.
+ * noopt - Disable all options (why?).
*/
static int
-setescape(argv)
+noopt(argv)
char **argv;
{
- int n, ret;
- char *p, *endp;
-
- p = *argv;
- ret = 1;
- while (*p) {
- n = strtol(p, &endp, 16);
- if (p == endp) {
- option_error("escape parameter contains invalid hex number '%s'",
- p);
- return 0;
- }
- p = endp;
- if (n < 0 || n == 0x5E || n > 0xFF) {
- option_error("can't escape character 0x%x", n);
- ret = 0;
- } else
- xmit_accm[0][n >> 5] |= 1 << (n & 0x1F);
- while (*p == ',' || *p == ' ')
- ++p;
- }
- return ret;
+ BZERO((char *) &lcp_wantoptions[0], sizeof (struct lcp_options));
+ BZERO((char *) &lcp_allowoptions[0], sizeof (struct lcp_options));
+
+ return (1);
}
#ifdef HAVE_MULTILINK
option_error("Can't parse '%s' as an endpoint discriminator", *argv);
return 0;
}
+
+static void
+printendpoint(opt, printer, arg)
+ option_t *opt;
+ void (*printer) __P((void *, char *, ...));
+ void *arg;
+{
+ printer(arg, "%s", epdisc_to_str(&lcp_wantoptions[0].endpoint));
+}
#endif /* HAVE_MULTILINK */
/*
wo->neg_mru = 1;
wo->mru = DEFMRU;
wo->neg_asyncmap = 1;
- wo->chap_mdtype = CHAP_DIGEST_MD5;
wo->neg_magicnumber = 1;
wo->neg_pcompression = 1;
wo->neg_accompression = 1;
ao->mru = MAXMRU;
ao->neg_asyncmap = 1;
ao->neg_chap = 1;
- ao->chap_mdtype = CHAP_DIGEST_MD5;
+ ao->chap_mdtype = MDTYPE_ALL;
ao->neg_upap = 1;
ao->neg_magicnumber = 1;
ao->neg_pcompression = 1;
#ifdef CBCP_SUPPORT
ao->neg_cbcp = 1;
#endif
-#ifdef HAVE_MULTILINK
ao->neg_endpoint = 1;
-#endif
-
- BZERO(xmit_accm[unit], sizeof(xmit_accm[0]));
- xmit_accm[unit][3] = 0x60000000;
}
fsm *f = &lcp_fsm[unit];
lcp_options *wo = &lcp_wantoptions[unit];
- f->flags = 0;
+ f->flags &= ~(OPT_PASSIVE | OPT_SILENT);
if (wo->passive)
f->flags |= OPT_PASSIVE;
if (wo->silent)
int unit;
{
lcp_options *wo = &lcp_wantoptions[unit];
+ fsm *f = &lcp_fsm[unit];
/*
* Don't use A/C or protocol compression on transmission,
* but accept A/C and protocol compressed packets
* if we are going to ask for A/C and protocol compression.
*/
- ppp_set_xaccm(unit, xmit_accm[unit]);
ppp_send_config(unit, PPP_MRU, 0xffffffff, 0, 0);
ppp_recv_config(unit, PPP_MRU, (lax_recv? 0: 0xffffffff),
wo->neg_pcompression, wo->neg_accompression);
peer_mru[unit] = PPP_MRU;
- lcp_allowoptions[unit].asyncmap = xmit_accm[unit][0];
- fsm_lowerup(&lcp_fsm[unit]);
+ if (listen_time != 0) {
+ f->flags |= DELAYED_UP;
+ timeout(lcp_delayed_up, f, 0, listen_time * 1000);
+ } else
+ fsm_lowerup(f);
}
lcp_lowerdown(unit)
int unit;
{
- fsm_lowerdown(&lcp_fsm[unit]);
+ fsm *f = &lcp_fsm[unit];
+
+ if (f->flags & DELAYED_UP)
+ f->flags &= ~DELAYED_UP;
+ else
+ fsm_lowerdown(&lcp_fsm[unit]);
+}
+
+
+/*
+ * lcp_delayed_up - Bring the lower layer up now.
+ */
+static void
+lcp_delayed_up(arg)
+ void *arg;
+{
+ fsm *f = arg;
+
+ if (f->flags & DELAYED_UP) {
+ f->flags &= ~DELAYED_UP;
+ fsm_lowerup(f);
+ }
}
{
fsm *f = &lcp_fsm[unit];
+ if (f->flags & DELAYED_UP) {
+ f->flags &= ~DELAYED_UP;
+ fsm_lowerup(f);
+ }
fsm_input(f, p, len);
}
{
lcp_options *wo = &lcp_wantoptions[f->unit];
lcp_options *go = &lcp_gotoptions[f->unit];
+ lcp_options *ao = &lcp_allowoptions[f->unit];
wo->magicnumber = magic();
wo->numloops = 0;
go->neg_ssnhf = 0;
go->neg_endpoint = 0;
}
+ if (noendpoint)
+ ao->neg_endpoint = 0;
peer_mru[f->unit] = PPP_MRU;
auth_reset(f->unit);
}
}
#define ADDCICHAP(opt, neg, val, digest) \
if (neg) { \
- PUTCHAR(opt, ucp); \
+ PUTCHAR((opt), ucp); \
PUTCHAR(CILEN_CHAP, ucp); \
- PUTSHORT(val, ucp); \
- PUTCHAR(digest, ucp); \
+ PUTSHORT((val), ucp); \
+ PUTCHAR((digest), ucp); \
}
#define ADDCILONG(opt, neg, val) \
if (neg) { \
ADDCISHORT(CI_MRU, go->neg_mru && go->mru != DEFMRU, go->mru);
ADDCILONG(CI_ASYNCMAP, go->neg_asyncmap && go->asyncmap != 0xFFFFFFFF,
go->asyncmap);
- ADDCICHAP(CI_AUTHTYPE, go->neg_chap, PPP_CHAP, go->chap_mdtype);
+ ADDCICHAP(CI_AUTHTYPE, go->neg_chap, PPP_CHAP,CHAP_DIGEST(go->chap_mdtype));
ADDCISHORT(CI_AUTHTYPE, !go->neg_chap && go->neg_upap, PPP_PAP);
ADDCILQR(CI_QUALITY, go->neg_lqr, go->lqr_period);
ADDCICHAR(CI_CALLBACK, go->neg_cbcp, CBCP_OPT);
GETCHAR(citype, p); \
GETCHAR(cilen, p); \
if (cilen != CILEN_CHAP || \
- citype != opt) \
+ citype != (opt)) \
goto bad; \
GETSHORT(cishort, p); \
- if (cishort != val) \
+ if (cishort != (val)) \
goto bad; \
GETCHAR(cichar, p); \
- if (cichar != digest) \
+ if (cichar != (digest)) \
goto bad; \
}
#define ACKCILONG(opt, neg, val) \
ACKCISHORT(CI_MRU, go->neg_mru && go->mru != DEFMRU, go->mru);
ACKCILONG(CI_ASYNCMAP, go->neg_asyncmap && go->asyncmap != 0xFFFFFFFF,
go->asyncmap);
- ACKCICHAP(CI_AUTHTYPE, go->neg_chap, PPP_CHAP, go->chap_mdtype);
+ ACKCICHAP(CI_AUTHTYPE, go->neg_chap, PPP_CHAP,CHAP_DIGEST(go->chap_mdtype));
ACKCISHORT(CI_AUTHTYPE, !go->neg_chap && go->neg_upap, PPP_PAP);
ACKCILQR(CI_QUALITY, go->neg_lqr, go->lqr_period);
ACKCICHAR(CI_CALLBACK, go->neg_cbcp, CBCP_OPT);
no.neg_chap = go->neg_chap;
no.neg_upap = go->neg_upap;
INCPTR(2, p);
- GETSHORT(cishort, p);
+ GETSHORT(cishort, p);
if (cishort == PPP_PAP && cilen == CILEN_SHORT) {
/*
* If we were asking for CHAP, they obviously don't want to do it.
GETCHAR(cichar, p);
if (go->neg_chap) {
/*
- * We were asking for CHAP/MD5; they must want a different
- * 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.
+ * We were asking for our preferred algorithm, they must
+ * want something different.
*/
- if (cichar != go->chap_mdtype) {
-#ifdef CHAPMS
- if (cichar == CHAP_MICROSOFT)
- go->chap_mdtype = CHAP_MICROSOFT;
- else
-#endif /* CHAPMS */
- try.neg_chap = 0;
+ 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);
+ } else {
+ /* ... otherwise, try our next-preferred algorithm. */
+ go->chap_mdtype &= ~(CHAP_MDTYPE(go->chap_mdtype));
+ if (go->chap_mdtype == MDTYPE_NONE) /* out of algos */
+ try.neg_chap = 0;
+ }
+ } else {
+ /*
+ * Whoops, they Nak'd our algorithm of choice
+ * but then suggested it back to us.
+ */
+ goto bad;
}
} else {
/*
GETSHORT(cishort, p); \
GETCHAR(cichar, p); \
/* Check rejected value. */ \
- if (cishort != val || cichar != digest) \
+ if ((cishort != (val)) || (cichar != (digest))) \
goto bad; \
try.neg = 0; \
try.neg_upap = 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);
+ REJCICHAP(CI_AUTHTYPE, neg_chap, PPP_CHAP, CHAP_DIGEST(go->chap_mdtype));
if (!go->neg_chap) {
REJCISHORT(CI_AUTHTYPE, neg_upap, PPP_PAP);
}
* 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 */
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 */
+ PUTCHAR(CHAP_DIGEST(ao->chap_mdtype), nakp);
break;
}
ho->neg_upap = 1;
PUTSHORT(PPP_PAP, nakp);
break;
}
- GETCHAR(cichar, p); /* get digest type*/
- if (cichar != CHAP_DIGEST_MD5
-#ifdef CHAPMS
- && cichar != CHAP_MICROSOFT
-#endif
- ) {
+ GETCHAR(cichar, p); /* get digest type */
+ if (!(CHAP_CANDIGEST(ao->chap_mdtype, cichar))) {
+ /*
+ * We can't/won't do the requested type,
+ * suggest something else.
+ */
orc = CONFNAK;
PUTCHAR(CI_AUTHTYPE, nakp);
PUTCHAR(CILEN_CHAP, nakp);
PUTSHORT(PPP_CHAP, nakp);
- PUTCHAR(ao->chap_mdtype, nakp);
+ PUTCHAR(CHAP_DIGEST(ao->chap_mdtype), nakp);
break;
}
- ho->chap_mdtype = cichar; /* save md type */
+ ho->chap_mdtype = CHAP_MDTYPE_D(cichar); /* save md type */
ho->neg_chap = 1;
break;
}
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);
break;
case CI_EPDISC:
- if (!ao->neg_endpoint || !multilink ||
+ if (!ao->neg_endpoint ||
cilen < CILEN_CHAR ||
cilen > CILEN_CHAR + MAX_ENDP_LEN) {
orc = CONFREJ;
lcp_options *ho = &lcp_hisoptions[f->unit];
lcp_options *go = &lcp_gotoptions[f->unit];
lcp_options *ao = &lcp_allowoptions[f->unit];
+ int mtu;
if (!go->neg_magicnumber)
go->magicnumber = 0;
* the MRU our peer wanted. If we negotiated an MRU,
* set our MRU to the larger of value we wanted and
* the value we got in the negotiation.
+ * Note on the MTU: the link MTU can be the MRU the peer wanted,
+ * the interface MTU is set to the lower of that and the
+ * MTU we want to use.
*/
- ppp_send_config(f->unit, MIN(ao->mru, (ho->neg_mru? ho->mru: PPP_MRU)),
+ mtu = ho->neg_mru? ho->mru: PPP_MRU;
+#ifdef HAVE_MULTILINK
+ if (!(multilink && go->neg_mrru && ho->neg_mrru))
+#endif /* HAVE_MULTILINK */
+ netif_set_mtu(f->unit, MIN(mtu, ao->mru));
+ ppp_send_config(f->unit, mtu,
(ho->neg_asyncmap? ho->asyncmap: 0xffffffff),
ho->neg_pcompression, ho->neg_accompression);
ppp_recv_config(f->unit, (go->neg_mru? MAX(wo->mru, go->mru): PPP_MRU),
break;
#ifdef CHAPMS
case CHAP_MICROSOFT:
- printer(arg, " m$oft");
+ printer(arg, " MS");
+ ++p;
+ break;
+
+ case CHAP_MICROSOFT_V2:
+ printer(arg, " MS-v2");
++p;
break;
#endif
}
break;
case CI_EPDISC:
+#ifdef HAVE_MULTILINK
if (olen >= CILEN_CHAR) {
struct epdisc epd;
p += 2;
}
printer(arg, "endpoint [%s]", epdisc_to_str(&epd));
}
+#else
+ printer(arg, "endpoint");
+#endif
break;
}
while (p < optend) {
case TERMREQ:
if (len > 0 && *p >= ' ' && *p < 0x7f) {
printer(arg, " ");
- print_string(p, len, printer, arg);
+ print_string((char *)p, len, printer, arg);
p += len;
len = 0;
}