Marco Zecchini
/
Example_RTOS
Rtos API example
Embed:
(wiki syntax)
Show/hide line numbers
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 #if PPP_IPV4_SUPPORT && PPP_IPV6_SUPPORT 00477 if (pcb->ipv6cp_disabled) { 00478 return; 00479 } 00480 #endif 00481 fsm_lowerup(&pcb->ipv6cp_fsm); 00482 } 00483 00484 00485 /* 00486 * ipv6cp_lowerdown - The lower layer is down. 00487 */ 00488 static void ipv6cp_lowerdown(ppp_pcb *pcb) { 00489 fsm_lowerdown(&pcb->ipv6cp_fsm); 00490 } 00491 00492 00493 /* 00494 * ipv6cp_input - Input IPV6CP packet. 00495 */ 00496 static void ipv6cp_input(ppp_pcb *pcb, u_char *p, int len) { 00497 fsm_input(&pcb->ipv6cp_fsm, p, len); 00498 } 00499 00500 00501 /* 00502 * ipv6cp_protrej - A Protocol-Reject was received for IPV6CP. 00503 * 00504 * Pretend the lower layer went down, so we shut up. 00505 */ 00506 static void ipv6cp_protrej(ppp_pcb *pcb) { 00507 fsm_lowerdown(&pcb->ipv6cp_fsm); 00508 } 00509 00510 00511 /* 00512 * ipv6cp_resetci - Reset our CI. 00513 */ 00514 static void ipv6cp_resetci(fsm *f) { 00515 ppp_pcb *pcb = f->pcb; 00516 ipv6cp_options *wo = &pcb->ipv6cp_wantoptions; 00517 ipv6cp_options *go = &pcb->ipv6cp_gotoptions; 00518 ipv6cp_options *ao = &pcb->ipv6cp_allowoptions; 00519 00520 wo->req_ifaceid = wo->neg_ifaceid && ao->neg_ifaceid; 00521 00522 if (!wo->opt_local) { 00523 eui64_magic_nz(wo->ourid); 00524 } 00525 00526 *go = *wo; 00527 eui64_zero(go->hisid); /* last proposed interface identifier */ 00528 } 00529 00530 00531 /* 00532 * ipv6cp_cilen - Return length of our CI. 00533 */ 00534 static int ipv6cp_cilen(fsm *f) { 00535 ppp_pcb *pcb = f->pcb; 00536 ipv6cp_options *go = &pcb->ipv6cp_gotoptions; 00537 00538 #ifdef IPV6CP_COMP 00539 #define LENCIVJ(neg) (neg ? CILEN_COMPRESS : 0) 00540 #endif /* IPV6CP_COMP */ 00541 #define LENCIIFACEID(neg) (neg ? CILEN_IFACEID : 0) 00542 00543 return (LENCIIFACEID(go->neg_ifaceid) + 00544 #ifdef IPV6CP_COMP 00545 LENCIVJ(go->neg_vj) + 00546 #endif /* IPV6CP_COMP */ 00547 0); 00548 } 00549 00550 00551 /* 00552 * ipv6cp_addci - Add our desired CIs to a packet. 00553 */ 00554 static void ipv6cp_addci(fsm *f, u_char *ucp, int *lenp) { 00555 ppp_pcb *pcb = f->pcb; 00556 ipv6cp_options *go = &pcb->ipv6cp_gotoptions; 00557 int len = *lenp; 00558 00559 #ifdef IPV6CP_COMP 00560 #define ADDCIVJ(opt, neg, val) \ 00561 if (neg) { \ 00562 int vjlen = CILEN_COMPRESS; \ 00563 if (len >= vjlen) { \ 00564 PUTCHAR(opt, ucp); \ 00565 PUTCHAR(vjlen, ucp); \ 00566 PUTSHORT(val, ucp); \ 00567 len -= vjlen; \ 00568 } else \ 00569 neg = 0; \ 00570 } 00571 #endif /* IPV6CP_COMP */ 00572 00573 #define ADDCIIFACEID(opt, neg, val1) \ 00574 if (neg) { \ 00575 int idlen = CILEN_IFACEID; \ 00576 if (len >= idlen) { \ 00577 PUTCHAR(opt, ucp); \ 00578 PUTCHAR(idlen, ucp); \ 00579 eui64_put(val1, ucp); \ 00580 len -= idlen; \ 00581 } else \ 00582 neg = 0; \ 00583 } 00584 00585 ADDCIIFACEID(CI_IFACEID, go->neg_ifaceid, go->ourid); 00586 00587 #ifdef IPV6CP_COMP 00588 ADDCIVJ(CI_COMPRESSTYPE, go->neg_vj, go->vj_protocol); 00589 #endif /* IPV6CP_COMP */ 00590 00591 *lenp -= len; 00592 } 00593 00594 00595 /* 00596 * ipv6cp_ackci - Ack our CIs. 00597 * 00598 * Returns: 00599 * 0 - Ack was bad. 00600 * 1 - Ack was good. 00601 */ 00602 static int ipv6cp_ackci(fsm *f, u_char *p, int len) { 00603 ppp_pcb *pcb = f->pcb; 00604 ipv6cp_options *go = &pcb->ipv6cp_gotoptions; 00605 u_short cilen, citype; 00606 #ifdef IPV6CP_COMP 00607 u_short cishort; 00608 #endif /* IPV6CP_COMP */ 00609 eui64_t ifaceid; 00610 00611 /* 00612 * CIs must be in exactly the same order that we sent... 00613 * Check packet length and CI length at each step. 00614 * If we find any deviations, then this packet is bad. 00615 */ 00616 00617 #ifdef IPV6CP_COMP 00618 #define ACKCIVJ(opt, neg, val) \ 00619 if (neg) { \ 00620 int vjlen = CILEN_COMPRESS; \ 00621 if ((len -= vjlen) < 0) \ 00622 goto bad; \ 00623 GETCHAR(citype, p); \ 00624 GETCHAR(cilen, p); \ 00625 if (cilen != vjlen || \ 00626 citype != opt) \ 00627 goto bad; \ 00628 GETSHORT(cishort, p); \ 00629 if (cishort != val) \ 00630 goto bad; \ 00631 } 00632 #endif /* IPV6CP_COMP */ 00633 00634 #define ACKCIIFACEID(opt, neg, val1) \ 00635 if (neg) { \ 00636 int idlen = CILEN_IFACEID; \ 00637 if ((len -= idlen) < 0) \ 00638 goto bad; \ 00639 GETCHAR(citype, p); \ 00640 GETCHAR(cilen, p); \ 00641 if (cilen != idlen || \ 00642 citype != opt) \ 00643 goto bad; \ 00644 eui64_get(ifaceid, p); \ 00645 if (! eui64_equals(val1, ifaceid)) \ 00646 goto bad; \ 00647 } 00648 00649 ACKCIIFACEID(CI_IFACEID, go->neg_ifaceid, go->ourid); 00650 00651 #ifdef IPV6CP_COMP 00652 ACKCIVJ(CI_COMPRESSTYPE, go->neg_vj, go->vj_protocol); 00653 #endif /* IPV6CP_COMP */ 00654 00655 /* 00656 * If there are any remaining CIs, then this packet is bad. 00657 */ 00658 if (len != 0) 00659 goto bad; 00660 return (1); 00661 00662 bad: 00663 IPV6CPDEBUG(("ipv6cp_ackci: received bad Ack!")); 00664 return (0); 00665 } 00666 00667 /* 00668 * ipv6cp_nakci - Peer has sent a NAK for some of our CIs. 00669 * This should not modify any state if the Nak is bad 00670 * or if IPV6CP is in the OPENED state. 00671 * 00672 * Returns: 00673 * 0 - Nak was bad. 00674 * 1 - Nak was good. 00675 */ 00676 static int ipv6cp_nakci(fsm *f, u_char *p, int len, int treat_as_reject) { 00677 ppp_pcb *pcb = f->pcb; 00678 ipv6cp_options *go = &pcb->ipv6cp_gotoptions; 00679 u_char citype, cilen, *next; 00680 #ifdef IPV6CP_COMP 00681 u_short cishort; 00682 #endif /* IPV6CP_COMP */ 00683 eui64_t ifaceid; 00684 ipv6cp_options no; /* options we've seen Naks for */ 00685 ipv6cp_options try_; /* options to request next time */ 00686 00687 BZERO(&no, sizeof(no)); 00688 try_ = *go; 00689 00690 /* 00691 * Any Nak'd CIs must be in exactly the same order that we sent. 00692 * Check packet length and CI length at each step. 00693 * If we find any deviations, then this packet is bad. 00694 */ 00695 #define NAKCIIFACEID(opt, neg, code) \ 00696 if (go->neg && \ 00697 len >= (cilen = CILEN_IFACEID) && \ 00698 p[1] == cilen && \ 00699 p[0] == opt) { \ 00700 len -= cilen; \ 00701 INCPTR(2, p); \ 00702 eui64_get(ifaceid, p); \ 00703 no.neg = 1; \ 00704 code \ 00705 } 00706 00707 #ifdef IPV6CP_COMP 00708 #define NAKCIVJ(opt, neg, code) \ 00709 if (go->neg && \ 00710 ((cilen = p[1]) == CILEN_COMPRESS) && \ 00711 len >= cilen && \ 00712 p[0] == opt) { \ 00713 len -= cilen; \ 00714 INCPTR(2, p); \ 00715 GETSHORT(cishort, p); \ 00716 no.neg = 1; \ 00717 code \ 00718 } 00719 #endif /* IPV6CP_COMP */ 00720 00721 /* 00722 * Accept the peer's idea of {our,his} interface identifier, if different 00723 * from our idea, only if the accept_{local,remote} flag is set. 00724 */ 00725 NAKCIIFACEID(CI_IFACEID, neg_ifaceid, 00726 if (treat_as_reject) { 00727 try_.neg_ifaceid = 0; 00728 } else if (go->accept_local) { 00729 while (eui64_iszero(ifaceid) || 00730 eui64_equals(ifaceid, go->hisid)) /* bad luck */ 00731 eui64_magic(ifaceid); 00732 try_.ourid = ifaceid; 00733 IPV6CPDEBUG(("local LL address %s", llv6_ntoa(ifaceid))); 00734 } 00735 ); 00736 00737 #ifdef IPV6CP_COMP 00738 NAKCIVJ(CI_COMPRESSTYPE, neg_vj, 00739 { 00740 if (cishort == IPV6CP_COMP && !treat_as_reject) { 00741 try_.vj_protocol = cishort; 00742 } else { 00743 try_.neg_vj = 0; 00744 } 00745 } 00746 ); 00747 #endif /* IPV6CP_COMP */ 00748 00749 /* 00750 * There may be remaining CIs, if the peer is requesting negotiation 00751 * on an option that we didn't include in our request packet. 00752 * If they want to negotiate about interface identifier, we comply. 00753 * If they want us to ask for compression, we refuse. 00754 */ 00755 while (len >= CILEN_VOID) { 00756 GETCHAR(citype, p); 00757 GETCHAR(cilen, p); 00758 if ( cilen < CILEN_VOID || (len -= cilen) < 0 ) 00759 goto bad; 00760 next = p + cilen - 2; 00761 00762 switch (citype) { 00763 #ifdef IPV6CP_COMP 00764 case CI_COMPRESSTYPE: 00765 if (go->neg_vj || no.neg_vj || 00766 (cilen != CILEN_COMPRESS)) 00767 goto bad; 00768 no.neg_vj = 1; 00769 break; 00770 #endif /* IPV6CP_COMP */ 00771 case CI_IFACEID: 00772 if (go->neg_ifaceid || no.neg_ifaceid || cilen != CILEN_IFACEID) 00773 goto bad; 00774 try_.neg_ifaceid = 1; 00775 eui64_get(ifaceid, p); 00776 if (go->accept_local) { 00777 while (eui64_iszero(ifaceid) || 00778 eui64_equals(ifaceid, go->hisid)) /* bad luck */ 00779 eui64_magic(ifaceid); 00780 try_.ourid = ifaceid; 00781 } 00782 no.neg_ifaceid = 1; 00783 break; 00784 default: 00785 break; 00786 } 00787 p = next; 00788 } 00789 00790 /* If there is still anything left, this packet is bad. */ 00791 if (len != 0) 00792 goto bad; 00793 00794 /* 00795 * OK, the Nak is good. Now we can update state. 00796 */ 00797 if (f->state != PPP_FSM_OPENED) 00798 *go = try_; 00799 00800 return 1; 00801 00802 bad: 00803 IPV6CPDEBUG(("ipv6cp_nakci: received bad Nak!")); 00804 return 0; 00805 } 00806 00807 00808 /* 00809 * ipv6cp_rejci - Reject some of our CIs. 00810 */ 00811 static int ipv6cp_rejci(fsm *f, u_char *p, int len) { 00812 ppp_pcb *pcb = f->pcb; 00813 ipv6cp_options *go = &pcb->ipv6cp_gotoptions; 00814 u_char cilen; 00815 #ifdef IPV6CP_COMP 00816 u_short cishort; 00817 #endif /* IPV6CP_COMP */ 00818 eui64_t ifaceid; 00819 ipv6cp_options try_; /* options to request next time */ 00820 00821 try_ = *go; 00822 /* 00823 * Any Rejected CIs must be in exactly the same order that we sent. 00824 * Check packet length and CI length at each step. 00825 * If we find any deviations, then this packet is bad. 00826 */ 00827 #define REJCIIFACEID(opt, neg, val1) \ 00828 if (go->neg && \ 00829 len >= (cilen = CILEN_IFACEID) && \ 00830 p[1] == cilen && \ 00831 p[0] == opt) { \ 00832 len -= cilen; \ 00833 INCPTR(2, p); \ 00834 eui64_get(ifaceid, p); \ 00835 /* Check rejected value. */ \ 00836 if (! eui64_equals(ifaceid, val1)) \ 00837 goto bad; \ 00838 try_.neg = 0; \ 00839 } 00840 00841 #ifdef IPV6CP_COMP 00842 #define REJCIVJ(opt, neg, val) \ 00843 if (go->neg && \ 00844 p[1] == CILEN_COMPRESS && \ 00845 len >= p[1] && \ 00846 p[0] == opt) { \ 00847 len -= p[1]; \ 00848 INCPTR(2, p); \ 00849 GETSHORT(cishort, p); \ 00850 /* Check rejected value. */ \ 00851 if (cishort != val) \ 00852 goto bad; \ 00853 try_.neg = 0; \ 00854 } 00855 #endif /* IPV6CP_COMP */ 00856 00857 REJCIIFACEID(CI_IFACEID, neg_ifaceid, go->ourid); 00858 00859 #ifdef IPV6CP_COMP 00860 REJCIVJ(CI_COMPRESSTYPE, neg_vj, go->vj_protocol); 00861 #endif /* IPV6CP_COMP */ 00862 00863 /* 00864 * If there are any remaining CIs, then this packet is bad. 00865 */ 00866 if (len != 0) 00867 goto bad; 00868 /* 00869 * Now we can update state. 00870 */ 00871 if (f->state != PPP_FSM_OPENED) 00872 *go = try_; 00873 return 1; 00874 00875 bad: 00876 IPV6CPDEBUG(("ipv6cp_rejci: received bad Reject!")); 00877 return 0; 00878 } 00879 00880 00881 /* 00882 * ipv6cp_reqci - Check the peer's requested CIs and send appropriate response. 00883 * 00884 * Returns: CONFACK, CONFNAK or CONFREJ and input packet modified 00885 * appropriately. If reject_if_disagree is non-zero, doesn't return 00886 * CONFNAK; returns CONFREJ if it can't return CONFACK. 00887 * 00888 * inp = Requested CIs 00889 * len = Length of requested CIs 00890 * 00891 */ 00892 static int ipv6cp_reqci(fsm *f, u_char *inp, int *len, int reject_if_disagree) { 00893 ppp_pcb *pcb = f->pcb; 00894 ipv6cp_options *wo = &pcb->ipv6cp_wantoptions; 00895 ipv6cp_options *ho = &pcb->ipv6cp_hisoptions; 00896 ipv6cp_options *ao = &pcb->ipv6cp_allowoptions; 00897 ipv6cp_options *go = &pcb->ipv6cp_gotoptions; 00898 u_char *cip, *next; /* Pointer to current and next CIs */ 00899 u_short cilen, citype; /* Parsed len, type */ 00900 #ifdef IPV6CP_COMP 00901 u_short cishort; /* Parsed short value */ 00902 #endif /* IPV6CP_COMP */ 00903 eui64_t ifaceid; /* Parsed interface identifier */ 00904 int rc = CONFACK; /* Final packet return code */ 00905 int orc; /* Individual option return code */ 00906 u_char *p; /* Pointer to next char to parse */ 00907 u_char *ucp = inp; /* Pointer to current output char */ 00908 int l = *len; /* Length left */ 00909 00910 /* 00911 * Reset all his options. 00912 */ 00913 BZERO(ho, sizeof(*ho)); 00914 00915 /* 00916 * Process all his options. 00917 */ 00918 next = inp; 00919 while (l) { 00920 orc = CONFACK; /* Assume success */ 00921 cip = p = next; /* Remember begining of CI */ 00922 if (l < 2 || /* Not enough data for CI header or */ 00923 p[1] < 2 || /* CI length too small or */ 00924 p[1] > l) { /* CI length too big? */ 00925 IPV6CPDEBUG(("ipv6cp_reqci: bad CI length!")); 00926 orc = CONFREJ; /* Reject bad CI */ 00927 cilen = l; /* Reject till end of packet */ 00928 l = 0; /* Don't loop again */ 00929 goto endswitch; 00930 } 00931 GETCHAR(citype, p); /* Parse CI type */ 00932 GETCHAR(cilen, p); /* Parse CI length */ 00933 l -= cilen; /* Adjust remaining length */ 00934 next += cilen; /* Step to next CI */ 00935 00936 switch (citype) { /* Check CI type */ 00937 case CI_IFACEID: 00938 IPV6CPDEBUG(("ipv6cp: received interface identifier ")); 00939 00940 if (!ao->neg_ifaceid || 00941 cilen != CILEN_IFACEID) { /* Check CI length */ 00942 orc = CONFREJ; /* Reject CI */ 00943 break; 00944 } 00945 00946 /* 00947 * If he has no interface identifier, or if we both have same 00948 * identifier then NAK it with new idea. 00949 * In particular, if we don't know his identifier, but he does, 00950 * then accept it. 00951 */ 00952 eui64_get(ifaceid, p); 00953 IPV6CPDEBUG(("(%s)", llv6_ntoa(ifaceid))); 00954 if (eui64_iszero(ifaceid) && eui64_iszero(go->ourid)) { 00955 orc = CONFREJ; /* Reject CI */ 00956 break; 00957 } 00958 if (!eui64_iszero(wo->hisid) && 00959 !eui64_equals(ifaceid, wo->hisid) && 00960 eui64_iszero(go->hisid)) { 00961 00962 orc = CONFNAK; 00963 ifaceid = wo->hisid; 00964 go->hisid = ifaceid; 00965 DECPTR(sizeof(ifaceid), p); 00966 eui64_put(ifaceid, p); 00967 } else 00968 if (eui64_iszero(ifaceid) || eui64_equals(ifaceid, go->ourid)) { 00969 orc = CONFNAK; 00970 if (eui64_iszero(go->hisid)) /* first time, try option */ 00971 ifaceid = wo->hisid; 00972 while (eui64_iszero(ifaceid) || 00973 eui64_equals(ifaceid, go->ourid)) /* bad luck */ 00974 eui64_magic(ifaceid); 00975 go->hisid = ifaceid; 00976 DECPTR(sizeof(ifaceid), p); 00977 eui64_put(ifaceid, p); 00978 } 00979 00980 ho->neg_ifaceid = 1; 00981 ho->hisid = ifaceid; 00982 break; 00983 00984 #ifdef IPV6CP_COMP 00985 case CI_COMPRESSTYPE: 00986 IPV6CPDEBUG(("ipv6cp: received COMPRESSTYPE ")); 00987 if (!ao->neg_vj || 00988 (cilen != CILEN_COMPRESS)) { 00989 orc = CONFREJ; 00990 break; 00991 } 00992 GETSHORT(cishort, p); 00993 IPV6CPDEBUG(("(%d)", cishort)); 00994 00995 if (!(cishort == IPV6CP_COMP)) { 00996 orc = CONFREJ; 00997 break; 00998 } 00999 01000 ho->neg_vj = 1; 01001 ho->vj_protocol = cishort; 01002 break; 01003 #endif /* IPV6CP_COMP */ 01004 01005 default: 01006 orc = CONFREJ; 01007 break; 01008 } 01009 01010 endswitch: 01011 IPV6CPDEBUG((" (%s)\n", CODENAME(orc))); 01012 01013 if (orc == CONFACK && /* Good CI */ 01014 rc != CONFACK) /* but prior CI wasnt? */ 01015 continue; /* Don't send this one */ 01016 01017 if (orc == CONFNAK) { /* Nak this CI? */ 01018 if (reject_if_disagree) /* Getting fed up with sending NAKs? */ 01019 orc = CONFREJ; /* Get tough if so */ 01020 else { 01021 if (rc == CONFREJ) /* Rejecting prior CI? */ 01022 continue; /* Don't send this one */ 01023 if (rc == CONFACK) { /* Ack'd all prior CIs? */ 01024 rc = CONFNAK; /* Not anymore... */ 01025 ucp = inp; /* Backup */ 01026 } 01027 } 01028 } 01029 01030 if (orc == CONFREJ && /* Reject this CI */ 01031 rc != CONFREJ) { /* but no prior ones? */ 01032 rc = CONFREJ; 01033 ucp = inp; /* Backup */ 01034 } 01035 01036 /* Need to move CI? */ 01037 if (ucp != cip) 01038 MEMCPY(ucp, cip, cilen); /* Move it */ 01039 01040 /* Update output pointer */ 01041 INCPTR(cilen, ucp); 01042 } 01043 01044 /* 01045 * If we aren't rejecting this packet, and we want to negotiate 01046 * their identifier and they didn't send their identifier, then we 01047 * send a NAK with a CI_IFACEID option appended. We assume the 01048 * input buffer is long enough that we can append the extra 01049 * option safely. 01050 */ 01051 if (rc != CONFREJ && !ho->neg_ifaceid && 01052 wo->req_ifaceid && !reject_if_disagree) { 01053 if (rc == CONFACK) { 01054 rc = CONFNAK; 01055 ucp = inp; /* reset pointer */ 01056 wo->req_ifaceid = 0; /* don't ask again */ 01057 } 01058 PUTCHAR(CI_IFACEID, ucp); 01059 PUTCHAR(CILEN_IFACEID, ucp); 01060 eui64_put(wo->hisid, ucp); 01061 } 01062 01063 *len = ucp - inp; /* Compute output length */ 01064 IPV6CPDEBUG(("ipv6cp: returning Configure-%s", CODENAME(rc))); 01065 return (rc); /* Return final code */ 01066 } 01067 01068 #if PPP_OPTIONS 01069 /* 01070 * ipv6_check_options - check that any IP-related options are OK, 01071 * and assign appropriate defaults. 01072 */ 01073 static void ipv6_check_options() { 01074 ipv6cp_options *wo = &ipv6cp_wantoptions[0]; 01075 01076 if (!ipv6cp_protent.enabled_flag) 01077 return; 01078 01079 /* 01080 * Persistent link-local id is only used when user has not explicitly 01081 * configure/hard-code the id 01082 */ 01083 if ((wo->use_persistent) && (!wo->opt_local) && (!wo->opt_remote)) { 01084 01085 /* 01086 * On systems where there are no Ethernet interfaces used, there 01087 * may be other ways to obtain a persistent id. Right now, it 01088 * will fall back to using magic [see eui64_magic] below when 01089 * an EUI-48 from MAC address can't be obtained. Other possibilities 01090 * include obtaining EEPROM serial numbers, or some other unique 01091 * yet persistent number. On Sparc platforms, this is possible, 01092 * but too bad there's no standards yet for x86 machines. 01093 */ 01094 if (ether_to_eui64(&wo->ourid)) { 01095 wo->opt_local = 1; 01096 } 01097 } 01098 01099 if (!wo->opt_local) { /* init interface identifier */ 01100 if (wo->use_ip && eui64_iszero(wo->ourid)) { 01101 eui64_setlo32(wo->ourid, lwip_ntohl(ipcp_wantoptions[0].ouraddr)); 01102 if (!eui64_iszero(wo->ourid)) 01103 wo->opt_local = 1; 01104 } 01105 01106 while (eui64_iszero(wo->ourid)) 01107 eui64_magic(wo->ourid); 01108 } 01109 01110 if (!wo->opt_remote) { 01111 if (wo->use_ip && eui64_iszero(wo->hisid)) { 01112 eui64_setlo32(wo->hisid, lwip_ntohl(ipcp_wantoptions[0].hisaddr)); 01113 if (!eui64_iszero(wo->hisid)) 01114 wo->opt_remote = 1; 01115 } 01116 } 01117 01118 if (demand && (eui64_iszero(wo->ourid) || eui64_iszero(wo->hisid))) { 01119 option_error("local/remote LL address required for demand-dialling\n"); 01120 exit(1); 01121 } 01122 } 01123 #endif /* PPP_OPTIONS */ 01124 01125 #if DEMAND_SUPPORT 01126 /* 01127 * ipv6_demand_conf - configure the interface as though 01128 * IPV6CP were up, for use with dial-on-demand. 01129 */ 01130 static int ipv6_demand_conf(int u) { 01131 ipv6cp_options *wo = &ipv6cp_wantoptions[u]; 01132 01133 if (!sif6up(u)) 01134 return 0; 01135 01136 if (!sif6addr(u, wo->ourid, wo->hisid)) 01137 return 0; 01138 01139 if (!sifnpmode(u, PPP_IPV6, NPMODE_QUEUE)) 01140 return 0; 01141 01142 ppp_notice("ipv6_demand_conf"); 01143 ppp_notice("local LL address %s", llv6_ntoa(wo->ourid)); 01144 ppp_notice("remote LL address %s", llv6_ntoa(wo->hisid)); 01145 01146 return 1; 01147 } 01148 #endif /* DEMAND_SUPPORT */ 01149 01150 01151 /* 01152 * ipv6cp_up - IPV6CP has come UP. 01153 * 01154 * Configure the IPv6 network interface appropriately and bring it up. 01155 */ 01156 static void ipv6cp_up(fsm *f) { 01157 ppp_pcb *pcb = f->pcb; 01158 ipv6cp_options *wo = &pcb->ipv6cp_wantoptions; 01159 ipv6cp_options *ho = &pcb->ipv6cp_hisoptions; 01160 ipv6cp_options *go = &pcb->ipv6cp_gotoptions; 01161 01162 IPV6CPDEBUG(("ipv6cp: up")); 01163 01164 /* 01165 * We must have a non-zero LL address for both ends of the link. 01166 */ 01167 if (!ho->neg_ifaceid) 01168 ho->hisid = wo->hisid; 01169 01170 #if 0 /* UNUSED */ 01171 if(!no_ifaceid_neg) { 01172 #endif /* UNUSED */ 01173 if (eui64_iszero(ho->hisid)) { 01174 ppp_error("Could not determine remote LL address"); 01175 ipv6cp_close(f->pcb, "Could not determine remote LL address"); 01176 return; 01177 } 01178 if (eui64_iszero(go->ourid)) { 01179 ppp_error("Could not determine local LL address"); 01180 ipv6cp_close(f->pcb, "Could not determine local LL address"); 01181 return; 01182 } 01183 if (eui64_equals(go->ourid, ho->hisid)) { 01184 ppp_error("local and remote LL addresses are equal"); 01185 ipv6cp_close(f->pcb, "local and remote LL addresses are equal"); 01186 return; 01187 } 01188 #if 0 /* UNUSED */ 01189 } 01190 #endif /* UNUSED */ 01191 #if 0 /* UNUSED */ 01192 script_setenv("LLLOCAL", llv6_ntoa(go->ourid), 0); 01193 script_setenv("LLREMOTE", llv6_ntoa(ho->hisid), 0); 01194 #endif /* UNUSED */ 01195 01196 #ifdef IPV6CP_COMP 01197 /* set tcp compression */ 01198 sif6comp(f->unit, ho->neg_vj); 01199 #endif 01200 01201 #if DEMAND_SUPPORT 01202 /* 01203 * If we are doing dial-on-demand, the interface is already 01204 * configured, so we put out any saved-up packets, then set the 01205 * interface to pass IPv6 packets. 01206 */ 01207 if (demand) { 01208 if (! eui64_equals(go->ourid, wo->ourid) || 01209 ! eui64_equals(ho->hisid, wo->hisid)) { 01210 if (! eui64_equals(go->ourid, wo->ourid)) 01211 warn("Local LL address changed to %s", 01212 llv6_ntoa(go->ourid)); 01213 if (! eui64_equals(ho->hisid, wo->hisid)) 01214 warn("Remote LL address changed to %s", 01215 llv6_ntoa(ho->hisid)); 01216 ipv6cp_clear_addrs(f->pcb, go->ourid, ho->hisid); 01217 01218 /* Set the interface to the new addresses */ 01219 if (!sif6addr(f->pcb, go->ourid, ho->hisid)) { 01220 if (debug) 01221 warn("sif6addr failed"); 01222 ipv6cp_close(f->unit, "Interface configuration failed"); 01223 return; 01224 } 01225 01226 } 01227 demand_rexmit(PPP_IPV6); 01228 sifnpmode(f->unit, PPP_IPV6, NPMODE_PASS); 01229 01230 } else 01231 #endif /* DEMAND_SUPPORT */ 01232 { 01233 /* 01234 * Set LL addresses 01235 */ 01236 if (!sif6addr(f->pcb, go->ourid, ho->hisid)) { 01237 PPPDEBUG(LOG_DEBUG, ("sif6addr failed")); 01238 ipv6cp_close(f->pcb, "Interface configuration failed"); 01239 return; 01240 } 01241 01242 /* bring the interface up for IPv6 */ 01243 if (!sif6up(f->pcb)) { 01244 PPPDEBUG(LOG_DEBUG, ("sif6up failed (IPV6)")); 01245 ipv6cp_close(f->pcb, "Interface configuration failed"); 01246 return; 01247 } 01248 #if DEMAND_SUPPORT 01249 sifnpmode(f->pcb, PPP_IPV6, NPMODE_PASS); 01250 #endif /* DEMAND_SUPPORT */ 01251 01252 ppp_notice("local LL address %s", llv6_ntoa(go->ourid)); 01253 ppp_notice("remote LL address %s", llv6_ntoa(ho->hisid)); 01254 } 01255 01256 np_up(f->pcb, PPP_IPV6); 01257 pcb->ipv6cp_is_up = 1; 01258 01259 #if 0 /* UNUSED */ 01260 /* 01261 * Execute the ipv6-up script, like this: 01262 * /etc/ppp/ipv6-up interface tty speed local-LL remote-LL 01263 */ 01264 if (ipv6cp_script_state == s_down && ipv6cp_script_pid == 0) { 01265 ipv6cp_script_state = s_up; 01266 ipv6cp_script(_PATH_IPV6UP); 01267 } 01268 #endif /* UNUSED */ 01269 } 01270 01271 01272 /* 01273 * ipv6cp_down - IPV6CP has gone DOWN. 01274 * 01275 * Take the IPv6 network interface down, clear its addresses 01276 * and delete routes through it. 01277 */ 01278 static void ipv6cp_down(fsm *f) { 01279 ppp_pcb *pcb = f->pcb; 01280 ipv6cp_options *go = &pcb->ipv6cp_gotoptions; 01281 ipv6cp_options *ho = &pcb->ipv6cp_hisoptions; 01282 01283 IPV6CPDEBUG(("ipv6cp: down")); 01284 #if PPP_STATS_SUPPORT 01285 update_link_stats(f->unit); 01286 #endif /* PPP_STATS_SUPPORT */ 01287 if (pcb->ipv6cp_is_up) { 01288 pcb->ipv6cp_is_up = 0; 01289 np_down(f->pcb, PPP_IPV6); 01290 } 01291 #ifdef IPV6CP_COMP 01292 sif6comp(f->unit, 0); 01293 #endif 01294 01295 #if DEMAND_SUPPORT 01296 /* 01297 * If we are doing dial-on-demand, set the interface 01298 * to queue up outgoing packets (for now). 01299 */ 01300 if (demand) { 01301 sifnpmode(f->pcb, PPP_IPV6, NPMODE_QUEUE); 01302 } else 01303 #endif /* DEMAND_SUPPORT */ 01304 { 01305 #if DEMAND_SUPPORT 01306 sifnpmode(f->pcb, PPP_IPV6, NPMODE_DROP); 01307 #endif /* DEMAND_SUPPORT */ 01308 ipv6cp_clear_addrs(f->pcb, 01309 go->ourid, 01310 ho->hisid); 01311 sif6down(f->pcb); 01312 } 01313 01314 #if 0 /* UNUSED */ 01315 /* Execute the ipv6-down script */ 01316 if (ipv6cp_script_state == s_up && ipv6cp_script_pid == 0) { 01317 ipv6cp_script_state = s_down; 01318 ipv6cp_script(_PATH_IPV6DOWN); 01319 } 01320 #endif /* UNUSED */ 01321 } 01322 01323 01324 /* 01325 * ipv6cp_clear_addrs() - clear the interface addresses, routes, 01326 * proxy neighbour discovery entries, etc. 01327 */ 01328 static void ipv6cp_clear_addrs(ppp_pcb *pcb, eui64_t ourid, eui64_t hisid) { 01329 cif6addr(pcb, ourid, hisid); 01330 } 01331 01332 01333 /* 01334 * ipv6cp_finished - possibly shut down the lower layers. 01335 */ 01336 static void ipv6cp_finished(fsm *f) { 01337 np_finished(f->pcb, PPP_IPV6); 01338 } 01339 01340 01341 #if 0 /* UNUSED */ 01342 /* 01343 * ipv6cp_script_done - called when the ipv6-up or ipv6-down script 01344 * has finished. 01345 */ 01346 static void 01347 ipv6cp_script_done(arg) 01348 void *arg; 01349 { 01350 ipv6cp_script_pid = 0; 01351 switch (ipv6cp_script_state) { 01352 case s_up: 01353 if (ipv6cp_fsm[0].state != PPP_FSM_OPENED) { 01354 ipv6cp_script_state = s_down; 01355 ipv6cp_script(_PATH_IPV6DOWN); 01356 } 01357 break; 01358 case s_down: 01359 if (ipv6cp_fsm[0].state == PPP_FSM_OPENED) { 01360 ipv6cp_script_state = s_up; 01361 ipv6cp_script(_PATH_IPV6UP); 01362 } 01363 break; 01364 } 01365 } 01366 01367 01368 /* 01369 * ipv6cp_script - Execute a script with arguments 01370 * interface-name tty-name speed local-LL remote-LL. 01371 */ 01372 static void 01373 ipv6cp_script(script) 01374 char *script; 01375 { 01376 char strspeed[32], strlocal[32], strremote[32]; 01377 char *argv[8]; 01378 01379 sprintf(strspeed, "%d", baud_rate); 01380 strcpy(strlocal, llv6_ntoa(ipv6cp_gotoptions[0].ourid)); 01381 strcpy(strremote, llv6_ntoa(ipv6cp_hisoptions[0].hisid)); 01382 01383 argv[0] = script; 01384 argv[1] = ifname; 01385 argv[2] = devnam; 01386 argv[3] = strspeed; 01387 argv[4] = strlocal; 01388 argv[5] = strremote; 01389 argv[6] = ipparam; 01390 argv[7] = NULL; 01391 01392 ipv6cp_script_pid = run_program(script, argv, 0, ipv6cp_script_done, 01393 NULL, 0); 01394 } 01395 #endif /* UNUSED */ 01396 01397 #if PRINTPKT_SUPPORT 01398 /* 01399 * ipv6cp_printpkt - print the contents of an IPV6CP packet. 01400 */ 01401 static const char* const ipv6cp_codenames[] = { 01402 "ConfReq", "ConfAck", "ConfNak", "ConfRej", 01403 "TermReq", "TermAck", "CodeRej" 01404 }; 01405 01406 static int ipv6cp_printpkt(const u_char *p, int plen, 01407 void (*printer)(void *, const char *, ...), void *arg) { 01408 int code, id, len, olen; 01409 const u_char *pstart, *optend; 01410 #ifdef IPV6CP_COMP 01411 u_short cishort; 01412 #endif /* IPV6CP_COMP */ 01413 eui64_t ifaceid; 01414 01415 if (plen < HEADERLEN) 01416 return 0; 01417 pstart = p; 01418 GETCHAR(code, p); 01419 GETCHAR(id, p); 01420 GETSHORT(len, p); 01421 if (len < HEADERLEN || len > plen) 01422 return 0; 01423 01424 if (code >= 1 && code <= (int)LWIP_ARRAYSIZE(ipv6cp_codenames)) 01425 printer(arg, " %s", ipv6cp_codenames[code-1]); 01426 else 01427 printer(arg, " code=0x%x", code); 01428 printer(arg, " id=0x%x", id); 01429 len -= HEADERLEN; 01430 switch (code) { 01431 case CONFREQ: 01432 case CONFACK: 01433 case CONFNAK: 01434 case CONFREJ: 01435 /* print option list */ 01436 while (len >= 2) { 01437 GETCHAR(code, p); 01438 GETCHAR(olen, p); 01439 p -= 2; 01440 if (olen < 2 || olen > len) { 01441 break; 01442 } 01443 printer(arg, " <"); 01444 len -= olen; 01445 optend = p + olen; 01446 switch (code) { 01447 #ifdef IPV6CP_COMP 01448 case CI_COMPRESSTYPE: 01449 if (olen >= CILEN_COMPRESS) { 01450 p += 2; 01451 GETSHORT(cishort, p); 01452 printer(arg, "compress "); 01453 printer(arg, "0x%x", cishort); 01454 } 01455 break; 01456 #endif /* IPV6CP_COMP */ 01457 case CI_IFACEID: 01458 if (olen == CILEN_IFACEID) { 01459 p += 2; 01460 eui64_get(ifaceid, p); 01461 printer(arg, "addr %s", llv6_ntoa(ifaceid)); 01462 } 01463 break; 01464 default: 01465 break; 01466 } 01467 while (p < optend) { 01468 GETCHAR(code, p); 01469 printer(arg, " %.2x", code); 01470 } 01471 printer(arg, ">"); 01472 } 01473 break; 01474 01475 case TERMACK: 01476 case TERMREQ: 01477 if (len > 0 && *p >= ' ' && *p < 0x7f) { 01478 printer(arg, " "); 01479 ppp_print_string(p, len, printer, arg); 01480 p += len; 01481 len = 0; 01482 } 01483 break; 01484 default: 01485 break; 01486 } 01487 01488 /* print the rest of the bytes in the packet */ 01489 for (; len > 0; --len) { 01490 GETCHAR(code, p); 01491 printer(arg, " %.2x", code); 01492 } 01493 01494 return p - pstart; 01495 } 01496 #endif /* PRINTPKT_SUPPORT */ 01497 01498 #if DEMAND_SUPPORT 01499 /* 01500 * ipv6_active_pkt - see if this IP packet is worth bringing the link up for. 01501 * We don't bring the link up for IP fragments or for TCP FIN packets 01502 * with no data. 01503 */ 01504 #define IP6_HDRLEN 40 /* bytes */ 01505 #define IP6_NHDR_FRAG 44 /* fragment IPv6 header */ 01506 #define TCP_HDRLEN 20 01507 #define TH_FIN 0x01 01508 01509 /* 01510 * We use these macros because the IP header may be at an odd address, 01511 * and some compilers might use word loads to get th_off or ip_hl. 01512 */ 01513 01514 #define get_ip6nh(x) (((unsigned char *)(x))[6]) 01515 #define get_tcpoff(x) (((unsigned char *)(x))[12] >> 4) 01516 #define get_tcpflags(x) (((unsigned char *)(x))[13]) 01517 01518 static int ipv6_active_pkt(u_char *pkt, int len) { 01519 u_char *tcp; 01520 01521 len -= PPP_HDRLEN; 01522 pkt += PPP_HDRLEN; 01523 if (len < IP6_HDRLEN) 01524 return 0; 01525 if (get_ip6nh(pkt) == IP6_NHDR_FRAG) 01526 return 0; 01527 if (get_ip6nh(pkt) != IPPROTO_TCP) 01528 return 1; 01529 if (len < IP6_HDRLEN + TCP_HDRLEN) 01530 return 0; 01531 tcp = pkt + IP6_HDRLEN; 01532 if ((get_tcpflags(tcp) & TH_FIN) != 0 && len == IP6_HDRLEN + get_tcpoff(tcp) * 4) 01533 return 0; 01534 return 1; 01535 } 01536 #endif /* DEMAND_SUPPORT */ 01537 01538 #endif /* PPP_SUPPORT && PPP_IPV6_SUPPORT */
Generated on Sun Jul 17 2022 08:25:24 by 1.7.2