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