Rtos API example

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