Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: mbed-TFT-example-NCS36510 mbed-Accelerometer-example-NCS36510 mbed-Accelerometer-example-NCS36510
lwip_ipv6cp.c
00001 /* 00002 * ipv6cp.c - PPP IPV6 Control Protocol. 00003 * 00004 * Copyright (c) 1999 Tommi Komulainen. 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(s) of the authors of this software must not be used to 00019 * endorse or promote products derived from this software without 00020 * prior written permission. 00021 * 00022 * 4. Redistributions of any form whatsoever must retain the following 00023 * acknowledgment: 00024 * "This product includes software developed by Tommi Komulainen 00025 * <Tommi.Komulainen@iki.fi>". 00026 * 00027 * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO 00028 * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 00029 * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY 00030 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 00031 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN 00032 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 00033 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 00034 * 00035 */ 00036 00037 /* Original version, based on RFC2023 : 00038 00039 Copyright (c) 1995, 1996, 1997 Francis.Dupont@inria.fr, INRIA Rocquencourt, 00040 Alain.Durand@imag.fr, IMAG, 00041 Jean-Luc.Richier@imag.fr, IMAG-LSR. 00042 00043 Copyright (c) 1998, 1999 Francis.Dupont@inria.fr, GIE DYADE, 00044 Alain.Durand@imag.fr, IMAG, 00045 Jean-Luc.Richier@imag.fr, IMAG-LSR. 00046 00047 Ce travail a été fait au sein du GIE DYADE (Groupement d'Intérêt 00048 Économique ayant pour membres BULL S.A. et l'INRIA). 00049 00050 Ce logiciel informatique est disponible aux conditions 00051 usuelles dans la recherche, c'est-à-dire qu'il peut 00052 être utilisé, copié, modifié, distribué à l'unique 00053 condition que ce texte soit conservé afin que 00054 l'origine de ce logiciel soit reconnue. 00055 00056 Le nom de l'Institut National de Recherche en Informatique 00057 et en Automatique (INRIA), de l'IMAG, ou d'une personne morale 00058 ou physique ayant participé à l'élaboration de ce logiciel ne peut 00059 être utilisé sans son accord préalable explicite. 00060 00061 Ce logiciel est fourni tel quel sans aucune garantie, 00062 support ou responsabilité d'aucune sorte. 00063 Ce logiciel est dérivé de sources d'origine 00064 "University of California at Berkeley" et 00065 "Digital Equipment Corporation" couvertes par des copyrights. 00066 00067 L'Institut d'Informatique et de Mathématiques Appliquées de Grenoble (IMAG) 00068 est une fédération d'unités mixtes de recherche du CNRS, de l'Institut National 00069 Polytechnique de Grenoble et de l'Université Joseph Fourier regroupant 00070 sept laboratoires dont le laboratoire Logiciels, Systèmes, Réseaux (LSR). 00071 00072 This work has been done in the context of GIE DYADE (joint R & D venture 00073 between BULL S.A. and INRIA). 00074 00075 This software is available with usual "research" terms 00076 with the aim of retain credits of the software. 00077 Permission to use, copy, modify and distribute this software for any 00078 purpose and without fee is hereby granted, provided that the above 00079 copyright notice and this permission notice appear in all copies, 00080 and the name of INRIA, IMAG, or any contributor not be used in advertising 00081 or publicity pertaining to this material without the prior explicit 00082 permission. The software is provided "as is" without any 00083 warranties, support or liabilities of any kind. 00084 This software is derived from source code from 00085 "University of California at Berkeley" and 00086 "Digital Equipment Corporation" protected by copyrights. 00087 00088 Grenoble's Institute of Computer Science and Applied Mathematics (IMAG) 00089 is a federation of seven research units funded by the CNRS, National 00090 Polytechnic Institute of Grenoble and University Joseph Fourier. 00091 The research unit in Software, Systems, Networks (LSR) is member of IMAG. 00092 */ 00093 00094 /* 00095 * Derived from : 00096 * 00097 * 00098 * ipcp.c - PPP IP Control Protocol. 00099 * 00100 * Copyright (c) 1984-2000 Carnegie Mellon University. All rights reserved. 00101 * 00102 * Redistribution and use in source and binary forms, with or without 00103 * modification, are permitted provided that the following conditions 00104 * are met: 00105 * 00106 * 1. Redistributions of source code must retain the above copyright 00107 * notice, this list of conditions and the following disclaimer. 00108 * 00109 * 2. Redistributions in binary form must reproduce the above copyright 00110 * notice, this list of conditions and the following disclaimer in 00111 * the documentation and/or other materials provided with the 00112 * distribution. 00113 * 00114 * 3. The name "Carnegie Mellon University" must not be used to 00115 * endorse or promote products derived from this software without 00116 * prior written permission. For permission or any legal 00117 * details, please contact 00118 * Office of Technology Transfer 00119 * Carnegie Mellon University 00120 * 5000 Forbes Avenue 00121 * Pittsburgh, PA 15213-3890 00122 * (412) 268-4387, fax: (412) 268-7395 00123 * tech-transfer@andrew.cmu.edu 00124 * 00125 * 4. Redistributions of any form whatsoever must retain the following 00126 * acknowledgment: 00127 * "This product includes software developed by Computing Services 00128 * at Carnegie Mellon University (http://www.cmu.edu/computing/)." 00129 * 00130 * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO 00131 * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 00132 * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE 00133 * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 00134 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN 00135 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 00136 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 00137 * 00138 * $Id: ipv6cp.c,v 1.21 2005/08/25 23:59:34 paulus Exp $ 00139 */ 00140 00141 /* 00142 * @todo: 00143 * 00144 * Proxy Neighbour Discovery. 00145 * 00146 * Better defines for selecting the ordering of 00147 * interface up / set address. 00148 */ 00149 00150 #include "netif/ppp/ppp_opts.h" 00151 #if PPP_SUPPORT && PPP_IPV6_SUPPORT /* don't build if not configured for use in lwipopts.h */ 00152 00153 #if 0 /* UNUSED */ 00154 #include <stdio.h> 00155 #include <string.h> 00156 #include <unistd.h> 00157 #include <netdb.h> 00158 #include <sys/param.h> 00159 #include <sys/types.h> 00160 #include <sys/socket.h> 00161 #include <netinet/in.h> 00162 #include <arpa/inet.h> 00163 #endif /* UNUSED */ 00164 00165 #include "netif/ppp/ppp_impl.h" 00166 #include "netif/ppp/fsm.h" 00167 #include "netif/ppp/ipcp.h" 00168 #include "netif/ppp/ipv6cp.h" 00169 #include "netif/ppp/magic.h" 00170 00171 /* global vars */ 00172 #if 0 /* UNUSED */ 00173 int no_ifaceid_neg = 0; 00174 #endif /* UNUSED */ 00175 00176 /* 00177 * Callbacks for fsm code. (CI = Configuration Information) 00178 */ 00179 static void ipv6cp_resetci(fsm *f); /* Reset our CI */ 00180 static int ipv6cp_cilen(fsm *f); /* Return length of our CI */ 00181 static void ipv6cp_addci(fsm *f, u_char *ucp, int *lenp); /* Add our CI */ 00182 static int ipv6cp_ackci(fsm *f, u_char *p, int len); /* Peer ack'd our CI */ 00183 static int ipv6cp_nakci(fsm *f, u_char *p, int len, int treat_as_reject); /* Peer nak'd our CI */ 00184 static int ipv6cp_rejci(fsm *f, u_char *p, int len); /* Peer rej'd our CI */ 00185 static int ipv6cp_reqci(fsm *f, u_char *inp, int *len, int reject_if_disagree); /* Rcv CI */ 00186 static void ipv6cp_up(fsm *f); /* We're UP */ 00187 static void ipv6cp_down(fsm *f); /* We're DOWN */ 00188 static void ipv6cp_finished(fsm *f); /* Don't need lower layer */ 00189 00190 static const fsm_callbacks ipv6cp_callbacks = { /* IPV6CP callback routines */ 00191 ipv6cp_resetci, /* Reset our Configuration Information */ 00192 ipv6cp_cilen, /* Length of our Configuration Information */ 00193 ipv6cp_addci, /* Add our Configuration Information */ 00194 ipv6cp_ackci, /* ACK our Configuration Information */ 00195 ipv6cp_nakci, /* NAK our Configuration Information */ 00196 ipv6cp_rejci, /* Reject our Configuration Information */ 00197 ipv6cp_reqci, /* Request peer's Configuration Information */ 00198 ipv6cp_up, /* Called when fsm reaches OPENED state */ 00199 ipv6cp_down, /* Called when fsm leaves OPENED state */ 00200 NULL, /* Called when we want the lower layer up */ 00201 ipv6cp_finished, /* Called when we want the lower layer down */ 00202 NULL, /* Called when Protocol-Reject received */ 00203 NULL, /* Retransmission is necessary */ 00204 NULL, /* Called to handle protocol-specific codes */ 00205 "IPV6CP" /* String name of protocol */ 00206 }; 00207 00208 #if PPP_OPTIONS 00209 /* 00210 * Command-line options. 00211 */ 00212 static int setifaceid(char **arg)); 00213 static void printifaceid(option_t *, 00214 void (*)(void *, char *, ...), void *)); 00215 00216 static option_t ipv6cp_option_list[] = { 00217 { "ipv6", o_special, (void *)setifaceid, 00218 "Set interface identifiers for IPV6", 00219 OPT_A2PRINTER, (void *)printifaceid }, 00220 00221 { "+ipv6", o_bool, &ipv6cp_protent.enabled_flag, 00222 "Enable IPv6 and IPv6CP", OPT_PRIO | 1 }, 00223 { "noipv6", o_bool, &ipv6cp_protent.enabled_flag, 00224 "Disable IPv6 and IPv6CP", OPT_PRIOSUB }, 00225 { "-ipv6", o_bool, &ipv6cp_protent.enabled_flag, 00226 "Disable IPv6 and IPv6CP", OPT_PRIOSUB | OPT_ALIAS }, 00227 00228 { "ipv6cp-accept-local", o_bool, &ipv6cp_allowoptions[0].accept_local, 00229 "Accept peer's interface identifier for us", 1 }, 00230 00231 { "ipv6cp-use-ipaddr", o_bool, &ipv6cp_allowoptions[0].use_ip, 00232 "Use (default) IPv4 address as interface identifier", 1 }, 00233 00234 { "ipv6cp-use-persistent", o_bool, &ipv6cp_wantoptions[0].use_persistent, 00235 "Use uniquely-available persistent value for link local address", 1 }, 00236 00237 { "ipv6cp-restart", o_int, &ipv6cp_fsm[0].timeouttime, 00238 "Set timeout for IPv6CP", OPT_PRIO }, 00239 { "ipv6cp-max-terminate", o_int, &ipv6cp_fsm[0].maxtermtransmits, 00240 "Set max #xmits for term-reqs", OPT_PRIO }, 00241 { "ipv6cp-max-configure", o_int, &ipv6cp_fsm[0].maxconfreqtransmits, 00242 "Set max #xmits for conf-reqs", OPT_PRIO }, 00243 { "ipv6cp-max-failure", o_int, &ipv6cp_fsm[0].maxnakloops, 00244 "Set max #conf-naks for IPv6CP", OPT_PRIO }, 00245 00246 { NULL } 00247 }; 00248 #endif /* PPP_OPTIONS */ 00249 00250 /* 00251 * Protocol entry points from main code. 00252 */ 00253 static void ipv6cp_init(ppp_pcb *pcb); 00254 static void ipv6cp_open(ppp_pcb *pcb); 00255 static void ipv6cp_close(ppp_pcb *pcb, const char *reason); 00256 static void ipv6cp_lowerup(ppp_pcb *pcb); 00257 static void ipv6cp_lowerdown(ppp_pcb *pcb); 00258 static void ipv6cp_input(ppp_pcb *pcb, u_char *p, int len); 00259 static void ipv6cp_protrej(ppp_pcb *pcb); 00260 #if PPP_OPTIONS 00261 static void ipv6_check_options(void); 00262 #endif /* PPP_OPTIONS */ 00263 #if DEMAND_SUPPORT 00264 static int ipv6_demand_conf(int u); 00265 #endif /* DEMAND_SUPPORT */ 00266 #if PRINTPKT_SUPPORT 00267 static int ipv6cp_printpkt(const u_char *p, int plen, 00268 void (*printer)(void *, const char *, ...), void *arg); 00269 #endif /* PRINTPKT_SUPPORT */ 00270 #if DEMAND_SUPPORT 00271 static int ipv6_active_pkt(u_char *pkt, int len); 00272 #endif /* DEMAND_SUPPORT */ 00273 00274 const struct protent ipv6cp_protent = { 00275 PPP_IPV6CP, 00276 ipv6cp_init, 00277 ipv6cp_input, 00278 ipv6cp_protrej, 00279 ipv6cp_lowerup, 00280 ipv6cp_lowerdown, 00281 ipv6cp_open, 00282 ipv6cp_close, 00283 #if PRINTPKT_SUPPORT 00284 ipv6cp_printpkt, 00285 #endif /* PRINTPKT_SUPPORT */ 00286 #if PPP_DATAINPUT 00287 NULL, 00288 #endif /* PPP_DATAINPUT */ 00289 #if PRINTPKT_SUPPORT 00290 "IPV6CP", 00291 "IPV6", 00292 #endif /* PRINTPKT_SUPPORT */ 00293 #if PPP_OPTIONS 00294 ipv6cp_option_list, 00295 ipv6_check_options, 00296 #endif /* PPP_OPTIONS */ 00297 #if DEMAND_SUPPORT 00298 ipv6_demand_conf, 00299 ipv6_active_pkt 00300 #endif /* DEMAND_SUPPORT */ 00301 }; 00302 00303 static void ipv6cp_clear_addrs(ppp_pcb *pcb, eui64_t ourid, eui64_t hisid); 00304 #if 0 /* UNUSED */ 00305 static void ipv6cp_script(char *)); 00306 static void ipv6cp_script_done(void *)); 00307 #endif /* UNUSED */ 00308 00309 /* 00310 * Lengths of configuration options. 00311 */ 00312 #define CILEN_VOID 2 00313 #define CILEN_COMPRESS 4 /* length for RFC2023 compress opt. */ 00314 #define CILEN_IFACEID 10 /* RFC2472, interface identifier */ 00315 00316 #define CODENAME(x) ((x) == CONFACK ? "ACK" : \ 00317 (x) == CONFNAK ? "NAK" : "REJ") 00318 00319 #if 0 /* UNUSED */ 00320 /* 00321 * This state variable is used to ensure that we don't 00322 * run an ipcp-up/down script while one is already running. 00323 */ 00324 static enum script_state { 00325 s_down, 00326 s_up, 00327 } ipv6cp_script_state; 00328 static pid_t ipv6cp_script_pid; 00329 #endif /* UNUSED */ 00330 00331 static char *llv6_ntoa(eui64_t ifaceid); 00332 00333 #if PPP_OPTIONS 00334 /* 00335 * setifaceid - set the interface identifiers manually 00336 */ 00337 static int 00338 setifaceid(argv) 00339 char **argv; 00340 { 00341 char *comma, *arg, c; 00342 ipv6cp_options *wo = &ipv6cp_wantoptions[0]; 00343 struct in6_addr addr; 00344 static int prio_local, prio_remote; 00345 00346 #define VALIDID(a) ( (((a).s6_addr32[0] == 0) && ((a).s6_addr32[1] == 0)) && \ 00347 (((a).s6_addr32[2] != 0) || ((a).s6_addr32[3] != 0)) ) 00348 00349 arg = *argv; 00350 if ((comma = strchr(arg, ',')) == NULL) 00351 comma = arg + strlen(arg); 00352 00353 /* 00354 * If comma first character, then no local identifier 00355 */ 00356 if (comma != arg) { 00357 c = *comma; 00358 *comma = '\0'; 00359 00360 if (inet_pton(AF_INET6, arg, &addr) == 0 || !VALIDID(addr)) { 00361 option_error("Illegal interface identifier (local): %s", arg); 00362 return 0; 00363 } 00364 00365 if (option_priority >= prio_local) { 00366 eui64_copy(addr.s6_addr32[2], wo->ourid); 00367 wo->opt_local = 1; 00368 prio_local = option_priority; 00369 } 00370 *comma = c; 00371 } 00372 00373 /* 00374 * If comma last character, the no remote identifier 00375 */ 00376 if (*comma != 0 && *++comma != '\0') { 00377 if (inet_pton(AF_INET6, comma, &addr) == 0 || !VALIDID(addr)) { 00378 option_error("Illegal interface identifier (remote): %s", comma); 00379 return 0; 00380 } 00381 if (option_priority >= prio_remote) { 00382 eui64_copy(addr.s6_addr32[2], wo->hisid); 00383 wo->opt_remote = 1; 00384 prio_remote = option_priority; 00385 } 00386 } 00387 00388 if (override_value("+ipv6", option_priority, option_source)) 00389 ipv6cp_protent.enabled_flag = 1; 00390 return 1; 00391 } 00392 00393 static void 00394 printifaceid(opt, printer, arg) 00395 option_t *opt; 00396 void (*printer)(void *, char *, ...)); 00397 void *arg; 00398 { 00399 ipv6cp_options *wo = &ipv6cp_wantoptions[0]; 00400 00401 if (wo->opt_local) 00402 printer(arg, "%s", llv6_ntoa(wo->ourid)); 00403 printer(arg, ","); 00404 if (wo->opt_remote) 00405 printer(arg, "%s", llv6_ntoa(wo->hisid)); 00406 } 00407 #endif /* PPP_OPTIONS */ 00408 00409 /* 00410 * Make a string representation of a network address. 00411 */ 00412 static char * 00413 llv6_ntoa(eui64_t ifaceid) 00414 { 00415 static char b[26]; 00416 00417 sprintf(b, "fe80::%02x%02x:%02x%02x:%02x%02x:%02x%02x", 00418 ifaceid.e8[0], ifaceid.e8[1], ifaceid.e8[2], ifaceid.e8[3], 00419 ifaceid.e8[4], ifaceid.e8[5], ifaceid.e8[6], ifaceid.e8[7]); 00420 00421 return b; 00422 } 00423 00424 00425 /* 00426 * ipv6cp_init - Initialize IPV6CP. 00427 */ 00428 static void ipv6cp_init(ppp_pcb *pcb) { 00429 fsm *f = &pcb->ipv6cp_fsm; 00430 ipv6cp_options *wo = &pcb->ipv6cp_wantoptions; 00431 ipv6cp_options *ao = &pcb->ipv6cp_allowoptions; 00432 00433 f->pcb = pcb; 00434 f->protocol = PPP_IPV6CP; 00435 f->callbacks = &ipv6cp_callbacks; 00436 fsm_init(f); 00437 00438 #if 0 /* Not necessary, everything is cleared in ppp_new() */ 00439 memset(wo, 0, sizeof(*wo)); 00440 memset(ao, 0, sizeof(*ao)); 00441 #endif /* 0 */ 00442 00443 wo->accept_local = 1; 00444 wo->neg_ifaceid = 1; 00445 ao->neg_ifaceid = 1; 00446 00447 #ifdef IPV6CP_COMP 00448 wo->neg_vj = 1; 00449 ao->neg_vj = 1; 00450 wo->vj_protocol = IPV6CP_COMP; 00451 #endif 00452 00453 } 00454 00455 00456 /* 00457 * ipv6cp_open - IPV6CP is allowed to come up. 00458 */ 00459 static void ipv6cp_open(ppp_pcb *pcb) { 00460 fsm_open(&pcb->ipv6cp_fsm); 00461 } 00462 00463 00464 /* 00465 * ipv6cp_close - Take IPV6CP down. 00466 */ 00467 static void ipv6cp_close(ppp_pcb *pcb, const char *reason) { 00468 fsm_close(&pcb->ipv6cp_fsm, reason); 00469 } 00470 00471 00472 /* 00473 * ipv6cp_lowerup - The lower layer is up. 00474 */ 00475 static void ipv6cp_lowerup(ppp_pcb *pcb) { 00476 fsm_lowerup(&pcb->ipv6cp_fsm); 00477 } 00478 00479 00480 /* 00481 * ipv6cp_lowerdown - The lower layer is down. 00482 */ 00483 static void ipv6cp_lowerdown(ppp_pcb *pcb) { 00484 fsm_lowerdown(&pcb->ipv6cp_fsm); 00485 } 00486 00487 00488 /* 00489 * ipv6cp_input - Input IPV6CP packet. 00490 */ 00491 static void ipv6cp_input(ppp_pcb *pcb, u_char *p, int len) { 00492 fsm_input(&pcb->ipv6cp_fsm, p, len); 00493 } 00494 00495 00496 /* 00497 * ipv6cp_protrej - A Protocol-Reject was received for IPV6CP. 00498 * 00499 * Pretend the lower layer went down, so we shut up. 00500 */ 00501 static void ipv6cp_protrej(ppp_pcb *pcb) { 00502 fsm_lowerdown(&pcb->ipv6cp_fsm); 00503 } 00504 00505 00506 /* 00507 * ipv6cp_resetci - Reset our CI. 00508 */ 00509 static void ipv6cp_resetci(fsm *f) { 00510 ppp_pcb *pcb = f->pcb; 00511 ipv6cp_options *wo = &pcb->ipv6cp_wantoptions; 00512 ipv6cp_options *go = &pcb->ipv6cp_gotoptions; 00513 ipv6cp_options *ao = &pcb->ipv6cp_allowoptions; 00514 00515 wo->req_ifaceid = wo->neg_ifaceid && ao->neg_ifaceid; 00516 00517 if (!wo->opt_local) { 00518 eui64_magic_nz(wo->ourid); 00519 } 00520 00521 *go = *wo; 00522 eui64_zero(go->hisid); /* last proposed interface identifier */ 00523 } 00524 00525 00526 /* 00527 * ipv6cp_cilen - Return length of our CI. 00528 */ 00529 static int ipv6cp_cilen(fsm *f) { 00530 ppp_pcb *pcb = f->pcb; 00531 ipv6cp_options *go = &pcb->ipv6cp_gotoptions; 00532 00533 #ifdef IPV6CP_COMP 00534 #define LENCIVJ(neg) (neg ? CILEN_COMPRESS : 0) 00535 #endif /* IPV6CP_COMP */ 00536 #define LENCIIFACEID(neg) (neg ? CILEN_IFACEID : 0) 00537 00538 return (LENCIIFACEID(go->neg_ifaceid) + 00539 #ifdef IPV6CP_COMP 00540 LENCIVJ(go->neg_vj) + 00541 #endif /* IPV6CP_COMP */ 00542 0); 00543 } 00544 00545 00546 /* 00547 * ipv6cp_addci - Add our desired CIs to a packet. 00548 */ 00549 static void ipv6cp_addci(fsm *f, u_char *ucp, int *lenp) { 00550 ppp_pcb *pcb = f->pcb; 00551 ipv6cp_options *go = &pcb->ipv6cp_gotoptions; 00552 int len = *lenp; 00553 00554 #ifdef IPV6CP_COMP 00555 #define ADDCIVJ(opt, neg, val) \ 00556 if (neg) { \ 00557 int vjlen = CILEN_COMPRESS; \ 00558 if (len >= vjlen) { \ 00559 PUTCHAR(opt, ucp); \ 00560 PUTCHAR(vjlen, ucp); \ 00561 PUTSHORT(val, ucp); \ 00562 len -= vjlen; \ 00563 } else \ 00564 neg = 0; \ 00565 } 00566 #endif /* IPV6CP_COMP */ 00567 00568 #define ADDCIIFACEID(opt, neg, val1) \ 00569 if (neg) { \ 00570 int idlen = CILEN_IFACEID; \ 00571 if (len >= idlen) { \ 00572 PUTCHAR(opt, ucp); \ 00573 PUTCHAR(idlen, ucp); \ 00574 eui64_put(val1, ucp); \ 00575 len -= idlen; \ 00576 } else \ 00577 neg = 0; \ 00578 } 00579 00580 ADDCIIFACEID(CI_IFACEID, go->neg_ifaceid, go->ourid); 00581 00582 #ifdef IPV6CP_COMP 00583 ADDCIVJ(CI_COMPRESSTYPE, go->neg_vj, go->vj_protocol); 00584 #endif /* IPV6CP_COMP */ 00585 00586 *lenp -= len; 00587 } 00588 00589 00590 /* 00591 * ipv6cp_ackci - Ack our CIs. 00592 * 00593 * Returns: 00594 * 0 - Ack was bad. 00595 * 1 - Ack was good. 00596 */ 00597 static int ipv6cp_ackci(fsm *f, u_char *p, int len) { 00598 ppp_pcb *pcb = f->pcb; 00599 ipv6cp_options *go = &pcb->ipv6cp_gotoptions; 00600 u_short cilen, citype; 00601 #ifdef IPV6CP_COMP 00602 u_short cishort; 00603 #endif /* IPV6CP_COMP */ 00604 eui64_t ifaceid; 00605 00606 /* 00607 * CIs must be in exactly the same order that we sent... 00608 * Check packet length and CI length at each step. 00609 * If we find any deviations, then this packet is bad. 00610 */ 00611 00612 #ifdef IPV6CP_COMP 00613 #define ACKCIVJ(opt, neg, val) \ 00614 if (neg) { \ 00615 int vjlen = CILEN_COMPRESS; \ 00616 if ((len -= vjlen) < 0) \ 00617 goto bad; \ 00618 GETCHAR(citype, p); \ 00619 GETCHAR(cilen, p); \ 00620 if (cilen != vjlen || \ 00621 citype != opt) \ 00622 goto bad; \ 00623 GETSHORT(cishort, p); \ 00624 if (cishort != val) \ 00625 goto bad; \ 00626 } 00627 #endif /* IPV6CP_COMP */ 00628 00629 #define ACKCIIFACEID(opt, neg, val1) \ 00630 if (neg) { \ 00631 int idlen = CILEN_IFACEID; \ 00632 if ((len -= idlen) < 0) \ 00633 goto bad; \ 00634 GETCHAR(citype, p); \ 00635 GETCHAR(cilen, p); \ 00636 if (cilen != idlen || \ 00637 citype != opt) \ 00638 goto bad; \ 00639 eui64_get(ifaceid, p); \ 00640 if (! eui64_equals(val1, ifaceid)) \ 00641 goto bad; \ 00642 } 00643 00644 ACKCIIFACEID(CI_IFACEID, go->neg_ifaceid, go->ourid); 00645 00646 #ifdef IPV6CP_COMP 00647 ACKCIVJ(CI_COMPRESSTYPE, go->neg_vj, go->vj_protocol); 00648 #endif /* IPV6CP_COMP */ 00649 00650 /* 00651 * If there are any remaining CIs, then this packet is bad. 00652 */ 00653 if (len != 0) 00654 goto bad; 00655 return (1); 00656 00657 bad: 00658 IPV6CPDEBUG(("ipv6cp_ackci: received bad Ack!")); 00659 return (0); 00660 } 00661 00662 /* 00663 * ipv6cp_nakci - Peer has sent a NAK for some of our CIs. 00664 * This should not modify any state if the Nak is bad 00665 * or if IPV6CP is in the OPENED state. 00666 * 00667 * Returns: 00668 * 0 - Nak was bad. 00669 * 1 - Nak was good. 00670 */ 00671 static int ipv6cp_nakci(fsm *f, u_char *p, int len, int treat_as_reject) { 00672 ppp_pcb *pcb = f->pcb; 00673 ipv6cp_options *go = &pcb->ipv6cp_gotoptions; 00674 u_char citype, cilen, *next; 00675 #ifdef IPV6CP_COMP 00676 u_short cishort; 00677 #endif /* IPV6CP_COMP */ 00678 eui64_t ifaceid; 00679 ipv6cp_options no; /* options we've seen Naks for */ 00680 ipv6cp_options try_; /* options to request next time */ 00681 00682 BZERO(&no, sizeof(no)); 00683 try_ = *go; 00684 00685 /* 00686 * Any Nak'd CIs must be in exactly the same order that we sent. 00687 * Check packet length and CI length at each step. 00688 * If we find any deviations, then this packet is bad. 00689 */ 00690 #define NAKCIIFACEID(opt, neg, code) \ 00691 if (go->neg && \ 00692 len >= (cilen = CILEN_IFACEID) && \ 00693 p[1] == cilen && \ 00694 p[0] == opt) { \ 00695 len -= cilen; \ 00696 INCPTR(2, p); \ 00697 eui64_get(ifaceid, p); \ 00698 no.neg = 1; \ 00699 code \ 00700 } 00701 00702 #ifdef IPV6CP_COMP 00703 #define NAKCIVJ(opt, neg, code) \ 00704 if (go->neg && \ 00705 ((cilen = p[1]) == CILEN_COMPRESS) && \ 00706 len >= cilen && \ 00707 p[0] == opt) { \ 00708 len -= cilen; \ 00709 INCPTR(2, p); \ 00710 GETSHORT(cishort, p); \ 00711 no.neg = 1; \ 00712 code \ 00713 } 00714 #endif /* IPV6CP_COMP */ 00715 00716 /* 00717 * Accept the peer's idea of {our,his} interface identifier, if different 00718 * from our idea, only if the accept_{local,remote} flag is set. 00719 */ 00720 NAKCIIFACEID(CI_IFACEID, neg_ifaceid, 00721 if (treat_as_reject) { 00722 try_.neg_ifaceid = 0; 00723 } else if (go->accept_local) { 00724 while (eui64_iszero(ifaceid) || 00725 eui64_equals(ifaceid, go->hisid)) /* bad luck */ 00726 eui64_magic(ifaceid); 00727 try_.ourid = ifaceid; 00728 IPV6CPDEBUG(("local LL address %s", llv6_ntoa(ifaceid))); 00729 } 00730 ); 00731 00732 #ifdef IPV6CP_COMP 00733 NAKCIVJ(CI_COMPRESSTYPE, neg_vj, 00734 { 00735 if (cishort == IPV6CP_COMP && !treat_as_reject) { 00736 try_.vj_protocol = cishort; 00737 } else { 00738 try_.neg_vj = 0; 00739 } 00740 } 00741 ); 00742 #endif /* IPV6CP_COMP */ 00743 00744 /* 00745 * There may be remaining CIs, if the peer is requesting negotiation 00746 * on an option that we didn't include in our request packet. 00747 * If they want to negotiate about interface identifier, we comply. 00748 * If they want us to ask for compression, we refuse. 00749 */ 00750 while (len >= CILEN_VOID) { 00751 GETCHAR(citype, p); 00752 GETCHAR(cilen, p); 00753 if ( cilen < CILEN_VOID || (len -= cilen) < 0 ) 00754 goto bad; 00755 next = p + cilen - 2; 00756 00757 switch (citype) { 00758 #ifdef IPV6CP_COMP 00759 case CI_COMPRESSTYPE: 00760 if (go->neg_vj || no.neg_vj || 00761 (cilen != CILEN_COMPRESS)) 00762 goto bad; 00763 no.neg_vj = 1; 00764 break; 00765 #endif /* IPV6CP_COMP */ 00766 case CI_IFACEID: 00767 if (go->neg_ifaceid || no.neg_ifaceid || cilen != CILEN_IFACEID) 00768 goto bad; 00769 try_.neg_ifaceid = 1; 00770 eui64_get(ifaceid, p); 00771 if (go->accept_local) { 00772 while (eui64_iszero(ifaceid) || 00773 eui64_equals(ifaceid, go->hisid)) /* bad luck */ 00774 eui64_magic(ifaceid); 00775 try_.ourid = ifaceid; 00776 } 00777 no.neg_ifaceid = 1; 00778 break; 00779 default: 00780 break; 00781 } 00782 p = next; 00783 } 00784 00785 /* If there is still anything left, this packet is bad. */ 00786 if (len != 0) 00787 goto bad; 00788 00789 /* 00790 * OK, the Nak is good. Now we can update state. 00791 */ 00792 if (f->state != PPP_FSM_OPENED) 00793 *go = try_; 00794 00795 return 1; 00796 00797 bad: 00798 IPV6CPDEBUG(("ipv6cp_nakci: received bad Nak!")); 00799 return 0; 00800 } 00801 00802 00803 /* 00804 * ipv6cp_rejci - Reject some of our CIs. 00805 */ 00806 static int ipv6cp_rejci(fsm *f, u_char *p, int len) { 00807 ppp_pcb *pcb = f->pcb; 00808 ipv6cp_options *go = &pcb->ipv6cp_gotoptions; 00809 u_char cilen; 00810 #ifdef IPV6CP_COMP 00811 u_short cishort; 00812 #endif /* IPV6CP_COMP */ 00813 eui64_t ifaceid; 00814 ipv6cp_options try_; /* options to request next time */ 00815 00816 try_ = *go; 00817 /* 00818 * Any Rejected CIs must be in exactly the same order that we sent. 00819 * Check packet length and CI length at each step. 00820 * If we find any deviations, then this packet is bad. 00821 */ 00822 #define REJCIIFACEID(opt, neg, val1) \ 00823 if (go->neg && \ 00824 len >= (cilen = CILEN_IFACEID) && \ 00825 p[1] == cilen && \ 00826 p[0] == opt) { \ 00827 len -= cilen; \ 00828 INCPTR(2, p); \ 00829 eui64_get(ifaceid, p); \ 00830 /* Check rejected value. */ \ 00831 if (! eui64_equals(ifaceid, val1)) \ 00832 goto bad; \ 00833 try_.neg = 0; \ 00834 } 00835 00836 #ifdef IPV6CP_COMP 00837 #define REJCIVJ(opt, neg, val) \ 00838 if (go->neg && \ 00839 p[1] == CILEN_COMPRESS && \ 00840 len >= p[1] && \ 00841 p[0] == opt) { \ 00842 len -= p[1]; \ 00843 INCPTR(2, p); \ 00844 GETSHORT(cishort, p); \ 00845 /* Check rejected value. */ \ 00846 if (cishort != val) \ 00847 goto bad; \ 00848 try_.neg = 0; \ 00849 } 00850 #endif /* IPV6CP_COMP */ 00851 00852 REJCIIFACEID(CI_IFACEID, neg_ifaceid, go->ourid); 00853 00854 #ifdef IPV6CP_COMP 00855 REJCIVJ(CI_COMPRESSTYPE, neg_vj, go->vj_protocol); 00856 #endif /* IPV6CP_COMP */ 00857 00858 /* 00859 * If there are any remaining CIs, then this packet is bad. 00860 */ 00861 if (len != 0) 00862 goto bad; 00863 /* 00864 * Now we can update state. 00865 */ 00866 if (f->state != PPP_FSM_OPENED) 00867 *go = try_; 00868 return 1; 00869 00870 bad: 00871 IPV6CPDEBUG(("ipv6cp_rejci: received bad Reject!")); 00872 return 0; 00873 } 00874 00875 00876 /* 00877 * ipv6cp_reqci - Check the peer's requested CIs and send appropriate response. 00878 * 00879 * Returns: CONFACK, CONFNAK or CONFREJ and input packet modified 00880 * appropriately. If reject_if_disagree is non-zero, doesn't return 00881 * CONFNAK; returns CONFREJ if it can't return CONFACK. 00882 * 00883 * inp = Requested CIs 00884 * len = Length of requested CIs 00885 * 00886 */ 00887 static int ipv6cp_reqci(fsm *f, u_char *inp, int *len, int reject_if_disagree) { 00888 ppp_pcb *pcb = f->pcb; 00889 ipv6cp_options *wo = &pcb->ipv6cp_wantoptions; 00890 ipv6cp_options *ho = &pcb->ipv6cp_hisoptions; 00891 ipv6cp_options *ao = &pcb->ipv6cp_allowoptions; 00892 ipv6cp_options *go = &pcb->ipv6cp_gotoptions; 00893 u_char *cip, *next; /* Pointer to current and next CIs */ 00894 u_short cilen, citype; /* Parsed len, type */ 00895 #ifdef IPV6CP_COMP 00896 u_short cishort; /* Parsed short value */ 00897 #endif /* IPV6CP_COMP */ 00898 eui64_t ifaceid; /* Parsed interface identifier */ 00899 int rc = CONFACK; /* Final packet return code */ 00900 int orc; /* Individual option return code */ 00901 u_char *p; /* Pointer to next char to parse */ 00902 u_char *ucp = inp; /* Pointer to current output char */ 00903 int l = *len; /* Length left */ 00904 00905 /* 00906 * Reset all his options. 00907 */ 00908 BZERO(ho, sizeof(*ho)); 00909 00910 /* 00911 * Process all his options. 00912 */ 00913 next = inp; 00914 while (l) { 00915 orc = CONFACK; /* Assume success */ 00916 cip = p = next; /* Remember begining of CI */ 00917 if (l < 2 || /* Not enough data for CI header or */ 00918 p[1] < 2 || /* CI length too small or */ 00919 p[1] > l) { /* CI length too big? */ 00920 IPV6CPDEBUG(("ipv6cp_reqci: bad CI length!")); 00921 orc = CONFREJ; /* Reject bad CI */ 00922 cilen = l; /* Reject till end of packet */ 00923 l = 0; /* Don't loop again */ 00924 goto endswitch; 00925 } 00926 GETCHAR(citype, p); /* Parse CI type */ 00927 GETCHAR(cilen, p); /* Parse CI length */ 00928 l -= cilen; /* Adjust remaining length */ 00929 next += cilen; /* Step to next CI */ 00930 00931 switch (citype) { /* Check CI type */ 00932 case CI_IFACEID: 00933 IPV6CPDEBUG(("ipv6cp: received interface identifier ")); 00934 00935 if (!ao->neg_ifaceid || 00936 cilen != CILEN_IFACEID) { /* Check CI length */ 00937 orc = CONFREJ; /* Reject CI */ 00938 break; 00939 } 00940 00941 /* 00942 * If he has no interface identifier, or if we both have same 00943 * identifier then NAK it with new idea. 00944 * In particular, if we don't know his identifier, but he does, 00945 * then accept it. 00946 */ 00947 eui64_get(ifaceid, p); 00948 IPV6CPDEBUG(("(%s)", llv6_ntoa(ifaceid))); 00949 if (eui64_iszero(ifaceid) && eui64_iszero(go->ourid)) { 00950 orc = CONFREJ; /* Reject CI */ 00951 break; 00952 } 00953 if (!eui64_iszero(wo->hisid) && 00954 !eui64_equals(ifaceid, wo->hisid) && 00955 eui64_iszero(go->hisid)) { 00956 00957 orc = CONFNAK; 00958 ifaceid = wo->hisid; 00959 go->hisid = ifaceid; 00960 DECPTR(sizeof(ifaceid), p); 00961 eui64_put(ifaceid, p); 00962 } else 00963 if (eui64_iszero(ifaceid) || eui64_equals(ifaceid, go->ourid)) { 00964 orc = CONFNAK; 00965 if (eui64_iszero(go->hisid)) /* first time, try option */ 00966 ifaceid = wo->hisid; 00967 while (eui64_iszero(ifaceid) || 00968 eui64_equals(ifaceid, go->ourid)) /* bad luck */ 00969 eui64_magic(ifaceid); 00970 go->hisid = ifaceid; 00971 DECPTR(sizeof(ifaceid), p); 00972 eui64_put(ifaceid, p); 00973 } 00974 00975 ho->neg_ifaceid = 1; 00976 ho->hisid = ifaceid; 00977 break; 00978 00979 #ifdef IPV6CP_COMP 00980 case CI_COMPRESSTYPE: 00981 IPV6CPDEBUG(("ipv6cp: received COMPRESSTYPE ")); 00982 if (!ao->neg_vj || 00983 (cilen != CILEN_COMPRESS)) { 00984 orc = CONFREJ; 00985 break; 00986 } 00987 GETSHORT(cishort, p); 00988 IPV6CPDEBUG(("(%d)", cishort)); 00989 00990 if (!(cishort == IPV6CP_COMP)) { 00991 orc = CONFREJ; 00992 break; 00993 } 00994 00995 ho->neg_vj = 1; 00996 ho->vj_protocol = cishort; 00997 break; 00998 #endif /* IPV6CP_COMP */ 00999 01000 default: 01001 orc = CONFREJ; 01002 break; 01003 } 01004 01005 endswitch: 01006 IPV6CPDEBUG((" (%s)\n", CODENAME(orc))); 01007 01008 if (orc == CONFACK && /* Good CI */ 01009 rc != CONFACK) /* but prior CI wasnt? */ 01010 continue; /* Don't send this one */ 01011 01012 if (orc == CONFNAK) { /* Nak this CI? */ 01013 if (reject_if_disagree) /* Getting fed up with sending NAKs? */ 01014 orc = CONFREJ; /* Get tough if so */ 01015 else { 01016 if (rc == CONFREJ) /* Rejecting prior CI? */ 01017 continue; /* Don't send this one */ 01018 if (rc == CONFACK) { /* Ack'd all prior CIs? */ 01019 rc = CONFNAK; /* Not anymore... */ 01020 ucp = inp; /* Backup */ 01021 } 01022 } 01023 } 01024 01025 if (orc == CONFREJ && /* Reject this CI */ 01026 rc != CONFREJ) { /* but no prior ones? */ 01027 rc = CONFREJ; 01028 ucp = inp; /* Backup */ 01029 } 01030 01031 /* Need to move CI? */ 01032 if (ucp != cip) 01033 MEMCPY(ucp, cip, cilen); /* Move it */ 01034 01035 /* Update output pointer */ 01036 INCPTR(cilen, ucp); 01037 } 01038 01039 /* 01040 * If we aren't rejecting this packet, and we want to negotiate 01041 * their identifier and they didn't send their identifier, then we 01042 * send a NAK with a CI_IFACEID option appended. We assume the 01043 * input buffer is long enough that we can append the extra 01044 * option safely. 01045 */ 01046 if (rc != CONFREJ && !ho->neg_ifaceid && 01047 wo->req_ifaceid && !reject_if_disagree) { 01048 if (rc == CONFACK) { 01049 rc = CONFNAK; 01050 ucp = inp; /* reset pointer */ 01051 wo->req_ifaceid = 0; /* don't ask again */ 01052 } 01053 PUTCHAR(CI_IFACEID, ucp); 01054 PUTCHAR(CILEN_IFACEID, ucp); 01055 eui64_put(wo->hisid, ucp); 01056 } 01057 01058 *len = ucp - inp; /* Compute output length */ 01059 IPV6CPDEBUG(("ipv6cp: returning Configure-%s", CODENAME(rc))); 01060 return (rc); /* Return final code */ 01061 } 01062 01063 #if PPP_OPTIONS 01064 /* 01065 * ipv6_check_options - check that any IP-related options are OK, 01066 * and assign appropriate defaults. 01067 */ 01068 static void ipv6_check_options() { 01069 ipv6cp_options *wo = &ipv6cp_wantoptions[0]; 01070 01071 if (!ipv6cp_protent.enabled_flag) 01072 return; 01073 01074 /* 01075 * Persistent link-local id is only used when user has not explicitly 01076 * configure/hard-code the id 01077 */ 01078 if ((wo->use_persistent) && (!wo->opt_local) && (!wo->opt_remote)) { 01079 01080 /* 01081 * On systems where there are no Ethernet interfaces used, there 01082 * may be other ways to obtain a persistent id. Right now, it 01083 * will fall back to using magic [see eui64_magic] below when 01084 * an EUI-48 from MAC address can't be obtained. Other possibilities 01085 * include obtaining EEPROM serial numbers, or some other unique 01086 * yet persistent number. On Sparc platforms, this is possible, 01087 * but too bad there's no standards yet for x86 machines. 01088 */ 01089 if (ether_to_eui64(&wo->ourid)) { 01090 wo->opt_local = 1; 01091 } 01092 } 01093 01094 if (!wo->opt_local) { /* init interface identifier */ 01095 if (wo->use_ip && eui64_iszero(wo->ourid)) { 01096 eui64_setlo32(wo->ourid, ntohl(ipcp_wantoptions[0].ouraddr)); 01097 if (!eui64_iszero(wo->ourid)) 01098 wo->opt_local = 1; 01099 } 01100 01101 while (eui64_iszero(wo->ourid)) 01102 eui64_magic(wo->ourid); 01103 } 01104 01105 if (!wo->opt_remote) { 01106 if (wo->use_ip && eui64_iszero(wo->hisid)) { 01107 eui64_setlo32(wo->hisid, ntohl(ipcp_wantoptions[0].hisaddr)); 01108 if (!eui64_iszero(wo->hisid)) 01109 wo->opt_remote = 1; 01110 } 01111 } 01112 01113 if (demand && (eui64_iszero(wo->ourid) || eui64_iszero(wo->hisid))) { 01114 option_error("local/remote LL address required for demand-dialling\n"); 01115 exit(1); 01116 } 01117 } 01118 #endif /* PPP_OPTIONS */ 01119 01120 #if DEMAND_SUPPORT 01121 /* 01122 * ipv6_demand_conf - configure the interface as though 01123 * IPV6CP were up, for use with dial-on-demand. 01124 */ 01125 static int ipv6_demand_conf(int u) { 01126 ipv6cp_options *wo = &ipv6cp_wantoptions[u]; 01127 01128 if (!sif6up(u)) 01129 return 0; 01130 01131 if (!sif6addr(u, wo->ourid, wo->hisid)) 01132 return 0; 01133 01134 if (!sifnpmode(u, PPP_IPV6, NPMODE_QUEUE)) 01135 return 0; 01136 01137 ppp_notice("ipv6_demand_conf"); 01138 ppp_notice("local LL address %s", llv6_ntoa(wo->ourid)); 01139 ppp_notice("remote LL address %s", llv6_ntoa(wo->hisid)); 01140 01141 return 1; 01142 } 01143 #endif /* DEMAND_SUPPORT */ 01144 01145 01146 /* 01147 * ipv6cp_up - IPV6CP has come UP. 01148 * 01149 * Configure the IPv6 network interface appropriately and bring it up. 01150 */ 01151 static void ipv6cp_up(fsm *f) { 01152 ppp_pcb *pcb = f->pcb; 01153 ipv6cp_options *wo = &pcb->ipv6cp_wantoptions; 01154 ipv6cp_options *ho = &pcb->ipv6cp_hisoptions; 01155 ipv6cp_options *go = &pcb->ipv6cp_gotoptions; 01156 01157 IPV6CPDEBUG(("ipv6cp: up")); 01158 01159 /* 01160 * We must have a non-zero LL address for both ends of the link. 01161 */ 01162 if (!ho->neg_ifaceid) 01163 ho->hisid = wo->hisid; 01164 01165 #if 0 /* UNUSED */ 01166 if(!no_ifaceid_neg) { 01167 #endif /* UNUSED */ 01168 if (eui64_iszero(ho->hisid)) { 01169 ppp_error("Could not determine remote LL address"); 01170 ipv6cp_close(f->pcb, "Could not determine remote LL address"); 01171 return; 01172 } 01173 if (eui64_iszero(go->ourid)) { 01174 ppp_error("Could not determine local LL address"); 01175 ipv6cp_close(f->pcb, "Could not determine local LL address"); 01176 return; 01177 } 01178 if (eui64_equals(go->ourid, ho->hisid)) { 01179 ppp_error("local and remote LL addresses are equal"); 01180 ipv6cp_close(f->pcb, "local and remote LL addresses are equal"); 01181 return; 01182 } 01183 #if 0 /* UNUSED */ 01184 } 01185 #endif /* UNUSED */ 01186 #if 0 /* UNUSED */ 01187 script_setenv("LLLOCAL", llv6_ntoa(go->ourid), 0); 01188 script_setenv("LLREMOTE", llv6_ntoa(ho->hisid), 0); 01189 #endif /* UNUSED */ 01190 01191 #ifdef IPV6CP_COMP 01192 /* set tcp compression */ 01193 sif6comp(f->unit, ho->neg_vj); 01194 #endif 01195 01196 #if DEMAND_SUPPORT 01197 /* 01198 * If we are doing dial-on-demand, the interface is already 01199 * configured, so we put out any saved-up packets, then set the 01200 * interface to pass IPv6 packets. 01201 */ 01202 if (demand) { 01203 if (! eui64_equals(go->ourid, wo->ourid) || 01204 ! eui64_equals(ho->hisid, wo->hisid)) { 01205 if (! eui64_equals(go->ourid, wo->ourid)) 01206 warn("Local LL address changed to %s", 01207 llv6_ntoa(go->ourid)); 01208 if (! eui64_equals(ho->hisid, wo->hisid)) 01209 warn("Remote LL address changed to %s", 01210 llv6_ntoa(ho->hisid)); 01211 ipv6cp_clear_addrs(f->pcb, go->ourid, ho->hisid); 01212 01213 /* Set the interface to the new addresses */ 01214 if (!sif6addr(f->pcb, go->ourid, ho->hisid)) { 01215 if (debug) 01216 warn("sif6addr failed"); 01217 ipv6cp_close(f->unit, "Interface configuration failed"); 01218 return; 01219 } 01220 01221 } 01222 demand_rexmit(PPP_IPV6); 01223 sifnpmode(f->unit, PPP_IPV6, NPMODE_PASS); 01224 01225 } else 01226 #endif /* DEMAND_SUPPORT */ 01227 { 01228 /* 01229 * Set LL addresses 01230 */ 01231 if (!sif6addr(f->pcb, go->ourid, ho->hisid)) { 01232 PPPDEBUG(LOG_DEBUG, ("sif6addr failed")); 01233 ipv6cp_close(f->pcb, "Interface configuration failed"); 01234 return; 01235 } 01236 01237 /* bring the interface up for IPv6 */ 01238 if (!sif6up(f->pcb)) { 01239 PPPDEBUG(LOG_DEBUG, ("sif6up failed (IPV6)")); 01240 ipv6cp_close(f->pcb, "Interface configuration failed"); 01241 return; 01242 } 01243 #if DEMAND_SUPPORT 01244 sifnpmode(f->pcb, PPP_IPV6, NPMODE_PASS); 01245 #endif /* DEMAND_SUPPORT */ 01246 01247 ppp_notice("local LL address %s", llv6_ntoa(go->ourid)); 01248 ppp_notice("remote LL address %s", llv6_ntoa(ho->hisid)); 01249 } 01250 01251 np_up(f->pcb, PPP_IPV6); 01252 pcb->ipv6cp_is_up = 1; 01253 01254 #if 0 /* UNUSED */ 01255 /* 01256 * Execute the ipv6-up script, like this: 01257 * /etc/ppp/ipv6-up interface tty speed local-LL remote-LL 01258 */ 01259 if (ipv6cp_script_state == s_down && ipv6cp_script_pid == 0) { 01260 ipv6cp_script_state = s_up; 01261 ipv6cp_script(_PATH_IPV6UP); 01262 } 01263 #endif /* UNUSED */ 01264 } 01265 01266 01267 /* 01268 * ipv6cp_down - IPV6CP has gone DOWN. 01269 * 01270 * Take the IPv6 network interface down, clear its addresses 01271 * and delete routes through it. 01272 */ 01273 static void ipv6cp_down(fsm *f) { 01274 ppp_pcb *pcb = f->pcb; 01275 ipv6cp_options *go = &pcb->ipv6cp_gotoptions; 01276 ipv6cp_options *ho = &pcb->ipv6cp_hisoptions; 01277 01278 IPV6CPDEBUG(("ipv6cp: down")); 01279 #if PPP_STATS_SUPPORT 01280 update_link_stats(f->unit); 01281 #endif /* PPP_STATS_SUPPORT */ 01282 if (pcb->ipv6cp_is_up) { 01283 pcb->ipv6cp_is_up = 0; 01284 np_down(f->pcb, PPP_IPV6); 01285 } 01286 #ifdef IPV6CP_COMP 01287 sif6comp(f->unit, 0); 01288 #endif 01289 01290 #if DEMAND_SUPPORT 01291 /* 01292 * If we are doing dial-on-demand, set the interface 01293 * to queue up outgoing packets (for now). 01294 */ 01295 if (demand) { 01296 sifnpmode(f->pcb, PPP_IPV6, NPMODE_QUEUE); 01297 } else 01298 #endif /* DEMAND_SUPPORT */ 01299 { 01300 #if DEMAND_SUPPORT 01301 sifnpmode(f->pcb, PPP_IPV6, NPMODE_DROP); 01302 #endif /* DEMAND_SUPPORT */ 01303 ipv6cp_clear_addrs(f->pcb, 01304 go->ourid, 01305 ho->hisid); 01306 sif6down(f->pcb); 01307 } 01308 01309 #if 0 /* UNUSED */ 01310 /* Execute the ipv6-down script */ 01311 if (ipv6cp_script_state == s_up && ipv6cp_script_pid == 0) { 01312 ipv6cp_script_state = s_down; 01313 ipv6cp_script(_PATH_IPV6DOWN); 01314 } 01315 #endif /* UNUSED */ 01316 } 01317 01318 01319 /* 01320 * ipv6cp_clear_addrs() - clear the interface addresses, routes, 01321 * proxy neighbour discovery entries, etc. 01322 */ 01323 static void ipv6cp_clear_addrs(ppp_pcb *pcb, eui64_t ourid, eui64_t hisid) { 01324 cif6addr(pcb, ourid, hisid); 01325 } 01326 01327 01328 /* 01329 * ipv6cp_finished - possibly shut down the lower layers. 01330 */ 01331 static void ipv6cp_finished(fsm *f) { 01332 np_finished(f->pcb, PPP_IPV6); 01333 } 01334 01335 01336 #if 0 /* UNUSED */ 01337 /* 01338 * ipv6cp_script_done - called when the ipv6-up or ipv6-down script 01339 * has finished. 01340 */ 01341 static void 01342 ipv6cp_script_done(arg) 01343 void *arg; 01344 { 01345 ipv6cp_script_pid = 0; 01346 switch (ipv6cp_script_state) { 01347 case s_up: 01348 if (ipv6cp_fsm[0].state != PPP_FSM_OPENED) { 01349 ipv6cp_script_state = s_down; 01350 ipv6cp_script(_PATH_IPV6DOWN); 01351 } 01352 break; 01353 case s_down: 01354 if (ipv6cp_fsm[0].state == PPP_FSM_OPENED) { 01355 ipv6cp_script_state = s_up; 01356 ipv6cp_script(_PATH_IPV6UP); 01357 } 01358 break; 01359 } 01360 } 01361 01362 01363 /* 01364 * ipv6cp_script - Execute a script with arguments 01365 * interface-name tty-name speed local-LL remote-LL. 01366 */ 01367 static void 01368 ipv6cp_script(script) 01369 char *script; 01370 { 01371 char strspeed[32], strlocal[32], strremote[32]; 01372 char *argv[8]; 01373 01374 sprintf(strspeed, "%d", baud_rate); 01375 strcpy(strlocal, llv6_ntoa(ipv6cp_gotoptions[0].ourid)); 01376 strcpy(strremote, llv6_ntoa(ipv6cp_hisoptions[0].hisid)); 01377 01378 argv[0] = script; 01379 argv[1] = ifname; 01380 argv[2] = devnam; 01381 argv[3] = strspeed; 01382 argv[4] = strlocal; 01383 argv[5] = strremote; 01384 argv[6] = ipparam; 01385 argv[7] = NULL; 01386 01387 ipv6cp_script_pid = run_program(script, argv, 0, ipv6cp_script_done, 01388 NULL, 0); 01389 } 01390 #endif /* UNUSED */ 01391 01392 #if PRINTPKT_SUPPORT 01393 /* 01394 * ipv6cp_printpkt - print the contents of an IPV6CP packet. 01395 */ 01396 static const char* const ipv6cp_codenames[] = { 01397 "ConfReq", "ConfAck", "ConfNak", "ConfRej", 01398 "TermReq", "TermAck", "CodeRej" 01399 }; 01400 01401 static int ipv6cp_printpkt(const u_char *p, int plen, 01402 void (*printer)(void *, const char *, ...), void *arg) { 01403 int code, id, len, olen; 01404 const u_char *pstart, *optend; 01405 #ifdef IPV6CP_COMP 01406 u_short cishort; 01407 #endif /* IPV6CP_COMP */ 01408 eui64_t ifaceid; 01409 01410 if (plen < HEADERLEN) 01411 return 0; 01412 pstart = p; 01413 GETCHAR(code, p); 01414 GETCHAR(id, p); 01415 GETSHORT(len, p); 01416 if (len < HEADERLEN || len > plen) 01417 return 0; 01418 01419 if (code >= 1 && code <= (int)LWIP_ARRAYSIZE(ipv6cp_codenames)) 01420 printer(arg, " %s", ipv6cp_codenames[code-1]); 01421 else 01422 printer(arg, " code=0x%x", code); 01423 printer(arg, " id=0x%x", id); 01424 len -= HEADERLEN; 01425 switch (code) { 01426 case CONFREQ: 01427 case CONFACK: 01428 case CONFNAK: 01429 case CONFREJ: 01430 /* print option list */ 01431 while (len >= 2) { 01432 GETCHAR(code, p); 01433 GETCHAR(olen, p); 01434 p -= 2; 01435 if (olen < 2 || olen > len) { 01436 break; 01437 } 01438 printer(arg, " <"); 01439 len -= olen; 01440 optend = p + olen; 01441 switch (code) { 01442 #ifdef IPV6CP_COMP 01443 case CI_COMPRESSTYPE: 01444 if (olen >= CILEN_COMPRESS) { 01445 p += 2; 01446 GETSHORT(cishort, p); 01447 printer(arg, "compress "); 01448 printer(arg, "0x%x", cishort); 01449 } 01450 break; 01451 #endif /* IPV6CP_COMP */ 01452 case CI_IFACEID: 01453 if (olen == CILEN_IFACEID) { 01454 p += 2; 01455 eui64_get(ifaceid, p); 01456 printer(arg, "addr %s", llv6_ntoa(ifaceid)); 01457 } 01458 break; 01459 default: 01460 break; 01461 } 01462 while (p < optend) { 01463 GETCHAR(code, p); 01464 printer(arg, " %.2x", code); 01465 } 01466 printer(arg, ">"); 01467 } 01468 break; 01469 01470 case TERMACK: 01471 case TERMREQ: 01472 if (len > 0 && *p >= ' ' && *p < 0x7f) { 01473 printer(arg, " "); 01474 ppp_print_string(p, len, printer, arg); 01475 p += len; 01476 len = 0; 01477 } 01478 break; 01479 default: 01480 break; 01481 } 01482 01483 /* print the rest of the bytes in the packet */ 01484 for (; len > 0; --len) { 01485 GETCHAR(code, p); 01486 printer(arg, " %.2x", code); 01487 } 01488 01489 return p - pstart; 01490 } 01491 #endif /* PRINTPKT_SUPPORT */ 01492 01493 #if DEMAND_SUPPORT 01494 /* 01495 * ipv6_active_pkt - see if this IP packet is worth bringing the link up for. 01496 * We don't bring the link up for IP fragments or for TCP FIN packets 01497 * with no data. 01498 */ 01499 #define IP6_HDRLEN 40 /* bytes */ 01500 #define IP6_NHDR_FRAG 44 /* fragment IPv6 header */ 01501 #define TCP_HDRLEN 20 01502 #define TH_FIN 0x01 01503 01504 /* 01505 * We use these macros because the IP header may be at an odd address, 01506 * and some compilers might use word loads to get th_off or ip_hl. 01507 */ 01508 01509 #define get_ip6nh(x) (((unsigned char *)(x))[6]) 01510 #define get_tcpoff(x) (((unsigned char *)(x))[12] >> 4) 01511 #define get_tcpflags(x) (((unsigned char *)(x))[13]) 01512 01513 static int ipv6_active_pkt(u_char *pkt, int len) { 01514 u_char *tcp; 01515 01516 len -= PPP_HDRLEN; 01517 pkt += PPP_HDRLEN; 01518 if (len < IP6_HDRLEN) 01519 return 0; 01520 if (get_ip6nh(pkt) == IP6_NHDR_FRAG) 01521 return 0; 01522 if (get_ip6nh(pkt) != IPPROTO_TCP) 01523 return 1; 01524 if (len < IP6_HDRLEN + TCP_HDRLEN) 01525 return 0; 01526 tcp = pkt + IP6_HDRLEN; 01527 if ((get_tcpflags(tcp) & TH_FIN) != 0 && len == IP6_HDRLEN + get_tcpoff(tcp) * 4) 01528 return 0; 01529 return 1; 01530 } 01531 #endif /* DEMAND_SUPPORT */ 01532 01533 #endif /* PPP_SUPPORT && PPP_IPV6_SUPPORT */
Generated on Tue Jul 12 2022 11:02:41 by
