source: azure_iot_hub_f767zi/trunk/asp_baseplatform/lwip/lwip-2.1.2/src/netif/ppp/lcp.c@ 457

Last change on this file since 457 was 457, checked in by coas-nagasima, 4 years ago

ファイルを追加

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