8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / cmd / cmd-inet / usr.bin / pppd / lcp.c
blobb4d653c06e1c4dd6b4b23957f5efbb6d558afa14
1 /*
2 * lcp.c - PPP Link Control Protocol.
4 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
5 * Use is subject to license terms.
7 * Copyright (c) 1989 Carnegie Mellon University.
8 * All rights reserved.
10 * Copyright (c) 2016 by Delphix. All rights reserved.
12 * Redistribution and use in source and binary forms are permitted
13 * provided that the above copyright notice and this paragraph are
14 * duplicated in all such forms and that any documentation,
15 * advertising materials, and other materials related to such
16 * distribution and use acknowledge that the software was developed
17 * by Carnegie Mellon University. The name of the
18 * University may not be used to endorse or promote products derived
19 * from this software without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
21 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
22 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
25 #define RCSID "$Id: lcp.c,v 1.54 2000/04/27 03:51:18 masputra Exp $"
28 * TODO:
31 #include <stdio.h>
32 #include <string.h>
33 #include <stdlib.h>
34 #include <ctype.h>
35 #if defined(CHAPMS) || defined(CHAPMSV2)
36 #ifdef HAVE_CRYPT_H
37 #include <crypt.h>
38 #endif
39 #ifndef USE_CRYPT
40 #include <des.h>
41 #endif
42 #ifdef SOL2
43 #include <errno.h>
44 #endif
45 #endif
47 #include "pppd.h"
48 #include "fsm.h"
49 #include "lcp.h"
50 #include "chap.h"
51 #include "magic.h"
52 #include "patchlevel.h"
54 #if !defined(lint) && !defined(_lint)
55 static const char rcsid[] = RCSID;
56 #endif
59 * Special failure codes for logging link failure reasons.
61 bool peer_nak_auth; /* Peer sent nak for our auth request */
62 u_short nak_auth_orig; /* Auth proto peer naked */
63 u_short nak_auth_proto; /* Auth proto peer suggested instead */
64 bool unsolicited_nak_auth; /* Peer asked us to authenticate */
65 u_short unsolicit_auth_proto; /* Auth proto peer wants */
66 bool peer_reject_auth; /* Peer sent reject for auth */
67 u_short reject_auth_proto; /* Protocol that peer rejected */
68 bool rejected_peers_auth; /* We sent a reject to the peer */
69 u_short rejected_auth_proto; /* Protocol that peer wanted to use */
70 bool naked_peers_auth; /* We sent a nak to the peer */
71 u_short naked_auth_orig; /* Protocol that we wanted to use */
72 u_short naked_auth_proto; /* Protocol that peer wants us to use */
75 * LCP-related command-line options.
77 int lcp_echo_interval = 0; /* Interval between LCP echo-requests */
78 int lcp_echo_fails = 0; /* Tolerance to unanswered echo-requests */
79 bool lax_recv = 0; /* accept control chars in asyncmap */
80 static int use_accm_test = 2; /* use big echo-requests to check ACCM */
81 #define ACCM_TEST_FAILS 5
83 #define _tostr2(x) #x
84 #define _tostr(x) _tostr2(x)
85 static char identstr[256] = /* Identification string */
86 "ppp-" VERSION "." _tostr(PATCHLEVEL) IMPLEMENTATION;
87 static int noident = 0; /* 1 to disable; 2 to reject */
88 static int sentident = 0; /* counts the # of ident codes sent */
90 /* set if we're allowed to send an unsolicited Configure-Nak for MRU. */
91 static bool unsolicit_mru;
93 static int setescape __P((char **, option_t *));
95 static bool do_msft_workaround = 1;
96 static int setasyncmap __P((char **, option_t *));
98 bool noendpoint = 0; /* don't send/accept endpoint discriminator */
99 static int setendpoint __P((char **, option_t *));
101 static char *callback_strings[] = {
102 "auth", "dialstring", "location", "E.164", "X.500", "", "CBCP", NULL
105 /* This is used in packet printing even if NEGOTIATE_FCS isn't enabled */
106 static char *fcsalt_strings[] = {
107 "null", "crc16", "crc32", NULL
110 #ifdef NEGOTIATE_FCS
111 static int setfcsallow __P((char **, option_t *));
112 static int setfcswant __P((char **, option_t *));
113 #endif
115 /* Backward compatibility for Linux */
116 #ifndef PPP_MAXMRU
117 #define PPP_MTU 1500 /* Default MTU (size of Info field) */
118 #define PPP_MAXMTU 65535 - (PPP_HDRLEN + PPP_FCSLEN)
119 #define PPP_MINMTU 64
120 #define PPP_MAXMRU 65000 /* Largest MRU we allow */
121 #define PPP_MINMRU 128
122 #endif
124 static option_t lcp_option_list[] = {
125 /* LCP options */
126 { "noaccomp", o_bool, &lcp_wantoptions[0].neg_accompression,
127 "Disable address/control compression",
128 OPT_A2COPY, &lcp_allowoptions[0].neg_accompression },
129 { "-ac", o_bool, &lcp_wantoptions[0].neg_accompression,
130 "Disable address/control compression",
131 OPT_A2COPY, &lcp_allowoptions[0].neg_accompression },
132 { "default-asyncmap", o_bool, &lcp_wantoptions[0].neg_asyncmap,
133 "Disable asyncmap negotiation",
134 OPT_A2COPY, &lcp_allowoptions[0].neg_asyncmap },
135 { "-am", o_bool, &lcp_wantoptions[0].neg_asyncmap,
136 "Disable asyncmap negotiation",
137 OPT_A2COPY, &lcp_allowoptions[0].neg_asyncmap },
138 { "asyncmap", o_special, (void *)setasyncmap,
139 "Set asyncmap (for received packets)" },
140 { "-as", o_special, (void *)setasyncmap,
141 "Set asyncmap (for received packets)" },
142 { "nomagic", o_bool, &lcp_wantoptions[0].neg_magicnumber,
143 "Disable magic number option (looped-back line detect)",
144 OPT_A2COPY, &lcp_allowoptions[0].neg_magicnumber },
145 { "-mn", o_bool, &lcp_wantoptions[0].neg_magicnumber,
146 "Disable magic number option (looped-back line detect)",
147 OPT_A2COPY, &lcp_allowoptions[0].neg_magicnumber },
148 { "default-mru", o_bool, &lcp_wantoptions[0].neg_mru,
149 "Disable MRU negotiation (use default 1500)",
150 OPT_A2COPY, &lcp_allowoptions[0].neg_mru },
151 { "-mru", o_bool, &lcp_wantoptions[0].neg_mru,
152 "Disable MRU negotiation (use default 1500)",
153 OPT_A2COPY, &lcp_allowoptions[0].neg_mru },
154 { "mru", o_int, &lcp_wantoptions[0].mru,
155 "Set MRU (maximum received packet size) for negotiation",
156 OPT_LIMITS, &lcp_wantoptions[0].neg_mru, PPP_MAXMRU, PPP_MINMRU },
157 { "mtu", o_int, &lcp_allowoptions[0].mru,
158 "Set our MTU", OPT_LIMITS|OPT_A2COPY, &lcp_allowoptions[0].mrru,
159 PPP_MAXMTU, PPP_MINMTU },
160 { "nopcomp", o_bool, &lcp_wantoptions[0].neg_pcompression,
161 "Disable protocol field compression",
162 OPT_A2COPY, &lcp_allowoptions[0].neg_pcompression },
163 { "-pc", o_bool, &lcp_wantoptions[0].neg_pcompression,
164 "Disable protocol field compression",
165 OPT_A2COPY, &lcp_allowoptions[0].neg_pcompression },
166 { "-p", o_bool, &lcp_wantoptions[0].passive,
167 "Set passive mode", 1 },
168 { "passive", o_bool, &lcp_wantoptions[0].passive,
169 "Set passive mode", 1 },
170 { "silent", o_bool, &lcp_wantoptions[0].silent,
171 "Set silent mode", 1 },
172 { "escape", o_special, (void *)setescape,
173 "List of character codes to escape on transmission" },
174 { "lcp-echo-failure", o_int, &lcp_echo_fails,
175 "Number of consecutive echo failures for link failure" },
176 { "lcp-echo-interval", o_int, &lcp_echo_interval,
177 "Set time in seconds between LCP echo requests" },
178 { "no-accm-test", o_int, &use_accm_test,
179 "Disable use of LCP Echo-Request asyncmap checking",
180 OPT_NOARG|OPT_VAL(0) },
181 { "small-accm-test", o_int, &use_accm_test,
182 "Use only small Echo-Requests for asyncmap checking",
183 OPT_NOARG|OPT_VAL(1) },
184 { "lcp-restart", o_int, &lcp_fsm[0].timeouttime,
185 "Set time in seconds between LCP retransmissions" },
186 { "lcp-max-terminate", o_int, &lcp_fsm[0].maxtermtransmits,
187 "Maximum number of LCP terminate-request transmissions" },
188 { "lcp-max-configure", o_int, &lcp_fsm[0].maxconfreqtransmits,
189 "Maximum number of LCP configure-request transmissions" },
190 { "lcp-max-failure", o_int, &lcp_fsm[0].maxnakloops,
191 "Set limit on number of LCP configure-naks" },
192 { "receive-all", o_bool, &lax_recv,
193 "Accept all received control characters", 1 },
194 #ifdef HAVE_MULTILINK
195 { "mrru", o_int, &lcp_wantoptions[0].mrru,
196 "Maximum received packet size for multilink bundle",
197 OPT_LIMITS, &lcp_wantoptions[0].neg_mrru, PPP_MAXMRU, PPP_MINMRU },
198 { "mpshortseq", o_bool, &lcp_wantoptions[0].neg_ssnhf,
199 "Use short sequence numbers in multilink headers",
200 OPT_A2COPY | 1, &lcp_allowoptions[0].neg_ssnhf },
201 { "nompshortseq", o_bool, &lcp_wantoptions[0].neg_ssnhf,
202 "Don't use short sequence numbers in multilink headers",
203 OPT_A2COPY, &lcp_allowoptions[0].neg_ssnhf },
204 #endif /* HAVE_MULTILINK */
205 { "endpoint", o_special, (void *)setendpoint,
206 "Endpoint discriminator for multilink", },
207 { "noendpoint", o_bool, &noendpoint,
208 "Don't send or accept multilink endpoint discriminator", 1 },
209 { "ident", o_string, identstr,
210 "LCP Identification string", OPT_STATIC, NULL, sizeof(identstr) },
211 { "noident", o_int, &noident,
212 "Disable use of LCP Identification", OPT_INC|OPT_NOARG|1 },
213 #ifdef NEGOTIATE_FCS
214 { "default-fcs", o_bool, &lcp_wantoptions[0].neg_fcs,
215 "Disable FCS Alternatives option (use default CRC-16)",
216 OPT_A2COPY, &lcp_allowoptions[0].neg_fcs },
217 { "allow-fcs", o_special, (void *)setfcsallow,
218 "Set allowable FCS types; crc16, crc32, null, or number" },
219 { "fcs", o_special, (void *)setfcswant,
220 "Set FCS type(s) desired; crc16, crc32, null, or number" },
221 #endif
222 #ifdef MUX_FRAME
224 * if pppmux option is turned on, then the parameter to this
225 * is time value in microseconds
227 { "pppmux", o_int, &lcp_wantoptions[0].pppmux,
228 "Set PPP Multiplexing option timer", OPT_LLIMIT | OPT_A2COPY,
229 &lcp_allowoptions[0].pppmux, 0, 0 },
230 #endif
231 {NULL}
234 /* global vars */
235 fsm lcp_fsm[NUM_PPP]; /* LCP fsm structure (global)*/
236 lcp_options lcp_wantoptions[NUM_PPP]; /* Options that we want to request */
237 lcp_options lcp_gotoptions[NUM_PPP]; /* Options that peer ack'd */
238 lcp_options lcp_allowoptions[NUM_PPP]; /* Options we allow peer to request */
239 lcp_options lcp_hisoptions[NUM_PPP]; /* Options that we ack'd */
240 u_int32_t xmit_accm[NUM_PPP][8]; /* extended transmit ACCM */
243 * These variables allow a plugin to assert limits on the maximum
244 * MRU/MTU values that can be negotiated.
246 int absmax_mru = PPP_MAXMRU;
247 int absmax_mtu = PPP_MAXMTU;
249 static int lcp_echos_pending = 0; /* Number of outstanding echo msgs */
250 static int lcp_echo_number = 0; /* ID number of next echo frame */
251 static int lcp_echo_timer_running = 0; /* set if a timer is running */
252 static bool lcp_echo_accm_test = 0; /* flag if still testing ACCM */
253 static int lcp_echo_badreplies = 0; /* number of bad replies from peer */
255 * The maximum number of bad replies we tolerate before bringing the
256 * link down.
258 #define LCP_ECHO_MAX_BADREPLIES 10
261 * Callbacks for fsm code. (CI = Configuration Information)
263 static void lcp_resetci __P((fsm *)); /* Reset our CI */
264 static int lcp_cilen __P((fsm *)); /* Return length of our CI */
265 static void lcp_addci __P((fsm *, u_char *, int *)); /* Add our CI to pkt */
266 static int lcp_ackci __P((fsm *, u_char *, int)); /* Peer ack'd our CI */
267 static int lcp_nakci __P((fsm *, u_char *, int)); /* Peer nak'd our CI */
268 static int lcp_rejci __P((fsm *, u_char *, int)); /* Peer rej'd our CI */
269 static int lcp_reqci __P((fsm *, u_char *, int *, int)); /* Rcv peer CI */
270 static void lcp_up __P((fsm *)); /* We're UP */
271 static void lcp_down __P((fsm *)); /* We're DOWN */
272 static void lcp_starting __P((fsm *)); /* We need lower layer up */
273 static void lcp_finished __P((fsm *)); /* We need lower layer down */
274 static int lcp_extcode __P((fsm *, int, int, u_char *, int));
275 static void lcp_rprotrej __P((fsm *, u_char *, int));
276 static int lcp_coderej __P((fsm *f, int code, int id, u_char *inp, int len));
279 * routines to send LCP echos to peer
282 static void lcp_echo_lowerup __P((int));
283 static void lcp_echo_lowerdown __P((int));
284 static void LcpEchoTimeout __P((void *));
285 static int lcp_received_echo_reply __P((fsm *, int, u_char *, int));
286 static void LcpSendEchoRequest __P((fsm *));
287 static void LcpLinkFailure __P((fsm *));
288 static void LcpEchoCheck __P((fsm *));
291 * routines to send and receive additional LCP packets described in
292 * section 1 of rfc1570.
294 static void LcpSendIdentification __P((fsm *));
295 static void lcp_received_identification __P((fsm *, int, u_char *, int));
296 static void LcpSendTimeRemaining __P((fsm *, u_int32_t));
297 static void lcp_timeremaining __P((void *));
298 static void lcp_received_timeremain __P((fsm *, int, u_char *, int));
301 static fsm_callbacks lcp_callbacks = { /* LCP callback routines */
302 lcp_resetci, /* Reset our Configuration Information */
303 lcp_cilen, /* Length of our Configuration Information */
304 lcp_addci, /* Add our Configuration Information */
305 lcp_ackci, /* ACK our Configuration Information */
306 lcp_nakci, /* NAK our Configuration Information */
307 lcp_rejci, /* Reject our Configuration Information */
308 lcp_reqci, /* Request peer's Configuration Information */
309 lcp_up, /* Called when fsm reaches OPENED state */
310 lcp_down, /* Called when fsm leaves OPENED state */
311 lcp_starting, /* Called when we want the lower layer up */
312 lcp_finished, /* Called when we want the lower layer down */
313 NULL, /* Retransmission is necessary */
314 lcp_extcode, /* Called to handle LCP-specific codes */
315 "LCP", /* String name of protocol */
316 lcp_coderej, /* Peer rejected a code number */
320 * Protocol entry points.
321 * Some of these are called directly.
324 static void lcp_init __P((int));
325 static void lcp_input __P((int, u_char *, int));
326 static void lcp_protrej __P((int));
327 static int lcp_printpkt __P((u_char *, int,
328 void (*) __P((void *, const char *, ...)), void *));
331 struct protent lcp_protent = {
332 PPP_LCP, /* Protocol Number for LCP */
333 lcp_init, /* Initializes LCP */
334 lcp_input, /* Processes a received LCP packet */
335 lcp_protrej, /* Process a received Protocol-reject */
336 lcp_lowerup, /* Called after the serial device has been set up */
337 lcp_lowerdown, /* Called when the link is brought down */
338 lcp_open, /* Called after lcp_lowerup when bringing up the link */
339 lcp_close, /* Called when the link goes down */
340 lcp_printpkt, /* Print a packet in human readable form */
341 NULL, /* Process a received data packet */
342 1, /* LCP is enabled by default */
343 "LCP", /* Name of the protocol */
344 NULL, /* Name of the corresponding data protocol */
345 lcp_option_list, /* List of LCP command-line options */
346 NULL, /* Assigns default values for options */
347 NULL, /* Configures demand-dial */
348 NULL /* Bring up the link for this packet? */
351 int lcp_loopbackfail = DEFLOOPBACKFAIL;
354 * Length of each type of configuration option (in octets)
356 #define CILEN_VOID 2
357 #define CILEN_CHAR 3
358 #define CILEN_SHORT 4 /* CILEN_VOID + 2 */
359 #define CILEN_CHAP 5 /* CILEN_VOID + 2 + 1 */
360 #define CILEN_LONG 6 /* CILEN_VOID + 4 */
361 #define CILEN_LQR 8 /* CILEN_VOID + 2 + 4 */
362 #define CILEN_CBCP 3
366 * setescape - add chars to the set we escape on transmission.
368 /*ARGSUSED*/
369 static int
370 setescape(argv, opt)
371 char **argv;
372 option_t *opt;
374 int n, ret;
375 char *p, *endp;
377 p = *argv;
378 ret = 1;
379 while (*p != '\0') {
380 n = strtol(p, &endp, 16);
381 if (p == endp) {
382 option_error("escape parameter contains invalid hex number '%s'",
384 return 0;
386 p = endp;
387 if (n < 0 || n == 0x5E || n > 0xFF) {
388 option_error("can't escape character 0x%x", n);
389 ret = 0;
390 } else
391 xmit_accm[0][n >> 5] |= 1 << (n & 0x1F);
392 while (*p == ',' || *p == ' ')
393 ++p;
395 return ret;
399 * setasyncmap - set async map negotiated
401 /*ARGSUSED*/
402 static int
403 setasyncmap(argv, opt)
404 char **argv;
405 option_t *opt;
407 u_int32_t val;
408 char *endp;
410 val = strtoul(*argv, &endp, 16);
411 if (*argv == endp) {
412 option_error("invalid numeric parameter '%s' for 'asyncmap' option",
413 *argv);
414 return 0;
416 lcp_wantoptions[0].asyncmap |= val;
417 lcp_wantoptions[0].neg_asyncmap = (~lcp_wantoptions[0].asyncmap != 0);
418 do_msft_workaround = 0;
419 return 1;
422 /*ARGSUSED*/
423 static int
424 setendpoint(argv, opt)
425 char **argv;
426 option_t *opt;
428 if (str_to_epdisc(&lcp_wantoptions[0].endpoint, *argv)) {
429 lcp_wantoptions[0].neg_endpoint = 1;
430 return 1;
432 option_error("Can't parse '%s' as an endpoint discriminator", *argv);
433 return 0;
436 #ifdef NEGOTIATE_FCS
437 static int
438 str_to_fcstype(opt,arg)
439 lcp_options *opt;
440 char *arg;
442 char **cpp, *cp;
443 int val, len;
445 if (*arg != '\0') {
446 val = 0;
447 while (*arg != '\0') {
448 len = 0;
449 if (isdigit(*arg)) {
450 len = strtol(arg, &cp, 0);
451 if (len < 0 || len > 255 || arg == cp ||
452 (*cp != '\0' && *cp != ','))
453 break;
454 val |= len;
455 len = cp - arg;
456 } else {
457 for (cpp = fcsalt_strings; *cpp != NULL; cpp++) {
458 len = strlen(*cpp);
459 if (strncasecmp(arg, *cpp, len) == 0 &&
460 (arg[len] == '\0' || arg[len] == ','))
461 break;
463 if (*cpp == NULL)
464 break;
465 val |= 1<<(cpp-fcsalt_strings);
467 if (arg[len] == '\0') {
468 opt->neg_fcs = 1;
469 opt->fcs_type = val;
470 return (1);
472 arg += len+1;
475 option_error("Can't parse '%s' as an FCS type", arg);
476 return (0);
479 /*ARGSUSED*/
480 static int
481 setfcsallow(argv, opt)
482 char **argv;
483 option_t *opt;
485 return str_to_fcstype(&lcp_allowoptions[0], *argv);
488 /*ARGSUSED*/
489 static int
490 setfcswant(argv, opt)
491 char **argv;
492 option_t *opt;
494 return str_to_fcstype(&lcp_wantoptions[0], *argv);
496 #endif
499 * lcp_init - Initialize LCP.
501 static void
502 lcp_init(unit)
503 int unit;
505 fsm *f = &lcp_fsm[unit];
506 lcp_options *wo = &lcp_wantoptions[unit];
507 lcp_options *ao = &lcp_allowoptions[unit];
509 f->unit = unit;
510 f->protocol = PPP_LCP;
511 f->callbacks = &lcp_callbacks;
513 fsm_init(f);
515 BZERO(wo, sizeof(*wo));
516 wo->neg_mru = 1;
517 wo->mru = PPP_MRU;
518 wo->neg_asyncmap = 1;
519 wo->chap_mdtype = CHAP_DIGEST_MD5;
520 wo->neg_magicnumber = 1;
521 wo->neg_pcompression = 1;
522 wo->neg_accompression = 1;
525 * Leave allowed MRU (MTU) at zero; configuration option sets it
526 * non-zero if we should nak for something else.
528 BZERO(ao, sizeof(*ao));
529 ao->neg_mru = 1;
530 ao->neg_asyncmap = 1;
531 ao->neg_chap = 1;
532 #if defined(CHAPMS) || defined(CHAPMSV2)
533 #ifdef SOL2
534 /* Check if DES wasn't exported */
535 errno = 0;
536 setkey("\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
537 "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0");
538 if (errno == 0)
539 #endif
541 #ifdef CHAPMS
542 ao->neg_mschap = 1;
543 #endif
544 #ifdef CHAPMSV2
545 ao->neg_mschapv2 = 1;
546 #endif
548 #endif
549 ao->chap_mdtype = CHAP_DIGEST_MD5;
550 ao->neg_upap = 1;
551 ao->neg_magicnumber = 1;
552 ao->neg_pcompression = 1;
553 ao->neg_accompression = 1;
554 #ifdef CBCP_SUPPORT
555 ao->neg_cbcp = 1;
556 #endif
557 ao->neg_endpoint = 1;
558 #ifdef NEGOTIATE_FCS
559 ao->neg_fcs = 1;
560 ao->fcs_type = FCSALT_NULL|FCSALT_16|FCSALT_32;
561 #endif
563 BZERO(xmit_accm[unit], sizeof(xmit_accm[0]));
564 xmit_accm[unit][3] = 0x60000000;
569 * lcp_open - LCP is allowed to come up.
571 void
572 lcp_open(unit)
573 int unit;
575 fsm *f = &lcp_fsm[unit];
576 lcp_options *wo = &lcp_wantoptions[unit];
578 f->flags = 0;
579 if (wo->passive)
580 f->flags |= OPT_PASSIVE;
581 if (wo->silent)
582 f->flags |= OPT_SILENT;
583 fsm_open(f);
588 * lcp_close - Take LCP down.
590 void
591 lcp_close(unit, reason)
592 int unit;
593 char *reason;
595 fsm *f = &lcp_fsm[unit];
597 if (phase != PHASE_DEAD)
598 new_phase(PHASE_TERMINATE);
599 if (f->state == STOPPED && (f->flags & (OPT_PASSIVE|OPT_SILENT))) {
601 * This action is not strictly according to the FSM in RFC1548,
602 * but it does mean that the program terminates if you do a
603 * lcp_close() in passive/silent mode when a connection hasn't
604 * been established.
606 f->state = CLOSED;
607 lcp_finished(f);
609 } else
610 fsm_close(&lcp_fsm[unit], reason);
615 * lcp_lowerup - The lower layer is up.
617 void
618 lcp_lowerup(unit)
619 int unit;
621 lcp_options *wo = &lcp_wantoptions[unit];
622 int mru, mtu;
624 mru = PPP_MRU > absmax_mru ? absmax_mru : PPP_MRU;
625 mtu = PPP_MTU > absmax_mtu ? absmax_mtu : PPP_MTU;
628 * Don't use A/C or protocol compression on transmission,
629 * but accept A/C and protocol compressed packets
630 * if we are going to ask for A/C and protocol compression.
632 ppp_set_xaccm(unit, xmit_accm[unit]);
633 ppp_send_config(unit, mtu, 0xffffffff, 0, 0);
634 ppp_recv_config(unit, mru, (lax_recv? 0: 0xffffffff),
635 wo->neg_pcompression, wo->neg_accompression);
636 #ifdef NEGOTIATE_FCS
637 ppp_send_fcs(unit, FCSALT_16);
638 ppp_recv_fcs(unit, FCSALT_16);
639 #endif
641 fsm_setpeermru(unit, mtu);
642 lcp_allowoptions[unit].asyncmap = xmit_accm[unit][0];
644 fsm_lowerup(&lcp_fsm[unit]);
649 * lcp_lowerdown - The lower layer is down.
651 void
652 lcp_lowerdown(unit)
653 int unit;
655 fsm_lowerdown(&lcp_fsm[unit]);
660 * lcp_input - Input LCP packet.
662 static void
663 lcp_input(unit, p, len)
664 int unit;
665 u_char *p;
666 int len;
668 fsm *f = &lcp_fsm[unit];
670 fsm_input(f, p, len);
675 * lcp_extcode - Handle a LCP-specific code.
677 static int
678 lcp_extcode(f, code, id, inp, len)
679 fsm *f;
680 int code, id;
681 u_char *inp;
682 int len;
684 u_char *magp;
686 switch( code ){
687 case CODE_PROTREJ:
688 lcp_rprotrej(f, inp, len);
689 break;
691 case CODE_ECHOREQ:
692 if (f->state != OPENED)
693 break;
694 magp = inp;
695 PUTLONG(lcp_gotoptions[f->unit].magicnumber, magp);
696 fsm_sdata(f, CODE_ECHOREP, id, inp, len);
697 break;
699 case CODE_ECHOREP:
700 if (!lcp_received_echo_reply(f, id, inp, len)) {
701 lcp_echo_badreplies++;
702 if (lcp_echo_badreplies > LCP_ECHO_MAX_BADREPLIES) {
703 LcpLinkFailure(f);
704 lcp_echos_pending = 0;
705 lcp_echo_badreplies = 0;
708 break;
710 case CODE_DISCREQ:
711 break;
713 case CODE_IDENT:
714 /* More than one 'noident' tells us to reject the code number. */
715 if (noident > 1)
716 return 0;
717 lcp_received_identification(f, id, inp, len);
718 break;
720 case CODE_TIMEREMAIN:
721 lcp_received_timeremain(f, id, inp, len);
722 break;
724 default:
725 return 0;
727 return 1;
731 * lcp_rprotrej - Receive an Protocol-Reject.
733 * Figure out which protocol is rejected and inform it.
735 static void
736 lcp_rprotrej(f, inp, len)
737 fsm *f;
738 u_char *inp;
739 int len;
741 int i;
742 struct protent *protp;
743 u_short prot;
745 if (len < 2) {
746 dbglog("lcp_rprotrej: Rcvd short Protocol-Reject packet!");
747 return;
750 GETSHORT(prot, inp);
753 * Protocol-Reject packets received in any state other than the LCP
754 * OPENED state SHOULD be silently discarded.
756 if( f->state != OPENED ){
757 dbglog("Protocol-Reject discarded: LCP in state %s",
758 fsm_state(f->state));
759 return;
763 * Upcall the proper Protocol-Reject routine.
765 for (i = 0; (protp = protocols[i]) != NULL; ++i)
766 if (protp->protocol == prot && protp->enabled_flag) {
767 (*protp->protrej)(f->unit);
768 return;
771 warn("Protocol-Reject for unsupported protocol 0x%x", prot);
776 * lcp_protrej - A Protocol-Reject was received.
778 /*ARGSUSED*/
779 static void
780 lcp_protrej(unit)
781 int unit;
784 * Can't reject LCP!
786 error("Received Protocol-Reject for LCP!");
790 * lcp_coderej - A Code-Reject was received.
792 /*ARGSUSED*/
793 static int
794 lcp_coderej(f, code, id, inp, len)
795 fsm *f;
796 int code;
797 int id;
798 u_char *inp;
799 int len;
801 /* The peer cannot reject these code numbers. */
802 if (code >= CODE_CONFREQ && code <= CODE_PROTREJ)
803 return 1;
804 switch (code) {
805 case CODE_ECHOREQ:
807 * If the peer rejects an Echo-Request, then stop doing that.
809 if (lcp_echo_timer_running != 0) {
810 UNTIMEOUT (LcpEchoTimeout, f);
811 lcp_echo_timer_running = 0;
812 lcp_echo_interval = 0;
814 break;
816 return 0;
820 * lcp_sprotrej - Send a Protocol-Reject for some protocol.
822 void
823 lcp_sprotrej(unit, p, len)
824 int unit;
825 u_char *p;
826 int len;
829 * Send back the protocol and the information field of the
830 * rejected packet. We only get here if LCP is in the OPENED state.
832 p += 2;
833 len -= 2;
835 fsm_sdata(&lcp_fsm[unit], CODE_PROTREJ, ++lcp_fsm[unit].id,
836 p, len);
841 * lcp_resetci - Reset our CI.
843 static void
844 lcp_resetci(f)
845 fsm *f;
847 lcp_options *wo = &lcp_wantoptions[f->unit];
848 lcp_options *go = &lcp_gotoptions[f->unit];
849 lcp_options *ao = &lcp_allowoptions[f->unit];
851 wo->magicnumber = magic();
852 wo->numloops = 0;
853 sentident = 0;
854 *go = *wo;
855 if (!multilink) {
856 go->neg_mrru = 0;
857 go->neg_ssnhf = 0;
859 if (noendpoint)
860 ao->neg_endpoint = 0;
861 if (go->mru > absmax_mru)
862 go->mru = absmax_mru;
863 if (ao->mru > absmax_mtu)
864 ao->mru = absmax_mtu;
865 unsolicit_mru = 1;
866 fsm_setpeermru(f->unit, PPP_MTU > absmax_mtu ? absmax_mtu : PPP_MTU);
867 auth_reset(f->unit);
872 * lcp_cilen - Return length of our CI.
874 static int
875 lcp_cilen(f)
876 fsm *f;
878 lcp_options *go = &lcp_gotoptions[f->unit];
880 #define LENCIVOID(neg) ((neg) ? CILEN_VOID : 0)
881 #define LENCICHAP(neg) ((neg) ? CILEN_CHAP : 0)
882 #define LENCICHAR(neg) ((neg) ? CILEN_CHAR : 0)
883 #define LENCISHORT(neg) ((neg) ? CILEN_SHORT : 0)
884 #define LENCILONG(neg) ((neg) ? CILEN_LONG : 0)
885 #define LENCILQR(neg) ((neg) ? CILEN_LQR: 0)
886 #define LENCICBCP(neg) ((neg) ? CILEN_CBCP: 0)
888 * NB: we only ask for one of CHAP and UPAP, even if we will
889 * accept either.
891 return (LENCISHORT(go->neg_mru && go->mru != PPP_MRU) +
892 LENCILONG(go->neg_asyncmap && go->asyncmap != 0xFFFFFFFF) +
893 LENCICHAP(go->neg_chap || go->neg_mschap || go->neg_mschapv2) +
894 LENCISHORT(!go->neg_chap && go->neg_upap && !go->neg_mschap &&
895 !go->neg_mschapv2) +
896 LENCILQR(go->neg_lqr) +
897 LENCICBCP(go->neg_cbcp) +
898 LENCILONG(go->neg_magicnumber) +
899 LENCIVOID(go->neg_pcompression) +
900 LENCIVOID(go->neg_accompression) +
901 LENCICHAR(go->neg_fcs) +
902 LENCISHORT(go->neg_mrru) +
903 LENCIVOID(go->neg_ssnhf) +
904 #ifdef MUX_FRAME
905 LENCIVOID(go->pppmux) +
906 #endif
907 (go->neg_endpoint? CILEN_CHAR + go->endpoint.length: 0));
912 * lcp_addci - Add our desired CIs to a packet.
914 static void
915 lcp_addci(f, ucp, lenp)
916 fsm *f;
917 u_char *ucp;
918 int *lenp;
920 lcp_options *go = &lcp_gotoptions[f->unit];
921 lcp_options *ho = &lcp_hisoptions[f->unit];
922 u_char *start_ucp = ucp;
924 #define ADDCIVOID(opt, neg) \
925 if (neg) { \
926 PUTCHAR(opt, ucp); \
927 PUTCHAR(CILEN_VOID, ucp); \
929 #define ADDCISHORT(opt, neg, val) \
930 if (neg) { \
931 PUTCHAR(opt, ucp); \
932 PUTCHAR(CILEN_SHORT, ucp); \
933 PUTSHORT(val, ucp); \
935 #define ADDCICHAP(opt, neg, val, digest) \
936 if (neg) { \
937 PUTCHAR(opt, ucp); \
938 PUTCHAR(CILEN_CHAP, ucp); \
939 PUTSHORT(val, ucp); \
940 PUTCHAR(digest, ucp); \
942 #define ADDCILONG(opt, neg, val) \
943 if (neg) { \
944 PUTCHAR(opt, ucp); \
945 PUTCHAR(CILEN_LONG, ucp); \
946 PUTLONG(val, ucp); \
948 #define ADDCILQR(opt, neg, val) \
949 if (neg) { \
950 PUTCHAR(opt, ucp); \
951 PUTCHAR(CILEN_LQR, ucp); \
952 PUTSHORT(PPP_LQR, ucp); \
953 PUTLONG(val, ucp); \
955 #define ADDCICHAR(opt, neg, val) \
956 if (neg) { \
957 PUTCHAR(opt, ucp); \
958 PUTCHAR(CILEN_CHAR, ucp); \
959 PUTCHAR(val, ucp); \
961 #define ADDCIENDP(opt, neg, class, val, len) \
962 if (neg) { \
963 int i; \
964 PUTCHAR(opt, ucp); \
965 PUTCHAR(CILEN_CHAR + len, ucp); \
966 PUTCHAR(class, ucp); \
967 for (i = 0; i < len; ++i) \
968 PUTCHAR(val[i], ucp); \
971 ADDCISHORT(CI_MRU, go->neg_mru && go->mru != PPP_MRU, go->mru);
972 ADDCILONG(CI_ASYNCMAP, go->neg_asyncmap && go->asyncmap != 0xFFFFFFFF,
973 go->asyncmap);
974 /* go->chap_mdtype always points to a useful value */
975 ADDCICHAP(CI_AUTHTYPE, go->neg_chap || go->neg_mschap || go->neg_mschapv2,
976 PPP_CHAP, go->chap_mdtype);
977 ADDCISHORT(CI_AUTHTYPE, !(go->neg_chap || go->neg_mschap ||
978 go->neg_mschapv2) && go->neg_upap, PPP_PAP);
979 /* We can't both say zero for LQR period. */
980 if (f->state == ACKSENT && go->neg_lqr && go->lqr_period == 0 &&
981 ho->neg_lqr && ho->lqr_period == 0)
982 go->lqr_period = 500;
983 ADDCILQR(CI_QUALITY, go->neg_lqr, go->lqr_period);
984 ADDCICHAR(CI_CALLBACK, go->neg_cbcp, CBOP_CBCP);
985 ADDCILONG(CI_MAGICNUMBER, go->neg_magicnumber, go->magicnumber);
986 ADDCIVOID(CI_PCOMPRESSION, go->neg_pcompression);
987 ADDCIVOID(CI_ACCOMPRESSION, go->neg_accompression);
988 ADDCICHAR(CI_FCSALTERN, (go->neg_fcs && go->fcs_type != 0), go->fcs_type);
989 ADDCIENDP(CI_EPDISC, go->neg_endpoint, go->endpoint.class,
990 go->endpoint.value, go->endpoint.length);
991 #ifdef MUX_FRAME
992 ADDCIVOID(CI_MUXING, go->pppmux);
993 #endif
994 ADDCISHORT(CI_MRRU, go->neg_mrru, go->mrru);
995 ADDCIVOID(CI_SSNHF, go->neg_ssnhf);
997 if (ucp - start_ucp != *lenp) {
998 /* this should never happen, because peer_mtu should be 1500 */
999 error("Bug in lcp_addci: wrong length");
1005 * lcp_ackci - Ack our CIs.
1006 * This should not modify any state if the Ack is bad.
1008 * Returns:
1009 * 0 - Ack was bad.
1010 * 1 - Ack was good.
1012 static int
1013 lcp_ackci(f, p, len)
1014 fsm *f;
1015 u_char *p;
1016 int len;
1018 lcp_options *go = &lcp_gotoptions[f->unit];
1019 #ifdef MUX_FRAME
1020 lcp_options *ao = &lcp_allowoptions[f->unit];
1021 #endif
1022 u_char cilen, citype, cichar;
1023 u_short cishort;
1024 u_int32_t cilong;
1027 * CIs must be in exactly the same order that we sent.
1028 * Check packet length and CI length at each step.
1029 * If we find any deviations, then this packet is bad.
1031 #define ACKCIVOID(opt, neg) \
1032 if (neg) { \
1033 if ((len -= CILEN_VOID) < 0) \
1034 goto bad; \
1035 GETCHAR(citype, p); \
1036 GETCHAR(cilen, p); \
1037 if (cilen != CILEN_VOID || \
1038 citype != opt) \
1039 goto bad; \
1041 #define ACKCISHORT(opt, neg, val) \
1042 if (neg) { \
1043 if ((len -= CILEN_SHORT) < 0) \
1044 goto bad; \
1045 GETCHAR(citype, p); \
1046 GETCHAR(cilen, p); \
1047 if (cilen != CILEN_SHORT || \
1048 citype != opt) \
1049 goto bad; \
1050 GETSHORT(cishort, p); \
1051 if (cishort != val) \
1052 goto bad; \
1054 #define ACKCIAUTH(opt, neg, val) \
1055 if (neg) { \
1056 if ((len -= CILEN_SHORT) < 0) \
1057 goto bad; \
1058 GETCHAR(citype, p); \
1059 GETCHAR(cilen, p); \
1060 if (cilen != CILEN_SHORT || \
1061 citype != opt) \
1062 goto bad; \
1063 GETSHORT(cishort, p); \
1064 if (cishort != val) \
1065 goto bad; \
1066 peer_nak_auth = 0; \
1067 peer_reject_auth = 0; \
1069 #define ACKCICHAR(opt, neg, val) \
1070 if (neg) { \
1071 if ((len -= CILEN_CHAR) < 0) \
1072 goto bad; \
1073 GETCHAR(citype, p); \
1074 GETCHAR(cilen, p); \
1075 if (cilen != CILEN_CHAR || \
1076 citype != opt) \
1077 goto bad; \
1078 GETCHAR(cichar, p); \
1079 if (cichar != val) \
1080 goto bad; \
1082 #define ACKCICHAP(opt, neg, val, digest) \
1083 if (neg) { \
1084 if ((len -= CILEN_CHAP) < 0) \
1085 goto bad; \
1086 GETCHAR(citype, p); \
1087 GETCHAR(cilen, p); \
1088 if (cilen != CILEN_CHAP || \
1089 citype != opt) \
1090 goto bad; \
1091 GETSHORT(cishort, p); \
1092 if (cishort != val) \
1093 goto bad; \
1094 GETCHAR(cichar, p); \
1095 if (cichar != digest) \
1096 goto bad; \
1097 peer_nak_auth = 0; \
1098 peer_reject_auth = 0; \
1100 #define ACKCILONG(opt, neg, val) \
1101 if (neg) { \
1102 if ((len -= CILEN_LONG) < 0) \
1103 goto bad; \
1104 GETCHAR(citype, p); \
1105 GETCHAR(cilen, p); \
1106 if (cilen != CILEN_LONG || \
1107 citype != opt) \
1108 goto bad; \
1109 GETLONG(cilong, p); \
1110 if (cilong != val) \
1111 goto bad; \
1113 #define ACKCILQR(opt, neg, val) \
1114 if (neg) { \
1115 if ((len -= CILEN_LQR) < 0) \
1116 goto bad; \
1117 GETCHAR(citype, p); \
1118 GETCHAR(cilen, p); \
1119 if (cilen != CILEN_LQR || \
1120 citype != opt) \
1121 goto bad; \
1122 GETSHORT(cishort, p); \
1123 if (cishort != PPP_LQR) \
1124 goto bad; \
1125 GETLONG(cilong, p); \
1126 if (cilong != val) \
1127 goto bad; \
1129 #define ACKCIENDP(opt, neg, class, val, vlen) \
1130 if (neg) { \
1131 int i; \
1132 if ((len -= CILEN_CHAR + vlen) < 0) \
1133 goto bad; \
1134 GETCHAR(citype, p); \
1135 GETCHAR(cilen, p); \
1136 if (cilen != CILEN_CHAR + vlen || \
1137 citype != opt) \
1138 goto bad; \
1139 GETCHAR(cichar, p); \
1140 if (cichar != class) \
1141 goto bad; \
1142 for (i = 0; i < vlen; ++i) { \
1143 GETCHAR(cichar, p); \
1144 if (cichar != val[i]) \
1145 goto bad; \
1149 ACKCISHORT(CI_MRU, go->neg_mru && go->mru != PPP_MRU, go->mru);
1150 ACKCILONG(CI_ASYNCMAP, go->neg_asyncmap && go->asyncmap != 0xFFFFFFFF,
1151 go->asyncmap);
1152 /* go->chap_mdtype always points to a useful value */
1153 ACKCICHAP(CI_AUTHTYPE, go->neg_chap || go->neg_mschap || go->neg_mschapv2,
1154 PPP_CHAP, go->chap_mdtype);
1155 ACKCIAUTH(CI_AUTHTYPE, !(go->neg_chap || go->neg_mschap ||
1156 go->neg_mschapv2) && go->neg_upap, PPP_PAP);
1157 ACKCILQR(CI_QUALITY, go->neg_lqr, go->lqr_period);
1158 ACKCICHAR(CI_CALLBACK, go->neg_cbcp, CBOP_CBCP);
1159 ACKCILONG(CI_MAGICNUMBER, go->neg_magicnumber, go->magicnumber);
1160 ACKCIVOID(CI_PCOMPRESSION, go->neg_pcompression);
1161 ACKCIVOID(CI_ACCOMPRESSION, go->neg_accompression);
1162 ACKCICHAR(CI_FCSALTERN, go->neg_fcs, go->fcs_type);
1163 ACKCIENDP(CI_EPDISC, go->neg_endpoint, go->endpoint.class,
1164 go->endpoint.value, go->endpoint.length);
1165 #ifdef MUX_FRAME
1166 ACKCIVOID(CI_MUXING, go->pppmux);
1167 if (go->pppmux)
1168 go->pppmux = ao->pppmux;
1169 #endif
1170 ACKCISHORT(CI_MRRU, go->neg_mrru, go->mrru);
1171 ACKCIVOID(CI_SSNHF, go->neg_ssnhf);
1174 * If there are any remaining CIs, then this packet is bad.
1176 if (len != 0)
1177 goto bad;
1178 return (1);
1179 bad:
1180 dbglog("lcp_acki: received bad Ack!");
1181 return (0);
1186 * lcp_nakci - Peer has sent a NAK for some of our CIs.
1187 * This should not modify any state if the Nak is bad
1188 * or if LCP is in the OPENED state.
1190 * Returns:
1191 * 0 - Nak was bad.
1192 * 1 - Nak was good.
1194 static int
1195 lcp_nakci(f, p, len)
1196 fsm *f;
1197 u_char *p;
1198 int len;
1200 lcp_options *go = &lcp_gotoptions[f->unit];
1201 lcp_options *wo = &lcp_wantoptions[f->unit];
1202 u_char citype, cichar, *next;
1203 u_short cishort;
1204 u_int32_t cilong;
1205 lcp_options no; /* options we've seen Naks for */
1206 lcp_options try; /* options to request next time */
1207 int looped_back = 0;
1208 int cilen;
1210 BZERO(&no, sizeof(no));
1211 try = *go;
1214 * Any Nak'd CIs must be in exactly the same order that we sent.
1215 * Check packet length and CI length at each step.
1216 * If we find any deviations, then this packet is bad.
1218 #define NAKCIVOID(opt, neg) \
1219 if (go->neg && \
1220 len >= CILEN_VOID && \
1221 p[1] == CILEN_VOID && \
1222 p[0] == opt) { \
1223 len -= CILEN_VOID; \
1224 INCPTR(CILEN_VOID, p); \
1225 no.neg = 1; \
1226 try.neg = 0; \
1228 #define NAKCICHAR(opt, neg, code) \
1229 if (go->neg && \
1230 len >= CILEN_CHAR && \
1231 p[1] == CILEN_CHAR && \
1232 p[0] == opt) { \
1233 len -= CILEN_CHAR; \
1234 INCPTR(2, p); \
1235 GETCHAR(cichar, p); \
1236 no.neg = 1; \
1237 code \
1239 #define NAKCISHORT(opt, neg, code) \
1240 if (go->neg && \
1241 len >= CILEN_SHORT && \
1242 p[1] == CILEN_SHORT && \
1243 p[0] == opt) { \
1244 len -= CILEN_SHORT; \
1245 INCPTR(2, p); \
1246 GETSHORT(cishort, p); \
1247 no.neg = 1; \
1248 code \
1250 #define NAKCILONG(opt, neg, code) \
1251 if (go->neg && \
1252 len >= CILEN_LONG && \
1253 p[1] == CILEN_LONG && \
1254 p[0] == opt) { \
1255 len -= CILEN_LONG; \
1256 INCPTR(2, p); \
1257 GETLONG(cilong, p); \
1258 no.neg = 1; \
1259 code \
1261 #define NAKCILQR(opt, neg, code) \
1262 if (go->neg && \
1263 len >= CILEN_LQR && \
1264 p[1] == CILEN_LQR && \
1265 p[0] == opt) { \
1266 len -= CILEN_LQR; \
1267 INCPTR(2, p); \
1268 GETSHORT(cishort, p); \
1269 GETLONG(cilong, p); \
1270 no.neg = 1; \
1271 code \
1273 #define NAKCIENDP(opt, neg) \
1274 if (go->neg && \
1275 len >= CILEN_CHAR && \
1276 p[0] == opt && \
1277 p[1] >= CILEN_CHAR && \
1278 p[1] <= len) { \
1279 len -= p[1]; \
1280 INCPTR(p[1], p); \
1281 no.neg = 1; \
1282 try.neg = 0; \
1286 * We don't care if they want to send us smaller packets than
1287 * we want. Therefore, accept any MRU less than what we asked for,
1288 * but then ignore the new value when setting the MRU in the kernel.
1289 * If they send us a bigger MRU than what we asked, accept it, up to
1290 * the limit of the default MRU we'd get if we didn't negotiate.
1292 if (go->neg_mru && go->mru != PPP_MRU) {
1293 NAKCISHORT(CI_MRU, neg_mru,
1294 if (cishort <= wo->mru ||
1295 (cishort <= PPP_MRU && cishort <= absmax_mru))
1296 try.mru = cishort;
1301 * Add any characters they want to our (receive-side) asyncmap.
1303 if (go->neg_asyncmap && go->asyncmap != 0xFFFFFFFF) {
1304 NAKCILONG(CI_ASYNCMAP, neg_asyncmap,
1305 try.asyncmap = go->asyncmap | cilong;
1310 * If they've nak'd our authentication-protocol, check whether
1311 * they are proposing a different protocol, or a different
1312 * hash algorithm for CHAP.
1314 if ((go->neg_chap || go->neg_mschap || go->neg_mschapv2 || go->neg_upap) &&
1315 len >= CILEN_SHORT && p[0] == CI_AUTHTYPE && p[1] >= CILEN_SHORT &&
1316 p[1] <= len) {
1317 cilen = p[1];
1318 len -= cilen;
1319 INCPTR(2, p);
1320 GETSHORT(cishort, p);
1321 peer_nak_auth = 1;
1322 nak_auth_orig = (go->neg_chap || go->neg_mschap || go->neg_mschapv2) ?
1323 PPP_CHAP : PPP_PAP;
1324 nak_auth_proto = cishort;
1325 if (cishort == PPP_PAP && cilen == CILEN_SHORT) {
1326 no.neg_upap = go->neg_upap;
1328 * If we were asking for CHAP, they obviously don't want to do it.
1329 * If we weren't asking for CHAP, then we were asking for PAP,
1330 * in which case this Nak is bad.
1332 if (!go->neg_chap && !go->neg_mschap && !go->neg_mschapv2)
1333 goto bad;
1334 try.neg_chap = 0;
1335 try.neg_mschap = 0;
1336 try.neg_mschapv2 = 0;
1338 } else if (cishort == PPP_CHAP && cilen >= CILEN_CHAP) {
1339 /* stop asking for that type */
1340 switch (go->chap_mdtype) {
1341 case CHAP_DIGEST_MD5:
1342 no.neg_chap = go->neg_chap;
1343 try.neg_chap = 0;
1344 break;
1345 case CHAP_MICROSOFT:
1346 no.neg_mschap = go->neg_mschap;
1347 try.neg_mschap = 0;
1348 break;
1349 case CHAP_MICROSOFT_V2:
1350 no.neg_mschapv2 = go->neg_mschapv2;
1351 try.neg_mschapv2 = 0;
1352 break;
1354 GETCHAR(cichar, p);
1355 /* Allow >= on length here for broken and silly peers. */
1356 p += cilen - CILEN_CHAP;
1357 try.neg_upap = 0;
1358 if ((cichar == CHAP_DIGEST_MD5 && wo->neg_chap) ||
1359 (cichar == CHAP_MICROSOFT && wo->neg_mschap) ||
1360 (cichar == CHAP_MICROSOFT_V2 && wo->neg_mschapv2)) {
1361 /* Try its requested algorithm. */
1362 try.chap_mdtype = cichar;
1363 } else {
1364 goto try_another;
1367 } else {
1369 * We don't recognize what they're suggesting.
1370 * Stop asking for what we were asking for.
1372 try_another:
1373 if (go->neg_chap || go->neg_mschap || go->neg_mschapv2) {
1374 switch (go->chap_mdtype) {
1375 case CHAP_DIGEST_MD5:
1376 try.neg_chap = 0;
1377 if (wo->neg_mschap) {
1378 try.chap_mdtype = CHAP_MICROSOFT;
1379 break;
1381 /*FALLTHROUGH*/
1382 case CHAP_MICROSOFT:
1383 try.neg_mschap = 0;
1384 if (wo->neg_mschapv2) {
1385 try.chap_mdtype = CHAP_MICROSOFT_V2;
1386 break;
1388 /*FALLTHROUGH*/
1389 case CHAP_MICROSOFT_V2:
1390 try.neg_mschapv2 = 0;
1391 break;
1393 } else
1394 try.neg_upap = 0;
1395 p += cilen - CILEN_SHORT;
1400 * If they can't cope with our link quality protocol, we'll have
1401 * to stop asking for LQR. We haven't got any other protocol. If
1402 * they Nak the reporting period, then the following logic
1403 * applies:
1404 * If it suggests zero and go->neg_fcs is true and
1405 * ao->lqr_period isn't zero, then take its suggestion. If it
1406 * suggests zero otherwise, ignore it. If it suggests a nonzero
1407 * value and wo->lqr_period is zero, then take its suggestion. If
1408 * it suggests a nonzero value otherwise that's less than
1409 * wo->lqr_period, then ignore it.
1411 NAKCILQR(CI_QUALITY, neg_lqr,
1412 if (cishort != PPP_LQR)
1413 try.neg_lqr = 0;
1414 else if (cilong == 0 && go->neg_fcs && wo->lqr_period != 0)
1415 try.lqr_period = cilong;
1416 else if (cilong != 0 &&
1417 (wo->lqr_period == 0 || cilong > wo->lqr_period))
1418 try.lqr_period = cilong;
1422 * Only implementing CBCP...not the rest of the callback options
1424 NAKCICHAR(CI_CALLBACK, neg_cbcp,
1425 try.neg_cbcp = 0;
1429 * Check for a looped-back line.
1431 NAKCILONG(CI_MAGICNUMBER, neg_magicnumber,
1432 try.magicnumber = magic();
1433 looped_back = 1;
1437 * Peer shouldn't send Nak for protocol compression or
1438 * address/control compression requests; they should send
1439 * a Reject instead. If they send a Nak, treat it as a Reject.
1441 NAKCIVOID(CI_PCOMPRESSION, neg_pcompression);
1442 NAKCIVOID(CI_ACCOMPRESSION, neg_accompression);
1445 * Remove any FCS types it doesn't like from our (receive-side)
1446 * FCS list.
1448 NAKCICHAR(CI_FCSALTERN, neg_fcs, try.fcs_type = go->fcs_type & cichar;);
1450 #ifdef MUX_FRAME
1451 /* Nacked MUX option */
1452 NAKCIVOID(CI_MUXING, pppmux);
1453 #endif
1456 * Nak of the endpoint discriminator option is not permitted,
1457 * treat it like a reject.
1459 NAKCIENDP(CI_EPDISC, neg_endpoint);
1462 * Nak for MRRU option - accept their value if it is smaller
1463 * than the one we want.
1465 if (go->neg_mrru) {
1466 NAKCISHORT(CI_MRRU, neg_mrru,
1467 if (cishort <= wo->mrru)
1468 try.mrru = cishort;
1473 * Nak for short sequence numbers shouldn't be sent, treat it
1474 * like a reject.
1476 NAKCIVOID(CI_SSNHF, neg_ssnhf);
1479 * There may be remaining CIs, if the peer is requesting negotiation
1480 * on an option that we didn't include in our request packet.
1481 * If we see an option that we requested, or one we've already seen
1482 * in this packet, then this packet is bad.
1483 * If we wanted to respond by starting to negotiate on the requested
1484 * option(s), we could, but we don't, because except for the
1485 * authentication type and quality protocol, if we are not negotiating
1486 * an option, it is because we were told not to.
1487 * For the authentication type, the Nak from the peer means
1488 * `let me authenticate myself with you' which is a bit pointless.
1489 * For the quality protocol, the Nak means `ask me to send you quality
1490 * reports', but if we didn't ask for them, we don't want them.
1491 * An option we don't recognize represents the peer asking to
1492 * negotiate some option we don't support, so ignore it.
1494 while (len > CILEN_VOID) {
1495 GETCHAR(citype, p);
1496 GETCHAR(cilen, p);
1497 if (cilen < CILEN_VOID || (len -= cilen) < 0)
1498 goto bad;
1499 next = p + cilen - 2;
1501 switch (citype) {
1502 case CI_MRU:
1503 if ((go->neg_mru && go->mru != PPP_MRU)
1504 || no.neg_mru || cilen != CILEN_SHORT)
1505 goto bad;
1506 GETSHORT(cishort, p);
1507 if (cishort < PPP_MRU && cishort < absmax_mru) {
1508 try.neg_mru = 1;
1509 try.mru = cishort;
1510 notice("Peer sent unsolicited Nak for MRU less than default.");
1512 break;
1513 case CI_ASYNCMAP:
1514 if ((go->neg_asyncmap && go->asyncmap != 0xFFFFFFFF)
1515 || no.neg_asyncmap || cilen != CILEN_LONG)
1516 goto bad;
1517 break;
1518 case CI_AUTHTYPE:
1519 unsolicited_nak_auth = 1;
1520 if (cilen >= CILEN_SHORT) {
1521 GETSHORT(unsolicit_auth_proto, p);
1522 } else {
1523 unsolicit_auth_proto = 0;
1525 if (go->neg_chap || no.neg_chap ||
1526 go->neg_mschap || no.neg_mschap ||
1527 go->neg_mschapv2 || no.neg_mschapv2 ||
1528 go->neg_upap || no.neg_upap)
1529 goto bad;
1530 break;
1531 case CI_MAGICNUMBER:
1532 if (go->neg_magicnumber || no.neg_magicnumber ||
1533 cilen != CILEN_LONG)
1534 goto bad;
1535 break;
1536 case CI_PCOMPRESSION:
1537 if (go->neg_pcompression || no.neg_pcompression
1538 || cilen != CILEN_VOID)
1539 goto bad;
1540 break;
1541 case CI_ACCOMPRESSION:
1542 if (go->neg_accompression || no.neg_accompression
1543 || cilen != CILEN_VOID)
1544 goto bad;
1545 break;
1546 case CI_QUALITY:
1547 if (go->neg_lqr || no.neg_lqr || cilen != CILEN_LQR)
1548 goto bad;
1549 break;
1550 case CI_MRRU:
1551 if (go->neg_mrru || no.neg_mrru || cilen != CILEN_SHORT)
1552 goto bad;
1553 break;
1554 case CI_SSNHF:
1555 if (go->neg_ssnhf || no.neg_ssnhf || cilen != CILEN_VOID)
1556 goto bad;
1557 try.neg_ssnhf = 1;
1558 break;
1559 case CI_EPDISC:
1560 if (go->neg_endpoint || no.neg_endpoint || cilen < CILEN_CHAR)
1561 goto bad;
1562 break;
1563 case CI_FCSALTERN:
1564 if (go->neg_fcs || no.neg_fcs || cilen < CILEN_CHAR)
1565 goto bad;
1566 break;
1567 #ifdef MUX_FRAME
1568 case CI_MUXING:
1569 if (go->pppmux || no.pppmux || cilen < CILEN_VOID)
1570 goto bad;
1571 break;
1572 #endif
1574 p = next;
1578 * OK, the Nak is good. Now we can update state.
1579 * If there are any options left we ignore them.
1581 if (f->state != OPENED) {
1583 * Note: the code once reset try.numloops to zero here if
1584 * looped_back wasn't set. This is wrong because a mixture of
1585 * looped-back and peer data (possible if half-duplex is used)
1586 * will allow the link to come up, and it shouldn't.
1588 if (looped_back) {
1589 if (++try.numloops >= lcp_loopbackfail) {
1590 notice("Serial line is looped back.");
1591 lcp_close(f->unit, "Loopback detected");
1592 status = EXIT_LOOPBACK;
1595 *go = try;
1598 return 1;
1600 bad:
1601 dbglog("lcp_nakci: received bad Nak!");
1602 return 0;
1607 * lcp_rejci - Peer has Rejected some of our CIs.
1608 * This should not modify any state if the Reject is bad
1609 * or if LCP is in the OPENED state.
1611 * Returns:
1612 * 0 - Reject was bad.
1613 * 1 - Reject was good.
1615 static int
1616 lcp_rejci(f, p, len)
1617 fsm *f;
1618 u_char *p;
1619 int len;
1621 lcp_options *go = &lcp_gotoptions[f->unit];
1622 u_char cichar;
1623 u_short cishort;
1624 u_int32_t cilong;
1625 lcp_options try; /* options to request next time */
1627 try = *go;
1630 * Any Rejected CIs must be in exactly the same order that we sent.
1631 * Check packet length and CI length at each step.
1632 * If we find any deviations, then this packet is bad.
1634 #define REJCIVOID(opt, neg) \
1635 if (go->neg && \
1636 len >= CILEN_VOID && \
1637 p[1] == CILEN_VOID && \
1638 p[0] == opt) { \
1639 len -= CILEN_VOID; \
1640 INCPTR(CILEN_VOID, p); \
1641 try.neg = 0; \
1643 #define REJCICHAR(opt, neg, val) \
1644 if (go->neg && \
1645 len >= CILEN_CHAR && \
1646 p[1] == CILEN_CHAR && \
1647 p[0] == opt) { \
1648 len -= CILEN_CHAR; \
1649 INCPTR(2, p); \
1650 GETCHAR(cichar, p); \
1651 /* Check rejected value. */ \
1652 if (cichar != val) \
1653 goto bad; \
1654 try.neg = 0; \
1656 #define REJCISHORT(opt, neg, val) \
1657 if (go->neg && \
1658 len >= CILEN_SHORT && \
1659 p[1] == CILEN_SHORT && \
1660 p[0] == opt) { \
1661 len -= CILEN_SHORT; \
1662 INCPTR(2, p); \
1663 GETSHORT(cishort, p); \
1664 /* Check rejected value. */ \
1665 if (cishort != val) \
1666 goto bad; \
1667 try.neg = 0; \
1669 #define REJCIAUTH(opt, neg, val) \
1670 if (go->neg && \
1671 len >= CILEN_SHORT && \
1672 p[1] == CILEN_SHORT && \
1673 p[0] == opt) { \
1674 len -= CILEN_SHORT; \
1675 INCPTR(2, p); \
1676 GETSHORT(cishort, p); \
1677 /* Check rejected value. */ \
1678 peer_reject_auth = 1; \
1679 reject_auth_proto = cishort; \
1680 if (cishort != val) \
1681 goto bad; \
1682 try.neg = 0; \
1684 #define REJCILONG(opt, neg, val) \
1685 if (go->neg && \
1686 len >= CILEN_LONG && \
1687 p[1] == CILEN_LONG && \
1688 p[0] == opt) { \
1689 len -= CILEN_LONG; \
1690 INCPTR(2, p); \
1691 GETLONG(cilong, p); \
1692 /* Check rejected value. */ \
1693 if (cilong != val) \
1694 goto bad; \
1695 try.neg = 0; \
1697 #define REJCILQR(opt, neg, val) \
1698 if (go->neg && \
1699 len >= CILEN_LQR && \
1700 p[1] == CILEN_LQR && \
1701 p[0] == opt) { \
1702 len -= CILEN_LQR; \
1703 INCPTR(2, p); \
1704 GETSHORT(cishort, p); \
1705 GETLONG(cilong, p); \
1706 /* Check rejected value. */ \
1707 if (cishort != PPP_LQR || cilong != val) \
1708 goto bad; \
1709 try.neg = 0; \
1711 #define REJCICBCP(opt, neg, val) \
1712 if (go->neg && \
1713 len >= CILEN_CBCP && \
1714 p[1] == CILEN_CBCP && \
1715 p[0] == opt) { \
1716 len -= CILEN_CBCP; \
1717 INCPTR(2, p); \
1718 GETCHAR(cichar, p); \
1719 /* Check rejected value. */ \
1720 if (cichar != val) \
1721 goto bad; \
1722 try.neg = 0; \
1724 #define REJCIENDP(opt, neg, class, val, vlen) \
1725 if (go->neg && \
1726 len >= CILEN_CHAR + vlen && \
1727 p[0] == opt && \
1728 p[1] == CILEN_CHAR + vlen) { \
1729 int i; \
1730 len -= CILEN_CHAR + vlen; \
1731 INCPTR(2, p); \
1732 GETCHAR(cichar, p); \
1733 if (cichar != class) \
1734 goto bad; \
1735 for (i = 0; i < vlen; ++i) { \
1736 GETCHAR(cichar, p); \
1737 if (cichar != val[i]) \
1738 goto bad; \
1740 try.neg = 0; \
1743 /* Received a Configure-Reject, try to send Identification now. */
1744 if (!noident && sentident < 3) {
1745 LcpSendIdentification(f);
1746 sentident++;
1749 REJCISHORT(CI_MRU, neg_mru, go->mru);
1750 REJCILONG(CI_ASYNCMAP, neg_asyncmap, go->asyncmap);
1753 * There are broken peers (such as unbundled Solaris PPP) that
1754 * send Configure-Reject for authentication when they really
1755 * intend Configure-Nak. This code works around this problem.
1757 if ((go->neg_chap || go->neg_mschap || go->neg_mschapv2) &&
1758 len >= CILEN_CHAP && p[1] == CILEN_CHAP && p[0] == CI_AUTHTYPE) {
1759 len -= CILEN_CHAP;
1760 INCPTR(2, p);
1761 GETSHORT(cishort, p);
1762 GETCHAR(cichar, p);
1763 peer_reject_auth = 1;
1764 reject_auth_proto = cishort;
1765 /* Check rejected value. */
1766 if (cishort != PPP_CHAP || cichar != go->chap_mdtype)
1767 goto bad;
1768 /* Disable the one that it rejected */
1769 switch (cichar) {
1770 case CHAP_DIGEST_MD5:
1771 try.neg_chap = 0;
1772 break;
1773 case CHAP_MICROSOFT:
1774 try.neg_mschap = 0;
1775 break;
1776 case CHAP_MICROSOFT_V2:
1777 try.neg_mschapv2 = 0;
1778 break;
1780 /* Try another, if we can. */
1781 if (try.neg_chap)
1782 try.chap_mdtype = CHAP_DIGEST_MD5;
1783 else if (try.neg_mschap)
1784 try.chap_mdtype = CHAP_MICROSOFT;
1785 else
1786 try.chap_mdtype = CHAP_MICROSOFT_V2;
1789 if (!go->neg_chap && !go->neg_mschap && !go->neg_mschapv2) {
1790 REJCIAUTH(CI_AUTHTYPE, neg_upap, PPP_PAP);
1792 REJCILQR(CI_QUALITY, neg_lqr, go->lqr_period);
1793 REJCICBCP(CI_CALLBACK, neg_cbcp, CBOP_CBCP);
1794 REJCILONG(CI_MAGICNUMBER, neg_magicnumber, go->magicnumber);
1795 REJCIVOID(CI_PCOMPRESSION, neg_pcompression);
1796 REJCIVOID(CI_ACCOMPRESSION, neg_accompression);
1797 REJCICHAR(CI_FCSALTERN, neg_fcs, go->fcs_type);
1798 #ifdef MUX_FRAME
1799 REJCIVOID(CI_MUXING,pppmux);
1800 #endif
1801 REJCIENDP(CI_EPDISC, neg_endpoint, go->endpoint.class,
1802 go->endpoint.value, go->endpoint.length);
1803 REJCISHORT(CI_MRRU, neg_mrru, go->mrru);
1804 REJCIVOID(CI_SSNHF, neg_ssnhf);
1807 * If there are any remaining CIs, then this packet is bad.
1809 if (len != 0)
1810 goto bad;
1812 * Now we can update state.
1814 if (f->state != OPENED)
1815 *go = try;
1816 return 1;
1818 bad:
1819 dbglog("lcp_rejci: received bad Reject!");
1820 return 0;
1825 * lcp_reqci - Check the peer's requested CIs and send appropriate response.
1827 * Returns: CODE_CONFACK, CODE_CONFNAK or CODE_CONFREJ and input
1828 * packet modified appropriately. If reject_if_disagree is non-zero,
1829 * doesn't return CODE_CONFNAK; returns CODE_CONFREJ if it can't
1830 * return CODE_CONFACK.
1832 static int
1833 lcp_reqci(f, p, lenp, dont_nak)
1834 fsm *f;
1835 u_char *p; /* Requested CIs */
1836 int *lenp; /* Length of requested CIs */
1837 int dont_nak;
1839 lcp_options *wo = &lcp_wantoptions[f->unit];
1840 lcp_options *go = &lcp_gotoptions[f->unit];
1841 lcp_options *ho = &lcp_hisoptions[f->unit];
1842 lcp_options *ao = &lcp_allowoptions[f->unit];
1843 int cilen, citype, cichar; /* Parsed len, type, char value */
1844 u_short cishort; /* Parsed short value */
1845 u_int32_t cilong; /* Parse long value */
1846 int ret, newret;
1847 u_char *p0, *nakp, *rejp, *prev;
1848 int len;
1851 * Loop through options once to find out if peer is offering
1852 * Multilink, and repair values as needed.
1854 ao->mru = ao->mrru;
1855 p0 = p;
1856 for (len = *lenp; len > 0; len -= cilen, p = prev + cilen) {
1857 if (len < 2 || p[1] > len) {
1859 * RFC 1661 page 40 -- if the option extends beyond the
1860 * packet, then discard the entire packet.
1862 dbglog("discarding LCP Configure-Request due to truncated option");
1863 return (0);
1865 prev = p;
1866 GETCHAR(citype, p);
1867 GETCHAR(cilen, p);
1868 if (citype == CI_MRRU) {
1869 if (ao->mrru != 0) {
1870 if (ao->mrru+6 > PPP_MTU)
1871 ao->mru = PPP_MTU;
1872 else
1873 ao->mru = ao->mrru + 6;
1876 if (cilen < 2)
1877 cilen = 2;
1879 if (ao->mru > absmax_mtu)
1880 ao->mru = absmax_mtu;
1882 ret = CODE_CONFACK;
1883 rejp = p = p0;
1884 nakp = nak_buffer;
1887 * Reset all its options.
1889 BZERO(ho, sizeof(*ho));
1892 * Process all its options.
1894 for (len = *lenp; len > 0; len -= cilen, p = prev + cilen) {
1895 newret = CODE_CONFACK; /* Assume success */
1897 prev = p;
1898 GETCHAR(citype, p);
1899 GETCHAR(cilen, p);
1901 switch (citype) { /* Check CI type */
1902 case CI_MRU:
1903 if (!ao->neg_mru) {
1904 newret = CODE_CONFREJ;
1905 break;
1908 if (cilen != CILEN_SHORT) { /* Check CI length */
1909 newret = CODE_CONFNAK;
1910 cishort = ao->mru;
1911 } else {
1912 /* extract the MRU from the option */
1913 GETSHORT(cishort, p);
1916 * If the offered MRU is less than our desired MTU, we
1917 * should nak. This is especially helpful if we're
1918 * doing demand-dial, since those queued up packets
1919 * might be discarded otherwise.
1921 if (cishort < ao->mru) {
1922 newret = CODE_CONFNAK;
1923 cishort = ao->mru;
1928 * If we're going to send a nak with something less than
1929 * or equal to the default PPP MTU, then just reject instead.
1931 if (newret == CODE_CONFNAK && cishort <= PPP_MTU)
1932 newret = CODE_CONFREJ;
1934 if (newret == CODE_CONFNAK) {
1935 PUTCHAR(CI_MRU, nakp);
1936 PUTCHAR(CILEN_SHORT, nakp);
1937 PUTSHORT(cishort, nakp); /* Give it a hint */
1940 ho->neg_mru = 1; /* Remember that it sent MRU */
1941 ho->mru = cishort; /* And remember value */
1942 break;
1944 case CI_ASYNCMAP:
1945 if (!ao->neg_asyncmap) {
1946 newret = CODE_CONFREJ;
1947 break;
1950 if (cilen != CILEN_LONG) {
1951 newret = CODE_CONFNAK;
1952 cilong = 0;
1953 } else {
1954 GETLONG(cilong, p);
1957 * Asyncmap must have set at least the bits
1958 * which are set in lcp_allowoptions[unit].asyncmap.
1960 if ((ao->asyncmap & ~cilong) != 0)
1961 newret = CODE_CONFNAK;
1965 * Workaround for common broken Microsoft software -- if
1966 * the peer is sending us a nonzero ACCM, then it *needs*
1967 * us to send the same to it. Adjust our Configure-
1968 * Request message and restart LCP.
1970 if (do_msft_workaround && (cilong & ~wo->asyncmap)) {
1971 dbglog("adjusted requested asyncmap from %X to %X",
1972 wo->asyncmap, wo->asyncmap | cilong);
1973 do_msft_workaround = 0;
1974 wo->neg_asyncmap = 1;
1975 wo->asyncmap |= cilong;
1976 f->flags &= ~OPT_SILENT;
1977 info("possibly broken peer detected; restarting LCP");
1978 fsm_lowerdown(f);
1979 fsm_lowerup(f);
1980 return (0);
1983 if (newret == CODE_CONFNAK) {
1984 PUTCHAR(CI_ASYNCMAP, nakp);
1985 PUTCHAR(CILEN_LONG, nakp);
1986 PUTLONG(ao->asyncmap | cilong, nakp);
1988 ho->neg_asyncmap = 1;
1989 ho->asyncmap = cilong;
1990 break;
1992 case CI_AUTHTYPE:
1993 if (!(ao->neg_upap || ao->neg_chap || ao->neg_mschap ||
1994 ao->neg_mschapv2)) {
1995 rejected_peers_auth = 1;
1996 if (cilen >= CILEN_SHORT) {
1997 GETSHORT(rejected_auth_proto, p);
1998 } else {
1999 rejected_auth_proto = 0;
2002 * Reject the option if we're not willing to authenticate.
2004 newret = CODE_CONFREJ;
2005 break;
2007 rejected_peers_auth = 0;
2008 naked_peers_auth = 0;
2010 if (cilen >= CILEN_SHORT) {
2011 /* Extract the authentication protocol from the option */
2012 GETSHORT(cishort, p);
2014 if (ho->neg_upap || ho->neg_chap || ho->neg_mschap ||
2015 ho->neg_mschapv2) {
2016 dbglog("Rejecting extra authentication protocol option");
2017 newret = CODE_CONFREJ;
2018 break;
2022 * Authtype must be PAP or CHAP.
2024 * Note: if both ao->neg_upap and ao->neg_*chap* are
2025 * set, and the peer sends a Configure-Request with
2026 * two authenticate-protocol requests, one for CHAP
2027 * and one for UPAP, then we will reject the second
2028 * request. Whether we end up doing CHAP or UPAP
2029 * depends then on the ordering of the CIs in the
2030 * peer's Configure-Request.
2032 * We're supposed to list all of the protocols we can
2033 * possibly use in the returned Configure-Nak. This
2034 * part of RFC 1661 (section 5.3) is in conflict with
2035 * the section that says the options shouldn't be
2036 * reordered, so it's often ignored.
2039 if (cishort == PPP_PAP) {
2040 if (ao->neg_upap) {
2041 if (cilen != CILEN_SHORT)
2042 goto try_pap_anyway;
2043 ho->neg_upap = 1;
2044 break;
2046 } else if (cishort == PPP_CHAP) {
2047 /* Test >= here to allow for broken peers. */
2048 if (cilen >= CILEN_CHAP &&
2049 (ao->neg_chap || ao->neg_mschap || ao->neg_mschapv2)) {
2050 GETCHAR(cichar, p);
2051 if (cichar == CHAP_DIGEST_MD5 && ao->neg_chap)
2052 ho->neg_chap = 1;
2053 else if (cichar == CHAP_MICROSOFT && ao->neg_mschap)
2054 ho->neg_mschap = 1;
2055 else if (cichar == CHAP_MICROSOFT_V2 &&
2056 ao->neg_mschapv2)
2057 ho->neg_mschap = 1;
2058 if (ho->neg_chap || ho->neg_mschap ||
2059 ho->neg_mschapv2) {
2060 ho->chap_mdtype = cichar; /* save md type */
2061 break;
2068 * We don't recognize the protocol they're asking for.
2069 * Nak it with something we're willing to do.
2070 * (At this point we know ao->neg_upap || ao->neg_chap.)
2072 PUTCHAR(CI_AUTHTYPE, nakp);
2073 if (ao->neg_chap || ao->neg_mschap || ao->neg_mschapv2) {
2074 PUTCHAR(CILEN_CHAP, nakp);
2075 PUTSHORT(PPP_CHAP, nakp);
2076 PUTCHAR(ao->chap_mdtype, nakp);
2077 naked_auth_proto = PPP_CHAP;
2078 } else {
2079 try_pap_anyway:
2080 PUTCHAR(CILEN_SHORT, nakp);
2081 PUTSHORT(PPP_PAP, nakp);
2082 naked_auth_proto = PPP_PAP;
2084 naked_peers_auth = 1;
2085 naked_auth_orig = cishort;
2086 newret = CODE_CONFNAK;
2087 break;
2089 case CI_QUALITY:
2090 if (!ao->neg_lqr) {
2091 newret = CODE_CONFREJ;
2092 break;
2095 if (cilen != CILEN_LQR) {
2096 newret = CODE_CONFNAK;
2097 cilong = ao->lqr_period;
2098 } else {
2100 GETSHORT(cishort, p);
2101 GETLONG(cilong, p);
2103 /* Check the LQM protocol */
2104 if (cishort != PPP_LQR) {
2105 newret = CODE_CONFNAK;
2108 /* Check the reporting period; we can't both send zero */
2109 if ((cilong == 0 && go->lqr_period == 0) ||
2110 cilong < ao->lqr_period) {
2111 newret = CODE_CONFNAK;
2112 if ((cilong = ao->lqr_period) == 0)
2113 cilong = 500;
2117 if (newret == CODE_CONFNAK) {
2118 PUTCHAR(CI_QUALITY, nakp);
2119 PUTCHAR(CILEN_LQR, nakp);
2120 PUTSHORT(PPP_LQR, nakp);
2121 PUTLONG(cilong, nakp);
2124 ho->neg_lqr = 1;
2125 ho->lqr_period = cilong;
2126 break;
2128 case CI_MAGICNUMBER:
2129 if (!(ao->neg_magicnumber || go->neg_magicnumber)) {
2130 newret = CODE_CONFREJ;
2131 break;
2134 ho->neg_magicnumber = 1;
2135 if (cilen < CILEN_LONG) {
2137 * If we send Magic-Number, then we must not reject it
2138 * when the peer sends it to us, even if its version
2139 * looks odd to us. Ack if the cilent is wrong in this
2140 * case. If we're not sending Magic-Number, then we don't
2141 * much care what its value is anyway.
2143 break;
2146 GETLONG(cilong, p);
2147 ho->magicnumber = cilong;
2148 if (cilen > CILEN_LONG)
2149 break;
2152 * It must have a different magic number. Make sure we
2153 * give it a good one to use.
2155 while (go->neg_magicnumber && cilong == go->magicnumber) {
2156 newret = CODE_CONFNAK;
2157 cilong = magic();
2160 if (newret == CODE_CONFNAK) {
2161 PUTCHAR(CI_MAGICNUMBER, nakp);
2162 PUTCHAR(CILEN_LONG, nakp);
2163 PUTLONG(cilong, nakp);
2165 * We don't need to bump the numloops counter here
2166 * since it's already done upon reception of a nak.
2169 break;
2171 case CI_PCOMPRESSION:
2172 if (!ao->neg_pcompression) {
2173 newret = CODE_CONFREJ;
2174 break;
2176 if (cilen != CILEN_VOID) {
2177 newret = CODE_CONFNAK;
2178 PUTCHAR(CI_PCOMPRESSION, nakp);
2179 PUTCHAR(CILEN_VOID, nakp);
2181 ho->neg_pcompression = 1;
2182 break;
2184 case CI_ACCOMPRESSION:
2185 if (!ao->neg_accompression) {
2186 newret = CODE_CONFREJ;
2187 break;
2189 if (cilen != CILEN_VOID) {
2190 newret = CODE_CONFNAK;
2191 PUTCHAR(CI_ACCOMPRESSION, nakp);
2192 PUTCHAR(CILEN_VOID, nakp);
2194 ho->neg_accompression = 1;
2195 break;
2197 case CI_FCSALTERN:
2198 if (!ao->neg_fcs) {
2199 newret = CODE_CONFREJ;
2200 break;
2203 if (cilen != CILEN_CHAR) {
2204 newret = CODE_CONFNAK;
2205 cichar = ao->fcs_type;
2206 } else {
2208 GETCHAR(cichar, p);
2209 /* If it has bits we don't like, tell it to stop. */
2210 if (cichar & ~ao->fcs_type) {
2211 if ((cichar &= ao->fcs_type) == 0) {
2212 newret = CODE_CONFREJ;
2213 break;
2215 newret = CODE_CONFNAK;
2218 if (newret == CODE_CONFNAK) {
2219 PUTCHAR(CI_FCSALTERN, nakp);
2220 PUTCHAR(CILEN_CHAR, nakp);
2221 PUTCHAR(cichar, nakp);
2223 ho->neg_fcs = 1;
2224 ho->fcs_type = cichar;
2225 break;
2227 case CI_MRRU:
2228 if (!ao->neg_mrru || !multilink) {
2229 newret = CODE_CONFREJ;
2230 break;
2232 if (cilen != CILEN_SHORT) {
2233 newret = CODE_CONFNAK;
2234 cishort = ao->mrru;
2235 } else {
2236 GETSHORT(cishort, p);
2237 if (cishort < ao->mrru) {
2238 newret = CODE_CONFNAK;
2239 cishort = ao->mrru;
2243 if (cishort < PPP_MINMTU) {
2244 newret = CODE_CONFNAK;
2245 cishort = PPP_MINMTU;
2248 if (newret == CODE_CONFNAK) {
2249 PUTCHAR(CI_MRRU, nakp);
2250 PUTCHAR(CILEN_SHORT, nakp);
2251 PUTSHORT(cishort, nakp);
2254 ho->neg_mrru = 1;
2255 ho->mrru = cishort;
2256 break;
2258 case CI_SSNHF:
2259 if (!ao->neg_ssnhf || !multilink) {
2260 newret = CODE_CONFREJ;
2261 break;
2263 if (cilen != CILEN_VOID) {
2264 newret = CODE_CONFNAK;
2265 PUTCHAR(CI_SSNHF, nakp);
2266 PUTCHAR(CILEN_VOID, nakp);
2268 ho->neg_ssnhf = 1;
2269 break;
2271 case CI_EPDISC:
2272 if (!ao->neg_endpoint) {
2273 newret = CODE_CONFREJ;
2274 break;
2276 if (cilen < CILEN_CHAR || cilen > CILEN_CHAR + MAX_ENDP_LEN) {
2277 int i;
2279 newret = CODE_CONFNAK;
2280 PUTCHAR(CI_EPDISC, nakp);
2281 PUTCHAR(CILEN_CHAR + ao->endpoint.length, nakp);
2282 PUTCHAR(ao->endpoint.class, nakp);
2283 for (i = 0; i < ao->endpoint.length; i++)
2284 PUTCHAR(ao->endpoint.value[i], nakp);
2285 break;
2287 GETCHAR(cichar, p);
2288 ho->neg_endpoint = 1;
2289 ho->endpoint.class = cichar;
2290 ho->endpoint.length = cilen - 3;
2291 BCOPY(p, ho->endpoint.value, cilen - 3);
2292 break;
2294 #ifdef MUX_FRAME
2295 case CI_MUXING:
2296 if (ao->pppmux == 0 || cilen != CILEN_VOID) {
2297 newret = CODE_CONFREJ;
2298 break;
2300 /* remember its option */
2301 ho->pppmux = ao->pppmux;
2302 break;
2303 #endif
2305 default:
2306 dbglog("LCP: rejecting unknown option %d", citype);
2307 newret = CODE_CONFREJ;
2308 break;
2311 /* Cope with confused peers. */
2312 if (cilen < 2)
2313 cilen = 2;
2316 * If this is an Ack'able CI, but we're sending back a Nak,
2317 * don't include this CI.
2319 if (newret == CODE_CONFACK && ret != CODE_CONFACK)
2320 continue;
2322 if (newret == CODE_CONFNAK) {
2324 * Continue naking the Magic Number option until the cows come
2325 * home -- rejecting it is wrong.
2327 if (dont_nak && citype != CI_MAGICNUMBER) {
2328 newret = CODE_CONFREJ;
2329 } else {
2330 /* Ignore subsequent Nak'able things if rejecting. */
2331 if (ret == CODE_CONFREJ)
2332 continue;
2333 ret = CODE_CONFNAK;
2337 if (newret == CODE_CONFREJ) {
2338 ret = CODE_CONFREJ;
2339 if (prev != rejp)
2340 BCOPY(prev, rejp, cilen);
2341 rejp += cilen;
2346 * If the peer hasn't negotiated its MRU, and we'd like an MTU
2347 * that's larger than the default, try sending an unsolicited
2348 * Nak for what we want.
2350 if (ret != CODE_CONFREJ && !ho->neg_mru && ao->mru > PPP_MTU &&
2351 !dont_nak && unsolicit_mru) {
2352 unsolicit_mru = 0; /* don't ask again */
2353 ret = CODE_CONFNAK;
2354 PUTCHAR(CI_MRU, nakp);
2355 PUTCHAR(CILEN_SHORT, nakp);
2356 PUTSHORT(ao->mru, nakp);
2359 switch (ret) {
2360 case CODE_CONFACK:
2361 *lenp = p - p0;
2362 break;
2363 case CODE_CONFNAK:
2365 * Copy the Nak'd options from the nak_buffer to the caller's buffer.
2367 *lenp = nakp - nak_buffer;
2368 BCOPY(nak_buffer, p0, *lenp);
2369 break;
2370 case CODE_CONFREJ:
2371 *lenp = rejp - p0;
2373 /* We're about to send Configure-Reject; send Identification */
2374 if (!noident && sentident < 3) {
2375 LcpSendIdentification(f);
2376 sentident++;
2378 break;
2381 LCPDEBUG(("lcp_reqci: returning %s.", code_name(ret, 1)));
2382 return (ret); /* Return final code */
2387 * lcp_up - LCP has come UP.
2389 static void
2390 lcp_up(f)
2391 fsm *f;
2393 lcp_options *wo = &lcp_wantoptions[f->unit];
2394 lcp_options *ho = &lcp_hisoptions[f->unit];
2395 lcp_options *go = &lcp_gotoptions[f->unit];
2396 lcp_options *ao = &lcp_allowoptions[f->unit];
2397 int mru, mtu;
2399 if (!go->neg_magicnumber)
2400 go->magicnumber = 0;
2401 if (!ho->neg_magicnumber)
2402 ho->magicnumber = 0;
2405 * Set our MTU to the smaller of the MTU we wanted and
2406 * the MRU our peer wanted. If we negotiated an MRU,
2407 * set our MRU to the larger of value we wanted and
2408 * the value we got in the negotiation.
2410 if (ao->mru != 0 && ho->mru > ao->mru)
2411 ho->mru = ao->mru;
2412 mtu = (ho->neg_mru ? ho->mru: PPP_MRU);
2413 if (mtu > absmax_mtu)
2414 mtu = absmax_mtu;
2415 ppp_send_config(f->unit, mtu,
2416 (ho->neg_asyncmap? ho->asyncmap: 0xffffffff),
2417 ho->neg_pcompression, ho->neg_accompression);
2418 fsm_setpeermru(f->unit, mtu);
2419 mru = (go->neg_mru? MAX(wo->mru, go->mru): PPP_MRU);
2420 if (mru > absmax_mru)
2421 mru = absmax_mru;
2422 ppp_recv_config(f->unit, mru,
2423 (lax_recv? 0: go->neg_asyncmap? go->asyncmap: 0xffffffff),
2424 go->neg_pcompression, go->neg_accompression);
2425 #ifdef NEGOTIATE_FCS
2426 ppp_send_fcs(f->unit, ho->neg_fcs ? ho->fcs_type : FCSALT_16);
2427 ppp_recv_fcs(f->unit, go->neg_fcs ? go->fcs_type : FCSALT_16);
2428 #endif
2429 #ifdef MUX_FRAME
2430 ppp_send_muxoption(f->unit, ho->pppmux);
2431 ppp_recv_muxoption(f->unit, go->pppmux);
2432 #endif
2434 lcp_echo_lowerup(f->unit); /* Enable echo messages */
2436 /* LCP is Up; send Identification */
2437 if (!noident) {
2438 LcpSendIdentification(f);
2439 sentident++;
2442 link_established(f->unit);
2447 * lcp_down - LCP has gone DOWN.
2449 * Alert other protocols.
2451 static void
2452 lcp_down(f)
2453 fsm *f;
2455 int mtu;
2456 lcp_options *go = &lcp_gotoptions[f->unit];
2458 lcp_echo_lowerdown(f->unit);
2460 link_down(f->unit);
2462 mtu = PPP_MTU > absmax_mtu ? absmax_mtu : PPP_MTU;
2463 ppp_send_config(f->unit, mtu, 0xffffffff, 0, 0);
2464 ppp_recv_config(f->unit, (PPP_MRU > absmax_mru ? absmax_mru : PPP_MRU),
2465 (go->neg_asyncmap? go->asyncmap: 0xffffffff),
2466 go->neg_pcompression, go->neg_accompression);
2467 #ifdef NEGOTIATE_FCS
2468 ppp_send_fcs(f->unit, FCSALT_16);
2469 ppp_recv_fcs(f->unit, FCSALT_16);
2470 #endif
2471 fsm_setpeermru(f->unit, mtu);
2476 * lcp_starting - LCP needs the lower layer up.
2478 static void
2479 lcp_starting(f)
2480 fsm *f;
2482 link_required(f->unit);
2487 * lcp_finished - LCP has finished with the lower layer.
2489 static void
2490 lcp_finished(f)
2491 fsm *f;
2493 link_terminated(f->unit);
2498 * lcp_printpkt - print the contents of an LCP packet.
2501 static int
2502 lcp_printpkt(p, plen, printer, arg)
2503 u_char *p;
2504 int plen;
2505 void (*printer) __P((void *, const char *, ...));
2506 void *arg;
2508 int code, id, len, olen, i;
2509 u_char *pstart, *optend, cichar;
2510 u_short cishort;
2511 u_int32_t cilong;
2513 if (plen < HEADERLEN)
2514 return 0;
2515 pstart = p;
2516 GETCHAR(code, p);
2517 GETCHAR(id, p);
2518 GETSHORT(len, p);
2519 if (len < HEADERLEN || len > plen)
2520 return 0;
2522 printer(arg, " %s id=0x%x", code_name(code,1), id);
2523 len -= HEADERLEN;
2524 switch (code) {
2525 case CODE_CONFREQ:
2526 case CODE_CONFACK:
2527 case CODE_CONFNAK:
2528 case CODE_CONFREJ:
2529 /* print option list */
2530 while (len >= 2) {
2531 GETCHAR(code, p);
2532 GETCHAR(olen, p);
2533 p -= 2;
2534 if (olen < 2 || olen > len) {
2535 break;
2537 printer(arg, " <");
2538 len -= olen;
2539 optend = p + olen;
2540 switch (code) {
2541 case CI_MRU:
2542 if (olen >= CILEN_SHORT) {
2543 p += 2;
2544 GETSHORT(cishort, p);
2545 printer(arg, "mru %d", cishort);
2547 break;
2548 case CI_ASYNCMAP:
2549 if (olen >= CILEN_LONG) {
2550 p += 2;
2551 GETLONG(cilong, p);
2552 printer(arg, "asyncmap 0x%x", cilong);
2554 break;
2555 case CI_AUTHTYPE:
2556 if (olen >= CILEN_SHORT) {
2557 p += 2;
2558 printer(arg, "auth ");
2559 GETSHORT(cishort, p);
2560 switch (cishort) {
2561 case PPP_PAP:
2562 printer(arg, "pap");
2563 break;
2564 case PPP_CHAP:
2565 printer(arg, "chap");
2566 if (p < optend) {
2567 switch (*p) {
2568 case CHAP_DIGEST_MD5:
2569 printer(arg, " MD5");
2570 ++p;
2571 break;
2572 case CHAP_MICROSOFT:
2573 printer(arg, " m$oft");
2574 ++p;
2575 break;
2576 case CHAP_MICROSOFT_V2:
2577 printer(arg, " m$oft-v2");
2578 ++p;
2579 break;
2582 break;
2583 #ifdef PPP_EAP
2584 case PPP_EAP:
2585 printer(arg, "eap");
2586 break;
2587 #endif
2588 case 0xC027:
2589 printer(arg, "spap");
2590 break;
2591 case 0xC123:
2592 printer(arg, "old-spap");
2593 break;
2594 default:
2595 printer(arg, "0x%x", cishort);
2598 break;
2599 case CI_QUALITY:
2600 if (olen >= CILEN_SHORT) {
2601 p += 2;
2602 printer(arg, "quality ");
2603 GETSHORT(cishort, p);
2604 switch (cishort) {
2605 case PPP_LQR:
2606 printer(arg, "lqr");
2607 break;
2608 default:
2609 printer(arg, "0x%x", cishort);
2612 break;
2613 case CI_CALLBACK:
2614 if (olen >= CILEN_CHAR) {
2615 p += 2;
2616 printer(arg, "callback ");
2617 GETCHAR(cichar, p);
2618 if (cichar <= 6 &&
2619 *callback_strings[(int)cichar] != '\0') {
2620 printer(arg, "%s", callback_strings[(int)cichar]);
2621 } else {
2622 printer(arg, "0x%x", cichar);
2625 break;
2626 case CI_MAGICNUMBER:
2627 if (olen >= CILEN_LONG) {
2628 p += 2;
2629 GETLONG(cilong, p);
2630 printer(arg, "magic 0x%x", cilong);
2632 break;
2633 case CI_PCOMPRESSION:
2634 if (olen >= CILEN_VOID) {
2635 p += 2;
2636 printer(arg, "pcomp");
2638 break;
2639 case CI_ACCOMPRESSION:
2640 if (olen >= CILEN_VOID) {
2641 p += 2;
2642 printer(arg, "accomp");
2644 break;
2645 case CI_FCSALTERN:
2646 if (olen >= CILEN_CHAR) {
2647 char **cpp;
2648 int needcomma = 0;
2650 p += 2;
2651 GETCHAR(cichar, p);
2652 for (cpp = fcsalt_strings; *cpp != NULL; cpp++)
2653 if (cichar & 1<<(cpp-fcsalt_strings)) {
2654 cichar &= ~(1<<(cpp-fcsalt_strings));
2655 printer(arg, (needcomma ? ",%s" : "fcs %s"), *cpp);
2656 needcomma = 1;
2658 if (cichar != 0 || !needcomma)
2659 printer(arg, (needcomma ? ",0x%x" : "fcs 0x%x"),
2660 cichar);
2662 break;
2663 case CI_NUMBERED:
2664 if (olen >= CILEN_SHORT) {
2665 p += 2;
2666 GETCHAR(cichar, p);
2667 printer(arg, "numb win %d", cichar);
2668 GETCHAR(cichar, p);
2669 printer(arg, " addr %d", cichar);
2671 break;
2672 case CI_MRRU:
2673 if (olen >= CILEN_SHORT) {
2674 p += 2;
2675 GETSHORT(cishort, p);
2676 printer(arg, "mrru %d", cishort);
2678 break;
2679 case CI_SSNHF:
2680 if (olen >= CILEN_VOID) {
2681 p += 2;
2682 printer(arg, "ssnhf");
2684 break;
2685 case CI_EPDISC:
2686 if (olen >= CILEN_CHAR) {
2687 struct epdisc epd;
2688 p += 2;
2689 GETCHAR(epd.class, p);
2690 epd.length = olen - CILEN_CHAR;
2691 if (epd.length > MAX_ENDP_LEN)
2692 epd.length = MAX_ENDP_LEN;
2693 if (epd.length > 0) {
2694 BCOPY(p, epd.value, epd.length);
2695 p += epd.length;
2697 printer(arg, "endpoint [%s]", epdisc_to_str(&epd));
2699 break;
2700 case CI_LINKDISC:
2701 if (olen >= CILEN_SHORT) {
2702 p += 2;
2703 GETSHORT(cishort, p);
2704 printer(arg, "linkdisc %d", cishort);
2706 break;
2707 case CI_COBS:
2708 if (olen >= CILEN_CHAR) {
2709 p += 2;
2710 GETCHAR(cichar, p);
2711 printer(arg, "cobs 0x%x", cichar);
2713 break;
2714 case CI_PFXELISION:
2715 if (olen >= CILEN_CHAR) {
2716 p += 2;
2717 printer(arg, "pfx");
2719 break;
2720 case CI_MPHDRFMT:
2721 if (olen >= CILEN_SHORT) {
2722 p += 2;
2723 printer(arg, "mphdr ");
2724 GETCHAR(cichar, p);
2725 switch (cichar) {
2726 case 2:
2727 printer(arg, "long");
2728 break;
2729 case 6:
2730 printer(arg, "short");
2731 break;
2732 default:
2733 printer(arg, "0x%x", cichar);
2734 break;
2736 GETCHAR(cichar, p);
2737 printer(arg, " #cl %d", cichar);
2739 break;
2740 case CI_I18N:
2741 if (olen >= CILEN_LONG) {
2742 p += 2;
2743 GETLONG(cilong, p);
2744 printer(arg, "i18n charset 0x%x", cilong);
2745 if (olen > CILEN_LONG) {
2746 printer(arg, " lang ");
2747 print_string((char *)p, olen-CILEN_LONG, printer, arg);
2748 p = optend;
2751 break;
2752 case CI_SDL:
2753 if (olen >= CILEN_VOID) {
2754 p += 2;
2755 printer(arg, "sdl");
2757 break;
2758 case CI_MUXING:
2759 if (olen >= CILEN_VOID) {
2760 p += 2;
2761 printer(arg, "mux");
2763 break;
2765 while (p < optend) {
2766 GETCHAR(code, p);
2767 printer(arg, " %.2x", code);
2769 printer(arg, ">");
2771 break;
2773 case CODE_TERMACK:
2774 case CODE_TERMREQ:
2775 if (len > 0 && *p >= ' ' && *p < 0x7f) {
2776 printer(arg, " ");
2777 print_string((char *)p, len, printer, arg);
2778 p += len;
2779 len = 0;
2781 break;
2783 case CODE_ECHOREQ:
2784 case CODE_ECHOREP:
2785 case CODE_DISCREQ:
2786 if (len >= 4) {
2787 GETLONG(cilong, p);
2788 printer(arg, " magic=0x%x", cilong);
2789 len -= 4;
2791 break;
2793 case CODE_IDENT:
2794 if (len >= 4) {
2795 GETLONG(cilong, p);
2796 printer(arg, " magic=0x%x", cilong);
2797 len -= 4;
2798 } else
2799 break;
2800 if (len > 0 && (len > 1 || *p != '\0')) {
2801 printer(arg, " ");
2802 print_string((char *)p, len, printer, arg);
2803 p += len;
2804 len = 0;
2806 break;
2808 case CODE_TIMEREMAIN:
2809 if (len >= 4) {
2810 GETLONG(cilong, p);
2811 printer(arg, " magic=0x%x", cilong);
2812 len -= 4;
2813 } else
2814 break;
2815 if (len >= 4) {
2816 GETLONG(cilong, p);
2817 printer(arg, " seconds=%d", cilong);
2818 len -= 4;
2819 } else
2820 break;
2821 if (len > 0 && (len > 1 || *p != '\0')) {
2822 printer(arg, " ");
2823 print_string((char *)p, len, printer, arg);
2824 p += len;
2825 len = 0;
2827 break;
2830 /* print the rest of the bytes in the packet */
2831 for (i = 0; i < len && i < 32; ++i) {
2832 GETCHAR(code, p);
2833 printer(arg, " %.2x", code);
2835 if (i < len) {
2836 printer(arg, " ...");
2837 p += len - i;
2840 return p - pstart;
2844 * Time to shut down the link because there is nothing out there.
2847 static void
2848 LcpLinkFailure (f)
2849 fsm *f;
2851 char *close_message;
2853 if (f->state == OPENED) {
2854 if (lcp_echo_badreplies > LCP_ECHO_MAX_BADREPLIES) {
2855 info("Received %d bad echo-replies", lcp_echo_badreplies);
2856 close_message = "Receiving malformed Echo-Replies";
2857 } else if (lcp_echo_accm_test) {
2859 * If this is an asynchronous line and we've missed all of
2860 * the initial echo requests, then this is probably due to
2861 * a bad ACCM.
2863 notice("Peer not responding to initial Echo-Requests.");
2864 notice("Negotiated asyncmap may be incorrect for this link.");
2865 close_message = "Peer not responding; perhaps bad asyncmap";
2866 } else {
2867 info("No response to %d echo-requests", lcp_echos_pending);
2868 notice("Serial link appears to be disconnected.");
2869 close_message = "Peer not responding";
2872 lcp_close(f->unit, close_message);
2873 status = EXIT_PEER_DEAD;
2878 * Timer expired for the LCP echo requests from this process.
2881 static void
2882 LcpEchoCheck (f)
2883 fsm *f;
2885 if (f->state != OPENED || lcp_echo_interval == 0)
2886 return;
2888 LcpSendEchoRequest (f);
2891 * Start the timer for the next interval.
2893 if (lcp_echo_timer_running)
2894 warn("assertion lcp_echo_timer_running==0 failed");
2895 TIMEOUT (LcpEchoTimeout, f, lcp_echo_interval);
2896 lcp_echo_timer_running = 1;
2900 * LcpEchoTimeout - Timer expired on the LCP echo
2903 static void
2904 LcpEchoTimeout (arg)
2905 void *arg;
2907 if (lcp_echo_timer_running != 0) {
2908 lcp_echo_timer_running = 0;
2909 LcpEchoCheck ((fsm *) arg);
2914 * LcpEchoReply - LCP has received a reply to the echo
2916 /*ARGSUSED*/
2917 static int
2918 lcp_received_echo_reply (f, id, inp, len)
2919 fsm *f;
2920 int id;
2921 u_char *inp;
2922 int len;
2924 u_int32_t magic;
2926 /* Check the magic number - don't count replies from ourselves. */
2927 if (len < 4) {
2928 dbglog("lcp: received short Echo-Reply, length %d", len);
2929 return (0);
2931 GETLONG(magic, inp);
2932 if (lcp_gotoptions[f->unit].neg_magicnumber &&
2933 magic == lcp_gotoptions[f->unit].magicnumber) {
2934 warn("appear to have received our own echo-reply!");
2935 return (0);
2938 /* Reset the number of outstanding echo frames */
2939 lcp_echos_pending = 0;
2941 if (lcp_echo_accm_test) {
2942 dbglog("lcp: validated asyncmap setting");
2943 lcp_echo_accm_test = 0;
2944 if (lcp_echo_fails == 0)
2945 lcp_echo_interval = 0;
2947 return (1);
2951 * LcpSendEchoRequest - Send an echo request frame to the peer
2954 static void
2955 LcpSendEchoRequest (f)
2956 fsm *f;
2958 u_int32_t lcp_magic;
2959 u_char pkt[4+256], *pktp;
2960 int i;
2963 * Detect the failure of the peer at this point. If we're not currently
2964 * performing the ACCM test, then we just check for the user's echo-failure
2965 * point. If we are performing the ACCM test, then use ACCM_TEST_FAILS if
2966 * the user hasn't specified a different failure point.
2968 i = lcp_echo_fails;
2969 if (i == 0)
2970 i = ACCM_TEST_FAILS;
2971 if ((!lcp_echo_accm_test && lcp_echo_fails != 0 &&
2972 lcp_echos_pending >= lcp_echo_fails) ||
2973 (lcp_echo_accm_test && lcp_echos_pending >= i)) {
2974 LcpLinkFailure(f);
2975 lcp_echos_pending = 0;
2976 lcp_echo_badreplies = 0;
2980 * Make and send the echo request frame.
2982 if (f->state == OPENED) {
2983 lcp_magic = lcp_gotoptions[f->unit].magicnumber;
2984 pktp = pkt;
2985 PUTLONG(lcp_magic, pktp);
2986 /* Send some test packets so we can fail the link early. */
2987 if (lcp_echo_accm_test) {
2988 switch (use_accm_test) {
2989 case 1:
2990 /* Only the characters covered by negotiated ACCM */
2991 for (i = 0; i < 32; i++)
2992 *pktp++ = i;
2993 break;
2994 case 2:
2995 /* All characters */
2996 for (i = 0; i < 256; i++)
2997 *pktp++ = i;
2998 break;
3001 fsm_sdata(f, CODE_ECHOREQ, lcp_echo_number++ & 0xFF, pkt, pktp - pkt);
3002 ++lcp_echos_pending;
3007 * lcp_echo_lowerup - Start the timer for the LCP frame
3010 static void
3011 lcp_echo_lowerup (unit)
3012 int unit;
3014 fsm *f = &lcp_fsm[unit];
3016 /* Clear the parameters for generating echo frames */
3017 lcp_echos_pending = 0;
3018 lcp_echo_number = 0;
3019 lcp_echo_timer_running = 0;
3020 lcp_echo_accm_test = !sync_serial && use_accm_test;
3022 /* If a timeout interval is specified then start the timer */
3023 LcpEchoCheck(f);
3027 * lcp_echo_lowerdown - Stop the timer for the LCP frame
3030 static void
3031 lcp_echo_lowerdown (unit)
3032 int unit;
3034 fsm *f = &lcp_fsm[unit];
3036 if (lcp_echo_timer_running != 0) {
3037 UNTIMEOUT (LcpEchoTimeout, f);
3038 lcp_echo_timer_running = 0;
3043 * LcpSendIdentification - Send LCP Identification string to peer.
3046 static void
3047 LcpSendIdentification (f)
3048 fsm *f;
3050 u_int32_t lcp_magic;
3051 u_char pkt[4 + sizeof(identstr)], *pktp;
3052 int idlen;
3055 * Make and send the Identification frame.
3057 if (f->state == OPENED)
3058 lcp_magic = lcp_gotoptions[f->unit].magicnumber;
3059 else
3060 lcp_magic = 0;
3062 pktp = pkt;
3063 PUTLONG(lcp_magic, pktp);
3064 idlen = strlen(identstr);
3065 BCOPY(identstr, pktp, idlen);
3066 INCPTR(idlen, pktp);
3067 fsm_sdata(f, CODE_IDENT, ++f->id, pkt, pktp - pkt);
3070 /*ARGSUSED*/
3071 static void
3072 lcp_received_identification (f, id, inp, len)
3073 fsm *f;
3074 int id;
3075 u_char *inp;
3076 int len;
3078 u_int32_t magic;
3080 /* Check the magic number - don't count replies from ourselves. */
3081 if (len < 4) {
3082 dbglog("%s: received short Identification; %d < 4", len);
3083 return;
3085 GETLONG(magic, inp);
3086 len -= 4;
3087 if (lcp_gotoptions[f->unit].neg_magicnumber && f->state == OPENED &&
3088 magic == lcp_gotoptions[f->unit].magicnumber) {
3089 warn("appear to have received our own Identification!");
3090 return;
3092 if (len > 0 && (len > 1 || *inp != '\0'))
3093 notice("Peer Identification: %0.*v", len, inp);
3097 * Send a Time-Remaining LCP packet. We don't include a message.
3099 static void
3100 LcpSendTimeRemaining(f, time_remaining)
3101 fsm *f;
3102 u_int32_t time_remaining;
3104 u_int32_t lcp_magic;
3105 u_char pkt[8];
3106 u_char *pktp;
3108 if (f->state != OPENED)
3109 return;
3111 lcp_magic = lcp_gotoptions[f->unit].magicnumber;
3112 pktp = pkt;
3113 PUTLONG(lcp_magic, pktp);
3114 PUTLONG(time_remaining, pktp);
3115 fsm_sdata(f, CODE_TIMEREMAIN, ++f->id, pkt, pktp - pkt);
3118 /*ARGSUSED*/
3119 static void
3120 lcp_received_timeremain(f, id, inp, len)
3121 fsm *f;
3122 int id;
3123 u_char *inp;
3124 int len;
3126 u_int32_t magic;
3127 u_int32_t time_remaining;
3129 /* Check the magic number - don't count replies from ourselves. */
3130 if (len < 8) {
3131 dbglog("%s: received short Time-Remain; %d < 8", len);
3132 return;
3134 GETLONG(magic, inp);
3135 if (lcp_gotoptions[f->unit].neg_magicnumber && f->state == OPENED &&
3136 magic == lcp_gotoptions[f->unit].magicnumber) {
3137 warn("appear to have received our own Time-Remain!");
3138 return;
3140 GETLONG(time_remaining, inp);
3141 if (len > 8) {
3142 notice("%d seconds remain: \"%.*s\"", time_remaining,
3143 len-8, inp);
3144 } else {
3145 notice("Time Remaining: %d seconds", time_remaining);
3150 * lcp_timeremaining - timeout handler which sends LCP Time-Remaining
3151 * packet.
3153 static void
3154 lcp_timeremaining(arg)
3155 void *arg;
3157 struct lcp_timer *lt = (struct lcp_timer *)arg;
3158 u_int32_t time_remaining;
3159 int unit;
3161 unit = lt->unit;
3162 time_remaining = lt->tr;
3163 LcpSendTimeRemaining(&lcp_fsm[unit], time_remaining);
3164 free(lt);
3168 * lcp_settimeremaining - set a timeout to send an LCP Time-Remaining
3169 * packet. The first argument, connecttime, is the time remaining
3170 * at the time this function is called. The second argument is the
3171 * desired time remaining when the packet should be sent out.
3173 void
3174 lcp_settimeremaining(unit, connecttime, time_remaining)
3175 int unit;
3176 u_int32_t connecttime;
3177 u_int32_t time_remaining;
3179 struct lcp_timer *lt;
3181 if (connecttime == time_remaining) {
3182 LcpSendTimeRemaining(&lcp_fsm[unit], time_remaining);
3183 } else {
3184 lt = (struct lcp_timer *)malloc(sizeof (struct lcp_timer));
3185 lt->unit = unit;
3186 lt->tr = time_remaining;
3187 TIMEOUT(lcp_timeremaining, (void *)lt, connecttime - time_remaining);