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