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