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