* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
-#define RCSID "$Id: lcp.c,v 1.48 2000/03/27 06:02:59 paulus Exp $";
+#define RCSID "$Id: lcp.c,v 1.56 2001/02/22 03:16:26 paulus 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 noopt __P((char **));
static int setescape __P((char **));
+#ifdef HAVE_MULTILINK
+static int setendpoint __P((char **));
+#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 },
{ "mru", o_int, &lcp_wantoptions[0].mru,
"Set MRU (maximum received packet size) for negotiation",
0, &lcp_wantoptions[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 },
"Set passive mode", 1 },
{ "silent", o_bool, &lcp_wantoptions[0].silent,
"Set silent mode", 1 },
- { "escape", o_special, setescape,
+ { "escape", o_special, (void *)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" },
{ "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 },
{ "mpshortseq", o_bool, &lcp_wantoptions[0].neg_ssnhf,
"Use short sequence numbers in multilink headers",
- OPT_A2COPY, &lcp_allowoptions[0].neg_ssnhf },
+ OPT_A2COPY | 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" },
#endif /* HAVE_MULTILINK */
+ { "noendpoint", o_bool, &noendpoint,
+ "Don't send or accept multilink endpoint discriminator", 1 },
{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 */
+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")
+/*
+ * noopt - Disable all options (why?).
+ */
+static int
+noopt(argv)
+ char **argv;
+{
+ BZERO((char *) &lcp_wantoptions[0], sizeof (struct lcp_options));
+ BZERO((char *) &lcp_allowoptions[0], sizeof (struct lcp_options));
+
+ return (1);
+}
/*
* setescape - add chars to the set we escape on transmission.
return ret;
}
+#ifdef HAVE_MULTILINK
+static int
+setendpoint(argv)
+ char **argv;
+{
+ if (str_to_epdisc(&lcp_wantoptions[0].endpoint, *argv)) {
+ lcp_wantoptions[0].neg_endpoint = 1;
+ return 1;
+ }
+ option_error("Can't parse '%s' as an endpoint discriminator", *argv);
+ return 0;
+}
+#endif /* HAVE_MULTILINK */
+
/*
* lcp_init - Initialize LCP.
*/
fsm_init(f);
- wo->passive = 0;
- wo->silent = 0;
- wo->restart = 0; /* Set to 1 in kernels or multi-line
- implementations */
+ BZERO(wo, sizeof(*wo));
wo->neg_mru = 1;
wo->mru = DEFMRU;
wo->neg_asyncmap = 1;
- wo->asyncmap = 0;
- wo->neg_chap = 0; /* Set to 1 on server */
- wo->neg_upap = 0; /* Set to 1 on server */
wo->chap_mdtype = CHAP_DIGEST_MD5;
wo->neg_magicnumber = 1;
wo->neg_pcompression = 1;
wo->neg_accompression = 1;
- wo->neg_lqr = 0; /* no LQR implementation yet */
- wo->neg_cbcp = 0;
+ BZERO(ao, sizeof(*ao));
ao->neg_mru = 1;
ao->mru = MAXMRU;
ao->neg_asyncmap = 1;
- ao->asyncmap = 0;
ao->neg_chap = 1;
ao->chap_mdtype = CHAP_DIGEST_MD5;
ao->neg_upap = 1;
ao->neg_magicnumber = 1;
ao->neg_pcompression = 1;
ao->neg_accompression = 1;
- ao->neg_lqr = 0; /* no LQR implementation yet */
#ifdef CBCP_SUPPORT
ao->neg_cbcp = 1;
-#else
- ao->neg_cbcp = 0;
#endif
+ ao->neg_endpoint = 1;
- memset(xmit_accm[unit], 0, sizeof(xmit_accm[0]));
+ 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,
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);
}
fsm *f;
{
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;
- if (!wo->neg_multilink)
- wo->neg_ssnhf = 0;
- lcp_gotoptions[f->unit] = *wo;
+ *go = *wo;
+ if (!multilink) {
+ go->neg_mrru = 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);
}
LENCILONG(go->neg_magicnumber) +
LENCIVOID(go->neg_pcompression) +
LENCIVOID(go->neg_accompression) +
- LENCISHORT(go->neg_multilink) +
+ LENCISHORT(go->neg_mrru) +
LENCIVOID(go->neg_ssnhf) +
- (go->neg_endpoint? CILEN_CHAR + go->endp_len: 0));
+ (go->neg_endpoint? CILEN_CHAR + go->endpoint.length: 0));
}
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);
+ ADDCISHORT(CI_MRRU, go->neg_mrru, go->mrru);
ADDCIVOID(CI_SSNHF, go->neg_ssnhf);
- ADDCIENDP(CI_EPDISC, go->neg_endpoint, go->endp_class, go->endpoint,
- go->endp_len);
+ ADDCIENDP(CI_EPDISC, go->neg_endpoint, go->endpoint.class,
+ go->endpoint.value, go->endpoint.length);
if (ucp - start_ucp != *lenp) {
/* this should never happen, because peer_mtu should be 1500 */
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);
+ ACKCISHORT(CI_MRRU, go->neg_mrru, go->mrru);
ACKCIVOID(CI_SSNHF, go->neg_ssnhf);
- ACKCIENDP(CI_EPDISC, go->neg_endpoint, go->endp_class, go->endpoint,
- go->endp_len);
+ ACKCIENDP(CI_EPDISC, go->neg_endpoint, go->endpoint.class,
+ go->endpoint.value, go->endpoint.length);
/*
* If there are any remaining CIs, then this packet is bad.
* 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 (go->neg_mrru) {
+ NAKCISHORT(CI_MRRU, neg_mrru,
if (cishort <= wo->mrru)
try.mrru = cishort;
);
goto bad;
break;
case CI_MRRU:
- if (go->neg_multilink || no.neg_multilink || cilen != CILEN_SHORT)
+ if (go->neg_mrru || no.neg_mrru || cilen != CILEN_SHORT)
goto bad;
break;
case CI_SSNHF:
p[1] == CILEN_CHAR + vlen) { \
int i; \
len -= CILEN_CHAR + vlen; \
- INCPTR(p[1], p); \
+ INCPTR(2, p); \
GETCHAR(cichar, p); \
if (cichar != class) \
goto bad; \
REJCILONG(CI_MAGICNUMBER, neg_magicnumber, go->magicnumber);
REJCIVOID(CI_PCOMPRESSION, neg_pcompression);
REJCIVOID(CI_ACCOMPRESSION, neg_accompression);
- REJCISHORT(CI_MRRU, neg_multilink, go->mrru);
+ REJCISHORT(CI_MRRU, neg_mrru, go->mrru);
REJCIVOID(CI_SSNHF, neg_ssnhf);
- REJCIENDP(CI_EPDISC, neg_endpoint, go->endp_class, go->endpoint,
- go->endp_len);
+ 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.
break;
case CI_MRRU:
- if (!ao->neg_multilink ||
+ if (!ao->neg_mrru || !multilink ||
cilen != CILEN_SHORT) {
orc = CONFREJ;
break;
GETSHORT(cishort, p);
/* possibly should insist on a minimum/maximum MRRU here */
- ho->neg_multilink = 1;
+ ho->neg_mrru = 1;
ho->mrru = cishort;
break;
case CI_SSNHF:
- if (!ao->neg_ssnhf ||
+ if (!ao->neg_ssnhf || !multilink ||
cilen != CILEN_VOID) {
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);
+ ho->endpoint.class = cichar;
+ ho->endpoint.length = cilen;
+ BCOPY(p, ho->endpoint.value, cilen);
INCPTR(cilen, p);
break;
"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;
{
int code, id, len, olen, i;
u_char *pstart, *optend;
- u_char cichar;
u_short cishort;
u_int32_t cilong;
}
break;
case CI_EPDISC:
+#ifdef HAVE_MULTILINK
if (olen >= CILEN_CHAR) {
+ struct epdisc epd;
p += 2;
- GETCHAR(cichar, p);
- if (cichar <= 5)
- printer(arg, "endpoint [%s]:",
- endp_class_names[cichar]);
- else
- printer(arg, "endpoint [%d]:");
+ GETCHAR(epd.class, p);
+ epd.length = olen - CILEN_CHAR;
+ if (epd.length > MAX_ENDP_LEN)
+ epd.length = MAX_ENDP_LEN;
+ if (epd.length > 0) {
+ BCOPY(p, epd.value, epd.length);
+ p += epd.length;
+ }
+ 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;
}