1/*
2 * lcp.c - PPP Link Control Protocol.
3 *
4 * Copyright (c) 1984-2000 Carnegie Mellon University. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 *
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in
15 *    the documentation and/or other materials provided with the
16 *    distribution.
17 *
18 * 3. The name "Carnegie Mellon University" must not be used to
19 *    endorse or promote products derived from this software without
20 *    prior written permission. For permission or any legal
21 *    details, please contact
22 *      Office of Technology Transfer
23 *      Carnegie Mellon University
24 *      5000 Forbes Avenue
25 *      Pittsburgh, PA  15213-3890
26 *      (412) 268-4387, fax: (412) 268-7395
27 *      tech-transfer@andrew.cmu.edu
28 *
29 * 4. Redistributions of any form whatsoever must retain the following
30 *    acknowledgment:
31 *    "This product includes software developed by Computing Services
32 *     at Carnegie Mellon University (http://www.cmu.edu/computing/)."
33 *
34 * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
35 * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
36 * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
37 * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
38 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
39 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
40 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
41 */
42
43#include "netif/ppp/ppp_opts.h"
44#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */
45
46/*
47 * @todo:
48 */
49
50#if 0 /* UNUSED */
51#include <stdio.h>
52#include <string.h>
53#include <stdlib.h>
54#endif /* UNUSED */
55
56#include "netif/ppp/ppp_impl.h"
57
58#include "netif/ppp/fsm.h"
59#include "netif/ppp/lcp.h"
60#if CHAP_SUPPORT
61#include "netif/ppp/chap-new.h"
62#endif /* CHAP_SUPPORT */
63#include "netif/ppp/magic.h"
64
65/*
66 * When the link comes up we want to be able to wait for a short while,
67 * or until seeing some input from the peer, before starting to send
68 * configure-requests.  We do this by delaying the fsm_lowerup call.
69 */
70/* steal a bit in fsm flags word */
71#define DELAYED_UP	0x80
72
73static void lcp_delayed_up(void *arg);
74
75/*
76 * LCP-related command-line options.
77 */
78#if 0 /* UNUSED */
79int	lcp_echo_interval = 0; 	/* Interval between LCP echo-requests */
80int	lcp_echo_fails = 0;	/* Tolerance to unanswered echo-requests */
81#endif /* UNUSED */
82
83#if 0 /* UNUSED */
84/* options */
85static u_int lcp_echo_interval      = LCP_ECHOINTERVAL; /* Interval between LCP echo-requests */
86static u_int lcp_echo_fails         = LCP_MAXECHOFAILS; /* Tolerance to unanswered echo-requests */
87#endif /* UNUSED */
88
89#if 0 /* UNUSED */
90#if PPP_LCP_ADAPTIVE
91bool	lcp_echo_adaptive = 0;	/* request echo only if the link was idle */
92#endif
93bool	lax_recv = 0;		/* accept control chars in asyncmap */
94bool	noendpoint = 0;		/* don't send/accept endpoint discriminator */
95#endif /* UNUSED */
96
97#if PPP_OPTIONS
98static int noopt (char **);
99#endif /* PPP_OPTIONS */
100
101#ifdef HAVE_MULTILINK
102static int setendpoint (char **);
103static void printendpoint (option_t *, void (*)(void *, char *, ...),
104			       void *);
105#endif /* HAVE_MULTILINK */
106
107#if PPP_OPTIONS
108static option_t lcp_option_list[] = {
109    /* LCP options */
110    { "-all", o_special_noarg, (void *)noopt,
111      "Don't request/allow any LCP options" },
112
113    { "noaccomp", o_bool, &lcp_wantoptions[0].neg_accompression,
114      "Disable address/control compression",
115      OPT_A2CLR, &lcp_allowoptions[0].neg_accompression },
116    { "-ac", o_bool, &lcp_wantoptions[0].neg_accompression,
117      "Disable address/control compression",
118      OPT_ALIAS | OPT_A2CLR, &lcp_allowoptions[0].neg_accompression },
119
120    { "asyncmap", o_uint32, &lcp_wantoptions[0].asyncmap,
121      "Set asyncmap (for received packets)",
122      OPT_OR, &lcp_wantoptions[0].neg_asyncmap },
123    { "-as", o_uint32, &lcp_wantoptions[0].asyncmap,
124      "Set asyncmap (for received packets)",
125      OPT_ALIAS | OPT_OR, &lcp_wantoptions[0].neg_asyncmap },
126    { "default-asyncmap", o_uint32, &lcp_wantoptions[0].asyncmap,
127      "Disable asyncmap negotiation",
128      OPT_OR | OPT_NOARG | OPT_VAL(~0U) | OPT_A2CLR,
129      &lcp_allowoptions[0].neg_asyncmap },
130    { "-am", o_uint32, &lcp_wantoptions[0].asyncmap,
131      "Disable asyncmap negotiation",
132      OPT_ALIAS | OPT_OR | OPT_NOARG | OPT_VAL(~0U) | OPT_A2CLR,
133      &lcp_allowoptions[0].neg_asyncmap },
134
135    { "nomagic", o_bool, &lcp_wantoptions[0].neg_magicnumber,
136      "Disable magic number negotiation (looped-back line detection)",
137      OPT_A2CLR, &lcp_allowoptions[0].neg_magicnumber },
138    { "-mn", o_bool, &lcp_wantoptions[0].neg_magicnumber,
139      "Disable magic number negotiation (looped-back line detection)",
140      OPT_ALIAS | OPT_A2CLR, &lcp_allowoptions[0].neg_magicnumber },
141
142    { "mru", o_int, &lcp_wantoptions[0].mru,
143      "Set MRU (maximum received packet size) for negotiation",
144      OPT_PRIO, &lcp_wantoptions[0].neg_mru },
145    { "default-mru", o_bool, &lcp_wantoptions[0].neg_mru,
146      "Disable MRU negotiation (use default 1500)",
147      OPT_PRIOSUB | OPT_A2CLR, &lcp_allowoptions[0].neg_mru },
148    { "-mru", o_bool, &lcp_wantoptions[0].neg_mru,
149      "Disable MRU negotiation (use default 1500)",
150      OPT_ALIAS | OPT_PRIOSUB | OPT_A2CLR, &lcp_allowoptions[0].neg_mru },
151
152    { "mtu", o_int, &lcp_allowoptions[0].mru,
153      "Set our MTU", OPT_LIMITS, NULL, MAXMRU, MINMRU },
154
155    { "nopcomp", o_bool, &lcp_wantoptions[0].neg_pcompression,
156      "Disable protocol field compression",
157      OPT_A2CLR, &lcp_allowoptions[0].neg_pcompression },
158    { "-pc", o_bool, &lcp_wantoptions[0].neg_pcompression,
159      "Disable protocol field compression",
160      OPT_ALIAS | OPT_A2CLR, &lcp_allowoptions[0].neg_pcompression },
161
162    { "passive", o_bool, &lcp_wantoptions[0].passive,
163      "Set passive mode", 1 },
164    { "-p", o_bool, &lcp_wantoptions[0].passive,
165      "Set passive mode", OPT_ALIAS | 1 },
166
167    { "silent", o_bool, &lcp_wantoptions[0].silent,
168      "Set silent mode", 1 },
169
170    { "lcp-echo-failure", o_int, &lcp_echo_fails,
171      "Set number of consecutive echo failures to indicate link failure",
172      OPT_PRIO },
173    { "lcp-echo-interval", o_int, &lcp_echo_interval,
174      "Set time in seconds between LCP echo requests", OPT_PRIO },
175#if PPP_LCP_ADAPTIVE
176    { "lcp-echo-adaptive", o_bool, &lcp_echo_adaptive,
177      "Suppress LCP echo requests if traffic was received", 1 },
178#endif
179    { "lcp-restart", o_int, &lcp_fsm[0].timeouttime,
180      "Set time in seconds between LCP retransmissions", OPT_PRIO },
181    { "lcp-max-terminate", o_int, &lcp_fsm[0].maxtermtransmits,
182      "Set maximum number of LCP terminate-request transmissions", OPT_PRIO },
183    { "lcp-max-configure", o_int, &lcp_fsm[0].maxconfreqtransmits,
184      "Set maximum number of LCP configure-request transmissions", OPT_PRIO },
185    { "lcp-max-failure", o_int, &lcp_fsm[0].maxnakloops,
186      "Set limit on number of LCP configure-naks", OPT_PRIO },
187
188    { "receive-all", o_bool, &lax_recv,
189      "Accept all received control characters", 1 },
190
191#ifdef HAVE_MULTILINK
192    { "mrru", o_int, &lcp_wantoptions[0].mrru,
193      "Maximum received packet size for multilink bundle",
194      OPT_PRIO, &lcp_wantoptions[0].neg_mrru },
195
196    { "mpshortseq", o_bool, &lcp_wantoptions[0].neg_ssnhf,
197      "Use short sequence numbers in multilink headers",
198      OPT_PRIO | 1, &lcp_allowoptions[0].neg_ssnhf },
199    { "nompshortseq", o_bool, &lcp_wantoptions[0].neg_ssnhf,
200      "Don't use short sequence numbers in multilink headers",
201      OPT_PRIOSUB | OPT_A2CLR, &lcp_allowoptions[0].neg_ssnhf },
202
203    { "endpoint", o_special, (void *) setendpoint,
204      "Endpoint discriminator for multilink",
205      OPT_PRIO | OPT_A2PRINTER, (void *) printendpoint },
206#endif /* HAVE_MULTILINK */
207
208    { "noendpoint", o_bool, &noendpoint,
209      "Don't send or accept multilink endpoint discriminator", 1 },
210
211    {NULL}
212};
213#endif /* PPP_OPTIONS */
214
215/*
216 * Callbacks for fsm code.  (CI = Configuration Information)
217 */
218static void lcp_resetci(fsm *f);	/* Reset our CI */
219static int  lcp_cilen(fsm *f);		/* Return length of our CI */
220static void lcp_addci(fsm *f, u_char *ucp, int *lenp); /* Add our CI to pkt */
221static int  lcp_ackci(fsm *f, u_char *p, int len); /* Peer ack'd our CI */
222static int  lcp_nakci(fsm *f, u_char *p, int len, int treat_as_reject); /* Peer nak'd our CI */
223static int  lcp_rejci(fsm *f, u_char *p, int len); /* Peer rej'd our CI */
224static int  lcp_reqci(fsm *f, u_char *inp, int *lenp, int reject_if_disagree); /* Rcv peer CI */
225static void lcp_up(fsm *f);		/* We're UP */
226static void lcp_down(fsm *f);		/* We're DOWN */
227static void lcp_starting (fsm *);	/* We need lower layer up */
228static void lcp_finished (fsm *);	/* We need lower layer down */
229static int  lcp_extcode(fsm *f, int code, int id, u_char *inp, int len);
230static void lcp_rprotrej(fsm *f, u_char *inp, int len);
231
232/*
233 * routines to send LCP echos to peer
234 */
235
236static void lcp_echo_lowerup(ppp_pcb *pcb);
237static void lcp_echo_lowerdown(ppp_pcb *pcb);
238static void LcpEchoTimeout(void *arg);
239static void lcp_received_echo_reply(fsm *f, int id, u_char *inp, int len);
240static void LcpSendEchoRequest(fsm *f);
241static void LcpLinkFailure(fsm *f);
242static void LcpEchoCheck(fsm *f);
243
244static const fsm_callbacks lcp_callbacks = {	/* LCP callback routines */
245    lcp_resetci,		/* Reset our Configuration Information */
246    lcp_cilen,			/* Length of our Configuration Information */
247    lcp_addci,			/* Add our Configuration Information */
248    lcp_ackci,			/* ACK our Configuration Information */
249    lcp_nakci,			/* NAK our Configuration Information */
250    lcp_rejci,			/* Reject our Configuration Information */
251    lcp_reqci,			/* Request peer's Configuration Information */
252    lcp_up,			/* Called when fsm reaches OPENED state */
253    lcp_down,			/* Called when fsm leaves OPENED state */
254    lcp_starting,		/* Called when we want the lower layer up */
255    lcp_finished,		/* Called when we want the lower layer down */
256    NULL,			/* Called when Protocol-Reject received */
257    NULL,			/* Retransmission is necessary */
258    lcp_extcode,		/* Called to handle LCP-specific codes */
259    "LCP"			/* String name of protocol */
260};
261
262/*
263 * Protocol entry points.
264 * Some of these are called directly.
265 */
266
267static void lcp_init(ppp_pcb *pcb);
268static void lcp_input(ppp_pcb *pcb, u_char *p, int len);
269static void lcp_protrej(ppp_pcb *pcb);
270#if PRINTPKT_SUPPORT
271static int lcp_printpkt(const u_char *p, int plen,
272		void (*printer) (void *, const char *, ...), void *arg);
273#endif /* PRINTPKT_SUPPORT */
274
275const struct protent lcp_protent = {
276    PPP_LCP,
277    lcp_init,
278    lcp_input,
279    lcp_protrej,
280    lcp_lowerup,
281    lcp_lowerdown,
282    lcp_open,
283    lcp_close,
284#if PRINTPKT_SUPPORT
285    lcp_printpkt,
286#endif /* PRINTPKT_SUPPORT */
287#if PPP_DATAINPUT
288    NULL,
289#endif /* PPP_DATAINPUT */
290#if PRINTPKT_SUPPORT
291    "LCP",
292    NULL,
293#endif /* PRINTPKT_SUPPORT */
294#if PPP_OPTIONS
295    lcp_option_list,
296    NULL,
297#endif /* PPP_OPTIONS */
298#if DEMAND_SUPPORT
299    NULL,
300    NULL
301#endif /* DEMAND_SUPPORT */
302};
303
304/*
305 * Length of each type of configuration option (in octets)
306 */
307#define CILEN_VOID	2
308#define CILEN_CHAR	3
309#define CILEN_SHORT	4	/* CILEN_VOID + 2 */
310#if CHAP_SUPPORT
311#define CILEN_CHAP	5	/* CILEN_VOID + 2 + 1 */
312#endif /* CHAP_SUPPORT */
313#define CILEN_LONG	6	/* CILEN_VOID + 4 */
314#if LQR_SUPPORT
315#define CILEN_LQR	8	/* CILEN_VOID + 2 + 4 */
316#endif /* LQR_SUPPORT */
317#define CILEN_CBCP	3
318
319#define CODENAME(x)	((x) == CONFACK ? "ACK" : \
320			 (x) == CONFNAK ? "NAK" : "REJ")
321
322#if PPP_OPTIONS
323/*
324 * noopt - Disable all options (why?).
325 */
326static int
327noopt(argv)
328    char **argv;
329{
330    BZERO((char *) &lcp_wantoptions[0], sizeof (struct lcp_options));
331    BZERO((char *) &lcp_allowoptions[0], sizeof (struct lcp_options));
332
333    return (1);
334}
335#endif /* PPP_OPTIONS */
336
337#ifdef HAVE_MULTILINK
338static int
339setendpoint(argv)
340    char **argv;
341{
342    if (str_to_epdisc(&lcp_wantoptions[0].endpoint, *argv)) {
343	lcp_wantoptions[0].neg_endpoint = 1;
344	return 1;
345    }
346    option_error("Can't parse '%s' as an endpoint discriminator", *argv);
347    return 0;
348}
349
350static void
351printendpoint(opt, printer, arg)
352    option_t *opt;
353    void (*printer) (void *, char *, ...);
354    void *arg;
355{
356	printer(arg, "%s", epdisc_to_str(&lcp_wantoptions[0].endpoint));
357}
358#endif /* HAVE_MULTILINK */
359
360/*
361 * lcp_init - Initialize LCP.
362 */
363static void lcp_init(ppp_pcb *pcb) {
364    fsm *f = &pcb->lcp_fsm;
365    lcp_options *wo = &pcb->lcp_wantoptions;
366    lcp_options *ao = &pcb->lcp_allowoptions;
367
368    f->pcb = pcb;
369    f->protocol = PPP_LCP;
370    f->callbacks = &lcp_callbacks;
371
372    fsm_init(f);
373
374    BZERO(wo, sizeof(*wo));
375    wo->neg_mru = 1;
376    wo->mru = PPP_DEFMRU;
377    wo->neg_asyncmap = 1;
378    wo->neg_magicnumber = 1;
379    wo->neg_pcompression = 1;
380    wo->neg_accompression = 1;
381
382    BZERO(ao, sizeof(*ao));
383    ao->neg_mru = 1;
384    ao->mru = PPP_MAXMRU;
385    ao->neg_asyncmap = 1;
386#if CHAP_SUPPORT
387    ao->neg_chap = 1;
388    ao->chap_mdtype = CHAP_MDTYPE_SUPPORTED;
389#endif /* CHAP_SUPPORT */
390#if PAP_SUPPORT
391    ao->neg_upap = 1;
392#endif /* PAP_SUPPORT */
393#if EAP_SUPPORT
394    ao->neg_eap = 1;
395#endif /* EAP_SUPPORT */
396    ao->neg_magicnumber = 1;
397    ao->neg_pcompression = 1;
398    ao->neg_accompression = 1;
399    ao->neg_endpoint = 1;
400}
401
402
403/*
404 * lcp_open - LCP is allowed to come up.
405 */
406void lcp_open(ppp_pcb *pcb) {
407    fsm *f = &pcb->lcp_fsm;
408    lcp_options *wo = &pcb->lcp_wantoptions;
409
410    f->flags &= ~(OPT_PASSIVE | OPT_SILENT);
411    if (wo->passive)
412	f->flags |= OPT_PASSIVE;
413    if (wo->silent)
414	f->flags |= OPT_SILENT;
415    fsm_open(f);
416}
417
418
419/*
420 * lcp_close - Take LCP down.
421 */
422void lcp_close(ppp_pcb *pcb, const char *reason) {
423    fsm *f = &pcb->lcp_fsm;
424    int oldstate;
425
426    if (pcb->phase != PPP_PHASE_DEAD
427#ifdef HAVE_MULTILINK
428    && pcb->phase != PPP_PHASE_MASTER
429#endif /* HAVE_MULTILINK */
430    )
431	new_phase(pcb, PPP_PHASE_TERMINATE);
432
433    if (f->flags & DELAYED_UP) {
434	UNTIMEOUT(lcp_delayed_up, f);
435	f->state = PPP_FSM_STOPPED;
436    }
437    oldstate = f->state;
438
439    fsm_close(f, reason);
440    if (oldstate == PPP_FSM_STOPPED && (f->flags & (OPT_PASSIVE|OPT_SILENT|DELAYED_UP))) {
441	/*
442	 * This action is not strictly according to the FSM in RFC1548,
443	 * but it does mean that the program terminates if you do a
444	 * lcp_close() when a connection hasn't been established
445	 * because we are in passive/silent mode or because we have
446	 * delayed the fsm_lowerup() call and it hasn't happened yet.
447	 */
448	f->flags &= ~DELAYED_UP;
449	lcp_finished(f);
450    }
451}
452
453
454/*
455 * lcp_lowerup - The lower layer is up.
456 */
457void lcp_lowerup(ppp_pcb *pcb) {
458    lcp_options *wo = &pcb->lcp_wantoptions;
459    fsm *f = &pcb->lcp_fsm;
460    /*
461     * Don't use A/C or protocol compression on transmission,
462     * but accept A/C and protocol compressed packets
463     * if we are going to ask for A/C and protocol compression.
464     */
465    if (ppp_send_config(pcb, PPP_MRU, 0xffffffff, 0, 0) < 0
466	|| ppp_recv_config(pcb, PPP_MRU, (pcb->settings.lax_recv? 0: 0xffffffff),
467			   wo->neg_pcompression, wo->neg_accompression) < 0)
468	    return;
469    pcb->peer_mru = PPP_MRU;
470
471    if (pcb->settings.listen_time != 0) {
472	f->flags |= DELAYED_UP;
473	TIMEOUTMS(lcp_delayed_up, f, pcb->settings.listen_time);
474    } else
475	fsm_lowerup(f);
476}
477
478
479/*
480 * lcp_lowerdown - The lower layer is down.
481 */
482void lcp_lowerdown(ppp_pcb *pcb) {
483    fsm *f = &pcb->lcp_fsm;
484
485    if (f->flags & DELAYED_UP) {
486	f->flags &= ~DELAYED_UP;
487	UNTIMEOUT(lcp_delayed_up, f);
488    } else
489	fsm_lowerdown(f);
490}
491
492
493/*
494 * lcp_delayed_up - Bring the lower layer up now.
495 */
496static void lcp_delayed_up(void *arg) {
497    fsm *f = (fsm*)arg;
498
499    if (f->flags & DELAYED_UP) {
500	f->flags &= ~DELAYED_UP;
501	fsm_lowerup(f);
502    }
503}
504
505
506/*
507 * lcp_input - Input LCP packet.
508 */
509static void lcp_input(ppp_pcb *pcb, u_char *p, int len) {
510    fsm *f = &pcb->lcp_fsm;
511
512    if (f->flags & DELAYED_UP) {
513	f->flags &= ~DELAYED_UP;
514	UNTIMEOUT(lcp_delayed_up, f);
515	fsm_lowerup(f);
516    }
517    fsm_input(f, p, len);
518}
519
520/*
521 * lcp_extcode - Handle a LCP-specific code.
522 */
523static int lcp_extcode(fsm *f, int code, int id, u_char *inp, int len) {
524    ppp_pcb *pcb = f->pcb;
525    lcp_options *go = &pcb->lcp_gotoptions;
526    u_char *magp;
527
528    switch( code ){
529    case PROTREJ:
530	lcp_rprotrej(f, inp, len);
531	break;
532
533    case ECHOREQ:
534	if (f->state != PPP_FSM_OPENED)
535	    break;
536	magp = inp;
537	PUTLONG(go->magicnumber, magp);
538	fsm_sdata(f, ECHOREP, id, inp, len);
539	break;
540
541    case ECHOREP:
542	lcp_received_echo_reply(f, id, inp, len);
543	break;
544
545    case DISCREQ:
546    case IDENTIF:
547    case TIMEREM:
548	break;
549
550    default:
551	return 0;
552    }
553    return 1;
554}
555
556
557/*
558 * lcp_rprotrej - Receive an Protocol-Reject.
559 *
560 * Figure out which protocol is rejected and inform it.
561 */
562static void lcp_rprotrej(fsm *f, u_char *inp, int len) {
563    int i;
564    const struct protent *protp;
565    u_short prot;
566#if PPP_PROTOCOLNAME
567    const char *pname;
568#endif /* PPP_PROTOCOLNAME */
569
570    if (len < 2) {
571	LCPDEBUG(("lcp_rprotrej: Rcvd short Protocol-Reject packet!"));
572	return;
573    }
574
575    GETSHORT(prot, inp);
576
577    /*
578     * Protocol-Reject packets received in any state other than the LCP
579     * OPENED state SHOULD be silently discarded.
580     */
581    if( f->state != PPP_FSM_OPENED ){
582	LCPDEBUG(("Protocol-Reject discarded: LCP in state %d", f->state));
583	return;
584    }
585
586#if PPP_PROTOCOLNAME
587    pname = protocol_name(prot);
588#endif /* PPP_PROTOCOLNAME */
589
590    /*
591     * Upcall the proper Protocol-Reject routine.
592     */
593    for (i = 0; (protp = protocols[i]) != NULL; ++i)
594	if (protp->protocol == prot) {
595#if PPP_PROTOCOLNAME
596	    if (pname != NULL)
597		ppp_dbglog("Protocol-Reject for '%s' (0x%x) received", pname,
598		       prot);
599	    else
600#endif /* PPP_PROTOCOLNAME */
601		ppp_dbglog("Protocol-Reject for 0x%x received", prot);
602	    (*protp->protrej)(f->pcb);
603	    return;
604	}
605
606#if PPP_PROTOCOLNAME
607    if (pname != NULL)
608	ppp_warn("Protocol-Reject for unsupported protocol '%s' (0x%x)", pname,
609	     prot);
610    else
611#endif /* #if PPP_PROTOCOLNAME */
612	ppp_warn("Protocol-Reject for unsupported protocol 0x%x", prot);
613}
614
615
616/*
617 * lcp_protrej - A Protocol-Reject was received.
618 */
619/*ARGSUSED*/
620static void lcp_protrej(ppp_pcb *pcb) {
621    /*
622     * Can't reject LCP!
623     */
624    ppp_error("Received Protocol-Reject for LCP!");
625    fsm_protreject(&pcb->lcp_fsm);
626}
627
628
629/*
630 * lcp_sprotrej - Send a Protocol-Reject for some protocol.
631 */
632void lcp_sprotrej(ppp_pcb *pcb, u_char *p, int len) {
633    fsm *f = &pcb->lcp_fsm;
634    /*
635     * Send back the protocol and the information field of the
636     * rejected packet.  We only get here if LCP is in the OPENED state.
637     */
638#if 0
639    p += 2;
640    len -= 2;
641#endif
642
643    fsm_sdata(f, PROTREJ, ++f->id,
644	      p, len);
645}
646
647
648/*
649 * lcp_resetci - Reset our CI.
650 */
651static void lcp_resetci(fsm *f) {
652    ppp_pcb *pcb = f->pcb;
653    lcp_options *wo = &pcb->lcp_wantoptions;
654    lcp_options *go = &pcb->lcp_gotoptions;
655    lcp_options *ao = &pcb->lcp_allowoptions;
656
657#if PPP_AUTH_SUPPORT
658
659    /* note: default value is true for allow options */
660    if (pcb->settings.user && pcb->settings.passwd) {
661#if PAP_SUPPORT
662      if (pcb->settings.refuse_pap) {
663        ao->neg_upap = 0;
664      }
665#endif /* PAP_SUPPORT */
666#if CHAP_SUPPORT
667      if (pcb->settings.refuse_chap) {
668        ao->chap_mdtype &= ~MDTYPE_MD5;
669      }
670#if MSCHAP_SUPPORT
671      if (pcb->settings.refuse_mschap) {
672        ao->chap_mdtype &= ~MDTYPE_MICROSOFT;
673      }
674      if (pcb->settings.refuse_mschap_v2) {
675        ao->chap_mdtype &= ~MDTYPE_MICROSOFT_V2;
676      }
677#endif /* MSCHAP_SUPPORT */
678      ao->neg_chap = (ao->chap_mdtype != MDTYPE_NONE);
679#endif /* CHAP_SUPPORT */
680#if EAP_SUPPORT
681      if (pcb->settings.refuse_eap) {
682        ao->neg_eap = 0;
683      }
684#endif /* EAP_SUPPORT */
685
686#if PPP_SERVER
687      /* note: default value is false for wanted options */
688      if (pcb->settings.auth_required) {
689#if PAP_SUPPORT
690        if (!pcb->settings.refuse_pap) {
691          wo->neg_upap = 1;
692        }
693#endif /* PAP_SUPPORT */
694#if CHAP_SUPPORT
695        if (!pcb->settings.refuse_chap) {
696          wo->chap_mdtype |= MDTYPE_MD5;
697        }
698#if MSCHAP_SUPPORT
699        if (!pcb->settings.refuse_mschap) {
700          wo->chap_mdtype |= MDTYPE_MICROSOFT;
701        }
702        if (!pcb->settings.refuse_mschap_v2) {
703          wo->chap_mdtype |= MDTYPE_MICROSOFT_V2;
704        }
705#endif /* MSCHAP_SUPPORT */
706        wo->neg_chap = (wo->chap_mdtype != MDTYPE_NONE);
707#endif /* CHAP_SUPPORT */
708#if EAP_SUPPORT
709        if (!pcb->settings.refuse_eap) {
710          wo->neg_eap = 1;
711        }
712#endif /* EAP_SUPPORT */
713      }
714#endif /* PPP_SERVER */
715
716    } else {
717#if PAP_SUPPORT
718      ao->neg_upap = 0;
719#endif /* PAP_SUPPORT */
720#if CHAP_SUPPORT
721      ao->neg_chap = 0;
722      ao->chap_mdtype = MDTYPE_NONE;
723#endif /* CHAP_SUPPORT */
724#if EAP_SUPPORT
725      ao->neg_eap = 0;
726#endif /* EAP_SUPPORT */
727    }
728
729    PPPDEBUG(LOG_DEBUG, ("ppp: auth protocols:"));
730#if PAP_SUPPORT
731    PPPDEBUG(LOG_DEBUG, (" PAP=%d", ao->neg_upap));
732#endif /* PAP_SUPPORT */
733#if CHAP_SUPPORT
734    PPPDEBUG(LOG_DEBUG, (" CHAP=%d CHAP_MD5=%d", ao->neg_chap, !!(ao->chap_mdtype&MDTYPE_MD5)));
735#if MSCHAP_SUPPORT
736    PPPDEBUG(LOG_DEBUG, (" CHAP_MS=%d CHAP_MS2=%d", !!(ao->chap_mdtype&MDTYPE_MICROSOFT), !!(ao->chap_mdtype&MDTYPE_MICROSOFT_V2)));
737#endif /* MSCHAP_SUPPORT */
738#endif /* CHAP_SUPPORT */
739#if EAP_SUPPORT
740    PPPDEBUG(LOG_DEBUG, (" EAP=%d", ao->neg_eap));
741#endif /* EAP_SUPPORT */
742    PPPDEBUG(LOG_DEBUG, ("\n"));
743
744#endif /* PPP_AUTH_SUPPORT */
745
746    wo->magicnumber = magic();
747    wo->numloops = 0;
748    *go = *wo;
749#ifdef HAVE_MULTILINK
750    if (!multilink) {
751	go->neg_mrru = 0;
752#endif /* HAVE_MULTILINK */
753	go->neg_ssnhf = 0;
754	go->neg_endpoint = 0;
755#ifdef HAVE_MULTILINK
756    }
757#endif /* HAVE_MULTILINK */
758    if (pcb->settings.noendpoint)
759	ao->neg_endpoint = 0;
760    pcb->peer_mru = PPP_MRU;
761#if 0 /* UNUSED */
762    auth_reset(pcb);
763#endif /* UNUSED */
764}
765
766
767/*
768 * lcp_cilen - Return length of our CI.
769 */
770static int lcp_cilen(fsm *f) {
771    ppp_pcb *pcb = f->pcb;
772    lcp_options *go = &pcb->lcp_gotoptions;
773
774#define LENCIVOID(neg)	((neg) ? CILEN_VOID : 0)
775#if CHAP_SUPPORT
776#define LENCICHAP(neg)	((neg) ? CILEN_CHAP : 0)
777#endif /* CHAP_SUPPORT */
778#define LENCISHORT(neg)	((neg) ? CILEN_SHORT : 0)
779#define LENCILONG(neg)	((neg) ? CILEN_LONG : 0)
780#if LQR_SUPPORT
781#define LENCILQR(neg)	((neg) ? CILEN_LQR: 0)
782#endif /* LQR_SUPPORT */
783#define LENCICBCP(neg)	((neg) ? CILEN_CBCP: 0)
784    /*
785     * NB: we only ask for one of CHAP, UPAP, or EAP, even if we will
786     * accept more than one.  We prefer EAP first, then CHAP, then
787     * PAP.
788     */
789    return (LENCISHORT(go->neg_mru && go->mru != PPP_DEFMRU) +
790	    LENCILONG(go->neg_asyncmap && go->asyncmap != 0xFFFFFFFF) +
791#if EAP_SUPPORT
792	    LENCISHORT(go->neg_eap) +
793#endif /* EAP_SUPPORT */
794#if CHAP_SUPPORT /* cannot be improved, embedding a directive within macro arguments is not portable */
795#if EAP_SUPPORT
796	    LENCICHAP(!go->neg_eap && go->neg_chap) +
797#endif /* EAP_SUPPORT */
798#if !EAP_SUPPORT
799	    LENCICHAP(go->neg_chap) +
800#endif /* !EAP_SUPPORT */
801#endif /* CHAP_SUPPORT */
802#if PAP_SUPPORT /* cannot be improved, embedding a directive within macro arguments is not portable */
803#if EAP_SUPPORT && CHAP_SUPPORT
804	    LENCISHORT(!go->neg_eap && !go->neg_chap && go->neg_upap) +
805#endif /* EAP_SUPPORT && CHAP_SUPPORT */
806#if EAP_SUPPORT && !CHAP_SUPPORT
807	    LENCISHORT(!go->neg_eap && go->neg_upap) +
808#endif /* EAP_SUPPORT && !CHAP_SUPPORT */
809#if !EAP_SUPPORT && CHAP_SUPPORT
810	    LENCISHORT(!go->neg_chap && go->neg_upap) +
811#endif /* !EAP_SUPPORT && CHAP_SUPPORT */
812#if !EAP_SUPPORT && !CHAP_SUPPORT
813	    LENCISHORT(go->neg_upap) +
814#endif /* !EAP_SUPPORT && !CHAP_SUPPORT */
815#endif /* PAP_SUPPORT */
816#if LQR_SUPPORT
817	    LENCILQR(go->neg_lqr) +
818#endif /* LQR_SUPPORT */
819	    LENCICBCP(go->neg_cbcp) +
820	    LENCILONG(go->neg_magicnumber) +
821	    LENCIVOID(go->neg_pcompression) +
822	    LENCIVOID(go->neg_accompression) +
823#ifdef HAVE_MULTILINK
824	    LENCISHORT(go->neg_mrru) +
825#endif /* HAVE_MULTILINK */
826	    LENCIVOID(go->neg_ssnhf) +
827	    (go->neg_endpoint? CILEN_CHAR + go->endpoint.length: 0));
828}
829
830
831/*
832 * lcp_addci - Add our desired CIs to a packet.
833 */
834static void lcp_addci(fsm *f, u_char *ucp, int *lenp) {
835    ppp_pcb *pcb = f->pcb;
836    lcp_options *go = &pcb->lcp_gotoptions;
837    u_char *start_ucp = ucp;
838
839#define ADDCIVOID(opt, neg) \
840    if (neg) { \
841	PUTCHAR(opt, ucp); \
842	PUTCHAR(CILEN_VOID, ucp); \
843    }
844#define ADDCISHORT(opt, neg, val) \
845    if (neg) { \
846	PUTCHAR(opt, ucp); \
847	PUTCHAR(CILEN_SHORT, ucp); \
848	PUTSHORT(val, ucp); \
849    }
850#if CHAP_SUPPORT
851#define ADDCICHAP(opt, neg, val) \
852    if (neg) { \
853	PUTCHAR((opt), ucp); \
854	PUTCHAR(CILEN_CHAP, ucp); \
855	PUTSHORT(PPP_CHAP, ucp); \
856	PUTCHAR((CHAP_DIGEST(val)), ucp); \
857    }
858#endif /* CHAP_SUPPORT */
859#define ADDCILONG(opt, neg, val) \
860    if (neg) { \
861	PUTCHAR(opt, ucp); \
862	PUTCHAR(CILEN_LONG, ucp); \
863	PUTLONG(val, ucp); \
864    }
865#if LQR_SUPPORT
866#define ADDCILQR(opt, neg, val) \
867    if (neg) { \
868	PUTCHAR(opt, ucp); \
869	PUTCHAR(CILEN_LQR, ucp); \
870	PUTSHORT(PPP_LQR, ucp); \
871	PUTLONG(val, ucp); \
872    }
873#endif /* LQR_SUPPORT */
874#define ADDCICHAR(opt, neg, val) \
875    if (neg) { \
876	PUTCHAR(opt, ucp); \
877	PUTCHAR(CILEN_CHAR, ucp); \
878	PUTCHAR(val, ucp); \
879    }
880#define ADDCIENDP(opt, neg, class, val, len) \
881    if (neg) { \
882	int i; \
883	PUTCHAR(opt, ucp); \
884	PUTCHAR(CILEN_CHAR + len, ucp); \
885	PUTCHAR(class, ucp); \
886	for (i = 0; i < len; ++i) \
887	    PUTCHAR(val[i], ucp); \
888    }
889
890    ADDCISHORT(CI_MRU, go->neg_mru && go->mru != PPP_DEFMRU, go->mru);
891    ADDCILONG(CI_ASYNCMAP, go->neg_asyncmap && go->asyncmap != 0xFFFFFFFF,
892	      go->asyncmap);
893#if EAP_SUPPORT
894    ADDCISHORT(CI_AUTHTYPE, go->neg_eap, PPP_EAP);
895#endif /* EAP_SUPPORT */
896#if CHAP_SUPPORT /* cannot be improved, embedding a directive within macro arguments is not portable */
897#if EAP_SUPPORT
898    ADDCICHAP(CI_AUTHTYPE, !go->neg_eap && go->neg_chap, go->chap_mdtype);
899#endif /* EAP_SUPPORT */
900#if !EAP_SUPPORT
901    ADDCICHAP(CI_AUTHTYPE, go->neg_chap, go->chap_mdtype);
902#endif /* !EAP_SUPPORT */
903#endif /* CHAP_SUPPORT */
904#if PAP_SUPPORT /* cannot be improved, embedding a directive within macro arguments is not portable */
905#if EAP_SUPPORT && CHAP_SUPPORT
906    ADDCISHORT(CI_AUTHTYPE, !go->neg_eap && !go->neg_chap && go->neg_upap, PPP_PAP);
907#endif /* EAP_SUPPORT && CHAP_SUPPORT */
908#if EAP_SUPPORT && !CHAP_SUPPORT
909    ADDCISHORT(CI_AUTHTYPE, !go->neg_eap && go->neg_upap, PPP_PAP);
910#endif /* EAP_SUPPORT && !CHAP_SUPPORT */
911#if !EAP_SUPPORT && CHAP_SUPPORT
912    ADDCISHORT(CI_AUTHTYPE, !go->neg_chap && go->neg_upap, PPP_PAP);
913#endif /* !EAP_SUPPORT && CHAP_SUPPORT */
914#if !EAP_SUPPORT && !CHAP_SUPPORT
915    ADDCISHORT(CI_AUTHTYPE, go->neg_upap, PPP_PAP);
916#endif /* !EAP_SUPPORT && !CHAP_SUPPORT */
917#endif /* PAP_SUPPORT */
918#if LQR_SUPPORT
919    ADDCILQR(CI_QUALITY, go->neg_lqr, go->lqr_period);
920#endif /* LQR_SUPPORT */
921    ADDCICHAR(CI_CALLBACK, go->neg_cbcp, CBCP_OPT);
922    ADDCILONG(CI_MAGICNUMBER, go->neg_magicnumber, go->magicnumber);
923    ADDCIVOID(CI_PCOMPRESSION, go->neg_pcompression);
924    ADDCIVOID(CI_ACCOMPRESSION, go->neg_accompression);
925#ifdef HAVE_MULTILINK
926    ADDCISHORT(CI_MRRU, go->neg_mrru, go->mrru);
927#endif
928    ADDCIVOID(CI_SSNHF, go->neg_ssnhf);
929    ADDCIENDP(CI_EPDISC, go->neg_endpoint, go->endpoint.class_,
930	      go->endpoint.value, go->endpoint.length);
931
932    if (ucp - start_ucp != *lenp) {
933	/* this should never happen, because peer_mtu should be 1500 */
934	ppp_error("Bug in lcp_addci: wrong length");
935    }
936}
937
938
939/*
940 * lcp_ackci - Ack our CIs.
941 * This should not modify any state if the Ack is bad.
942 *
943 * Returns:
944 *	0 - Ack was bad.
945 *	1 - Ack was good.
946 */
947static int lcp_ackci(fsm *f, u_char *p, int len) {
948    ppp_pcb *pcb = f->pcb;
949    lcp_options *go = &pcb->lcp_gotoptions;
950    u_char cilen, citype, cichar;
951    u_short cishort;
952    u32_t cilong;
953
954    /*
955     * CIs must be in exactly the same order that we sent.
956     * Check packet length and CI length at each step.
957     * If we find any deviations, then this packet is bad.
958     */
959#define ACKCIVOID(opt, neg) \
960    if (neg) { \
961	if ((len -= CILEN_VOID) < 0) \
962	    goto bad; \
963	GETCHAR(citype, p); \
964	GETCHAR(cilen, p); \
965	if (cilen != CILEN_VOID || \
966	    citype != opt) \
967	    goto bad; \
968    }
969#define ACKCISHORT(opt, neg, val) \
970    if (neg) { \
971	if ((len -= CILEN_SHORT) < 0) \
972	    goto bad; \
973	GETCHAR(citype, p); \
974	GETCHAR(cilen, p); \
975	if (cilen != CILEN_SHORT || \
976	    citype != opt) \
977	    goto bad; \
978	GETSHORT(cishort, p); \
979	if (cishort != val) \
980	    goto bad; \
981    }
982#define ACKCICHAR(opt, neg, val) \
983    if (neg) { \
984	if ((len -= CILEN_CHAR) < 0) \
985	    goto bad; \
986	GETCHAR(citype, p); \
987	GETCHAR(cilen, p); \
988	if (cilen != CILEN_CHAR || \
989	    citype != opt) \
990	    goto bad; \
991	GETCHAR(cichar, p); \
992	if (cichar != val) \
993	    goto bad; \
994    }
995#if CHAP_SUPPORT
996#define ACKCICHAP(opt, neg, val) \
997    if (neg) { \
998	if ((len -= CILEN_CHAP) < 0) \
999	    goto bad; \
1000	GETCHAR(citype, p); \
1001	GETCHAR(cilen, p); \
1002	if (cilen != CILEN_CHAP || \
1003	    citype != (opt)) \
1004	    goto bad; \
1005	GETSHORT(cishort, p); \
1006	if (cishort != PPP_CHAP) \
1007	    goto bad; \
1008	GETCHAR(cichar, p); \
1009	if (cichar != (CHAP_DIGEST(val))) \
1010	  goto bad; \
1011    }
1012#endif /* CHAP_SUPPORT */
1013#define ACKCILONG(opt, neg, val) \
1014    if (neg) { \
1015	if ((len -= CILEN_LONG) < 0) \
1016	    goto bad; \
1017	GETCHAR(citype, p); \
1018	GETCHAR(cilen, p); \
1019	if (cilen != CILEN_LONG || \
1020	    citype != opt) \
1021	    goto bad; \
1022	GETLONG(cilong, p); \
1023	if (cilong != val) \
1024	    goto bad; \
1025    }
1026#if LQR_SUPPORT
1027#define ACKCILQR(opt, neg, val) \
1028    if (neg) { \
1029	if ((len -= CILEN_LQR) < 0) \
1030	    goto bad; \
1031	GETCHAR(citype, p); \
1032	GETCHAR(cilen, p); \
1033	if (cilen != CILEN_LQR || \
1034	    citype != opt) \
1035	    goto bad; \
1036	GETSHORT(cishort, p); \
1037	if (cishort != PPP_LQR) \
1038	    goto bad; \
1039	GETLONG(cilong, p); \
1040	if (cilong != val) \
1041	  goto bad; \
1042    }
1043#endif /* LQR_SUPPORT */
1044#define ACKCIENDP(opt, neg, class, val, vlen) \
1045    if (neg) { \
1046	int i; \
1047	if ((len -= CILEN_CHAR + vlen) < 0) \
1048	    goto bad; \
1049	GETCHAR(citype, p); \
1050	GETCHAR(cilen, p); \
1051	if (cilen != CILEN_CHAR + vlen || \
1052	    citype != opt) \
1053	    goto bad; \
1054	GETCHAR(cichar, p); \
1055	if (cichar != class) \
1056	    goto bad; \
1057	for (i = 0; i < vlen; ++i) { \
1058	    GETCHAR(cichar, p); \
1059	    if (cichar != val[i]) \
1060		goto bad; \
1061	} \
1062    }
1063
1064    ACKCISHORT(CI_MRU, go->neg_mru && go->mru != PPP_DEFMRU, go->mru);
1065    ACKCILONG(CI_ASYNCMAP, go->neg_asyncmap && go->asyncmap != 0xFFFFFFFF,
1066	      go->asyncmap);
1067#if EAP_SUPPORT
1068    ACKCISHORT(CI_AUTHTYPE, go->neg_eap, PPP_EAP);
1069#endif /* EAP_SUPPORT */
1070#if CHAP_SUPPORT /* cannot be improved, embedding a directive within macro arguments is not portable */
1071#if EAP_SUPPORT
1072    ACKCICHAP(CI_AUTHTYPE, !go->neg_eap && go->neg_chap, go->chap_mdtype);
1073#endif /* EAP_SUPPORT */
1074#if !EAP_SUPPORT
1075    ACKCICHAP(CI_AUTHTYPE, go->neg_chap, go->chap_mdtype);
1076#endif /* !EAP_SUPPORT */
1077#endif /* CHAP_SUPPORT */
1078#if PAP_SUPPORT /* cannot be improved, embedding a directive within macro arguments is not portable */
1079#if EAP_SUPPORT && CHAP_SUPPORT
1080    ACKCISHORT(CI_AUTHTYPE, !go->neg_eap && !go->neg_chap && go->neg_upap, PPP_PAP);
1081#endif /* EAP_SUPPORT && CHAP_SUPPORT */
1082#if EAP_SUPPORT && !CHAP_SUPPORT
1083    ACKCISHORT(CI_AUTHTYPE, !go->neg_eap && go->neg_upap, PPP_PAP);
1084#endif /* EAP_SUPPORT && !CHAP_SUPPORT */
1085#if !EAP_SUPPORT && CHAP_SUPPORT
1086    ACKCISHORT(CI_AUTHTYPE, !go->neg_chap && go->neg_upap, PPP_PAP);
1087#endif /* !EAP_SUPPORT && CHAP_SUPPORT */
1088#if !EAP_SUPPORT && !CHAP_SUPPORT
1089    ACKCISHORT(CI_AUTHTYPE, go->neg_upap, PPP_PAP);
1090#endif /* !EAP_SUPPORT && !CHAP_SUPPORT */
1091#endif /* PAP_SUPPORT */
1092#if LQR_SUPPORT
1093    ACKCILQR(CI_QUALITY, go->neg_lqr, go->lqr_period);
1094#endif /* LQR_SUPPORT */
1095    ACKCICHAR(CI_CALLBACK, go->neg_cbcp, CBCP_OPT);
1096    ACKCILONG(CI_MAGICNUMBER, go->neg_magicnumber, go->magicnumber);
1097    ACKCIVOID(CI_PCOMPRESSION, go->neg_pcompression);
1098    ACKCIVOID(CI_ACCOMPRESSION, go->neg_accompression);
1099#ifdef HAVE_MULTILINK
1100    ACKCISHORT(CI_MRRU, go->neg_mrru, go->mrru);
1101#endif /* HAVE_MULTILINK */
1102    ACKCIVOID(CI_SSNHF, go->neg_ssnhf);
1103    ACKCIENDP(CI_EPDISC, go->neg_endpoint, go->endpoint.class_,
1104	      go->endpoint.value, go->endpoint.length);
1105
1106    /*
1107     * If there are any remaining CIs, then this packet is bad.
1108     */
1109    if (len != 0)
1110	goto bad;
1111    return (1);
1112bad:
1113    LCPDEBUG(("lcp_acki: received bad Ack!"));
1114    return (0);
1115}
1116
1117
1118/*
1119 * lcp_nakci - Peer has sent a NAK for some of our CIs.
1120 * This should not modify any state if the Nak is bad
1121 * or if LCP is in the OPENED state.
1122 *
1123 * Returns:
1124 *	0 - Nak was bad.
1125 *	1 - Nak was good.
1126 */
1127static int lcp_nakci(fsm *f, u_char *p, int len, int treat_as_reject) {
1128    ppp_pcb *pcb = f->pcb;
1129    lcp_options *go = &pcb->lcp_gotoptions;
1130    lcp_options *wo = &pcb->lcp_wantoptions;
1131    u_char citype, cichar, *next;
1132    u_short cishort;
1133    u32_t cilong;
1134    lcp_options no;		/* options we've seen Naks for */
1135    lcp_options try_;		/* options to request next time */
1136    int looped_back = 0;
1137    int cilen;
1138
1139    BZERO(&no, sizeof(no));
1140    try_ = *go;
1141
1142    /*
1143     * Any Nak'd CIs must be in exactly the same order that we sent.
1144     * Check packet length and CI length at each step.
1145     * If we find any deviations, then this packet is bad.
1146     */
1147#define NAKCIVOID(opt, neg) \
1148    if (go->neg && \
1149	len >= CILEN_VOID && \
1150	p[1] == CILEN_VOID && \
1151	p[0] == opt) { \
1152	len -= CILEN_VOID; \
1153	INCPTR(CILEN_VOID, p); \
1154	no.neg = 1; \
1155	try_.neg = 0; \
1156    }
1157#if CHAP_SUPPORT
1158#define NAKCICHAP(opt, neg, code) \
1159    if (go->neg && \
1160	len >= CILEN_CHAP && \
1161	p[1] == CILEN_CHAP && \
1162	p[0] == opt) { \
1163	len -= CILEN_CHAP; \
1164	INCPTR(2, p); \
1165	GETSHORT(cishort, p); \
1166	GETCHAR(cichar, p); \
1167	no.neg = 1; \
1168	code \
1169    }
1170#endif /* CHAP_SUPPORT */
1171#define NAKCICHAR(opt, neg, code) \
1172    if (go->neg && \
1173	len >= CILEN_CHAR && \
1174	p[1] == CILEN_CHAR && \
1175	p[0] == opt) { \
1176	len -= CILEN_CHAR; \
1177	INCPTR(2, p); \
1178	GETCHAR(cichar, p); \
1179	no.neg = 1; \
1180	code \
1181    }
1182#define NAKCISHORT(opt, neg, code) \
1183    if (go->neg && \
1184	len >= CILEN_SHORT && \
1185	p[1] == CILEN_SHORT && \
1186	p[0] == opt) { \
1187	len -= CILEN_SHORT; \
1188	INCPTR(2, p); \
1189	GETSHORT(cishort, p); \
1190	no.neg = 1; \
1191	code \
1192    }
1193#define NAKCILONG(opt, neg, code) \
1194    if (go->neg && \
1195	len >= CILEN_LONG && \
1196	p[1] == CILEN_LONG && \
1197	p[0] == opt) { \
1198	len -= CILEN_LONG; \
1199	INCPTR(2, p); \
1200	GETLONG(cilong, p); \
1201	no.neg = 1; \
1202	code \
1203    }
1204#if LQR_SUPPORT
1205#define NAKCILQR(opt, neg, code) \
1206    if (go->neg && \
1207	len >= CILEN_LQR && \
1208	p[1] == CILEN_LQR && \
1209	p[0] == opt) { \
1210	len -= CILEN_LQR; \
1211	INCPTR(2, p); \
1212	GETSHORT(cishort, p); \
1213	GETLONG(cilong, p); \
1214	no.neg = 1; \
1215	code \
1216    }
1217#endif /* LQR_SUPPORT */
1218#define NAKCIENDP(opt, neg) \
1219    if (go->neg && \
1220	len >= CILEN_CHAR && \
1221	p[0] == opt && \
1222	p[1] >= CILEN_CHAR && \
1223	p[1] <= len) { \
1224	len -= p[1]; \
1225	INCPTR(p[1], p); \
1226	no.neg = 1; \
1227	try_.neg = 0; \
1228    }
1229
1230    /*
1231     * NOTE!  There must be no assignments to individual fields of *go in
1232     * the code below.  Any such assignment is a BUG!
1233     */
1234    /*
1235     * We don't care if they want to send us smaller packets than
1236     * we want.  Therefore, accept any MRU less than what we asked for,
1237     * but then ignore the new value when setting the MRU in the kernel.
1238     * If they send us a bigger MRU than what we asked, accept it, up to
1239     * the limit of the default MRU we'd get if we didn't negotiate.
1240     */
1241    if (go->neg_mru && go->mru != PPP_DEFMRU) {
1242	NAKCISHORT(CI_MRU, neg_mru,
1243		   if (cishort <= wo->mru || cishort <= PPP_DEFMRU)
1244		       try_.mru = cishort;
1245		   );
1246    }
1247
1248    /*
1249     * Add any characters they want to our (receive-side) asyncmap.
1250     */
1251    if (go->neg_asyncmap && go->asyncmap != 0xFFFFFFFF) {
1252	NAKCILONG(CI_ASYNCMAP, neg_asyncmap,
1253		  try_.asyncmap = go->asyncmap | cilong;
1254		  );
1255    }
1256
1257    /*
1258     * If they've nak'd our authentication-protocol, check whether
1259     * they are proposing a different protocol, or a different
1260     * hash algorithm for CHAP.
1261     */
1262    if ((0
1263#if CHAP_SUPPORT
1264        || go->neg_chap
1265#endif /* CHAP_SUPPORT */
1266#if PAP_SUPPORT
1267        || go->neg_upap
1268#endif /* PAP_SUPPORT */
1269#if EAP_SUPPORT
1270        || go->neg_eap
1271#endif /* EAP_SUPPORT */
1272        )
1273	&& len >= CILEN_SHORT
1274	&& p[0] == CI_AUTHTYPE && p[1] >= CILEN_SHORT && p[1] <= len) {
1275	cilen = p[1];
1276	len -= cilen;
1277#if CHAP_SUPPORT
1278	no.neg_chap = go->neg_chap;
1279#endif /* CHAP_SUPPORT */
1280#if PAP_SUPPORT
1281	no.neg_upap = go->neg_upap;
1282#endif /* PAP_SUPPORT */
1283#if EAP_SUPPORT
1284	no.neg_eap = go->neg_eap;
1285#endif /* EAP_SUPPORT */
1286	INCPTR(2, p);
1287	GETSHORT(cishort, p);
1288
1289#if PAP_SUPPORT
1290	if (cishort == PPP_PAP && cilen == CILEN_SHORT) {
1291#if EAP_SUPPORT
1292	    /* If we were asking for EAP, then we need to stop that. */
1293	    if (go->neg_eap)
1294		try_.neg_eap = 0;
1295	    else
1296#endif /* EAP_SUPPORT */
1297
1298#if CHAP_SUPPORT
1299	    /* If we were asking for CHAP, then we need to stop that. */
1300	    if (go->neg_chap)
1301		try_.neg_chap = 0;
1302	    else
1303#endif /* CHAP_SUPPORT */
1304
1305	    /*
1306	     * If we weren't asking for CHAP or EAP, then we were asking for
1307	     * PAP, in which case this Nak is bad.
1308	     */
1309		goto bad;
1310	} else
1311#endif /* PAP_SUPPORT */
1312
1313#if CHAP_SUPPORT
1314	if (cishort == PPP_CHAP && cilen == CILEN_CHAP) {
1315	    GETCHAR(cichar, p);
1316#if EAP_SUPPORT
1317	    /* Stop asking for EAP, if we were. */
1318	    if (go->neg_eap) {
1319		try_.neg_eap = 0;
1320		/* Try to set up to use their suggestion, if possible */
1321		if (CHAP_CANDIGEST(go->chap_mdtype, cichar))
1322		    try_.chap_mdtype = CHAP_MDTYPE_D(cichar);
1323	    } else
1324#endif /* EAP_SUPPORT */
1325	    if (go->neg_chap) {
1326		/*
1327		 * We were asking for our preferred algorithm, they must
1328		 * want something different.
1329		 */
1330		if (cichar != CHAP_DIGEST(go->chap_mdtype)) {
1331		    if (CHAP_CANDIGEST(go->chap_mdtype, cichar)) {
1332			/* Use their suggestion if we support it ... */
1333			try_.chap_mdtype = CHAP_MDTYPE_D(cichar);
1334		    } else {
1335			/* ... otherwise, try our next-preferred algorithm. */
1336			try_.chap_mdtype &= ~(CHAP_MDTYPE(try_.chap_mdtype));
1337			if (try_.chap_mdtype == MDTYPE_NONE) /* out of algos */
1338			    try_.neg_chap = 0;
1339		    }
1340		} else {
1341		    /*
1342		     * Whoops, they Nak'd our algorithm of choice
1343		     * but then suggested it back to us.
1344		     */
1345		    goto bad;
1346		}
1347	    } else {
1348		/*
1349		 * Stop asking for PAP if we were asking for it.
1350		 */
1351#if PAP_SUPPORT
1352		try_.neg_upap = 0;
1353#endif /* PAP_SUPPORT */
1354	    }
1355
1356	} else
1357#endif /* CHAP_SUPPORT */
1358	{
1359
1360#if EAP_SUPPORT
1361	    /*
1362	     * If we were asking for EAP, and they're Conf-Naking EAP,
1363	     * well, that's just strange.  Nobody should do that.
1364	     */
1365	    if (cishort == PPP_EAP && cilen == CILEN_SHORT && go->neg_eap)
1366		ppp_dbglog("Unexpected Conf-Nak for EAP");
1367
1368	    /*
1369	     * We don't recognize what they're suggesting.
1370	     * Stop asking for what we were asking for.
1371	     */
1372	    if (go->neg_eap)
1373		try_.neg_eap = 0;
1374	    else
1375#endif /* EAP_SUPPORT */
1376
1377#if CHAP_SUPPORT
1378	    if (go->neg_chap)
1379		try_.neg_chap = 0;
1380	    else
1381#endif /* CHAP_SUPPORT */
1382
1383#if PAP_SUPPORT
1384	    if(1)
1385		try_.neg_upap = 0;
1386	    else
1387#endif /* PAP_SUPPORT */
1388	    {}
1389
1390	    p += cilen - CILEN_SHORT;
1391	}
1392    }
1393
1394#if LQR_SUPPORT
1395    /*
1396     * If they can't cope with our link quality protocol, we'll have
1397     * to stop asking for LQR.  We haven't got any other protocol.
1398     * If they Nak the reporting period, take their value XXX ?
1399     */
1400    NAKCILQR(CI_QUALITY, neg_lqr,
1401	     if (cishort != PPP_LQR)
1402		 try_.neg_lqr = 0;
1403	     else
1404		 try_.lqr_period = cilong;
1405	     );
1406#endif /* LQR_SUPPORT */
1407
1408    /*
1409     * Only implementing CBCP...not the rest of the callback options
1410     */
1411    NAKCICHAR(CI_CALLBACK, neg_cbcp,
1412              try_.neg_cbcp = 0;
1413              (void)cichar; /* if CHAP support is not compiled, cichar is set but not used, which makes some compilers complaining */
1414              );
1415
1416    /*
1417     * Check for a looped-back line.
1418     */
1419    NAKCILONG(CI_MAGICNUMBER, neg_magicnumber,
1420	      try_.magicnumber = magic();
1421	      looped_back = 1;
1422	      );
1423
1424    /*
1425     * Peer shouldn't send Nak for protocol compression or
1426     * address/control compression requests; they should send
1427     * a Reject instead.  If they send a Nak, treat it as a Reject.
1428     */
1429    NAKCIVOID(CI_PCOMPRESSION, neg_pcompression);
1430    NAKCIVOID(CI_ACCOMPRESSION, neg_accompression);
1431
1432#ifdef HAVE_MULTILINK
1433    /*
1434     * Nak for MRRU option - accept their value if it is smaller
1435     * than the one we want.
1436     */
1437    if (go->neg_mrru) {
1438	NAKCISHORT(CI_MRRU, neg_mrru,
1439		   if (treat_as_reject)
1440		       try_.neg_mrru = 0;
1441		   else if (cishort <= wo->mrru)
1442		       try_.mrru = cishort;
1443		   );
1444    }
1445#else /* HAVE_MULTILINK */
1446    LWIP_UNUSED_ARG(treat_as_reject);
1447#endif /* HAVE_MULTILINK */
1448
1449    /*
1450     * Nak for short sequence numbers shouldn't be sent, treat it
1451     * like a reject.
1452     */
1453    NAKCIVOID(CI_SSNHF, neg_ssnhf);
1454
1455    /*
1456     * Nak of the endpoint discriminator option is not permitted,
1457     * treat it like a reject.
1458     */
1459    NAKCIENDP(CI_EPDISC, neg_endpoint);
1460
1461    /*
1462     * There may be remaining CIs, if the peer is requesting negotiation
1463     * on an option that we didn't include in our request packet.
1464     * If we see an option that we requested, or one we've already seen
1465     * in this packet, then this packet is bad.
1466     * If we wanted to respond by starting to negotiate on the requested
1467     * option(s), we could, but we don't, because except for the
1468     * authentication type and quality protocol, if we are not negotiating
1469     * an option, it is because we were told not to.
1470     * For the authentication type, the Nak from the peer means
1471     * `let me authenticate myself with you' which is a bit pointless.
1472     * For the quality protocol, the Nak means `ask me to send you quality
1473     * reports', but if we didn't ask for them, we don't want them.
1474     * An option we don't recognize represents the peer asking to
1475     * negotiate some option we don't support, so ignore it.
1476     */
1477    while (len >= CILEN_VOID) {
1478	GETCHAR(citype, p);
1479	GETCHAR(cilen, p);
1480	if (cilen < CILEN_VOID || (len -= cilen) < 0)
1481	    goto bad;
1482	next = p + cilen - 2;
1483
1484	switch (citype) {
1485	case CI_MRU:
1486	    if ((go->neg_mru && go->mru != PPP_DEFMRU)
1487		|| no.neg_mru || cilen != CILEN_SHORT)
1488		goto bad;
1489	    GETSHORT(cishort, p);
1490	    if (cishort < PPP_DEFMRU) {
1491		try_.neg_mru = 1;
1492		try_.mru = cishort;
1493	    }
1494	    break;
1495	case CI_ASYNCMAP:
1496	    if ((go->neg_asyncmap && go->asyncmap != 0xFFFFFFFF)
1497		|| no.neg_asyncmap || cilen != CILEN_LONG)
1498		goto bad;
1499	    break;
1500	case CI_AUTHTYPE:
1501	    if (0
1502#if CHAP_SUPPORT
1503                || go->neg_chap || no.neg_chap
1504#endif /* CHAP_SUPPORT */
1505#if PAP_SUPPORT
1506                || go->neg_upap || no.neg_upap
1507#endif /* PAP_SUPPORT */
1508#if EAP_SUPPORT
1509		|| go->neg_eap || no.neg_eap
1510#endif /* EAP_SUPPORT */
1511		)
1512		goto bad;
1513	    break;
1514	case CI_MAGICNUMBER:
1515	    if (go->neg_magicnumber || no.neg_magicnumber ||
1516		cilen != CILEN_LONG)
1517		goto bad;
1518	    break;
1519	case CI_PCOMPRESSION:
1520	    if (go->neg_pcompression || no.neg_pcompression
1521		|| cilen != CILEN_VOID)
1522		goto bad;
1523	    break;
1524	case CI_ACCOMPRESSION:
1525	    if (go->neg_accompression || no.neg_accompression
1526		|| cilen != CILEN_VOID)
1527		goto bad;
1528	    break;
1529#if LQR_SUPPORT
1530	case CI_QUALITY:
1531	    if (go->neg_lqr || no.neg_lqr || cilen != CILEN_LQR)
1532		goto bad;
1533	    break;
1534#endif /* LQR_SUPPORT */
1535#ifdef HAVE_MULTILINK
1536	case CI_MRRU:
1537	    if (go->neg_mrru || no.neg_mrru || cilen != CILEN_SHORT)
1538		goto bad;
1539	    break;
1540#endif /* HAVE_MULTILINK */
1541	case CI_SSNHF:
1542	    if (go->neg_ssnhf || no.neg_ssnhf || cilen != CILEN_VOID)
1543		goto bad;
1544	    try_.neg_ssnhf = 1;
1545	    break;
1546	case CI_EPDISC:
1547	    if (go->neg_endpoint || no.neg_endpoint || cilen < CILEN_CHAR)
1548		goto bad;
1549	    break;
1550	default:
1551	    break;
1552	}
1553	p = next;
1554    }
1555
1556    /*
1557     * OK, the Nak is good.  Now we can update state.
1558     * If there are any options left we ignore them.
1559     */
1560    if (f->state != PPP_FSM_OPENED) {
1561	if (looped_back) {
1562	    if (++try_.numloops >= pcb->settings.lcp_loopbackfail) {
1563		ppp_notice("Serial line is looped back.");
1564		pcb->err_code = PPPERR_LOOPBACK;
1565		lcp_close(f->pcb, "Loopback detected");
1566	    }
1567	} else
1568	    try_.numloops = 0;
1569	*go = try_;
1570    }
1571
1572    return 1;
1573
1574bad:
1575    LCPDEBUG(("lcp_nakci: received bad Nak!"));
1576    return 0;
1577}
1578
1579
1580/*
1581 * lcp_rejci - Peer has Rejected some of our CIs.
1582 * This should not modify any state if the Reject is bad
1583 * or if LCP is in the OPENED state.
1584 *
1585 * Returns:
1586 *	0 - Reject was bad.
1587 *	1 - Reject was good.
1588 */
1589static int lcp_rejci(fsm *f, u_char *p, int len) {
1590    ppp_pcb *pcb = f->pcb;
1591    lcp_options *go = &pcb->lcp_gotoptions;
1592    u_char cichar;
1593    u_short cishort;
1594    u32_t cilong;
1595    lcp_options try_;		/* options to request next time */
1596
1597    try_ = *go;
1598
1599    /*
1600     * Any Rejected CIs must be in exactly the same order that we sent.
1601     * Check packet length and CI length at each step.
1602     * If we find any deviations, then this packet is bad.
1603     */
1604#define REJCIVOID(opt, neg) \
1605    if (go->neg && \
1606	len >= CILEN_VOID && \
1607	p[1] == CILEN_VOID && \
1608	p[0] == opt) { \
1609	len -= CILEN_VOID; \
1610	INCPTR(CILEN_VOID, p); \
1611	try_.neg = 0; \
1612    }
1613#define REJCISHORT(opt, neg, val) \
1614    if (go->neg && \
1615	len >= CILEN_SHORT && \
1616	p[1] == CILEN_SHORT && \
1617	p[0] == opt) { \
1618	len -= CILEN_SHORT; \
1619	INCPTR(2, p); \
1620	GETSHORT(cishort, p); \
1621	/* Check rejected value. */ \
1622	if (cishort != val) \
1623	    goto bad; \
1624	try_.neg = 0; \
1625    }
1626
1627#if CHAP_SUPPORT && EAP_SUPPORT && PAP_SUPPORT
1628#define REJCICHAP(opt, neg, val) \
1629    if (go->neg && \
1630	len >= CILEN_CHAP && \
1631	p[1] == CILEN_CHAP && \
1632	p[0] == opt) { \
1633	len -= CILEN_CHAP; \
1634	INCPTR(2, p); \
1635	GETSHORT(cishort, p); \
1636	GETCHAR(cichar, p); \
1637	/* Check rejected value. */ \
1638	if ((cishort != PPP_CHAP) || (cichar != (CHAP_DIGEST(val)))) \
1639	    goto bad; \
1640	try_.neg = 0; \
1641	try_.neg_eap = try_.neg_upap = 0; \
1642    }
1643#endif /* CHAP_SUPPORT && EAP_SUPPORT && PAP_SUPPORT */
1644
1645#if CHAP_SUPPORT && !EAP_SUPPORT && PAP_SUPPORT
1646#define REJCICHAP(opt, neg, val) \
1647    if (go->neg && \
1648	len >= CILEN_CHAP && \
1649	p[1] == CILEN_CHAP && \
1650	p[0] == opt) { \
1651	len -= CILEN_CHAP; \
1652	INCPTR(2, p); \
1653	GETSHORT(cishort, p); \
1654	GETCHAR(cichar, p); \
1655	/* Check rejected value. */ \
1656	if ((cishort != PPP_CHAP) || (cichar != (CHAP_DIGEST(val)))) \
1657	    goto bad; \
1658	try_.neg = 0; \
1659	try_.neg_upap = 0; \
1660    }
1661#endif /* CHAP_SUPPORT && !EAP_SUPPORT && PAP_SUPPORT */
1662
1663#if CHAP_SUPPORT && EAP_SUPPORT && !PAP_SUPPORT
1664#define REJCICHAP(opt, neg, val) \
1665    if (go->neg && \
1666	len >= CILEN_CHAP && \
1667	p[1] == CILEN_CHAP && \
1668	p[0] == opt) { \
1669	len -= CILEN_CHAP; \
1670	INCPTR(2, p); \
1671	GETSHORT(cishort, p); \
1672	GETCHAR(cichar, p); \
1673	/* Check rejected value. */ \
1674	if ((cishort != PPP_CHAP) || (cichar != (CHAP_DIGEST(val)))) \
1675	    goto bad; \
1676	try_.neg = 0; \
1677	try_.neg_eap = 0; \
1678    }
1679#endif /* CHAP_SUPPORT && EAP_SUPPORT && !PAP_SUPPORT */
1680
1681#if CHAP_SUPPORT && !EAP_SUPPORT && !PAP_SUPPORT
1682#define REJCICHAP(opt, neg, val) \
1683    if (go->neg && \
1684	len >= CILEN_CHAP && \
1685	p[1] == CILEN_CHAP && \
1686	p[0] == opt) { \
1687	len -= CILEN_CHAP; \
1688	INCPTR(2, p); \
1689	GETSHORT(cishort, p); \
1690	GETCHAR(cichar, p); \
1691	/* Check rejected value. */ \
1692	if ((cishort != PPP_CHAP) || (cichar != (CHAP_DIGEST(val)))) \
1693	    goto bad; \
1694	try_.neg = 0; \
1695    }
1696#endif /* CHAP_SUPPORT && !EAP_SUPPORT && !PAP_SUPPORT */
1697
1698#define REJCILONG(opt, neg, val) \
1699    if (go->neg && \
1700	len >= CILEN_LONG && \
1701	p[1] == CILEN_LONG && \
1702	p[0] == opt) { \
1703	len -= CILEN_LONG; \
1704	INCPTR(2, p); \
1705	GETLONG(cilong, p); \
1706	/* Check rejected value. */ \
1707	if (cilong != val) \
1708	    goto bad; \
1709	try_.neg = 0; \
1710    }
1711#if LQR_SUPPORT
1712#define REJCILQR(opt, neg, val) \
1713    if (go->neg && \
1714	len >= CILEN_LQR && \
1715	p[1] == CILEN_LQR && \
1716	p[0] == opt) { \
1717	len -= CILEN_LQR; \
1718	INCPTR(2, p); \
1719	GETSHORT(cishort, p); \
1720	GETLONG(cilong, p); \
1721	/* Check rejected value. */ \
1722	if (cishort != PPP_LQR || cilong != val) \
1723	    goto bad; \
1724	try_.neg = 0; \
1725    }
1726#endif /* LQR_SUPPORT */
1727#define REJCICBCP(opt, neg, val) \
1728    if (go->neg && \
1729	len >= CILEN_CBCP && \
1730	p[1] == CILEN_CBCP && \
1731	p[0] == opt) { \
1732	len -= CILEN_CBCP; \
1733	INCPTR(2, p); \
1734	GETCHAR(cichar, p); \
1735	/* Check rejected value. */ \
1736	if (cichar != val) \
1737	    goto bad; \
1738	try_.neg = 0; \
1739    }
1740#define REJCIENDP(opt, neg, class, val, vlen) \
1741    if (go->neg && \
1742	len >= CILEN_CHAR + vlen && \
1743	p[0] == opt && \
1744	p[1] == CILEN_CHAR + vlen) { \
1745	int i; \
1746	len -= CILEN_CHAR + vlen; \
1747	INCPTR(2, p); \
1748	GETCHAR(cichar, p); \
1749	if (cichar != class) \
1750	    goto bad; \
1751	for (i = 0; i < vlen; ++i) { \
1752	    GETCHAR(cichar, p); \
1753	    if (cichar != val[i]) \
1754		goto bad; \
1755	} \
1756	try_.neg = 0; \
1757    }
1758
1759    REJCISHORT(CI_MRU, neg_mru, go->mru);
1760    REJCILONG(CI_ASYNCMAP, neg_asyncmap, go->asyncmap);
1761#if EAP_SUPPORT
1762    REJCISHORT(CI_AUTHTYPE, neg_eap, PPP_EAP);
1763    if (!go->neg_eap) {
1764#endif /* EAP_SUPPORT */
1765#if CHAP_SUPPORT
1766	REJCICHAP(CI_AUTHTYPE, neg_chap, go->chap_mdtype);
1767	if (!go->neg_chap) {
1768#endif /* CHAP_SUPPORT */
1769#if PAP_SUPPORT
1770	    REJCISHORT(CI_AUTHTYPE, neg_upap, PPP_PAP);
1771#endif /* PAP_SUPPORT */
1772#if CHAP_SUPPORT
1773	}
1774#endif /* CHAP_SUPPORT */
1775#if EAP_SUPPORT
1776    }
1777#endif /* EAP_SUPPORT */
1778#if LQR_SUPPORT
1779    REJCILQR(CI_QUALITY, neg_lqr, go->lqr_period);
1780#endif /* LQR_SUPPORT */
1781    REJCICBCP(CI_CALLBACK, neg_cbcp, CBCP_OPT);
1782    REJCILONG(CI_MAGICNUMBER, neg_magicnumber, go->magicnumber);
1783    REJCIVOID(CI_PCOMPRESSION, neg_pcompression);
1784    REJCIVOID(CI_ACCOMPRESSION, neg_accompression);
1785#ifdef HAVE_MULTILINK
1786    REJCISHORT(CI_MRRU, neg_mrru, go->mrru);
1787#endif /* HAVE_MULTILINK */
1788    REJCIVOID(CI_SSNHF, neg_ssnhf);
1789    REJCIENDP(CI_EPDISC, neg_endpoint, go->endpoint.class_,
1790	      go->endpoint.value, go->endpoint.length);
1791
1792    /*
1793     * If there are any remaining CIs, then this packet is bad.
1794     */
1795    if (len != 0)
1796	goto bad;
1797    /*
1798     * Now we can update state.
1799     */
1800    if (f->state != PPP_FSM_OPENED)
1801	*go = try_;
1802    return 1;
1803
1804bad:
1805    LCPDEBUG(("lcp_rejci: received bad Reject!"));
1806    return 0;
1807}
1808
1809
1810/*
1811 * lcp_reqci - Check the peer's requested CIs and send appropriate response.
1812 *
1813 * Returns: CONFACK, CONFNAK or CONFREJ and input packet modified
1814 * appropriately.  If reject_if_disagree is non-zero, doesn't return
1815 * CONFNAK; returns CONFREJ if it can't return CONFACK.
1816 *
1817 * inp = Requested CIs
1818 * lenp = Length of requested CIs
1819 */
1820static int lcp_reqci(fsm *f, u_char *inp, int *lenp, int reject_if_disagree) {
1821    ppp_pcb *pcb = f->pcb;
1822    lcp_options *go = &pcb->lcp_gotoptions;
1823    lcp_options *ho = &pcb->lcp_hisoptions;
1824    lcp_options *ao = &pcb->lcp_allowoptions;
1825    u_char *cip, *next;		/* Pointer to current and next CIs */
1826    int cilen, citype, cichar;	/* Parsed len, type, char value */
1827    u_short cishort;		/* Parsed short value */
1828    u32_t cilong;		/* Parse long value */
1829    int rc = CONFACK;		/* Final packet return code */
1830    int orc;			/* Individual option return code */
1831    u_char *p;			/* Pointer to next char to parse */
1832    u_char *rejp;		/* Pointer to next char in reject frame */
1833    struct pbuf *nakp;          /* Nak buffer */
1834    u_char *nakoutp;		/* Pointer to next char in Nak frame */
1835    int l = *lenp;		/* Length left */
1836
1837    /*
1838     * Reset all his options.
1839     */
1840    BZERO(ho, sizeof(*ho));
1841
1842    /*
1843     * Process all his options.
1844     */
1845    next = inp;
1846    nakp = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_CTRL_PBUF_MAX_SIZE), PPP_CTRL_PBUF_TYPE);
1847    if(NULL == nakp)
1848        return 0;
1849    if(nakp->tot_len != nakp->len) {
1850        pbuf_free(nakp);
1851        return 0;
1852    }
1853
1854    nakoutp = (u_char*)nakp->payload;
1855    rejp = inp;
1856    while (l) {
1857	orc = CONFACK;			/* Assume success */
1858	cip = p = next;			/* Remember begining of CI */
1859	if (l < 2 ||			/* Not enough data for CI header or */
1860	    p[1] < 2 ||			/*  CI length too small or */
1861	    p[1] > l) {			/*  CI length too big? */
1862	    LCPDEBUG(("lcp_reqci: bad CI length!"));
1863	    orc = CONFREJ;		/* Reject bad CI */
1864	    cilen = l;			/* Reject till end of packet */
1865	    l = 0;			/* Don't loop again */
1866	    citype = 0;
1867	    goto endswitch;
1868	}
1869	GETCHAR(citype, p);		/* Parse CI type */
1870	GETCHAR(cilen, p);		/* Parse CI length */
1871	l -= cilen;			/* Adjust remaining length */
1872	next += cilen;			/* Step to next CI */
1873
1874	switch (citype) {		/* Check CI type */
1875	case CI_MRU:
1876	    if (!ao->neg_mru ||		/* Allow option? */
1877		cilen != CILEN_SHORT) {	/* Check CI length */
1878		orc = CONFREJ;		/* Reject CI */
1879		break;
1880	    }
1881	    GETSHORT(cishort, p);	/* Parse MRU */
1882
1883	    /*
1884	     * He must be able to receive at least our minimum.
1885	     * No need to check a maximum.  If he sends a large number,
1886	     * we'll just ignore it.
1887	     */
1888	    if (cishort < PPP_MINMRU) {
1889		orc = CONFNAK;		/* Nak CI */
1890		PUTCHAR(CI_MRU, nakoutp);
1891		PUTCHAR(CILEN_SHORT, nakoutp);
1892		PUTSHORT(PPP_MINMRU, nakoutp);	/* Give him a hint */
1893		break;
1894	    }
1895	    ho->neg_mru = 1;		/* Remember he sent MRU */
1896	    ho->mru = cishort;		/* And remember value */
1897	    break;
1898
1899	case CI_ASYNCMAP:
1900	    if (!ao->neg_asyncmap ||
1901		cilen != CILEN_LONG) {
1902		orc = CONFREJ;
1903		break;
1904	    }
1905	    GETLONG(cilong, p);
1906
1907	    /*
1908	     * Asyncmap must have set at least the bits
1909	     * which are set in lcp_allowoptions[unit].asyncmap.
1910	     */
1911	    if ((ao->asyncmap & ~cilong) != 0) {
1912		orc = CONFNAK;
1913		PUTCHAR(CI_ASYNCMAP, nakoutp);
1914		PUTCHAR(CILEN_LONG, nakoutp);
1915		PUTLONG(ao->asyncmap | cilong, nakoutp);
1916		break;
1917	    }
1918	    ho->neg_asyncmap = 1;
1919	    ho->asyncmap = cilong;
1920	    break;
1921
1922	case CI_AUTHTYPE:
1923	    if (cilen < CILEN_SHORT ||
1924		!(0
1925#if PAP_SUPPORT
1926		|| ao->neg_upap
1927#endif /* PAP_SUPPORT */
1928#if CHAP_SUPPORT
1929		|| ao->neg_chap
1930#endif /* CHAP_SUPPORT */
1931#if EAP_SUPPORT
1932		|| ao->neg_eap
1933#endif /* EAP_SUPPORT */
1934		)) {
1935		/*
1936		 * Reject the option if we're not willing to authenticate.
1937		 */
1938		ppp_dbglog("No auth is possible");
1939		orc = CONFREJ;
1940		break;
1941	    }
1942	    GETSHORT(cishort, p);
1943
1944	    /*
1945	     * Authtype must be PAP, CHAP, or EAP.
1946	     *
1947	     * Note: if more than one of ao->neg_upap, ao->neg_chap, and
1948	     * ao->neg_eap are set, and the peer sends a Configure-Request
1949	     * with two or more authenticate-protocol requests, then we will
1950	     * reject the second request.
1951	     * Whether we end up doing CHAP, UPAP, or EAP depends then on
1952	     * the ordering of the CIs in the peer's Configure-Request.
1953             */
1954
1955#if PAP_SUPPORT
1956	    if (cishort == PPP_PAP) {
1957		/* we've already accepted CHAP or EAP */
1958		if (0
1959#if CHAP_SUPPORT
1960		    || ho->neg_chap
1961#endif /* CHAP_SUPPORT */
1962#if EAP_SUPPORT
1963		    || ho->neg_eap
1964#endif /* EAP_SUPPORT */
1965		    || cilen != CILEN_SHORT) {
1966		    LCPDEBUG(("lcp_reqci: rcvd AUTHTYPE PAP, rejecting..."));
1967		    orc = CONFREJ;
1968		    break;
1969		}
1970		if (!ao->neg_upap) {	/* we don't want to do PAP */
1971		    orc = CONFNAK;	/* NAK it and suggest CHAP or EAP */
1972		    PUTCHAR(CI_AUTHTYPE, nakoutp);
1973#if EAP_SUPPORT
1974		    if (ao->neg_eap) {
1975			PUTCHAR(CILEN_SHORT, nakoutp);
1976			PUTSHORT(PPP_EAP, nakoutp);
1977		    } else {
1978#endif /* EAP_SUPPORT */
1979#if CHAP_SUPPORT
1980			PUTCHAR(CILEN_CHAP, nakoutp);
1981			PUTSHORT(PPP_CHAP, nakoutp);
1982			PUTCHAR(CHAP_DIGEST(ao->chap_mdtype), nakoutp);
1983#endif /* CHAP_SUPPORT */
1984#if EAP_SUPPORT
1985		    }
1986#endif /* EAP_SUPPORT */
1987		    break;
1988		}
1989		ho->neg_upap = 1;
1990		break;
1991	    }
1992#endif /* PAP_SUPPORT */
1993#if CHAP_SUPPORT
1994	    if (cishort == PPP_CHAP) {
1995		/* we've already accepted PAP or EAP */
1996		if (
1997#if PAP_SUPPORT
1998		    ho->neg_upap ||
1999#endif /* PAP_SUPPORT */
2000#if EAP_SUPPORT
2001		    ho->neg_eap ||
2002#endif /* EAP_SUPPORT */
2003		    cilen != CILEN_CHAP) {
2004		    LCPDEBUG(("lcp_reqci: rcvd AUTHTYPE CHAP, rejecting..."));
2005		    orc = CONFREJ;
2006		    break;
2007		}
2008		if (!ao->neg_chap) {	/* we don't want to do CHAP */
2009		    orc = CONFNAK;	/* NAK it and suggest EAP or PAP */
2010		    PUTCHAR(CI_AUTHTYPE, nakoutp);
2011		    PUTCHAR(CILEN_SHORT, nakoutp);
2012#if EAP_SUPPORT
2013		    if (ao->neg_eap) {
2014			PUTSHORT(PPP_EAP, nakoutp);
2015		    } else
2016#endif /* EAP_SUPPORT */
2017#if PAP_SUPPORT
2018		    if(1) {
2019			PUTSHORT(PPP_PAP, nakoutp);
2020		    }
2021		    else
2022#endif /* PAP_SUPPORT */
2023		    {}
2024		    break;
2025		}
2026		GETCHAR(cichar, p);	/* get digest type */
2027		if (!(CHAP_CANDIGEST(ao->chap_mdtype, cichar))) {
2028		    /*
2029		     * We can't/won't do the requested type,
2030		     * suggest something else.
2031		     */
2032		    orc = CONFNAK;
2033		    PUTCHAR(CI_AUTHTYPE, nakoutp);
2034		    PUTCHAR(CILEN_CHAP, nakoutp);
2035		    PUTSHORT(PPP_CHAP, nakoutp);
2036		    PUTCHAR(CHAP_DIGEST(ao->chap_mdtype), nakoutp);
2037		    break;
2038		}
2039		ho->chap_mdtype = CHAP_MDTYPE_D(cichar); /* save md type */
2040		ho->neg_chap = 1;
2041		break;
2042	    }
2043#endif /* CHAP_SUPPORT */
2044#if EAP_SUPPORT
2045	    if (cishort == PPP_EAP) {
2046		/* we've already accepted CHAP or PAP */
2047		if (
2048#if CHAP_SUPPORT
2049		    ho->neg_chap ||
2050#endif /* CHAP_SUPPORT */
2051#if PAP_SUPPORT
2052		    ho->neg_upap ||
2053#endif /* PAP_SUPPORT */
2054		    cilen != CILEN_SHORT) {
2055		    LCPDEBUG(("lcp_reqci: rcvd AUTHTYPE EAP, rejecting..."));
2056		    orc = CONFREJ;
2057		    break;
2058		}
2059		if (!ao->neg_eap) {	/* we don't want to do EAP */
2060		    orc = CONFNAK;	/* NAK it and suggest CHAP or PAP */
2061		    PUTCHAR(CI_AUTHTYPE, nakoutp);
2062#if CHAP_SUPPORT
2063		    if (ao->neg_chap) {
2064			PUTCHAR(CILEN_CHAP, nakoutp);
2065			PUTSHORT(PPP_CHAP, nakoutp);
2066			PUTCHAR(CHAP_DIGEST(ao->chap_mdtype), nakoutp);
2067		    } else
2068#endif /* CHAP_SUPPORT */
2069#if PAP_SUPPORT
2070		    if(1) {
2071			PUTCHAR(CILEN_SHORT, nakoutp);
2072			PUTSHORT(PPP_PAP, nakoutp);
2073		    } else
2074#endif /* PAP_SUPPORT */
2075		    {}
2076		    break;
2077		}
2078		ho->neg_eap = 1;
2079		break;
2080	    }
2081#endif /* EAP_SUPPORT */
2082
2083	    /*
2084	     * We don't recognize the protocol they're asking for.
2085	     * Nak it with something we're willing to do.
2086	     * (At this point we know ao->neg_upap || ao->neg_chap ||
2087	     * ao->neg_eap.)
2088	     */
2089	    orc = CONFNAK;
2090	    PUTCHAR(CI_AUTHTYPE, nakoutp);
2091
2092#if EAP_SUPPORT
2093	    if (ao->neg_eap) {
2094		PUTCHAR(CILEN_SHORT, nakoutp);
2095		PUTSHORT(PPP_EAP, nakoutp);
2096	    } else
2097#endif /* EAP_SUPPORT */
2098#if CHAP_SUPPORT
2099	    if (ao->neg_chap) {
2100		PUTCHAR(CILEN_CHAP, nakoutp);
2101		PUTSHORT(PPP_CHAP, nakoutp);
2102		PUTCHAR(CHAP_DIGEST(ao->chap_mdtype), nakoutp);
2103	    } else
2104#endif /* CHAP_SUPPORT */
2105#if PAP_SUPPORT
2106	    if(1) {
2107		PUTCHAR(CILEN_SHORT, nakoutp);
2108		PUTSHORT(PPP_PAP, nakoutp);
2109	    } else
2110#endif /* PAP_SUPPORT */
2111	    {}
2112	    break;
2113
2114#if LQR_SUPPORT
2115	case CI_QUALITY:
2116	    if (!ao->neg_lqr ||
2117		cilen != CILEN_LQR) {
2118		orc = CONFREJ;
2119		break;
2120	    }
2121
2122	    GETSHORT(cishort, p);
2123	    GETLONG(cilong, p);
2124
2125	    /*
2126	     * Check the protocol and the reporting period.
2127	     * XXX When should we Nak this, and what with?
2128	     */
2129	    if (cishort != PPP_LQR) {
2130		orc = CONFNAK;
2131		PUTCHAR(CI_QUALITY, nakoutp);
2132		PUTCHAR(CILEN_LQR, nakoutp);
2133		PUTSHORT(PPP_LQR, nakoutp);
2134		PUTLONG(ao->lqr_period, nakoutp);
2135		break;
2136	    }
2137	    break;
2138#endif /* LQR_SUPPORT */
2139
2140	case CI_MAGICNUMBER:
2141	    if (!(ao->neg_magicnumber || go->neg_magicnumber) ||
2142		cilen != CILEN_LONG) {
2143		orc = CONFREJ;
2144		break;
2145	    }
2146	    GETLONG(cilong, p);
2147
2148	    /*
2149	     * He must have a different magic number.
2150	     */
2151	    if (go->neg_magicnumber &&
2152		cilong == go->magicnumber) {
2153		cilong = magic();	/* Don't put magic() inside macro! */
2154		orc = CONFNAK;
2155		PUTCHAR(CI_MAGICNUMBER, nakoutp);
2156		PUTCHAR(CILEN_LONG, nakoutp);
2157		PUTLONG(cilong, nakoutp);
2158		break;
2159	    }
2160	    ho->neg_magicnumber = 1;
2161	    ho->magicnumber = cilong;
2162	    break;
2163
2164
2165	case CI_PCOMPRESSION:
2166	    if (!ao->neg_pcompression ||
2167		cilen != CILEN_VOID) {
2168		orc = CONFREJ;
2169		break;
2170	    }
2171	    ho->neg_pcompression = 1;
2172	    break;
2173
2174	case CI_ACCOMPRESSION:
2175	    if (!ao->neg_accompression ||
2176		cilen != CILEN_VOID) {
2177		orc = CONFREJ;
2178		break;
2179	    }
2180	    ho->neg_accompression = 1;
2181	    break;
2182
2183#ifdef HAVE_MULTILINK
2184	case CI_MRRU:
2185	    if (!ao->neg_mrru
2186		|| !multilink
2187		|| cilen != CILEN_SHORT) {
2188		orc = CONFREJ;
2189		break;
2190	    }
2191
2192	    GETSHORT(cishort, p);
2193	    /* possibly should insist on a minimum/maximum MRRU here */
2194	    ho->neg_mrru = 1;
2195	    ho->mrru = cishort;
2196	    break;
2197#endif /* HAVE_MULTILINK */
2198
2199	case CI_SSNHF:
2200	    if (!ao->neg_ssnhf
2201#ifdef HAVE_MULTILINK
2202		|| !multilink
2203#endif /* HAVE_MULTILINK */
2204		|| cilen != CILEN_VOID) {
2205		orc = CONFREJ;
2206		break;
2207	    }
2208	    ho->neg_ssnhf = 1;
2209	    break;
2210
2211	case CI_EPDISC:
2212	    if (!ao->neg_endpoint ||
2213		cilen < CILEN_CHAR ||
2214		cilen > CILEN_CHAR + MAX_ENDP_LEN) {
2215		orc = CONFREJ;
2216		break;
2217	    }
2218	    GETCHAR(cichar, p);
2219	    cilen -= CILEN_CHAR;
2220	    ho->neg_endpoint = 1;
2221	    ho->endpoint.class_ = cichar;
2222	    ho->endpoint.length = cilen;
2223	    MEMCPY(ho->endpoint.value, p, cilen);
2224	    INCPTR(cilen, p);
2225	    break;
2226
2227	default:
2228	    LCPDEBUG(("lcp_reqci: rcvd unknown option %d", citype));
2229	    orc = CONFREJ;
2230	    break;
2231	}
2232
2233endswitch:
2234	if (orc == CONFACK &&		/* Good CI */
2235	    rc != CONFACK)		/*  but prior CI wasnt? */
2236	    continue;			/* Don't send this one */
2237
2238	if (orc == CONFNAK) {		/* Nak this CI? */
2239	    if (reject_if_disagree	/* Getting fed up with sending NAKs? */
2240		&& citype != CI_MAGICNUMBER) {
2241		orc = CONFREJ;		/* Get tough if so */
2242	    } else {
2243		if (rc == CONFREJ)	/* Rejecting prior CI? */
2244		    continue;		/* Don't send this one */
2245		rc = CONFNAK;
2246	    }
2247	}
2248	if (orc == CONFREJ) {		/* Reject this CI */
2249	    rc = CONFREJ;
2250	    if (cip != rejp)		/* Need to move rejected CI? */
2251		MEMCPY(rejp, cip, cilen); /* Move it */
2252	    INCPTR(cilen, rejp);	/* Update output pointer */
2253	}
2254    }
2255
2256    /*
2257     * If we wanted to send additional NAKs (for unsent CIs), the
2258     * code would go here.  The extra NAKs would go at *nakoutp.
2259     * At present there are no cases where we want to ask the
2260     * peer to negotiate an option.
2261     */
2262
2263    switch (rc) {
2264    case CONFACK:
2265	*lenp = next - inp;
2266	break;
2267    case CONFNAK:
2268	/*
2269	 * Copy the Nak'd options from the nak buffer to the caller's buffer.
2270	 */
2271	*lenp = nakoutp - (u_char*)nakp->payload;
2272	MEMCPY(inp, nakp->payload, *lenp);
2273	break;
2274    case CONFREJ:
2275	*lenp = rejp - inp;
2276	break;
2277    default:
2278	break;
2279    }
2280
2281    pbuf_free(nakp);
2282    LCPDEBUG(("lcp_reqci: returning CONF%s.", CODENAME(rc)));
2283    return (rc);			/* Return final code */
2284}
2285
2286
2287/*
2288 * lcp_up - LCP has come UP.
2289 */
2290static void lcp_up(fsm *f) {
2291    ppp_pcb *pcb = f->pcb;
2292    lcp_options *wo = &pcb->lcp_wantoptions;
2293    lcp_options *ho = &pcb->lcp_hisoptions;
2294    lcp_options *go = &pcb->lcp_gotoptions;
2295    lcp_options *ao = &pcb->lcp_allowoptions;
2296    int mtu, mru;
2297
2298    if (!go->neg_magicnumber)
2299	go->magicnumber = 0;
2300    if (!ho->neg_magicnumber)
2301	ho->magicnumber = 0;
2302
2303    /*
2304     * Set our MTU to the smaller of the MTU we wanted and
2305     * the MRU our peer wanted.  If we negotiated an MRU,
2306     * set our MRU to the larger of value we wanted and
2307     * the value we got in the negotiation.
2308     * Note on the MTU: the link MTU can be the MRU the peer wanted,
2309     * the interface MTU is set to the lowest of that, the
2310     * MTU we want to use, and our link MRU.
2311     */
2312    mtu = ho->neg_mru? ho->mru: PPP_MRU;
2313    mru = go->neg_mru? LWIP_MAX(wo->mru, go->mru): PPP_MRU;
2314#ifdef HAVE_MULTILINK
2315    if (!(multilink && go->neg_mrru && ho->neg_mrru))
2316#endif /* HAVE_MULTILINK */
2317	netif_set_mtu(pcb, LWIP_MIN(LWIP_MIN(mtu, mru), ao->mru));
2318    ppp_send_config(pcb, mtu,
2319		    (ho->neg_asyncmap? ho->asyncmap: 0xffffffff),
2320		    ho->neg_pcompression, ho->neg_accompression);
2321    ppp_recv_config(pcb, mru,
2322		    (pcb->settings.lax_recv? 0: go->neg_asyncmap? go->asyncmap: 0xffffffff),
2323		    go->neg_pcompression, go->neg_accompression);
2324
2325    if (ho->neg_mru)
2326	pcb->peer_mru = ho->mru;
2327
2328    lcp_echo_lowerup(f->pcb);  /* Enable echo messages */
2329
2330    link_established(pcb);
2331}
2332
2333
2334/*
2335 * lcp_down - LCP has gone DOWN.
2336 *
2337 * Alert other protocols.
2338 */
2339static void lcp_down(fsm *f) {
2340    ppp_pcb *pcb = f->pcb;
2341    lcp_options *go = &pcb->lcp_gotoptions;
2342
2343    lcp_echo_lowerdown(f->pcb);
2344
2345    link_down(pcb);
2346
2347    ppp_send_config(pcb, PPP_MRU, 0xffffffff, 0, 0);
2348    ppp_recv_config(pcb, PPP_MRU,
2349		    (go->neg_asyncmap? go->asyncmap: 0xffffffff),
2350		    go->neg_pcompression, go->neg_accompression);
2351    pcb->peer_mru = PPP_MRU;
2352}
2353
2354
2355/*
2356 * lcp_starting - LCP needs the lower layer up.
2357 */
2358static void lcp_starting(fsm *f) {
2359    ppp_pcb *pcb = f->pcb;
2360    link_required(pcb);
2361}
2362
2363
2364/*
2365 * lcp_finished - LCP has finished with the lower layer.
2366 */
2367static void lcp_finished(fsm *f) {
2368    ppp_pcb *pcb = f->pcb;
2369    link_terminated(pcb);
2370}
2371
2372
2373#if PRINTPKT_SUPPORT
2374/*
2375 * lcp_printpkt - print the contents of an LCP packet.
2376 */
2377static const char* const lcp_codenames[] = {
2378    "ConfReq", "ConfAck", "ConfNak", "ConfRej",
2379    "TermReq", "TermAck", "CodeRej", "ProtRej",
2380    "EchoReq", "EchoRep", "DiscReq", "Ident",
2381    "TimeRem"
2382};
2383
2384static int lcp_printpkt(const u_char *p, int plen,
2385		void (*printer) (void *, const char *, ...), void *arg) {
2386    int code, id, len, olen, i;
2387    const u_char *pstart, *optend;
2388    u_short cishort;
2389    u32_t cilong;
2390
2391    if (plen < HEADERLEN)
2392	return 0;
2393    pstart = p;
2394    GETCHAR(code, p);
2395    GETCHAR(id, p);
2396    GETSHORT(len, p);
2397    if (len < HEADERLEN || len > plen)
2398	return 0;
2399
2400   if (code >= 1 && code <= (int)LWIP_ARRAYSIZE(lcp_codenames))
2401	printer(arg, " %s", lcp_codenames[code-1]);
2402    else
2403	printer(arg, " code=0x%x", code);
2404    printer(arg, " id=0x%x", id);
2405    len -= HEADERLEN;
2406    switch (code) {
2407    case CONFREQ:
2408    case CONFACK:
2409    case CONFNAK:
2410    case CONFREJ:
2411	/* print option list */
2412	while (len >= 2) {
2413	    GETCHAR(code, p);
2414	    GETCHAR(olen, p);
2415	    p -= 2;
2416	    if (olen < 2 || olen > len) {
2417		break;
2418	    }
2419	    printer(arg, " <");
2420	    len -= olen;
2421	    optend = p + olen;
2422	    switch (code) {
2423	    case CI_MRU:
2424		if (olen == CILEN_SHORT) {
2425		    p += 2;
2426		    GETSHORT(cishort, p);
2427		    printer(arg, "mru %d", cishort);
2428		}
2429		break;
2430	    case CI_ASYNCMAP:
2431		if (olen == CILEN_LONG) {
2432		    p += 2;
2433		    GETLONG(cilong, p);
2434		    printer(arg, "asyncmap 0x%x", cilong);
2435		}
2436		break;
2437	    case CI_AUTHTYPE:
2438		if (olen >= CILEN_SHORT) {
2439		    p += 2;
2440		    printer(arg, "auth ");
2441		    GETSHORT(cishort, p);
2442		    switch (cishort) {
2443#if PAP_SUPPORT
2444		    case PPP_PAP:
2445			printer(arg, "pap");
2446			break;
2447#endif /* PAP_SUPPORT */
2448#if CHAP_SUPPORT
2449		    case PPP_CHAP:
2450			printer(arg, "chap");
2451			if (p < optend) {
2452			    switch (*p) {
2453			    case CHAP_MD5:
2454				printer(arg, " MD5");
2455				++p;
2456				break;
2457#if MSCHAP_SUPPORT
2458			    case CHAP_MICROSOFT:
2459				printer(arg, " MS");
2460				++p;
2461				break;
2462
2463			    case CHAP_MICROSOFT_V2:
2464				printer(arg, " MS-v2");
2465				++p;
2466				break;
2467#endif /* MSCHAP_SUPPORT */
2468			    default:
2469				break;
2470			    }
2471			}
2472			break;
2473#endif /* CHAP_SUPPORT */
2474#if EAP_SUPPORT
2475		    case PPP_EAP:
2476			printer(arg, "eap");
2477			break;
2478#endif /* EAP_SUPPORT */
2479		    default:
2480			printer(arg, "0x%x", cishort);
2481		    }
2482		}
2483		break;
2484#if LQR_SUPPORT
2485	    case CI_QUALITY:
2486		if (olen >= CILEN_SHORT) {
2487		    p += 2;
2488		    printer(arg, "quality ");
2489		    GETSHORT(cishort, p);
2490		    switch (cishort) {
2491		    case PPP_LQR:
2492			printer(arg, "lqr");
2493			break;
2494		    default:
2495			printer(arg, "0x%x", cishort);
2496		    }
2497		}
2498		break;
2499#endif /* LQR_SUPPORT */
2500	    case CI_CALLBACK:
2501		if (olen >= CILEN_CHAR) {
2502		    p += 2;
2503		    printer(arg, "callback ");
2504		    GETCHAR(cishort, p);
2505		    switch (cishort) {
2506		    case CBCP_OPT:
2507			printer(arg, "CBCP");
2508			break;
2509		    default:
2510			printer(arg, "0x%x", cishort);
2511		    }
2512		}
2513		break;
2514	    case CI_MAGICNUMBER:
2515		if (olen == CILEN_LONG) {
2516		    p += 2;
2517		    GETLONG(cilong, p);
2518		    printer(arg, "magic 0x%x", cilong);
2519		}
2520		break;
2521	    case CI_PCOMPRESSION:
2522		if (olen == CILEN_VOID) {
2523		    p += 2;
2524		    printer(arg, "pcomp");
2525		}
2526		break;
2527	    case CI_ACCOMPRESSION:
2528		if (olen == CILEN_VOID) {
2529		    p += 2;
2530		    printer(arg, "accomp");
2531		}
2532		break;
2533	    case CI_MRRU:
2534		if (olen == CILEN_SHORT) {
2535		    p += 2;
2536		    GETSHORT(cishort, p);
2537		    printer(arg, "mrru %d", cishort);
2538		}
2539		break;
2540	    case CI_SSNHF:
2541		if (olen == CILEN_VOID) {
2542		    p += 2;
2543		    printer(arg, "ssnhf");
2544		}
2545		break;
2546	    case CI_EPDISC:
2547#ifdef HAVE_MULTILINK
2548		if (olen >= CILEN_CHAR) {
2549		    struct epdisc epd;
2550		    p += 2;
2551		    GETCHAR(epd.class, p);
2552		    epd.length = olen - CILEN_CHAR;
2553		    if (epd.length > MAX_ENDP_LEN)
2554			epd.length = MAX_ENDP_LEN;
2555		    if (epd.length > 0) {
2556			MEMCPY(epd.value, p, epd.length);
2557			p += epd.length;
2558		    }
2559		    printer(arg, "endpoint [%s]", epdisc_to_str(&epd));
2560		}
2561#else
2562		printer(arg, "endpoint");
2563#endif
2564		break;
2565	    default:
2566		break;
2567	    }
2568	    while (p < optend) {
2569		GETCHAR(code, p);
2570		printer(arg, " %.2x", code);
2571	    }
2572	    printer(arg, ">");
2573	}
2574	break;
2575
2576    case TERMACK:
2577    case TERMREQ:
2578	if (len > 0 && *p >= ' ' && *p < 0x7f) {
2579	    printer(arg, " ");
2580	    ppp_print_string(p, len, printer, arg);
2581	    p += len;
2582	    len = 0;
2583	}
2584	break;
2585
2586    case ECHOREQ:
2587    case ECHOREP:
2588    case DISCREQ:
2589	if (len >= 4) {
2590	    GETLONG(cilong, p);
2591	    printer(arg, " magic=0x%x", cilong);
2592	    len -= 4;
2593	}
2594	break;
2595
2596    case IDENTIF:
2597    case TIMEREM:
2598	if (len >= 4) {
2599	    GETLONG(cilong, p);
2600	    printer(arg, " magic=0x%x", cilong);
2601	    len -= 4;
2602	}
2603	if (code == TIMEREM) {
2604	    if (len < 4)
2605		break;
2606	    GETLONG(cilong, p);
2607	    printer(arg, " seconds=%u", cilong);
2608	    len -= 4;
2609	}
2610	if (len > 0) {
2611	    printer(arg, " ");
2612	    ppp_print_string(p, len, printer, arg);
2613	    p += len;
2614	    len = 0;
2615	}
2616	break;
2617    default:
2618	break;
2619    }
2620
2621    /* print the rest of the bytes in the packet */
2622    for (i = 0; i < len && i < 32; ++i) {
2623	GETCHAR(code, p);
2624	printer(arg, " %.2x", code);
2625    }
2626    if (i < len) {
2627	printer(arg, " ...");
2628	p += len - i;
2629    }
2630
2631    return p - pstart;
2632}
2633#endif /* PRINTPKT_SUPPORT */
2634
2635/*
2636 * Time to shut down the link because there is nothing out there.
2637 */
2638
2639static void LcpLinkFailure(fsm *f) {
2640    ppp_pcb *pcb = f->pcb;
2641    if (f->state == PPP_FSM_OPENED) {
2642	ppp_info("No response to %d echo-requests", pcb->lcp_echos_pending);
2643        ppp_notice("Serial link appears to be disconnected.");
2644	pcb->err_code = PPPERR_PEERDEAD;
2645	lcp_close(pcb, "Peer not responding");
2646    }
2647}
2648
2649/*
2650 * Timer expired for the LCP echo requests from this process.
2651 */
2652
2653static void LcpEchoCheck(fsm *f) {
2654    ppp_pcb *pcb = f->pcb;
2655
2656    LcpSendEchoRequest (f);
2657    if (f->state != PPP_FSM_OPENED)
2658	return;
2659
2660    /*
2661     * Start the timer for the next interval.
2662     */
2663    if (pcb->lcp_echo_timer_running)
2664	ppp_warn("assertion lcp_echo_timer_running==0 failed");
2665    TIMEOUT (LcpEchoTimeout, f, pcb->settings.lcp_echo_interval);
2666    pcb->lcp_echo_timer_running = 1;
2667}
2668
2669/*
2670 * LcpEchoTimeout - Timer expired on the LCP echo
2671 */
2672
2673static void LcpEchoTimeout(void *arg) {
2674    fsm *f = (fsm*)arg;
2675    ppp_pcb *pcb = f->pcb;
2676    if (pcb->lcp_echo_timer_running != 0) {
2677        pcb->lcp_echo_timer_running = 0;
2678        LcpEchoCheck ((fsm *) arg);
2679    }
2680}
2681
2682/*
2683 * LcpEchoReply - LCP has received a reply to the echo
2684 */
2685
2686static void lcp_received_echo_reply(fsm *f, int id, u_char *inp, int len) {
2687    ppp_pcb *pcb = f->pcb;
2688    lcp_options *go = &pcb->lcp_gotoptions;
2689    u32_t magic_val;
2690    LWIP_UNUSED_ARG(id);
2691
2692    /* Check the magic number - don't count replies from ourselves. */
2693    if (len < 4) {
2694	ppp_dbglog("lcp: received short Echo-Reply, length %d", len);
2695	return;
2696    }
2697    GETLONG(magic_val, inp);
2698    if (go->neg_magicnumber
2699	&& magic_val == go->magicnumber) {
2700	ppp_warn("appear to have received our own echo-reply!");
2701	return;
2702    }
2703
2704    /* Reset the number of outstanding echo frames */
2705    pcb->lcp_echos_pending = 0;
2706}
2707
2708/*
2709 * LcpSendEchoRequest - Send an echo request frame to the peer
2710 */
2711
2712static void LcpSendEchoRequest(fsm *f) {
2713    ppp_pcb *pcb = f->pcb;
2714    lcp_options *go = &pcb->lcp_gotoptions;
2715    u32_t lcp_magic;
2716    u_char pkt[4], *pktp;
2717
2718    /*
2719     * Detect the failure of the peer at this point.
2720     */
2721    if (pcb->settings.lcp_echo_fails != 0) {
2722        if (pcb->lcp_echos_pending >= pcb->settings.lcp_echo_fails) {
2723            LcpLinkFailure(f);
2724            pcb->lcp_echos_pending = 0;
2725	}
2726    }
2727
2728#if PPP_LCP_ADAPTIVE
2729    /*
2730     * If adaptive echos have been enabled, only send the echo request if
2731     * no traffic was received since the last one.
2732     */
2733    if (pcb->settings.lcp_echo_adaptive) {
2734	static unsigned int last_pkts_in = 0;
2735
2736#if PPP_STATS_SUPPORT
2737	update_link_stats(f->unit);
2738	link_stats_valid = 0;
2739#endif /* PPP_STATS_SUPPORT */
2740
2741	if (link_stats.pkts_in != last_pkts_in) {
2742	    last_pkts_in = link_stats.pkts_in;
2743	    return;
2744	}
2745    }
2746#endif
2747
2748    /*
2749     * Make and send the echo request frame.
2750     */
2751    if (f->state == PPP_FSM_OPENED) {
2752        lcp_magic = go->magicnumber;
2753	pktp = pkt;
2754	PUTLONG(lcp_magic, pktp);
2755        fsm_sdata(f, ECHOREQ, pcb->lcp_echo_number++, pkt, pktp - pkt);
2756	++pcb->lcp_echos_pending;
2757    }
2758}
2759
2760/*
2761 * lcp_echo_lowerup - Start the timer for the LCP frame
2762 */
2763
2764static void lcp_echo_lowerup(ppp_pcb *pcb) {
2765    fsm *f = &pcb->lcp_fsm;
2766
2767    /* Clear the parameters for generating echo frames */
2768    pcb->lcp_echos_pending      = 0;
2769    pcb->lcp_echo_number        = 0;
2770    pcb->lcp_echo_timer_running = 0;
2771
2772    /* If a timeout interval is specified then start the timer */
2773    if (pcb->settings.lcp_echo_interval != 0)
2774        LcpEchoCheck (f);
2775}
2776
2777/*
2778 * lcp_echo_lowerdown - Stop the timer for the LCP frame
2779 */
2780
2781static void lcp_echo_lowerdown(ppp_pcb *pcb) {
2782    fsm *f = &pcb->lcp_fsm;
2783
2784    if (pcb->lcp_echo_timer_running != 0) {
2785        UNTIMEOUT (LcpEchoTimeout, f);
2786        pcb->lcp_echo_timer_running = 0;
2787    }
2788}
2789
2790#endif /* PPP_SUPPORT */
2791