ON Semiconductor / mbed-os

Dependents:   mbed-TFT-example-NCS36510 mbed-Accelerometer-example-NCS36510 mbed-Accelerometer-example-NCS36510

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers lwip_lcp.c Source File

lwip_lcp.c

00001 /*
00002  * lcp.c - PPP Link Control Protocol.
00003  *
00004  * Copyright (c) 1984-2000 Carnegie Mellon University. All rights reserved.
00005  *
00006  * Redistribution and use in source and binary forms, with or without
00007  * modification, are permitted provided that the following conditions
00008  * are met:
00009  *
00010  * 1. Redistributions of source code must retain the above copyright
00011  *    notice, this list of conditions and the following disclaimer.
00012  *
00013  * 2. Redistributions in binary form must reproduce the above copyright
00014  *    notice, this list of conditions and the following disclaimer in
00015  *    the documentation and/or other materials provided with the
00016  *    distribution.
00017  *
00018  * 3. The name "Carnegie Mellon University" must not be used to
00019  *    endorse or promote products derived from this software without
00020  *    prior written permission. For permission or any legal
00021  *    details, please contact
00022  *      Office of Technology Transfer
00023  *      Carnegie Mellon University
00024  *      5000 Forbes Avenue
00025  *      Pittsburgh, PA  15213-3890
00026  *      (412) 268-4387, fax: (412) 268-7395
00027  *      tech-transfer@andrew.cmu.edu
00028  *
00029  * 4. Redistributions of any form whatsoever must retain the following
00030  *    acknowledgment:
00031  *    "This product includes software developed by Computing Services
00032  *     at Carnegie Mellon University (http://www.cmu.edu/computing/)."
00033  *
00034  * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
00035  * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
00036  * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
00037  * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
00038  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
00039  * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
00040  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
00041  */
00042 
00043 #include "netif/ppp/ppp_opts.h"
00044 #if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */
00045 
00046 /*
00047  * @todo:
00048  */
00049 
00050 #if 0 /* UNUSED */
00051 #include <stdio.h>
00052 #include <string.h>
00053 #include <stdlib.h>
00054 #endif /* UNUSED */
00055 
00056 #include "netif/ppp/ppp_impl.h"
00057 
00058 #include "netif/ppp/fsm.h"
00059 #include "netif/ppp/lcp.h"
00060 #if CHAP_SUPPORT
00061 #include "netif/ppp/chap-new.h"
00062 #endif /* CHAP_SUPPORT */
00063 #include "netif/ppp/magic.h"
00064 
00065 /*
00066  * When the link comes up we want to be able to wait for a short while,
00067  * or until seeing some input from the peer, before starting to send
00068  * configure-requests.  We do this by delaying the fsm_lowerup call.
00069  */
00070 /* steal a bit in fsm flags word */
00071 #define DELAYED_UP  0x80
00072 
00073 static void lcp_delayed_up(void *arg);
00074 
00075 /*
00076  * LCP-related command-line options.
00077  */
00078 #if 0 /* UNUSED */
00079 int lcp_echo_interval = 0;  /* Interval between LCP echo-requests */
00080 int lcp_echo_fails = 0; /* Tolerance to unanswered echo-requests */
00081 #endif /* UNUSED */
00082 
00083 #if 0 /* UNUSED */
00084 /* options */
00085 static u_int lcp_echo_interval      = LCP_ECHOINTERVAL; /* Interval between LCP echo-requests */
00086 static u_int lcp_echo_fails         = LCP_MAXECHOFAILS; /* Tolerance to unanswered echo-requests */
00087 #endif /* UNUSED */
00088 
00089 #if 0 /* UNUSED */
00090 #if PPP_LCP_ADAPTIVE
00091 bool    lcp_echo_adaptive = 0;  /* request echo only if the link was idle */
00092 #endif
00093 bool    lax_recv = 0;       /* accept control chars in asyncmap */
00094 bool    noendpoint = 0;     /* don't send/accept endpoint discriminator */
00095 #endif /* UNUSED */
00096 
00097 #if PPP_OPTIONS
00098 static int noopt (char **);
00099 #endif /* PPP_OPTIONS */
00100 
00101 #ifdef HAVE_MULTILINK
00102 static int setendpoint (char **);
00103 static void printendpoint (option_t *, void (*)(void *, char *, ...),
00104                    void *);
00105 #endif /* HAVE_MULTILINK */
00106 
00107 #if PPP_OPTIONS
00108 static option_t lcp_option_list[] = {
00109     /* LCP options */
00110     { "-all", o_special_noarg, (void *)noopt,
00111       "Don't request/allow any LCP options" },
00112 
00113     { "noaccomp", o_bool, &lcp_wantoptions[0].neg_accompression,
00114       "Disable address/control compression",
00115       OPT_A2CLR, &lcp_allowoptions[0].neg_accompression },
00116     { "-ac", o_bool, &lcp_wantoptions[0].neg_accompression,
00117       "Disable address/control compression",
00118       OPT_ALIAS | OPT_A2CLR, &lcp_allowoptions[0].neg_accompression },
00119 
00120     { "asyncmap", o_uint32, &lcp_wantoptions[0].asyncmap,
00121       "Set asyncmap (for received packets)",
00122       OPT_OR, &lcp_wantoptions[0].neg_asyncmap },
00123     { "-as", o_uint32, &lcp_wantoptions[0].asyncmap,
00124       "Set asyncmap (for received packets)",
00125       OPT_ALIAS | OPT_OR, &lcp_wantoptions[0].neg_asyncmap },
00126     { "default-asyncmap", o_uint32, &lcp_wantoptions[0].asyncmap,
00127       "Disable asyncmap negotiation",
00128       OPT_OR | OPT_NOARG | OPT_VAL(~0U) | OPT_A2CLR,
00129       &lcp_allowoptions[0].neg_asyncmap },
00130     { "-am", o_uint32, &lcp_wantoptions[0].asyncmap,
00131       "Disable asyncmap negotiation",
00132       OPT_ALIAS | OPT_OR | OPT_NOARG | OPT_VAL(~0U) | OPT_A2CLR,
00133       &lcp_allowoptions[0].neg_asyncmap },
00134 
00135     { "nomagic", o_bool, &lcp_wantoptions[0].neg_magicnumber,
00136       "Disable magic number negotiation (looped-back line detection)",
00137       OPT_A2CLR, &lcp_allowoptions[0].neg_magicnumber },
00138     { "-mn", o_bool, &lcp_wantoptions[0].neg_magicnumber,
00139       "Disable magic number negotiation (looped-back line detection)",
00140       OPT_ALIAS | OPT_A2CLR, &lcp_allowoptions[0].neg_magicnumber },
00141 
00142     { "mru", o_int, &lcp_wantoptions[0].mru,
00143       "Set MRU (maximum received packet size) for negotiation",
00144       OPT_PRIO, &lcp_wantoptions[0].neg_mru },
00145     { "default-mru", o_bool, &lcp_wantoptions[0].neg_mru,
00146       "Disable MRU negotiation (use default 1500)",
00147       OPT_PRIOSUB | OPT_A2CLR, &lcp_allowoptions[0].neg_mru },
00148     { "-mru", o_bool, &lcp_wantoptions[0].neg_mru,
00149       "Disable MRU negotiation (use default 1500)",
00150       OPT_ALIAS | OPT_PRIOSUB | OPT_A2CLR, &lcp_allowoptions[0].neg_mru },
00151 
00152     { "mtu", o_int, &lcp_allowoptions[0].mru,
00153       "Set our MTU", OPT_LIMITS, NULL, MAXMRU, MINMRU },
00154 
00155     { "nopcomp", o_bool, &lcp_wantoptions[0].neg_pcompression,
00156       "Disable protocol field compression",
00157       OPT_A2CLR, &lcp_allowoptions[0].neg_pcompression },
00158     { "-pc", o_bool, &lcp_wantoptions[0].neg_pcompression,
00159       "Disable protocol field compression",
00160       OPT_ALIAS | OPT_A2CLR, &lcp_allowoptions[0].neg_pcompression },
00161 
00162     { "passive", o_bool, &lcp_wantoptions[0].passive,
00163       "Set passive mode", 1 },
00164     { "-p", o_bool, &lcp_wantoptions[0].passive,
00165       "Set passive mode", OPT_ALIAS | 1 },
00166 
00167     { "silent", o_bool, &lcp_wantoptions[0].silent,
00168       "Set silent mode", 1 },
00169 
00170     { "lcp-echo-failure", o_int, &lcp_echo_fails,
00171       "Set number of consecutive echo failures to indicate link failure",
00172       OPT_PRIO },
00173     { "lcp-echo-interval", o_int, &lcp_echo_interval,
00174       "Set time in seconds between LCP echo requests", OPT_PRIO },
00175 #if PPP_LCP_ADAPTIVE
00176     { "lcp-echo-adaptive", o_bool, &lcp_echo_adaptive,
00177       "Suppress LCP echo requests if traffic was received", 1 },
00178 #endif
00179     { "lcp-restart", o_int, &lcp_fsm[0].timeouttime,
00180       "Set time in seconds between LCP retransmissions", OPT_PRIO },
00181     { "lcp-max-terminate", o_int, &lcp_fsm[0].maxtermtransmits,
00182       "Set maximum number of LCP terminate-request transmissions", OPT_PRIO },
00183     { "lcp-max-configure", o_int, &lcp_fsm[0].maxconfreqtransmits,
00184       "Set maximum number of LCP configure-request transmissions", OPT_PRIO },
00185     { "lcp-max-failure", o_int, &lcp_fsm[0].maxnakloops,
00186       "Set limit on number of LCP configure-naks", OPT_PRIO },
00187 
00188     { "receive-all", o_bool, &lax_recv,
00189       "Accept all received control characters", 1 },
00190 
00191 #ifdef HAVE_MULTILINK
00192     { "mrru", o_int, &lcp_wantoptions[0].mrru,
00193       "Maximum received packet size for multilink bundle",
00194       OPT_PRIO, &lcp_wantoptions[0].neg_mrru },
00195 
00196     { "mpshortseq", o_bool, &lcp_wantoptions[0].neg_ssnhf,
00197       "Use short sequence numbers in multilink headers",
00198       OPT_PRIO | 1, &lcp_allowoptions[0].neg_ssnhf },
00199     { "nompshortseq", o_bool, &lcp_wantoptions[0].neg_ssnhf,
00200       "Don't use short sequence numbers in multilink headers",
00201       OPT_PRIOSUB | OPT_A2CLR, &lcp_allowoptions[0].neg_ssnhf },
00202 
00203     { "endpoint", o_special, (void *) setendpoint,
00204       "Endpoint discriminator for multilink",
00205       OPT_PRIO | OPT_A2PRINTER, (void *) printendpoint },
00206 #endif /* HAVE_MULTILINK */
00207 
00208     { "noendpoint", o_bool, &noendpoint,
00209       "Don't send or accept multilink endpoint discriminator", 1 },
00210 
00211     {NULL}
00212 };
00213 #endif /* PPP_OPTIONS */
00214 
00215 /*
00216  * Callbacks for fsm code.  (CI = Configuration Information)
00217  */
00218 static void lcp_resetci(fsm *f);    /* Reset our CI */
00219 static int  lcp_cilen(fsm *f);      /* Return length of our CI */
00220 static void lcp_addci(fsm *f, u_char *ucp, int *lenp); /* Add our CI to pkt */
00221 static int  lcp_ackci(fsm *f, u_char *p, int len); /* Peer ack'd our CI */
00222 static int  lcp_nakci(fsm *f, u_char *p, int len, int treat_as_reject); /* Peer nak'd our CI */
00223 static int  lcp_rejci(fsm *f, u_char *p, int len); /* Peer rej'd our CI */
00224 static int  lcp_reqci(fsm *f, u_char *inp, int *lenp, int reject_if_disagree); /* Rcv peer CI */
00225 static void lcp_up(fsm *f);     /* We're UP */
00226 static void lcp_down(fsm *f);       /* We're DOWN */
00227 static void lcp_starting (fsm *);   /* We need lower layer up */
00228 static void lcp_finished (fsm *);   /* We need lower layer down */
00229 static int  lcp_extcode(fsm *f, int code, int id, u_char *inp, int len);
00230 static void lcp_rprotrej(fsm *f, u_char *inp, int len);
00231 
00232 /*
00233  * routines to send LCP echos to peer
00234  */
00235 
00236 static void lcp_echo_lowerup(ppp_pcb *pcb);
00237 static void lcp_echo_lowerdown(ppp_pcb *pcb);
00238 static void LcpEchoTimeout(void *arg);
00239 static void lcp_received_echo_reply(fsm *f, int id, u_char *inp, int len);
00240 static void LcpSendEchoRequest(fsm *f);
00241 static void LcpLinkFailure(fsm *f);
00242 static void LcpEchoCheck(fsm *f);
00243 
00244 static const fsm_callbacks lcp_callbacks = {    /* LCP callback routines */
00245     lcp_resetci,        /* Reset our Configuration Information */
00246     lcp_cilen,          /* Length of our Configuration Information */
00247     lcp_addci,          /* Add our Configuration Information */
00248     lcp_ackci,          /* ACK our Configuration Information */
00249     lcp_nakci,          /* NAK our Configuration Information */
00250     lcp_rejci,          /* Reject our Configuration Information */
00251     lcp_reqci,          /* Request peer's Configuration Information */
00252     lcp_up,         /* Called when fsm reaches OPENED state */
00253     lcp_down,           /* Called when fsm leaves OPENED state */
00254     lcp_starting,       /* Called when we want the lower layer up */
00255     lcp_finished,       /* Called when we want the lower layer down */
00256     NULL,           /* Called when Protocol-Reject received */
00257     NULL,           /* Retransmission is necessary */
00258     lcp_extcode,        /* Called to handle LCP-specific codes */
00259     "LCP"           /* String name of protocol */
00260 };
00261 
00262 /*
00263  * Protocol entry points.
00264  * Some of these are called directly.
00265  */
00266 
00267 static void lcp_init(ppp_pcb *pcb);
00268 static void lcp_input(ppp_pcb *pcb, u_char *p, int len);
00269 static void lcp_protrej(ppp_pcb *pcb);
00270 #if PRINTPKT_SUPPORT
00271 static int lcp_printpkt(const u_char *p, int plen,
00272         void (*printer) (void *, const char *, ...), void *arg);
00273 #endif /* PRINTPKT_SUPPORT */
00274 
00275 const struct protent lcp_protent = {
00276     PPP_LCP,
00277     lcp_init,
00278     lcp_input,
00279     lcp_protrej,
00280     lcp_lowerup,
00281     lcp_lowerdown,
00282     lcp_open,
00283     lcp_close,
00284 #if PRINTPKT_SUPPORT
00285     lcp_printpkt,
00286 #endif /* PRINTPKT_SUPPORT */
00287 #if PPP_DATAINPUT
00288     NULL,
00289 #endif /* PPP_DATAINPUT */
00290 #if PRINTPKT_SUPPORT
00291     "LCP",
00292     NULL,
00293 #endif /* PRINTPKT_SUPPORT */
00294 #if PPP_OPTIONS
00295     lcp_option_list,
00296     NULL,
00297 #endif /* PPP_OPTIONS */
00298 #if DEMAND_SUPPORT
00299     NULL,
00300     NULL
00301 #endif /* DEMAND_SUPPORT */
00302 };
00303 
00304 /*
00305  * Length of each type of configuration option (in octets)
00306  */
00307 #define CILEN_VOID  2
00308 #define CILEN_CHAR  3
00309 #define CILEN_SHORT 4   /* CILEN_VOID + 2 */
00310 #if CHAP_SUPPORT
00311 #define CILEN_CHAP  5   /* CILEN_VOID + 2 + 1 */
00312 #endif /* CHAP_SUPPORT */
00313 #define CILEN_LONG  6   /* CILEN_VOID + 4 */
00314 #if LQR_SUPPORT
00315 #define CILEN_LQR   8   /* CILEN_VOID + 2 + 4 */
00316 #endif /* LQR_SUPPORT */
00317 #define CILEN_CBCP  3
00318 
00319 #define CODENAME(x) ((x) == CONFACK ? "ACK" : \
00320              (x) == CONFNAK ? "NAK" : "REJ")
00321 
00322 #if PPP_OPTIONS
00323 /*
00324  * noopt - Disable all options (why?).
00325  */
00326 static int
00327 noopt(argv)
00328     char **argv;
00329 {
00330     BZERO((char *) &lcp_wantoptions[0], sizeof (struct lcp_options));
00331     BZERO((char *) &lcp_allowoptions[0], sizeof (struct lcp_options));
00332 
00333     return (1);
00334 }
00335 #endif /* PPP_OPTIONS */
00336 
00337 #ifdef HAVE_MULTILINK
00338 static int
00339 setendpoint(argv)
00340     char **argv;
00341 {
00342     if (str_to_epdisc(&lcp_wantoptions[0].endpoint, *argv)) {
00343     lcp_wantoptions[0].neg_endpoint = 1;
00344     return 1;
00345     }
00346     option_error("Can't parse '%s' as an endpoint discriminator", *argv);
00347     return 0;
00348 }
00349 
00350 static void
00351 printendpoint(opt, printer, arg)
00352     option_t *opt;
00353     void (*printer) (void *, char *, ...);
00354     void *arg;
00355 {
00356     printer(arg, "%s", epdisc_to_str(&lcp_wantoptions[0].endpoint));
00357 }
00358 #endif /* HAVE_MULTILINK */
00359 
00360 /*
00361  * lcp_init - Initialize LCP.
00362  */
00363 static void lcp_init(ppp_pcb *pcb) {
00364     fsm *f = &pcb->lcp_fsm;
00365     lcp_options *wo = &pcb->lcp_wantoptions;
00366     lcp_options *ao = &pcb->lcp_allowoptions;
00367 
00368     f->pcb = pcb;
00369     f->protocol = PPP_LCP;
00370     f->callbacks = &lcp_callbacks;
00371 
00372     fsm_init(f);
00373 
00374     BZERO(wo, sizeof(*wo));
00375     wo->neg_mru = 1;
00376     wo->mru = PPP_DEFMRU;
00377     wo->neg_asyncmap = 1;
00378     wo->neg_magicnumber = 1;
00379     wo->neg_pcompression = 1;
00380     wo->neg_accompression = 1;
00381 
00382     BZERO(ao, sizeof(*ao));
00383     ao->neg_mru = 1;
00384     ao->mru = PPP_MAXMRU;
00385     ao->neg_asyncmap = 1;
00386 #if CHAP_SUPPORT
00387     ao->neg_chap = 1;
00388     ao->chap_mdtype = CHAP_MDTYPE_SUPPORTED;
00389 #endif /* CHAP_SUPPORT */
00390 #if PAP_SUPPORT
00391     ao->neg_upap = 1;
00392 #endif /* PAP_SUPPORT */
00393 #if EAP_SUPPORT
00394     ao->neg_eap = 1;
00395 #endif /* EAP_SUPPORT */
00396     ao->neg_magicnumber = 1;
00397     ao->neg_pcompression = 1;
00398     ao->neg_accompression = 1;
00399     ao->neg_endpoint = 1;
00400 }
00401 
00402 
00403 /*
00404  * lcp_open - LCP is allowed to come up.
00405  */
00406 void lcp_open(ppp_pcb *pcb) {
00407     fsm *f = &pcb->lcp_fsm;
00408     lcp_options *wo = &pcb->lcp_wantoptions;
00409 
00410     f->flags &= ~(OPT_PASSIVE | OPT_SILENT);
00411     if (wo->passive)
00412     f->flags |= OPT_PASSIVE;
00413     if (wo->silent)
00414     f->flags |= OPT_SILENT;
00415     fsm_open(f);
00416 }
00417 
00418 
00419 /*
00420  * lcp_close - Take LCP down.
00421  */
00422 void lcp_close(ppp_pcb *pcb, const char *reason) {
00423     fsm *f = &pcb->lcp_fsm;
00424     int oldstate;
00425 
00426     if (pcb->phase != PPP_PHASE_DEAD && pcb->phase != PPP_PHASE_MASTER)
00427     new_phase(pcb, PPP_PHASE_TERMINATE);
00428 
00429     if (f->flags & DELAYED_UP) {
00430     UNTIMEOUT(lcp_delayed_up, f);
00431     f->state = PPP_FSM_STOPPED;
00432     }
00433     oldstate = f->state;
00434 
00435     fsm_close(f, reason);
00436     if (oldstate == PPP_FSM_STOPPED && (f->flags & (OPT_PASSIVE|OPT_SILENT|DELAYED_UP))) {
00437     /*
00438      * This action is not strictly according to the FSM in RFC1548,
00439      * but it does mean that the program terminates if you do a
00440      * lcp_close() when a connection hasn't been established
00441      * because we are in passive/silent mode or because we have
00442      * delayed the fsm_lowerup() call and it hasn't happened yet.
00443      */
00444     f->flags &= ~DELAYED_UP;
00445     lcp_finished(f);
00446     }
00447 }
00448 
00449 
00450 /*
00451  * lcp_lowerup - The lower layer is up.
00452  */
00453 void lcp_lowerup(ppp_pcb *pcb) {
00454     lcp_options *wo = &pcb->lcp_wantoptions;
00455     fsm *f = &pcb->lcp_fsm;
00456     /*
00457      * Don't use A/C or protocol compression on transmission,
00458      * but accept A/C and protocol compressed packets
00459      * if we are going to ask for A/C and protocol compression.
00460      */
00461     if (ppp_send_config(pcb, PPP_MRU, 0xffffffff, 0, 0) < 0
00462     || ppp_recv_config(pcb, PPP_MRU, (pcb->settings.lax_recv? 0: 0xffffffff),
00463                wo->neg_pcompression, wo->neg_accompression) < 0)
00464         return;
00465     pcb->peer_mru = PPP_MRU;
00466 
00467     if (pcb->settings.listen_time != 0) {
00468     f->flags |= DELAYED_UP;
00469     TIMEOUTMS(lcp_delayed_up, f, pcb->settings.listen_time);
00470     } else
00471     fsm_lowerup(f);
00472 }
00473 
00474 
00475 /*
00476  * lcp_lowerdown - The lower layer is down.
00477  */
00478 void lcp_lowerdown(ppp_pcb *pcb) {
00479     fsm *f = &pcb->lcp_fsm;
00480 
00481     if (f->flags & DELAYED_UP) {
00482     f->flags &= ~DELAYED_UP;
00483     UNTIMEOUT(lcp_delayed_up, f);
00484     } else
00485     fsm_lowerdown(f);
00486 }
00487 
00488 
00489 /*
00490  * lcp_delayed_up - Bring the lower layer up now.
00491  */
00492 static void lcp_delayed_up(void *arg) {
00493     fsm *f = (fsm*)arg;
00494 
00495     if (f->flags & DELAYED_UP) {
00496     f->flags &= ~DELAYED_UP;
00497     fsm_lowerup(f);
00498     }
00499 }
00500 
00501 
00502 /*
00503  * lcp_input - Input LCP packet.
00504  */
00505 static void lcp_input(ppp_pcb *pcb, u_char *p, int len) {
00506     fsm *f = &pcb->lcp_fsm;
00507 
00508     if (f->flags & DELAYED_UP) {
00509     f->flags &= ~DELAYED_UP;
00510     UNTIMEOUT(lcp_delayed_up, f);
00511     fsm_lowerup(f);
00512     }
00513     fsm_input(f, p, len);
00514 }
00515 
00516 /*
00517  * lcp_extcode - Handle a LCP-specific code.
00518  */
00519 static int lcp_extcode(fsm *f, int code, int id, u_char *inp, int len) {
00520     ppp_pcb *pcb = f->pcb;
00521     lcp_options *go = &pcb->lcp_gotoptions;
00522     u_char *magp;
00523 
00524     switch( code ){
00525     case PROTREJ:
00526     lcp_rprotrej(f, inp, len);
00527     break;
00528     
00529     case ECHOREQ:
00530     if (f->state != PPP_FSM_OPENED)
00531         break;
00532     magp = inp;
00533     PUTLONG(go->magicnumber, magp);
00534     fsm_sdata(f, ECHOREP, id, inp, len);
00535     break;
00536     
00537     case ECHOREP:
00538     lcp_received_echo_reply(f, id, inp, len);
00539     break;
00540 
00541     case DISCREQ:
00542     case IDENTIF:
00543     case TIMEREM:
00544     break;
00545 
00546     default:
00547     return 0;
00548     }
00549     return 1;
00550 }
00551 
00552     
00553 /*
00554  * lcp_rprotrej - Receive an Protocol-Reject.
00555  *
00556  * Figure out which protocol is rejected and inform it.
00557  */
00558 static void lcp_rprotrej(fsm *f, u_char *inp, int len) {
00559     int i;
00560     const struct protent *protp;
00561     u_short prot;
00562 #if PPP_PROTOCOLNAME
00563     const char *pname;
00564 #endif /* PPP_PROTOCOLNAME */
00565 
00566     if (len < 2) {
00567     LCPDEBUG(("lcp_rprotrej: Rcvd short Protocol-Reject packet!"));
00568     return;
00569     }
00570 
00571     GETSHORT(prot, inp);
00572 
00573     /*
00574      * Protocol-Reject packets received in any state other than the LCP
00575      * OPENED state SHOULD be silently discarded.
00576      */
00577     if( f->state != PPP_FSM_OPENED ){
00578     LCPDEBUG(("Protocol-Reject discarded: LCP in state %d", f->state));
00579     return;
00580     }
00581 
00582 #if PPP_PROTOCOLNAME
00583     pname = protocol_name(prot);
00584 #endif /* PPP_PROTOCOLNAME */
00585 
00586     /*
00587      * Upcall the proper Protocol-Reject routine.
00588      */
00589     for (i = 0; (protp = protocols[i]) != NULL; ++i)
00590     if (protp->protocol == prot) {
00591 #if PPP_PROTOCOLNAME
00592         if (pname != NULL)
00593         ppp_dbglog("Protocol-Reject for '%s' (0x%x) received", pname,
00594                prot);
00595         else
00596 #endif /* PPP_PROTOCOLNAME */
00597         ppp_dbglog("Protocol-Reject for 0x%x received", prot);
00598         (*protp->protrej)(f->pcb);
00599         return;
00600     }
00601 
00602 #if PPP_PROTOCOLNAME
00603     if (pname != NULL)
00604     ppp_warn("Protocol-Reject for unsupported protocol '%s' (0x%x)", pname,
00605          prot);
00606     else
00607 #endif /* #if PPP_PROTOCOLNAME */
00608     ppp_warn("Protocol-Reject for unsupported protocol 0x%x", prot);
00609 }
00610 
00611 
00612 /*
00613  * lcp_protrej - A Protocol-Reject was received.
00614  */
00615 /*ARGSUSED*/
00616 static void lcp_protrej(ppp_pcb *pcb) {
00617     /*
00618      * Can't reject LCP!
00619      */
00620     ppp_error("Received Protocol-Reject for LCP!");
00621     fsm_protreject(&pcb->lcp_fsm);
00622 }
00623 
00624 
00625 /*
00626  * lcp_sprotrej - Send a Protocol-Reject for some protocol.
00627  */
00628 void lcp_sprotrej(ppp_pcb *pcb, u_char *p, int len) {
00629     fsm *f = &pcb->lcp_fsm;
00630     /*
00631      * Send back the protocol and the information field of the
00632      * rejected packet.  We only get here if LCP is in the OPENED state.
00633      */
00634 #if 0
00635     p += 2;
00636     len -= 2;
00637 #endif
00638 
00639     fsm_sdata(f, PROTREJ, ++f->id,
00640           p, len);
00641 }
00642 
00643 
00644 /*
00645  * lcp_resetci - Reset our CI.
00646  */
00647 static void lcp_resetci(fsm *f) {
00648     ppp_pcb *pcb = f->pcb;
00649     lcp_options *wo = &pcb->lcp_wantoptions;
00650     lcp_options *go = &pcb->lcp_gotoptions;
00651     lcp_options *ao = &pcb->lcp_allowoptions;
00652 
00653 #if PPP_AUTH_SUPPORT
00654 
00655     /* note: default value is true for allow options */
00656     if (pcb->settings.user && pcb->settings.passwd) {
00657 #if PAP_SUPPORT
00658       if (pcb->settings.refuse_pap) {
00659         ao->neg_upap = 0;
00660       }
00661 #endif /* PAP_SUPPORT */
00662 #if CHAP_SUPPORT
00663       if (pcb->settings.refuse_chap) {
00664         ao->chap_mdtype &= ~MDTYPE_MD5;
00665       }
00666 #if MSCHAP_SUPPORT
00667       if (pcb->settings.refuse_mschap) {
00668         ao->chap_mdtype &= ~MDTYPE_MICROSOFT;
00669       }
00670       if (pcb->settings.refuse_mschap_v2) {
00671         ao->chap_mdtype &= ~MDTYPE_MICROSOFT_V2;
00672       }
00673 #endif /* MSCHAP_SUPPORT */
00674       ao->neg_chap = (ao->chap_mdtype != MDTYPE_NONE);
00675 #endif /* CHAP_SUPPORT */
00676 #if EAP_SUPPORT
00677       if (pcb->settings.refuse_eap) {
00678         ao->neg_eap = 0;
00679       }
00680 #endif /* EAP_SUPPORT */
00681 
00682 #if PPP_SERVER
00683       /* note: default value is false for wanted options */
00684       if (pcb->settings.auth_required) {
00685 #if PAP_SUPPORT
00686         if (!pcb->settings.refuse_pap) {
00687           wo->neg_upap = 1;
00688         }
00689 #endif /* PAP_SUPPORT */
00690 #if CHAP_SUPPORT
00691         if (!pcb->settings.refuse_chap) {
00692           wo->chap_mdtype |= MDTYPE_MD5;
00693         }
00694 #if MSCHAP_SUPPORT
00695         if (!pcb->settings.refuse_mschap) {
00696           wo->chap_mdtype |= MDTYPE_MICROSOFT;
00697         }
00698         if (!pcb->settings.refuse_mschap_v2) {
00699           wo->chap_mdtype |= MDTYPE_MICROSOFT_V2;
00700         }
00701 #endif /* MSCHAP_SUPPORT */
00702         wo->neg_chap = (wo->chap_mdtype != MDTYPE_NONE);
00703 #endif /* CHAP_SUPPORT */
00704 #if EAP_SUPPORT
00705         if (!pcb->settings.refuse_eap) {
00706           wo->neg_eap = 1;
00707         }
00708 #endif /* EAP_SUPPORT */
00709       }
00710 #endif /* PPP_SERVER */
00711 
00712     } else {
00713 #if PAP_SUPPORT
00714       ao->neg_upap = 0;
00715 #endif /* PAP_SUPPORT */
00716 #if CHAP_SUPPORT
00717       ao->neg_chap = 0;
00718       ao->chap_mdtype = MDTYPE_NONE;
00719 #endif /* CHAP_SUPPORT */
00720 #if EAP_SUPPORT
00721       ao->neg_eap = 0;
00722 #endif /* EAP_SUPPORT */
00723     }
00724 
00725     PPPDEBUG(LOG_DEBUG, ("ppp: auth protocols:"));
00726 #if PAP_SUPPORT
00727     PPPDEBUG(LOG_DEBUG, (" PAP=%d", ao->neg_upap));
00728 #endif /* PAP_SUPPORT */
00729 #if CHAP_SUPPORT
00730     PPPDEBUG(LOG_DEBUG, (" CHAP=%d CHAP_MD5=%d", ao->neg_chap, !!(ao->chap_mdtype&MDTYPE_MD5)));
00731 #if MSCHAP_SUPPORT
00732     PPPDEBUG(LOG_DEBUG, (" CHAP_MS=%d CHAP_MS2=%d", !!(ao->chap_mdtype&MDTYPE_MICROSOFT), !!(ao->chap_mdtype&MDTYPE_MICROSOFT_V2)));
00733 #endif /* MSCHAP_SUPPORT */
00734 #endif /* CHAP_SUPPORT */
00735 #if EAP_SUPPORT
00736     PPPDEBUG(LOG_DEBUG, (" EAP=%d", ao->neg_eap));
00737 #endif /* EAP_SUPPORT */
00738     PPPDEBUG(LOG_DEBUG, ("\n"));
00739 
00740 #endif /* PPP_AUTH_SUPPORT */
00741 
00742     wo->magicnumber = magic();
00743     wo->numloops = 0;
00744     *go = *wo;
00745 #ifdef HAVE_MULTILINK
00746     if (!multilink) {
00747     go->neg_mrru = 0;
00748 #endif /* HAVE_MULTILINK */
00749     go->neg_ssnhf = 0;
00750     go->neg_endpoint = 0;
00751 #ifdef HAVE_MULTILINK
00752     }
00753 #endif /* HAVE_MULTILINK */
00754     if (pcb->settings.noendpoint)
00755     ao->neg_endpoint = 0;
00756     pcb->peer_mru = PPP_MRU;
00757 #if 0 /* UNUSED */
00758     auth_reset(pcb);
00759 #endif /* UNUSED */
00760 }
00761 
00762 
00763 /*
00764  * lcp_cilen - Return length of our CI.
00765  */
00766 static int lcp_cilen(fsm *f) {
00767     ppp_pcb *pcb = f->pcb;
00768     lcp_options *go = &pcb->lcp_gotoptions;
00769 
00770 #define LENCIVOID(neg)  ((neg) ? CILEN_VOID : 0)
00771 #if CHAP_SUPPORT
00772 #define LENCICHAP(neg)  ((neg) ? CILEN_CHAP : 0)
00773 #endif /* CHAP_SUPPORT */
00774 #define LENCISHORT(neg) ((neg) ? CILEN_SHORT : 0)
00775 #define LENCILONG(neg)  ((neg) ? CILEN_LONG : 0)
00776 #if LQR_SUPPORT
00777 #define LENCILQR(neg)   ((neg) ? CILEN_LQR: 0)
00778 #endif /* LQR_SUPPORT */
00779 #define LENCICBCP(neg)  ((neg) ? CILEN_CBCP: 0)
00780     /*
00781      * NB: we only ask for one of CHAP, UPAP, or EAP, even if we will
00782      * accept more than one.  We prefer EAP first, then CHAP, then
00783      * PAP.
00784      */
00785     return (LENCISHORT(go->neg_mru && go->mru != PPP_DEFMRU) +
00786         LENCILONG(go->neg_asyncmap && go->asyncmap != 0xFFFFFFFF) +
00787 #if EAP_SUPPORT
00788         LENCISHORT(go->neg_eap) +
00789 #endif /* EAP_SUPPORT */
00790 #if CHAP_SUPPORT /* cannot be improved, embedding a directive within macro arguments is not portable */
00791 #if EAP_SUPPORT
00792         LENCICHAP(!go->neg_eap && go->neg_chap) +
00793 #endif /* EAP_SUPPORT */
00794 #if !EAP_SUPPORT
00795         LENCICHAP(go->neg_chap) +
00796 #endif /* !EAP_SUPPORT */
00797 #endif /* CHAP_SUPPORT */
00798 #if PAP_SUPPORT /* cannot be improved, embedding a directive within macro arguments is not portable */
00799 #if EAP_SUPPORT && CHAP_SUPPORT
00800         LENCISHORT(!go->neg_eap && !go->neg_chap && go->neg_upap) +
00801 #endif /* EAP_SUPPORT && CHAP_SUPPORT */
00802 #if EAP_SUPPORT && !CHAP_SUPPORT
00803         LENCISHORT(!go->neg_eap && go->neg_upap) +
00804 #endif /* EAP_SUPPORT && !CHAP_SUPPORT */
00805 #if !EAP_SUPPORT && CHAP_SUPPORT
00806         LENCISHORT(!go->neg_chap && go->neg_upap) +
00807 #endif /* !EAP_SUPPORT && CHAP_SUPPORT */
00808 #if !EAP_SUPPORT && !CHAP_SUPPORT
00809         LENCISHORT(go->neg_upap) +
00810 #endif /* !EAP_SUPPORT && !CHAP_SUPPORT */
00811 #endif /* PAP_SUPPORT */
00812 #if LQR_SUPPORT
00813         LENCILQR(go->neg_lqr) +
00814 #endif /* LQR_SUPPORT */
00815         LENCICBCP(go->neg_cbcp) +
00816         LENCILONG(go->neg_magicnumber) +
00817         LENCIVOID(go->neg_pcompression) +
00818         LENCIVOID(go->neg_accompression) +
00819 #ifdef HAVE_MULTILINK
00820         LENCISHORT(go->neg_mrru) +
00821 #endif /* HAVE_MULTILINK */
00822         LENCIVOID(go->neg_ssnhf) +
00823         (go->neg_endpoint? CILEN_CHAR + go->endpoint.length: 0));
00824 }
00825 
00826 
00827 /*
00828  * lcp_addci - Add our desired CIs to a packet.
00829  */
00830 static void lcp_addci(fsm *f, u_char *ucp, int *lenp) {
00831     ppp_pcb *pcb = f->pcb;
00832     lcp_options *go = &pcb->lcp_gotoptions;
00833     u_char *start_ucp = ucp;
00834 
00835 #define ADDCIVOID(opt, neg) \
00836     if (neg) { \
00837     PUTCHAR(opt, ucp); \
00838     PUTCHAR(CILEN_VOID, ucp); \
00839     }
00840 #define ADDCISHORT(opt, neg, val) \
00841     if (neg) { \
00842     PUTCHAR(opt, ucp); \
00843     PUTCHAR(CILEN_SHORT, ucp); \
00844     PUTSHORT(val, ucp); \
00845     }
00846 #if CHAP_SUPPORT
00847 #define ADDCICHAP(opt, neg, val) \
00848     if (neg) { \
00849     PUTCHAR((opt), ucp); \
00850     PUTCHAR(CILEN_CHAP, ucp); \
00851     PUTSHORT(PPP_CHAP, ucp); \
00852     PUTCHAR((CHAP_DIGEST(val)), ucp); \
00853     }
00854 #endif /* CHAP_SUPPORT */
00855 #define ADDCILONG(opt, neg, val) \
00856     if (neg) { \
00857     PUTCHAR(opt, ucp); \
00858     PUTCHAR(CILEN_LONG, ucp); \
00859     PUTLONG(val, ucp); \
00860     }
00861 #if LQR_SUPPORT
00862 #define ADDCILQR(opt, neg, val) \
00863     if (neg) { \
00864     PUTCHAR(opt, ucp); \
00865     PUTCHAR(CILEN_LQR, ucp); \
00866     PUTSHORT(PPP_LQR, ucp); \
00867     PUTLONG(val, ucp); \
00868     }
00869 #endif /* LQR_SUPPORT */
00870 #define ADDCICHAR(opt, neg, val) \
00871     if (neg) { \
00872     PUTCHAR(opt, ucp); \
00873     PUTCHAR(CILEN_CHAR, ucp); \
00874     PUTCHAR(val, ucp); \
00875     }
00876 #define ADDCIENDP(opt, neg, class, val, len) \
00877     if (neg) { \
00878     int i; \
00879     PUTCHAR(opt, ucp); \
00880     PUTCHAR(CILEN_CHAR + len, ucp); \
00881     PUTCHAR(class, ucp); \
00882     for (i = 0; i < len; ++i) \
00883         PUTCHAR(val[i], ucp); \
00884     }
00885 
00886     ADDCISHORT(CI_MRU, go->neg_mru && go->mru != PPP_DEFMRU, go->mru);
00887     ADDCILONG(CI_ASYNCMAP, go->neg_asyncmap && go->asyncmap != 0xFFFFFFFF,
00888           go->asyncmap);
00889 #if EAP_SUPPORT
00890     ADDCISHORT(CI_AUTHTYPE, go->neg_eap, PPP_EAP);
00891 #endif /* EAP_SUPPORT */
00892 #if CHAP_SUPPORT /* cannot be improved, embedding a directive within macro arguments is not portable */
00893 #if EAP_SUPPORT
00894     ADDCICHAP(CI_AUTHTYPE, !go->neg_eap && go->neg_chap, go->chap_mdtype);
00895 #endif /* EAP_SUPPORT */
00896 #if !EAP_SUPPORT
00897     ADDCICHAP(CI_AUTHTYPE, go->neg_chap, go->chap_mdtype);
00898 #endif /* !EAP_SUPPORT */
00899 #endif /* CHAP_SUPPORT */
00900 #if PAP_SUPPORT /* cannot be improved, embedding a directive within macro arguments is not portable */
00901 #if EAP_SUPPORT && CHAP_SUPPORT
00902     ADDCISHORT(CI_AUTHTYPE, !go->neg_eap && !go->neg_chap && go->neg_upap, PPP_PAP);
00903 #endif /* EAP_SUPPORT && CHAP_SUPPORT */
00904 #if EAP_SUPPORT && !CHAP_SUPPORT
00905     ADDCISHORT(CI_AUTHTYPE, !go->neg_eap && go->neg_upap, PPP_PAP);
00906 #endif /* EAP_SUPPORT && !CHAP_SUPPORT */
00907 #if !EAP_SUPPORT && CHAP_SUPPORT
00908     ADDCISHORT(CI_AUTHTYPE, !go->neg_chap && go->neg_upap, PPP_PAP);
00909 #endif /* !EAP_SUPPORT && CHAP_SUPPORT */
00910 #if !EAP_SUPPORT && !CHAP_SUPPORT
00911     ADDCISHORT(CI_AUTHTYPE, go->neg_upap, PPP_PAP);
00912 #endif /* !EAP_SUPPORT && !CHAP_SUPPORT */
00913 #endif /* PAP_SUPPORT */
00914 #if LQR_SUPPORT
00915     ADDCILQR(CI_QUALITY, go->neg_lqr, go->lqr_period);
00916 #endif /* LQR_SUPPORT */
00917     ADDCICHAR(CI_CALLBACK, go->neg_cbcp, CBCP_OPT);
00918     ADDCILONG(CI_MAGICNUMBER, go->neg_magicnumber, go->magicnumber);
00919     ADDCIVOID(CI_PCOMPRESSION, go->neg_pcompression);
00920     ADDCIVOID(CI_ACCOMPRESSION, go->neg_accompression);
00921 #ifdef HAVE_MULTILINK
00922     ADDCISHORT(CI_MRRU, go->neg_mrru, go->mrru);
00923 #endif
00924     ADDCIVOID(CI_SSNHF, go->neg_ssnhf);
00925     ADDCIENDP(CI_EPDISC, go->neg_endpoint, go->endpoint.class_,
00926           go->endpoint.value, go->endpoint.length);
00927 
00928     if (ucp - start_ucp != *lenp) {
00929     /* this should never happen, because peer_mtu should be 1500 */
00930     ppp_error("Bug in lcp_addci: wrong length");
00931     }
00932 }
00933 
00934 
00935 /*
00936  * lcp_ackci - Ack our CIs.
00937  * This should not modify any state if the Ack is bad.
00938  *
00939  * Returns:
00940  *  0 - Ack was bad.
00941  *  1 - Ack was good.
00942  */
00943 static int lcp_ackci(fsm *f, u_char *p, int len) {
00944     ppp_pcb *pcb = f->pcb;
00945     lcp_options *go = &pcb->lcp_gotoptions;
00946     u_char cilen, citype, cichar;
00947     u_short cishort;
00948     u32_t cilong;
00949 
00950     /*
00951      * CIs must be in exactly the same order that we sent.
00952      * Check packet length and CI length at each step.
00953      * If we find any deviations, then this packet is bad.
00954      */
00955 #define ACKCIVOID(opt, neg) \
00956     if (neg) { \
00957     if ((len -= CILEN_VOID) < 0) \
00958         goto bad; \
00959     GETCHAR(citype, p); \
00960     GETCHAR(cilen, p); \
00961     if (cilen != CILEN_VOID || \
00962         citype != opt) \
00963         goto bad; \
00964     }
00965 #define ACKCISHORT(opt, neg, val) \
00966     if (neg) { \
00967     if ((len -= CILEN_SHORT) < 0) \
00968         goto bad; \
00969     GETCHAR(citype, p); \
00970     GETCHAR(cilen, p); \
00971     if (cilen != CILEN_SHORT || \
00972         citype != opt) \
00973         goto bad; \
00974     GETSHORT(cishort, p); \
00975     if (cishort != val) \
00976         goto bad; \
00977     }
00978 #define ACKCICHAR(opt, neg, val) \
00979     if (neg) { \
00980     if ((len -= CILEN_CHAR) < 0) \
00981         goto bad; \
00982     GETCHAR(citype, p); \
00983     GETCHAR(cilen, p); \
00984     if (cilen != CILEN_CHAR || \
00985         citype != opt) \
00986         goto bad; \
00987     GETCHAR(cichar, p); \
00988     if (cichar != val) \
00989         goto bad; \
00990     }
00991 #if CHAP_SUPPORT
00992 #define ACKCICHAP(opt, neg, val) \
00993     if (neg) { \
00994     if ((len -= CILEN_CHAP) < 0) \
00995         goto bad; \
00996     GETCHAR(citype, p); \
00997     GETCHAR(cilen, p); \
00998     if (cilen != CILEN_CHAP || \
00999         citype != (opt)) \
01000         goto bad; \
01001     GETSHORT(cishort, p); \
01002     if (cishort != PPP_CHAP) \
01003         goto bad; \
01004     GETCHAR(cichar, p); \
01005     if (cichar != (CHAP_DIGEST(val))) \
01006       goto bad; \
01007     }
01008 #endif /* CHAP_SUPPORT */
01009 #define ACKCILONG(opt, neg, val) \
01010     if (neg) { \
01011     if ((len -= CILEN_LONG) < 0) \
01012         goto bad; \
01013     GETCHAR(citype, p); \
01014     GETCHAR(cilen, p); \
01015     if (cilen != CILEN_LONG || \
01016         citype != opt) \
01017         goto bad; \
01018     GETLONG(cilong, p); \
01019     if (cilong != val) \
01020         goto bad; \
01021     }
01022 #if LQR_SUPPORT
01023 #define ACKCILQR(opt, neg, val) \
01024     if (neg) { \
01025     if ((len -= CILEN_LQR) < 0) \
01026         goto bad; \
01027     GETCHAR(citype, p); \
01028     GETCHAR(cilen, p); \
01029     if (cilen != CILEN_LQR || \
01030         citype != opt) \
01031         goto bad; \
01032     GETSHORT(cishort, p); \
01033     if (cishort != PPP_LQR) \
01034         goto bad; \
01035     GETLONG(cilong, p); \
01036     if (cilong != val) \
01037       goto bad; \
01038     }
01039 #endif /* LQR_SUPPORT */
01040 #define ACKCIENDP(opt, neg, class, val, vlen) \
01041     if (neg) { \
01042     int i; \
01043     if ((len -= CILEN_CHAR + vlen) < 0) \
01044         goto bad; \
01045     GETCHAR(citype, p); \
01046     GETCHAR(cilen, p); \
01047     if (cilen != CILEN_CHAR + vlen || \
01048         citype != opt) \
01049         goto bad; \
01050     GETCHAR(cichar, p); \
01051     if (cichar != class) \
01052         goto bad; \
01053     for (i = 0; i < vlen; ++i) { \
01054         GETCHAR(cichar, p); \
01055         if (cichar != val[i]) \
01056         goto bad; \
01057     } \
01058     }
01059 
01060     ACKCISHORT(CI_MRU, go->neg_mru && go->mru != PPP_DEFMRU, go->mru);
01061     ACKCILONG(CI_ASYNCMAP, go->neg_asyncmap && go->asyncmap != 0xFFFFFFFF,
01062           go->asyncmap);
01063 #if EAP_SUPPORT
01064     ACKCISHORT(CI_AUTHTYPE, go->neg_eap, PPP_EAP);
01065 #endif /* EAP_SUPPORT */
01066 #if CHAP_SUPPORT /* cannot be improved, embedding a directive within macro arguments is not portable */
01067 #if EAP_SUPPORT
01068     ACKCICHAP(CI_AUTHTYPE, !go->neg_eap && go->neg_chap, go->chap_mdtype);
01069 #endif /* EAP_SUPPORT */
01070 #if !EAP_SUPPORT
01071     ACKCICHAP(CI_AUTHTYPE, go->neg_chap, go->chap_mdtype);
01072 #endif /* !EAP_SUPPORT */
01073 #endif /* CHAP_SUPPORT */
01074 #if PAP_SUPPORT /* cannot be improved, embedding a directive within macro arguments is not portable */
01075 #if EAP_SUPPORT && CHAP_SUPPORT
01076     ACKCISHORT(CI_AUTHTYPE, !go->neg_eap && !go->neg_chap && go->neg_upap, PPP_PAP);
01077 #endif /* EAP_SUPPORT && CHAP_SUPPORT */
01078 #if EAP_SUPPORT && !CHAP_SUPPORT
01079     ACKCISHORT(CI_AUTHTYPE, !go->neg_eap && go->neg_upap, PPP_PAP);
01080 #endif /* EAP_SUPPORT && !CHAP_SUPPORT */
01081 #if !EAP_SUPPORT && CHAP_SUPPORT
01082     ACKCISHORT(CI_AUTHTYPE, !go->neg_chap && go->neg_upap, PPP_PAP);
01083 #endif /* !EAP_SUPPORT && CHAP_SUPPORT */
01084 #if !EAP_SUPPORT && !CHAP_SUPPORT
01085     ACKCISHORT(CI_AUTHTYPE, go->neg_upap, PPP_PAP);
01086 #endif /* !EAP_SUPPORT && !CHAP_SUPPORT */
01087 #endif /* PAP_SUPPORT */
01088 #if LQR_SUPPORT
01089     ACKCILQR(CI_QUALITY, go->neg_lqr, go->lqr_period);
01090 #endif /* LQR_SUPPORT */
01091     ACKCICHAR(CI_CALLBACK, go->neg_cbcp, CBCP_OPT);
01092     ACKCILONG(CI_MAGICNUMBER, go->neg_magicnumber, go->magicnumber);
01093     ACKCIVOID(CI_PCOMPRESSION, go->neg_pcompression);
01094     ACKCIVOID(CI_ACCOMPRESSION, go->neg_accompression);
01095 #ifdef HAVE_MULTILINK
01096     ACKCISHORT(CI_MRRU, go->neg_mrru, go->mrru);
01097 #endif /* HAVE_MULTILINK */
01098     ACKCIVOID(CI_SSNHF, go->neg_ssnhf);
01099     ACKCIENDP(CI_EPDISC, go->neg_endpoint, go->endpoint.class_,
01100           go->endpoint.value, go->endpoint.length);
01101 
01102     /*
01103      * If there are any remaining CIs, then this packet is bad.
01104      */
01105     if (len != 0)
01106     goto bad;
01107     return (1);
01108 bad:
01109     LCPDEBUG(("lcp_acki: received bad Ack!"));
01110     return (0);
01111 }
01112 
01113 
01114 /*
01115  * lcp_nakci - Peer has sent a NAK for some of our CIs.
01116  * This should not modify any state if the Nak is bad
01117  * or if LCP is in the OPENED state.
01118  *
01119  * Returns:
01120  *  0 - Nak was bad.
01121  *  1 - Nak was good.
01122  */
01123 static int lcp_nakci(fsm *f, u_char *p, int len, int treat_as_reject) {
01124     ppp_pcb *pcb = f->pcb;
01125     lcp_options *go = &pcb->lcp_gotoptions;
01126     lcp_options *wo = &pcb->lcp_wantoptions;
01127     u_char citype, cichar, *next;
01128     u_short cishort;
01129     u32_t cilong;
01130     lcp_options no;     /* options we've seen Naks for */
01131     lcp_options try_;       /* options to request next time */
01132     int looped_back = 0;
01133     int cilen;
01134 
01135     BZERO(&no, sizeof(no));
01136     try_ = *go;
01137 
01138     /*
01139      * Any Nak'd CIs must be in exactly the same order that we sent.
01140      * Check packet length and CI length at each step.
01141      * If we find any deviations, then this packet is bad.
01142      */
01143 #define NAKCIVOID(opt, neg) \
01144     if (go->neg && \
01145     len >= CILEN_VOID && \
01146     p[1] == CILEN_VOID && \
01147     p[0] == opt) { \
01148     len -= CILEN_VOID; \
01149     INCPTR(CILEN_VOID, p); \
01150     no.neg = 1; \
01151     try_.neg = 0; \
01152     }
01153 #if CHAP_SUPPORT
01154 #define NAKCICHAP(opt, neg, code) \
01155     if (go->neg && \
01156     len >= CILEN_CHAP && \
01157     p[1] == CILEN_CHAP && \
01158     p[0] == opt) { \
01159     len -= CILEN_CHAP; \
01160     INCPTR(2, p); \
01161     GETSHORT(cishort, p); \
01162     GETCHAR(cichar, p); \
01163     no.neg = 1; \
01164     code \
01165     }
01166 #endif /* CHAP_SUPPORT */
01167 #define NAKCICHAR(opt, neg, code) \
01168     if (go->neg && \
01169     len >= CILEN_CHAR && \
01170     p[1] == CILEN_CHAR && \
01171     p[0] == opt) { \
01172     len -= CILEN_CHAR; \
01173     INCPTR(2, p); \
01174     GETCHAR(cichar, p); \
01175     no.neg = 1; \
01176     code \
01177     }
01178 #define NAKCISHORT(opt, neg, code) \
01179     if (go->neg && \
01180     len >= CILEN_SHORT && \
01181     p[1] == CILEN_SHORT && \
01182     p[0] == opt) { \
01183     len -= CILEN_SHORT; \
01184     INCPTR(2, p); \
01185     GETSHORT(cishort, p); \
01186     no.neg = 1; \
01187     code \
01188     }
01189 #define NAKCILONG(opt, neg, code) \
01190     if (go->neg && \
01191     len >= CILEN_LONG && \
01192     p[1] == CILEN_LONG && \
01193     p[0] == opt) { \
01194     len -= CILEN_LONG; \
01195     INCPTR(2, p); \
01196     GETLONG(cilong, p); \
01197     no.neg = 1; \
01198     code \
01199     }
01200 #if LQR_SUPPORT
01201 #define NAKCILQR(opt, neg, code) \
01202     if (go->neg && \
01203     len >= CILEN_LQR && \
01204     p[1] == CILEN_LQR && \
01205     p[0] == opt) { \
01206     len -= CILEN_LQR; \
01207     INCPTR(2, p); \
01208     GETSHORT(cishort, p); \
01209     GETLONG(cilong, p); \
01210     no.neg = 1; \
01211     code \
01212     }
01213 #endif /* LQR_SUPPORT */
01214 #define NAKCIENDP(opt, neg) \
01215     if (go->neg && \
01216     len >= CILEN_CHAR && \
01217     p[0] == opt && \
01218     p[1] >= CILEN_CHAR && \
01219     p[1] <= len) { \
01220     len -= p[1]; \
01221     INCPTR(p[1], p); \
01222     no.neg = 1; \
01223     try_.neg = 0; \
01224     }
01225 
01226     /*
01227      * NOTE!  There must be no assignments to individual fields of *go in
01228      * the code below.  Any such assignment is a BUG!
01229      */
01230     /*
01231      * We don't care if they want to send us smaller packets than
01232      * we want.  Therefore, accept any MRU less than what we asked for,
01233      * but then ignore the new value when setting the MRU in the kernel.
01234      * If they send us a bigger MRU than what we asked, accept it, up to
01235      * the limit of the default MRU we'd get if we didn't negotiate.
01236      */
01237     if (go->neg_mru && go->mru != PPP_DEFMRU) {
01238     NAKCISHORT(CI_MRU, neg_mru,
01239            if (cishort <= wo->mru || cishort <= PPP_DEFMRU)
01240                try_.mru = cishort;
01241            );
01242     }
01243 
01244     /*
01245      * Add any characters they want to our (receive-side) asyncmap.
01246      */
01247     if (go->neg_asyncmap && go->asyncmap != 0xFFFFFFFF) {
01248     NAKCILONG(CI_ASYNCMAP, neg_asyncmap,
01249           try_.asyncmap = go->asyncmap | cilong;
01250           );
01251     }
01252 
01253     /*
01254      * If they've nak'd our authentication-protocol, check whether
01255      * they are proposing a different protocol, or a different
01256      * hash algorithm for CHAP.
01257      */
01258     if ((0
01259 #if CHAP_SUPPORT
01260         || go->neg_chap
01261 #endif /* CHAP_SUPPORT */
01262 #if PAP_SUPPORT
01263         || go->neg_upap
01264 #endif /* PAP_SUPPORT */
01265 #if EAP_SUPPORT
01266         || go->neg_eap
01267 #endif /* EAP_SUPPORT */
01268         )
01269     && len >= CILEN_SHORT
01270     && p[0] == CI_AUTHTYPE && p[1] >= CILEN_SHORT && p[1] <= len) {
01271     cilen = p[1];
01272     len -= cilen;
01273 #if CHAP_SUPPORT
01274     no.neg_chap = go->neg_chap;
01275 #endif /* CHAP_SUPPORT */
01276 #if PAP_SUPPORT
01277     no.neg_upap = go->neg_upap;
01278 #endif /* PAP_SUPPORT */
01279 #if EAP_SUPPORT
01280     no.neg_eap = go->neg_eap;
01281 #endif /* EAP_SUPPORT */
01282     INCPTR(2, p);
01283     GETSHORT(cishort, p);
01284 
01285 #if PAP_SUPPORT
01286     if (cishort == PPP_PAP && cilen == CILEN_SHORT) {
01287 #if EAP_SUPPORT
01288         /* If we were asking for EAP, then we need to stop that. */
01289         if (go->neg_eap)
01290         try_.neg_eap = 0;
01291         else
01292 #endif /* EAP_SUPPORT */
01293 
01294 #if CHAP_SUPPORT
01295         /* If we were asking for CHAP, then we need to stop that. */
01296         if (go->neg_chap)
01297         try_.neg_chap = 0;
01298         else
01299 #endif /* CHAP_SUPPORT */
01300 
01301         /*
01302          * If we weren't asking for CHAP or EAP, then we were asking for
01303          * PAP, in which case this Nak is bad.
01304          */
01305         goto bad;
01306     } else
01307 #endif /* PAP_SUPPORT */
01308 
01309 #if CHAP_SUPPORT
01310     if (cishort == PPP_CHAP && cilen == CILEN_CHAP) {
01311         GETCHAR(cichar, p);
01312 #if EAP_SUPPORT
01313         /* Stop asking for EAP, if we were. */
01314         if (go->neg_eap) {
01315         try_.neg_eap = 0;
01316         /* Try to set up to use their suggestion, if possible */
01317         if (CHAP_CANDIGEST(go->chap_mdtype, cichar))
01318             try_.chap_mdtype = CHAP_MDTYPE_D(cichar);
01319         } else
01320 #endif /* EAP_SUPPORT */
01321         if (go->neg_chap) {
01322         /*
01323          * We were asking for our preferred algorithm, they must
01324          * want something different.
01325          */
01326         if (cichar != CHAP_DIGEST(go->chap_mdtype)) {
01327             if (CHAP_CANDIGEST(go->chap_mdtype, cichar)) {
01328             /* Use their suggestion if we support it ... */
01329             try_.chap_mdtype = CHAP_MDTYPE_D(cichar);
01330             } else {
01331             /* ... otherwise, try our next-preferred algorithm. */
01332             try_.chap_mdtype &= ~(CHAP_MDTYPE(try_.chap_mdtype));
01333             if (try_.chap_mdtype == MDTYPE_NONE) /* out of algos */
01334                 try_.neg_chap = 0;
01335             }
01336         } else {
01337             /*
01338              * Whoops, they Nak'd our algorithm of choice
01339              * but then suggested it back to us.
01340              */
01341             goto bad;
01342         }
01343         } else {
01344         /*
01345          * Stop asking for PAP if we were asking for it.
01346          */
01347 #if PAP_SUPPORT
01348         try_.neg_upap = 0;
01349 #endif /* PAP_SUPPORT */
01350         }
01351 
01352     } else
01353 #endif /* CHAP_SUPPORT */
01354     {
01355 
01356 #if EAP_SUPPORT
01357         /*
01358          * If we were asking for EAP, and they're Conf-Naking EAP,
01359          * well, that's just strange.  Nobody should do that.
01360          */
01361         if (cishort == PPP_EAP && cilen == CILEN_SHORT && go->neg_eap)
01362         ppp_dbglog("Unexpected Conf-Nak for EAP");
01363 
01364         /*
01365          * We don't recognize what they're suggesting.
01366          * Stop asking for what we were asking for.
01367          */
01368         if (go->neg_eap)
01369         try_.neg_eap = 0;
01370         else
01371 #endif /* EAP_SUPPORT */
01372 
01373 #if CHAP_SUPPORT
01374         if (go->neg_chap)
01375         try_.neg_chap = 0;
01376         else
01377 #endif /* CHAP_SUPPORT */
01378 
01379 #if PAP_SUPPORT
01380         if(1)
01381         try_.neg_upap = 0;
01382         else
01383 #endif /* PAP_SUPPORT */
01384         {}
01385 
01386         p += cilen - CILEN_SHORT;
01387     }
01388     }
01389 
01390 #if LQR_SUPPORT
01391     /*
01392      * If they can't cope with our link quality protocol, we'll have
01393      * to stop asking for LQR.  We haven't got any other protocol.
01394      * If they Nak the reporting period, take their value XXX ?
01395      */
01396     NAKCILQR(CI_QUALITY, neg_lqr,
01397          if (cishort != PPP_LQR)
01398          try_.neg_lqr = 0;
01399          else
01400          try_.lqr_period = cilong;
01401          );
01402 #endif /* LQR_SUPPORT */
01403 
01404     /*
01405      * Only implementing CBCP...not the rest of the callback options
01406      */
01407     NAKCICHAR(CI_CALLBACK, neg_cbcp,
01408               try_.neg_cbcp = 0;
01409               (void)cichar; /* if CHAP support is not compiled, cichar is set but not used, which makes some compilers complaining */
01410               );
01411 
01412     /*
01413      * Check for a looped-back line.
01414      */
01415     NAKCILONG(CI_MAGICNUMBER, neg_magicnumber,
01416           try_.magicnumber = magic();
01417           looped_back = 1;
01418           );
01419 
01420     /*
01421      * Peer shouldn't send Nak for protocol compression or
01422      * address/control compression requests; they should send
01423      * a Reject instead.  If they send a Nak, treat it as a Reject.
01424      */
01425     NAKCIVOID(CI_PCOMPRESSION, neg_pcompression);
01426     NAKCIVOID(CI_ACCOMPRESSION, neg_accompression);
01427 
01428 #ifdef HAVE_MULTILINK
01429     /*
01430      * Nak for MRRU option - accept their value if it is smaller
01431      * than the one we want.
01432      */
01433     if (go->neg_mrru) {
01434     NAKCISHORT(CI_MRRU, neg_mrru,
01435            if (treat_as_reject)
01436                try_.neg_mrru = 0;
01437            else if (cishort <= wo->mrru)
01438                try_.mrru = cishort;
01439            );
01440     }
01441 #else /* HAVE_MULTILINK */
01442     LWIP_UNUSED_ARG(treat_as_reject);
01443 #endif /* HAVE_MULTILINK */
01444 
01445     /*
01446      * Nak for short sequence numbers shouldn't be sent, treat it
01447      * like a reject.
01448      */
01449     NAKCIVOID(CI_SSNHF, neg_ssnhf);
01450 
01451     /*
01452      * Nak of the endpoint discriminator option is not permitted,
01453      * treat it like a reject.
01454      */
01455     NAKCIENDP(CI_EPDISC, neg_endpoint);
01456 
01457     /*
01458      * There may be remaining CIs, if the peer is requesting negotiation
01459      * on an option that we didn't include in our request packet.
01460      * If we see an option that we requested, or one we've already seen
01461      * in this packet, then this packet is bad.
01462      * If we wanted to respond by starting to negotiate on the requested
01463      * option(s), we could, but we don't, because except for the
01464      * authentication type and quality protocol, if we are not negotiating
01465      * an option, it is because we were told not to.
01466      * For the authentication type, the Nak from the peer means
01467      * `let me authenticate myself with you' which is a bit pointless.
01468      * For the quality protocol, the Nak means `ask me to send you quality
01469      * reports', but if we didn't ask for them, we don't want them.
01470      * An option we don't recognize represents the peer asking to
01471      * negotiate some option we don't support, so ignore it.
01472      */
01473     while (len >= CILEN_VOID) {
01474     GETCHAR(citype, p);
01475     GETCHAR(cilen, p);
01476     if (cilen < CILEN_VOID || (len -= cilen) < 0)
01477         goto bad;
01478     next = p + cilen - 2;
01479 
01480     switch (citype) {
01481     case CI_MRU:
01482         if ((go->neg_mru && go->mru != PPP_DEFMRU)
01483         || no.neg_mru || cilen != CILEN_SHORT)
01484         goto bad;
01485         GETSHORT(cishort, p);
01486         if (cishort < PPP_DEFMRU) {
01487         try_.neg_mru = 1;
01488         try_.mru = cishort;
01489         }
01490         break;
01491     case CI_ASYNCMAP:
01492         if ((go->neg_asyncmap && go->asyncmap != 0xFFFFFFFF)
01493         || no.neg_asyncmap || cilen != CILEN_LONG)
01494         goto bad;
01495         break;
01496     case CI_AUTHTYPE:
01497         if (0
01498 #if CHAP_SUPPORT
01499                 || go->neg_chap || no.neg_chap
01500 #endif /* CHAP_SUPPORT */
01501 #if PAP_SUPPORT
01502                 || go->neg_upap || no.neg_upap
01503 #endif /* PAP_SUPPORT */
01504 #if EAP_SUPPORT
01505         || go->neg_eap || no.neg_eap
01506 #endif /* EAP_SUPPORT */
01507         )
01508         goto bad;
01509         break;
01510     case CI_MAGICNUMBER:
01511         if (go->neg_magicnumber || no.neg_magicnumber ||
01512         cilen != CILEN_LONG)
01513         goto bad;
01514         break;
01515     case CI_PCOMPRESSION:
01516         if (go->neg_pcompression || no.neg_pcompression
01517         || cilen != CILEN_VOID)
01518         goto bad;
01519         break;
01520     case CI_ACCOMPRESSION:
01521         if (go->neg_accompression || no.neg_accompression
01522         || cilen != CILEN_VOID)
01523         goto bad;
01524         break;
01525 #if LQR_SUPPORT
01526     case CI_QUALITY:
01527         if (go->neg_lqr || no.neg_lqr || cilen != CILEN_LQR)
01528         goto bad;
01529         break;
01530 #endif /* LQR_SUPPORT */
01531 #ifdef HAVE_MULTILINK
01532     case CI_MRRU:
01533         if (go->neg_mrru || no.neg_mrru || cilen != CILEN_SHORT)
01534         goto bad;
01535         break;
01536 #endif /* HAVE_MULTILINK */
01537     case CI_SSNHF:
01538         if (go->neg_ssnhf || no.neg_ssnhf || cilen != CILEN_VOID)
01539         goto bad;
01540         try_.neg_ssnhf = 1;
01541         break;
01542     case CI_EPDISC:
01543         if (go->neg_endpoint || no.neg_endpoint || cilen < CILEN_CHAR)
01544         goto bad;
01545         break;
01546     default:
01547         break;
01548     }
01549     p = next;
01550     }
01551 
01552     /*
01553      * OK, the Nak is good.  Now we can update state.
01554      * If there are any options left we ignore them.
01555      */
01556     if (f->state != PPP_FSM_OPENED) {
01557     if (looped_back) {
01558         if (++try_.numloops >= pcb->settings.lcp_loopbackfail) {
01559         ppp_notice("Serial line is looped back.");
01560         pcb->err_code = PPPERR_LOOPBACK;
01561         lcp_close(f->pcb, "Loopback detected");
01562         }
01563     } else
01564         try_.numloops = 0;
01565     *go = try_;
01566     }
01567 
01568     return 1;
01569 
01570 bad:
01571     LCPDEBUG(("lcp_nakci: received bad Nak!"));
01572     return 0;
01573 }
01574 
01575 
01576 /*
01577  * lcp_rejci - Peer has Rejected some of our CIs.
01578  * This should not modify any state if the Reject is bad
01579  * or if LCP is in the OPENED state.
01580  *
01581  * Returns:
01582  *  0 - Reject was bad.
01583  *  1 - Reject was good.
01584  */
01585 static int lcp_rejci(fsm *f, u_char *p, int len) {
01586     ppp_pcb *pcb = f->pcb;
01587     lcp_options *go = &pcb->lcp_gotoptions;
01588     u_char cichar;
01589     u_short cishort;
01590     u32_t cilong;
01591     lcp_options try_;       /* options to request next time */
01592 
01593     try_ = *go;
01594 
01595     /*
01596      * Any Rejected CIs must be in exactly the same order that we sent.
01597      * Check packet length and CI length at each step.
01598      * If we find any deviations, then this packet is bad.
01599      */
01600 #define REJCIVOID(opt, neg) \
01601     if (go->neg && \
01602     len >= CILEN_VOID && \
01603     p[1] == CILEN_VOID && \
01604     p[0] == opt) { \
01605     len -= CILEN_VOID; \
01606     INCPTR(CILEN_VOID, p); \
01607     try_.neg = 0; \
01608     }
01609 #define REJCISHORT(opt, neg, val) \
01610     if (go->neg && \
01611     len >= CILEN_SHORT && \
01612     p[1] == CILEN_SHORT && \
01613     p[0] == opt) { \
01614     len -= CILEN_SHORT; \
01615     INCPTR(2, p); \
01616     GETSHORT(cishort, p); \
01617     /* Check rejected value. */ \
01618     if (cishort != val) \
01619         goto bad; \
01620     try_.neg = 0; \
01621     }
01622 
01623 #if CHAP_SUPPORT && EAP_SUPPORT && PAP_SUPPORT
01624 #define REJCICHAP(opt, neg, val) \
01625     if (go->neg && \
01626     len >= CILEN_CHAP && \
01627     p[1] == CILEN_CHAP && \
01628     p[0] == opt) { \
01629     len -= CILEN_CHAP; \
01630     INCPTR(2, p); \
01631     GETSHORT(cishort, p); \
01632     GETCHAR(cichar, p); \
01633     /* Check rejected value. */ \
01634     if ((cishort != PPP_CHAP) || (cichar != (CHAP_DIGEST(val)))) \
01635         goto bad; \
01636     try_.neg = 0; \
01637     try_.neg_eap = try_.neg_upap = 0; \
01638     }
01639 #endif /* CHAP_SUPPORT && EAP_SUPPORT && PAP_SUPPORT */
01640 
01641 #if CHAP_SUPPORT && !EAP_SUPPORT && PAP_SUPPORT
01642 #define REJCICHAP(opt, neg, val) \
01643     if (go->neg && \
01644     len >= CILEN_CHAP && \
01645     p[1] == CILEN_CHAP && \
01646     p[0] == opt) { \
01647     len -= CILEN_CHAP; \
01648     INCPTR(2, p); \
01649     GETSHORT(cishort, p); \
01650     GETCHAR(cichar, p); \
01651     /* Check rejected value. */ \
01652     if ((cishort != PPP_CHAP) || (cichar != (CHAP_DIGEST(val)))) \
01653         goto bad; \
01654     try_.neg = 0; \
01655     try_.neg_upap = 0; \
01656     }
01657 #endif /* CHAP_SUPPORT && !EAP_SUPPORT && PAP_SUPPORT */
01658 
01659 #if CHAP_SUPPORT && EAP_SUPPORT && !PAP_SUPPORT
01660 #define REJCICHAP(opt, neg, val) \
01661     if (go->neg && \
01662     len >= CILEN_CHAP && \
01663     p[1] == CILEN_CHAP && \
01664     p[0] == opt) { \
01665     len -= CILEN_CHAP; \
01666     INCPTR(2, p); \
01667     GETSHORT(cishort, p); \
01668     GETCHAR(cichar, p); \
01669     /* Check rejected value. */ \
01670     if ((cishort != PPP_CHAP) || (cichar != (CHAP_DIGEST(val)))) \
01671         goto bad; \
01672     try_.neg = 0; \
01673     try_.neg_eap = 0; \
01674     }
01675 #endif /* CHAP_SUPPORT && EAP_SUPPORT && !PAP_SUPPORT */
01676 
01677 #if CHAP_SUPPORT && !EAP_SUPPORT && !PAP_SUPPORT
01678 #define REJCICHAP(opt, neg, val) \
01679     if (go->neg && \
01680     len >= CILEN_CHAP && \
01681     p[1] == CILEN_CHAP && \
01682     p[0] == opt) { \
01683     len -= CILEN_CHAP; \
01684     INCPTR(2, p); \
01685     GETSHORT(cishort, p); \
01686     GETCHAR(cichar, p); \
01687     /* Check rejected value. */ \
01688     if ((cishort != PPP_CHAP) || (cichar != (CHAP_DIGEST(val)))) \
01689         goto bad; \
01690     try_.neg = 0; \
01691     }
01692 #endif /* CHAP_SUPPORT && !EAP_SUPPORT && !PAP_SUPPORT */
01693 
01694 #define REJCILONG(opt, neg, val) \
01695     if (go->neg && \
01696     len >= CILEN_LONG && \
01697     p[1] == CILEN_LONG && \
01698     p[0] == opt) { \
01699     len -= CILEN_LONG; \
01700     INCPTR(2, p); \
01701     GETLONG(cilong, p); \
01702     /* Check rejected value. */ \
01703     if (cilong != val) \
01704         goto bad; \
01705     try_.neg = 0; \
01706     }
01707 #if LQR_SUPPORT
01708 #define REJCILQR(opt, neg, val) \
01709     if (go->neg && \
01710     len >= CILEN_LQR && \
01711     p[1] == CILEN_LQR && \
01712     p[0] == opt) { \
01713     len -= CILEN_LQR; \
01714     INCPTR(2, p); \
01715     GETSHORT(cishort, p); \
01716     GETLONG(cilong, p); \
01717     /* Check rejected value. */ \
01718     if (cishort != PPP_LQR || cilong != val) \
01719         goto bad; \
01720     try_.neg = 0; \
01721     }
01722 #endif /* LQR_SUPPORT */
01723 #define REJCICBCP(opt, neg, val) \
01724     if (go->neg && \
01725     len >= CILEN_CBCP && \
01726     p[1] == CILEN_CBCP && \
01727     p[0] == opt) { \
01728     len -= CILEN_CBCP; \
01729     INCPTR(2, p); \
01730     GETCHAR(cichar, p); \
01731     /* Check rejected value. */ \
01732     if (cichar != val) \
01733         goto bad; \
01734     try_.neg = 0; \
01735     }
01736 #define REJCIENDP(opt, neg, class, val, vlen) \
01737     if (go->neg && \
01738     len >= CILEN_CHAR + vlen && \
01739     p[0] == opt && \
01740     p[1] == CILEN_CHAR + vlen) { \
01741     int i; \
01742     len -= CILEN_CHAR + vlen; \
01743     INCPTR(2, p); \
01744     GETCHAR(cichar, p); \
01745     if (cichar != class) \
01746         goto bad; \
01747     for (i = 0; i < vlen; ++i) { \
01748         GETCHAR(cichar, p); \
01749         if (cichar != val[i]) \
01750         goto bad; \
01751     } \
01752     try_.neg = 0; \
01753     }
01754 
01755     REJCISHORT(CI_MRU, neg_mru, go->mru);
01756     REJCILONG(CI_ASYNCMAP, neg_asyncmap, go->asyncmap);
01757 #if EAP_SUPPORT
01758     REJCISHORT(CI_AUTHTYPE, neg_eap, PPP_EAP);
01759     if (!go->neg_eap) {
01760 #endif /* EAP_SUPPORT */
01761 #if CHAP_SUPPORT
01762     REJCICHAP(CI_AUTHTYPE, neg_chap, go->chap_mdtype);
01763     if (!go->neg_chap) {
01764 #endif /* CHAP_SUPPORT */
01765 #if PAP_SUPPORT
01766         REJCISHORT(CI_AUTHTYPE, neg_upap, PPP_PAP);
01767 #endif /* PAP_SUPPORT */
01768 #if CHAP_SUPPORT
01769     }
01770 #endif /* CHAP_SUPPORT */
01771 #if EAP_SUPPORT
01772     }
01773 #endif /* EAP_SUPPORT */
01774 #if LQR_SUPPORT
01775     REJCILQR(CI_QUALITY, neg_lqr, go->lqr_period);
01776 #endif /* LQR_SUPPORT */
01777     REJCICBCP(CI_CALLBACK, neg_cbcp, CBCP_OPT);
01778     REJCILONG(CI_MAGICNUMBER, neg_magicnumber, go->magicnumber);
01779     REJCIVOID(CI_PCOMPRESSION, neg_pcompression);
01780     REJCIVOID(CI_ACCOMPRESSION, neg_accompression);
01781 #ifdef HAVE_MULTILINK
01782     REJCISHORT(CI_MRRU, neg_mrru, go->mrru);
01783 #endif /* HAVE_MULTILINK */
01784     REJCIVOID(CI_SSNHF, neg_ssnhf);
01785     REJCIENDP(CI_EPDISC, neg_endpoint, go->endpoint.class_,
01786           go->endpoint.value, go->endpoint.length);
01787 
01788     /*
01789      * If there are any remaining CIs, then this packet is bad.
01790      */
01791     if (len != 0)
01792     goto bad;
01793     /*
01794      * Now we can update state.
01795      */
01796     if (f->state != PPP_FSM_OPENED)
01797     *go = try_;
01798     return 1;
01799 
01800 bad:
01801     LCPDEBUG(("lcp_rejci: received bad Reject!"));
01802     return 0;
01803 }
01804 
01805 
01806 /*
01807  * lcp_reqci - Check the peer's requested CIs and send appropriate response.
01808  *
01809  * Returns: CONFACK, CONFNAK or CONFREJ and input packet modified
01810  * appropriately.  If reject_if_disagree is non-zero, doesn't return
01811  * CONFNAK; returns CONFREJ if it can't return CONFACK.
01812  *
01813  * inp = Requested CIs
01814  * lenp = Length of requested CIs
01815  */
01816 static int lcp_reqci(fsm *f, u_char *inp, int *lenp, int reject_if_disagree) {
01817     ppp_pcb *pcb = f->pcb;
01818     lcp_options *go = &pcb->lcp_gotoptions;
01819     lcp_options *ho = &pcb->lcp_hisoptions;
01820     lcp_options *ao = &pcb->lcp_allowoptions;
01821     u_char *cip, *next;     /* Pointer to current and next CIs */
01822     int cilen, citype, cichar;  /* Parsed len, type, char value */
01823     u_short cishort;        /* Parsed short value */
01824     u32_t cilong;       /* Parse long value */
01825     int rc = CONFACK;       /* Final packet return code */
01826     int orc;            /* Individual option return code */
01827     u_char *p;          /* Pointer to next char to parse */
01828     u_char *rejp;       /* Pointer to next char in reject frame */
01829     struct pbuf *nakp;          /* Nak buffer */
01830     u_char *nakoutp;        /* Pointer to next char in Nak frame */
01831     int l = *lenp;      /* Length left */
01832 
01833     /*
01834      * Reset all his options.
01835      */
01836     BZERO(ho, sizeof(*ho));
01837 
01838     /*
01839      * Process all his options.
01840      */
01841     next = inp;
01842     nakp = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_CTRL_PBUF_MAX_SIZE), PPP_CTRL_PBUF_TYPE);
01843     if(NULL == nakp)
01844         return 0;
01845     if(nakp->tot_len != nakp->len) {
01846         pbuf_free(nakp);
01847         return 0;
01848     }
01849 
01850     nakoutp = (u_char*)nakp->payload;
01851     rejp = inp;
01852     while (l) {
01853     orc = CONFACK;          /* Assume success */
01854     cip = p = next;         /* Remember begining of CI */
01855     if (l < 2 ||            /* Not enough data for CI header or */
01856         p[1] < 2 ||         /*  CI length too small or */
01857         p[1] > l) {         /*  CI length too big? */
01858         LCPDEBUG(("lcp_reqci: bad CI length!"));
01859         orc = CONFREJ;      /* Reject bad CI */
01860         cilen = l;          /* Reject till end of packet */
01861         l = 0;          /* Don't loop again */
01862         citype = 0;
01863         goto endswitch;
01864     }
01865     GETCHAR(citype, p);     /* Parse CI type */
01866     GETCHAR(cilen, p);      /* Parse CI length */
01867     l -= cilen;         /* Adjust remaining length */
01868     next += cilen;          /* Step to next CI */
01869 
01870     switch (citype) {       /* Check CI type */
01871     case CI_MRU:
01872         if (!ao->neg_mru ||     /* Allow option? */
01873         cilen != CILEN_SHORT) { /* Check CI length */
01874         orc = CONFREJ;      /* Reject CI */
01875         break;
01876         }
01877         GETSHORT(cishort, p);   /* Parse MRU */
01878 
01879         /*
01880          * He must be able to receive at least our minimum.
01881          * No need to check a maximum.  If he sends a large number,
01882          * we'll just ignore it.
01883          */
01884         if (cishort < PPP_MINMRU) {
01885         orc = CONFNAK;      /* Nak CI */
01886         PUTCHAR(CI_MRU, nakoutp);
01887         PUTCHAR(CILEN_SHORT, nakoutp);
01888         PUTSHORT(PPP_MINMRU, nakoutp);  /* Give him a hint */
01889         break;
01890         }
01891         ho->neg_mru = 1;        /* Remember he sent MRU */
01892         ho->mru = cishort;      /* And remember value */
01893         break;
01894 
01895     case CI_ASYNCMAP:
01896         if (!ao->neg_asyncmap ||
01897         cilen != CILEN_LONG) {
01898         orc = CONFREJ;
01899         break;
01900         }
01901         GETLONG(cilong, p);
01902 
01903         /*
01904          * Asyncmap must have set at least the bits
01905          * which are set in lcp_allowoptions[unit].asyncmap.
01906          */
01907         if ((ao->asyncmap & ~cilong) != 0) {
01908         orc = CONFNAK;
01909         PUTCHAR(CI_ASYNCMAP, nakoutp);
01910         PUTCHAR(CILEN_LONG, nakoutp);
01911         PUTLONG(ao->asyncmap | cilong, nakoutp);
01912         break;
01913         }
01914         ho->neg_asyncmap = 1;
01915         ho->asyncmap = cilong;
01916         break;
01917 
01918     case CI_AUTHTYPE:
01919         if (cilen < CILEN_SHORT ||
01920         !(0
01921 #if PAP_SUPPORT
01922         || ao->neg_upap
01923 #endif /* PAP_SUPPORT */
01924 #if CHAP_SUPPORT
01925         || ao->neg_chap
01926 #endif /* CHAP_SUPPORT */
01927 #if EAP_SUPPORT
01928         || ao->neg_eap
01929 #endif /* EAP_SUPPORT */
01930         )) {
01931         /*
01932          * Reject the option if we're not willing to authenticate.
01933          */
01934         ppp_dbglog("No auth is possible");
01935         orc = CONFREJ;
01936         break;
01937         }
01938         GETSHORT(cishort, p);
01939 
01940         /*
01941          * Authtype must be PAP, CHAP, or EAP.
01942          *
01943          * Note: if more than one of ao->neg_upap, ao->neg_chap, and
01944          * ao->neg_eap are set, and the peer sends a Configure-Request
01945          * with two or more authenticate-protocol requests, then we will
01946          * reject the second request.
01947          * Whether we end up doing CHAP, UPAP, or EAP depends then on
01948          * the ordering of the CIs in the peer's Configure-Request.
01949              */
01950 
01951 #if PAP_SUPPORT
01952         if (cishort == PPP_PAP) {
01953         /* we've already accepted CHAP or EAP */
01954         if (0
01955 #if CHAP_SUPPORT
01956             || ho->neg_chap
01957 #endif /* CHAP_SUPPORT */
01958 #if EAP_SUPPORT
01959             || ho->neg_eap
01960 #endif /* EAP_SUPPORT */
01961             || cilen != CILEN_SHORT) {
01962             LCPDEBUG(("lcp_reqci: rcvd AUTHTYPE PAP, rejecting..."));
01963             orc = CONFREJ;
01964             break;
01965         }
01966         if (!ao->neg_upap) {    /* we don't want to do PAP */
01967             orc = CONFNAK;  /* NAK it and suggest CHAP or EAP */
01968             PUTCHAR(CI_AUTHTYPE, nakoutp);
01969 #if EAP_SUPPORT
01970             if (ao->neg_eap) {
01971             PUTCHAR(CILEN_SHORT, nakoutp);
01972             PUTSHORT(PPP_EAP, nakoutp);
01973             } else {
01974 #endif /* EAP_SUPPORT */
01975 #if CHAP_SUPPORT
01976             PUTCHAR(CILEN_CHAP, nakoutp);
01977             PUTSHORT(PPP_CHAP, nakoutp);
01978             PUTCHAR(CHAP_DIGEST(ao->chap_mdtype), nakoutp);
01979 #endif /* CHAP_SUPPORT */
01980 #if EAP_SUPPORT
01981             }
01982 #endif /* EAP_SUPPORT */
01983             break;
01984         }
01985         ho->neg_upap = 1;
01986         break;
01987         }
01988 #endif /* PAP_SUPPORT */
01989 #if CHAP_SUPPORT
01990         if (cishort == PPP_CHAP) {
01991         /* we've already accepted PAP or EAP */
01992         if (
01993 #if PAP_SUPPORT
01994             ho->neg_upap ||
01995 #endif /* PAP_SUPPORT */
01996 #if EAP_SUPPORT
01997             ho->neg_eap ||
01998 #endif /* EAP_SUPPORT */
01999             cilen != CILEN_CHAP) {
02000             LCPDEBUG(("lcp_reqci: rcvd AUTHTYPE CHAP, rejecting..."));
02001             orc = CONFREJ;
02002             break;
02003         }
02004         if (!ao->neg_chap) {    /* we don't want to do CHAP */
02005             orc = CONFNAK;  /* NAK it and suggest EAP or PAP */
02006             PUTCHAR(CI_AUTHTYPE, nakoutp);
02007             PUTCHAR(CILEN_SHORT, nakoutp);
02008 #if EAP_SUPPORT
02009             if (ao->neg_eap) {
02010             PUTSHORT(PPP_EAP, nakoutp);
02011             } else
02012 #endif /* EAP_SUPPORT */
02013 #if PAP_SUPPORT
02014             if(1) {
02015             PUTSHORT(PPP_PAP, nakoutp);
02016             }
02017             else
02018 #endif /* PAP_SUPPORT */
02019             {}
02020             break;
02021         }
02022         GETCHAR(cichar, p); /* get digest type */
02023         if (!(CHAP_CANDIGEST(ao->chap_mdtype, cichar))) {
02024             /*
02025              * We can't/won't do the requested type,
02026              * suggest something else.
02027              */
02028             orc = CONFNAK;
02029             PUTCHAR(CI_AUTHTYPE, nakoutp);
02030             PUTCHAR(CILEN_CHAP, nakoutp);
02031             PUTSHORT(PPP_CHAP, nakoutp);
02032             PUTCHAR(CHAP_DIGEST(ao->chap_mdtype), nakoutp);
02033             break;
02034         }
02035         ho->chap_mdtype = CHAP_MDTYPE_D(cichar); /* save md type */
02036         ho->neg_chap = 1;
02037         break;
02038         }
02039 #endif /* CHAP_SUPPORT */
02040 #if EAP_SUPPORT
02041         if (cishort == PPP_EAP) {
02042         /* we've already accepted CHAP or PAP */
02043         if (
02044 #if CHAP_SUPPORT
02045             ho->neg_chap ||
02046 #endif /* CHAP_SUPPORT */
02047 #if PAP_SUPPORT
02048             ho->neg_upap ||
02049 #endif /* PAP_SUPPORT */
02050             cilen != CILEN_SHORT) {
02051             LCPDEBUG(("lcp_reqci: rcvd AUTHTYPE EAP, rejecting..."));
02052             orc = CONFREJ;
02053             break;
02054         }
02055         if (!ao->neg_eap) { /* we don't want to do EAP */
02056             orc = CONFNAK;  /* NAK it and suggest CHAP or PAP */
02057             PUTCHAR(CI_AUTHTYPE, nakoutp);
02058 #if CHAP_SUPPORT
02059             if (ao->neg_chap) {
02060             PUTCHAR(CILEN_CHAP, nakoutp);
02061             PUTSHORT(PPP_CHAP, nakoutp);
02062             PUTCHAR(CHAP_DIGEST(ao->chap_mdtype), nakoutp);
02063             } else
02064 #endif /* CHAP_SUPPORT */
02065 #if PAP_SUPPORT
02066             if(1) {
02067             PUTCHAR(CILEN_SHORT, nakoutp);
02068             PUTSHORT(PPP_PAP, nakoutp);
02069             } else
02070 #endif /* PAP_SUPPORT */
02071             {}
02072             break;
02073         }
02074         ho->neg_eap = 1;
02075         break;
02076         }
02077 #endif /* EAP_SUPPORT */
02078 
02079         /*
02080          * We don't recognize the protocol they're asking for.
02081          * Nak it with something we're willing to do.
02082          * (At this point we know ao->neg_upap || ao->neg_chap ||
02083          * ao->neg_eap.)
02084          */
02085         orc = CONFNAK;
02086         PUTCHAR(CI_AUTHTYPE, nakoutp);
02087 
02088 #if EAP_SUPPORT
02089         if (ao->neg_eap) {
02090         PUTCHAR(CILEN_SHORT, nakoutp);
02091         PUTSHORT(PPP_EAP, nakoutp);
02092         } else
02093 #endif /* EAP_SUPPORT */
02094 #if CHAP_SUPPORT
02095         if (ao->neg_chap) {
02096         PUTCHAR(CILEN_CHAP, nakoutp);
02097         PUTSHORT(PPP_CHAP, nakoutp);
02098         PUTCHAR(CHAP_DIGEST(ao->chap_mdtype), nakoutp);
02099         } else
02100 #endif /* CHAP_SUPPORT */
02101 #if PAP_SUPPORT
02102         if(1) {
02103         PUTCHAR(CILEN_SHORT, nakoutp);
02104         PUTSHORT(PPP_PAP, nakoutp);
02105         } else
02106 #endif /* PAP_SUPPORT */
02107         {}
02108         break;
02109 
02110 #if LQR_SUPPORT
02111     case CI_QUALITY:
02112         if (!ao->neg_lqr ||
02113         cilen != CILEN_LQR) {
02114         orc = CONFREJ;
02115         break;
02116         }
02117 
02118         GETSHORT(cishort, p);
02119         GETLONG(cilong, p);
02120 
02121         /*
02122          * Check the protocol and the reporting period.
02123          * XXX When should we Nak this, and what with?
02124          */
02125         if (cishort != PPP_LQR) {
02126         orc = CONFNAK;
02127         PUTCHAR(CI_QUALITY, nakoutp);
02128         PUTCHAR(CILEN_LQR, nakoutp);
02129         PUTSHORT(PPP_LQR, nakoutp);
02130         PUTLONG(ao->lqr_period, nakoutp);
02131         break;
02132         }
02133         break;
02134 #endif /* LQR_SUPPORT */
02135 
02136     case CI_MAGICNUMBER:
02137         if (!(ao->neg_magicnumber || go->neg_magicnumber) ||
02138         cilen != CILEN_LONG) {
02139         orc = CONFREJ;
02140         break;
02141         }
02142         GETLONG(cilong, p);
02143 
02144         /*
02145          * He must have a different magic number.
02146          */
02147         if (go->neg_magicnumber &&
02148         cilong == go->magicnumber) {
02149         cilong = magic();   /* Don't put magic() inside macro! */
02150         orc = CONFNAK;
02151         PUTCHAR(CI_MAGICNUMBER, nakoutp);
02152         PUTCHAR(CILEN_LONG, nakoutp);
02153         PUTLONG(cilong, nakoutp);
02154         break;
02155         }
02156         ho->neg_magicnumber = 1;
02157         ho->magicnumber = cilong;
02158         break;
02159 
02160 
02161     case CI_PCOMPRESSION:
02162         if (!ao->neg_pcompression ||
02163         cilen != CILEN_VOID) {
02164         orc = CONFREJ;
02165         break;
02166         }
02167         ho->neg_pcompression = 1;
02168         break;
02169 
02170     case CI_ACCOMPRESSION:
02171         if (!ao->neg_accompression ||
02172         cilen != CILEN_VOID) {
02173         orc = CONFREJ;
02174         break;
02175         }
02176         ho->neg_accompression = 1;
02177         break;
02178 
02179 #ifdef HAVE_MULTILINK
02180     case CI_MRRU:
02181         if (!ao->neg_mrru
02182         || !multilink
02183         || cilen != CILEN_SHORT) {
02184         orc = CONFREJ;
02185         break;
02186         }
02187 
02188         GETSHORT(cishort, p);
02189         /* possibly should insist on a minimum/maximum MRRU here */
02190         ho->neg_mrru = 1;
02191         ho->mrru = cishort;
02192         break;
02193 #endif /* HAVE_MULTILINK */
02194 
02195     case CI_SSNHF:
02196         if (!ao->neg_ssnhf
02197 #ifdef HAVE_MULTILINK
02198         || !multilink
02199 #endif /* HAVE_MULTILINK */
02200         || cilen != CILEN_VOID) {
02201         orc = CONFREJ;
02202         break;
02203         }
02204         ho->neg_ssnhf = 1;
02205         break;
02206 
02207     case CI_EPDISC:
02208         if (!ao->neg_endpoint ||
02209         cilen < CILEN_CHAR ||
02210         cilen > CILEN_CHAR + MAX_ENDP_LEN) {
02211         orc = CONFREJ;
02212         break;
02213         }
02214         GETCHAR(cichar, p);
02215         cilen -= CILEN_CHAR;
02216         ho->neg_endpoint = 1;
02217         ho->endpoint.class_ = cichar;
02218         ho->endpoint.length = cilen;
02219         MEMCPY(ho->endpoint.value, p, cilen);
02220         INCPTR(cilen, p);
02221         break;
02222 
02223     default:
02224         LCPDEBUG(("lcp_reqci: rcvd unknown option %d", citype));
02225         orc = CONFREJ;
02226         break;
02227     }
02228 
02229 endswitch:
02230     if (orc == CONFACK &&       /* Good CI */
02231         rc != CONFACK)      /*  but prior CI wasnt? */
02232         continue;           /* Don't send this one */
02233 
02234     if (orc == CONFNAK) {       /* Nak this CI? */
02235         if (reject_if_disagree  /* Getting fed up with sending NAKs? */
02236         && citype != CI_MAGICNUMBER) {
02237         orc = CONFREJ;      /* Get tough if so */
02238         } else {
02239         if (rc == CONFREJ)  /* Rejecting prior CI? */
02240             continue;       /* Don't send this one */
02241         rc = CONFNAK;
02242         }
02243     }
02244     if (orc == CONFREJ) {       /* Reject this CI */
02245         rc = CONFREJ;
02246         if (cip != rejp)        /* Need to move rejected CI? */
02247         MEMCPY(rejp, cip, cilen); /* Move it */
02248         INCPTR(cilen, rejp);    /* Update output pointer */
02249     }
02250     }
02251 
02252     /*
02253      * If we wanted to send additional NAKs (for unsent CIs), the
02254      * code would go here.  The extra NAKs would go at *nakoutp.
02255      * At present there are no cases where we want to ask the
02256      * peer to negotiate an option.
02257      */
02258 
02259     switch (rc) {
02260     case CONFACK:
02261     *lenp = next - inp;
02262     break;
02263     case CONFNAK:
02264     /*
02265      * Copy the Nak'd options from the nak buffer to the caller's buffer.
02266      */
02267     *lenp = nakoutp - (u_char*)nakp->payload;
02268     MEMCPY(inp, nakp->payload, *lenp);
02269     break;
02270     case CONFREJ:
02271     *lenp = rejp - inp;
02272     break;
02273     default:
02274     break;
02275     }
02276 
02277     pbuf_free(nakp);
02278     LCPDEBUG(("lcp_reqci: returning CONF%s.", CODENAME(rc)));
02279     return (rc);            /* Return final code */
02280 }
02281 
02282 
02283 /*
02284  * lcp_up - LCP has come UP.
02285  */
02286 static void lcp_up(fsm *f) {
02287     ppp_pcb *pcb = f->pcb;
02288     lcp_options *wo = &pcb->lcp_wantoptions;
02289     lcp_options *ho = &pcb->lcp_hisoptions;
02290     lcp_options *go = &pcb->lcp_gotoptions;
02291     lcp_options *ao = &pcb->lcp_allowoptions;
02292     int mtu, mru;
02293 
02294     if (!go->neg_magicnumber)
02295     go->magicnumber = 0;
02296     if (!ho->neg_magicnumber)
02297     ho->magicnumber = 0;
02298 
02299     /*
02300      * Set our MTU to the smaller of the MTU we wanted and
02301      * the MRU our peer wanted.  If we negotiated an MRU,
02302      * set our MRU to the larger of value we wanted and
02303      * the value we got in the negotiation.
02304      * Note on the MTU: the link MTU can be the MRU the peer wanted,
02305      * the interface MTU is set to the lowest of that, the
02306      * MTU we want to use, and our link MRU.
02307      */
02308     mtu = ho->neg_mru? ho->mru: PPP_MRU;
02309     mru = go->neg_mru? LWIP_MAX(wo->mru, go->mru): PPP_MRU;
02310 #ifdef HAVE_MULTILINK
02311     if (!(multilink && go->neg_mrru && ho->neg_mrru))
02312 #endif /* HAVE_MULTILINK */
02313     netif_set_mtu(pcb, LWIP_MIN(LWIP_MIN(mtu, mru), ao->mru));
02314     ppp_send_config(pcb, mtu,
02315             (ho->neg_asyncmap? ho->asyncmap: 0xffffffff),
02316             ho->neg_pcompression, ho->neg_accompression);
02317     ppp_recv_config(pcb, mru,
02318             (pcb->settings.lax_recv? 0: go->neg_asyncmap? go->asyncmap: 0xffffffff),
02319             go->neg_pcompression, go->neg_accompression);
02320 
02321     if (ho->neg_mru)
02322     pcb->peer_mru = ho->mru;
02323 
02324     lcp_echo_lowerup(f->pcb);  /* Enable echo messages */
02325 
02326     link_established(pcb);
02327 }
02328 
02329 
02330 /*
02331  * lcp_down - LCP has gone DOWN.
02332  *
02333  * Alert other protocols.
02334  */
02335 static void lcp_down(fsm *f) {
02336     ppp_pcb *pcb = f->pcb;
02337     lcp_options *go = &pcb->lcp_gotoptions;
02338 
02339     lcp_echo_lowerdown(f->pcb);
02340 
02341     link_down(pcb);
02342 
02343     ppp_send_config(pcb, PPP_MRU, 0xffffffff, 0, 0);
02344     ppp_recv_config(pcb, PPP_MRU,
02345             (go->neg_asyncmap? go->asyncmap: 0xffffffff),
02346             go->neg_pcompression, go->neg_accompression);
02347     pcb->peer_mru = PPP_MRU;
02348 }
02349 
02350 
02351 /*
02352  * lcp_starting - LCP needs the lower layer up.
02353  */
02354 static void lcp_starting(fsm *f) {
02355     ppp_pcb *pcb = f->pcb;
02356     link_required(pcb);
02357 }
02358 
02359 
02360 /*
02361  * lcp_finished - LCP has finished with the lower layer.
02362  */
02363 static void lcp_finished(fsm *f) {
02364     ppp_pcb *pcb = f->pcb;
02365     link_terminated(pcb);
02366 }
02367 
02368 
02369 #if PRINTPKT_SUPPORT
02370 /*
02371  * lcp_printpkt - print the contents of an LCP packet.
02372  */
02373 static const char* const lcp_codenames[] = {
02374     "ConfReq", "ConfAck", "ConfNak", "ConfRej",
02375     "TermReq", "TermAck", "CodeRej", "ProtRej",
02376     "EchoReq", "EchoRep", "DiscReq", "Ident",
02377     "TimeRem"
02378 };
02379 
02380 static int lcp_printpkt(const u_char *p, int plen,
02381         void (*printer) (void *, const char *, ...), void *arg) {
02382     int code, id, len, olen, i;
02383     const u_char *pstart, *optend;
02384     u_short cishort;
02385     u32_t cilong;
02386 
02387     if (plen < HEADERLEN)
02388     return 0;
02389     pstart = p;
02390     GETCHAR(code, p);
02391     GETCHAR(id, p);
02392     GETSHORT(len, p);
02393     if (len < HEADERLEN || len > plen)
02394     return 0;
02395 
02396    if (code >= 1 && code <= (int)LWIP_ARRAYSIZE(lcp_codenames))
02397     printer(arg, " %s", lcp_codenames[code-1]);
02398     else
02399     printer(arg, " code=0x%x", code);
02400     printer(arg, " id=0x%x", id);
02401     len -= HEADERLEN;
02402     switch (code) {
02403     case CONFREQ:
02404     case CONFACK:
02405     case CONFNAK:
02406     case CONFREJ:
02407     /* print option list */
02408     while (len >= 2) {
02409         GETCHAR(code, p);
02410         GETCHAR(olen, p);
02411         p -= 2;
02412         if (olen < 2 || olen > len) {
02413         break;
02414         }
02415         printer(arg, " <");
02416         len -= olen;
02417         optend = p + olen;
02418         switch (code) {
02419         case CI_MRU:
02420         if (olen == CILEN_SHORT) {
02421             p += 2;
02422             GETSHORT(cishort, p);
02423             printer(arg, "mru %d", cishort);
02424         }
02425         break;
02426         case CI_ASYNCMAP:
02427         if (olen == CILEN_LONG) {
02428             p += 2;
02429             GETLONG(cilong, p);
02430             printer(arg, "asyncmap 0x%x", cilong);
02431         }
02432         break;
02433         case CI_AUTHTYPE:
02434         if (olen >= CILEN_SHORT) {
02435             p += 2;
02436             printer(arg, "auth ");
02437             GETSHORT(cishort, p);
02438             switch (cishort) {
02439 #if PAP_SUPPORT
02440             case PPP_PAP:
02441             printer(arg, "pap");
02442             break;
02443 #endif /* PAP_SUPPORT */
02444 #if CHAP_SUPPORT
02445             case PPP_CHAP:
02446             printer(arg, "chap");
02447             if (p < optend) {
02448                 switch (*p) {
02449                 case CHAP_MD5:
02450                 printer(arg, " MD5");
02451                 ++p;
02452                 break;
02453 #if MSCHAP_SUPPORT
02454                 case CHAP_MICROSOFT:
02455                 printer(arg, " MS");
02456                 ++p;
02457                 break;
02458 
02459                 case CHAP_MICROSOFT_V2:
02460                 printer(arg, " MS-v2");
02461                 ++p;
02462                 break;
02463 #endif /* MSCHAP_SUPPORT */
02464                 default:
02465                 break;
02466                 }
02467             }
02468             break;
02469 #endif /* CHAP_SUPPORT */
02470 #if EAP_SUPPORT
02471             case PPP_EAP:
02472             printer(arg, "eap");
02473             break;
02474 #endif /* EAP_SUPPORT */
02475             default:
02476             printer(arg, "0x%x", cishort);
02477             }
02478         }
02479         break;
02480 #if LQR_SUPPORT
02481         case CI_QUALITY:
02482         if (olen >= CILEN_SHORT) {
02483             p += 2;
02484             printer(arg, "quality ");
02485             GETSHORT(cishort, p);
02486             switch (cishort) {
02487             case PPP_LQR:
02488             printer(arg, "lqr");
02489             break;
02490             default:
02491             printer(arg, "0x%x", cishort);
02492             }
02493         }
02494         break;
02495 #endif /* LQR_SUPPORT */
02496         case CI_CALLBACK:
02497         if (olen >= CILEN_CHAR) {
02498             p += 2;
02499             printer(arg, "callback ");
02500             GETCHAR(cishort, p);
02501             switch (cishort) {
02502             case CBCP_OPT:
02503             printer(arg, "CBCP");
02504             break;
02505             default:
02506             printer(arg, "0x%x", cishort);
02507             }
02508         }
02509         break;
02510         case CI_MAGICNUMBER:
02511         if (olen == CILEN_LONG) {
02512             p += 2;
02513             GETLONG(cilong, p);
02514             printer(arg, "magic 0x%x", cilong);
02515         }
02516         break;
02517         case CI_PCOMPRESSION:
02518         if (olen == CILEN_VOID) {
02519             p += 2;
02520             printer(arg, "pcomp");
02521         }
02522         break;
02523         case CI_ACCOMPRESSION:
02524         if (olen == CILEN_VOID) {
02525             p += 2;
02526             printer(arg, "accomp");
02527         }
02528         break;
02529         case CI_MRRU:
02530         if (olen == CILEN_SHORT) {
02531             p += 2;
02532             GETSHORT(cishort, p);
02533             printer(arg, "mrru %d", cishort);
02534         }
02535         break;
02536         case CI_SSNHF:
02537         if (olen == CILEN_VOID) {
02538             p += 2;
02539             printer(arg, "ssnhf");
02540         }
02541         break;
02542         case CI_EPDISC:
02543 #ifdef HAVE_MULTILINK
02544         if (olen >= CILEN_CHAR) {
02545             struct epdisc epd;
02546             p += 2;
02547             GETCHAR(epd.class, p);
02548             epd.length = olen - CILEN_CHAR;
02549             if (epd.length > MAX_ENDP_LEN)
02550             epd.length = MAX_ENDP_LEN;
02551             if (epd.length > 0) {
02552             MEMCPY(epd.value, p, epd.length);
02553             p += epd.length;
02554             }
02555             printer(arg, "endpoint [%s]", epdisc_to_str(&epd));
02556         }
02557 #else
02558         printer(arg, "endpoint");
02559 #endif
02560         break;
02561         default:
02562         break;
02563         }
02564         while (p < optend) {
02565         GETCHAR(code, p);
02566         printer(arg, " %.2x", code);
02567         }
02568         printer(arg, ">");
02569     }
02570     break;
02571 
02572     case TERMACK:
02573     case TERMREQ:
02574     if (len > 0 && *p >= ' ' && *p < 0x7f) {
02575         printer(arg, " ");
02576         ppp_print_string(p, len, printer, arg);
02577         p += len;
02578         len = 0;
02579     }
02580     break;
02581 
02582     case ECHOREQ:
02583     case ECHOREP:
02584     case DISCREQ:
02585     if (len >= 4) {
02586         GETLONG(cilong, p);
02587         printer(arg, " magic=0x%x", cilong);
02588         len -= 4;
02589     }
02590     break;
02591 
02592     case IDENTIF:
02593     case TIMEREM:
02594     if (len >= 4) {
02595         GETLONG(cilong, p);
02596         printer(arg, " magic=0x%x", cilong);
02597         len -= 4;
02598     }
02599     if (code == TIMEREM) {
02600         if (len < 4)
02601         break;
02602         GETLONG(cilong, p);
02603         printer(arg, " seconds=%u", cilong);
02604         len -= 4;
02605     }
02606     if (len > 0) {
02607         printer(arg, " ");
02608         ppp_print_string(p, len, printer, arg);
02609         p += len;
02610         len = 0;
02611     }
02612     break;
02613     default:
02614     break;
02615     }
02616 
02617     /* print the rest of the bytes in the packet */
02618     for (i = 0; i < len && i < 32; ++i) {
02619     GETCHAR(code, p);
02620     printer(arg, " %.2x", code);
02621     }
02622     if (i < len) {
02623     printer(arg, " ...");
02624     p += len - i;
02625     }
02626 
02627     return p - pstart;
02628 }
02629 #endif /* PRINTPKT_SUPPORT */
02630 
02631 /*
02632  * Time to shut down the link because there is nothing out there.
02633  */
02634 
02635 static void LcpLinkFailure(fsm *f) {
02636     ppp_pcb *pcb = f->pcb;
02637     if (f->state == PPP_FSM_OPENED) {
02638     ppp_info("No response to %d echo-requests", pcb->lcp_echos_pending);
02639         ppp_notice("Serial link appears to be disconnected.");
02640     pcb->err_code = PPPERR_PEERDEAD;
02641     lcp_close(pcb, "Peer not responding");
02642     }
02643 }
02644 
02645 /*
02646  * Timer expired for the LCP echo requests from this process.
02647  */
02648 
02649 static void LcpEchoCheck(fsm *f) {
02650     ppp_pcb *pcb = f->pcb;
02651 
02652     LcpSendEchoRequest (f);
02653     if (f->state != PPP_FSM_OPENED)
02654     return;
02655 
02656     /*
02657      * Start the timer for the next interval.
02658      */
02659     if (pcb->lcp_echo_timer_running)
02660     ppp_warn("assertion lcp_echo_timer_running==0 failed");
02661     TIMEOUT (LcpEchoTimeout, f, pcb->settings.lcp_echo_interval);
02662     pcb->lcp_echo_timer_running = 1;
02663 }
02664 
02665 /*
02666  * LcpEchoTimeout - Timer expired on the LCP echo
02667  */
02668 
02669 static void LcpEchoTimeout(void *arg) {
02670     fsm *f = (fsm*)arg;
02671     ppp_pcb *pcb = f->pcb;
02672     if (pcb->lcp_echo_timer_running != 0) {
02673         pcb->lcp_echo_timer_running = 0;
02674         LcpEchoCheck ((fsm *) arg);
02675     }
02676 }
02677 
02678 /*
02679  * LcpEchoReply - LCP has received a reply to the echo
02680  */
02681 
02682 static void lcp_received_echo_reply(fsm *f, int id, u_char *inp, int len) {
02683     ppp_pcb *pcb = f->pcb;
02684     lcp_options *go = &pcb->lcp_gotoptions;
02685     u32_t magic_val;
02686     LWIP_UNUSED_ARG(id);
02687 
02688     /* Check the magic number - don't count replies from ourselves. */
02689     if (len < 4) {
02690     ppp_dbglog("lcp: received short Echo-Reply, length %d", len);
02691     return;
02692     }
02693     GETLONG(magic_val, inp);
02694     if (go->neg_magicnumber
02695     && magic_val == go->magicnumber) {
02696     ppp_warn("appear to have received our own echo-reply!");
02697     return;
02698     }
02699 
02700     /* Reset the number of outstanding echo frames */
02701     pcb->lcp_echos_pending = 0;
02702 }
02703 
02704 /*
02705  * LcpSendEchoRequest - Send an echo request frame to the peer
02706  */
02707 
02708 static void LcpSendEchoRequest(fsm *f) {
02709     ppp_pcb *pcb = f->pcb;
02710     lcp_options *go = &pcb->lcp_gotoptions;
02711     u32_t lcp_magic;
02712     u_char pkt[4], *pktp;
02713 
02714     /*
02715      * Detect the failure of the peer at this point.
02716      */
02717     if (pcb->settings.lcp_echo_fails != 0) {
02718         if (pcb->lcp_echos_pending >= pcb->settings.lcp_echo_fails) {
02719             LcpLinkFailure(f);
02720             pcb->lcp_echos_pending = 0;
02721     }
02722     }
02723 
02724 #if PPP_LCP_ADAPTIVE
02725     /*
02726      * If adaptive echos have been enabled, only send the echo request if
02727      * no traffic was received since the last one.
02728      */
02729     if (pcb->settings.lcp_echo_adaptive) {
02730     static unsigned int last_pkts_in = 0;
02731 
02732 #if PPP_STATS_SUPPORT
02733     update_link_stats(f->unit);
02734     link_stats_valid = 0;
02735 #endif /* PPP_STATS_SUPPORT */
02736 
02737     if (link_stats.pkts_in != last_pkts_in) {
02738         last_pkts_in = link_stats.pkts_in;
02739         return;
02740     }
02741     }
02742 #endif
02743 
02744     /*
02745      * Make and send the echo request frame.
02746      */
02747     if (f->state == PPP_FSM_OPENED) {
02748         lcp_magic = go->magicnumber;
02749     pktp = pkt;
02750     PUTLONG(lcp_magic, pktp);
02751         fsm_sdata(f, ECHOREQ, pcb->lcp_echo_number++, pkt, pktp - pkt);
02752     ++pcb->lcp_echos_pending;
02753     }
02754 }
02755 
02756 /*
02757  * lcp_echo_lowerup - Start the timer for the LCP frame
02758  */
02759 
02760 static void lcp_echo_lowerup(ppp_pcb *pcb) {
02761     fsm *f = &pcb->lcp_fsm;
02762 
02763     /* Clear the parameters for generating echo frames */
02764     pcb->lcp_echos_pending      = 0;
02765     pcb->lcp_echo_number        = 0;
02766     pcb->lcp_echo_timer_running = 0;
02767   
02768     /* If a timeout interval is specified then start the timer */
02769     if (pcb->settings.lcp_echo_interval != 0)
02770         LcpEchoCheck (f);
02771 }
02772 
02773 /*
02774  * lcp_echo_lowerdown - Stop the timer for the LCP frame
02775  */
02776 
02777 static void lcp_echo_lowerdown(ppp_pcb *pcb) {
02778     fsm *f = &pcb->lcp_fsm;
02779 
02780     if (pcb->lcp_echo_timer_running != 0) {
02781         UNTIMEOUT (LcpEchoTimeout, f);
02782         pcb->lcp_echo_timer_running = 0;
02783     }
02784 }
02785 
02786 #endif /* PPP_SUPPORT */