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