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 mbed-os 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 && 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 13:15:53 by
