]>
Commit | Line | Data |
---|---|---|
1 | /***************************************************************************** | |
2 | * lcp.c - Network Link Control Protocol program file. | |
3 | * | |
4 | * Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc. | |
5 | * portions Copyright (c) 1997 by Global Election Systems Inc. | |
6 | * | |
7 | * The authors hereby grant permission to use, copy, modify, distribute, | |
8 | * and license this software and its documentation for any purpose, provided | |
9 | * that existing copyright notices are retained in all copies and that this | |
10 | * notice and the following disclaimer are included verbatim in any | |
11 | * distributions. No written agreement, license, or royalty fee is required | |
12 | * for any of the authorized uses. | |
13 | * | |
14 | * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR | |
15 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | |
16 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | |
17 | * IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | |
18 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | |
19 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
20 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
21 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
22 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | |
23 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
24 | * | |
25 | ****************************************************************************** | |
26 | * REVISION HISTORY | |
27 | * | |
28 | * 03-01-01 Marc Boucher <marc@mbsi.ca> | |
29 | * Ported to lwIP. | |
30 | * 97-12-01 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc. | |
31 | * Original. | |
32 | *****************************************************************************/ | |
33 | ||
34 | /* | |
35 | * lcp.c - PPP Link Control Protocol. | |
36 | * | |
37 | * Copyright (c) 1989 Carnegie Mellon University. | |
38 | * All rights reserved. | |
39 | * | |
40 | * Redistribution and use in source and binary forms are permitted | |
41 | * provided that the above copyright notice and this paragraph are | |
42 | * duplicated in all such forms and that any documentation, | |
43 | * advertising materials, and other materials related to such | |
44 | * distribution and use acknowledge that the software was developed | |
45 | * by Carnegie Mellon University. The name of the | |
46 | * University may not be used to endorse or promote products derived | |
47 | * from this software without specific prior written permission. | |
48 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR | |
49 | * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED | |
50 | * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. | |
51 | */ | |
52 | ||
53 | ||
54 | #include "lwip/opt.h" | |
55 | ||
56 | #if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */ | |
57 | ||
58 | #include "ppp.h" | |
59 | #include "pppdebug.h" | |
60 | ||
61 | #include "fsm.h" | |
62 | #include "chap.h" | |
63 | #include "magic.h" | |
64 | #include "auth.h" | |
65 | #include "lcp.h" | |
66 | ||
67 | #include <string.h> | |
68 | ||
69 | #if PPPOE_SUPPORT | |
70 | #include "netif/ppp_oe.h" | |
71 | #else | |
72 | #define PPPOE_MAXMTU PPP_MAXMRU | |
73 | #endif | |
74 | ||
75 | ||
76 | /*************************/ | |
77 | /*** LOCAL DEFINITIONS ***/ | |
78 | /*************************/ | |
79 | /* | |
80 | * Length of each type of configuration option (in octets) | |
81 | */ | |
82 | #define CILEN_VOID 2 | |
83 | #define CILEN_CHAR 3 | |
84 | #define CILEN_SHORT 4 /* CILEN_VOID + sizeof(short) */ | |
85 | #define CILEN_CHAP 5 /* CILEN_VOID + sizeof(short) + 1 */ | |
86 | #define CILEN_LONG 6 /* CILEN_VOID + sizeof(long) */ | |
87 | #define CILEN_LQR 8 /* CILEN_VOID + sizeof(short) + sizeof(long) */ | |
88 | #define CILEN_CBCP 3 | |
89 | ||
90 | ||
91 | /***********************************/ | |
92 | /*** LOCAL FUNCTION DECLARATIONS ***/ | |
93 | /***********************************/ | |
94 | /* | |
95 | * Callbacks for fsm code. (CI = Configuration Information) | |
96 | */ | |
97 | static void lcp_resetci (fsm*); /* Reset our CI */ | |
98 | static int lcp_cilen (fsm*); /* Return length of our CI */ | |
99 | static void lcp_addci (fsm*, u_char*, int*); /* Add our CI to pkt */ | |
100 | static int lcp_ackci (fsm*, u_char*, int); /* Peer ack'd our CI */ | |
101 | static int lcp_nakci (fsm*, u_char*, int); /* Peer nak'd our CI */ | |
102 | static int lcp_rejci (fsm*, u_char*, int); /* Peer rej'd our CI */ | |
103 | static int lcp_reqci (fsm*, u_char*, int*, int); /* Rcv peer CI */ | |
104 | static void lcp_up (fsm*); /* We're UP */ | |
105 | static void lcp_down (fsm*); /* We're DOWN */ | |
106 | static void lcp_starting (fsm*); /* We need lower layer up */ | |
107 | static void lcp_finished (fsm*); /* We need lower layer down */ | |
108 | static int lcp_extcode (fsm*, int, u_char, u_char*, int); | |
109 | ||
110 | static void lcp_rprotrej (fsm*, u_char*, int); | |
111 | ||
112 | /* | |
113 | * routines to send LCP echos to peer | |
114 | */ | |
115 | static void lcp_echo_lowerup (int); | |
116 | static void lcp_echo_lowerdown (int); | |
117 | static void LcpEchoTimeout (void*); | |
118 | static void lcp_received_echo_reply (fsm*, int, u_char*, int); | |
119 | static void LcpSendEchoRequest (fsm*); | |
120 | static void LcpLinkFailure (fsm*); | |
121 | static void LcpEchoCheck (fsm*); | |
122 | ||
123 | /* | |
124 | * Protocol entry points. | |
125 | * Some of these are called directly. | |
126 | */ | |
127 | static void lcp_input (int, u_char *, int); | |
128 | static void lcp_protrej (int); | |
129 | ||
130 | #define CODENAME(x) ((x) == CONFACK ? "ACK" : (x) == CONFNAK ? "NAK" : "REJ") | |
131 | ||
132 | ||
133 | /******************************/ | |
134 | /*** PUBLIC DATA STRUCTURES ***/ | |
135 | /******************************/ | |
136 | /* global vars */ | |
137 | LinkPhase lcp_phase[NUM_PPP]; /* Phase of link session (RFC 1661) */ | |
138 | lcp_options lcp_wantoptions[NUM_PPP]; /* Options that we want to request */ | |
139 | lcp_options lcp_gotoptions[NUM_PPP]; /* Options that peer ack'd */ | |
140 | lcp_options lcp_allowoptions[NUM_PPP]; /* Options we allow peer to request */ | |
141 | lcp_options lcp_hisoptions[NUM_PPP]; /* Options that we ack'd */ | |
142 | ext_accm xmit_accm[NUM_PPP]; /* extended transmit ACCM */ | |
143 | ||
144 | ||
145 | ||
146 | /*****************************/ | |
147 | /*** LOCAL DATA STRUCTURES ***/ | |
148 | /*****************************/ | |
149 | static fsm lcp_fsm[NUM_PPP]; /* LCP fsm structure (global)*/ | |
150 | static u_int lcp_echo_interval = LCP_ECHOINTERVAL; /* Interval between LCP echo-requests */ | |
151 | static u_int lcp_echo_fails = LCP_MAXECHOFAILS; /* Tolerance to unanswered echo-requests */ | |
152 | static u32_t lcp_echos_pending = 0; /* Number of outstanding echo msgs */ | |
153 | static u32_t lcp_echo_number = 0; /* ID number of next echo frame */ | |
154 | static u32_t lcp_echo_timer_running = 0; /* TRUE if a timer is running */ | |
155 | ||
156 | static u_char nak_buffer[PPP_MRU]; /* where we construct a nak packet */ | |
157 | ||
158 | static fsm_callbacks lcp_callbacks = { /* LCP callback routines */ | |
159 | lcp_resetci, /* Reset our Configuration Information */ | |
160 | lcp_cilen, /* Length of our Configuration Information */ | |
161 | lcp_addci, /* Add our Configuration Information */ | |
162 | lcp_ackci, /* ACK our Configuration Information */ | |
163 | lcp_nakci, /* NAK our Configuration Information */ | |
164 | lcp_rejci, /* Reject our Configuration Information */ | |
165 | lcp_reqci, /* Request peer's Configuration Information */ | |
166 | lcp_up, /* Called when fsm reaches LS_OPENED state */ | |
167 | lcp_down, /* Called when fsm leaves LS_OPENED state */ | |
168 | lcp_starting, /* Called when we want the lower layer up */ | |
169 | lcp_finished, /* Called when we want the lower layer down */ | |
170 | NULL, /* Called when Protocol-Reject received */ | |
171 | NULL, /* Retransmission is necessary */ | |
172 | lcp_extcode, /* Called to handle LCP-specific codes */ | |
173 | "LCP" /* String name of protocol */ | |
174 | }; | |
175 | ||
176 | struct protent lcp_protent = { | |
177 | PPP_LCP, | |
178 | lcp_init, | |
179 | lcp_input, | |
180 | lcp_protrej, | |
181 | lcp_lowerup, | |
182 | lcp_lowerdown, | |
183 | lcp_open, | |
184 | lcp_close, | |
185 | #if 0 | |
186 | lcp_printpkt, | |
187 | NULL, | |
188 | #endif | |
189 | 1, | |
190 | "LCP", | |
191 | #if 0 | |
192 | NULL, | |
193 | NULL, | |
194 | NULL | |
195 | #endif | |
196 | }; | |
197 | ||
198 | int lcp_loopbackfail = DEFLOOPBACKFAIL; | |
199 | ||
200 | ||
201 | ||
202 | /***********************************/ | |
203 | /*** PUBLIC FUNCTION DEFINITIONS ***/ | |
204 | /***********************************/ | |
205 | /* | |
206 | * lcp_init - Initialize LCP. | |
207 | */ | |
208 | void | |
209 | lcp_init(int unit) | |
210 | { | |
211 | fsm *f = &lcp_fsm[unit]; | |
212 | lcp_options *wo = &lcp_wantoptions[unit]; | |
213 | lcp_options *ao = &lcp_allowoptions[unit]; | |
214 | ||
215 | f->unit = unit; | |
216 | f->protocol = PPP_LCP; | |
217 | f->callbacks = &lcp_callbacks; | |
218 | ||
219 | fsm_init(f); | |
220 | ||
221 | wo->passive = 0; | |
222 | wo->silent = 0; | |
223 | wo->restart = 0; /* Set to 1 in kernels or multi-line implementations */ | |
224 | wo->neg_mru = 1; | |
225 | wo->mru = PPP_DEFMRU; | |
226 | wo->neg_asyncmap = 1; | |
227 | wo->asyncmap = 0x00000000l; /* Assume don't need to escape any ctl chars. */ | |
228 | wo->neg_chap = 0; /* Set to 1 on server */ | |
229 | wo->neg_upap = 0; /* Set to 1 on server */ | |
230 | wo->chap_mdtype = CHAP_DIGEST_MD5; | |
231 | wo->neg_magicnumber = 1; | |
232 | wo->neg_pcompression = 1; | |
233 | wo->neg_accompression = 1; | |
234 | wo->neg_lqr = 0; /* no LQR implementation yet */ | |
235 | wo->neg_cbcp = 0; | |
236 | ||
237 | ao->neg_mru = 1; | |
238 | ao->mru = PPP_MAXMRU; | |
239 | ao->neg_asyncmap = 1; | |
240 | ao->asyncmap = 0x00000000l; /* Assume don't need to escape any ctl chars. */ | |
241 | ao->neg_chap = (CHAP_SUPPORT != 0); | |
242 | ao->chap_mdtype = CHAP_DIGEST_MD5; | |
243 | ao->neg_upap = (PAP_SUPPORT != 0); | |
244 | ao->neg_magicnumber = 1; | |
245 | ao->neg_pcompression = 1; | |
246 | ao->neg_accompression = 1; | |
247 | ao->neg_lqr = 0; /* no LQR implementation yet */ | |
248 | ao->neg_cbcp = (CBCP_SUPPORT != 0); | |
249 | ||
250 | /* | |
251 | * Set transmit escape for the flag and escape characters plus anything | |
252 | * set for the allowable options. | |
253 | */ | |
254 | memset(xmit_accm[unit], 0, sizeof(xmit_accm[0])); | |
255 | xmit_accm[unit][15] = 0x60; | |
256 | xmit_accm[unit][0] = (u_char)((ao->asyncmap & 0xFF)); | |
257 | xmit_accm[unit][1] = (u_char)((ao->asyncmap >> 8) & 0xFF); | |
258 | xmit_accm[unit][2] = (u_char)((ao->asyncmap >> 16) & 0xFF); | |
259 | xmit_accm[unit][3] = (u_char)((ao->asyncmap >> 24) & 0xFF); | |
260 | LCPDEBUG((LOG_INFO, "lcp_init: xmit_accm=%X %X %X %X\n", | |
261 | xmit_accm[unit][0], | |
262 | xmit_accm[unit][1], | |
263 | xmit_accm[unit][2], | |
264 | xmit_accm[unit][3])); | |
265 | ||
266 | lcp_phase[unit] = PHASE_INITIALIZE; | |
267 | } | |
268 | ||
269 | ||
270 | /* | |
271 | * lcp_open - LCP is allowed to come up. | |
272 | */ | |
273 | void | |
274 | lcp_open(int unit) | |
275 | { | |
276 | fsm *f = &lcp_fsm[unit]; | |
277 | lcp_options *wo = &lcp_wantoptions[unit]; | |
278 | ||
279 | f->flags = 0; | |
280 | if (wo->passive) { | |
281 | f->flags |= OPT_PASSIVE; | |
282 | } | |
283 | if (wo->silent) { | |
284 | f->flags |= OPT_SILENT; | |
285 | } | |
286 | fsm_open(f); | |
287 | ||
288 | lcp_phase[unit] = PHASE_ESTABLISH; | |
289 | } | |
290 | ||
291 | ||
292 | /* | |
293 | * lcp_close - Take LCP down. | |
294 | */ | |
295 | void | |
296 | lcp_close(int unit, char *reason) | |
297 | { | |
298 | fsm *f = &lcp_fsm[unit]; | |
299 | ||
300 | if (lcp_phase[unit] != PHASE_DEAD) { | |
301 | lcp_phase[unit] = PHASE_TERMINATE; | |
302 | } | |
303 | if (f->state == LS_STOPPED && f->flags & (OPT_PASSIVE|OPT_SILENT)) { | |
304 | /* | |
305 | * This action is not strictly according to the FSM in RFC1548, | |
306 | * but it does mean that the program terminates if you do an | |
307 | * lcp_close() in passive/silent mode when a connection hasn't | |
308 | * been established. | |
309 | */ | |
310 | f->state = LS_CLOSED; | |
311 | lcp_finished(f); | |
312 | } else { | |
313 | fsm_close(&lcp_fsm[unit], reason); | |
314 | } | |
315 | } | |
316 | ||
317 | ||
318 | /* | |
319 | * lcp_lowerup - The lower layer is up. | |
320 | */ | |
321 | void | |
322 | lcp_lowerup(int unit) | |
323 | { | |
324 | lcp_options *wo = &lcp_wantoptions[unit]; | |
325 | ||
326 | /* | |
327 | * Don't use A/C or protocol compression on transmission, | |
328 | * but accept A/C and protocol compressed packets | |
329 | * if we are going to ask for A/C and protocol compression. | |
330 | */ | |
331 | ppp_set_xaccm(unit, &xmit_accm[unit]); | |
332 | ppp_send_config(unit, PPP_MRU, 0xffffffffl, 0, 0); | |
333 | ppp_recv_config(unit, PPP_MRU, 0x00000000l, | |
334 | wo->neg_pcompression, wo->neg_accompression); | |
335 | peer_mru[unit] = PPP_MRU; | |
336 | lcp_allowoptions[unit].asyncmap = (u_long)xmit_accm[unit][0] | |
337 | | ((u_long)xmit_accm[unit][1] << 8) | |
338 | | ((u_long)xmit_accm[unit][2] << 16) | |
339 | | ((u_long)xmit_accm[unit][3] << 24); | |
340 | LCPDEBUG((LOG_INFO, "lcp_lowerup: asyncmap=%X %X %X %X\n", | |
341 | xmit_accm[unit][3], | |
342 | xmit_accm[unit][2], | |
343 | xmit_accm[unit][1], | |
344 | xmit_accm[unit][0])); | |
345 | ||
346 | fsm_lowerup(&lcp_fsm[unit]); | |
347 | } | |
348 | ||
349 | ||
350 | /* | |
351 | * lcp_lowerdown - The lower layer is down. | |
352 | */ | |
353 | void | |
354 | lcp_lowerdown(int unit) | |
355 | { | |
356 | fsm_lowerdown(&lcp_fsm[unit]); | |
357 | } | |
358 | ||
359 | /* | |
360 | * lcp_sprotrej - Send a Protocol-Reject for some protocol. | |
361 | */ | |
362 | void | |
363 | lcp_sprotrej(int unit, u_char *p, int len) | |
364 | { | |
365 | /* | |
366 | * Send back the protocol and the information field of the | |
367 | * rejected packet. We only get here if LCP is in the LS_OPENED state. | |
368 | */ | |
369 | ||
370 | fsm_sdata(&lcp_fsm[unit], PROTREJ, ++lcp_fsm[unit].id, p, len); | |
371 | } | |
372 | ||
373 | ||
374 | ||
375 | /**********************************/ | |
376 | /*** LOCAL FUNCTION DEFINITIONS ***/ | |
377 | /**********************************/ | |
378 | /* | |
379 | * lcp_input - Input LCP packet. | |
380 | */ | |
381 | static void | |
382 | lcp_input(int unit, u_char *p, int len) | |
383 | { | |
384 | fsm *f = &lcp_fsm[unit]; | |
385 | ||
386 | fsm_input(f, p, len); | |
387 | } | |
388 | ||
389 | ||
390 | /* | |
391 | * lcp_extcode - Handle a LCP-specific code. | |
392 | */ | |
393 | static int | |
394 | lcp_extcode(fsm *f, int code, u_char id, u_char *inp, int len) | |
395 | { | |
396 | u_char *magp; | |
397 | ||
398 | switch( code ){ | |
399 | case PROTREJ: | |
400 | lcp_rprotrej(f, inp, len); | |
401 | break; | |
402 | ||
403 | case ECHOREQ: | |
404 | if (f->state != LS_OPENED) { | |
405 | break; | |
406 | } | |
407 | LCPDEBUG((LOG_INFO, "lcp: Echo-Request, Rcvd id %d\n", id)); | |
408 | magp = inp; | |
409 | PUTLONG(lcp_gotoptions[f->unit].magicnumber, magp); | |
410 | fsm_sdata(f, ECHOREP, id, inp, len); | |
411 | break; | |
412 | ||
413 | case ECHOREP: | |
414 | lcp_received_echo_reply(f, id, inp, len); | |
415 | break; | |
416 | ||
417 | case DISCREQ: | |
418 | break; | |
419 | ||
420 | default: | |
421 | return 0; | |
422 | } | |
423 | return 1; | |
424 | } | |
425 | ||
426 | ||
427 | /* | |
428 | * lcp_rprotrej - Receive an Protocol-Reject. | |
429 | * | |
430 | * Figure out which protocol is rejected and inform it. | |
431 | */ | |
432 | static void | |
433 | lcp_rprotrej(fsm *f, u_char *inp, int len) | |
434 | { | |
435 | int i; | |
436 | struct protent *protp; | |
437 | u_short prot; | |
438 | ||
439 | if (len < sizeof (u_short)) { | |
440 | LCPDEBUG((LOG_INFO, "lcp_rprotrej: Rcvd short Protocol-Reject packet!\n")); | |
441 | return; | |
442 | } | |
443 | ||
444 | GETSHORT(prot, inp); | |
445 | ||
446 | LCPDEBUG((LOG_INFO, "lcp_rprotrej: Rcvd Protocol-Reject packet for %x!\n", prot)); | |
447 | ||
448 | /* | |
449 | * Protocol-Reject packets received in any state other than the LCP | |
450 | * LS_OPENED state SHOULD be silently discarded. | |
451 | */ | |
452 | if( f->state != LS_OPENED ) { | |
453 | LCPDEBUG((LOG_INFO, "Protocol-Reject discarded: LCP in state %d\n", f->state)); | |
454 | return; | |
455 | } | |
456 | ||
457 | /* | |
458 | * Upcall the proper Protocol-Reject routine. | |
459 | */ | |
460 | for (i = 0; (protp = ppp_protocols[i]) != NULL; ++i) { | |
461 | if (protp->protocol == prot && protp->enabled_flag) { | |
462 | (*protp->protrej)(f->unit); | |
463 | return; | |
464 | } | |
465 | } | |
466 | ||
467 | LCPDEBUG((LOG_WARNING, "Protocol-Reject for unsupported protocol 0x%x\n", prot)); | |
468 | } | |
469 | ||
470 | ||
471 | /* | |
472 | * lcp_protrej - A Protocol-Reject was received. | |
473 | */ | |
474 | static void | |
475 | lcp_protrej(int unit) | |
476 | { | |
477 | LWIP_UNUSED_ARG(unit); | |
478 | /* | |
479 | * Can't reject LCP! | |
480 | */ | |
481 | LCPDEBUG((LOG_WARNING, "lcp_protrej: Received Protocol-Reject for LCP!\n")); | |
482 | fsm_protreject(&lcp_fsm[unit]); | |
483 | } | |
484 | ||
485 | ||
486 | /* | |
487 | * lcp_resetci - Reset our CI. | |
488 | */ | |
489 | static void | |
490 | lcp_resetci(fsm *f) | |
491 | { | |
492 | lcp_wantoptions[f->unit].magicnumber = magic(); | |
493 | lcp_wantoptions[f->unit].numloops = 0; | |
494 | lcp_gotoptions[f->unit] = lcp_wantoptions[f->unit]; | |
495 | peer_mru[f->unit] = PPP_MRU; | |
496 | auth_reset(f->unit); | |
497 | } | |
498 | ||
499 | ||
500 | /* | |
501 | * lcp_cilen - Return length of our CI. | |
502 | */ | |
503 | static int lcp_cilen(fsm *f) | |
504 | { | |
505 | lcp_options *go = &lcp_gotoptions[f->unit]; | |
506 | ||
507 | #define LENCIVOID(neg) ((neg) ? CILEN_VOID : 0) | |
508 | #define LENCICHAP(neg) ((neg) ? CILEN_CHAP : 0) | |
509 | #define LENCISHORT(neg) ((neg) ? CILEN_SHORT : 0) | |
510 | #define LENCILONG(neg) ((neg) ? CILEN_LONG : 0) | |
511 | #define LENCILQR(neg) ((neg) ? CILEN_LQR: 0) | |
512 | #define LENCICBCP(neg) ((neg) ? CILEN_CBCP: 0) | |
513 | /* | |
514 | * NB: we only ask for one of CHAP and UPAP, even if we will | |
515 | * accept either. | |
516 | */ | |
517 | return (LENCISHORT(go->neg_mru && go->mru != PPP_DEFMRU) + | |
518 | LENCILONG(go->neg_asyncmap && go->asyncmap != 0xFFFFFFFFl) + | |
519 | LENCICHAP(go->neg_chap) + | |
520 | LENCISHORT(!go->neg_chap && go->neg_upap) + | |
521 | LENCILQR(go->neg_lqr) + | |
522 | LENCICBCP(go->neg_cbcp) + | |
523 | LENCILONG(go->neg_magicnumber) + | |
524 | LENCIVOID(go->neg_pcompression) + | |
525 | LENCIVOID(go->neg_accompression)); | |
526 | } | |
527 | ||
528 | ||
529 | /* | |
530 | * lcp_addci - Add our desired CIs to a packet. | |
531 | */ | |
532 | static void | |
533 | lcp_addci(fsm *f, u_char *ucp, int *lenp) | |
534 | { | |
535 | lcp_options *go = &lcp_gotoptions[f->unit]; | |
536 | u_char *start_ucp = ucp; | |
537 | ||
538 | #define ADDCIVOID(opt, neg) \ | |
539 | if (neg) { \ | |
540 | LCPDEBUG((LOG_INFO, "lcp_addci: opt=%d\n", opt)); \ | |
541 | PUTCHAR(opt, ucp); \ | |
542 | PUTCHAR(CILEN_VOID, ucp); \ | |
543 | } | |
544 | #define ADDCISHORT(opt, neg, val) \ | |
545 | if (neg) { \ | |
546 | LCPDEBUG((LOG_INFO, "lcp_addci: INT opt=%d %X\n", opt, val)); \ | |
547 | PUTCHAR(opt, ucp); \ | |
548 | PUTCHAR(CILEN_SHORT, ucp); \ | |
549 | PUTSHORT(val, ucp); \ | |
550 | } | |
551 | #define ADDCICHAP(opt, neg, val, digest) \ | |
552 | if (neg) { \ | |
553 | LCPDEBUG((LOG_INFO, "lcp_addci: CHAP opt=%d %X\n", opt, val)); \ | |
554 | PUTCHAR(opt, ucp); \ | |
555 | PUTCHAR(CILEN_CHAP, ucp); \ | |
556 | PUTSHORT(val, ucp); \ | |
557 | PUTCHAR(digest, ucp); \ | |
558 | } | |
559 | #define ADDCILONG(opt, neg, val) \ | |
560 | if (neg) { \ | |
561 | LCPDEBUG((LOG_INFO, "lcp_addci: L opt=%d %lX\n", opt, val)); \ | |
562 | PUTCHAR(opt, ucp); \ | |
563 | PUTCHAR(CILEN_LONG, ucp); \ | |
564 | PUTLONG(val, ucp); \ | |
565 | } | |
566 | #define ADDCILQR(opt, neg, val) \ | |
567 | if (neg) { \ | |
568 | LCPDEBUG((LOG_INFO, "lcp_addci: LQR opt=%d %lX\n", opt, val)); \ | |
569 | PUTCHAR(opt, ucp); \ | |
570 | PUTCHAR(CILEN_LQR, ucp); \ | |
571 | PUTSHORT(PPP_LQR, ucp); \ | |
572 | PUTLONG(val, ucp); \ | |
573 | } | |
574 | #define ADDCICHAR(opt, neg, val) \ | |
575 | if (neg) { \ | |
576 | LCPDEBUG((LOG_INFO, "lcp_addci: CHAR opt=%d %X '%z'\n", opt, val, val)); \ | |
577 | PUTCHAR(opt, ucp); \ | |
578 | PUTCHAR(CILEN_CHAR, ucp); \ | |
579 | PUTCHAR(val, ucp); \ | |
580 | } | |
581 | ||
582 | ADDCISHORT(CI_MRU, go->neg_mru && go->mru != PPP_DEFMRU, go->mru); | |
583 | ADDCILONG(CI_ASYNCMAP, go->neg_asyncmap && go->asyncmap != 0xFFFFFFFFl, go->asyncmap); | |
584 | ADDCICHAP(CI_AUTHTYPE, go->neg_chap, PPP_CHAP, go->chap_mdtype); | |
585 | ADDCISHORT(CI_AUTHTYPE, !go->neg_chap && go->neg_upap, PPP_PAP); | |
586 | ADDCILQR(CI_QUALITY, go->neg_lqr, go->lqr_period); | |
587 | ADDCICHAR(CI_CALLBACK, go->neg_cbcp, CBCP_OPT); | |
588 | ADDCILONG(CI_MAGICNUMBER, go->neg_magicnumber, go->magicnumber); | |
589 | ADDCIVOID(CI_PCOMPRESSION, go->neg_pcompression); | |
590 | ADDCIVOID(CI_ACCOMPRESSION, go->neg_accompression); | |
591 | ||
592 | if (ucp - start_ucp != *lenp) { | |
593 | /* this should never happen, because peer_mtu should be 1500 */ | |
594 | LCPDEBUG((LOG_ERR, "Bug in lcp_addci: wrong length\n")); | |
595 | } | |
596 | } | |
597 | ||
598 | ||
599 | /* | |
600 | * lcp_ackci - Ack our CIs. | |
601 | * This should not modify any state if the Ack is bad. | |
602 | * | |
603 | * Returns: | |
604 | * 0 - Ack was bad. | |
605 | * 1 - Ack was good. | |
606 | */ | |
607 | static int | |
608 | lcp_ackci(fsm *f, u_char *p, int len) | |
609 | { | |
610 | lcp_options *go = &lcp_gotoptions[f->unit]; | |
611 | u_char cilen, citype, cichar; | |
612 | u_short cishort; | |
613 | u32_t cilong; | |
614 | ||
615 | /* | |
616 | * CIs must be in exactly the same order that we sent. | |
617 | * Check packet length and CI length at each step. | |
618 | * If we find any deviations, then this packet is bad. | |
619 | */ | |
620 | #define ACKCIVOID(opt, neg) \ | |
621 | if (neg) { \ | |
622 | if ((len -= CILEN_VOID) < 0) \ | |
623 | goto bad; \ | |
624 | GETCHAR(citype, p); \ | |
625 | GETCHAR(cilen, p); \ | |
626 | if (cilen != CILEN_VOID || citype != opt) \ | |
627 | goto bad; \ | |
628 | } | |
629 | #define ACKCISHORT(opt, neg, val) \ | |
630 | if (neg) { \ | |
631 | if ((len -= CILEN_SHORT) < 0) \ | |
632 | goto bad; \ | |
633 | GETCHAR(citype, p); \ | |
634 | GETCHAR(cilen, p); \ | |
635 | if (cilen != CILEN_SHORT || citype != opt) \ | |
636 | goto bad; \ | |
637 | GETSHORT(cishort, p); \ | |
638 | if (cishort != val) \ | |
639 | goto bad; \ | |
640 | } | |
641 | #define ACKCICHAR(opt, neg, val) \ | |
642 | if (neg) { \ | |
643 | if ((len -= CILEN_CHAR) < 0) \ | |
644 | goto bad; \ | |
645 | GETCHAR(citype, p); \ | |
646 | GETCHAR(cilen, p); \ | |
647 | if (cilen != CILEN_CHAR || citype != opt) \ | |
648 | goto bad; \ | |
649 | GETCHAR(cichar, p); \ | |
650 | if (cichar != val) \ | |
651 | goto bad; \ | |
652 | } | |
653 | #define ACKCICHAP(opt, neg, val, digest) \ | |
654 | if (neg) { \ | |
655 | if ((len -= CILEN_CHAP) < 0) \ | |
656 | goto bad; \ | |
657 | GETCHAR(citype, p); \ | |
658 | GETCHAR(cilen, p); \ | |
659 | if (cilen != CILEN_CHAP || citype != opt) \ | |
660 | goto bad; \ | |
661 | GETSHORT(cishort, p); \ | |
662 | if (cishort != val) \ | |
663 | goto bad; \ | |
664 | GETCHAR(cichar, p); \ | |
665 | if (cichar != digest) \ | |
666 | goto bad; \ | |
667 | } | |
668 | #define ACKCILONG(opt, neg, val) \ | |
669 | if (neg) { \ | |
670 | if ((len -= CILEN_LONG) < 0) \ | |
671 | goto bad; \ | |
672 | GETCHAR(citype, p); \ | |
673 | GETCHAR(cilen, p); \ | |
674 | if (cilen != CILEN_LONG || citype != opt) \ | |
675 | goto bad; \ | |
676 | GETLONG(cilong, p); \ | |
677 | if (cilong != val) \ | |
678 | goto bad; \ | |
679 | } | |
680 | #define ACKCILQR(opt, neg, val) \ | |
681 | if (neg) { \ | |
682 | if ((len -= CILEN_LQR) < 0) \ | |
683 | goto bad; \ | |
684 | GETCHAR(citype, p); \ | |
685 | GETCHAR(cilen, p); \ | |
686 | if (cilen != CILEN_LQR || citype != opt) \ | |
687 | goto bad; \ | |
688 | GETSHORT(cishort, p); \ | |
689 | if (cishort != PPP_LQR) \ | |
690 | goto bad; \ | |
691 | GETLONG(cilong, p); \ | |
692 | if (cilong != val) \ | |
693 | goto bad; \ | |
694 | } | |
695 | ||
696 | ACKCISHORT(CI_MRU, go->neg_mru && go->mru != PPP_DEFMRU, go->mru); | |
697 | ACKCILONG(CI_ASYNCMAP, go->neg_asyncmap && go->asyncmap != 0xFFFFFFFFl, go->asyncmap); | |
698 | ACKCICHAP(CI_AUTHTYPE, go->neg_chap, PPP_CHAP, go->chap_mdtype); | |
699 | ACKCISHORT(CI_AUTHTYPE, !go->neg_chap && go->neg_upap, PPP_PAP); | |
700 | ACKCILQR(CI_QUALITY, go->neg_lqr, go->lqr_period); | |
701 | ACKCICHAR(CI_CALLBACK, go->neg_cbcp, CBCP_OPT); | |
702 | ACKCILONG(CI_MAGICNUMBER, go->neg_magicnumber, go->magicnumber); | |
703 | ACKCIVOID(CI_PCOMPRESSION, go->neg_pcompression); | |
704 | ACKCIVOID(CI_ACCOMPRESSION, go->neg_accompression); | |
705 | ||
706 | /* | |
707 | * If there are any remaining CIs, then this packet is bad. | |
708 | */ | |
709 | if (len != 0) { | |
710 | goto bad; | |
711 | } | |
712 | LCPDEBUG((LOG_INFO, "lcp_acki: Ack\n")); | |
713 | return (1); | |
714 | bad: | |
715 | LCPDEBUG((LOG_WARNING, "lcp_acki: received bad Ack!\n")); | |
716 | return (0); | |
717 | } | |
718 | ||
719 | ||
720 | /* | |
721 | * lcp_nakci - Peer has sent a NAK for some of our CIs. | |
722 | * This should not modify any state if the Nak is bad | |
723 | * or if LCP is in the LS_OPENED state. | |
724 | * | |
725 | * Returns: | |
726 | * 0 - Nak was bad. | |
727 | * 1 - Nak was good. | |
728 | */ | |
729 | static int | |
730 | lcp_nakci(fsm *f, u_char *p, int len) | |
731 | { | |
732 | lcp_options *go = &lcp_gotoptions[f->unit]; | |
733 | lcp_options *wo = &lcp_wantoptions[f->unit]; | |
734 | u_char citype, cichar, *next; | |
735 | u_short cishort; | |
736 | u32_t cilong; | |
737 | lcp_options no; /* options we've seen Naks for */ | |
738 | lcp_options try; /* options to request next time */ | |
739 | int looped_back = 0; | |
740 | int cilen; | |
741 | ||
742 | BZERO(&no, sizeof(no)); | |
743 | try = *go; | |
744 | ||
745 | /* | |
746 | * Any Nak'd CIs must be in exactly the same order that we sent. | |
747 | * Check packet length and CI length at each step. | |
748 | * If we find any deviations, then this packet is bad. | |
749 | */ | |
750 | #define NAKCIVOID(opt, neg, code) \ | |
751 | if (go->neg && \ | |
752 | len >= CILEN_VOID && \ | |
753 | p[1] == CILEN_VOID && \ | |
754 | p[0] == opt) { \ | |
755 | len -= CILEN_VOID; \ | |
756 | INCPTR(CILEN_VOID, p); \ | |
757 | no.neg = 1; \ | |
758 | code \ | |
759 | } | |
760 | #define NAKCICHAP(opt, neg, code) \ | |
761 | if (go->neg && \ | |
762 | len >= CILEN_CHAP && \ | |
763 | p[1] == CILEN_CHAP && \ | |
764 | p[0] == opt) { \ | |
765 | len -= CILEN_CHAP; \ | |
766 | INCPTR(2, p); \ | |
767 | GETSHORT(cishort, p); \ | |
768 | GETCHAR(cichar, p); \ | |
769 | no.neg = 1; \ | |
770 | code \ | |
771 | } | |
772 | #define NAKCICHAR(opt, neg, code) \ | |
773 | if (go->neg && \ | |
774 | len >= CILEN_CHAR && \ | |
775 | p[1] == CILEN_CHAR && \ | |
776 | p[0] == opt) { \ | |
777 | len -= CILEN_CHAR; \ | |
778 | INCPTR(2, p); \ | |
779 | GETCHAR(cichar, p); \ | |
780 | no.neg = 1; \ | |
781 | code \ | |
782 | } | |
783 | #define NAKCISHORT(opt, neg, code) \ | |
784 | if (go->neg && \ | |
785 | len >= CILEN_SHORT && \ | |
786 | p[1] == CILEN_SHORT && \ | |
787 | p[0] == opt) { \ | |
788 | len -= CILEN_SHORT; \ | |
789 | INCPTR(2, p); \ | |
790 | GETSHORT(cishort, p); \ | |
791 | no.neg = 1; \ | |
792 | code \ | |
793 | } | |
794 | #define NAKCILONG(opt, neg, code) \ | |
795 | if (go->neg && \ | |
796 | len >= CILEN_LONG && \ | |
797 | p[1] == CILEN_LONG && \ | |
798 | p[0] == opt) { \ | |
799 | len -= CILEN_LONG; \ | |
800 | INCPTR(2, p); \ | |
801 | GETLONG(cilong, p); \ | |
802 | no.neg = 1; \ | |
803 | code \ | |
804 | } | |
805 | #define NAKCILQR(opt, neg, code) \ | |
806 | if (go->neg && \ | |
807 | len >= CILEN_LQR && \ | |
808 | p[1] == CILEN_LQR && \ | |
809 | p[0] == opt) { \ | |
810 | len -= CILEN_LQR; \ | |
811 | INCPTR(2, p); \ | |
812 | GETSHORT(cishort, p); \ | |
813 | GETLONG(cilong, p); \ | |
814 | no.neg = 1; \ | |
815 | code \ | |
816 | } | |
817 | ||
818 | /* | |
819 | * We don't care if they want to send us smaller packets than | |
820 | * we want. Therefore, accept any MRU less than what we asked for, | |
821 | * but then ignore the new value when setting the MRU in the kernel. | |
822 | * If they send us a bigger MRU than what we asked, accept it, up to | |
823 | * the limit of the default MRU we'd get if we didn't negotiate. | |
824 | */ | |
825 | if (go->neg_mru && go->mru != PPP_DEFMRU) { | |
826 | NAKCISHORT(CI_MRU, neg_mru, | |
827 | if (cishort <= wo->mru || cishort < PPP_DEFMRU) { | |
828 | try.mru = cishort; | |
829 | } | |
830 | ); | |
831 | } | |
832 | ||
833 | /* | |
834 | * Add any characters they want to our (receive-side) asyncmap. | |
835 | */ | |
836 | if (go->neg_asyncmap && go->asyncmap != 0xFFFFFFFFl) { | |
837 | NAKCILONG(CI_ASYNCMAP, neg_asyncmap, | |
838 | try.asyncmap = go->asyncmap | cilong; | |
839 | ); | |
840 | } | |
841 | ||
842 | /* | |
843 | * If they've nak'd our authentication-protocol, check whether | |
844 | * they are proposing a different protocol, or a different | |
845 | * hash algorithm for CHAP. | |
846 | */ | |
847 | if ((go->neg_chap || go->neg_upap) | |
848 | && len >= CILEN_SHORT | |
849 | && p[0] == CI_AUTHTYPE && p[1] >= CILEN_SHORT && p[1] <= len) { | |
850 | cilen = p[1]; | |
851 | len -= cilen; | |
852 | no.neg_chap = go->neg_chap; | |
853 | no.neg_upap = go->neg_upap; | |
854 | INCPTR(2, p); | |
855 | GETSHORT(cishort, p); | |
856 | if (cishort == PPP_PAP && cilen == CILEN_SHORT) { | |
857 | /* | |
858 | * If we were asking for CHAP, they obviously don't want to do it. | |
859 | * If we weren't asking for CHAP, then we were asking for PAP, | |
860 | * in which case this Nak is bad. | |
861 | */ | |
862 | if (!go->neg_chap) { | |
863 | goto bad; | |
864 | } | |
865 | try.neg_chap = 0; | |
866 | ||
867 | } else if (cishort == PPP_CHAP && cilen == CILEN_CHAP) { | |
868 | GETCHAR(cichar, p); | |
869 | if (go->neg_chap) { | |
870 | /* | |
871 | * We were asking for CHAP/MD5; they must want a different | |
872 | * algorithm. If they can't do MD5, we'll have to stop | |
873 | * asking for CHAP. | |
874 | */ | |
875 | if (cichar != go->chap_mdtype) { | |
876 | try.neg_chap = 0; | |
877 | } | |
878 | } else { | |
879 | /* | |
880 | * Stop asking for PAP if we were asking for it. | |
881 | */ | |
882 | try.neg_upap = 0; | |
883 | } | |
884 | ||
885 | } else { | |
886 | /* | |
887 | * We don't recognize what they're suggesting. | |
888 | * Stop asking for what we were asking for. | |
889 | */ | |
890 | if (go->neg_chap) { | |
891 | try.neg_chap = 0; | |
892 | } else { | |
893 | try.neg_upap = 0; | |
894 | } | |
895 | p += cilen - CILEN_SHORT; | |
896 | } | |
897 | } | |
898 | ||
899 | /* | |
900 | * If they can't cope with our link quality protocol, we'll have | |
901 | * to stop asking for LQR. We haven't got any other protocol. | |
902 | * If they Nak the reporting period, take their value XXX ? | |
903 | */ | |
904 | NAKCILQR(CI_QUALITY, neg_lqr, | |
905 | if (cishort != PPP_LQR) { | |
906 | try.neg_lqr = 0; | |
907 | } else { | |
908 | try.lqr_period = cilong; | |
909 | } | |
910 | ); | |
911 | ||
912 | /* | |
913 | * Only implementing CBCP...not the rest of the callback options | |
914 | */ | |
915 | NAKCICHAR(CI_CALLBACK, neg_cbcp, | |
916 | try.neg_cbcp = 0; | |
917 | ); | |
918 | ||
919 | /* | |
920 | * Check for a looped-back line. | |
921 | */ | |
922 | NAKCILONG(CI_MAGICNUMBER, neg_magicnumber, | |
923 | try.magicnumber = magic(); | |
924 | looped_back = 1; | |
925 | ); | |
926 | ||
927 | /* | |
928 | * Peer shouldn't send Nak for protocol compression or | |
929 | * address/control compression requests; they should send | |
930 | * a Reject instead. If they send a Nak, treat it as a Reject. | |
931 | */ | |
932 | NAKCIVOID(CI_PCOMPRESSION, neg_pcompression, | |
933 | try.neg_pcompression = 0; | |
934 | ); | |
935 | NAKCIVOID(CI_ACCOMPRESSION, neg_accompression, | |
936 | try.neg_accompression = 0; | |
937 | ); | |
938 | ||
939 | /* | |
940 | * There may be remaining CIs, if the peer is requesting negotiation | |
941 | * on an option that we didn't include in our request packet. | |
942 | * If we see an option that we requested, or one we've already seen | |
943 | * in this packet, then this packet is bad. | |
944 | * If we wanted to respond by starting to negotiate on the requested | |
945 | * option(s), we could, but we don't, because except for the | |
946 | * authentication type and quality protocol, if we are not negotiating | |
947 | * an option, it is because we were told not to. | |
948 | * For the authentication type, the Nak from the peer means | |
949 | * `let me authenticate myself with you' which is a bit pointless. | |
950 | * For the quality protocol, the Nak means `ask me to send you quality | |
951 | * reports', but if we didn't ask for them, we don't want them. | |
952 | * An option we don't recognize represents the peer asking to | |
953 | * negotiate some option we don't support, so ignore it. | |
954 | */ | |
955 | while (len > CILEN_VOID) { | |
956 | GETCHAR(citype, p); | |
957 | GETCHAR(cilen, p); | |
958 | if (cilen < CILEN_VOID || (len -= cilen) < 0) { | |
959 | goto bad; | |
960 | } | |
961 | next = p + cilen - 2; | |
962 | ||
963 | switch (citype) { | |
964 | case CI_MRU: | |
965 | if ((go->neg_mru && go->mru != PPP_DEFMRU) | |
966 | || no.neg_mru || cilen != CILEN_SHORT) { | |
967 | goto bad; | |
968 | } | |
969 | GETSHORT(cishort, p); | |
970 | if (cishort < PPP_DEFMRU) { | |
971 | try.mru = cishort; | |
972 | } | |
973 | break; | |
974 | case CI_ASYNCMAP: | |
975 | if ((go->neg_asyncmap && go->asyncmap != 0xFFFFFFFFl) | |
976 | || no.neg_asyncmap || cilen != CILEN_LONG) { | |
977 | goto bad; | |
978 | } | |
979 | break; | |
980 | case CI_AUTHTYPE: | |
981 | if (go->neg_chap || no.neg_chap || go->neg_upap || no.neg_upap) { | |
982 | goto bad; | |
983 | } | |
984 | break; | |
985 | case CI_MAGICNUMBER: | |
986 | if (go->neg_magicnumber || no.neg_magicnumber || | |
987 | cilen != CILEN_LONG) { | |
988 | goto bad; | |
989 | } | |
990 | break; | |
991 | case CI_PCOMPRESSION: | |
992 | if (go->neg_pcompression || no.neg_pcompression | |
993 | || cilen != CILEN_VOID) { | |
994 | goto bad; | |
995 | } | |
996 | break; | |
997 | case CI_ACCOMPRESSION: | |
998 | if (go->neg_accompression || no.neg_accompression | |
999 | || cilen != CILEN_VOID) { | |
1000 | goto bad; | |
1001 | } | |
1002 | break; | |
1003 | case CI_QUALITY: | |
1004 | if (go->neg_lqr || no.neg_lqr || cilen != CILEN_LQR) { | |
1005 | goto bad; | |
1006 | } | |
1007 | break; | |
1008 | } | |
1009 | p = next; | |
1010 | } | |
1011 | ||
1012 | /* If there is still anything left, this packet is bad. */ | |
1013 | if (len != 0) { | |
1014 | goto bad; | |
1015 | } | |
1016 | ||
1017 | /* | |
1018 | * OK, the Nak is good. Now we can update state. | |
1019 | */ | |
1020 | if (f->state != LS_OPENED) { | |
1021 | if (looped_back) { | |
1022 | if (++try.numloops >= lcp_loopbackfail) { | |
1023 | LCPDEBUG((LOG_NOTICE, "Serial line is looped back.\n")); | |
1024 | lcp_close(f->unit, "Loopback detected"); | |
1025 | } | |
1026 | } else { | |
1027 | try.numloops = 0; | |
1028 | } | |
1029 | *go = try; | |
1030 | } | |
1031 | ||
1032 | return 1; | |
1033 | ||
1034 | bad: | |
1035 | LCPDEBUG((LOG_WARNING, "lcp_nakci: received bad Nak!\n")); | |
1036 | return 0; | |
1037 | } | |
1038 | ||
1039 | ||
1040 | /* | |
1041 | * lcp_rejci - Peer has Rejected some of our CIs. | |
1042 | * This should not modify any state if the Reject is bad | |
1043 | * or if LCP is in the LS_OPENED state. | |
1044 | * | |
1045 | * Returns: | |
1046 | * 0 - Reject was bad. | |
1047 | * 1 - Reject was good. | |
1048 | */ | |
1049 | static int | |
1050 | lcp_rejci(fsm *f, u_char *p, int len) | |
1051 | { | |
1052 | lcp_options *go = &lcp_gotoptions[f->unit]; | |
1053 | u_char cichar; | |
1054 | u_short cishort; | |
1055 | u32_t cilong; | |
1056 | lcp_options try; /* options to request next time */ | |
1057 | ||
1058 | try = *go; | |
1059 | ||
1060 | /* | |
1061 | * Any Rejected CIs must be in exactly the same order that we sent. | |
1062 | * Check packet length and CI length at each step. | |
1063 | * If we find any deviations, then this packet is bad. | |
1064 | */ | |
1065 | #define REJCIVOID(opt, neg) \ | |
1066 | if (go->neg && \ | |
1067 | len >= CILEN_VOID && \ | |
1068 | p[1] == CILEN_VOID && \ | |
1069 | p[0] == opt) { \ | |
1070 | len -= CILEN_VOID; \ | |
1071 | INCPTR(CILEN_VOID, p); \ | |
1072 | try.neg = 0; \ | |
1073 | LCPDEBUG((LOG_INFO, "lcp_rejci: void opt %d rejected\n", opt)); \ | |
1074 | } | |
1075 | #define REJCISHORT(opt, neg, val) \ | |
1076 | if (go->neg && \ | |
1077 | len >= CILEN_SHORT && \ | |
1078 | p[1] == CILEN_SHORT && \ | |
1079 | p[0] == opt) { \ | |
1080 | len -= CILEN_SHORT; \ | |
1081 | INCPTR(2, p); \ | |
1082 | GETSHORT(cishort, p); \ | |
1083 | /* Check rejected value. */ \ | |
1084 | if (cishort != val) { \ | |
1085 | goto bad; \ | |
1086 | } \ | |
1087 | try.neg = 0; \ | |
1088 | LCPDEBUG((LOG_INFO,"lcp_rejci: short opt %d rejected\n", opt)); \ | |
1089 | } | |
1090 | #define REJCICHAP(opt, neg, val, digest) \ | |
1091 | if (go->neg && \ | |
1092 | len >= CILEN_CHAP && \ | |
1093 | p[1] == CILEN_CHAP && \ | |
1094 | p[0] == opt) { \ | |
1095 | len -= CILEN_CHAP; \ | |
1096 | INCPTR(2, p); \ | |
1097 | GETSHORT(cishort, p); \ | |
1098 | GETCHAR(cichar, p); \ | |
1099 | /* Check rejected value. */ \ | |
1100 | if (cishort != val || cichar != digest) { \ | |
1101 | goto bad; \ | |
1102 | } \ | |
1103 | try.neg = 0; \ | |
1104 | try.neg_upap = 0; \ | |
1105 | LCPDEBUG((LOG_INFO,"lcp_rejci: chap opt %d rejected\n", opt)); \ | |
1106 | } | |
1107 | #define REJCILONG(opt, neg, val) \ | |
1108 | if (go->neg && \ | |
1109 | len >= CILEN_LONG && \ | |
1110 | p[1] == CILEN_LONG && \ | |
1111 | p[0] == opt) { \ | |
1112 | len -= CILEN_LONG; \ | |
1113 | INCPTR(2, p); \ | |
1114 | GETLONG(cilong, p); \ | |
1115 | /* Check rejected value. */ \ | |
1116 | if (cilong != val) { \ | |
1117 | goto bad; \ | |
1118 | } \ | |
1119 | try.neg = 0; \ | |
1120 | LCPDEBUG((LOG_INFO,"lcp_rejci: long opt %d rejected\n", opt)); \ | |
1121 | } | |
1122 | #define REJCILQR(opt, neg, val) \ | |
1123 | if (go->neg && \ | |
1124 | len >= CILEN_LQR && \ | |
1125 | p[1] == CILEN_LQR && \ | |
1126 | p[0] == opt) { \ | |
1127 | len -= CILEN_LQR; \ | |
1128 | INCPTR(2, p); \ | |
1129 | GETSHORT(cishort, p); \ | |
1130 | GETLONG(cilong, p); \ | |
1131 | /* Check rejected value. */ \ | |
1132 | if (cishort != PPP_LQR || cilong != val) { \ | |
1133 | goto bad; \ | |
1134 | } \ | |
1135 | try.neg = 0; \ | |
1136 | LCPDEBUG((LOG_INFO,"lcp_rejci: LQR opt %d rejected\n", opt)); \ | |
1137 | } | |
1138 | #define REJCICBCP(opt, neg, val) \ | |
1139 | if (go->neg && \ | |
1140 | len >= CILEN_CBCP && \ | |
1141 | p[1] == CILEN_CBCP && \ | |
1142 | p[0] == opt) { \ | |
1143 | len -= CILEN_CBCP; \ | |
1144 | INCPTR(2, p); \ | |
1145 | GETCHAR(cichar, p); \ | |
1146 | /* Check rejected value. */ \ | |
1147 | if (cichar != val) { \ | |
1148 | goto bad; \ | |
1149 | } \ | |
1150 | try.neg = 0; \ | |
1151 | LCPDEBUG((LOG_INFO,"lcp_rejci: Callback opt %d rejected\n", opt)); \ | |
1152 | } | |
1153 | ||
1154 | REJCISHORT(CI_MRU, neg_mru, go->mru); | |
1155 | REJCILONG(CI_ASYNCMAP, neg_asyncmap, go->asyncmap); | |
1156 | REJCICHAP(CI_AUTHTYPE, neg_chap, PPP_CHAP, go->chap_mdtype); | |
1157 | if (!go->neg_chap) { | |
1158 | REJCISHORT(CI_AUTHTYPE, neg_upap, PPP_PAP); | |
1159 | } | |
1160 | REJCILQR(CI_QUALITY, neg_lqr, go->lqr_period); | |
1161 | REJCICBCP(CI_CALLBACK, neg_cbcp, CBCP_OPT); | |
1162 | REJCILONG(CI_MAGICNUMBER, neg_magicnumber, go->magicnumber); | |
1163 | REJCIVOID(CI_PCOMPRESSION, neg_pcompression); | |
1164 | REJCIVOID(CI_ACCOMPRESSION, neg_accompression); | |
1165 | ||
1166 | /* | |
1167 | * If there are any remaining CIs, then this packet is bad. | |
1168 | */ | |
1169 | if (len != 0) { | |
1170 | goto bad; | |
1171 | } | |
1172 | /* | |
1173 | * Now we can update state. | |
1174 | */ | |
1175 | if (f->state != LS_OPENED) { | |
1176 | *go = try; | |
1177 | } | |
1178 | return 1; | |
1179 | ||
1180 | bad: | |
1181 | LCPDEBUG((LOG_WARNING, "lcp_rejci: received bad Reject!\n")); | |
1182 | return 0; | |
1183 | } | |
1184 | ||
1185 | ||
1186 | /* | |
1187 | * lcp_reqci - Check the peer's requested CIs and send appropriate response. | |
1188 | * | |
1189 | * Returns: CONFACK, CONFNAK or CONFREJ and input packet modified | |
1190 | * appropriately. If reject_if_disagree is non-zero, doesn't return | |
1191 | * CONFNAK; returns CONFREJ if it can't return CONFACK. | |
1192 | */ | |
1193 | static int | |
1194 | lcp_reqci(fsm *f, | |
1195 | u_char *inp, /* Requested CIs */ | |
1196 | int *lenp, /* Length of requested CIs */ | |
1197 | int reject_if_disagree) | |
1198 | { | |
1199 | lcp_options *go = &lcp_gotoptions[f->unit]; | |
1200 | lcp_options *ho = &lcp_hisoptions[f->unit]; | |
1201 | lcp_options *ao = &lcp_allowoptions[f->unit]; | |
1202 | u_char *cip, *next; /* Pointer to current and next CIs */ | |
1203 | int cilen, citype, cichar; /* Parsed len, type, char value */ | |
1204 | u_short cishort; /* Parsed short value */ | |
1205 | u32_t cilong; /* Parse long value */ | |
1206 | int rc = CONFACK; /* Final packet return code */ | |
1207 | int orc; /* Individual option return code */ | |
1208 | u_char *p; /* Pointer to next char to parse */ | |
1209 | u_char *rejp; /* Pointer to next char in reject frame */ | |
1210 | u_char *nakp; /* Pointer to next char in Nak frame */ | |
1211 | int l = *lenp; /* Length left */ | |
1212 | #if TRACELCP > 0 | |
1213 | char traceBuf[80]; | |
1214 | int traceNdx = 0; | |
1215 | #endif | |
1216 | ||
1217 | /* | |
1218 | * Reset all his options. | |
1219 | */ | |
1220 | BZERO(ho, sizeof(*ho)); | |
1221 | ||
1222 | /* | |
1223 | * Process all his options. | |
1224 | */ | |
1225 | next = inp; | |
1226 | nakp = nak_buffer; | |
1227 | rejp = inp; | |
1228 | while (l) { | |
1229 | orc = CONFACK; /* Assume success */ | |
1230 | cip = p = next; /* Remember begining of CI */ | |
1231 | if (l < 2 || /* Not enough data for CI header or */ | |
1232 | p[1] < 2 || /* CI length too small or */ | |
1233 | p[1] > l) { /* CI length too big? */ | |
1234 | LCPDEBUG((LOG_WARNING, "lcp_reqci: bad CI length!\n")); | |
1235 | orc = CONFREJ; /* Reject bad CI */ | |
1236 | cilen = l; /* Reject till end of packet */ | |
1237 | l = 0; /* Don't loop again */ | |
1238 | citype = 0; | |
1239 | goto endswitch; | |
1240 | } | |
1241 | GETCHAR(citype, p); /* Parse CI type */ | |
1242 | GETCHAR(cilen, p); /* Parse CI length */ | |
1243 | l -= cilen; /* Adjust remaining length */ | |
1244 | next += cilen; /* Step to next CI */ | |
1245 | ||
1246 | switch (citype) { /* Check CI type */ | |
1247 | case CI_MRU: | |
1248 | if (!ao->neg_mru) { /* Allow option? */ | |
1249 | LCPDEBUG((LOG_INFO, "lcp_reqci: Reject MRU - not allowed\n")); | |
1250 | orc = CONFREJ; /* Reject CI */ | |
1251 | break; | |
1252 | } else if (cilen != CILEN_SHORT) { /* Check CI length */ | |
1253 | LCPDEBUG((LOG_INFO, "lcp_reqci: Reject MRU - bad length\n")); | |
1254 | orc = CONFREJ; /* Reject CI */ | |
1255 | break; | |
1256 | } | |
1257 | GETSHORT(cishort, p); /* Parse MRU */ | |
1258 | ||
1259 | /* | |
1260 | * He must be able to receive at least our minimum. | |
1261 | * No need to check a maximum. If he sends a large number, | |
1262 | * we'll just ignore it. | |
1263 | */ | |
1264 | if (cishort < PPP_MINMRU) { | |
1265 | LCPDEBUG((LOG_INFO, "lcp_reqci: Nak - MRU too small\n")); | |
1266 | orc = CONFNAK; /* Nak CI */ | |
1267 | PUTCHAR(CI_MRU, nakp); | |
1268 | PUTCHAR(CILEN_SHORT, nakp); | |
1269 | PUTSHORT(PPP_MINMRU, nakp); /* Give him a hint */ | |
1270 | break; | |
1271 | } | |
1272 | ho->neg_mru = 1; /* Remember he sent MRU */ | |
1273 | ho->mru = cishort; /* And remember value */ | |
1274 | #if TRACELCP > 0 | |
1275 | snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " MRU %d", cishort); | |
1276 | traceNdx = strlen(traceBuf); | |
1277 | #endif | |
1278 | break; | |
1279 | ||
1280 | case CI_ASYNCMAP: | |
1281 | if (!ao->neg_asyncmap) { | |
1282 | LCPDEBUG((LOG_INFO, "lcp_reqci: Reject ASYNCMAP not allowed\n")); | |
1283 | orc = CONFREJ; | |
1284 | break; | |
1285 | } else if (cilen != CILEN_LONG) { | |
1286 | LCPDEBUG((LOG_INFO, "lcp_reqci: Reject ASYNCMAP bad length\n")); | |
1287 | orc = CONFREJ; | |
1288 | break; | |
1289 | } | |
1290 | GETLONG(cilong, p); | |
1291 | ||
1292 | /* | |
1293 | * Asyncmap must have set at least the bits | |
1294 | * which are set in lcp_allowoptions[unit].asyncmap. | |
1295 | */ | |
1296 | if ((ao->asyncmap & ~cilong) != 0) { | |
1297 | LCPDEBUG((LOG_INFO, "lcp_reqci: Nak ASYNCMAP %lX missing %lX\n", | |
1298 | cilong, ao->asyncmap)); | |
1299 | orc = CONFNAK; | |
1300 | PUTCHAR(CI_ASYNCMAP, nakp); | |
1301 | PUTCHAR(CILEN_LONG, nakp); | |
1302 | PUTLONG(ao->asyncmap | cilong, nakp); | |
1303 | break; | |
1304 | } | |
1305 | ho->neg_asyncmap = 1; | |
1306 | ho->asyncmap = cilong; | |
1307 | #if TRACELCP > 0 | |
1308 | snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " ASYNCMAP=%lX", cilong); | |
1309 | traceNdx = strlen(traceBuf); | |
1310 | #endif | |
1311 | break; | |
1312 | ||
1313 | case CI_AUTHTYPE: | |
1314 | if (cilen < CILEN_SHORT) { | |
1315 | LCPDEBUG((LOG_INFO, "lcp_reqci: Reject AUTHTYPE missing arg\n")); | |
1316 | orc = CONFREJ; | |
1317 | break; | |
1318 | } else if (!(ao->neg_upap || ao->neg_chap)) { | |
1319 | /* | |
1320 | * Reject the option if we're not willing to authenticate. | |
1321 | */ | |
1322 | LCPDEBUG((LOG_INFO, "lcp_reqci: Reject AUTHTYPE not allowed\n")); | |
1323 | orc = CONFREJ; | |
1324 | break; | |
1325 | } | |
1326 | GETSHORT(cishort, p); | |
1327 | ||
1328 | /* | |
1329 | * Authtype must be UPAP or CHAP. | |
1330 | * | |
1331 | * Note: if both ao->neg_upap and ao->neg_chap are set, | |
1332 | * and the peer sends a Configure-Request with two | |
1333 | * authenticate-protocol requests, one for CHAP and one | |
1334 | * for UPAP, then we will reject the second request. | |
1335 | * Whether we end up doing CHAP or UPAP depends then on | |
1336 | * the ordering of the CIs in the peer's Configure-Request. | |
1337 | */ | |
1338 | ||
1339 | if (cishort == PPP_PAP) { | |
1340 | if (ho->neg_chap) { /* we've already accepted CHAP */ | |
1341 | LCPDEBUG((LOG_WARNING, "lcp_reqci: Reject AUTHTYPE PAP already accepted\n")); | |
1342 | orc = CONFREJ; | |
1343 | break; | |
1344 | } else if (cilen != CILEN_SHORT) { | |
1345 | LCPDEBUG((LOG_WARNING, "lcp_reqci: Reject AUTHTYPE PAP bad len\n")); | |
1346 | orc = CONFREJ; | |
1347 | break; | |
1348 | } | |
1349 | if (!ao->neg_upap) { /* we don't want to do PAP */ | |
1350 | LCPDEBUG((LOG_WARNING, "lcp_reqci: Nak AUTHTYPE PAP not allowed\n")); | |
1351 | orc = CONFNAK; /* NAK it and suggest CHAP */ | |
1352 | PUTCHAR(CI_AUTHTYPE, nakp); | |
1353 | PUTCHAR(CILEN_CHAP, nakp); | |
1354 | PUTSHORT(PPP_CHAP, nakp); | |
1355 | PUTCHAR(ao->chap_mdtype, nakp); | |
1356 | break; | |
1357 | } | |
1358 | ho->neg_upap = 1; | |
1359 | #if TRACELCP > 0 | |
1360 | snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " PAP (%X)", cishort); | |
1361 | traceNdx = strlen(traceBuf); | |
1362 | #endif | |
1363 | break; | |
1364 | } | |
1365 | if (cishort == PPP_CHAP) { | |
1366 | if (ho->neg_upap) { /* we've already accepted PAP */ | |
1367 | LCPDEBUG((LOG_WARNING, "lcp_reqci: Reject AUTHTYPE CHAP accepted PAP\n")); | |
1368 | orc = CONFREJ; | |
1369 | break; | |
1370 | } else if (cilen != CILEN_CHAP) { | |
1371 | LCPDEBUG((LOG_WARNING, "lcp_reqci: Reject AUTHTYPE CHAP bad len\n")); | |
1372 | orc = CONFREJ; | |
1373 | break; | |
1374 | } | |
1375 | if (!ao->neg_chap) { /* we don't want to do CHAP */ | |
1376 | LCPDEBUG((LOG_WARNING, "lcp_reqci: Nak AUTHTYPE CHAP not allowed\n")); | |
1377 | orc = CONFNAK; /* NAK it and suggest PAP */ | |
1378 | PUTCHAR(CI_AUTHTYPE, nakp); | |
1379 | PUTCHAR(CILEN_SHORT, nakp); | |
1380 | PUTSHORT(PPP_PAP, nakp); | |
1381 | break; | |
1382 | } | |
1383 | GETCHAR(cichar, p); /* get digest type*/ | |
1384 | if (cichar != CHAP_DIGEST_MD5 | |
1385 | #ifdef CHAPMS | |
1386 | && cichar != CHAP_MICROSOFT | |
1387 | #endif | |
1388 | ) { | |
1389 | LCPDEBUG((LOG_WARNING, "lcp_reqci: Nak AUTHTYPE CHAP digest=%d\n", cichar)); | |
1390 | orc = CONFNAK; | |
1391 | PUTCHAR(CI_AUTHTYPE, nakp); | |
1392 | PUTCHAR(CILEN_CHAP, nakp); | |
1393 | PUTSHORT(PPP_CHAP, nakp); | |
1394 | PUTCHAR(ao->chap_mdtype, nakp); | |
1395 | break; | |
1396 | } | |
1397 | #if TRACELCP > 0 | |
1398 | snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " CHAP %X,%d", cishort, cichar); | |
1399 | traceNdx = strlen(traceBuf); | |
1400 | #endif | |
1401 | ho->chap_mdtype = cichar; /* save md type */ | |
1402 | ho->neg_chap = 1; | |
1403 | break; | |
1404 | } | |
1405 | ||
1406 | /* | |
1407 | * We don't recognize the protocol they're asking for. | |
1408 | * Nak it with something we're willing to do. | |
1409 | * (At this point we know ao->neg_upap || ao->neg_chap.) | |
1410 | */ | |
1411 | orc = CONFNAK; | |
1412 | PUTCHAR(CI_AUTHTYPE, nakp); | |
1413 | if (ao->neg_chap) { | |
1414 | LCPDEBUG((LOG_WARNING, "lcp_reqci: Nak AUTHTYPE %d req CHAP\n", cishort)); | |
1415 | PUTCHAR(CILEN_CHAP, nakp); | |
1416 | PUTSHORT(PPP_CHAP, nakp); | |
1417 | PUTCHAR(ao->chap_mdtype, nakp); | |
1418 | } else { | |
1419 | LCPDEBUG((LOG_WARNING, "lcp_reqci: Nak AUTHTYPE %d req PAP\n", cishort)); | |
1420 | PUTCHAR(CILEN_SHORT, nakp); | |
1421 | PUTSHORT(PPP_PAP, nakp); | |
1422 | } | |
1423 | break; | |
1424 | ||
1425 | case CI_QUALITY: | |
1426 | GETSHORT(cishort, p); | |
1427 | GETLONG(cilong, p); | |
1428 | #if TRACELCP > 0 | |
1429 | snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " QUALITY (%x %x)", cishort, (unsigned int) cilong); | |
1430 | traceNdx = strlen(traceBuf); | |
1431 | #endif | |
1432 | ||
1433 | if (!ao->neg_lqr || | |
1434 | cilen != CILEN_LQR) { | |
1435 | orc = CONFREJ; | |
1436 | break; | |
1437 | } | |
1438 | ||
1439 | /* | |
1440 | * Check the protocol and the reporting period. | |
1441 | * XXX When should we Nak this, and what with? | |
1442 | */ | |
1443 | if (cishort != PPP_LQR) { | |
1444 | orc = CONFNAK; | |
1445 | PUTCHAR(CI_QUALITY, nakp); | |
1446 | PUTCHAR(CILEN_LQR, nakp); | |
1447 | PUTSHORT(PPP_LQR, nakp); | |
1448 | PUTLONG(ao->lqr_period, nakp); | |
1449 | break; | |
1450 | } | |
1451 | break; | |
1452 | ||
1453 | case CI_MAGICNUMBER: | |
1454 | if (!(ao->neg_magicnumber || go->neg_magicnumber) || | |
1455 | cilen != CILEN_LONG) { | |
1456 | orc = CONFREJ; | |
1457 | break; | |
1458 | } | |
1459 | GETLONG(cilong, p); | |
1460 | #if TRACELCP > 0 | |
1461 | snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " MAGICNUMBER (%lX)", cilong); | |
1462 | traceNdx = strlen(traceBuf); | |
1463 | #endif | |
1464 | ||
1465 | /* | |
1466 | * He must have a different magic number. | |
1467 | */ | |
1468 | if (go->neg_magicnumber && | |
1469 | cilong == go->magicnumber) { | |
1470 | cilong = magic(); /* Don't put magic() inside macro! */ | |
1471 | orc = CONFNAK; | |
1472 | PUTCHAR(CI_MAGICNUMBER, nakp); | |
1473 | PUTCHAR(CILEN_LONG, nakp); | |
1474 | PUTLONG(cilong, nakp); | |
1475 | break; | |
1476 | } | |
1477 | ho->neg_magicnumber = 1; | |
1478 | ho->magicnumber = cilong; | |
1479 | break; | |
1480 | ||
1481 | ||
1482 | case CI_PCOMPRESSION: | |
1483 | #if TRACELCP > 0 | |
1484 | snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " PCOMPRESSION"); | |
1485 | traceNdx = strlen(traceBuf); | |
1486 | #endif | |
1487 | if (!ao->neg_pcompression || | |
1488 | cilen != CILEN_VOID) { | |
1489 | orc = CONFREJ; | |
1490 | break; | |
1491 | } | |
1492 | ho->neg_pcompression = 1; | |
1493 | break; | |
1494 | ||
1495 | case CI_ACCOMPRESSION: | |
1496 | #if TRACELCP > 0 | |
1497 | snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " ACCOMPRESSION"); | |
1498 | traceNdx = strlen(traceBuf); | |
1499 | #endif | |
1500 | if (!ao->neg_accompression || | |
1501 | cilen != CILEN_VOID) { | |
1502 | orc = CONFREJ; | |
1503 | break; | |
1504 | } | |
1505 | ho->neg_accompression = 1; | |
1506 | break; | |
1507 | ||
1508 | case CI_MRRU: | |
1509 | #if TRACELCP > 0 | |
1510 | snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " CI_MRRU"); | |
1511 | traceNdx = strlen(traceBuf); | |
1512 | #endif | |
1513 | orc = CONFREJ; | |
1514 | break; | |
1515 | ||
1516 | case CI_SSNHF: | |
1517 | #if TRACELCP > 0 | |
1518 | snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " CI_SSNHF"); | |
1519 | traceNdx = strlen(traceBuf); | |
1520 | #endif | |
1521 | orc = CONFREJ; | |
1522 | break; | |
1523 | ||
1524 | case CI_EPDISC: | |
1525 | #if TRACELCP > 0 | |
1526 | snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " CI_EPDISC"); | |
1527 | traceNdx = strlen(traceBuf); | |
1528 | #endif | |
1529 | orc = CONFREJ; | |
1530 | break; | |
1531 | ||
1532 | default: | |
1533 | #if TRACELCP | |
1534 | snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " unknown %d", citype); | |
1535 | traceNdx = strlen(traceBuf); | |
1536 | #endif | |
1537 | orc = CONFREJ; | |
1538 | break; | |
1539 | } | |
1540 | ||
1541 | endswitch: | |
1542 | #if TRACELCP | |
1543 | if (traceNdx >= 80 - 32) { | |
1544 | LCPDEBUG((LOG_INFO, "lcp_reqci: rcvd%s\n", traceBuf)); | |
1545 | traceNdx = 0; | |
1546 | } | |
1547 | #endif | |
1548 | if (orc == CONFACK && /* Good CI */ | |
1549 | rc != CONFACK) { /* but prior CI wasnt? */ | |
1550 | continue; /* Don't send this one */ | |
1551 | } | |
1552 | ||
1553 | if (orc == CONFNAK) { /* Nak this CI? */ | |
1554 | if (reject_if_disagree /* Getting fed up with sending NAKs? */ | |
1555 | && citype != CI_MAGICNUMBER) { | |
1556 | orc = CONFREJ; /* Get tough if so */ | |
1557 | } else { | |
1558 | if (rc == CONFREJ) { /* Rejecting prior CI? */ | |
1559 | continue; /* Don't send this one */ | |
1560 | } | |
1561 | rc = CONFNAK; | |
1562 | } | |
1563 | } | |
1564 | if (orc == CONFREJ) { /* Reject this CI */ | |
1565 | rc = CONFREJ; | |
1566 | if (cip != rejp) { /* Need to move rejected CI? */ | |
1567 | BCOPY(cip, rejp, cilen); /* Move it */ | |
1568 | } | |
1569 | INCPTR(cilen, rejp); /* Update output pointer */ | |
1570 | } | |
1571 | } | |
1572 | ||
1573 | /* | |
1574 | * If we wanted to send additional NAKs (for unsent CIs), the | |
1575 | * code would go here. The extra NAKs would go at *nakp. | |
1576 | * At present there are no cases where we want to ask the | |
1577 | * peer to negotiate an option. | |
1578 | */ | |
1579 | ||
1580 | switch (rc) { | |
1581 | case CONFACK: | |
1582 | *lenp = (int)(next - inp); | |
1583 | break; | |
1584 | case CONFNAK: | |
1585 | /* | |
1586 | * Copy the Nak'd options from the nak_buffer to the caller's buffer. | |
1587 | */ | |
1588 | *lenp = (int)(nakp - nak_buffer); | |
1589 | BCOPY(nak_buffer, inp, *lenp); | |
1590 | break; | |
1591 | case CONFREJ: | |
1592 | *lenp = (int)(rejp - inp); | |
1593 | break; | |
1594 | } | |
1595 | ||
1596 | #if TRACELCP > 0 | |
1597 | if (traceNdx > 0) { | |
1598 | LCPDEBUG((LOG_INFO, "lcp_reqci: %s\n", traceBuf)); | |
1599 | } | |
1600 | #endif | |
1601 | LCPDEBUG((LOG_INFO, "lcp_reqci: returning CONF%s.\n", CODENAME(rc))); | |
1602 | return (rc); /* Return final code */ | |
1603 | } | |
1604 | ||
1605 | ||
1606 | /* | |
1607 | * lcp_up - LCP has come UP. | |
1608 | */ | |
1609 | static void | |
1610 | lcp_up(fsm *f) | |
1611 | { | |
1612 | lcp_options *wo = &lcp_wantoptions[f->unit]; | |
1613 | lcp_options *ho = &lcp_hisoptions[f->unit]; | |
1614 | lcp_options *go = &lcp_gotoptions[f->unit]; | |
1615 | lcp_options *ao = &lcp_allowoptions[f->unit]; | |
1616 | ||
1617 | if (!go->neg_magicnumber) { | |
1618 | go->magicnumber = 0; | |
1619 | } | |
1620 | if (!ho->neg_magicnumber) { | |
1621 | ho->magicnumber = 0; | |
1622 | } | |
1623 | ||
1624 | /* | |
1625 | * Set our MTU to the smaller of the MTU we wanted and | |
1626 | * the MRU our peer wanted. If we negotiated an MRU, | |
1627 | * set our MRU to the larger of value we wanted and | |
1628 | * the value we got in the negotiation. | |
1629 | */ | |
1630 | ppp_send_config(f->unit, LWIP_MIN(ao->mru, (ho->neg_mru? ho->mru: PPP_MRU)), | |
1631 | (ho->neg_asyncmap? ho->asyncmap: 0xffffffffl), | |
1632 | ho->neg_pcompression, ho->neg_accompression); | |
1633 | /* | |
1634 | * If the asyncmap hasn't been negotiated, we really should | |
1635 | * set the receive asyncmap to ffffffff, but we set it to 0 | |
1636 | * for backwards contemptibility. | |
1637 | */ | |
1638 | ppp_recv_config(f->unit, (go->neg_mru? LWIP_MAX(wo->mru, go->mru): PPP_MRU), | |
1639 | (go->neg_asyncmap? go->asyncmap: 0x00000000), | |
1640 | go->neg_pcompression, go->neg_accompression); | |
1641 | ||
1642 | if (ho->neg_mru) { | |
1643 | peer_mru[f->unit] = ho->mru; | |
1644 | } | |
1645 | ||
1646 | lcp_echo_lowerup(f->unit); /* Enable echo messages */ | |
1647 | ||
1648 | link_established(f->unit); | |
1649 | } | |
1650 | ||
1651 | ||
1652 | /* | |
1653 | * lcp_down - LCP has gone DOWN. | |
1654 | * | |
1655 | * Alert other protocols. | |
1656 | */ | |
1657 | static void | |
1658 | lcp_down(fsm *f) | |
1659 | { | |
1660 | lcp_options *go = &lcp_gotoptions[f->unit]; | |
1661 | ||
1662 | lcp_echo_lowerdown(f->unit); | |
1663 | ||
1664 | link_down(f->unit); | |
1665 | ||
1666 | ppp_send_config(f->unit, PPP_MRU, 0xffffffffl, 0, 0); | |
1667 | ppp_recv_config(f->unit, PPP_MRU, | |
1668 | (go->neg_asyncmap? go->asyncmap: 0x00000000), | |
1669 | go->neg_pcompression, go->neg_accompression); | |
1670 | peer_mru[f->unit] = PPP_MRU; | |
1671 | } | |
1672 | ||
1673 | ||
1674 | /* | |
1675 | * lcp_starting - LCP needs the lower layer up. | |
1676 | */ | |
1677 | static void | |
1678 | lcp_starting(fsm *f) | |
1679 | { | |
1680 | link_required(f->unit); | |
1681 | } | |
1682 | ||
1683 | ||
1684 | /* | |
1685 | * lcp_finished - LCP has finished with the lower layer. | |
1686 | */ | |
1687 | static void | |
1688 | lcp_finished(fsm *f) | |
1689 | { | |
1690 | link_terminated(f->unit); | |
1691 | } | |
1692 | ||
1693 | ||
1694 | #if 0 | |
1695 | /* | |
1696 | * print_string - print a readable representation of a string using | |
1697 | * printer. | |
1698 | */ | |
1699 | static void | |
1700 | print_string( char *p, int len, void (*printer) (void *, char *, ...), void *arg) | |
1701 | { | |
1702 | int c; | |
1703 | ||
1704 | printer(arg, "\""); | |
1705 | for (; len > 0; --len) { | |
1706 | c = *p++; | |
1707 | if (' ' <= c && c <= '~') { | |
1708 | if (c == '\\' || c == '"') { | |
1709 | printer(arg, "\\"); | |
1710 | } | |
1711 | printer(arg, "%c", c); | |
1712 | } else { | |
1713 | switch (c) { | |
1714 | case '\n': | |
1715 | printer(arg, "\\n"); | |
1716 | break; | |
1717 | case '\r': | |
1718 | printer(arg, "\\r"); | |
1719 | break; | |
1720 | case '\t': | |
1721 | printer(arg, "\\t"); | |
1722 | break; | |
1723 | default: | |
1724 | printer(arg, "\\%.3o", c); | |
1725 | } | |
1726 | } | |
1727 | } | |
1728 | printer(arg, "\""); | |
1729 | } | |
1730 | ||
1731 | ||
1732 | /* | |
1733 | * lcp_printpkt - print the contents of an LCP packet. | |
1734 | */ | |
1735 | static char *lcp_codenames[] = { | |
1736 | "ConfReq", "ConfAck", "ConfNak", "ConfRej", | |
1737 | "TermReq", "TermAck", "CodeRej", "ProtRej", | |
1738 | "EchoReq", "EchoRep", "DiscReq" | |
1739 | }; | |
1740 | ||
1741 | static int | |
1742 | lcp_printpkt( u_char *p, int plen, void (*printer) (void *, char *, ...), void *arg) | |
1743 | { | |
1744 | int code, id, len, olen; | |
1745 | u_char *pstart, *optend; | |
1746 | u_short cishort; | |
1747 | u32_t cilong; | |
1748 | ||
1749 | if (plen < HEADERLEN) { | |
1750 | return 0; | |
1751 | } | |
1752 | pstart = p; | |
1753 | GETCHAR(code, p); | |
1754 | GETCHAR(id, p); | |
1755 | GETSHORT(len, p); | |
1756 | if (len < HEADERLEN || len > plen) { | |
1757 | return 0; | |
1758 | } | |
1759 | ||
1760 | if (code >= 1 && code <= sizeof(lcp_codenames) / sizeof(char *)) { | |
1761 | printer(arg, " %s", lcp_codenames[code-1]); | |
1762 | } else { | |
1763 | printer(arg, " code=0x%x", code); | |
1764 | } | |
1765 | printer(arg, " id=0x%x", id); | |
1766 | len -= HEADERLEN; | |
1767 | switch (code) { | |
1768 | case CONFREQ: | |
1769 | case CONFACK: | |
1770 | case CONFNAK: | |
1771 | case CONFREJ: | |
1772 | /* print option list */ | |
1773 | while (len >= 2) { | |
1774 | GETCHAR(code, p); | |
1775 | GETCHAR(olen, p); | |
1776 | p -= 2; | |
1777 | if (olen < 2 || olen > len) { | |
1778 | break; | |
1779 | } | |
1780 | printer(arg, " <"); | |
1781 | len -= olen; | |
1782 | optend = p + olen; | |
1783 | switch (code) { | |
1784 | case CI_MRU: | |
1785 | if (olen == CILEN_SHORT) { | |
1786 | p += 2; | |
1787 | GETSHORT(cishort, p); | |
1788 | printer(arg, "mru %d", cishort); | |
1789 | } | |
1790 | break; | |
1791 | case CI_ASYNCMAP: | |
1792 | if (olen == CILEN_LONG) { | |
1793 | p += 2; | |
1794 | GETLONG(cilong, p); | |
1795 | printer(arg, "asyncmap 0x%lx", cilong); | |
1796 | } | |
1797 | break; | |
1798 | case CI_AUTHTYPE: | |
1799 | if (olen >= CILEN_SHORT) { | |
1800 | p += 2; | |
1801 | printer(arg, "auth "); | |
1802 | GETSHORT(cishort, p); | |
1803 | switch (cishort) { | |
1804 | case PPP_PAP: | |
1805 | printer(arg, "pap"); | |
1806 | break; | |
1807 | case PPP_CHAP: | |
1808 | printer(arg, "chap"); | |
1809 | break; | |
1810 | default: | |
1811 | printer(arg, "0x%x", cishort); | |
1812 | } | |
1813 | } | |
1814 | break; | |
1815 | case CI_QUALITY: | |
1816 | if (olen >= CILEN_SHORT) { | |
1817 | p += 2; | |
1818 | printer(arg, "quality "); | |
1819 | GETSHORT(cishort, p); | |
1820 | switch (cishort) { | |
1821 | case PPP_LQR: | |
1822 | printer(arg, "lqr"); | |
1823 | break; | |
1824 | default: | |
1825 | printer(arg, "0x%x", cishort); | |
1826 | } | |
1827 | } | |
1828 | break; | |
1829 | case CI_CALLBACK: | |
1830 | if (olen >= CILEN_CHAR) { | |
1831 | p += 2; | |
1832 | printer(arg, "callback "); | |
1833 | GETSHORT(cishort, p); | |
1834 | switch (cishort) { | |
1835 | case CBCP_OPT: | |
1836 | printer(arg, "CBCP"); | |
1837 | break; | |
1838 | default: | |
1839 | printer(arg, "0x%x", cishort); | |
1840 | } | |
1841 | } | |
1842 | break; | |
1843 | case CI_MAGICNUMBER: | |
1844 | if (olen == CILEN_LONG) { | |
1845 | p += 2; | |
1846 | GETLONG(cilong, p); | |
1847 | printer(arg, "magic 0x%x", cilong); | |
1848 | } | |
1849 | break; | |
1850 | case CI_PCOMPRESSION: | |
1851 | if (olen == CILEN_VOID) { | |
1852 | p += 2; | |
1853 | printer(arg, "pcomp"); | |
1854 | } | |
1855 | break; | |
1856 | case CI_ACCOMPRESSION: | |
1857 | if (olen == CILEN_VOID) { | |
1858 | p += 2; | |
1859 | printer(arg, "accomp"); | |
1860 | } | |
1861 | break; | |
1862 | } | |
1863 | while (p < optend) { | |
1864 | GETCHAR(code, p); | |
1865 | printer(arg, " %.2x", code); | |
1866 | } | |
1867 | printer(arg, ">"); | |
1868 | } | |
1869 | break; | |
1870 | ||
1871 | case TERMACK: | |
1872 | case TERMREQ: | |
1873 | if (len > 0 && *p >= ' ' && *p < 0x7f) { | |
1874 | printer(arg, " "); | |
1875 | print_string((char*)p, len, printer, arg); | |
1876 | p += len; | |
1877 | len = 0; | |
1878 | } | |
1879 | break; | |
1880 | ||
1881 | case ECHOREQ: | |
1882 | case ECHOREP: | |
1883 | case DISCREQ: | |
1884 | if (len >= 4) { | |
1885 | GETLONG(cilong, p); | |
1886 | printer(arg, " magic=0x%x", cilong); | |
1887 | p += 4; | |
1888 | len -= 4; | |
1889 | } | |
1890 | break; | |
1891 | } | |
1892 | ||
1893 | /* print the rest of the bytes in the packet */ | |
1894 | for (; len > 0; --len) { | |
1895 | GETCHAR(code, p); | |
1896 | printer(arg, " %.2x", code); | |
1897 | } | |
1898 | ||
1899 | return (int)(p - pstart); | |
1900 | } | |
1901 | #endif | |
1902 | ||
1903 | /* | |
1904 | * Time to shut down the link because there is nothing out there. | |
1905 | */ | |
1906 | static void | |
1907 | LcpLinkFailure (fsm *f) | |
1908 | { | |
1909 | if (f->state == LS_OPENED) { | |
1910 | LCPDEBUG((LOG_INFO, "No response to %d echo-requests\n", lcp_echos_pending)); | |
1911 | LCPDEBUG((LOG_NOTICE, "Serial link appears to be disconnected.\n")); | |
1912 | lcp_close(f->unit, "Peer not responding"); | |
1913 | } | |
1914 | } | |
1915 | ||
1916 | /* | |
1917 | * Timer expired for the LCP echo requests from this process. | |
1918 | */ | |
1919 | static void | |
1920 | LcpEchoCheck (fsm *f) | |
1921 | { | |
1922 | LcpSendEchoRequest (f); | |
1923 | ||
1924 | /* | |
1925 | * Start the timer for the next interval. | |
1926 | */ | |
1927 | LWIP_ASSERT("lcp_echo_timer_running == 0", lcp_echo_timer_running == 0); | |
1928 | ||
1929 | TIMEOUT (LcpEchoTimeout, f, lcp_echo_interval); | |
1930 | lcp_echo_timer_running = 1; | |
1931 | } | |
1932 | ||
1933 | /* | |
1934 | * LcpEchoTimeout - Timer expired on the LCP echo | |
1935 | */ | |
1936 | static void | |
1937 | LcpEchoTimeout (void *arg) | |
1938 | { | |
1939 | if (lcp_echo_timer_running != 0) { | |
1940 | lcp_echo_timer_running = 0; | |
1941 | LcpEchoCheck ((fsm *) arg); | |
1942 | } | |
1943 | } | |
1944 | ||
1945 | /* | |
1946 | * LcpEchoReply - LCP has received a reply to the echo | |
1947 | */ | |
1948 | static void | |
1949 | lcp_received_echo_reply (fsm *f, int id, u_char *inp, int len) | |
1950 | { | |
1951 | u32_t magic; | |
1952 | ||
1953 | LWIP_UNUSED_ARG(id); | |
1954 | ||
1955 | /* Check the magic number - don't count replies from ourselves. */ | |
1956 | if (len < 4) { | |
1957 | LCPDEBUG((LOG_WARNING, "lcp: received short Echo-Reply, length %d\n", len)); | |
1958 | return; | |
1959 | } | |
1960 | GETLONG(magic, inp); | |
1961 | if (lcp_gotoptions[f->unit].neg_magicnumber && magic == lcp_gotoptions[f->unit].magicnumber) { | |
1962 | LCPDEBUG((LOG_WARNING, "appear to have received our own echo-reply!\n")); | |
1963 | return; | |
1964 | } | |
1965 | ||
1966 | /* Reset the number of outstanding echo frames */ | |
1967 | lcp_echos_pending = 0; | |
1968 | } | |
1969 | ||
1970 | /* | |
1971 | * LcpSendEchoRequest - Send an echo request frame to the peer | |
1972 | */ | |
1973 | static void | |
1974 | LcpSendEchoRequest (fsm *f) | |
1975 | { | |
1976 | u32_t lcp_magic; | |
1977 | u_char pkt[4], *pktp; | |
1978 | ||
1979 | /* | |
1980 | * Detect the failure of the peer at this point. | |
1981 | */ | |
1982 | if (lcp_echo_fails != 0) { | |
1983 | if (lcp_echos_pending++ >= lcp_echo_fails) { | |
1984 | LcpLinkFailure(f); | |
1985 | lcp_echos_pending = 0; | |
1986 | } | |
1987 | } | |
1988 | ||
1989 | /* | |
1990 | * Make and send the echo request frame. | |
1991 | */ | |
1992 | if (f->state == LS_OPENED) { | |
1993 | lcp_magic = lcp_gotoptions[f->unit].magicnumber; | |
1994 | pktp = pkt; | |
1995 | PUTLONG(lcp_magic, pktp); | |
1996 | fsm_sdata(f, ECHOREQ, (u_char)(lcp_echo_number++ & 0xFF), pkt, (int)(pktp - pkt)); | |
1997 | } | |
1998 | } | |
1999 | ||
2000 | /* | |
2001 | * lcp_echo_lowerup - Start the timer for the LCP frame | |
2002 | */ | |
2003 | ||
2004 | static void | |
2005 | lcp_echo_lowerup (int unit) | |
2006 | { | |
2007 | fsm *f = &lcp_fsm[unit]; | |
2008 | ||
2009 | /* Clear the parameters for generating echo frames */ | |
2010 | lcp_echos_pending = 0; | |
2011 | lcp_echo_number = 0; | |
2012 | lcp_echo_timer_running = 0; | |
2013 | ||
2014 | /* If a timeout interval is specified then start the timer */ | |
2015 | if (lcp_echo_interval != 0) { | |
2016 | LcpEchoCheck (f); | |
2017 | } | |
2018 | } | |
2019 | ||
2020 | /* | |
2021 | * lcp_echo_lowerdown - Stop the timer for the LCP frame | |
2022 | */ | |
2023 | ||
2024 | static void | |
2025 | lcp_echo_lowerdown (int unit) | |
2026 | { | |
2027 | fsm *f = &lcp_fsm[unit]; | |
2028 | ||
2029 | if (lcp_echo_timer_running != 0) { | |
2030 | UNTIMEOUT (LcpEchoTimeout, f); | |
2031 | lcp_echo_timer_running = 0; | |
2032 | } | |
2033 | } | |
2034 | ||
2035 | #endif /* PPP_SUPPORT */ |