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