Fix for x86_64 build fail
[platform/upstream/connectedhomeip.git] / third_party / lwip / repo / lwip / src / netif / ppp / lcp.c
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
73 static void lcp_delayed_up(void *arg);
74
75 /*
76  * LCP-related command-line options.
77  */
78 #if 0 /* UNUSED */
79 int     lcp_echo_interval = 0;  /* Interval between LCP echo-requests */
80 int     lcp_echo_fails = 0;     /* Tolerance to unanswered echo-requests */
81 #endif /* UNUSED */
82
83 #if 0 /* UNUSED */
84 /* options */
85 static u_int lcp_echo_interval      = LCP_ECHOINTERVAL; /* Interval between LCP echo-requests */
86 static 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
91 bool    lcp_echo_adaptive = 0;  /* request echo only if the link was idle */
92 #endif
93 bool    lax_recv = 0;           /* accept control chars in asyncmap */
94 bool    noendpoint = 0;         /* don't send/accept endpoint discriminator */
95 #endif /* UNUSED */
96
97 #if PPP_OPTIONS
98 static int noopt (char **);
99 #endif /* PPP_OPTIONS */
100
101 #ifdef HAVE_MULTILINK
102 static int setendpoint (char **);
103 static void printendpoint (option_t *, void (*)(void *, char *, ...),
104                                void *);
105 #endif /* HAVE_MULTILINK */
106
107 #if PPP_OPTIONS
108 static 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  */
218 static void lcp_resetci(fsm *f);        /* Reset our CI */
219 static int  lcp_cilen(fsm *f);          /* Return length of our CI */
220 static void lcp_addci(fsm *f, u_char *ucp, int *lenp); /* Add our CI to pkt */
221 static int  lcp_ackci(fsm *f, u_char *p, int len); /* Peer ack'd our CI */
222 static int  lcp_nakci(fsm *f, u_char *p, int len, int treat_as_reject); /* Peer nak'd our CI */
223 static int  lcp_rejci(fsm *f, u_char *p, int len); /* Peer rej'd our CI */
224 static int  lcp_reqci(fsm *f, u_char *inp, int *lenp, int reject_if_disagree); /* Rcv peer CI */
225 static void lcp_up(fsm *f);             /* We're UP */
226 static void lcp_down(fsm *f);           /* We're DOWN */
227 static void lcp_starting (fsm *);       /* We need lower layer up */
228 static void lcp_finished (fsm *);       /* We need lower layer down */
229 static int  lcp_extcode(fsm *f, int code, int id, u_char *inp, int len);
230 static void lcp_rprotrej(fsm *f, u_char *inp, int len);
231
232 /*
233  * routines to send LCP echos to peer
234  */
235
236 static void lcp_echo_lowerup(ppp_pcb *pcb);
237 static void lcp_echo_lowerdown(ppp_pcb *pcb);
238 static void LcpEchoTimeout(void *arg);
239 static void lcp_received_echo_reply(fsm *f, int id, u_char *inp, int len);
240 static void LcpSendEchoRequest(fsm *f);
241 static void LcpLinkFailure(fsm *f);
242 static void LcpEchoCheck(fsm *f);
243
244 static 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
267 static void lcp_init(ppp_pcb *pcb);
268 static void lcp_input(ppp_pcb *pcb, u_char *p, int len);
269 static void lcp_protrej(ppp_pcb *pcb);
270 #if PRINTPKT_SUPPORT
271 static int lcp_printpkt(const u_char *p, int plen,
272                 void (*printer) (void *, const char *, ...), void *arg);
273 #endif /* PRINTPKT_SUPPORT */
274
275 const 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  */
326 static int
327 noopt(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
338 static int
339 setendpoint(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
350 static void
351 printendpoint(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  */
363 static 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  */
406 void 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  */
422 void 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  */
457 void 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  */
482 void 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  */
496 static 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  */
509 static 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  */
523 static 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  */
562 static 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*/
620 static 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  */
632 void 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  */
651 static 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  */
770 static 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  */
834 static 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  */
947 static 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);
1112 bad:
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  */
1127 static 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
1574 bad:
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  */
1589 static 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
1804 bad:
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  */
1820 static 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
2233 endswitch:
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  */
2290 static 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  */
2339 static 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  */
2358 static 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  */
2367 static 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  */
2377 static const char* const lcp_codenames[] = {
2378     "ConfReq", "ConfAck", "ConfNak", "ConfRej",
2379     "TermReq", "TermAck", "CodeRej", "ProtRej",
2380     "EchoReq", "EchoRep", "DiscReq", "Ident",
2381     "TimeRem"
2382 };
2383
2384 static 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
2639 static 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
2653 static 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
2673 static 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
2686 static 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
2712 static 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
2764 static 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
2781 static 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 */