1 /* $NetBSD: ipv6cp.c,v 1.6 2025/01/08 19:59:39 christos Exp $ */ 2 3 /* 4 * ipv6cp.c - PPP IPV6 Control Protocol. 5 * 6 * Copyright (c) 1999 Tommi Komulainen. All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in 17 * the documentation and/or other materials provided with the 18 * distribution. 19 * 20 * 3. The name(s) of the authors of this software must not be used to 21 * endorse or promote products derived from this software without 22 * prior written permission. 23 * 24 * 4. Redistributions of any form whatsoever must retain the following 25 * acknowledgment: 26 * "This product includes software developed by Tommi Komulainen 27 * <Tommi.Komulainen@iki.fi>". 28 * 29 * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO 30 * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 31 * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY 32 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 33 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN 34 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 35 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 36 * 37 */ 38 39 /* Original version, based on RFC2023 : 40 41 Copyright (c) 1995, 1996, 1997 Francis.Dupont@inria.fr, INRIA Rocquencourt, 42 Alain.Durand@imag.fr, IMAG, 43 Jean-Luc.Richier@imag.fr, IMAG-LSR. 44 45 Copyright (c) 1998, 1999 Francis.Dupont@inria.fr, GIE DYADE, 46 Alain.Durand@imag.fr, IMAG, 47 Jean-Luc.Richier@imag.fr, IMAG-LSR. 48 49 Ce travail a �t� fait au sein du GIE DYADE (Groupement d'Int�r�t 50 �conomique ayant pour membres BULL S.A. et l'INRIA). 51 52 Ce logiciel informatique est disponible aux conditions 53 usuelles dans la recherche, c'est-�-dire qu'il peut 54 �tre utilis�, copi�, modifi�, distribu� � l'unique 55 condition que ce texte soit conserv� afin que 56 l'origine de ce logiciel soit reconnue. 57 58 Le nom de l'Institut National de Recherche en Informatique 59 et en Automatique (INRIA), de l'IMAG, ou d'une personne morale 60 ou physique ayant particip� � l'�laboration de ce logiciel ne peut 61 �tre utilis� sans son accord pr�alable explicite. 62 63 Ce logiciel est fourni tel quel sans aucune garantie, 64 support ou responsabilit� d'aucune sorte. 65 Ce logiciel est d�riv� de sources d'origine 66 "University of California at Berkeley" et 67 "Digital Equipment Corporation" couvertes par des copyrights. 68 69 L'Institut d'Informatique et de Math�matiques Appliqu�es de Grenoble (IMAG) 70 est une f�d�ration d'unit�s mixtes de recherche du CNRS, de l'Institut National 71 Polytechnique de Grenoble et de l'Universit� Joseph Fourier regroupant 72 sept laboratoires dont le laboratoire Logiciels, Syst�mes, R�seaux (LSR). 73 74 This work has been done in the context of GIE DYADE (joint R & D venture 75 between BULL S.A. and INRIA). 76 77 This software is available with usual "research" terms 78 with the aim of retain credits of the software. 79 Permission to use, copy, modify and distribute this software for any 80 purpose and without fee is hereby granted, provided that the above 81 copyright notice and this permission notice appear in all copies, 82 and the name of INRIA, IMAG, or any contributor not be used in advertising 83 or publicity pertaining to this material without the prior explicit 84 permission. The software is provided "as is" without any 85 warranties, support or liabilities of any kind. 86 This software is derived from source code from 87 "University of California at Berkeley" and 88 "Digital Equipment Corporation" protected by copyrights. 89 90 Grenoble's Institute of Computer Science and Applied Mathematics (IMAG) 91 is a federation of seven research units funded by the CNRS, National 92 Polytechnic Institute of Grenoble and University Joseph Fourier. 93 The research unit in Software, Systems, Networks (LSR) is member of IMAG. 94 */ 95 96 /* 97 * Derived from : 98 * 99 * 100 * ipcp.c - PPP IP Control Protocol. 101 * 102 * Copyright (c) 1984-2000 Carnegie Mellon University. All rights reserved. 103 * 104 * Redistribution and use in source and binary forms, with or without 105 * modification, are permitted provided that the following conditions 106 * are met: 107 * 108 * 1. Redistributions of source code must retain the above copyright 109 * notice, this list of conditions and the following disclaimer. 110 * 111 * 2. Redistributions in binary form must reproduce the above copyright 112 * notice, this list of conditions and the following disclaimer in 113 * the documentation and/or other materials provided with the 114 * distribution. 115 * 116 * 3. The name "Carnegie Mellon University" must not be used to 117 * endorse or promote products derived from this software without 118 * prior written permission. For permission or any legal 119 * details, please contact 120 * Office of Technology Transfer 121 * Carnegie Mellon University 122 * 5000 Forbes Avenue 123 * Pittsburgh, PA 15213-3890 124 * (412) 268-4387, fax: (412) 268-7395 125 * tech-transfer@andrew.cmu.edu 126 * 127 * 4. Redistributions of any form whatsoever must retain the following 128 * acknowledgment: 129 * "This product includes software developed by Computing Services 130 * at Carnegie Mellon University (http://www.cmu.edu/computing/)." 131 * 132 * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO 133 * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 134 * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE 135 * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 136 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN 137 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 138 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 139 */ 140 141 #include <sys/cdefs.h> 142 __RCSID("$NetBSD: ipv6cp.c,v 1.6 2025/01/08 19:59:39 christos Exp $"); 143 144 /* 145 * TODO: 146 * 147 * Proxy Neighbour Discovery. 148 * 149 * Better defines for selecting the ordering of 150 * interface up / set address. (currently checks for __linux__, 151 * since SVR4 && (SNI || __USLC__) didn't work properly) 152 */ 153 154 #ifdef HAVE_CONFIG_H 155 #include "config.h" 156 #endif 157 158 #include <stdio.h> 159 #include <stdlib.h> 160 #include <string.h> 161 #include <errno.h> 162 #include <unistd.h> 163 #include <netdb.h> 164 #include <sys/param.h> 165 #include <sys/types.h> 166 #include <sys/socket.h> 167 #include <netinet/in.h> 168 #include <arpa/inet.h> 169 170 #include "pppd-private.h" 171 #include "options.h" 172 #include "fsm.h" 173 #include "eui64.h" 174 #include "ipcp.h" 175 #include "ipv6cp.h" 176 #include "magic.h" 177 #include "pathnames.h" 178 179 #define s6_addr32 __u6_addr.__u6_addr32 /* Non-standard */ 180 181 /* global vars */ 182 ipv6cp_options ipv6cp_wantoptions[NUM_PPP]; /* Options that we want to request */ 183 ipv6cp_options ipv6cp_gotoptions[NUM_PPP]; /* Options that peer ack'd */ 184 ipv6cp_options ipv6cp_allowoptions[NUM_PPP]; /* Options we allow peer to request */ 185 ipv6cp_options ipv6cp_hisoptions[NUM_PPP]; /* Options that we ack'd */ 186 int no_ifaceid_neg = 0; 187 188 /* local vars */ 189 static int default_route_set[NUM_PPP]; /* Have set up a default route */ 190 static int ipv6cp_is_up; 191 static bool ipv6cp_noremote; 192 193 ipv6_up_hook_fn *ipv6_up_hook = NULL; 194 ipv6_down_hook_fn *ipv6_down_hook = NULL; 195 196 /* Notifiers for when IPCPv6 goes up and down */ 197 struct notifier *ipv6_up_notifier = NULL; 198 struct notifier *ipv6_down_notifier = NULL; 199 200 /* 201 * Callbacks for fsm code. (CI = Configuration Information) 202 */ 203 static void ipv6cp_resetci (fsm *); /* Reset our CI */ 204 static int ipv6cp_cilen (fsm *); /* Return length of our CI */ 205 static void ipv6cp_addci (fsm *, u_char *, int *); /* Add our CI */ 206 static int ipv6cp_ackci (fsm *, u_char *, int); /* Peer ack'd our CI */ 207 static int ipv6cp_nakci (fsm *, u_char *, int, int);/* Peer nak'd our CI */ 208 static int ipv6cp_rejci (fsm *, u_char *, int); /* Peer rej'd our CI */ 209 static int ipv6cp_reqci (fsm *, u_char *, int *, int); /* Rcv CI */ 210 static void ipv6cp_up (fsm *); /* We're UP */ 211 static void ipv6cp_down (fsm *); /* We're DOWN */ 212 static void ipv6cp_finished (fsm *); /* Don't need lower layer */ 213 214 fsm ipv6cp_fsm[NUM_PPP]; /* IPV6CP fsm structure */ 215 216 static fsm_callbacks ipv6cp_callbacks = { /* IPV6CP callback routines */ 217 ipv6cp_resetci, /* Reset our Configuration Information */ 218 ipv6cp_cilen, /* Length of our Configuration Information */ 219 ipv6cp_addci, /* Add our Configuration Information */ 220 ipv6cp_ackci, /* ACK our Configuration Information */ 221 ipv6cp_nakci, /* NAK our Configuration Information */ 222 ipv6cp_rejci, /* Reject our Configuration Information */ 223 ipv6cp_reqci, /* Request peer's Configuration Information */ 224 ipv6cp_up, /* Called when fsm reaches OPENED state */ 225 ipv6cp_down, /* Called when fsm leaves OPENED state */ 226 NULL, /* Called when we want the lower layer up */ 227 ipv6cp_finished, /* Called when we want the lower layer down */ 228 NULL, /* Called when Protocol-Reject received */ 229 NULL, /* Retransmission is necessary */ 230 NULL, /* Called to handle protocol-specific codes */ 231 "IPV6CP" /* String name of protocol */ 232 }; 233 234 /* 235 * Command-line options. 236 */ 237 static int setifaceid (char **arg); 238 static void printifaceid (struct option *, 239 void (*)(void *, char *, ...), void *); 240 241 static struct option ipv6cp_option_list[] = { 242 { "ipv6", o_special, (void *)setifaceid, 243 "Set interface identifiers for IPV6", 244 OPT_A2PRINTER, (void *)printifaceid }, 245 246 { "+ipv6", o_bool, &ipv6cp_protent.enabled_flag, 247 "Enable IPv6 and IPv6CP", OPT_PRIO | 1 }, 248 { "noipv6", o_bool, &ipv6cp_protent.enabled_flag, 249 "Disable IPv6 and IPv6CP", OPT_PRIOSUB }, 250 { "-ipv6", o_bool, &ipv6cp_protent.enabled_flag, 251 "Disable IPv6 and IPv6CP", OPT_PRIOSUB | OPT_ALIAS }, 252 253 { "ipv6cp-accept-local", o_bool, &ipv6cp_wantoptions[0].accept_local, 254 "Accept peer's interface identifier for us", 1 }, 255 { "ipv6cp-accept-remote", o_bool, &ipv6cp_wantoptions[0].accept_remote, 256 "Accept peer's interface identifier for itself", 1 }, 257 258 { "defaultroute6", o_bool, &ipv6cp_wantoptions[0].default_route, 259 "Add default IPv6 route", OPT_ENABLE|1, &ipv6cp_allowoptions[0].default_route }, 260 { "nodefaultroute6", o_bool, &ipv6cp_allowoptions[0].default_route, 261 "disable defaultroute6 option", OPT_A2CLR, 262 &ipv6cp_wantoptions[0].default_route }, 263 { "-defaultroute6", o_bool, &ipv6cp_allowoptions[0].default_route, 264 "disable defaultroute6 option", OPT_ALIAS | OPT_A2CLR, 265 &ipv6cp_wantoptions[0].default_route }, 266 267 { "ipv6cp-use-ipaddr", o_bool, &ipv6cp_allowoptions[0].use_ip, 268 "Use (default) IPv4 addresses for both local and remote interface identifiers", 1 }, 269 { "ipv6cp-use-persistent", o_bool, &ipv6cp_wantoptions[0].use_persistent, 270 "Use uniquely-available persistent value for local interface identifier", 1 }, 271 { "ipv6cp-use-remotenumber", o_bool, &ipv6cp_wantoptions[0].use_remotenumber, 272 "Use remotenumber value for remote interface identifier", 1 }, 273 274 #ifdef __linux__ 275 { "ipv6cp-noremote", o_bool, &ipv6cp_noremote, 276 "Allow peer to have no interface identifier", 1 }, 277 #endif 278 { "ipv6cp-nosend", o_bool, &ipv6cp_wantoptions[0].neg_ifaceid, 279 "Don't send local interface identifier to peer", OPT_A2CLR }, 280 281 { "ipv6cp-restart", o_int, &ipv6cp_fsm[0].timeouttime, 282 "Set timeout for IPv6CP", OPT_PRIO }, 283 { "ipv6cp-max-terminate", o_int, &ipv6cp_fsm[0].maxtermtransmits, 284 "Set max #xmits for term-reqs", OPT_PRIO }, 285 { "ipv6cp-max-configure", o_int, &ipv6cp_fsm[0].maxconfreqtransmits, 286 "Set max #xmits for conf-reqs", OPT_PRIO }, 287 { "ipv6cp-max-failure", o_int, &ipv6cp_fsm[0].maxnakloops, 288 "Set max #conf-naks for IPv6CP", OPT_PRIO }, 289 290 { NULL } 291 }; 292 293 294 /* 295 * Protocol entry points from main code. 296 */ 297 static void ipv6cp_init (int); 298 static void ipv6cp_open (int); 299 static void ipv6cp_close (int, char *); 300 static void ipv6cp_lowerup (int); 301 static void ipv6cp_lowerdown (int); 302 static void ipv6cp_input (int, u_char *, int); 303 static void ipv6cp_protrej (int); 304 static int ipv6cp_printpkt (u_char *, int, 305 void (*) (void *, char *, ...), void *); 306 static void ipv6_check_options (void); 307 static int ipv6_demand_conf (int); 308 static int ipv6_active_pkt (u_char *, int); 309 310 struct protent ipv6cp_protent = { 311 PPP_IPV6CP, 312 ipv6cp_init, 313 ipv6cp_input, 314 ipv6cp_protrej, 315 ipv6cp_lowerup, 316 ipv6cp_lowerdown, 317 ipv6cp_open, 318 ipv6cp_close, 319 ipv6cp_printpkt, 320 NULL, 321 1, 322 "IPV6CP", 323 "IPV6", 324 ipv6cp_option_list, 325 ipv6_check_options, 326 ipv6_demand_conf, 327 ipv6_active_pkt 328 }; 329 330 static void ipv6cp_clear_addrs (int, eui64_t, eui64_t); 331 static void ipv6cp_script (char *); 332 static void ipv6cp_script_done (void *); 333 334 /* 335 * Lengths of configuration options. 336 */ 337 #define CILEN_VOID 2 338 #define CILEN_COMPRESS 4 /* length for RFC2023 compress opt. */ 339 #define CILEN_IFACEID 10 /* RFC2472, interface identifier */ 340 341 #define CODENAME(x) ((x) == CONFACK ? "ACK" : \ 342 (x) == CONFNAK ? "NAK" : "REJ") 343 344 /* 345 * This state variable is used to ensure that we don't 346 * run an ipcp-up/down script while one is already running. 347 */ 348 static enum script_state { 349 s_down, 350 s_up, 351 } ipv6cp_script_state; 352 static pid_t ipv6cp_script_pid; 353 354 /* 355 * setifaceid - set the interface identifiers manually 356 */ 357 static int 358 setifaceid(char **argv) 359 { 360 char *comma, *arg, c; 361 ipv6cp_options *wo = &ipv6cp_wantoptions[0]; 362 struct in6_addr addr; 363 static int prio_local, prio_remote; 364 365 #define VALIDID(a) ( (((a).s6_addr32[0] == 0) && ((a).s6_addr32[1] == 0)) && \ 366 (((a).s6_addr32[2] != 0) || ((a).s6_addr32[3] != 0)) ) 367 368 arg = *argv; 369 if ((comma = strchr(arg, ',')) == NULL) 370 comma = arg + strlen(arg); 371 372 /* 373 * If comma first character, then no local identifier 374 */ 375 if (comma != arg) { 376 c = *comma; 377 *comma = '\0'; 378 379 if (inet_pton(AF_INET6, arg, &addr) == 0 || !VALIDID(addr)) { 380 ppp_option_error("Illegal interface identifier (local): %s", arg); 381 return 0; 382 } 383 384 if (option_priority >= prio_local) { 385 eui64_copy(addr.s6_addr32[2], wo->ourid); 386 wo->opt_local = 1; 387 prio_local = option_priority; 388 } 389 *comma = c; 390 } 391 392 /* 393 * If comma last character, the no remote identifier 394 */ 395 if (*comma != 0 && *++comma != '\0') { 396 if (inet_pton(AF_INET6, comma, &addr) == 0 || !VALIDID(addr)) { 397 ppp_option_error("Illegal interface identifier (remote): %s", comma); 398 return 0; 399 } 400 if (option_priority >= prio_remote) { 401 eui64_copy(addr.s6_addr32[2], wo->hisid); 402 wo->opt_remote = 1; 403 prio_remote = option_priority; 404 } 405 } 406 407 if (override_value("+ipv6", option_priority, option_source)) 408 ipv6cp_protent.enabled_flag = 1; 409 return 1; 410 } 411 412 char *llv6_ntoa(eui64_t ifaceid); 413 414 static void 415 printifaceid(struct option *opt, void (*printer) (void *, char *, ...), void *arg) 416 { 417 ipv6cp_options *wo = &ipv6cp_wantoptions[0]; 418 419 if (wo->opt_local) 420 printer(arg, "%s", llv6_ntoa(wo->ourid)); 421 printer(arg, ","); 422 if (wo->opt_remote) 423 printer(arg, "%s", llv6_ntoa(wo->hisid)); 424 } 425 426 /* 427 * Make a string representation of a network address. 428 */ 429 char * 430 llv6_ntoa(eui64_t ifaceid) 431 { 432 static char b[64]; 433 434 snprintf(b, sizeof(b), "fe80::%s", eui64_ntoa(ifaceid)); 435 return b; 436 } 437 438 439 /* 440 * ipv6cp_init - Initialize IPV6CP. 441 */ 442 static void 443 ipv6cp_init(int unit) 444 { 445 fsm *f = &ipv6cp_fsm[unit]; 446 ipv6cp_options *wo = &ipv6cp_wantoptions[unit]; 447 ipv6cp_options *ao = &ipv6cp_allowoptions[unit]; 448 449 f->unit = unit; 450 f->protocol = PPP_IPV6CP; 451 f->callbacks = &ipv6cp_callbacks; 452 fsm_init(&ipv6cp_fsm[unit]); 453 454 memset(wo, 0, sizeof(*wo)); 455 memset(ao, 0, sizeof(*ao)); 456 457 wo->accept_local = 0; 458 wo->accept_remote = 0; 459 wo->neg_ifaceid = 1; 460 ao->neg_ifaceid = 1; 461 462 #ifdef IPV6CP_COMP 463 wo->neg_vj = 1; 464 ao->neg_vj = 1; 465 wo->vj_protocol = IPV6CP_COMP; 466 #endif 467 468 /* 469 * XXX This controls whether the user may use the defaultroute option. 470 */ 471 ao->default_route = 1; 472 } 473 474 475 /* 476 * ipv6cp_open - IPV6CP is allowed to come up. 477 */ 478 static void 479 ipv6cp_open(int unit) 480 { 481 fsm_open(&ipv6cp_fsm[unit]); 482 } 483 484 485 /* 486 * ipv6cp_close - Take IPV6CP down. 487 */ 488 static void 489 ipv6cp_close(int unit, char *reason) 490 { 491 fsm_close(&ipv6cp_fsm[unit], reason); 492 } 493 494 495 /* 496 * ipv6cp_lowerup - The lower layer is up. 497 */ 498 static void 499 ipv6cp_lowerup(int unit) 500 { 501 fsm_lowerup(&ipv6cp_fsm[unit]); 502 } 503 504 505 /* 506 * ipv6cp_lowerdown - The lower layer is down. 507 */ 508 static void 509 ipv6cp_lowerdown(int unit) 510 { 511 fsm_lowerdown(&ipv6cp_fsm[unit]); 512 } 513 514 515 /* 516 * ipv6cp_input - Input IPV6CP packet. 517 */ 518 static void 519 ipv6cp_input(int unit, u_char *p, int len) 520 { 521 fsm_input(&ipv6cp_fsm[unit], p, len); 522 } 523 524 525 /* 526 * ipv6cp_protrej - A Protocol-Reject was received for IPV6CP. 527 * 528 * Pretend the lower layer went down, so we shut up. 529 */ 530 static void 531 ipv6cp_protrej(int unit) 532 { 533 fsm_lowerdown(&ipv6cp_fsm[unit]); 534 } 535 536 537 /* 538 * ipv6cp_resetci - Reset our CI. 539 */ 540 static void 541 ipv6cp_resetci(fsm *f) 542 { 543 ipv6cp_options *wo = &ipv6cp_wantoptions[f->unit]; 544 ipv6cp_options *go = &ipv6cp_gotoptions[f->unit]; 545 546 wo->req_ifaceid = wo->neg_ifaceid && ipv6cp_allowoptions[f->unit].neg_ifaceid; 547 548 if (!wo->opt_local) { 549 wo->accept_local = 1; 550 if (!demand) 551 eui64_magic_nz(wo->ourid); 552 } 553 if (!wo->opt_remote) 554 wo->accept_remote = 1; 555 556 *go = *wo; 557 eui64_zero(go->hisid); /* last proposed interface identifier */ 558 } 559 560 561 /* 562 * ipv6cp_cilen - Return length of our CI. 563 */ 564 static int 565 ipv6cp_cilen(fsm *f) 566 { 567 ipv6cp_options *go = &ipv6cp_gotoptions[f->unit]; 568 569 #define LENCIVJ(neg) (neg ? CILEN_COMPRESS : 0) 570 #define LENCIIFACEID(neg) (neg ? CILEN_IFACEID : 0) 571 572 return (LENCIIFACEID(go->neg_ifaceid) + 573 LENCIVJ(go->neg_vj)); 574 } 575 576 577 /* 578 * ipv6cp_addci - Add our desired CIs to a packet. 579 */ 580 static void 581 ipv6cp_addci(fsm *f, u_char *ucp, int *lenp) 582 { 583 ipv6cp_options *go = &ipv6cp_gotoptions[f->unit]; 584 int len = *lenp; 585 586 #define ADDCIVJ(opt, neg, val) \ 587 if (neg) { \ 588 int vjlen = CILEN_COMPRESS; \ 589 if (len >= vjlen) { \ 590 PUTCHAR(opt, ucp); \ 591 PUTCHAR(vjlen, ucp); \ 592 PUTSHORT(val, ucp); \ 593 len -= vjlen; \ 594 } else \ 595 neg = 0; \ 596 } 597 598 #define ADDCIIFACEID(opt, neg, val1) \ 599 if (neg) { \ 600 int idlen = CILEN_IFACEID; \ 601 if (len >= idlen) { \ 602 PUTCHAR(opt, ucp); \ 603 PUTCHAR(idlen, ucp); \ 604 eui64_put(val1, ucp); \ 605 len -= idlen; \ 606 } else \ 607 neg = 0; \ 608 } 609 610 ADDCIIFACEID(CI_IFACEID, go->neg_ifaceid, go->ourid); 611 612 ADDCIVJ(CI_COMPRESSTYPE, go->neg_vj, go->vj_protocol); 613 614 *lenp -= len; 615 } 616 617 618 /* 619 * ipv6cp_ackci - Ack our CIs. 620 * 621 * Returns: 622 * 0 - Ack was bad. 623 * 1 - Ack was good. 624 */ 625 static int 626 ipv6cp_ackci(fsm *f, u_char *p, int len) 627 { 628 ipv6cp_options *go = &ipv6cp_gotoptions[f->unit]; 629 u_short cilen, citype, cishort; 630 eui64_t ifaceid; 631 632 /* 633 * CIs must be in exactly the same order that we sent... 634 * Check packet length and CI length at each step. 635 * If we find any deviations, then this packet is bad. 636 */ 637 638 #define ACKCIVJ(opt, neg, val) \ 639 if (neg) { \ 640 int vjlen = CILEN_COMPRESS; \ 641 if ((len -= vjlen) < 0) \ 642 goto bad; \ 643 GETCHAR(citype, p); \ 644 GETCHAR(cilen, p); \ 645 if (cilen != vjlen || \ 646 citype != opt) \ 647 goto bad; \ 648 GETSHORT(cishort, p); \ 649 if (cishort != val) \ 650 goto bad; \ 651 } 652 653 #define ACKCIIFACEID(opt, neg, val1) \ 654 if (neg) { \ 655 int idlen = CILEN_IFACEID; \ 656 if ((len -= idlen) < 0) \ 657 goto bad; \ 658 GETCHAR(citype, p); \ 659 GETCHAR(cilen, p); \ 660 if (cilen != idlen || \ 661 citype != opt) \ 662 goto bad; \ 663 eui64_get(ifaceid, p); \ 664 if (! eui64_equals(val1, ifaceid)) \ 665 goto bad; \ 666 } 667 668 ACKCIIFACEID(CI_IFACEID, go->neg_ifaceid, go->ourid); 669 670 ACKCIVJ(CI_COMPRESSTYPE, go->neg_vj, go->vj_protocol); 671 672 /* 673 * If there are any remaining CIs, then this packet is bad. 674 */ 675 if (len != 0) 676 goto bad; 677 return (1); 678 679 bad: 680 IPV6CPDEBUG(("ipv6cp_ackci: received bad Ack!")); 681 return (0); 682 } 683 684 /* 685 * ipv6cp_nakci - Peer has sent a NAK for some of our CIs. 686 * This should not modify any state if the Nak is bad 687 * or if IPV6CP is in the OPENED state. 688 * 689 * Returns: 690 * 0 - Nak was bad. 691 * 1 - Nak was good. 692 */ 693 static int 694 ipv6cp_nakci(fsm *f, u_char *p, int len, int treat_as_reject) 695 { 696 ipv6cp_options *wo = &ipv6cp_wantoptions[f->unit]; 697 ipv6cp_options *go = &ipv6cp_gotoptions[f->unit]; 698 u_char citype, cilen, *next; 699 u_short cishort; 700 eui64_t ifaceid; 701 ipv6cp_options no; /* options we've seen Naks for */ 702 ipv6cp_options try; /* options to request next time */ 703 704 BZERO(&no, sizeof(no)); 705 try = *go; 706 707 /* 708 * Any Nak'd CIs must be in exactly the same order that we sent. 709 * Check packet length and CI length at each step. 710 * If we find any deviations, then this packet is bad. 711 */ 712 #define NAKCIIFACEID(opt, neg, code) \ 713 if (go->neg && \ 714 len >= (cilen = CILEN_IFACEID) && \ 715 p[1] == cilen && \ 716 p[0] == opt) { \ 717 len -= cilen; \ 718 INCPTR(2, p); \ 719 eui64_get(ifaceid, p); \ 720 no.neg = 1; \ 721 code \ 722 } 723 724 #define NAKCIVJ(opt, neg, code) \ 725 if (go->neg && \ 726 ((cilen = p[1]) == CILEN_COMPRESS) && \ 727 len >= cilen && \ 728 p[0] == opt) { \ 729 len -= cilen; \ 730 INCPTR(2, p); \ 731 GETSHORT(cishort, p); \ 732 no.neg = 1; \ 733 code \ 734 } 735 736 /* 737 * Accept the peer's idea of {our,his} interface identifier, if different 738 * from our idea, only if the accept_{local,remote} flag is set. 739 */ 740 NAKCIIFACEID(CI_IFACEID, neg_ifaceid, 741 if (treat_as_reject) { 742 try.neg_ifaceid = 0; 743 } else if (go->accept_local && !eui64_iszero(ifaceid) && !eui64_equals(ifaceid, go->hisid)) { 744 try.ourid = ifaceid; 745 } else if (eui64_iszero(ifaceid) && !go->opt_local && wo->neg_ifaceid) { 746 while (eui64_iszero(ifaceid) || 747 eui64_equals(ifaceid, go->hisid)) /* bad luck */ 748 eui64_magic(ifaceid); 749 try.ourid = ifaceid; 750 IPV6CPDEBUG(("local LL address %s", llv6_ntoa(ifaceid))); 751 } 752 ); 753 754 #ifdef IPV6CP_COMP 755 NAKCIVJ(CI_COMPRESSTYPE, neg_vj, 756 { 757 if (cishort == IPV6CP_COMP && !treat_as_reject) { 758 try.vj_protocol = cishort; 759 } else { 760 try.neg_vj = 0; 761 } 762 } 763 ); 764 #else 765 NAKCIVJ(CI_COMPRESSTYPE, neg_vj, 766 { 767 try.neg_vj = 0; 768 } 769 ); 770 #endif 771 772 /* 773 * There may be remaining CIs, if the peer is requesting negotiation 774 * on an option that we didn't include in our request packet. 775 * If they want to negotiate about interface identifier, we comply. 776 * If they want us to ask for compression, we refuse. 777 */ 778 while (len >= CILEN_VOID) { 779 GETCHAR(citype, p); 780 GETCHAR(cilen, p); 781 if ( cilen < CILEN_VOID || (len -= cilen) < 0 ) 782 goto bad; 783 next = p + cilen - 2; 784 785 switch (citype) { 786 case CI_COMPRESSTYPE: 787 if (go->neg_vj || no.neg_vj || 788 (cilen != CILEN_COMPRESS)) 789 goto bad; 790 no.neg_vj = 1; 791 break; 792 case CI_IFACEID: 793 if (go->neg_ifaceid || no.neg_ifaceid || cilen != CILEN_IFACEID) 794 goto bad; 795 try.neg_ifaceid = 1; 796 eui64_get(ifaceid, p); 797 if (go->accept_local && !eui64_iszero(ifaceid) && !eui64_equals(ifaceid, go->hisid)) { 798 try.ourid = ifaceid; 799 } else if (eui64_iszero(ifaceid) && !go->opt_local && wo->neg_ifaceid) { 800 while (eui64_iszero(ifaceid) || 801 eui64_equals(ifaceid, go->hisid)) /* bad luck */ 802 eui64_magic(ifaceid); 803 try.ourid = ifaceid; 804 } else { 805 try.neg_ifaceid = 0; 806 } 807 no.neg_ifaceid = 1; 808 break; 809 } 810 p = next; 811 } 812 813 /* If there is still anything left, this packet is bad. */ 814 if (len != 0) 815 goto bad; 816 817 /* 818 * OK, the Nak is good. Now we can update state. 819 */ 820 if (f->state != OPENED) 821 *go = try; 822 823 return 1; 824 825 bad: 826 IPV6CPDEBUG(("ipv6cp_nakci: received bad Nak!")); 827 return 0; 828 } 829 830 831 /* 832 * ipv6cp_rejci - Reject some of our CIs. 833 */ 834 static int 835 ipv6cp_rejci(fsm *f, u_char *p, int len) 836 { 837 ipv6cp_options *go = &ipv6cp_gotoptions[f->unit]; 838 u_char cilen; 839 u_short cishort; 840 eui64_t ifaceid; 841 ipv6cp_options try; /* options to request next time */ 842 843 try = *go; 844 /* 845 * Any Rejected CIs must be in exactly the same order that we sent. 846 * Check packet length and CI length at each step. 847 * If we find any deviations, then this packet is bad. 848 */ 849 #define REJCIIFACEID(opt, neg, val1) \ 850 if (go->neg && \ 851 len >= (cilen = CILEN_IFACEID) && \ 852 p[1] == cilen && \ 853 p[0] == opt) { \ 854 len -= cilen; \ 855 INCPTR(2, p); \ 856 eui64_get(ifaceid, p); \ 857 /* Check rejected value. */ \ 858 if (! eui64_equals(ifaceid, val1)) \ 859 goto bad; \ 860 try.neg = 0; \ 861 } 862 863 #define REJCIVJ(opt, neg, val) \ 864 if (go->neg && \ 865 p[1] == CILEN_COMPRESS && \ 866 len >= p[1] && \ 867 p[0] == opt) { \ 868 len -= p[1]; \ 869 INCPTR(2, p); \ 870 GETSHORT(cishort, p); \ 871 /* Check rejected value. */ \ 872 if (cishort != val) \ 873 goto bad; \ 874 try.neg = 0; \ 875 } 876 877 REJCIIFACEID(CI_IFACEID, neg_ifaceid, go->ourid); 878 879 REJCIVJ(CI_COMPRESSTYPE, neg_vj, go->vj_protocol); 880 881 /* 882 * If there are any remaining CIs, then this packet is bad. 883 */ 884 if (len != 0) 885 goto bad; 886 /* 887 * Now we can update state. 888 */ 889 if (f->state != OPENED) 890 *go = try; 891 return 1; 892 893 bad: 894 IPV6CPDEBUG(("ipv6cp_rejci: received bad Reject!")); 895 return 0; 896 } 897 898 899 /* 900 * ipv6cp_reqci - Check the peer's requested CIs and send appropriate response. 901 * 902 * Returns: CONFACK, CONFNAK or CONFREJ and input packet modified 903 * appropriately. If reject_if_disagree is non-zero, doesn't return 904 * CONFNAK; returns CONFREJ if it can't return CONFACK. 905 */ 906 static int 907 ipv6cp_reqci(fsm *f, u_char *inp, int *len, int reject_if_disagree) 908 { 909 ipv6cp_options *wo = &ipv6cp_wantoptions[f->unit]; 910 ipv6cp_options *ho = &ipv6cp_hisoptions[f->unit]; 911 ipv6cp_options *ao = &ipv6cp_allowoptions[f->unit]; 912 ipv6cp_options *go = &ipv6cp_gotoptions[f->unit]; 913 u_char *cip, *next; /* Pointer to current and next CIs */ 914 u_short cilen, citype; /* Parsed len, type */ 915 u_short cishort; /* Parsed short value */ 916 eui64_t ifaceid; /* Parsed interface identifier */ 917 int rc = CONFACK; /* Final packet return code */ 918 int orc; /* Individual option return code */ 919 u_char *p; /* Pointer to next char to parse */ 920 u_char *ucp = inp; /* Pointer to current output char */ 921 int l = *len; /* Length left */ 922 923 /* 924 * Reset all his options. 925 */ 926 BZERO(ho, sizeof(*ho)); 927 928 /* 929 * Process all his options. 930 */ 931 next = inp; 932 while (l) { 933 orc = CONFACK; /* Assume success */ 934 cip = p = next; /* Remember begining of CI */ 935 if (l < 2 || /* Not enough data for CI header or */ 936 p[1] < 2 || /* CI length too small or */ 937 p[1] > l) { /* CI length too big? */ 938 IPV6CPDEBUG(("ipv6cp_reqci: bad CI length!")); 939 orc = CONFREJ; /* Reject bad CI */ 940 cilen = l; /* Reject till end of packet */ 941 l = 0; /* Don't loop again */ 942 goto endswitch; 943 } 944 GETCHAR(citype, p); /* Parse CI type */ 945 GETCHAR(cilen, p); /* Parse CI length */ 946 l -= cilen; /* Adjust remaining length */ 947 next += cilen; /* Step to next CI */ 948 949 switch (citype) { /* Check CI type */ 950 case CI_IFACEID: 951 IPV6CPDEBUG(("ipv6cp: received interface identifier ")); 952 953 if (!ao->neg_ifaceid || 954 cilen != CILEN_IFACEID) { /* Check CI length */ 955 orc = CONFREJ; /* Reject CI */ 956 break; 957 } 958 959 /* 960 * If he has no interface identifier, or if we both have same 961 * identifier then NAK it with new idea. 962 * In particular, if we don't know his identifier, but he does, 963 * then accept it. 964 */ 965 eui64_get(ifaceid, p); 966 IPV6CPDEBUG(("(%s)", llv6_ntoa(ifaceid))); 967 if (eui64_iszero(ifaceid) && eui64_iszero(go->ourid)) { 968 orc = CONFREJ; /* Reject CI */ 969 break; 970 } 971 if (!eui64_iszero(wo->hisid) && !wo->accept_remote && 972 !eui64_equals(ifaceid, wo->hisid)) { 973 974 orc = CONFNAK; 975 ifaceid = wo->hisid; 976 go->hisid = ifaceid; 977 DECPTR(sizeof(ifaceid), p); 978 eui64_put(ifaceid, p); 979 } else 980 if (eui64_iszero(ifaceid) || eui64_equals(ifaceid, go->ourid)) { 981 orc = CONFNAK; 982 if (eui64_iszero(go->hisid)) /* first time, try option */ 983 ifaceid = wo->hisid; 984 if (eui64_equals(ifaceid, go->ourid)) /* bad luck */ 985 eui64_zero(ifaceid); 986 if (eui64_iszero(ifaceid)) { 987 if (wo->opt_remote) 988 ifaceid = wo->hisid; 989 else { 990 while (eui64_iszero(ifaceid) || 991 eui64_equals(ifaceid, go->ourid)) /* bad luck */ 992 eui64_magic(ifaceid); 993 } 994 } 995 go->hisid = ifaceid; 996 DECPTR(sizeof(ifaceid), p); 997 eui64_put(ifaceid, p); 998 } 999 1000 ho->neg_ifaceid = 1; 1001 ho->hisid = ifaceid; 1002 break; 1003 1004 case CI_COMPRESSTYPE: 1005 IPV6CPDEBUG(("ipv6cp: received COMPRESSTYPE ")); 1006 if (!ao->neg_vj || 1007 (cilen != CILEN_COMPRESS)) { 1008 orc = CONFREJ; 1009 break; 1010 } 1011 GETSHORT(cishort, p); 1012 IPV6CPDEBUG(("(%d)", cishort)); 1013 1014 #ifdef IPV6CP_COMP 1015 if (!(cishort == IPV6CP_COMP)) { 1016 orc = CONFREJ; 1017 break; 1018 } 1019 1020 ho->neg_vj = 1; 1021 ho->vj_protocol = cishort; 1022 break; 1023 #else 1024 orc = CONFREJ; 1025 break; 1026 #endif 1027 1028 default: 1029 orc = CONFREJ; 1030 break; 1031 } 1032 1033 endswitch: 1034 IPV6CPDEBUG((" (%s)\n", CODENAME(orc))); 1035 1036 if (orc == CONFACK && /* Good CI */ 1037 rc != CONFACK) /* but prior CI wasnt? */ 1038 continue; /* Don't send this one */ 1039 1040 if (orc == CONFNAK) { /* Nak this CI? */ 1041 if (reject_if_disagree) /* Getting fed up with sending NAKs? */ 1042 orc = CONFREJ; /* Get tough if so */ 1043 else { 1044 if (rc == CONFREJ) /* Rejecting prior CI? */ 1045 continue; /* Don't send this one */ 1046 if (rc == CONFACK) { /* Ack'd all prior CIs? */ 1047 rc = CONFNAK; /* Not anymore... */ 1048 ucp = inp; /* Backup */ 1049 } 1050 } 1051 } 1052 1053 if (orc == CONFREJ && /* Reject this CI */ 1054 rc != CONFREJ) { /* but no prior ones? */ 1055 rc = CONFREJ; 1056 ucp = inp; /* Backup */ 1057 } 1058 1059 /* Need to move CI? */ 1060 if (ucp != cip) 1061 BCOPY(cip, ucp, cilen); /* Move it */ 1062 1063 /* Update output pointer */ 1064 INCPTR(cilen, ucp); 1065 } 1066 1067 /* 1068 * If we aren't rejecting this packet, and we want to negotiate 1069 * their identifier and they didn't send their identifier, then we 1070 * send a NAK with a CI_IFACEID option appended. We assume the 1071 * input buffer is long enough that we can append the extra 1072 * option safely. 1073 */ 1074 if (rc != CONFREJ && !ho->neg_ifaceid && 1075 wo->req_ifaceid && !reject_if_disagree) { 1076 if (rc == CONFACK) { 1077 rc = CONFNAK; 1078 ucp = inp; /* reset pointer */ 1079 wo->req_ifaceid = 0; /* don't ask again */ 1080 } 1081 PUTCHAR(CI_IFACEID, ucp); 1082 PUTCHAR(CILEN_IFACEID, ucp); 1083 eui64_put(wo->hisid, ucp); 1084 } 1085 1086 *len = ucp - inp; /* Compute output length */ 1087 IPV6CPDEBUG(("ipv6cp: returning Configure-%s", CODENAME(rc))); 1088 return (rc); /* Return final code */ 1089 } 1090 1091 1092 /* 1093 * eui48_to_eui64 - Convert the EUI-48 into EUI-64, per RFC 2472 [sec 4.1] 1094 */ 1095 static void 1096 eui48_to_eui64(eui64_t *p_eui64, const u_char addr[6]) 1097 { 1098 p_eui64->e8[0] = addr[0] | 0x02; 1099 p_eui64->e8[1] = addr[1]; 1100 p_eui64->e8[2] = addr[2]; 1101 p_eui64->e8[3] = 0xFF; 1102 p_eui64->e8[4] = 0xFE; 1103 p_eui64->e8[5] = addr[3]; 1104 p_eui64->e8[6] = addr[4]; 1105 p_eui64->e8[7] = addr[5]; 1106 } 1107 1108 1109 /* 1110 * ether_to_eui64 - Convert 48-bit Ethernet address into 64-bit EUI 1111 * 1112 * walks the list of valid ethernet interfaces, starting with devnam 1113 * (for PPPoE it is ethernet interface), and convert the first 1114 * found 48-bit MAC address into EUI 64. caller also assumes that 1115 * the system has a properly configured Ethernet interface for this 1116 * function to return non-zero. 1117 */ 1118 static int 1119 ether_to_eui64(eui64_t *p_eui64) 1120 { 1121 u_char addr[6]; 1122 1123 if (get_if_hwaddr(addr, devnam) < 0 && get_first_ether_hwaddr(addr) < 0) { 1124 error("ipv6cp: no persistent id can be found"); 1125 return 0; 1126 } 1127 1128 eui48_to_eui64(p_eui64, addr); 1129 return 1; 1130 } 1131 1132 1133 /* 1134 * ipv6_check_options - check that any IP-related options are OK, 1135 * and assign appropriate defaults. 1136 */ 1137 static void 1138 ipv6_check_options(void) 1139 { 1140 ipv6cp_options *wo = &ipv6cp_wantoptions[0]; 1141 1142 if (!ipv6cp_protent.enabled_flag) 1143 return; 1144 1145 /* 1146 * Persistent link-local id is only used when user has not explicitly 1147 * configure/hard-code the id 1148 */ 1149 if ((wo->use_persistent) && (!wo->opt_local)) { 1150 1151 /* 1152 * On systems where there are no Ethernet interfaces used, there 1153 * may be other ways to obtain a persistent id. Right now, it 1154 * will fall back to using magic [see eui64_magic] below when 1155 * an EUI-48 from MAC address can't be obtained. Other possibilities 1156 * include obtaining EEPROM serial numbers, or some other unique 1157 * yet persistent number. On Sparc platforms, this is possible, 1158 * but too bad there's no standards yet for x86 machines. 1159 */ 1160 if (ether_to_eui64(&wo->ourid)) { 1161 wo->opt_local = 1; 1162 } 1163 } 1164 1165 if (!wo->opt_remote && wo->use_remotenumber && *remote_number) { 1166 /* remote number can be either MAC address, IPv4 address, IPv6 address or telephone number */ 1167 struct in_addr addr; 1168 struct in6_addr addr6; 1169 unsigned long long tel; 1170 unsigned char mac[6]; 1171 const char *str; 1172 char *endptr; 1173 if (sscanf(remote_number, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", 1174 &mac[0], &mac[1], &mac[2], 1175 &mac[3], &mac[4], &mac[5]) == 6) { 1176 eui48_to_eui64(&wo->hisid, mac); 1177 } else if (inet_pton(AF_INET, remote_number, &addr) == 1) { 1178 eui64_setlo32(wo->hisid, ntohl(addr.s_addr)); 1179 } else if (inet_pton(AF_INET6, remote_number, &addr6) == 1) { 1180 /* use low 64 bits of IPv6 address for interface identifier */ 1181 wo->hisid.e8[0] = addr6.s6_addr[8]; 1182 wo->hisid.e8[1] = addr6.s6_addr[9]; 1183 wo->hisid.e8[2] = addr6.s6_addr[10]; 1184 wo->hisid.e8[3] = addr6.s6_addr[11]; 1185 wo->hisid.e8[4] = addr6.s6_addr[12]; 1186 wo->hisid.e8[5] = addr6.s6_addr[13]; 1187 wo->hisid.e8[6] = addr6.s6_addr[14]; 1188 wo->hisid.e8[7] = addr6.s6_addr[15]; 1189 } else { 1190 str = remote_number; 1191 /* telephone number may start with leading '+' sign, so skip it */ 1192 if (str[0] == '+') 1193 str++; 1194 errno = 0; 1195 tel = strtoull(str, &endptr, 10); 1196 if (!errno && *str && !*endptr && tel) { 1197 wo->hisid.e32[0] = htonl(tel >> 32); 1198 wo->hisid.e32[1] = htonl(tel & 0xFFFFFFFF); 1199 } 1200 } 1201 if (!eui64_iszero(wo->hisid)) 1202 wo->opt_remote = 1; 1203 } 1204 1205 if (!wo->opt_local) { /* init interface identifier */ 1206 if (wo->use_ip && eui64_iszero(wo->ourid)) { 1207 eui64_setlo32(wo->ourid, ntohl(ipcp_wantoptions[0].ouraddr)); 1208 if (!eui64_iszero(wo->ourid)) 1209 wo->opt_local = 1; 1210 } 1211 1212 while (eui64_iszero(wo->ourid)) 1213 eui64_magic(wo->ourid); 1214 } 1215 1216 if (!wo->opt_remote) { 1217 if (wo->use_ip && eui64_iszero(wo->hisid)) { 1218 eui64_setlo32(wo->hisid, ntohl(ipcp_wantoptions[0].hisaddr)); 1219 if (!eui64_iszero(wo->hisid)) 1220 wo->opt_remote = 1; 1221 } 1222 } 1223 } 1224 1225 1226 /* 1227 * ipv6_demand_conf - configure the interface as though 1228 * IPV6CP were up, for use with dial-on-demand. 1229 */ 1230 static int 1231 ipv6_demand_conf(int u) 1232 { 1233 ipv6cp_options *wo = &ipv6cp_wantoptions[u]; 1234 1235 if (eui64_iszero(wo->hisid) && !ipv6cp_noremote) { 1236 /* make up an arbitrary identifier for the peer */ 1237 eui64_magic_nz(wo->hisid); 1238 } 1239 if (eui64_iszero(wo->ourid)) { 1240 /* make up an arbitrary identifier for us */ 1241 eui64_magic_nz(wo->ourid); 1242 } 1243 1244 if (!sif6up(u)) 1245 return 0; 1246 if (!sif6addr(u, wo->ourid, wo->hisid)) 1247 return 0; 1248 #if !defined(__linux__) && !(defined(SVR4) && (defined(SNI) || defined(__USLC__))) 1249 if (!sifup(u)) 1250 return 0; 1251 #endif 1252 if (!sifnpmode(u, PPP_IPV6, NPMODE_QUEUE)) 1253 return 0; 1254 if (wo->default_route) 1255 if (sif6defaultroute(u, wo->ourid, wo->hisid)) 1256 default_route_set[u] = 1; 1257 1258 notice("local LL address %s", llv6_ntoa(wo->ourid)); 1259 if (!eui64_iszero(wo->hisid)) 1260 notice("remote LL address %s", llv6_ntoa(wo->hisid)); 1261 1262 return 1; 1263 } 1264 1265 1266 /* 1267 * ipv6cp_up - IPV6CP has come UP. 1268 * 1269 * Configure the IPv6 network interface appropriately and bring it up. 1270 */ 1271 static void 1272 ipv6cp_up(fsm *f) 1273 { 1274 ipv6cp_options *ho = &ipv6cp_hisoptions[f->unit]; 1275 ipv6cp_options *go = &ipv6cp_gotoptions[f->unit]; 1276 ipv6cp_options *wo = &ipv6cp_wantoptions[f->unit]; 1277 1278 IPV6CPDEBUG(("ipv6cp: up")); 1279 1280 /* 1281 * We must have a non-zero LL address for both ends of the link. 1282 */ 1283 1284 if (!eui64_iszero(wo->hisid) && !wo->accept_remote && (!ho->neg_ifaceid || !eui64_equals(ho->hisid, wo->hisid))) { 1285 error("Peer refused to agree to his interface identifier"); 1286 ipv6cp_close(f->unit, "Refused his interface identifier"); 1287 return; 1288 } 1289 if (!ho->neg_ifaceid) 1290 ho->hisid = wo->hisid; 1291 1292 if(!no_ifaceid_neg) { 1293 if (eui64_iszero(ho->hisid) && !ipv6cp_noremote) { 1294 error("Could not determine remote LL address"); 1295 ipv6cp_close(f->unit, "Could not determine remote LL address"); 1296 return; 1297 } 1298 if (eui64_iszero(go->ourid)) { 1299 error("Could not determine local LL address"); 1300 ipv6cp_close(f->unit, "Could not determine local LL address"); 1301 return; 1302 } 1303 if (eui64_equals(go->ourid, ho->hisid)) { 1304 error("local and remote LL addresses are equal"); 1305 ipv6cp_close(f->unit, "local and remote LL addresses are equal"); 1306 return; 1307 } 1308 } 1309 ppp_script_setenv("LLLOCAL", llv6_ntoa(go->ourid), 0); 1310 if (!eui64_iszero(ho->hisid)) 1311 ppp_script_setenv("LLREMOTE", llv6_ntoa(ho->hisid), 0); 1312 1313 #ifdef IPV6CP_COMP 1314 /* set tcp compression */ 1315 sif6comp(f->unit, ho->neg_vj); 1316 #endif 1317 1318 /* 1319 * If we are doing dial-on-demand, the interface is already 1320 * configured, so we put out any saved-up packets, then set the 1321 * interface to pass IPv6 packets. 1322 */ 1323 if (demand) { 1324 if (! eui64_equals(go->ourid, wo->ourid) || 1325 ! eui64_equals(ho->hisid, wo->hisid)) { 1326 if (! eui64_equals(go->ourid, wo->ourid)) 1327 warn("Local LL address changed to %s", 1328 llv6_ntoa(go->ourid)); 1329 if (! eui64_equals(ho->hisid, wo->hisid)) 1330 warn("Remote LL address changed to %s", 1331 llv6_ntoa(ho->hisid)); 1332 ipv6cp_clear_addrs(f->unit, wo->ourid, wo->hisid); 1333 1334 /* Set the interface to the new addresses */ 1335 if (!sif6addr(f->unit, go->ourid, ho->hisid)) { 1336 if (debug) 1337 warn("sif6addr failed"); 1338 ipv6cp_close(f->unit, "Interface configuration failed"); 1339 return; 1340 } 1341 1342 /* assign a default route through the interface if required */ 1343 if (ipv6cp_wantoptions[f->unit].default_route) 1344 if (sif6defaultroute(f->unit, go->ourid, ho->hisid)) 1345 default_route_set[f->unit] = 1; 1346 } 1347 demand_rexmit(PPP_IPV6); 1348 sifnpmode(f->unit, PPP_IPV6, NPMODE_PASS); 1349 1350 } else { 1351 /* bring the interface up for IPv6 */ 1352 if (!sif6up(f->unit)) { 1353 if (debug) 1354 warn("sif6up failed (IPV6)"); 1355 ipv6cp_close(f->unit, "Interface configuration failed"); 1356 return; 1357 } 1358 1359 if (!sif6addr(f->unit, go->ourid, ho->hisid)) { 1360 if (debug) 1361 warn("sif6addr failed"); 1362 ipv6cp_close(f->unit, "Interface configuration failed"); 1363 return; 1364 } 1365 sifnpmode(f->unit, PPP_IPV6, NPMODE_PASS); 1366 1367 /* assign a default route through the interface if required */ 1368 if (ipv6cp_wantoptions[f->unit].default_route) 1369 if (sif6defaultroute(f->unit, go->ourid, ho->hisid)) 1370 default_route_set[f->unit] = 1; 1371 1372 notice("local LL address %s", llv6_ntoa(go->ourid)); 1373 if (!eui64_iszero(ho->hisid)) 1374 notice("remote LL address %s", llv6_ntoa(ho->hisid)); 1375 } 1376 1377 np_up(f->unit, PPP_IPV6); 1378 ipv6cp_is_up = 1; 1379 1380 notify(ipv6_up_notifier, 0); 1381 if (ipv6_up_hook) 1382 ipv6_up_hook(); 1383 1384 /* 1385 * Execute the ipv6-up script, like this: 1386 * /etc/ppp/ipv6-up interface tty speed local-LL remote-LL 1387 */ 1388 if (ipv6cp_script_state == s_down && ipv6cp_script_pid == 0) { 1389 ipv6cp_script_state = s_up; 1390 ipv6cp_script(path_ipv6up); 1391 } 1392 } 1393 1394 1395 /* 1396 * ipv6cp_down - IPV6CP has gone DOWN. 1397 * 1398 * Take the IPv6 network interface down, clear its addresses 1399 * and delete routes through it. 1400 */ 1401 static void 1402 ipv6cp_down(fsm *f) 1403 { 1404 IPV6CPDEBUG(("ipv6cp: down")); 1405 ppp_get_link_stats(NULL); 1406 notify(ipv6_down_notifier, 0); 1407 if (ipv6_down_hook) 1408 ipv6_down_hook(); 1409 if (ipv6cp_is_up) { 1410 ipv6cp_is_up = 0; 1411 np_down(f->unit, PPP_IPV6); 1412 } 1413 #ifdef IPV6CP_COMP 1414 sif6comp(f->unit, 0); 1415 #endif 1416 1417 /* 1418 * If we are doing dial-on-demand, set the interface 1419 * to queue up outgoing packets (for now). 1420 */ 1421 if (demand) { 1422 sifnpmode(f->unit, PPP_IPV6, NPMODE_QUEUE); 1423 } else { 1424 sifnpmode(f->unit, PPP_IPV6, NPMODE_DROP); 1425 #if !defined(__linux__) && !(defined(SVR4) && (defined(SNI) || defined(__USLC))) 1426 sif6down(f->unit); 1427 #endif 1428 ipv6cp_clear_addrs(f->unit, 1429 ipv6cp_gotoptions[f->unit].ourid, 1430 ipv6cp_hisoptions[f->unit].hisid); 1431 #if defined(__linux__) 1432 sif6down(f->unit); 1433 #elif defined(SVR4) && (defined(SNI) || defined(__USLC)) 1434 sifdown(f->unit); 1435 #endif 1436 } 1437 1438 /* Execute the ipv6-down script */ 1439 if (ipv6cp_script_state == s_up && ipv6cp_script_pid == 0) { 1440 ipv6cp_script_state = s_down; 1441 ipv6cp_script(path_ipv6down); 1442 } 1443 } 1444 1445 1446 /* 1447 * ipv6cp_clear_addrs() - clear the interface addresses, routes, 1448 * proxy neighbour discovery entries, etc. 1449 */ 1450 static void 1451 ipv6cp_clear_addrs(int unit, eui64_t ourid, eui64_t hisid) 1452 { 1453 cif6addr(unit, ourid, hisid); 1454 } 1455 1456 1457 /* 1458 * ipv6cp_finished - possibly shut down the lower layers. 1459 */ 1460 static void 1461 ipv6cp_finished(fsm *f) 1462 { 1463 np_finished(f->unit, PPP_IPV6); 1464 } 1465 1466 1467 /* 1468 * ipv6cp_script_done - called when the ipv6-up or ipv6-down script 1469 * has finished. 1470 */ 1471 static void 1472 ipv6cp_script_done(void *arg) 1473 { 1474 ipv6cp_script_pid = 0; 1475 switch (ipv6cp_script_state) { 1476 case s_up: 1477 if (ipv6cp_fsm[0].state != OPENED) { 1478 ipv6cp_script_state = s_down; 1479 ipv6cp_script(path_ipv6down); 1480 } 1481 break; 1482 case s_down: 1483 if (ipv6cp_fsm[0].state == OPENED) { 1484 ipv6cp_script_state = s_up; 1485 ipv6cp_script(path_ipv6up); 1486 } 1487 break; 1488 } 1489 } 1490 1491 1492 /* 1493 * ipv6cp_script - Execute a script with arguments 1494 * interface-name tty-name speed local-LL remote-LL. 1495 */ 1496 static void 1497 ipv6cp_script(char *script) 1498 { 1499 char strspeed[32], strlocal[64], strremote[64]; 1500 char *argv[8]; 1501 1502 snprintf(strspeed, sizeof(strspeed), "%d", baud_rate); 1503 strlcpy(strlocal, llv6_ntoa(ipv6cp_gotoptions[0].ourid), sizeof(strlocal)); 1504 strlcpy(strremote, llv6_ntoa(ipv6cp_hisoptions[0].hisid), 1505 sizeof(strremote)); 1506 1507 argv[0] = script; 1508 argv[1] = ifname; 1509 argv[2] = devnam; 1510 argv[3] = strspeed; 1511 argv[4] = strlocal; 1512 argv[5] = strremote; 1513 argv[6] = ipparam; 1514 argv[7] = NULL; 1515 1516 ipv6cp_script_pid = run_program(script, argv, 0, ipv6cp_script_done, 1517 NULL, 0); 1518 } 1519 1520 /* 1521 * ipv6cp_printpkt - print the contents of an IPV6CP packet. 1522 */ 1523 static char *ipv6cp_codenames[] = { 1524 "ConfReq", "ConfAck", "ConfNak", "ConfRej", 1525 "TermReq", "TermAck", "CodeRej" 1526 }; 1527 1528 static int 1529 ipv6cp_printpkt(u_char *p, int plen, 1530 void (*printer) (void *, char *, ...), void *arg) 1531 { 1532 int code, id, len, olen; 1533 u_char *pstart, *optend; 1534 u_short cishort; 1535 eui64_t ifaceid; 1536 1537 if (plen < HEADERLEN) 1538 return 0; 1539 pstart = p; 1540 GETCHAR(code, p); 1541 GETCHAR(id, p); 1542 GETSHORT(len, p); 1543 if (len < HEADERLEN || len > plen) 1544 return 0; 1545 1546 if (code >= 1 && code <= sizeof(ipv6cp_codenames) / sizeof(char *)) 1547 printer(arg, " %s", ipv6cp_codenames[code-1]); 1548 else 1549 printer(arg, " code=0x%x", code); 1550 printer(arg, " id=0x%x", id); 1551 len -= HEADERLEN; 1552 switch (code) { 1553 case CONFREQ: 1554 case CONFACK: 1555 case CONFNAK: 1556 case CONFREJ: 1557 /* print option list */ 1558 while (len >= 2) { 1559 GETCHAR(code, p); 1560 GETCHAR(olen, p); 1561 p -= 2; 1562 if (olen < 2 || olen > len) { 1563 break; 1564 } 1565 printer(arg, " <"); 1566 len -= olen; 1567 optend = p + olen; 1568 switch (code) { 1569 case CI_COMPRESSTYPE: 1570 if (olen >= CILEN_COMPRESS) { 1571 p += 2; 1572 GETSHORT(cishort, p); 1573 printer(arg, "compress "); 1574 printer(arg, "0x%x", cishort); 1575 } 1576 break; 1577 case CI_IFACEID: 1578 if (olen == CILEN_IFACEID) { 1579 p += 2; 1580 eui64_get(ifaceid, p); 1581 printer(arg, "addr %s", llv6_ntoa(ifaceid)); 1582 } 1583 break; 1584 } 1585 while (p < optend) { 1586 GETCHAR(code, p); 1587 printer(arg, " %.2x", code); 1588 } 1589 printer(arg, ">"); 1590 } 1591 break; 1592 1593 case TERMACK: 1594 case TERMREQ: 1595 if (len > 0 && *p >= ' ' && *p < 0x7f) { 1596 printer(arg, " "); 1597 print_string((char *)p, len, printer, arg); 1598 p += len; 1599 len = 0; 1600 } 1601 break; 1602 } 1603 1604 /* print the rest of the bytes in the packet */ 1605 for (; len > 0; --len) { 1606 GETCHAR(code, p); 1607 printer(arg, " %.2x", code); 1608 } 1609 1610 return p - pstart; 1611 } 1612 1613 /* 1614 * ipv6_active_pkt - see if this IP packet is worth bringing the link up for. 1615 * We don't bring the link up for IP fragments or for TCP FIN packets 1616 * with no data. 1617 */ 1618 #define IP6_HDRLEN 40 /* bytes */ 1619 #define IP6_NHDR_FRAG 44 /* fragment IPv6 header */ 1620 #define TCP_HDRLEN 20 1621 #define TH_FIN 0x01 1622 1623 /* 1624 * We use these macros because the IP header may be at an odd address, 1625 * and some compilers might use word loads to get th_off or ip_hl. 1626 */ 1627 1628 #define get_ip6nh(x) (((unsigned char *)(x))[6]) 1629 #define get_tcpoff(x) (((unsigned char *)(x))[12] >> 4) 1630 #define get_tcpflags(x) (((unsigned char *)(x))[13]) 1631 1632 static int 1633 ipv6_active_pkt(u_char *pkt, int len) 1634 { 1635 u_char *tcp; 1636 1637 len -= PPP_HDRLEN; 1638 pkt += PPP_HDRLEN; 1639 if (len < IP6_HDRLEN) 1640 return 0; 1641 if (get_ip6nh(pkt) == IP6_NHDR_FRAG) 1642 return 0; 1643 if (get_ip6nh(pkt) != IPPROTO_TCP) 1644 return 1; 1645 if (len < IP6_HDRLEN + TCP_HDRLEN) 1646 return 0; 1647 tcp = pkt + IP6_HDRLEN; 1648 if ((get_tcpflags(tcp) & TH_FIN) != 0 && len == IP6_HDRLEN + get_tcpoff(tcp) * 4) 1649 return 0; 1650 return 1; 1651 } 1652