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