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