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