Kenji Arai / mbed-os_TYBLE16

Dependents:   TYBLE16_simple_data_logger TYBLE16_MP3_Air

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers lcp.c Source File

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 "ppp_opts.h"
00044 #if PPP_SUPPORT /* don't build if not configured for use in ppp_opts.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 "ppp_impl.h"
00057 
00058 #include "fsm.h"
00059 #include "lcp.h"
00060 #if CHAP_SUPPORT
00061 #include "chap-new.h"
00062 #endif /* CHAP_SUPPORT */
00063 #include "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     PPP_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 
01846     next = inp;
01847 
01848     nakp = ppp_memory_buffer_allocate(pcb->netif->memory_manager, PPP_CTRL_PBUF_MAX_SIZE, PPP_BUF_HEAP);
01849     if(NULL == nakp)
01850         return 0;
01851     if(nakp->tot_len != nakp->len) {
01852         ppp_memory_buffer_free(nakp);
01853         return 0;
01854     }
01855 
01856     nakoutp = (u_char*)nakp->payload;
01857 
01858     rejp = inp;
01859     while (l) {
01860     orc = CONFACK;          /* Assume success */
01861     cip = p = next;         /* Remember begining of CI */
01862     if (l < 2 ||            /* Not enough data for CI header or */
01863         p[1] < 2 ||         /*  CI length too small or */
01864         p[1] > l) {         /*  CI length too big? */
01865         LCPDEBUG(("lcp_reqci: bad CI length!"));
01866         orc = CONFREJ;      /* Reject bad CI */
01867         cilen = l;          /* Reject till end of packet */
01868         l = 0;          /* Don't loop again */
01869         citype = 0;
01870         goto endswitch;
01871     }
01872     GETCHAR(citype, p);     /* Parse CI type */
01873     GETCHAR(cilen, p);      /* Parse CI length */
01874     l -= cilen;         /* Adjust remaining length */
01875     next += cilen;          /* Step to next CI */
01876 
01877     switch (citype) {       /* Check CI type */
01878     case CI_MRU:
01879         if (!ao->neg_mru ||     /* Allow option? */
01880         cilen != CILEN_SHORT) { /* Check CI length */
01881         orc = CONFREJ;      /* Reject CI */
01882         break;
01883         }
01884         GETSHORT(cishort, p);   /* Parse MRU */
01885 
01886         /*
01887          * He must be able to receive at least our minimum.
01888          * No need to check a maximum.  If he sends a large number,
01889          * we'll just ignore it.
01890          */
01891         if (cishort < PPP_MINMRU) {
01892         orc = CONFNAK;      /* Nak CI */
01893         PUTCHAR(CI_MRU, nakoutp);
01894         PUTCHAR(CILEN_SHORT, nakoutp);
01895         PUTSHORT(PPP_MINMRU, nakoutp);  /* Give him a hint */
01896         break;
01897         }
01898         ho->neg_mru = 1;        /* Remember he sent MRU */
01899         ho->mru = cishort;      /* And remember value */
01900         break;
01901 
01902     case CI_ASYNCMAP:
01903         if (!ao->neg_asyncmap ||
01904         cilen != CILEN_LONG) {
01905         orc = CONFREJ;
01906         break;
01907         }
01908         GETLONG(cilong, p);
01909 
01910         /*
01911          * Asyncmap must have set at least the bits
01912          * which are set in lcp_allowoptions[unit].asyncmap.
01913          */
01914         if ((ao->asyncmap & ~cilong) != 0) {
01915         orc = CONFNAK;
01916         PUTCHAR(CI_ASYNCMAP, nakoutp);
01917         PUTCHAR(CILEN_LONG, nakoutp);
01918         PUTLONG(ao->asyncmap | cilong, nakoutp);
01919         break;
01920         }
01921         ho->neg_asyncmap = 1;
01922         ho->asyncmap = cilong;
01923         break;
01924 
01925     case CI_AUTHTYPE:
01926         if (cilen < CILEN_SHORT ||
01927         !(0
01928 #if PAP_SUPPORT
01929         || ao->neg_upap
01930 #endif /* PAP_SUPPORT */
01931 #if CHAP_SUPPORT
01932         || ao->neg_chap
01933 #endif /* CHAP_SUPPORT */
01934 #if EAP_SUPPORT
01935         || ao->neg_eap
01936 #endif /* EAP_SUPPORT */
01937         )) {
01938         /*
01939          * Reject the option if we're not willing to authenticate.
01940          */
01941         ppp_dbglog("No auth is possible");
01942         orc = CONFREJ;
01943         break;
01944         }
01945         GETSHORT(cishort, p);
01946 
01947         /*
01948          * Authtype must be PAP, CHAP, or EAP.
01949          *
01950          * Note: if more than one of ao->neg_upap, ao->neg_chap, and
01951          * ao->neg_eap are set, and the peer sends a Configure-Request
01952          * with two or more authenticate-protocol requests, then we will
01953          * reject the second request.
01954          * Whether we end up doing CHAP, UPAP, or EAP depends then on
01955          * the ordering of the CIs in the peer's Configure-Request.
01956              */
01957 
01958 #if PAP_SUPPORT
01959         if (cishort == PPP_PAP) {
01960         /* we've already accepted CHAP or EAP */
01961         if (0
01962 #if CHAP_SUPPORT
01963             || ho->neg_chap
01964 #endif /* CHAP_SUPPORT */
01965 #if EAP_SUPPORT
01966             || ho->neg_eap
01967 #endif /* EAP_SUPPORT */
01968             || cilen != CILEN_SHORT) {
01969             LCPDEBUG(("lcp_reqci: rcvd AUTHTYPE PAP, rejecting..."));
01970             orc = CONFREJ;
01971             break;
01972         }
01973         if (!ao->neg_upap) {    /* we don't want to do PAP */
01974             orc = CONFNAK;  /* NAK it and suggest CHAP or EAP */
01975             PUTCHAR(CI_AUTHTYPE, nakoutp);
01976 #if EAP_SUPPORT
01977             if (ao->neg_eap) {
01978             PUTCHAR(CILEN_SHORT, nakoutp);
01979             PUTSHORT(PPP_EAP, nakoutp);
01980             } else {
01981 #endif /* EAP_SUPPORT */
01982 #if CHAP_SUPPORT
01983             PUTCHAR(CILEN_CHAP, nakoutp);
01984             PUTSHORT(PPP_CHAP, nakoutp);
01985             PUTCHAR(CHAP_DIGEST(ao->chap_mdtype), nakoutp);
01986 #endif /* CHAP_SUPPORT */
01987 #if EAP_SUPPORT
01988             }
01989 #endif /* EAP_SUPPORT */
01990             break;
01991         }
01992         ho->neg_upap = 1;
01993         break;
01994         }
01995 #endif /* PAP_SUPPORT */
01996 #if CHAP_SUPPORT
01997         if (cishort == PPP_CHAP) {
01998         /* we've already accepted PAP or EAP */
01999         if (
02000 #if PAP_SUPPORT
02001             ho->neg_upap ||
02002 #endif /* PAP_SUPPORT */
02003 #if EAP_SUPPORT
02004             ho->neg_eap ||
02005 #endif /* EAP_SUPPORT */
02006             cilen != CILEN_CHAP) {
02007             LCPDEBUG(("lcp_reqci: rcvd AUTHTYPE CHAP, rejecting..."));
02008             orc = CONFREJ;
02009             break;
02010         }
02011         if (!ao->neg_chap) {    /* we don't want to do CHAP */
02012             orc = CONFNAK;  /* NAK it and suggest EAP or PAP */
02013             PUTCHAR(CI_AUTHTYPE, nakoutp);
02014             PUTCHAR(CILEN_SHORT, nakoutp);
02015 #if EAP_SUPPORT
02016             if (ao->neg_eap) {
02017             PUTSHORT(PPP_EAP, nakoutp);
02018             } else
02019 #endif /* EAP_SUPPORT */
02020 #if PAP_SUPPORT
02021             if(1) {
02022             PUTSHORT(PPP_PAP, nakoutp);
02023             }
02024             else
02025 #endif /* PAP_SUPPORT */
02026             {}
02027             break;
02028         }
02029         GETCHAR(cichar, p); /* get digest type */
02030         if (!(CHAP_CANDIGEST(ao->chap_mdtype, cichar))) {
02031             /*
02032              * We can't/won't do the requested type,
02033              * suggest something else.
02034              */
02035             orc = CONFNAK;
02036             PUTCHAR(CI_AUTHTYPE, nakoutp);
02037             PUTCHAR(CILEN_CHAP, nakoutp);
02038             PUTSHORT(PPP_CHAP, nakoutp);
02039             PUTCHAR(CHAP_DIGEST(ao->chap_mdtype), nakoutp);
02040             break;
02041         }
02042         ho->chap_mdtype = CHAP_MDTYPE_D(cichar); /* save md type */
02043         ho->neg_chap = 1;
02044         break;
02045         }
02046 #endif /* CHAP_SUPPORT */
02047 #if EAP_SUPPORT
02048         if (cishort == PPP_EAP) {
02049         /* we've already accepted CHAP or PAP */
02050         if (
02051 #if CHAP_SUPPORT
02052             ho->neg_chap ||
02053 #endif /* CHAP_SUPPORT */
02054 #if PAP_SUPPORT
02055             ho->neg_upap ||
02056 #endif /* PAP_SUPPORT */
02057             cilen != CILEN_SHORT) {
02058             LCPDEBUG(("lcp_reqci: rcvd AUTHTYPE EAP, rejecting..."));
02059             orc = CONFREJ;
02060             break;
02061         }
02062         if (!ao->neg_eap) { /* we don't want to do EAP */
02063             orc = CONFNAK;  /* NAK it and suggest CHAP or PAP */
02064             PUTCHAR(CI_AUTHTYPE, nakoutp);
02065 #if CHAP_SUPPORT
02066             if (ao->neg_chap) {
02067             PUTCHAR(CILEN_CHAP, nakoutp);
02068             PUTSHORT(PPP_CHAP, nakoutp);
02069             PUTCHAR(CHAP_DIGEST(ao->chap_mdtype), nakoutp);
02070             } else
02071 #endif /* CHAP_SUPPORT */
02072 #if PAP_SUPPORT
02073             if(1) {
02074             PUTCHAR(CILEN_SHORT, nakoutp);
02075             PUTSHORT(PPP_PAP, nakoutp);
02076             } else
02077 #endif /* PAP_SUPPORT */
02078             {}
02079             break;
02080         }
02081         ho->neg_eap = 1;
02082         break;
02083         }
02084 #endif /* EAP_SUPPORT */
02085 
02086         /*
02087          * We don't recognize the protocol they're asking for.
02088          * Nak it with something we're willing to do.
02089          * (At this point we know ao->neg_upap || ao->neg_chap ||
02090          * ao->neg_eap.)
02091          */
02092         orc = CONFNAK;
02093         PUTCHAR(CI_AUTHTYPE, nakoutp);
02094 
02095 #if EAP_SUPPORT
02096         if (ao->neg_eap) {
02097         PUTCHAR(CILEN_SHORT, nakoutp);
02098         PUTSHORT(PPP_EAP, nakoutp);
02099         } else
02100 #endif /* EAP_SUPPORT */
02101 #if CHAP_SUPPORT
02102         if (ao->neg_chap) {
02103         PUTCHAR(CILEN_CHAP, nakoutp);
02104         PUTSHORT(PPP_CHAP, nakoutp);
02105         PUTCHAR(CHAP_DIGEST(ao->chap_mdtype), nakoutp);
02106         } else
02107 #endif /* CHAP_SUPPORT */
02108 #if PAP_SUPPORT
02109         if(1) {
02110         PUTCHAR(CILEN_SHORT, nakoutp);
02111         PUTSHORT(PPP_PAP, nakoutp);
02112         } else
02113 #endif /* PAP_SUPPORT */
02114         {}
02115         break;
02116 
02117 #if LQR_SUPPORT
02118     case CI_QUALITY:
02119         if (!ao->neg_lqr ||
02120         cilen != CILEN_LQR) {
02121         orc = CONFREJ;
02122         break;
02123         }
02124 
02125         GETSHORT(cishort, p);
02126         GETLONG(cilong, p);
02127 
02128         /*
02129          * Check the protocol and the reporting period.
02130          * XXX When should we Nak this, and what with?
02131          */
02132         if (cishort != PPP_LQR) {
02133         orc = CONFNAK;
02134         PUTCHAR(CI_QUALITY, nakoutp);
02135         PUTCHAR(CILEN_LQR, nakoutp);
02136         PUTSHORT(PPP_LQR, nakoutp);
02137         PUTLONG(ao->lqr_period, nakoutp);
02138         break;
02139         }
02140         break;
02141 #endif /* LQR_SUPPORT */
02142 
02143     case CI_MAGICNUMBER:
02144         if (!(ao->neg_magicnumber || go->neg_magicnumber) ||
02145         cilen != CILEN_LONG) {
02146         orc = CONFREJ;
02147         break;
02148         }
02149         GETLONG(cilong, p);
02150 
02151         /*
02152          * He must have a different magic number.
02153          */
02154         if (go->neg_magicnumber &&
02155         cilong == go->magicnumber) {
02156         cilong = magic();   /* Don't put magic() inside macro! */
02157         orc = CONFNAK;
02158         PUTCHAR(CI_MAGICNUMBER, nakoutp);
02159         PUTCHAR(CILEN_LONG, nakoutp);
02160         PUTLONG(cilong, nakoutp);
02161         break;
02162         }
02163         ho->neg_magicnumber = 1;
02164         ho->magicnumber = cilong;
02165         break;
02166 
02167 
02168     case CI_PCOMPRESSION:
02169         if (!ao->neg_pcompression ||
02170         cilen != CILEN_VOID) {
02171         orc = CONFREJ;
02172         break;
02173         }
02174         ho->neg_pcompression = 1;
02175         break;
02176 
02177     case CI_ACCOMPRESSION:
02178         if (!ao->neg_accompression ||
02179         cilen != CILEN_VOID) {
02180         orc = CONFREJ;
02181         break;
02182         }
02183         ho->neg_accompression = 1;
02184         break;
02185 
02186 #ifdef HAVE_MULTILINK
02187     case CI_MRRU:
02188         if (!ao->neg_mrru
02189         || !multilink
02190         || cilen != CILEN_SHORT) {
02191         orc = CONFREJ;
02192         break;
02193         }
02194 
02195         GETSHORT(cishort, p);
02196         /* possibly should insist on a minimum/maximum MRRU here */
02197         ho->neg_mrru = 1;
02198         ho->mrru = cishort;
02199         break;
02200 #endif /* HAVE_MULTILINK */
02201 
02202     case CI_SSNHF:
02203         if (!ao->neg_ssnhf
02204 #ifdef HAVE_MULTILINK
02205         || !multilink
02206 #endif /* HAVE_MULTILINK */
02207         || cilen != CILEN_VOID) {
02208         orc = CONFREJ;
02209         break;
02210         }
02211         ho->neg_ssnhf = 1;
02212         break;
02213 
02214     case CI_EPDISC:
02215         if (!ao->neg_endpoint ||
02216         cilen < CILEN_CHAR ||
02217         cilen > CILEN_CHAR + MAX_ENDP_LEN) {
02218         orc = CONFREJ;
02219         break;
02220         }
02221         GETCHAR(cichar, p);
02222         cilen -= CILEN_CHAR;
02223         ho->neg_endpoint = 1;
02224         ho->endpoint.class_ = cichar;
02225         ho->endpoint.length = cilen;
02226         MEMCPY(ho->endpoint.value, p, cilen);
02227         INCPTR(cilen, p);
02228         break;
02229 
02230     default:
02231         LCPDEBUG(("lcp_reqci: rcvd unknown option %d", citype));
02232         orc = CONFREJ;
02233         break;
02234     }
02235 
02236 endswitch:
02237     if (orc == CONFACK &&       /* Good CI */
02238         rc != CONFACK)      /*  but prior CI wasnt? */
02239         continue;           /* Don't send this one */
02240 
02241     if (orc == CONFNAK) {       /* Nak this CI? */
02242         if (reject_if_disagree  /* Getting fed up with sending NAKs? */
02243         && citype != CI_MAGICNUMBER) {
02244         orc = CONFREJ;      /* Get tough if so */
02245         } else {
02246         if (rc == CONFREJ)  /* Rejecting prior CI? */
02247             continue;       /* Don't send this one */
02248         rc = CONFNAK;
02249         }
02250     }
02251     if (orc == CONFREJ) {       /* Reject this CI */
02252         rc = CONFREJ;
02253         if (cip != rejp)        /* Need to move rejected CI? */
02254         MEMCPY(rejp, cip, cilen); /* Move it */
02255         INCPTR(cilen, rejp);    /* Update output pointer */
02256     }
02257     }
02258 
02259     /*
02260      * If we wanted to send additional NAKs (for unsent CIs), the
02261      * code would go here.  The extra NAKs would go at *nakoutp.
02262      * At present there are no cases where we want to ask the
02263      * peer to negotiate an option.
02264      */
02265 
02266     switch (rc) {
02267     case CONFACK:
02268     *lenp = next - inp;
02269     break;
02270     case CONFNAK:
02271     /*
02272      * Copy the Nak'd options from the nak buffer to the caller's buffer.
02273      */
02274     *lenp = nakoutp - (u_char*)nakp->payload;
02275 
02276     MEMCPY(inp, nakp->payload, *lenp);
02277     break;
02278     case CONFREJ:
02279     *lenp = rejp - inp;
02280     break;
02281     default:
02282     break;
02283     }
02284 
02285     ppp_memory_buffer_free(nakp);
02286     LCPDEBUG(("lcp_reqci: returning CONF%s.", CODENAME(rc)));
02287     return (rc);            /* Return final code */
02288 }
02289 
02290 
02291 /*
02292  * lcp_up - LCP has come UP.
02293  */
02294 static void lcp_up(fsm *f) {
02295     ppp_pcb *pcb = f->pcb;
02296     lcp_options *wo = &pcb->lcp_wantoptions;
02297     lcp_options *ho = &pcb->lcp_hisoptions;
02298     lcp_options *go = &pcb->lcp_gotoptions;
02299     lcp_options *ao = &pcb->lcp_allowoptions;
02300     int mtu, mru;
02301 
02302     if (!go->neg_magicnumber)
02303     go->magicnumber = 0;
02304     if (!ho->neg_magicnumber)
02305     ho->magicnumber = 0;
02306 
02307     /*
02308      * Set our MTU to the smaller of the MTU we wanted and
02309      * the MRU our peer wanted.  If we negotiated an MRU,
02310      * set our MRU to the larger of value we wanted and
02311      * the value we got in the negotiation.
02312      * Note on the MTU: the link MTU can be the MRU the peer wanted,
02313      * the interface MTU is set to the lowest of that, the
02314      * MTU we want to use, and our link MRU.
02315      */
02316     mtu = ho->neg_mru? ho->mru: PPP_MRU;
02317     mru = go->neg_mru? PPP_MAX(wo->mru, go->mru): PPP_MRU;
02318 #ifdef HAVE_MULTILINK
02319     if (!(multilink && go->neg_mrru && ho->neg_mrru))
02320 #endif /* HAVE_MULTILINK */
02321     netif_set_mtu(pcb, PPP_MIN(PPP_MIN(mtu, mru), ao->mru));
02322     ppp_send_config(pcb, mtu,
02323             (ho->neg_asyncmap? ho->asyncmap: 0xffffffff),
02324             ho->neg_pcompression, ho->neg_accompression);
02325     ppp_recv_config(pcb, mru,
02326             (pcb->settings.lax_recv? 0: go->neg_asyncmap? go->asyncmap: 0xffffffff),
02327             go->neg_pcompression, go->neg_accompression);
02328 
02329     if (ho->neg_mru)
02330     pcb->peer_mru = ho->mru;
02331 
02332     lcp_echo_lowerup(f->pcb);  /* Enable echo messages */
02333 
02334     link_established(pcb);
02335 }
02336 
02337 
02338 /*
02339  * lcp_down - LCP has gone DOWN.
02340  *
02341  * Alert other protocols.
02342  */
02343 static void lcp_down(fsm *f) {
02344     ppp_pcb *pcb = f->pcb;
02345     lcp_options *go = &pcb->lcp_gotoptions;
02346 
02347     lcp_echo_lowerdown(f->pcb);
02348 
02349     link_down(pcb);
02350 
02351     ppp_send_config(pcb, PPP_MRU, 0xffffffff, 0, 0);
02352     ppp_recv_config(pcb, PPP_MRU,
02353             (go->neg_asyncmap? go->asyncmap: 0xffffffff),
02354             go->neg_pcompression, go->neg_accompression);
02355     pcb->peer_mru = PPP_MRU;
02356 }
02357 
02358 
02359 /*
02360  * lcp_starting - LCP needs the lower layer up.
02361  */
02362 static void lcp_starting(fsm *f) {
02363     ppp_pcb *pcb = f->pcb;
02364     link_required(pcb);
02365 }
02366 
02367 
02368 /*
02369  * lcp_finished - LCP has finished with the lower layer.
02370  */
02371 static void lcp_finished(fsm *f) {
02372     ppp_pcb *pcb = f->pcb;
02373     link_terminated(pcb);
02374 }
02375 
02376 
02377 #if PRINTPKT_SUPPORT
02378 /*
02379  * lcp_printpkt - print the contents of an LCP packet.
02380  */
02381 static const char* const lcp_codenames[] = {
02382     "ConfReq", "ConfAck", "ConfNak", "ConfRej",
02383     "TermReq", "TermAck", "CodeRej", "ProtRej",
02384     "EchoReq", "EchoRep", "DiscReq", "Ident",
02385     "TimeRem"
02386 };
02387 
02388 static int lcp_printpkt(const u_char *p, int plen,
02389         void (*printer) (void *, const char *, ...), void *arg) {
02390     int code, id, len, olen, i;
02391     const u_char *pstart, *optend;
02392     u_short cishort;
02393     u32_t cilong;
02394 
02395     if (plen < HEADERLEN)
02396     return 0;
02397     pstart = p;
02398     GETCHAR(code, p);
02399     GETCHAR(id, p);
02400     GETSHORT(len, p);
02401     if (len < HEADERLEN || len > plen)
02402     return 0;
02403 
02404    if (code >= 1 && code <= (int)PPP_ARRAYSIZE(lcp_codenames))
02405     printer(arg, " %s", lcp_codenames[code-1]);
02406     else
02407     printer(arg, " code=0x%x", code);
02408     printer(arg, " id=0x%x", id);
02409     len -= HEADERLEN;
02410     switch (code) {
02411     case CONFREQ:
02412     case CONFACK:
02413     case CONFNAK:
02414     case CONFREJ:
02415     /* print option list */
02416     while (len >= 2) {
02417         GETCHAR(code, p);
02418         GETCHAR(olen, p);
02419         p -= 2;
02420         if (olen < 2 || olen > len) {
02421         break;
02422         }
02423         printer(arg, " <");
02424         len -= olen;
02425         optend = p + olen;
02426         switch (code) {
02427         case CI_MRU:
02428         if (olen == CILEN_SHORT) {
02429             p += 2;
02430             GETSHORT(cishort, p);
02431             printer(arg, "mru %d", cishort);
02432         }
02433         break;
02434         case CI_ASYNCMAP:
02435         if (olen == CILEN_LONG) {
02436             p += 2;
02437             GETLONG(cilong, p);
02438             printer(arg, "asyncmap 0x%x", cilong);
02439         }
02440         break;
02441         case CI_AUTHTYPE:
02442         if (olen >= CILEN_SHORT) {
02443             p += 2;
02444             printer(arg, "auth ");
02445             GETSHORT(cishort, p);
02446             switch (cishort) {
02447 #if PAP_SUPPORT
02448             case PPP_PAP:
02449             printer(arg, "pap");
02450             break;
02451 #endif /* PAP_SUPPORT */
02452 #if CHAP_SUPPORT
02453             case PPP_CHAP:
02454             printer(arg, "chap");
02455             if (p < optend) {
02456                 switch (*p) {
02457                 case CHAP_MD5:
02458                 printer(arg, " MD5");
02459                 ++p;
02460                 break;
02461 #if MSCHAP_SUPPORT
02462                 case CHAP_MICROSOFT:
02463                 printer(arg, " MS");
02464                 ++p;
02465                 break;
02466 
02467                 case CHAP_MICROSOFT_V2:
02468                 printer(arg, " MS-v2");
02469                 ++p;
02470                 break;
02471 #endif /* MSCHAP_SUPPORT */
02472                 default:
02473                 break;
02474                 }
02475             }
02476             break;
02477 #endif /* CHAP_SUPPORT */
02478 #if EAP_SUPPORT
02479             case PPP_EAP:
02480             printer(arg, "eap");
02481             break;
02482 #endif /* EAP_SUPPORT */
02483             default:
02484             printer(arg, "0x%x", cishort);
02485             }
02486         }
02487         break;
02488 #if LQR_SUPPORT
02489         case CI_QUALITY:
02490         if (olen >= CILEN_SHORT) {
02491             p += 2;
02492             printer(arg, "quality ");
02493             GETSHORT(cishort, p);
02494             switch (cishort) {
02495             case PPP_LQR:
02496             printer(arg, "lqr");
02497             break;
02498             default:
02499             printer(arg, "0x%x", cishort);
02500             }
02501         }
02502         break;
02503 #endif /* LQR_SUPPORT */
02504         case CI_CALLBACK:
02505         if (olen >= CILEN_CHAR) {
02506             p += 2;
02507             printer(arg, "callback ");
02508             GETCHAR(cishort, p);
02509             switch (cishort) {
02510             case CBCP_OPT:
02511             printer(arg, "CBCP");
02512             break;
02513             default:
02514             printer(arg, "0x%x", cishort);
02515             }
02516         }
02517         break;
02518         case CI_MAGICNUMBER:
02519         if (olen == CILEN_LONG) {
02520             p += 2;
02521             GETLONG(cilong, p);
02522             printer(arg, "magic 0x%x", cilong);
02523         }
02524         break;
02525         case CI_PCOMPRESSION:
02526         if (olen == CILEN_VOID) {
02527             p += 2;
02528             printer(arg, "pcomp");
02529         }
02530         break;
02531         case CI_ACCOMPRESSION:
02532         if (olen == CILEN_VOID) {
02533             p += 2;
02534             printer(arg, "accomp");
02535         }
02536         break;
02537         case CI_MRRU:
02538         if (olen == CILEN_SHORT) {
02539             p += 2;
02540             GETSHORT(cishort, p);
02541             printer(arg, "mrru %d", cishort);
02542         }
02543         break;
02544         case CI_SSNHF:
02545         if (olen == CILEN_VOID) {
02546             p += 2;
02547             printer(arg, "ssnhf");
02548         }
02549         break;
02550         case CI_EPDISC:
02551 #ifdef HAVE_MULTILINK
02552         if (olen >= CILEN_CHAR) {
02553             struct epdisc epd;
02554             p += 2;
02555             GETCHAR(epd.class, p);
02556             epd.length = olen - CILEN_CHAR;
02557             if (epd.length > MAX_ENDP_LEN)
02558             epd.length = MAX_ENDP_LEN;
02559             if (epd.length > 0) {
02560             MEMCPY(epd.value, p, epd.length);
02561             p += epd.length;
02562             }
02563             printer(arg, "endpoint [%s]", epdisc_to_str(&epd));
02564         }
02565 #else
02566         printer(arg, "endpoint");
02567 #endif
02568         break;
02569         default:
02570         break;
02571         }
02572         while (p < optend) {
02573         GETCHAR(code, p);
02574         printer(arg, " %.2x", code);
02575         }
02576         printer(arg, ">");
02577     }
02578     break;
02579 
02580     case TERMACK:
02581     case TERMREQ:
02582     if (len > 0 && *p >= ' ' && *p < 0x7f) {
02583         printer(arg, " ");
02584         ppp_print_string(p, len, printer, arg);
02585         p += len;
02586         len = 0;
02587     }
02588     break;
02589 
02590     case ECHOREQ:
02591     case ECHOREP:
02592     case DISCREQ:
02593     if (len >= 4) {
02594         GETLONG(cilong, p);
02595         printer(arg, " magic=0x%x", cilong);
02596         len -= 4;
02597     }
02598     break;
02599 
02600     case IDENTIF:
02601     case TIMEREM:
02602     if (len >= 4) {
02603         GETLONG(cilong, p);
02604         printer(arg, " magic=0x%x", cilong);
02605         len -= 4;
02606     }
02607     if (code == TIMEREM) {
02608         if (len < 4)
02609         break;
02610         GETLONG(cilong, p);
02611         printer(arg, " seconds=%u", cilong);
02612         len -= 4;
02613     }
02614     if (len > 0) {
02615         printer(arg, " ");
02616         ppp_print_string(p, len, printer, arg);
02617         p += len;
02618         len = 0;
02619     }
02620     break;
02621     default:
02622     break;
02623     }
02624 
02625     /* print the rest of the bytes in the packet */
02626     for (i = 0; i < len && i < 32; ++i) {
02627     GETCHAR(code, p);
02628     printer(arg, " %.2x", code);
02629     }
02630     if (i < len) {
02631     printer(arg, " ...");
02632     p += len - i;
02633     }
02634 
02635     return p - pstart;
02636 }
02637 #endif /* PRINTPKT_SUPPORT */
02638 
02639 /*
02640  * Time to shut down the link because there is nothing out there.
02641  */
02642 
02643 static void LcpLinkFailure(fsm *f) {
02644     ppp_pcb *pcb = f->pcb;
02645     if (f->state == PPP_FSM_OPENED) {
02646     ppp_info("No response to %d echo-requests", pcb->lcp_echos_pending);
02647         ppp_notice("Serial link appears to be disconnected.");
02648     pcb->err_code = PPPERR_PEERDEAD;
02649     lcp_close(pcb, "Peer not responding");
02650     }
02651 }
02652 
02653 /*
02654  * Timer expired for the LCP echo requests from this process.
02655  */
02656 
02657 static void LcpEchoCheck(fsm *f) {
02658     ppp_pcb *pcb = f->pcb;
02659 
02660     LcpSendEchoRequest (f);
02661     if (f->state != PPP_FSM_OPENED)
02662     return;
02663 
02664     /*
02665      * Start the timer for the next interval.
02666      */
02667     if (pcb->lcp_echo_timer_running)
02668     ppp_warn("assertion lcp_echo_timer_running==0 failed");
02669     TIMEOUT (LcpEchoTimeout, f, pcb->settings.lcp_echo_interval);
02670     pcb->lcp_echo_timer_running = 1;
02671 }
02672 
02673 /*
02674  * LcpEchoTimeout - Timer expired on the LCP echo
02675  */
02676 
02677 static void LcpEchoTimeout(void *arg) {
02678     fsm *f = (fsm*)arg;
02679     ppp_pcb *pcb = f->pcb;
02680     if (pcb->lcp_echo_timer_running != 0) {
02681         pcb->lcp_echo_timer_running = 0;
02682         LcpEchoCheck ((fsm *) arg);
02683     }
02684 }
02685 
02686 /*
02687  * LcpEchoReply - LCP has received a reply to the echo
02688  */
02689 
02690 static void lcp_received_echo_reply(fsm *f, int id, u_char *inp, int len) {
02691     ppp_pcb *pcb = f->pcb;
02692     lcp_options *go = &pcb->lcp_gotoptions;
02693     u32_t magic_val;
02694     PPP_UNUSED_ARG(id);
02695 
02696     /* Check the magic number - don't count replies from ourselves. */
02697     if (len < 4) {
02698     ppp_dbglog("lcp: received short Echo-Reply, length %d", len);
02699     return;
02700     }
02701     GETLONG(magic_val, inp);
02702     if (go->neg_magicnumber
02703     && magic_val == go->magicnumber) {
02704     ppp_warn("appear to have received our own echo-reply!");
02705     return;
02706     }
02707 
02708     /* Reset the number of outstanding echo frames */
02709     pcb->lcp_echos_pending = 0;
02710 }
02711 
02712 /*
02713  * LcpSendEchoRequest - Send an echo request frame to the peer
02714  */
02715 
02716 static void LcpSendEchoRequest(fsm *f) {
02717     ppp_pcb *pcb = f->pcb;
02718     lcp_options *go = &pcb->lcp_gotoptions;
02719     u32_t lcp_magic;
02720     u_char pkt[4], *pktp;
02721 
02722     /*
02723      * Detect the failure of the peer at this point.
02724      */
02725     if (pcb->settings.lcp_echo_fails != 0) {
02726         if (pcb->lcp_echos_pending >= pcb->settings.lcp_echo_fails) {
02727             LcpLinkFailure(f);
02728             pcb->lcp_echos_pending = 0;
02729     }
02730     }
02731 
02732 #if PPP_LCP_ADAPTIVE
02733     /*
02734      * If adaptive echos have been enabled, only send the echo request if
02735      * no traffic was received since the last one.
02736      */
02737     if (pcb->settings.lcp_echo_adaptive) {
02738     static unsigned int last_pkts_in = 0;
02739 
02740 #if PPP_STATS_SUPPORT
02741     update_link_stats(f->unit);
02742     link_stats_valid = 0;
02743 #endif /* PPP_STATS_SUPPORT */
02744 
02745     if (link_stats.pkts_in != last_pkts_in) {
02746         last_pkts_in = link_stats.pkts_in;
02747         return;
02748     }
02749     }
02750 #endif
02751 
02752     /*
02753      * Make and send the echo request frame.
02754      */
02755     if (f->state == PPP_FSM_OPENED) {
02756         lcp_magic = go->magicnumber;
02757     pktp = pkt;
02758     PUTLONG(lcp_magic, pktp);
02759         fsm_sdata(f, ECHOREQ, pcb->lcp_echo_number++, pkt, pktp - pkt);
02760     ++pcb->lcp_echos_pending;
02761     }
02762 }
02763 
02764 /*
02765  * lcp_echo_lowerup - Start the timer for the LCP frame
02766  */
02767 
02768 static void lcp_echo_lowerup(ppp_pcb *pcb) {
02769     fsm *f = &pcb->lcp_fsm;
02770 
02771     /* Clear the parameters for generating echo frames */
02772     pcb->lcp_echos_pending      = 0;
02773     pcb->lcp_echo_number        = 0;
02774     pcb->lcp_echo_timer_running = 0;
02775   
02776     /* If a timeout interval is specified then start the timer */
02777     if (pcb->settings.lcp_echo_interval != 0)
02778         LcpEchoCheck (f);
02779 }
02780 
02781 /*
02782  * lcp_echo_lowerdown - Stop the timer for the LCP frame
02783  */
02784 
02785 static void lcp_echo_lowerdown(ppp_pcb *pcb) {
02786     fsm *f = &pcb->lcp_fsm;
02787 
02788     if (pcb->lcp_echo_timer_running != 0) {
02789         UNTIMEOUT (LcpEchoTimeout, f);
02790         pcb->lcp_echo_timer_running = 0;
02791     }
02792 }
02793 
02794 #endif /* PPP_SUPPORT */