Example program with HTTPServer and sensor data streaming over TCPSockets, using Donatien Garnier's Net APIs and services code on top of LWIP. Files StreamServer.h and .cpp encapsulate streaming over TCPSockets. Broadcast is done by sendToAll(), and all incoming data is echoed back to the client. Echo code can be replaced with some remote control of the streaming interface. See main() that shows how to periodically send some data to all subscribed clients. To subscribe, a client should open a socket at <mbed_ip> port 123. I used few lines in TCL code to set up a quick sink for the data. HTTP files are served on port 80 concurrently to the streaming.

Dependencies:   mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers lcp.c Source File

lcp.c

00001 /*****************************************************************************
00002 * lcp.c - Network Link Control Protocol program file.
00003 *
00004 * Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.
00005 * portions Copyright (c) 1997 by Global Election Systems Inc.
00006 *
00007 * The authors hereby grant permission to use, copy, modify, distribute,
00008 * and license this software and its documentation for any purpose, provided
00009 * that existing copyright notices are retained in all copies and that this
00010 * notice and the following disclaimer are included verbatim in any 
00011 * distributions. No written agreement, license, or royalty fee is required
00012 * for any of the authorized uses.
00013 *
00014 * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR
00015 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00016 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
00017 * IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00018 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
00019 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00020 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00021 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00022 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
00023 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00024 *
00025 ******************************************************************************
00026 * REVISION HISTORY
00027 *
00028 * 03-01-01 Marc Boucher <marc@mbsi.ca>
00029 *   Ported to lwIP.
00030 * 97-12-01 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc.
00031 *   Original.
00032 *****************************************************************************/
00033 
00034 /*
00035  * lcp.c - PPP Link Control Protocol.
00036  *
00037  * Copyright (c) 1989 Carnegie Mellon University.
00038  * All rights reserved.
00039  *
00040  * Redistribution and use in source and binary forms are permitted
00041  * provided that the above copyright notice and this paragraph are
00042  * duplicated in all such forms and that any documentation,
00043  * advertising materials, and other materials related to such
00044  * distribution and use acknowledge that the software was developed
00045  * by Carnegie Mellon University.  The name of the
00046  * University may not be used to endorse or promote products derived
00047  * from this software without specific prior written permission.
00048  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
00049  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
00050  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
00051  */
00052  
00053 
00054 #include "lwip/opt.h"
00055 
00056 #if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */
00057 
00058 #include "ppp.h"
00059 #include "pppdebug.h"
00060 
00061 #include "fsm.h"
00062 #include "chap.h"
00063 #include "magic.h"
00064 #include "auth.h"
00065 #include "lcp.h"
00066 
00067 #include <string.h>
00068 
00069 #if PPPOE_SUPPORT
00070 #include "netif/ppp_oe.h"
00071 #else
00072 #define PPPOE_MAXMTU PPP_MAXMRU
00073 #endif
00074 
00075 #if 0 /* UNUSED */
00076 /*
00077  * LCP-related command-line options.
00078  */
00079 int lcp_echo_interval = 0;  /* Interval between LCP echo-requests */
00080 int lcp_echo_fails = 0;     /* Tolerance to unanswered echo-requests */
00081 bool  lax_recv = 0;         /* accept control chars in asyncmap */
00082 
00083 static int setescape (char **);
00084 
00085 static option_t lcp_option_list[] = {
00086     /* LCP options */
00087     /* list stripped for simplicity */
00088     {NULL}
00089 };
00090 #endif /* UNUSED */
00091 
00092 /* options */
00093 LinkPhase lcp_phase[NUM_PPP];          /* Phase of link session (RFC 1661) */
00094 static u_int lcp_echo_interval      = LCP_ECHOINTERVAL; /* Interval between LCP echo-requests */
00095 static u_int lcp_echo_fails         = LCP_MAXECHOFAILS; /* Tolerance to unanswered echo-requests */
00096 
00097 /* global vars */
00098 static fsm lcp_fsm[NUM_PPP];                            /* LCP fsm structure (global)*/
00099 lcp_options lcp_wantoptions[NUM_PPP];  /* Options that we want to request */
00100 lcp_options lcp_gotoptions[NUM_PPP];   /* Options that peer ack'd */
00101 lcp_options lcp_allowoptions[NUM_PPP]; /* Options we allow peer to request */
00102 lcp_options lcp_hisoptions[NUM_PPP];   /* Options that we ack'd */
00103 ext_accm xmit_accm[NUM_PPP];           /* extended transmit ACCM */
00104 
00105 static u32_t lcp_echos_pending      = 0;                /* Number of outstanding echo msgs */
00106 static u32_t lcp_echo_number        = 0;                /* ID number of next echo frame */
00107 static u32_t lcp_echo_timer_running = 0;                /* TRUE if a timer is running */
00108 
00109 /* @todo: do we really need such a large buffer? The typical 1500 bytes seem too much. */
00110 static u_char nak_buffer[PPP_MRU] MEM_POSITION; /* where we construct a nak packet */ 
00111 
00112 /*
00113  * Callbacks for fsm code.  (CI = Configuration Information)
00114  */
00115 static void lcp_resetci (fsm*);                   /* Reset our CI */
00116 static int  lcp_cilen (fsm*);                     /* Return length of our CI */
00117 static void lcp_addci (fsm*, u_char*, int*);      /* Add our CI to pkt */
00118 static int  lcp_ackci (fsm*, u_char*, int);       /* Peer ack'd our CI */
00119 static int  lcp_nakci (fsm*, u_char*, int);       /* Peer nak'd our CI */
00120 static int  lcp_rejci (fsm*, u_char*, int);       /* Peer rej'd our CI */
00121 static int  lcp_reqci (fsm*, u_char*, int*, int); /* Rcv peer CI */
00122 static void lcp_up (fsm*);                        /* We're UP */
00123 static void lcp_down (fsm*);                      /* We're DOWN */
00124 static void lcp_starting (fsm*);                  /* We need lower layer up */
00125 static void lcp_finished (fsm*);                  /* We need lower layer down */
00126 static int  lcp_extcode (fsm*, int, u_char, u_char*, int);
00127 static void lcp_rprotrej (fsm*, u_char*, int);
00128 
00129 /*
00130  * routines to send LCP echos to peer
00131  */
00132 
00133 static void lcp_echo_lowerup (int);
00134 static void lcp_echo_lowerdown (int);
00135 static void LcpEchoTimeout (void*);
00136 static void lcp_received_echo_reply (fsm*, int, u_char*, int);
00137 static void LcpSendEchoRequest (fsm*);
00138 static void LcpLinkFailure (fsm*);
00139 static void LcpEchoCheck (fsm*);
00140 
00141 static fsm_callbacks lcp_callbacks = { /* LCP callback routines */
00142   lcp_resetci,  /* Reset our Configuration Information */
00143   lcp_cilen,    /* Length of our Configuration Information */
00144   lcp_addci,    /* Add our Configuration Information */
00145   lcp_ackci,    /* ACK our Configuration Information */
00146   lcp_nakci,    /* NAK our Configuration Information */
00147   lcp_rejci,    /* Reject our Configuration Information */
00148   lcp_reqci,    /* Request peer's Configuration Information */
00149   lcp_up,       /* Called when fsm reaches LS_OPENED state */
00150   lcp_down,     /* Called when fsm leaves LS_OPENED state */
00151   lcp_starting, /* Called when we want the lower layer up */
00152   lcp_finished, /* Called when we want the lower layer down */
00153   NULL,         /* Called when Protocol-Reject received */
00154   NULL,         /* Retransmission is necessary */
00155   lcp_extcode,  /* Called to handle LCP-specific codes */
00156   "LCP"         /* String name of protocol */
00157 };
00158 
00159 /*
00160  * Protocol entry points.
00161  * Some of these are called directly.
00162  */
00163 
00164 static void lcp_input (int, u_char *, int);
00165 static void lcp_protrej (int);
00166 
00167 struct protent lcp_protent = {
00168     PPP_LCP,
00169     lcp_init,
00170     lcp_input,
00171     lcp_protrej,
00172     lcp_lowerup,
00173     lcp_lowerdown,
00174     lcp_open,
00175     lcp_close,
00176 #if PPP_ADDITIONAL_CALLBACKS
00177     lcp_printpkt,
00178     NULL,
00179 #endif /* PPP_ADDITIONAL_CALLBACKS */
00180     1,
00181     "LCP",
00182 #if PPP_ADDITIONAL_CALLBACKS
00183     NULL,
00184     NULL,
00185     NULL
00186 #endif /* PPP_ADDITIONAL_CALLBACKS */
00187 };
00188 
00189 int lcp_loopbackfail = DEFLOOPBACKFAIL;
00190 
00191 /*
00192  * Length of each type of configuration option (in octets)
00193  */
00194 #define CILEN_VOID  2
00195 #define CILEN_CHAR  3
00196 #define CILEN_SHORT 4 /* CILEN_VOID + sizeof(short) */
00197 #define CILEN_CHAP  5 /* CILEN_VOID + sizeof(short) + 1 */
00198 #define CILEN_LONG  6 /* CILEN_VOID + sizeof(long) */
00199 #define CILEN_LQR   8 /* CILEN_VOID + sizeof(short) + sizeof(long) */
00200 #define CILEN_CBCP  3
00201 
00202 #define CODENAME(x)  ((x) == CONFACK ? "ACK" : (x) == CONFNAK ? "NAK" : "REJ")
00203 
00204 #if 0 /* UNUSED */
00205 /*
00206  * setescape - add chars to the set we escape on transmission.
00207  */
00208 static int
00209 setescape(argv)
00210     char **argv;
00211 {
00212     int n, ret;
00213     char *p, *endp;
00214 
00215     p = *argv;
00216     ret = 1;
00217     while (*p) {
00218       n = strtol(p, &endp, 16);
00219       if (p == endp) {
00220         option_error("escape parameter contains invalid hex number '%s'", p);
00221         return 0;
00222       }
00223       p = endp;
00224       if (n < 0 || n == 0x5E || n > 0xFF) {
00225         option_error("can't escape character 0x%x", n);
00226         ret = 0;
00227       } else
00228         xmit_accm[0][n >> 5] |= 1 << (n & 0x1F);
00229       while (*p == ',' || *p == ' ')
00230         ++p;
00231     }
00232     return ret;
00233 }
00234 #endif /* UNUSED */
00235 
00236 /*
00237  * lcp_init - Initialize LCP.
00238  */
00239 void
00240 lcp_init(int unit)
00241 {
00242   fsm         *f  = &lcp_fsm[unit];
00243   lcp_options *wo = &lcp_wantoptions[unit];
00244   lcp_options *ao = &lcp_allowoptions[unit];
00245 
00246   f->unit      = unit;
00247   f->protocol  = PPP_LCP;
00248   f->callbacks = &lcp_callbacks;
00249 
00250   fsm_init(f);
00251 
00252   wo->passive           = 0;
00253   wo->silent            = 0;
00254   wo->restart           = 0;               /* Set to 1 in kernels or multi-line implementations */
00255   wo->neg_mru           = 1;
00256   wo->mru               = PPP_DEFMRU;
00257   wo->neg_asyncmap      = 1;
00258   wo->asyncmap          = 0x00000000l;     /* Assume don't need to escape any ctl chars. */
00259   wo->neg_chap          = 0;               /* Set to 1 on server */
00260   wo->neg_upap          = 0;               /* Set to 1 on server */
00261   wo->chap_mdtype       = CHAP_DIGEST_MD5;
00262   wo->neg_magicnumber   = 1;
00263   wo->neg_pcompression  = 1;
00264   wo->neg_accompression = 1;
00265   wo->neg_lqr           = 0;               /* no LQR implementation yet */
00266   wo->neg_cbcp          = 0;
00267 
00268   ao->neg_mru           = 1;
00269   ao->mru               = PPP_MAXMRU;
00270   ao->neg_asyncmap      = 1;
00271   ao->asyncmap          = 0x00000000l;     /* Assume don't need to escape any ctl chars. */
00272   ao->neg_chap          = (CHAP_SUPPORT != 0);
00273   ao->chap_mdtype       = CHAP_DIGEST_MD5;
00274   ao->neg_upap          = (PAP_SUPPORT != 0);
00275   ao->neg_magicnumber   = 1;
00276   ao->neg_pcompression  = 1;
00277   ao->neg_accompression = 1;
00278   ao->neg_lqr           = 0;               /* no LQR implementation yet */
00279   ao->neg_cbcp          = (CBCP_SUPPORT != 0);
00280 
00281   /* 
00282    * Set transmit escape for the flag and escape characters plus anything
00283    * set for the allowable options.
00284    */
00285   memset(xmit_accm[unit], 0, sizeof(xmit_accm[0]));
00286   xmit_accm[unit][15] = 0x60;
00287   xmit_accm[unit][0]  = (u_char)((ao->asyncmap        & 0xFF));
00288   xmit_accm[unit][1]  = (u_char)((ao->asyncmap >> 8)  & 0xFF);
00289   xmit_accm[unit][2]  = (u_char)((ao->asyncmap >> 16) & 0xFF);
00290   xmit_accm[unit][3]  = (u_char)((ao->asyncmap >> 24) & 0xFF);
00291   LCPDEBUG(LOG_INFO, ("lcp_init: xmit_accm=%X %X %X %X\n",
00292         xmit_accm[unit][0],
00293         xmit_accm[unit][1],
00294         xmit_accm[unit][2],
00295         xmit_accm[unit][3]));
00296   
00297   lcp_phase[unit] = PHASE_INITIALIZE;
00298 }
00299 
00300 
00301 /*
00302  * lcp_open - LCP is allowed to come up.
00303  */
00304 void
00305 lcp_open(int unit)
00306 {
00307   fsm         *f  = &lcp_fsm[unit];
00308   lcp_options *wo = &lcp_wantoptions[unit];
00309 
00310   f->flags = 0;
00311   if (wo->passive) {
00312     f->flags |= OPT_PASSIVE;
00313   }
00314   if (wo->silent) {
00315     f->flags |= OPT_SILENT;
00316   }
00317   fsm_open(f);
00318 
00319   lcp_phase[unit] = PHASE_ESTABLISH;
00320 }
00321 
00322 
00323 /*
00324  * lcp_close - Take LCP down.
00325  */
00326 void
00327 lcp_close(int unit, char *reason)
00328 {
00329   fsm *f = &lcp_fsm[unit];
00330 
00331   if (lcp_phase[unit] != PHASE_DEAD) {
00332     lcp_phase[unit] = PHASE_TERMINATE;
00333   }
00334   if (f->state == LS_STOPPED && f->flags & (OPT_PASSIVE|OPT_SILENT)) {
00335     /*
00336      * This action is not strictly according to the FSM in RFC1548,
00337      * but it does mean that the program terminates if you do an
00338      * lcp_close() in passive/silent mode when a connection hasn't
00339      * been established.
00340      */
00341     f->state = LS_CLOSED;
00342     lcp_finished(f);
00343   } else {
00344     fsm_close(f, reason);
00345   }
00346 }
00347 
00348 
00349 /*
00350  * lcp_lowerup - The lower layer is up.
00351  */
00352 void
00353 lcp_lowerup(int unit)
00354 {
00355   lcp_options *wo = &lcp_wantoptions[unit];
00356 
00357   /*
00358    * Don't use A/C or protocol compression on transmission,
00359    * but accept A/C and protocol compressed packets
00360    * if we are going to ask for A/C and protocol compression.
00361    */
00362   ppp_set_xaccm(unit, &xmit_accm[unit]);
00363   ppp_send_config(unit, PPP_MRU, 0xffffffffl, 0, 0);
00364   ppp_recv_config(unit, PPP_MRU, 0x00000000l,
00365   wo->neg_pcompression, wo->neg_accompression);
00366   peer_mru[unit] = PPP_MRU;
00367   lcp_allowoptions[unit].asyncmap = (u_long)xmit_accm[unit][0]
00368                                  | ((u_long)xmit_accm[unit][1] << 8)
00369                                  | ((u_long)xmit_accm[unit][2] << 16)
00370                                  | ((u_long)xmit_accm[unit][3] << 24);
00371   LCPDEBUG(LOG_INFO, ("lcp_lowerup: asyncmap=%X %X %X %X\n",
00372             xmit_accm[unit][3],
00373             xmit_accm[unit][2],
00374             xmit_accm[unit][1],
00375             xmit_accm[unit][0]));
00376 
00377   fsm_lowerup(&lcp_fsm[unit]);
00378 }
00379 
00380 
00381 /*
00382  * lcp_lowerdown - The lower layer is down.
00383  */
00384 void
00385 lcp_lowerdown(int unit)
00386 {
00387   fsm_lowerdown(&lcp_fsm[unit]);
00388 }
00389 
00390 
00391 /*
00392  * lcp_input - Input LCP packet.
00393  */
00394 static void
00395 lcp_input(int unit, u_char *p, int len)
00396 {
00397   fsm *f = &lcp_fsm[unit];
00398 
00399   fsm_input(f, p, len);
00400 }
00401 
00402 
00403 /*
00404  * lcp_extcode - Handle a LCP-specific code.
00405  */
00406 static int
00407 lcp_extcode(fsm *f, int code, u_char id, u_char *inp, int len)
00408 {
00409   u_char *magp;
00410 
00411   switch( code ){
00412     case PROTREJ:
00413       lcp_rprotrej(f, inp, len);
00414       break;
00415   
00416     case ECHOREQ:
00417       if (f->state != LS_OPENED) {
00418         break;
00419       }
00420       LCPDEBUG(LOG_INFO, ("lcp: Echo-Request, Rcvd id %d\n", id));
00421       magp = inp;
00422       PUTLONG(lcp_gotoptions[f->unit].magicnumber, magp);
00423       fsm_sdata(f, ECHOREP, id, inp, len);
00424       break;
00425 
00426     case ECHOREP:
00427       lcp_received_echo_reply(f, id, inp, len);
00428       break;
00429 
00430     case DISCREQ:
00431       break;
00432 
00433     default:
00434       return 0;
00435   }
00436   return 1;
00437 }
00438 
00439 
00440 /*
00441  * lcp_rprotrej - Receive an Protocol-Reject.
00442  *
00443  * Figure out which protocol is rejected and inform it.
00444  */
00445 static void
00446 lcp_rprotrej(fsm *f, u_char *inp, int len)
00447 {
00448   int i;
00449   struct protent *protp;
00450   u_short prot;
00451 
00452   if (len < (int)sizeof (u_short)) {
00453     LCPDEBUG(LOG_INFO, ("lcp_rprotrej: Rcvd short Protocol-Reject packet!\n"));
00454     return;
00455   }
00456 
00457   GETSHORT(prot, inp);
00458 
00459   LCPDEBUG(LOG_INFO, ("lcp_rprotrej: Rcvd Protocol-Reject packet for %x!\n", prot));
00460 
00461   /*
00462    * Protocol-Reject packets received in any state other than the LCP
00463    * LS_OPENED state SHOULD be silently discarded.
00464    */
00465   if( f->state != LS_OPENED ) {
00466     LCPDEBUG(LOG_INFO, ("Protocol-Reject discarded: LCP in state %d\n", f->state));
00467     return;
00468   }
00469 
00470   /*
00471    * Upcall the proper Protocol-Reject routine.
00472    */
00473   for (i = 0; (protp = ppp_protocols[i]) != NULL; ++i) {
00474     if (protp->protocol == prot && protp->enabled_flag) {
00475       (*protp->protrej)(f->unit);
00476       return;
00477     }
00478   }
00479 
00480   LCPDEBUG(LOG_WARNING, ("Protocol-Reject for unsupported protocol 0x%x\n", prot));
00481 }
00482 
00483 
00484 /*
00485  * lcp_protrej - A Protocol-Reject was received.
00486  */
00487 static void
00488 lcp_protrej(int unit)
00489 {
00490   LWIP_UNUSED_ARG(unit);
00491   /*
00492    * Can't reject LCP!
00493    */
00494   LCPDEBUG(LOG_WARNING, ("lcp_protrej: Received Protocol-Reject for LCP!\n"));
00495   fsm_protreject(&lcp_fsm[unit]);
00496 }
00497 
00498 
00499 /*
00500  * lcp_sprotrej - Send a Protocol-Reject for some protocol.
00501  */
00502 void
00503 lcp_sprotrej(int unit, u_char *p, int len)
00504 {
00505   /*
00506    * Send back the protocol and the information field of the
00507    * rejected packet.  We only get here if LCP is in the LS_OPENED state.
00508    */
00509 
00510   fsm_sdata(&lcp_fsm[unit], PROTREJ, ++lcp_fsm[unit].id, p, len);
00511 }
00512 
00513 
00514 /*
00515  * lcp_resetci - Reset our CI.
00516  */
00517 static void
00518 lcp_resetci(fsm *f)
00519 {
00520   lcp_wantoptions[f->unit].magicnumber = magic();
00521   lcp_wantoptions[f->unit].numloops = 0;
00522   lcp_gotoptions[f->unit] = lcp_wantoptions[f->unit];
00523   peer_mru[f->unit] = PPP_MRU;
00524   auth_reset(f->unit);
00525 }
00526 
00527 
00528 /*
00529  * lcp_cilen - Return length of our CI.
00530  */
00531 static int
00532 lcp_cilen(fsm *f)
00533 {
00534   lcp_options *go = &lcp_gotoptions[f->unit];
00535 
00536 #define LENCIVOID(neg)  ((neg) ? CILEN_VOID : 0)
00537 #define LENCICHAP(neg)  ((neg) ? CILEN_CHAP : 0)
00538 #define LENCISHORT(neg) ((neg) ? CILEN_SHORT : 0)
00539 #define LENCILONG(neg)  ((neg) ? CILEN_LONG : 0)
00540 #define LENCILQR(neg)   ((neg) ? CILEN_LQR: 0)
00541 #define LENCICBCP(neg)  ((neg) ? CILEN_CBCP: 0)
00542   /*
00543    * NB: we only ask for one of CHAP and UPAP, even if we will
00544    * accept either.
00545    */
00546   return (LENCISHORT(go->neg_mru && go->mru != PPP_DEFMRU) +
00547           LENCILONG(go->neg_asyncmap && go->asyncmap != 0xFFFFFFFFl) +
00548           LENCICHAP(go->neg_chap) +
00549           LENCISHORT(!go->neg_chap && go->neg_upap) +
00550           LENCILQR(go->neg_lqr) +
00551           LENCICBCP(go->neg_cbcp) +
00552           LENCILONG(go->neg_magicnumber) +
00553           LENCIVOID(go->neg_pcompression) +
00554           LENCIVOID(go->neg_accompression));
00555 }
00556 
00557 
00558 /*
00559  * lcp_addci - Add our desired CIs to a packet.
00560  */
00561 static void
00562 lcp_addci(fsm *f, u_char *ucp, int *lenp)
00563 {
00564   lcp_options *go = &lcp_gotoptions[f->unit];
00565   u_char *start_ucp = ucp;
00566 
00567 #define ADDCIVOID(opt, neg) \
00568   if (neg) { \
00569     LCPDEBUG(LOG_INFO, ("lcp_addci: opt=%d\n", opt)); \
00570     PUTCHAR(opt, ucp); \
00571     PUTCHAR(CILEN_VOID, ucp); \
00572   }
00573 #define ADDCISHORT(opt, neg, val) \
00574   if (neg) { \
00575     LCPDEBUG(LOG_INFO, ("lcp_addci: INT opt=%d %X\n", opt, val)); \
00576     PUTCHAR(opt, ucp); \
00577     PUTCHAR(CILEN_SHORT, ucp); \
00578     PUTSHORT(val, ucp); \
00579   }
00580 #define ADDCICHAP(opt, neg, val, digest) \
00581   if (neg) { \
00582     LCPDEBUG(LOG_INFO, ("lcp_addci: CHAP opt=%d %X\n", opt, val)); \
00583     PUTCHAR(opt, ucp); \
00584     PUTCHAR(CILEN_CHAP, ucp); \
00585     PUTSHORT(val, ucp); \
00586     PUTCHAR(digest, ucp); \
00587   }
00588 #define ADDCILONG(opt, neg, val) \
00589   if (neg) { \
00590     LCPDEBUG(LOG_INFO, ("lcp_addci: L opt=%d %lX\n", opt, val)); \
00591     PUTCHAR(opt, ucp); \
00592     PUTCHAR(CILEN_LONG, ucp); \
00593     PUTLONG(val, ucp); \
00594   }
00595 #define ADDCILQR(opt, neg, val) \
00596   if (neg) { \
00597     LCPDEBUG(LOG_INFO, ("lcp_addci: LQR opt=%d %lX\n", opt, val)); \
00598     PUTCHAR(opt, ucp); \
00599     PUTCHAR(CILEN_LQR, ucp); \
00600     PUTSHORT(PPP_LQR, ucp); \
00601     PUTLONG(val, ucp); \
00602   }
00603 #define ADDCICHAR(opt, neg, val) \
00604   if (neg) { \
00605     LCPDEBUG(LOG_INFO, ("lcp_addci: CHAR opt=%d %X '%z'\n", opt, val, val)); \
00606     PUTCHAR(opt, ucp); \
00607     PUTCHAR(CILEN_CHAR, ucp); \
00608     PUTCHAR(val, ucp); \
00609   }
00610 
00611   ADDCISHORT(CI_MRU, go->neg_mru && go->mru != PPP_DEFMRU, go->mru);
00612   ADDCILONG(CI_ASYNCMAP, go->neg_asyncmap && go->asyncmap != 0xFFFFFFFFl, go->asyncmap);
00613   ADDCICHAP(CI_AUTHTYPE, go->neg_chap, PPP_CHAP, go->chap_mdtype);
00614   ADDCISHORT(CI_AUTHTYPE, !go->neg_chap && go->neg_upap, PPP_PAP);
00615   ADDCILQR(CI_QUALITY, go->neg_lqr, go->lqr_period);
00616   ADDCICHAR(CI_CALLBACK, go->neg_cbcp, CBCP_OPT);
00617   ADDCILONG(CI_MAGICNUMBER, go->neg_magicnumber, go->magicnumber);
00618   ADDCIVOID(CI_PCOMPRESSION, go->neg_pcompression);
00619   ADDCIVOID(CI_ACCOMPRESSION, go->neg_accompression);
00620 
00621   if (ucp - start_ucp != *lenp) {
00622     /* this should never happen, because peer_mtu should be 1500 */
00623     LCPDEBUG(LOG_ERR, ("Bug in lcp_addci: wrong length\n"));
00624   }
00625 }
00626 
00627 
00628 /*
00629  * lcp_ackci - Ack our CIs.
00630  * This should not modify any state if the Ack is bad.
00631  *
00632  * Returns:
00633  *  0 - Ack was bad.
00634  *  1 - Ack was good.
00635  */
00636 static int
00637 lcp_ackci(fsm *f, u_char *p, int len)
00638 {
00639   lcp_options *go = &lcp_gotoptions[f->unit];
00640   u_char cilen, citype, cichar;
00641   u_short cishort;
00642   u32_t cilong;
00643 
00644   /*
00645    * CIs must be in exactly the same order that we sent.
00646    * Check packet length and CI length at each step.
00647    * If we find any deviations, then this packet is bad.
00648    */
00649 #define ACKCIVOID(opt, neg) \
00650   if (neg) { \
00651     if ((len -= CILEN_VOID) < 0) \
00652       goto bad; \
00653     GETCHAR(citype, p); \
00654     GETCHAR(cilen, p); \
00655     if (cilen != CILEN_VOID || citype != opt) \
00656       goto bad; \
00657   }
00658 #define ACKCISHORT(opt, neg, val) \
00659   if (neg) { \
00660     if ((len -= CILEN_SHORT) < 0) \
00661       goto bad; \
00662     GETCHAR(citype, p); \
00663     GETCHAR(cilen, p); \
00664     if (cilen != CILEN_SHORT || citype != opt) \
00665       goto bad; \
00666     GETSHORT(cishort, p); \
00667     if (cishort != val) \
00668       goto bad; \
00669   }
00670 #define ACKCICHAR(opt, neg, val) \
00671   if (neg) { \
00672     if ((len -= CILEN_CHAR) < 0) \
00673       goto bad; \
00674     GETCHAR(citype, p); \
00675     GETCHAR(cilen, p); \
00676     if (cilen != CILEN_CHAR || citype != opt) \
00677       goto bad; \
00678     GETCHAR(cichar, p); \
00679     if (cichar != val) \
00680       goto bad; \
00681   }
00682 #define ACKCICHAP(opt, neg, val, digest) \
00683   if (neg) { \
00684     if ((len -= CILEN_CHAP) < 0) \
00685       goto bad; \
00686     GETCHAR(citype, p); \
00687     GETCHAR(cilen, p); \
00688     if (cilen != CILEN_CHAP || citype != opt) \
00689       goto bad; \
00690     GETSHORT(cishort, p); \
00691     if (cishort != val) \
00692       goto bad; \
00693     GETCHAR(cichar, p); \
00694     if (cichar != digest) \
00695       goto bad; \
00696   }
00697 #define ACKCILONG(opt, neg, val) \
00698   if (neg) { \
00699     if ((len -= CILEN_LONG) < 0) \
00700       goto bad; \
00701     GETCHAR(citype, p); \
00702     GETCHAR(cilen, p); \
00703     if (cilen != CILEN_LONG ||  citype != opt) \
00704       goto bad; \
00705     GETLONG(cilong, p); \
00706     if (cilong != val) \
00707       goto bad; \
00708   }
00709 #define ACKCILQR(opt, neg, val) \
00710   if (neg) { \
00711     if ((len -= CILEN_LQR) < 0) \
00712       goto bad; \
00713     GETCHAR(citype, p); \
00714     GETCHAR(cilen, p); \
00715     if (cilen != CILEN_LQR || citype != opt) \
00716       goto bad; \
00717     GETSHORT(cishort, p); \
00718     if (cishort != PPP_LQR) \
00719       goto bad; \
00720     GETLONG(cilong, p); \
00721     if (cilong != val) \
00722       goto bad; \
00723   }
00724 
00725   ACKCISHORT(CI_MRU, go->neg_mru && go->mru != PPP_DEFMRU, go->mru);
00726   ACKCILONG(CI_ASYNCMAP, go->neg_asyncmap && go->asyncmap != 0xFFFFFFFFl, go->asyncmap);
00727   ACKCICHAP(CI_AUTHTYPE, go->neg_chap, PPP_CHAP, go->chap_mdtype);
00728   ACKCISHORT(CI_AUTHTYPE, !go->neg_chap && go->neg_upap, PPP_PAP);
00729   ACKCILQR(CI_QUALITY, go->neg_lqr, go->lqr_period);
00730   ACKCICHAR(CI_CALLBACK, go->neg_cbcp, CBCP_OPT);
00731   ACKCILONG(CI_MAGICNUMBER, go->neg_magicnumber, go->magicnumber);
00732   ACKCIVOID(CI_PCOMPRESSION, go->neg_pcompression);
00733   ACKCIVOID(CI_ACCOMPRESSION, go->neg_accompression);
00734 
00735   /*
00736    * If there are any remaining CIs, then this packet is bad.
00737    */
00738   if (len != 0) {
00739     goto bad;
00740   }
00741   LCPDEBUG(LOG_INFO, ("lcp_acki: Ack\n"));
00742   return (1);
00743 bad:
00744   LCPDEBUG(LOG_WARNING, ("lcp_acki: received bad Ack!\n"));
00745   return (0);
00746 }
00747 
00748 
00749 /*
00750  * lcp_nakci - Peer has sent a NAK for some of our CIs.
00751  * This should not modify any state if the Nak is bad
00752  * or if LCP is in the LS_OPENED state.
00753  *
00754  * Returns:
00755  *  0 - Nak was bad.
00756  *  1 - Nak was good.
00757  */
00758 static int
00759 lcp_nakci(fsm *f, u_char *p, int len)
00760 {
00761   lcp_options *go = &lcp_gotoptions[f->unit];
00762   lcp_options *wo = &lcp_wantoptions[f->unit];
00763   u_char citype, cichar, *next;
00764   u_short cishort;
00765   u32_t cilong;
00766   lcp_options no;     /* options we've seen Naks for */
00767   lcp_options try;    /* options to request next time */
00768   int looped_back = 0;
00769   int cilen;
00770 
00771   BZERO(&no, sizeof(no));
00772   try = *go;
00773 
00774   /*
00775    * Any Nak'd CIs must be in exactly the same order that we sent.
00776    * Check packet length and CI length at each step.
00777    * If we find any deviations, then this packet is bad.
00778    */
00779 #define NAKCIVOID(opt, neg, code) \
00780   if (go->neg && \
00781       len >= CILEN_VOID && \
00782       p[1] == CILEN_VOID && \
00783       p[0] == opt) { \
00784     len -= CILEN_VOID; \
00785     INCPTR(CILEN_VOID, p); \
00786     no.neg = 1; \
00787     code \
00788   }
00789 #define NAKCICHAP(opt, neg, code) \
00790   if (go->neg && \
00791       len >= CILEN_CHAP && \
00792       p[1] == CILEN_CHAP && \
00793       p[0] == opt) { \
00794     len -= CILEN_CHAP; \
00795     INCPTR(2, p); \
00796     GETSHORT(cishort, p); \
00797     GETCHAR(cichar, p); \
00798     no.neg = 1; \
00799     code \
00800   }
00801 #define NAKCICHAR(opt, neg, code) \
00802   if (go->neg && \
00803       len >= CILEN_CHAR && \
00804       p[1] == CILEN_CHAR && \
00805       p[0] == opt) { \
00806     len -= CILEN_CHAR; \
00807     INCPTR(2, p); \
00808     GETCHAR(cichar, p); \
00809     no.neg = 1; \
00810     code \
00811   }
00812 #define NAKCISHORT(opt, neg, code) \
00813   if (go->neg && \
00814       len >= CILEN_SHORT && \
00815       p[1] == CILEN_SHORT && \
00816       p[0] == opt) { \
00817     len -= CILEN_SHORT; \
00818     INCPTR(2, p); \
00819     GETSHORT(cishort, p); \
00820     no.neg = 1; \
00821     code \
00822   }
00823 #define NAKCILONG(opt, neg, code) \
00824   if (go->neg && \
00825       len >= CILEN_LONG && \
00826       p[1] == CILEN_LONG && \
00827       p[0] == opt) { \
00828     len -= CILEN_LONG; \
00829     INCPTR(2, p); \
00830     GETLONG(cilong, p); \
00831     no.neg = 1; \
00832     code \
00833   }
00834 #define NAKCILQR(opt, neg, code) \
00835   if (go->neg && \
00836       len >= CILEN_LQR && \
00837       p[1] == CILEN_LQR && \
00838       p[0] == opt) { \
00839     len -= CILEN_LQR; \
00840     INCPTR(2, p); \
00841     GETSHORT(cishort, p); \
00842     GETLONG(cilong, p); \
00843     no.neg = 1; \
00844     code \
00845   }
00846 
00847   /*
00848    * We don't care if they want to send us smaller packets than
00849    * we want.  Therefore, accept any MRU less than what we asked for,
00850    * but then ignore the new value when setting the MRU in the kernel.
00851    * If they send us a bigger MRU than what we asked, accept it, up to
00852    * the limit of the default MRU we'd get if we didn't negotiate.
00853    */
00854   if (go->neg_mru && go->mru != PPP_DEFMRU) {
00855     NAKCISHORT(CI_MRU, neg_mru,
00856       if (cishort <= wo->mru || cishort < PPP_DEFMRU) {
00857         try.mru = cishort;
00858       }
00859     );
00860   }
00861 
00862   /*
00863    * Add any characters they want to our (receive-side) asyncmap.
00864    */
00865   if (go->neg_asyncmap && go->asyncmap != 0xFFFFFFFFl) {
00866     NAKCILONG(CI_ASYNCMAP, neg_asyncmap,
00867       try.asyncmap = go->asyncmap | cilong;
00868     );
00869   }
00870 
00871   /*
00872    * If they've nak'd our authentication-protocol, check whether
00873    * they are proposing a different protocol, or a different
00874    * hash algorithm for CHAP.
00875    */
00876   if ((go->neg_chap || go->neg_upap)
00877       && len >= CILEN_SHORT
00878       && p[0] == CI_AUTHTYPE && p[1] >= CILEN_SHORT && p[1] <= len) {
00879     cilen = p[1];
00880     len -= cilen;
00881     no.neg_chap = go->neg_chap;
00882     no.neg_upap = go->neg_upap;
00883     INCPTR(2, p);
00884     GETSHORT(cishort, p);
00885     if (cishort == PPP_PAP && cilen == CILEN_SHORT) {
00886       /*
00887        * If we were asking for CHAP, they obviously don't want to do it.
00888        * If we weren't asking for CHAP, then we were asking for PAP,
00889        * in which case this Nak is bad.
00890        */
00891       if (!go->neg_chap) {
00892         goto bad;
00893       }
00894       try.neg_chap = 0;
00895     
00896     } else if (cishort == PPP_CHAP && cilen == CILEN_CHAP) {
00897       GETCHAR(cichar, p);
00898       if (go->neg_chap) {
00899         /*
00900          * We were asking for CHAP/MD5; they must want a different
00901          * algorithm.  If they can't do MD5, we'll have to stop
00902          * asking for CHAP.
00903          */
00904         if (cichar != go->chap_mdtype) {
00905           try.neg_chap = 0;
00906         }
00907       } else {
00908         /*
00909          * Stop asking for PAP if we were asking for it.
00910          */
00911         try.neg_upap = 0;
00912       }
00913     
00914     } else {
00915       /*
00916        * We don't recognize what they're suggesting.
00917        * Stop asking for what we were asking for.
00918        */
00919       if (go->neg_chap) {
00920         try.neg_chap = 0;
00921       } else {
00922         try.neg_upap = 0;
00923       }
00924       p += cilen - CILEN_SHORT;
00925     }
00926   }
00927 
00928   /*
00929    * If they can't cope with our link quality protocol, we'll have
00930    * to stop asking for LQR.  We haven't got any other protocol.
00931    * If they Nak the reporting period, take their value XXX ?
00932    */
00933   NAKCILQR(CI_QUALITY, neg_lqr,
00934     if (cishort != PPP_LQR) {
00935       try.neg_lqr = 0;
00936     } else {
00937       try.lqr_period = cilong;
00938     }
00939   );
00940 
00941   /*
00942    * Only implementing CBCP...not the rest of the callback options
00943    */
00944   NAKCICHAR(CI_CALLBACK, neg_cbcp,
00945     try.neg_cbcp = 0;
00946   );
00947 
00948   /*
00949    * Check for a looped-back line.
00950    */
00951   NAKCILONG(CI_MAGICNUMBER, neg_magicnumber,
00952     try.magicnumber = magic();
00953     looped_back = 1;
00954   );
00955 
00956   /*
00957    * Peer shouldn't send Nak for protocol compression or
00958    * address/control compression requests; they should send
00959    * a Reject instead.  If they send a Nak, treat it as a Reject.
00960    */
00961   NAKCIVOID(CI_PCOMPRESSION, neg_pcompression,
00962     try.neg_pcompression = 0;
00963   );
00964   NAKCIVOID(CI_ACCOMPRESSION, neg_accompression,
00965     try.neg_accompression = 0;
00966   );
00967 
00968   /*
00969    * There may be remaining CIs, if the peer is requesting negotiation
00970    * on an option that we didn't include in our request packet.
00971    * If we see an option that we requested, or one we've already seen
00972    * in this packet, then this packet is bad.
00973    * If we wanted to respond by starting to negotiate on the requested
00974    * option(s), we could, but we don't, because except for the
00975    * authentication type and quality protocol, if we are not negotiating
00976    * an option, it is because we were told not to.
00977    * For the authentication type, the Nak from the peer means
00978    * `let me authenticate myself with you' which is a bit pointless.
00979    * For the quality protocol, the Nak means `ask me to send you quality
00980    * reports', but if we didn't ask for them, we don't want them.
00981    * An option we don't recognize represents the peer asking to
00982    * negotiate some option we don't support, so ignore it.
00983    */
00984   while (len > CILEN_VOID) {
00985     GETCHAR(citype, p);
00986     GETCHAR(cilen, p);
00987     if (cilen < CILEN_VOID || (len -= cilen) < 0) {
00988       goto bad;
00989     }
00990     next = p + cilen - 2;
00991 
00992     switch (citype) {
00993       case CI_MRU:
00994         if ((go->neg_mru && go->mru != PPP_DEFMRU)
00995             || no.neg_mru || cilen != CILEN_SHORT) {
00996           goto bad;
00997         }
00998         GETSHORT(cishort, p);
00999         if (cishort < PPP_DEFMRU) {
01000           try.mru = cishort;
01001         }
01002         break;
01003       case CI_ASYNCMAP:
01004         if ((go->neg_asyncmap && go->asyncmap != 0xFFFFFFFFl)
01005             || no.neg_asyncmap || cilen != CILEN_LONG) {
01006           goto bad;
01007         }
01008         break;
01009       case CI_AUTHTYPE:
01010         if (go->neg_chap || no.neg_chap || go->neg_upap || no.neg_upap) {
01011           goto bad;
01012         }
01013         break;
01014       case CI_MAGICNUMBER:
01015         if (go->neg_magicnumber || no.neg_magicnumber ||
01016             cilen != CILEN_LONG) {
01017           goto bad;
01018         }
01019         break;
01020       case CI_PCOMPRESSION:
01021         if (go->neg_pcompression || no.neg_pcompression
01022             || cilen != CILEN_VOID) {
01023           goto bad;
01024         }
01025         break;
01026       case CI_ACCOMPRESSION:
01027         if (go->neg_accompression || no.neg_accompression
01028             || cilen != CILEN_VOID) {
01029           goto bad;
01030         }
01031         break;
01032       case CI_QUALITY:
01033         if (go->neg_lqr || no.neg_lqr || cilen != CILEN_LQR) {
01034           goto bad;
01035         }
01036         break;
01037     }
01038     p = next;
01039   }
01040 
01041   /* If there is still anything left, this packet is bad. */
01042   if (len != 0) {
01043     goto bad;
01044   }
01045 
01046   /*
01047   * OK, the Nak is good.  Now we can update state.
01048   */
01049   if (f->state != LS_OPENED) {
01050     if (looped_back) {
01051       if (++try.numloops >= lcp_loopbackfail) {
01052         LCPDEBUG(LOG_NOTICE, ("Serial line is looped back.\n"));
01053         lcp_close(f->unit, "Loopback detected");
01054       }
01055     } else {
01056       try.numloops = 0;
01057     }
01058     *go = try;
01059   }
01060 
01061   return 1;
01062 
01063 bad:
01064   LCPDEBUG(LOG_WARNING, ("lcp_nakci: received bad Nak!\n"));
01065   return 0;
01066 }
01067 
01068 
01069 /*
01070  * lcp_rejci - Peer has Rejected some of our CIs.
01071  * This should not modify any state if the Reject is bad
01072  * or if LCP is in the LS_OPENED state.
01073  *
01074  * Returns:
01075  *  0 - Reject was bad.
01076  *  1 - Reject was good.
01077  */
01078 static int
01079 lcp_rejci(fsm *f, u_char *p, int len)
01080 {
01081   lcp_options *go = &lcp_gotoptions[f->unit];
01082   u_char cichar;
01083   u_short cishort;
01084   u32_t cilong;
01085   lcp_options try; /* options to request next time */
01086 
01087   try = *go;
01088 
01089   /*
01090    * Any Rejected CIs must be in exactly the same order that we sent.
01091    * Check packet length and CI length at each step.
01092    * If we find any deviations, then this packet is bad.
01093    */
01094 #define REJCIVOID(opt, neg) \
01095   if (go->neg && \
01096       len >= CILEN_VOID && \
01097       p[1] == CILEN_VOID && \
01098       p[0] == opt) { \
01099     len -= CILEN_VOID; \
01100     INCPTR(CILEN_VOID, p); \
01101     try.neg = 0; \
01102     LCPDEBUG(LOG_INFO, ("lcp_rejci: void opt %d rejected\n", opt)); \
01103   }
01104 #define REJCISHORT(opt, neg, val) \
01105   if (go->neg && \
01106       len >= CILEN_SHORT && \
01107       p[1] == CILEN_SHORT && \
01108       p[0] == opt) { \
01109     len -= CILEN_SHORT; \
01110     INCPTR(2, p); \
01111     GETSHORT(cishort, p); \
01112     /* Check rejected value. */ \
01113     if (cishort != val) { \
01114       goto bad; \
01115     } \
01116     try.neg = 0; \
01117     LCPDEBUG(LOG_INFO, ("lcp_rejci: short opt %d rejected\n", opt)); \
01118   }
01119 #define REJCICHAP(opt, neg, val, digest) \
01120   if (go->neg && \
01121       len >= CILEN_CHAP && \
01122       p[1] == CILEN_CHAP && \
01123       p[0] == opt) { \
01124     len -= CILEN_CHAP; \
01125     INCPTR(2, p); \
01126     GETSHORT(cishort, p); \
01127     GETCHAR(cichar, p); \
01128     /* Check rejected value. */ \
01129     if (cishort != val || cichar != digest) { \
01130       goto bad; \
01131     } \
01132     try.neg = 0; \
01133     try.neg_upap = 0; \
01134     LCPDEBUG(LOG_INFO, ("lcp_rejci: chap opt %d rejected\n", opt)); \
01135   }
01136 #define REJCILONG(opt, neg, val) \
01137   if (go->neg && \
01138       len >= CILEN_LONG && \
01139       p[1] == CILEN_LONG && \
01140       p[0] == opt) { \
01141     len -= CILEN_LONG; \
01142     INCPTR(2, p); \
01143     GETLONG(cilong, p); \
01144     /* Check rejected value. */ \
01145     if (cilong != val) { \
01146       goto bad; \
01147     } \
01148     try.neg = 0; \
01149     LCPDEBUG(LOG_INFO, ("lcp_rejci: long opt %d rejected\n", opt)); \
01150   }
01151 #define REJCILQR(opt, neg, val) \
01152   if (go->neg && \
01153       len >= CILEN_LQR && \
01154       p[1] == CILEN_LQR && \
01155       p[0] == opt) { \
01156     len -= CILEN_LQR; \
01157     INCPTR(2, p); \
01158     GETSHORT(cishort, p); \
01159     GETLONG(cilong, p); \
01160     /* Check rejected value. */ \
01161     if (cishort != PPP_LQR || cilong != val) { \
01162       goto bad; \
01163     } \
01164     try.neg = 0; \
01165     LCPDEBUG(LOG_INFO, ("lcp_rejci: LQR opt %d rejected\n", opt)); \
01166   }
01167 #define REJCICBCP(opt, neg, val) \
01168   if (go->neg && \
01169       len >= CILEN_CBCP && \
01170       p[1] == CILEN_CBCP && \
01171       p[0] == opt) { \
01172     len -= CILEN_CBCP; \
01173     INCPTR(2, p); \
01174     GETCHAR(cichar, p); \
01175     /* Check rejected value. */ \
01176     if (cichar != val) { \
01177       goto bad; \
01178     } \
01179     try.neg = 0; \
01180     LCPDEBUG(LOG_INFO, ("lcp_rejci: Callback opt %d rejected\n", opt)); \
01181   }
01182   
01183   REJCISHORT(CI_MRU, neg_mru, go->mru);
01184   REJCILONG(CI_ASYNCMAP, neg_asyncmap, go->asyncmap);
01185   REJCICHAP(CI_AUTHTYPE, neg_chap, PPP_CHAP, go->chap_mdtype);
01186   if (!go->neg_chap) {
01187     REJCISHORT(CI_AUTHTYPE, neg_upap, PPP_PAP);
01188   }
01189   REJCILQR(CI_QUALITY, neg_lqr, go->lqr_period);
01190   REJCICBCP(CI_CALLBACK, neg_cbcp, CBCP_OPT);
01191   REJCILONG(CI_MAGICNUMBER, neg_magicnumber, go->magicnumber);
01192   REJCIVOID(CI_PCOMPRESSION, neg_pcompression);
01193   REJCIVOID(CI_ACCOMPRESSION, neg_accompression);
01194   
01195   /*
01196    * If there are any remaining CIs, then this packet is bad.
01197    */
01198   if (len != 0) {
01199     goto bad;
01200   }
01201   /*
01202    * Now we can update state.
01203    */
01204   if (f->state != LS_OPENED) {
01205     *go = try;
01206   }
01207   return 1;
01208   
01209 bad:
01210   LCPDEBUG(LOG_WARNING, ("lcp_rejci: received bad Reject!\n"));
01211   return 0;
01212 }
01213 
01214 
01215 /*
01216  * lcp_reqci - Check the peer's requested CIs and send appropriate response.
01217  *
01218  * Returns: CONFACK, CONFNAK or CONFREJ and input packet modified
01219  * appropriately.  If reject_if_disagree is non-zero, doesn't return
01220  * CONFNAK; returns CONFREJ if it can't return CONFACK.
01221  */
01222 static int
01223 lcp_reqci(fsm *f, 
01224           u_char *inp,    /* Requested CIs */
01225           int *lenp,      /* Length of requested CIs */
01226           int reject_if_disagree)
01227 {
01228   lcp_options *go = &lcp_gotoptions[f->unit];
01229   lcp_options *ho = &lcp_hisoptions[f->unit];
01230   lcp_options *ao = &lcp_allowoptions[f->unit];
01231   u_char *cip, *next;         /* Pointer to current and next CIs */
01232   int cilen, citype;          /* Parsed len, type */
01233   u_char cichar;              /* Parsed char value */
01234   u_short cishort;            /* Parsed short value */
01235   u32_t cilong;               /* Parse long value */
01236   int rc = CONFACK;           /* Final packet return code */
01237   int orc;                    /* Individual option return code */
01238   u_char *p;                  /* Pointer to next char to parse */
01239   u_char *rejp;               /* Pointer to next char in reject frame */
01240   u_char *nakp;               /* Pointer to next char in Nak frame */
01241   int l = *lenp;              /* Length left */
01242 #if TRACELCP > 0
01243   char traceBuf[80];
01244   size_t traceNdx = 0;
01245 #endif
01246 
01247   /*
01248    * Reset all his options.
01249    */
01250   BZERO(ho, sizeof(*ho));
01251 
01252   /*
01253    * Process all his options.
01254    */
01255   next = inp;
01256   nakp = nak_buffer;
01257   rejp = inp;
01258   while (l) {
01259     orc = CONFACK;      /* Assume success */
01260     cip = p = next;     /* Remember begining of CI */
01261     if (l < 2 ||        /* Not enough data for CI header or */
01262         p[1] < 2 ||     /*  CI length too small or */
01263         p[1] > l) {     /*  CI length too big? */
01264       LCPDEBUG(LOG_WARNING, ("lcp_reqci: bad CI length!\n"));
01265       orc = CONFREJ;    /* Reject bad CI */
01266       cilen = l;        /* Reject till end of packet */
01267       l = 0;            /* Don't loop again */
01268       citype = 0;
01269       goto endswitch;
01270     }
01271     GETCHAR(citype, p); /* Parse CI type */
01272     GETCHAR(cilen, p);  /* Parse CI length */
01273     l -= cilen;         /* Adjust remaining length */
01274     next += cilen;      /* Step to next CI */
01275 
01276     switch (citype) {   /* Check CI type */
01277       case CI_MRU:
01278         if (!ao->neg_mru) {    /* Allow option? */
01279           LCPDEBUG(LOG_INFO, ("lcp_reqci: Reject MRU - not allowed\n"));
01280           orc = CONFREJ;    /* Reject CI */
01281           break;
01282         } else if (cilen != CILEN_SHORT) {  /* Check CI length */
01283           LCPDEBUG(LOG_INFO, ("lcp_reqci: Reject MRU - bad length\n"));
01284           orc = CONFREJ;    /* Reject CI */
01285           break;
01286         }
01287         GETSHORT(cishort, p);  /* Parse MRU */
01288 
01289         /*
01290          * He must be able to receive at least our minimum.
01291          * No need to check a maximum.  If he sends a large number,
01292          * we'll just ignore it.
01293          */
01294         if (cishort < PPP_MINMRU) {
01295           LCPDEBUG(LOG_INFO, ("lcp_reqci: Nak - MRU too small\n"));
01296           orc = CONFNAK;    /* Nak CI */
01297           PUTCHAR(CI_MRU, nakp);
01298           PUTCHAR(CILEN_SHORT, nakp);
01299           PUTSHORT(PPP_MINMRU, nakp);  /* Give him a hint */
01300           break;
01301         }
01302         ho->neg_mru = 1;    /* Remember he sent MRU */
01303         ho->mru = cishort;    /* And remember value */
01304 #if TRACELCP > 0
01305         snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " MRU %d", cishort);
01306         traceNdx = strlen(traceBuf);
01307 #endif
01308         break;
01309 
01310       case CI_ASYNCMAP:
01311         if (!ao->neg_asyncmap) {
01312           LCPDEBUG(LOG_INFO, ("lcp_reqci: Reject ASYNCMAP not allowed\n"));
01313           orc = CONFREJ;
01314           break;
01315         } else if (cilen != CILEN_LONG) {
01316           LCPDEBUG(LOG_INFO, ("lcp_reqci: Reject ASYNCMAP bad length\n"));
01317           orc = CONFREJ;
01318           break;
01319         }
01320         GETLONG(cilong, p);
01321         
01322         /*
01323          * Asyncmap must have set at least the bits
01324          * which are set in lcp_allowoptions[unit].asyncmap.
01325          */
01326         if ((ao->asyncmap & ~cilong) != 0) {
01327           LCPDEBUG(LOG_INFO, ("lcp_reqci: Nak ASYNCMAP %lX missing %lX\n", 
01328                     cilong, ao->asyncmap));
01329           orc = CONFNAK;
01330           PUTCHAR(CI_ASYNCMAP, nakp);
01331           PUTCHAR(CILEN_LONG, nakp);
01332           PUTLONG(ao->asyncmap | cilong, nakp);
01333           break;
01334         }
01335         ho->neg_asyncmap = 1;
01336         ho->asyncmap = cilong;
01337 #if TRACELCP > 0
01338         snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " ASYNCMAP=%lX", cilong);
01339         traceNdx = strlen(traceBuf);
01340 #endif
01341         break;
01342 
01343       case CI_AUTHTYPE:
01344         if (cilen < CILEN_SHORT) {
01345           LCPDEBUG(LOG_INFO, ("lcp_reqci: Reject AUTHTYPE missing arg\n"));
01346           orc = CONFREJ;
01347           break;
01348         } else if (!(ao->neg_upap || ao->neg_chap)) {
01349           /*
01350            * Reject the option if we're not willing to authenticate.
01351            */
01352           LCPDEBUG(LOG_INFO, ("lcp_reqci: Reject AUTHTYPE not allowed\n"));
01353           orc = CONFREJ;
01354           break;
01355         }
01356         GETSHORT(cishort, p);
01357         
01358         /*
01359          * Authtype must be UPAP or CHAP.
01360          *
01361          * Note: if both ao->neg_upap and ao->neg_chap are set,
01362          * and the peer sends a Configure-Request with two
01363          * authenticate-protocol requests, one for CHAP and one
01364          * for UPAP, then we will reject the second request.
01365          * Whether we end up doing CHAP or UPAP depends then on
01366          * the ordering of the CIs in the peer's Configure-Request.
01367          */
01368         
01369         if (cishort == PPP_PAP) {
01370           if (ho->neg_chap) {  /* we've already accepted CHAP */
01371             LCPDEBUG(LOG_WARNING, ("lcp_reqci: Reject AUTHTYPE PAP already accepted\n"));
01372             orc = CONFREJ;
01373             break;
01374           } else if (cilen != CILEN_SHORT) {
01375             LCPDEBUG(LOG_WARNING, ("lcp_reqci: Reject AUTHTYPE PAP bad len\n"));
01376             orc = CONFREJ;
01377             break;
01378           }
01379           if (!ao->neg_upap) {  /* we don't want to do PAP */
01380             LCPDEBUG(LOG_WARNING, ("lcp_reqci: Nak AUTHTYPE PAP not allowed\n"));
01381             orc = CONFNAK;  /* NAK it and suggest CHAP */
01382             PUTCHAR(CI_AUTHTYPE, nakp);
01383             PUTCHAR(CILEN_CHAP, nakp);
01384             PUTSHORT(PPP_CHAP, nakp);
01385             PUTCHAR(ao->chap_mdtype, nakp);
01386             break;
01387           }
01388           ho->neg_upap = 1;
01389 #if TRACELCP > 0
01390           snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " PAP (%X)", cishort);
01391           traceNdx = strlen(traceBuf);
01392 #endif
01393           break;
01394         }
01395         if (cishort == PPP_CHAP) {
01396           if (ho->neg_upap) {  /* we've already accepted PAP */
01397             LCPDEBUG(LOG_WARNING, ("lcp_reqci: Reject AUTHTYPE CHAP accepted PAP\n"));
01398             orc = CONFREJ;
01399             break;
01400           } else if (cilen != CILEN_CHAP) {
01401             LCPDEBUG(LOG_WARNING, ("lcp_reqci: Reject AUTHTYPE CHAP bad len\n"));
01402             orc = CONFREJ;
01403             break;
01404           }
01405           if (!ao->neg_chap) {  /* we don't want to do CHAP */
01406             LCPDEBUG(LOG_WARNING, ("lcp_reqci: Nak AUTHTYPE CHAP not allowed\n"));
01407             orc = CONFNAK;  /* NAK it and suggest PAP */
01408             PUTCHAR(CI_AUTHTYPE, nakp);
01409             PUTCHAR(CILEN_SHORT, nakp);
01410             PUTSHORT(PPP_PAP, nakp);
01411             break;
01412           }
01413           GETCHAR(cichar, p);  /* get digest type*/
01414           if (cichar != CHAP_DIGEST_MD5
01415 #if MSCHAP_SUPPORT
01416               && cichar != CHAP_MICROSOFT
01417 #endif
01418           ) {
01419             LCPDEBUG(LOG_WARNING, ("lcp_reqci: Nak AUTHTYPE CHAP digest=%d\n", (int)cichar));
01420             orc = CONFNAK;
01421             PUTCHAR(CI_AUTHTYPE, nakp);
01422             PUTCHAR(CILEN_CHAP, nakp);
01423             PUTSHORT(PPP_CHAP, nakp);
01424             PUTCHAR(ao->chap_mdtype, nakp);
01425             break;
01426           }
01427 #if TRACELCP > 0
01428           snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " CHAP %X,%d", cishort, (int)cichar);
01429           traceNdx = strlen(traceBuf);
01430 #endif
01431           ho->chap_mdtype = cichar; /* save md type */
01432           ho->neg_chap = 1;
01433           break;
01434         }
01435         
01436         /*
01437          * We don't recognize the protocol they're asking for.
01438          * Nak it with something we're willing to do.
01439          * (At this point we know ao->neg_upap || ao->neg_chap.)
01440          */
01441         orc = CONFNAK;
01442         PUTCHAR(CI_AUTHTYPE, nakp);
01443         if (ao->neg_chap) {
01444           LCPDEBUG(LOG_WARNING, ("lcp_reqci: Nak AUTHTYPE %d req CHAP\n", cishort));
01445           PUTCHAR(CILEN_CHAP, nakp);
01446           PUTSHORT(PPP_CHAP, nakp);
01447           PUTCHAR(ao->chap_mdtype, nakp);
01448         } else {
01449           LCPDEBUG(LOG_WARNING, ("lcp_reqci: Nak AUTHTYPE %d req PAP\n", cishort));
01450           PUTCHAR(CILEN_SHORT, nakp);
01451           PUTSHORT(PPP_PAP, nakp);
01452         }
01453         break;
01454       
01455       case CI_QUALITY:
01456         GETSHORT(cishort, p);
01457         GETLONG(cilong, p);
01458 #if TRACELCP > 0
01459         snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " QUALITY (%x %x)", cishort, (unsigned int) cilong);
01460         traceNdx = strlen(traceBuf);
01461 #endif
01462 
01463         if (!ao->neg_lqr ||
01464             cilen != CILEN_LQR) {
01465           orc = CONFREJ;
01466           break;
01467         }
01468         
01469         /*
01470          * Check the protocol and the reporting period.
01471          * XXX When should we Nak this, and what with?
01472          */
01473         if (cishort != PPP_LQR) {
01474           orc = CONFNAK;
01475           PUTCHAR(CI_QUALITY, nakp);
01476           PUTCHAR(CILEN_LQR, nakp);
01477           PUTSHORT(PPP_LQR, nakp);
01478           PUTLONG(ao->lqr_period, nakp);
01479           break;
01480         }
01481         break;
01482       
01483       case CI_MAGICNUMBER:
01484         if (!(ao->neg_magicnumber || go->neg_magicnumber) ||
01485             cilen != CILEN_LONG) {
01486           orc = CONFREJ;
01487           break;
01488         }
01489         GETLONG(cilong, p);
01490 #if TRACELCP > 0
01491         snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " MAGICNUMBER (%lX)", cilong);
01492         traceNdx = strlen(traceBuf);
01493 #endif
01494 
01495         /*
01496          * He must have a different magic number.
01497          */
01498         if (go->neg_magicnumber &&
01499             cilong == go->magicnumber) {
01500           cilong = magic();  /* Don't put magic() inside macro! */
01501           orc = CONFNAK;
01502           PUTCHAR(CI_MAGICNUMBER, nakp);
01503           PUTCHAR(CILEN_LONG, nakp);
01504           PUTLONG(cilong, nakp);
01505           break;
01506         }
01507         ho->neg_magicnumber = 1;
01508         ho->magicnumber = cilong;
01509         break;
01510       
01511       
01512       case CI_PCOMPRESSION:
01513 #if TRACELCP > 0
01514         snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " PCOMPRESSION");
01515         traceNdx = strlen(traceBuf);
01516 #endif
01517         if (!ao->neg_pcompression ||
01518             cilen != CILEN_VOID) {
01519           orc = CONFREJ;
01520           break;
01521         }
01522         ho->neg_pcompression = 1;
01523         break;
01524       
01525       case CI_ACCOMPRESSION:
01526 #if TRACELCP > 0
01527         snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " ACCOMPRESSION");
01528         traceNdx = strlen(traceBuf);
01529 #endif
01530         if (!ao->neg_accompression ||
01531             cilen != CILEN_VOID) {
01532           orc = CONFREJ;
01533           break;
01534         }
01535         ho->neg_accompression = 1;
01536         break;
01537       
01538       case CI_MRRU:
01539 #if TRACELCP > 0
01540         snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " CI_MRRU");
01541         traceNdx = strlen(traceBuf);
01542 #endif
01543         orc = CONFREJ;
01544         break;
01545       
01546       case CI_SSNHF:
01547 #if TRACELCP > 0
01548         snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " CI_SSNHF");
01549         traceNdx = strlen(traceBuf);
01550 #endif
01551         orc = CONFREJ;
01552         break;
01553       
01554       case CI_EPDISC:
01555 #if TRACELCP > 0
01556         snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " CI_EPDISC");
01557         traceNdx = strlen(traceBuf);
01558 #endif
01559         orc = CONFREJ;
01560         break;
01561       
01562       default:
01563 #if TRACELCP
01564         snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " unknown %d", citype);
01565         traceNdx = strlen(traceBuf);
01566 #endif
01567         orc = CONFREJ;
01568         break;
01569     }
01570 
01571   endswitch:
01572 #if TRACELCP
01573     if (traceNdx >= 80 - 32) {
01574       LCPDEBUG(LOG_INFO, ("lcp_reqci: rcvd%s\n", traceBuf));
01575       traceNdx = 0;
01576     }
01577 #endif
01578     if (orc == CONFACK && /* Good CI */
01579         rc != CONFACK) {  /*  but prior CI wasnt? */
01580       continue;           /* Don't send this one */
01581     }
01582 
01583     if (orc == CONFNAK) {     /* Nak this CI? */
01584       if (reject_if_disagree  /* Getting fed up with sending NAKs? */
01585           && citype != CI_MAGICNUMBER) {
01586         orc = CONFREJ;        /* Get tough if so */
01587       } else {
01588         if (rc == CONFREJ) {  /* Rejecting prior CI? */
01589           continue;           /* Don't send this one */
01590         }
01591         rc = CONFNAK;
01592       }
01593     }
01594     if (orc == CONFREJ) {        /* Reject this CI */
01595       rc = CONFREJ;
01596       if (cip != rejp) {         /* Need to move rejected CI? */
01597         BCOPY(cip, rejp, cilen); /* Move it */
01598       }
01599       INCPTR(cilen, rejp);       /* Update output pointer */
01600     }
01601   }
01602 
01603   /*
01604    * If we wanted to send additional NAKs (for unsent CIs), the
01605    * code would go here.  The extra NAKs would go at *nakp.
01606    * At present there are no cases where we want to ask the
01607    * peer to negotiate an option.
01608    */
01609 
01610   switch (rc) {
01611     case CONFACK:
01612       *lenp = (int)(next - inp);
01613       break;
01614     case CONFNAK:
01615       /*
01616        * Copy the Nak'd options from the nak_buffer to the caller's buffer.
01617        */
01618       *lenp = (int)(nakp - nak_buffer);
01619       BCOPY(nak_buffer, inp, *lenp);
01620       break;
01621     case CONFREJ:
01622       *lenp = (int)(rejp - inp);
01623       break;
01624   }
01625 
01626 #if TRACELCP > 0
01627   if (traceNdx > 0) {
01628     LCPDEBUG(LOG_INFO, ("lcp_reqci: %s\n", traceBuf));
01629   }
01630 #endif
01631   LCPDEBUG(LOG_INFO, ("lcp_reqci: returning CONF%s.\n", CODENAME(rc)));
01632   return (rc);      /* Return final code */
01633 }
01634 
01635 
01636 /*
01637  * lcp_up - LCP has come UP.
01638  */
01639 static void
01640 lcp_up(fsm *f)
01641 {
01642   lcp_options *wo = &lcp_wantoptions[f->unit];
01643   lcp_options *ho = &lcp_hisoptions[f->unit];
01644   lcp_options *go = &lcp_gotoptions[f->unit];
01645   lcp_options *ao = &lcp_allowoptions[f->unit];
01646 
01647   if (!go->neg_magicnumber) {
01648     go->magicnumber = 0;
01649   }
01650   if (!ho->neg_magicnumber) {
01651     ho->magicnumber = 0;
01652   }
01653 
01654   /*
01655    * Set our MTU to the smaller of the MTU we wanted and
01656    * the MRU our peer wanted.  If we negotiated an MRU,
01657    * set our MRU to the larger of value we wanted and
01658    * the value we got in the negotiation.
01659    */
01660   ppp_send_config(f->unit, LWIP_MIN(ao->mru, (ho->neg_mru? ho->mru: PPP_MRU)),
01661                  (ho->neg_asyncmap? ho->asyncmap: 0xffffffffl),
01662                   ho->neg_pcompression, ho->neg_accompression);
01663   /*
01664    * If the asyncmap hasn't been negotiated, we really should
01665    * set the receive asyncmap to ffffffff, but we set it to 0
01666    * for backwards contemptibility.
01667    */
01668   ppp_recv_config(f->unit, (go->neg_mru? LWIP_MAX(wo->mru, go->mru): PPP_MRU),
01669                  (go->neg_asyncmap? go->asyncmap: 0x00000000),
01670                   go->neg_pcompression, go->neg_accompression);
01671 
01672   if (ho->neg_mru) {
01673     peer_mru[f->unit] = ho->mru;
01674   }
01675 
01676   lcp_echo_lowerup(f->unit); /* Enable echo messages */
01677 
01678   link_established(f->unit); /* The link is up; authenticate now */
01679 }
01680 
01681 
01682 /*
01683  * lcp_down - LCP has gone DOWN.
01684  *
01685  * Alert other protocols.
01686  */
01687 static void
01688 lcp_down(fsm *f)
01689 {
01690   lcp_options *go = &lcp_gotoptions[f->unit];
01691 
01692   lcp_echo_lowerdown(f->unit);
01693 
01694   link_down(f->unit);
01695 
01696   ppp_send_config(f->unit, PPP_MRU, 0xffffffffl, 0, 0);
01697   ppp_recv_config(f->unit, PPP_MRU,
01698                   (go->neg_asyncmap? go->asyncmap: 0x00000000),
01699                    go->neg_pcompression, go->neg_accompression);
01700   peer_mru[f->unit] = PPP_MRU;
01701 }
01702 
01703 
01704 /*
01705  * lcp_starting - LCP needs the lower layer up.
01706  */
01707 static void
01708 lcp_starting(fsm *f)
01709 {
01710   link_required(f->unit); /* lwip: currently does nothing */
01711 }
01712 
01713 
01714 /*
01715  * lcp_finished - LCP has finished with the lower layer.
01716  */
01717 static void
01718 lcp_finished(fsm *f)
01719 {
01720   link_terminated(f->unit); /* we are finished with the link */
01721 }
01722 
01723 
01724 #if PPP_ADDITIONAL_CALLBACKS
01725 /*
01726  * print_string - print a readable representation of a string using
01727  * printer.
01728  */
01729 static void
01730 print_string( char *p, int len, void (*printer) (void *, char *, ...), void *arg)
01731 {
01732   int c;
01733   
01734   printer(arg, "\"");
01735   for (; len > 0; --len) {
01736     c = *p++;
01737     if (' ' <= c && c <= '~') {
01738         if (c == '\\' || c == '"') {
01739           printer(arg, "\\");
01740         }
01741         printer(arg, "%c", c);
01742     } else {
01743       switch (c) {
01744         case '\n':
01745           printer(arg, "\\n");
01746           break;
01747         case '\r':
01748           printer(arg, "\\r");
01749           break;
01750         case '\t':
01751           printer(arg, "\\t");
01752           break;
01753         default:
01754           printer(arg, "\\%.3o", c);
01755         }
01756     }
01757   }
01758   printer(arg, "\"");
01759 }
01760 
01761 
01762 /*
01763  * lcp_printpkt - print the contents of an LCP packet.
01764  */
01765 static char *lcp_codenames[] = {
01766   "ConfReq", "ConfAck", "ConfNak", "ConfRej",
01767   "TermReq", "TermAck", "CodeRej", "ProtRej",
01768   "EchoReq", "EchoRep", "DiscReq"
01769 };
01770 
01771 static int
01772 lcp_printpkt( u_char *p, int plen, void (*printer) (void *, char *, ...), void *arg)
01773 {
01774   int code, id, len, olen;
01775   u_char *pstart, *optend;
01776   u_short cishort;
01777   u32_t cilong;
01778 
01779   if (plen < HEADERLEN) {
01780     return 0;
01781   }
01782   pstart = p;
01783   GETCHAR(code, p);
01784   GETCHAR(id, p);
01785   GETSHORT(len, p);
01786   if (len < HEADERLEN || len > plen) {
01787     return 0;
01788   }
01789 
01790   if (code >= 1 && code <= sizeof(lcp_codenames) / sizeof(char *)) {
01791     printer(arg, " %s", lcp_codenames[code-1]);
01792   } else {
01793     printer(arg, " code=0x%x", code);
01794   }
01795   printer(arg, " id=0x%x", id);
01796   len -= HEADERLEN;
01797   switch (code) {
01798     case CONFREQ:
01799     case CONFACK:
01800     case CONFNAK:
01801     case CONFREJ:
01802       /* print option list */
01803       while (len >= 2) {
01804         GETCHAR(code, p);
01805         GETCHAR(olen, p);
01806         p -= 2;
01807         if (olen < 2 || olen > len) {
01808           break;
01809         }
01810         printer(arg, " <");
01811         len -= olen;
01812         optend = p + olen;
01813         switch (code) {
01814           case CI_MRU:
01815             if (olen == CILEN_SHORT) {
01816               p += 2;
01817               GETSHORT(cishort, p);
01818               printer(arg, "mru %d", cishort);
01819             }
01820             break;
01821           case CI_ASYNCMAP:
01822             if (olen == CILEN_LONG) {
01823               p += 2;
01824               GETLONG(cilong, p);
01825               printer(arg, "asyncmap 0x%lx", cilong);
01826             }
01827             break;
01828           case CI_AUTHTYPE:
01829             if (olen >= CILEN_SHORT) {
01830               p += 2;
01831               printer(arg, "auth ");
01832               GETSHORT(cishort, p);
01833               switch (cishort) {
01834                 case PPP_PAP:
01835                   printer(arg, "pap");
01836                   break;
01837                 case PPP_CHAP:
01838                   printer(arg, "chap");
01839                   break;
01840                 default:
01841                   printer(arg, "0x%x", cishort);
01842               }
01843             }
01844             break;
01845           case CI_QUALITY:
01846             if (olen >= CILEN_SHORT) {
01847               p += 2;
01848               printer(arg, "quality ");
01849               GETSHORT(cishort, p);
01850               switch (cishort) {
01851                 case PPP_LQR:
01852                   printer(arg, "lqr");
01853                   break;
01854                 default:
01855                   printer(arg, "0x%x", cishort);
01856               }
01857             }
01858             break;
01859           case CI_CALLBACK:
01860             if (olen >= CILEN_CHAR) {
01861               p += 2;
01862               printer(arg, "callback ");
01863               GETSHORT(cishort, p);
01864               switch (cishort) {
01865                 case CBCP_OPT:
01866                   printer(arg, "CBCP");
01867                   break;
01868                 default:
01869                   printer(arg, "0x%x", cishort);
01870               }
01871             }
01872             break;
01873           case CI_MAGICNUMBER:
01874             if (olen == CILEN_LONG) {
01875               p += 2;
01876               GETLONG(cilong, p);
01877               printer(arg, "magic 0x%x", cilong);
01878             }
01879             break;
01880           case CI_PCOMPRESSION:
01881             if (olen == CILEN_VOID) {
01882               p += 2;
01883               printer(arg, "pcomp");
01884             }
01885             break;
01886           case CI_ACCOMPRESSION:
01887             if (olen == CILEN_VOID) {
01888               p += 2;
01889               printer(arg, "accomp");
01890             }
01891             break;
01892         }
01893         while (p < optend) {
01894           GETCHAR(code, p);
01895           printer(arg, " %.2x", code);
01896         }
01897         printer(arg, ">");
01898       }
01899       break;
01900     
01901     case TERMACK:
01902     case TERMREQ:
01903       if (len > 0 && *p >= ' ' && *p < 0x7f) {
01904         printer(arg, " ");
01905         print_string((char*)p, len, printer, arg);
01906         p += len;
01907         len = 0;
01908       }
01909       break;
01910     
01911     case ECHOREQ:
01912     case ECHOREP:
01913     case DISCREQ:
01914       if (len >= 4) {
01915         GETLONG(cilong, p);
01916         printer(arg, " magic=0x%x", cilong);
01917         p += 4;
01918         len -= 4;
01919       }
01920       break;
01921   }
01922 
01923   /* print the rest of the bytes in the packet */
01924   for (; len > 0; --len) {
01925     GETCHAR(code, p);
01926     printer(arg, " %.2x", code);
01927   }
01928 
01929   return (int)(p - pstart);
01930 }
01931 #endif /* PPP_ADDITIONAL_CALLBACKS */
01932 
01933 /*
01934  * Time to shut down the link because there is nothing out there.
01935  */
01936 static void
01937 LcpLinkFailure (fsm *f)
01938 {
01939   if (f->state == LS_OPENED) {
01940     LCPDEBUG(LOG_INFO, ("No response to %d echo-requests\n", lcp_echos_pending));
01941     LCPDEBUG(LOG_NOTICE, ("Serial link appears to be disconnected.\n"));
01942     lcp_close(f->unit, "Peer not responding");
01943   }
01944 }
01945 
01946 /*
01947  * Timer expired for the LCP echo requests from this process.
01948  */
01949 static void
01950 LcpEchoCheck (fsm *f)
01951 {
01952   LcpSendEchoRequest (f);
01953 
01954   /*
01955    * Start the timer for the next interval.
01956    */
01957   LWIP_ASSERT("lcp_echo_timer_running == 0", lcp_echo_timer_running == 0);
01958 
01959   TIMEOUT (LcpEchoTimeout, f, lcp_echo_interval);
01960   lcp_echo_timer_running = 1;
01961 }
01962 
01963 /*
01964  * LcpEchoTimeout - Timer expired on the LCP echo
01965  */
01966 static void
01967 LcpEchoTimeout (void *arg)
01968 {
01969   if (lcp_echo_timer_running != 0) {
01970     lcp_echo_timer_running = 0;
01971     LcpEchoCheck ((fsm *) arg);
01972   }
01973 }
01974 
01975 /*
01976  * LcpEchoReply - LCP has received a reply to the echo
01977  */
01978 static void
01979 lcp_received_echo_reply (fsm *f, int id, u_char *inp, int len)
01980 {
01981   u32_t magic;
01982 
01983   LWIP_UNUSED_ARG(id);
01984 
01985   /* Check the magic number - don't count replies from ourselves. */
01986   if (len < 4) {
01987     LCPDEBUG(LOG_WARNING, ("lcp: received short Echo-Reply, length %d\n", len));
01988     return;
01989   }
01990   GETLONG(magic, inp);
01991   if (lcp_gotoptions[f->unit].neg_magicnumber && magic == lcp_gotoptions[f->unit].magicnumber) {
01992     LCPDEBUG(LOG_WARNING, ("appear to have received our own echo-reply!\n"));
01993     return;
01994   }
01995 
01996   /* Reset the number of outstanding echo frames */
01997   lcp_echos_pending = 0;
01998 }
01999 
02000 /*
02001  * LcpSendEchoRequest - Send an echo request frame to the peer
02002  */
02003 static void
02004 LcpSendEchoRequest (fsm *f)
02005 {
02006   u32_t lcp_magic;
02007   u_char pkt[4], *pktp;
02008 
02009   /*
02010    * Detect the failure of the peer at this point.
02011    */
02012   if (lcp_echo_fails != 0) {
02013     if (lcp_echos_pending++ >= lcp_echo_fails) {
02014       LcpLinkFailure(f);
02015       lcp_echos_pending = 0;
02016     }
02017   }
02018 
02019   /*
02020    * Make and send the echo request frame.
02021    */
02022   if (f->state == LS_OPENED) {
02023     lcp_magic = lcp_gotoptions[f->unit].magicnumber;
02024     pktp = pkt;
02025     PUTLONG(lcp_magic, pktp);
02026     fsm_sdata(f, ECHOREQ, (u_char)(lcp_echo_number++ & 0xFF), pkt, (int)(pktp - pkt));
02027   }
02028 }
02029 
02030 /*
02031  * lcp_echo_lowerup - Start the timer for the LCP frame
02032  */
02033 
02034 static void
02035 lcp_echo_lowerup (int unit)
02036 {
02037   fsm *f = &lcp_fsm[unit];
02038 
02039   /* Clear the parameters for generating echo frames */
02040   lcp_echos_pending      = 0;
02041   lcp_echo_number        = 0;
02042   lcp_echo_timer_running = 0;
02043 
02044   /* If a timeout interval is specified then start the timer */
02045   if (lcp_echo_interval != 0) {
02046     LcpEchoCheck (f);
02047   }
02048 }
02049 
02050 /*
02051  * lcp_echo_lowerdown - Stop the timer for the LCP frame
02052  */
02053 
02054 static void
02055 lcp_echo_lowerdown (int unit)
02056 {
02057   fsm *f = &lcp_fsm[unit];
02058 
02059   if (lcp_echo_timer_running != 0) {
02060     UNTIMEOUT (LcpEchoTimeout, f);
02061     lcp_echo_timer_running = 0;
02062   }
02063 }
02064 
02065 #endif /* PPP_SUPPORT */