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.20 2004/11/13 02:28:15 paulus Exp $
    139  */
    140 
    141 #define RCSID	"$Id: ipv6cp.c,v 1.20 2004/11/13 02:28:15 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 <string.h>
    155 #include <unistd.h>
    156 #include <netdb.h>
    157 #include <sys/param.h>
    158 #include <sys/types.h>
    159 #include <sys/socket.h>
    160 #include <netinet/in.h>
    161 #include <arpa/inet.h>
    162 
    163 #include "pppd.h"
    164 #include "fsm.h"
    165 #include "ipcp.h"
    166 #include "ipv6cp.h"
    167 #include "magic.h"
    168 #include "pathnames.h"
    169 
    170 static const char rcsid[] = RCSID;
    171 
    172 /* global vars */
    173 ipv6cp_options ipv6cp_wantoptions[NUM_PPP];     /* Options that we want to request */
    174 ipv6cp_options ipv6cp_gotoptions[NUM_PPP];	/* Options that peer ack'd */
    175 ipv6cp_options ipv6cp_allowoptions[NUM_PPP];	/* Options we allow peer to request */
    176 ipv6cp_options ipv6cp_hisoptions[NUM_PPP];	/* Options that we ack'd */
    177 int no_ifaceid_neg = 0;
    178 
    179 /* local vars */
    180 static int ipv6cp_is_up;
    181 
    182 /*
    183  * Callbacks for fsm code.  (CI = Configuration Information)
    184  */
    185 static void ipv6cp_resetci __P((fsm *));	/* Reset our CI */
    186 static int  ipv6cp_cilen __P((fsm *));	        /* Return length of our CI */
    187 static void ipv6cp_addci __P((fsm *, u_char *, int *)); /* Add our CI */
    188 static int  ipv6cp_ackci __P((fsm *, u_char *, int));	/* Peer ack'd our CI */
    189 static int  ipv6cp_nakci __P((fsm *, u_char *, int, int));/* Peer nak'd our CI */
    190 static int  ipv6cp_rejci __P((fsm *, u_char *, int));	/* Peer rej'd our CI */
    191 static int  ipv6cp_reqci __P((fsm *, u_char *, int *, int)); /* Rcv CI */
    192 static void ipv6cp_up __P((fsm *));		/* We're UP */
    193 static void ipv6cp_down __P((fsm *));		/* We're DOWN */
    194 static void ipv6cp_finished __P((fsm *));	/* Don't need lower layer */
    195 
    196 fsm ipv6cp_fsm[NUM_PPP];		/* IPV6CP fsm structure */
    197 
    198 static fsm_callbacks ipv6cp_callbacks = { /* IPV6CP callback routines */
    199     ipv6cp_resetci,		/* Reset our Configuration Information */
    200     ipv6cp_cilen,		/* Length of our Configuration Information */
    201     ipv6cp_addci,		/* Add our Configuration Information */
    202     ipv6cp_ackci,		/* ACK our Configuration Information */
    203     ipv6cp_nakci,		/* NAK our Configuration Information */
    204     ipv6cp_rejci,		/* Reject our Configuration Information */
    205     ipv6cp_reqci,		/* Request peer's Configuration Information */
    206     ipv6cp_up,			/* Called when fsm reaches OPENED state */
    207     ipv6cp_down,		/* Called when fsm leaves OPENED state */
    208     NULL,			/* Called when we want the lower layer up */
    209     ipv6cp_finished,		/* Called when we want the lower layer down */
    210     NULL,			/* Called when Protocol-Reject received */
    211     NULL,			/* Retransmission is necessary */
    212     NULL,			/* Called to handle protocol-specific codes */
    213     "IPV6CP"			/* String name of protocol */
    214 };
    215 
    216 /*
    217  * Command-line options.
    218  */
    219 static int setifaceid __P((char **arg));
    220 static void printifaceid __P((option_t *,
    221 			      void (*)(void *, char *, ...), void *));
    222 
    223 static option_t ipv6cp_option_list[] = {
    224     { "ipv6", o_special, (void *)setifaceid,
    225       "Set interface identifiers for IPV6",
    226       OPT_A2PRINTER, (void *)printifaceid },
    227 
    228     { "+ipv6", o_bool, &ipv6cp_protent.enabled_flag,
    229       "Enable IPv6 and IPv6CP", OPT_PRIO | 1 },
    230     { "noipv6", o_bool, &ipv6cp_protent.enabled_flag,
    231       "Disable IPv6 and IPv6CP", OPT_PRIOSUB },
    232     { "-ipv6", o_bool, &ipv6cp_protent.enabled_flag,
    233       "Disable IPv6 and IPv6CP", OPT_PRIOSUB | OPT_ALIAS },
    234 
    235     { "ipv6cp-accept-local", o_bool, &ipv6cp_allowoptions[0].accept_local,
    236       "Accept peer's interface identifier for us", 1 },
    237 
    238     { "ipv6cp-use-ipaddr", o_bool, &ipv6cp_allowoptions[0].use_ip,
    239       "Use (default) IPv4 address as interface identifier", 1 },
    240 
    241 #if defined(SOL2) || defined(__linux__)
    242     { "ipv6cp-use-persistent", o_bool, &ipv6cp_wantoptions[0].use_persistent,
    243       "Use uniquely-available persistent value for link local address", 1 },
    244 #endif /* defined(SOL2) */
    245 
    246     { "ipv6cp-restart", o_int, &ipv6cp_fsm[0].timeouttime,
    247       "Set timeout for IPv6CP", OPT_PRIO },
    248     { "ipv6cp-max-terminate", o_int, &ipv6cp_fsm[0].maxtermtransmits,
    249       "Set max #xmits for term-reqs", OPT_PRIO },
    250     { "ipv6cp-max-configure", o_int, &ipv6cp_fsm[0].maxconfreqtransmits,
    251       "Set max #xmits for conf-reqs", OPT_PRIO },
    252     { "ipv6cp-max-failure", o_int, &ipv6cp_fsm[0].maxnakloops,
    253       "Set max #conf-naks for IPv6CP", OPT_PRIO },
    254 
    255    { NULL }
    256 };
    257 
    258 
    259 /*
    260  * Protocol entry points from main code.
    261  */
    262 static void ipv6cp_init __P((int));
    263 static void ipv6cp_open __P((int));
    264 static void ipv6cp_close __P((int, char *));
    265 static void ipv6cp_lowerup __P((int));
    266 static void ipv6cp_lowerdown __P((int));
    267 static void ipv6cp_input __P((int, u_char *, int));
    268 static void ipv6cp_protrej __P((int));
    269 static int  ipv6cp_printpkt __P((u_char *, int,
    270 			       void (*) __P((void *, char *, ...)), void *));
    271 static void ipv6_check_options __P((void));
    272 static int  ipv6_demand_conf __P((int));
    273 static int  ipv6_active_pkt __P((u_char *, int));
    274 
    275 struct protent ipv6cp_protent = {
    276     PPP_IPV6CP,
    277     ipv6cp_init,
    278     ipv6cp_input,
    279     ipv6cp_protrej,
    280     ipv6cp_lowerup,
    281     ipv6cp_lowerdown,
    282     ipv6cp_open,
    283     ipv6cp_close,
    284     ipv6cp_printpkt,
    285     NULL,
    286     0,
    287     "IPV6CP",
    288     "IPV6",
    289     ipv6cp_option_list,
    290     ipv6_check_options,
    291     ipv6_demand_conf,
    292     ipv6_active_pkt
    293 };
    294 
    295 static void ipv6cp_clear_addrs __P((int, eui64_t, eui64_t));
    296 static void ipv6cp_script __P((char *));
    297 static void ipv6cp_script_done __P((void *));
    298 
    299 /*
    300  * Lengths of configuration options.
    301  */
    302 #define CILEN_VOID	2
    303 #define CILEN_COMPRESS	4	/* length for RFC2023 compress opt. */
    304 #define CILEN_IFACEID   10	/* RFC2472, interface identifier    */
    305 
    306 #define CODENAME(x)	((x) == CONFACK ? "ACK" : \
    307 			 (x) == CONFNAK ? "NAK" : "REJ")
    308 
    309 /*
    310  * This state variable is used to ensure that we don't
    311  * run an ipcp-up/down script while one is already running.
    312  */
    313 static enum script_state {
    314     s_down,
    315     s_up,
    316 } ipv6cp_script_state;
    317 static pid_t ipv6cp_script_pid;
    318 
    319 /*
    320  * setifaceid - set the interface identifiers manually
    321  */
    322 static int
    323 setifaceid(argv)
    324     char **argv;
    325 {
    326     char *comma, *arg, c;
    327     ipv6cp_options *wo = &ipv6cp_wantoptions[0];
    328     struct in6_addr addr;
    329     static int prio_local, prio_remote;
    330 
    331 #define VALIDID(a) ( (((a).s6_addr32[0] == 0) && ((a).s6_addr32[1] == 0)) && \
    332 			(((a).s6_addr32[2] != 0) || ((a).s6_addr32[3] != 0)) )
    333 
    334     arg = *argv;
    335     if ((comma = strchr(arg, ',')) == NULL)
    336 	comma = arg + strlen(arg);
    337 
    338     /*
    339      * If comma first character, then no local identifier
    340      */
    341     if (comma != arg) {
    342 	c = *comma;
    343 	*comma = '\0';
    344 
    345 	if (inet_pton(AF_INET6, arg, &addr) == 0 || !VALIDID(addr)) {
    346 	    option_error("Illegal interface identifier (local): %s", arg);
    347 	    return 0;
    348 	}
    349 
    350 	if (option_priority >= prio_local) {
    351 	    eui64_copy(addr.s6_addr32[2], wo->ourid);
    352 	    wo->opt_local = 1;
    353 	    prio_local = option_priority;
    354 	}
    355 	*comma = c;
    356     }
    357 
    358     /*
    359      * If comma last character, the no remote identifier
    360      */
    361     if (*comma != 0 && *++comma != '\0') {
    362 	if (inet_pton(AF_INET6, comma, &addr) == 0 || !VALIDID(addr)) {
    363 	    option_error("Illegal interface identifier (remote): %s", comma);
    364 	    return 0;
    365 	}
    366 	if (option_priority >= prio_remote) {
    367 	    eui64_copy(addr.s6_addr32[2], wo->hisid);
    368 	    wo->opt_remote = 1;
    369 	    prio_remote = option_priority;
    370 	}
    371     }
    372 
    373     if (override_value("+ipv6", option_priority, option_source))
    374 	ipv6cp_protent.enabled_flag = 1;
    375     return 1;
    376 }
    377 
    378 char *llv6_ntoa(eui64_t ifaceid);
    379 
    380 static void
    381 printifaceid(opt, printer, arg)
    382     option_t *opt;
    383     void (*printer) __P((void *, char *, ...));
    384     void *arg;
    385 {
    386 	ipv6cp_options *wo = &ipv6cp_wantoptions[0];
    387 
    388 	if (wo->opt_local)
    389 		printer(arg, "%s", llv6_ntoa(wo->ourid));
    390 	printer(arg, ",");
    391 	if (wo->opt_remote)
    392 		printer(arg, "%s", llv6_ntoa(wo->hisid));
    393 }
    394 
    395 /*
    396  * Make a string representation of a network address.
    397  */
    398 char *
    399 llv6_ntoa(ifaceid)
    400     eui64_t ifaceid;
    401 {
    402     static char b[64];
    403 
    404     sprintf(b, "fe80::%s", eui64_ntoa(ifaceid));
    405     return b;
    406 }
    407 
    408 
    409 /*
    410  * ipv6cp_init - Initialize IPV6CP.
    411  */
    412 static void
    413 ipv6cp_init(unit)
    414     int unit;
    415 {
    416     fsm *f = &ipv6cp_fsm[unit];
    417     ipv6cp_options *wo = &ipv6cp_wantoptions[unit];
    418     ipv6cp_options *ao = &ipv6cp_allowoptions[unit];
    419 
    420     f->unit = unit;
    421     f->protocol = PPP_IPV6CP;
    422     f->callbacks = &ipv6cp_callbacks;
    423     fsm_init(&ipv6cp_fsm[unit]);
    424 
    425     memset(wo, 0, sizeof(*wo));
    426     memset(ao, 0, sizeof(*ao));
    427 
    428     wo->accept_local = 1;
    429     wo->neg_ifaceid = 1;
    430     ao->neg_ifaceid = 1;
    431 
    432 #ifdef IPV6CP_COMP
    433     wo->neg_vj = 1;
    434     ao->neg_vj = 1;
    435     wo->vj_protocol = IPV6CP_COMP;
    436 #endif
    437 
    438 }
    439 
    440 
    441 /*
    442  * ipv6cp_open - IPV6CP is allowed to come up.
    443  */
    444 static void
    445 ipv6cp_open(unit)
    446     int unit;
    447 {
    448     fsm_open(&ipv6cp_fsm[unit]);
    449 }
    450 
    451 
    452 /*
    453  * ipv6cp_close - Take IPV6CP down.
    454  */
    455 static void
    456 ipv6cp_close(unit, reason)
    457     int unit;
    458     char *reason;
    459 {
    460     fsm_close(&ipv6cp_fsm[unit], reason);
    461 }
    462 
    463 
    464 /*
    465  * ipv6cp_lowerup - The lower layer is up.
    466  */
    467 static void
    468 ipv6cp_lowerup(unit)
    469     int unit;
    470 {
    471     fsm_lowerup(&ipv6cp_fsm[unit]);
    472 }
    473 
    474 
    475 /*
    476  * ipv6cp_lowerdown - The lower layer is down.
    477  */
    478 static void
    479 ipv6cp_lowerdown(unit)
    480     int unit;
    481 {
    482     fsm_lowerdown(&ipv6cp_fsm[unit]);
    483 }
    484 
    485 
    486 /*
    487  * ipv6cp_input - Input IPV6CP packet.
    488  */
    489 static void
    490 ipv6cp_input(unit, p, len)
    491     int unit;
    492     u_char *p;
    493     int len;
    494 {
    495     fsm_input(&ipv6cp_fsm[unit], p, len);
    496 }
    497 
    498 
    499 /*
    500  * ipv6cp_protrej - A Protocol-Reject was received for IPV6CP.
    501  *
    502  * Pretend the lower layer went down, so we shut up.
    503  */
    504 static void
    505 ipv6cp_protrej(unit)
    506     int unit;
    507 {
    508     fsm_lowerdown(&ipv6cp_fsm[unit]);
    509 }
    510 
    511 
    512 /*
    513  * ipv6cp_resetci - Reset our CI.
    514  */
    515 static void
    516 ipv6cp_resetci(f)
    517     fsm *f;
    518 {
    519     ipv6cp_options *wo = &ipv6cp_wantoptions[f->unit];
    520     ipv6cp_options *go = &ipv6cp_gotoptions[f->unit];
    521 
    522     wo->req_ifaceid = wo->neg_ifaceid && ipv6cp_allowoptions[f->unit].neg_ifaceid;
    523 
    524     if (!wo->opt_local) {
    525 	eui64_magic_nz(wo->ourid);
    526     }
    527 
    528     *go = *wo;
    529     eui64_zero(go->hisid);	/* last proposed interface identifier */
    530 }
    531 
    532 
    533 /*
    534  * ipv6cp_cilen - Return length of our CI.
    535  */
    536 static int
    537 ipv6cp_cilen(f)
    538     fsm *f;
    539 {
    540     ipv6cp_options *go = &ipv6cp_gotoptions[f->unit];
    541 
    542 #define LENCIVJ(neg)		(neg ? CILEN_COMPRESS : 0)
    543 #define LENCIIFACEID(neg)	(neg ? CILEN_IFACEID : 0)
    544 
    545     return (LENCIIFACEID(go->neg_ifaceid) +
    546 	    LENCIVJ(go->neg_vj));
    547 }
    548 
    549 
    550 /*
    551  * ipv6cp_addci - Add our desired CIs to a packet.
    552  */
    553 static void
    554 ipv6cp_addci(f, ucp, lenp)
    555     fsm *f;
    556     u_char *ucp;
    557     int *lenp;
    558 {
    559     ipv6cp_options *go = &ipv6cp_gotoptions[f->unit];
    560     int len = *lenp;
    561 
    562 #define ADDCIVJ(opt, neg, val) \
    563     if (neg) { \
    564 	int vjlen = CILEN_COMPRESS; \
    565 	if (len >= vjlen) { \
    566 	    PUTCHAR(opt, ucp); \
    567 	    PUTCHAR(vjlen, ucp); \
    568 	    PUTSHORT(val, ucp); \
    569 	    len -= vjlen; \
    570 	} else \
    571 	    neg = 0; \
    572     }
    573 
    574 #define ADDCIIFACEID(opt, neg, val1) \
    575     if (neg) { \
    576 	int idlen = CILEN_IFACEID; \
    577 	if (len >= idlen) { \
    578 	    PUTCHAR(opt, ucp); \
    579 	    PUTCHAR(idlen, ucp); \
    580 	    eui64_put(val1, ucp); \
    581 	    len -= idlen; \
    582 	} else \
    583 	    neg = 0; \
    584     }
    585 
    586     ADDCIIFACEID(CI_IFACEID, go->neg_ifaceid, go->ourid);
    587 
    588     ADDCIVJ(CI_COMPRESSTYPE, go->neg_vj, go->vj_protocol);
    589 
    590     *lenp -= len;
    591 }
    592 
    593 
    594 /*
    595  * ipv6cp_ackci - Ack our CIs.
    596  *
    597  * Returns:
    598  *	0 - Ack was bad.
    599  *	1 - Ack was good.
    600  */
    601 static int
    602 ipv6cp_ackci(f, p, len)
    603     fsm *f;
    604     u_char *p;
    605     int len;
    606 {
    607     ipv6cp_options *go = &ipv6cp_gotoptions[f->unit];
    608     u_short cilen, citype, cishort;
    609     eui64_t ifaceid;
    610 
    611     /*
    612      * CIs must be in exactly the same order that we sent...
    613      * Check packet length and CI length at each step.
    614      * If we find any deviations, then this packet is bad.
    615      */
    616 
    617 #define ACKCIVJ(opt, neg, val) \
    618     if (neg) { \
    619 	int vjlen = CILEN_COMPRESS; \
    620 	if ((len -= vjlen) < 0) \
    621 	    goto bad; \
    622 	GETCHAR(citype, p); \
    623 	GETCHAR(cilen, p); \
    624 	if (cilen != vjlen || \
    625 	    citype != opt)  \
    626 	    goto bad; \
    627 	GETSHORT(cishort, p); \
    628 	if (cishort != val) \
    629 	    goto bad; \
    630     }
    631 
    632 #define ACKCIIFACEID(opt, neg, val1) \
    633     if (neg) { \
    634 	int idlen = CILEN_IFACEID; \
    635 	if ((len -= idlen) < 0) \
    636 	    goto bad; \
    637 	GETCHAR(citype, p); \
    638 	GETCHAR(cilen, p); \
    639 	if (cilen != idlen || \
    640 	    citype != opt) \
    641 	    goto bad; \
    642 	eui64_get(ifaceid, p); \
    643 	if (! eui64_equals(val1, ifaceid)) \
    644 	    goto bad; \
    645     }
    646 
    647     ACKCIIFACEID(CI_IFACEID, go->neg_ifaceid, go->ourid);
    648 
    649     ACKCIVJ(CI_COMPRESSTYPE, go->neg_vj, go->vj_protocol);
    650 
    651     /*
    652      * If there are any remaining CIs, then this packet is bad.
    653      */
    654     if (len != 0)
    655 	goto bad;
    656     return (1);
    657 
    658 bad:
    659     IPV6CPDEBUG(("ipv6cp_ackci: received bad Ack!"));
    660     return (0);
    661 }
    662 
    663 /*
    664  * ipv6cp_nakci - Peer has sent a NAK for some of our CIs.
    665  * This should not modify any state if the Nak is bad
    666  * or if IPV6CP is in the OPENED state.
    667  *
    668  * Returns:
    669  *	0 - Nak was bad.
    670  *	1 - Nak was good.
    671  */
    672 static int
    673 ipv6cp_nakci(f, p, len, treat_as_reject)
    674     fsm *f;
    675     u_char *p;
    676     int len;
    677     int treat_as_reject;
    678 {
    679     ipv6cp_options *go = &ipv6cp_gotoptions[f->unit];
    680     u_char citype, cilen, *next;
    681     u_short cishort;
    682     eui64_t ifaceid;
    683     ipv6cp_options no;		/* options we've seen Naks for */
    684     ipv6cp_options try;		/* options to request next time */
    685 
    686     BZERO(&no, sizeof(no));
    687     try = *go;
    688 
    689     /*
    690      * Any Nak'd CIs must be in exactly the same order that we sent.
    691      * Check packet length and CI length at each step.
    692      * If we find any deviations, then this packet is bad.
    693      */
    694 #define NAKCIIFACEID(opt, neg, code) \
    695     if (go->neg && \
    696 	len >= (cilen = CILEN_IFACEID) && \
    697 	p[1] == cilen && \
    698 	p[0] == opt) { \
    699 	len -= cilen; \
    700 	INCPTR(2, p); \
    701 	eui64_get(ifaceid, p); \
    702 	no.neg = 1; \
    703 	code \
    704     }
    705 
    706 #define NAKCIVJ(opt, neg, code) \
    707     if (go->neg && \
    708 	((cilen = p[1]) == CILEN_COMPRESS) && \
    709 	len >= cilen && \
    710 	p[0] == opt) { \
    711 	len -= cilen; \
    712 	INCPTR(2, p); \
    713 	GETSHORT(cishort, p); \
    714 	no.neg = 1; \
    715         code \
    716     }
    717 
    718     /*
    719      * Accept the peer's idea of {our,his} interface identifier, if different
    720      * from our idea, only if the accept_{local,remote} flag is set.
    721      */
    722     NAKCIIFACEID(CI_IFACEID, neg_ifaceid,
    723 		 if (treat_as_reject) {
    724 		     try.neg_ifaceid = 0;
    725 		 } else if (go->accept_local) {
    726 		     while (eui64_iszero(ifaceid) ||
    727 			    eui64_equals(ifaceid, go->hisid)) /* bad luck */
    728 			 eui64_magic(ifaceid);
    729 		     try.ourid = ifaceid;
    730 		     IPV6CPDEBUG(("local LL address %s", llv6_ntoa(ifaceid)));
    731 		 }
    732 		 );
    733 
    734 #ifdef IPV6CP_COMP
    735     NAKCIVJ(CI_COMPRESSTYPE, neg_vj,
    736 	    {
    737 		if (cishort == IPV6CP_COMP && !treat_as_reject) {
    738 		    try.vj_protocol = cishort;
    739 		} else {
    740 		    try.neg_vj = 0;
    741 		}
    742 	    }
    743 	    );
    744 #else
    745     NAKCIVJ(CI_COMPRESSTYPE, neg_vj,
    746 	    {
    747 		try.neg_vj = 0;
    748 	    }
    749 	    );
    750 #endif
    751 
    752     /*
    753      * There may be remaining CIs, if the peer is requesting negotiation
    754      * on an option that we didn't include in our request packet.
    755      * If they want to negotiate about interface identifier, we comply.
    756      * If they want us to ask for compression, we refuse.
    757      */
    758     while (len >= CILEN_VOID) {
    759 	GETCHAR(citype, p);
    760 	GETCHAR(cilen, p);
    761 	if ( cilen < CILEN_VOID || (len -= cilen) < 0 )
    762 	    goto bad;
    763 	next = p + cilen - 2;
    764 
    765 	switch (citype) {
    766 	case CI_COMPRESSTYPE:
    767 	    if (go->neg_vj || no.neg_vj ||
    768 		(cilen != CILEN_COMPRESS))
    769 		goto bad;
    770 	    no.neg_vj = 1;
    771 	    break;
    772 	case CI_IFACEID:
    773 	    if (go->neg_ifaceid || no.neg_ifaceid || cilen != CILEN_IFACEID)
    774 		goto bad;
    775 	    try.neg_ifaceid = 1;
    776 	    eui64_get(ifaceid, p);
    777 	    if (go->accept_local) {
    778 		while (eui64_iszero(ifaceid) ||
    779 		       eui64_equals(ifaceid, go->hisid)) /* bad luck */
    780 		    eui64_magic(ifaceid);
    781 		try.ourid = ifaceid;
    782 	    }
    783 	    no.neg_ifaceid = 1;
    784 	    break;
    785 	}
    786 	p = next;
    787     }
    788 
    789     /* If there is still anything left, this packet is bad. */
    790     if (len != 0)
    791 	goto bad;
    792 
    793     /*
    794      * OK, the Nak is good.  Now we can update state.
    795      */
    796     if (f->state != OPENED)
    797 	*go = try;
    798 
    799     return 1;
    800 
    801 bad:
    802     IPV6CPDEBUG(("ipv6cp_nakci: received bad Nak!"));
    803     return 0;
    804 }
    805 
    806 
    807 /*
    808  * ipv6cp_rejci - Reject some of our CIs.
    809  */
    810 static int
    811 ipv6cp_rejci(f, p, len)
    812     fsm *f;
    813     u_char *p;
    814     int len;
    815 {
    816     ipv6cp_options *go = &ipv6cp_gotoptions[f->unit];
    817     u_char cilen;
    818     u_short cishort;
    819     eui64_t ifaceid;
    820     ipv6cp_options try;		/* options to request next time */
    821 
    822     try = *go;
    823     /*
    824      * Any Rejected CIs must be in exactly the same order that we sent.
    825      * Check packet length and CI length at each step.
    826      * If we find any deviations, then this packet is bad.
    827      */
    828 #define REJCIIFACEID(opt, neg, val1) \
    829     if (go->neg && \
    830 	len >= (cilen = CILEN_IFACEID) && \
    831 	p[1] == cilen && \
    832 	p[0] == opt) { \
    833 	len -= cilen; \
    834 	INCPTR(2, p); \
    835 	eui64_get(ifaceid, p); \
    836 	/* Check rejected value. */ \
    837 	if (! eui64_equals(ifaceid, val1)) \
    838 	    goto bad; \
    839 	try.neg = 0; \
    840     }
    841 
    842 #define REJCIVJ(opt, neg, val) \
    843     if (go->neg && \
    844 	p[1] == CILEN_COMPRESS && \
    845 	len >= p[1] && \
    846 	p[0] == opt) { \
    847 	len -= p[1]; \
    848 	INCPTR(2, p); \
    849 	GETSHORT(cishort, p); \
    850 	/* Check rejected value. */  \
    851 	if (cishort != val) \
    852 	    goto bad; \
    853 	try.neg = 0; \
    854      }
    855 
    856     REJCIIFACEID(CI_IFACEID, neg_ifaceid, go->ourid);
    857 
    858     REJCIVJ(CI_COMPRESSTYPE, neg_vj, go->vj_protocol);
    859 
    860     /*
    861      * If there are any remaining CIs, then this packet is bad.
    862      */
    863     if (len != 0)
    864 	goto bad;
    865     /*
    866      * Now we can update state.
    867      */
    868     if (f->state != OPENED)
    869 	*go = try;
    870     return 1;
    871 
    872 bad:
    873     IPV6CPDEBUG(("ipv6cp_rejci: received bad Reject!"));
    874     return 0;
    875 }
    876 
    877 
    878 /*
    879  * ipv6cp_reqci - Check the peer's requested CIs and send appropriate response.
    880  *
    881  * Returns: CONFACK, CONFNAK or CONFREJ and input packet modified
    882  * appropriately.  If reject_if_disagree is non-zero, doesn't return
    883  * CONFNAK; returns CONFREJ if it can't return CONFACK.
    884  */
    885 static int
    886 ipv6cp_reqci(f, inp, len, reject_if_disagree)
    887     fsm *f;
    888     u_char *inp;		/* Requested CIs */
    889     int *len;			/* Length of requested CIs */
    890     int reject_if_disagree;
    891 {
    892     ipv6cp_options *wo = &ipv6cp_wantoptions[f->unit];
    893     ipv6cp_options *ho = &ipv6cp_hisoptions[f->unit];
    894     ipv6cp_options *ao = &ipv6cp_allowoptions[f->unit];
    895     ipv6cp_options *go = &ipv6cp_gotoptions[f->unit];
    896     u_char *cip, *next;		/* Pointer to current and next CIs */
    897     u_short cilen, citype;	/* Parsed len, type */
    898     u_short cishort;		/* Parsed short value */
    899     eui64_t ifaceid;		/* Parsed interface identifier */
    900     int rc = CONFACK;		/* Final packet return code */
    901     int orc;			/* Individual option return code */
    902     u_char *p;			/* Pointer to next char to parse */
    903     u_char *ucp = inp;		/* Pointer to current output char */
    904     int l = *len;		/* Length left */
    905 
    906     /*
    907      * Reset all his options.
    908      */
    909     BZERO(ho, sizeof(*ho));
    910 
    911     /*
    912      * Process all his options.
    913      */
    914     next = inp;
    915     while (l) {
    916 	orc = CONFACK;			/* Assume success */
    917 	cip = p = next;			/* Remember begining of CI */
    918 	if (l < 2 ||			/* Not enough data for CI header or */
    919 	    p[1] < 2 ||			/*  CI length too small or */
    920 	    p[1] > l) {			/*  CI length too big? */
    921 	    IPV6CPDEBUG(("ipv6cp_reqci: bad CI length!"));
    922 	    orc = CONFREJ;		/* Reject bad CI */
    923 	    cilen = l;			/* Reject till end of packet */
    924 	    l = 0;			/* Don't loop again */
    925 	    goto endswitch;
    926 	}
    927 	GETCHAR(citype, p);		/* Parse CI type */
    928 	GETCHAR(cilen, p);		/* Parse CI length */
    929 	l -= cilen;			/* Adjust remaining length */
    930 	next += cilen;			/* Step to next CI */
    931 
    932 	switch (citype) {		/* Check CI type */
    933 	case CI_IFACEID:
    934 	    IPV6CPDEBUG(("ipv6cp: received interface identifier "));
    935 
    936 	    if (!ao->neg_ifaceid ||
    937 		cilen != CILEN_IFACEID) {	/* Check CI length */
    938 		orc = CONFREJ;		/* Reject CI */
    939 		break;
    940 	    }
    941 
    942 	    /*
    943 	     * If he has no interface identifier, or if we both have same
    944 	     * identifier then NAK it with new idea.
    945 	     * In particular, if we don't know his identifier, but he does,
    946 	     * then accept it.
    947 	     */
    948 	    eui64_get(ifaceid, p);
    949 	    IPV6CPDEBUG(("(%s)", llv6_ntoa(ifaceid)));
    950 	    if (eui64_iszero(ifaceid) && eui64_iszero(go->ourid)) {
    951 		orc = CONFREJ;		/* Reject CI */
    952 		break;
    953 	    }
    954 	    if (!eui64_iszero(wo->hisid) &&
    955 		!eui64_equals(ifaceid, wo->hisid) &&
    956 		eui64_iszero(go->hisid)) {
    957 
    958 		orc = CONFNAK;
    959 		ifaceid = wo->hisid;
    960 		go->hisid = ifaceid;
    961 		DECPTR(sizeof(ifaceid), p);
    962 		eui64_put(ifaceid, p);
    963 	    } else
    964 	    if (eui64_iszero(ifaceid) || eui64_equals(ifaceid, go->ourid)) {
    965 		orc = CONFNAK;
    966 		if (eui64_iszero(go->hisid))	/* first time, try option */
    967 		    ifaceid = wo->hisid;
    968 		while (eui64_iszero(ifaceid) ||
    969 		       eui64_equals(ifaceid, go->ourid)) /* bad luck */
    970 		    eui64_magic(ifaceid);
    971 		go->hisid = ifaceid;
    972 		DECPTR(sizeof(ifaceid), p);
    973 		eui64_put(ifaceid, p);
    974 	    }
    975 
    976 	    ho->neg_ifaceid = 1;
    977 	    ho->hisid = ifaceid;
    978 	    break;
    979 
    980 	case CI_COMPRESSTYPE:
    981 	    IPV6CPDEBUG(("ipv6cp: received COMPRESSTYPE "));
    982 	    if (!ao->neg_vj ||
    983 		(cilen != CILEN_COMPRESS)) {
    984 		orc = CONFREJ;
    985 		break;
    986 	    }
    987 	    GETSHORT(cishort, p);
    988 	    IPV6CPDEBUG(("(%d)", cishort));
    989 
    990 #ifdef IPV6CP_COMP
    991 	    if (!(cishort == IPV6CP_COMP)) {
    992 		orc = CONFREJ;
    993 		break;
    994 	    }
    995 
    996 	    ho->neg_vj = 1;
    997 	    ho->vj_protocol = cishort;
    998 	    break;
    999 #else
   1000 	    orc = CONFREJ;
   1001 	    break;
   1002 #endif
   1003 
   1004 	default:
   1005 	    orc = CONFREJ;
   1006 	    break;
   1007 	}
   1008 
   1009 endswitch:
   1010 	IPV6CPDEBUG((" (%s)\n", CODENAME(orc)));
   1011 
   1012 	if (orc == CONFACK &&		/* Good CI */
   1013 	    rc != CONFACK)		/*  but prior CI wasnt? */
   1014 	    continue;			/* Don't send this one */
   1015 
   1016 	if (orc == CONFNAK) {		/* Nak this CI? */
   1017 	    if (reject_if_disagree)	/* Getting fed up with sending NAKs? */
   1018 		orc = CONFREJ;		/* Get tough if so */
   1019 	    else {
   1020 		if (rc == CONFREJ)	/* Rejecting prior CI? */
   1021 		    continue;		/* Don't send this one */
   1022 		if (rc == CONFACK) {	/* Ack'd all prior CIs? */
   1023 		    rc = CONFNAK;	/* Not anymore... */
   1024 		    ucp = inp;		/* Backup */
   1025 		}
   1026 	    }
   1027 	}
   1028 
   1029 	if (orc == CONFREJ &&		/* Reject this CI */
   1030 	    rc != CONFREJ) {		/*  but no prior ones? */
   1031 	    rc = CONFREJ;
   1032 	    ucp = inp;			/* Backup */
   1033 	}
   1034 
   1035 	/* Need to move CI? */
   1036 	if (ucp != cip)
   1037 	    BCOPY(cip, ucp, cilen);	/* Move it */
   1038 
   1039 	/* Update output pointer */
   1040 	INCPTR(cilen, ucp);
   1041     }
   1042 
   1043     /*
   1044      * If we aren't rejecting this packet, and we want to negotiate
   1045      * their identifier and they didn't send their identifier, then we
   1046      * send a NAK with a CI_IFACEID option appended.  We assume the
   1047      * input buffer is long enough that we can append the extra
   1048      * option safely.
   1049      */
   1050     if (rc != CONFREJ && !ho->neg_ifaceid &&
   1051 	wo->req_ifaceid && !reject_if_disagree) {
   1052 	if (rc == CONFACK) {
   1053 	    rc = CONFNAK;
   1054 	    ucp = inp;				/* reset pointer */
   1055 	    wo->req_ifaceid = 0;		/* don't ask again */
   1056 	}
   1057 	PUTCHAR(CI_IFACEID, ucp);
   1058 	PUTCHAR(CILEN_IFACEID, ucp);
   1059 	eui64_put(wo->hisid, ucp);
   1060     }
   1061 
   1062     *len = ucp - inp;			/* Compute output length */
   1063     IPV6CPDEBUG(("ipv6cp: returning Configure-%s", CODENAME(rc)));
   1064     return (rc);			/* Return final code */
   1065 }
   1066 
   1067 
   1068 /*
   1069  * ipv6_check_options - check that any IP-related options are OK,
   1070  * and assign appropriate defaults.
   1071  */
   1072 static void
   1073 ipv6_check_options()
   1074 {
   1075     ipv6cp_options *wo = &ipv6cp_wantoptions[0];
   1076 
   1077     if (!ipv6cp_protent.enabled_flag)
   1078 	return;
   1079 
   1080 #if defined(SOL2) || defined(__linux__)
   1081     /*
   1082      * Persistent link-local id is only used when user has not explicitly
   1083      * configure/hard-code the id
   1084      */
   1085     if ((wo->use_persistent) && (!wo->opt_local) && (!wo->opt_remote)) {
   1086 
   1087 	/*
   1088 	 * On systems where there are no Ethernet interfaces used, there
   1089 	 * may be other ways to obtain a persistent id. Right now, it
   1090 	 * will fall back to using magic [see eui64_magic] below when
   1091 	 * an EUI-48 from MAC address can't be obtained. Other possibilities
   1092 	 * include obtaining EEPROM serial numbers, or some other unique
   1093 	 * yet persistent number. On Sparc platforms, this is possible,
   1094 	 * but too bad there's no standards yet for x86 machines.
   1095 	 */
   1096 	if (ether_to_eui64(&wo->ourid)) {
   1097 	    wo->opt_local = 1;
   1098 	}
   1099     }
   1100 #endif
   1101 
   1102     if (!wo->opt_local) {	/* init interface identifier */
   1103 	if (wo->use_ip && eui64_iszero(wo->ourid)) {
   1104 	    eui64_setlo32(wo->ourid, ntohl(ipcp_wantoptions[0].ouraddr));
   1105 	    if (!eui64_iszero(wo->ourid))
   1106 		wo->opt_local = 1;
   1107 	}
   1108 
   1109 	while (eui64_iszero(wo->ourid))
   1110 	    eui64_magic(wo->ourid);
   1111     }
   1112 
   1113     if (!wo->opt_remote) {
   1114 	if (wo->use_ip && eui64_iszero(wo->hisid)) {
   1115 	    eui64_setlo32(wo->hisid, ntohl(ipcp_wantoptions[0].hisaddr));
   1116 	    if (!eui64_iszero(wo->hisid))
   1117 		wo->opt_remote = 1;
   1118 	}
   1119     }
   1120 
   1121     if (demand && (eui64_iszero(wo->ourid) || eui64_iszero(wo->hisid))) {
   1122 	option_error("local/remote LL address required for demand-dialling\n");
   1123 	exit(1);
   1124     }
   1125 }
   1126 
   1127 
   1128 /*
   1129  * ipv6_demand_conf - configure the interface as though
   1130  * IPV6CP were up, for use with dial-on-demand.
   1131  */
   1132 static int
   1133 ipv6_demand_conf(u)
   1134     int u;
   1135 {
   1136     ipv6cp_options *wo = &ipv6cp_wantoptions[u];
   1137 
   1138 #if defined(__linux__) || defined(SOL2) || (defined(SVR4) && (defined(SNI) || defined(__USLC__)))
   1139 #if defined(SOL2)
   1140     if (!sif6up(u))
   1141 	return 0;
   1142 #else
   1143     if (!sifup(u))
   1144 	return 0;
   1145 #endif /* defined(SOL2) */
   1146 #endif
   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 	/*
   1240 	 * Set LL addresses
   1241 	 */
   1242 #if !defined(__linux__) && !defined(SOL2) && !(defined(SVR4) && (defined(SNI) || defined(__USLC__)))
   1243 	if (!sif6addr(f->unit, go->ourid, ho->hisid)) {
   1244 	    if (debug)
   1245 		warn("sif6addr failed");
   1246 	    ipv6cp_close(f->unit, "Interface configuration failed");
   1247 	    return;
   1248 	}
   1249 #endif
   1250 
   1251 	/* bring the interface up for IPv6 */
   1252 #if defined(SOL2)
   1253 	if (!sif6up(f->unit)) {
   1254 	    if (debug)
   1255 		warn("sifup failed (IPV6)");
   1256 	    ipv6cp_close(f->unit, "Interface configuration failed");
   1257 	    return;
   1258 	}
   1259 #else
   1260 	if (!sifup(f->unit)) {
   1261 	    if (debug)
   1262 		warn("sifup failed (IPV6)");
   1263 	    ipv6cp_close(f->unit, "Interface configuration failed");
   1264 	    return;
   1265 	}
   1266 #endif /* defined(SOL2) */
   1267 
   1268 #if defined(__linux__) || defined(SOL2) || (defined(SVR4) && (defined(SNI) || defined(__USLC__)))
   1269 	if (!sif6addr(f->unit, go->ourid, ho->hisid)) {
   1270 	    if (debug)
   1271 		warn("sif6addr failed");
   1272 	    ipv6cp_close(f->unit, "Interface configuration failed");
   1273 	    return;
   1274 	}
   1275 #endif
   1276 	sifnpmode(f->unit, PPP_IPV6, NPMODE_PASS);
   1277 
   1278 	notice("local  LL address %s", llv6_ntoa(go->ourid));
   1279 	notice("remote LL address %s", llv6_ntoa(ho->hisid));
   1280     }
   1281 
   1282     np_up(f->unit, PPP_IPV6);
   1283     ipv6cp_is_up = 1;
   1284 
   1285     /*
   1286      * Execute the ipv6-up script, like this:
   1287      *	/etc/ppp/ipv6-up interface tty speed local-LL remote-LL
   1288      */
   1289     if (ipv6cp_script_state == s_down && ipv6cp_script_pid == 0) {
   1290 	ipv6cp_script_state = s_up;
   1291 	ipv6cp_script(_PATH_IPV6UP);
   1292     }
   1293 }
   1294 
   1295 
   1296 /*
   1297  * ipv6cp_down - IPV6CP has gone DOWN.
   1298  *
   1299  * Take the IPv6 network interface down, clear its addresses
   1300  * and delete routes through it.
   1301  */
   1302 static void
   1303 ipv6cp_down(f)
   1304     fsm *f;
   1305 {
   1306     IPV6CPDEBUG(("ipv6cp: down"));
   1307     update_link_stats(f->unit);
   1308     if (ipv6cp_is_up) {
   1309 	ipv6cp_is_up = 0;
   1310 	np_down(f->unit, PPP_IPV6);
   1311     }
   1312 #ifdef IPV6CP_COMP
   1313     sif6comp(f->unit, 0);
   1314 #endif
   1315 
   1316     /*
   1317      * If we are doing dial-on-demand, set the interface
   1318      * to queue up outgoing packets (for now).
   1319      */
   1320     if (demand) {
   1321 	sifnpmode(f->unit, PPP_IPV6, NPMODE_QUEUE);
   1322     } else {
   1323 	sifnpmode(f->unit, PPP_IPV6, NPMODE_DROP);
   1324 #if !defined(__linux__) && !(defined(SVR4) && (defined(SNI) || defined(__USLC)))
   1325 #if defined(SOL2)
   1326 	sif6down(f->unit);
   1327 #else
   1328 	sifdown(f->unit);
   1329 #endif /* defined(SOL2) */
   1330 #endif
   1331 	ipv6cp_clear_addrs(f->unit,
   1332 			   ipv6cp_gotoptions[f->unit].ourid,
   1333 			   ipv6cp_hisoptions[f->unit].hisid);
   1334 #if defined(__linux__) || (defined(SVR4) && (defined(SNI) || defined(__USLC)))
   1335 	sifdown(f->unit);
   1336 #endif
   1337     }
   1338 
   1339     /* Execute the ipv6-down script */
   1340     if (ipv6cp_script_state == s_up && ipv6cp_script_pid == 0) {
   1341 	ipv6cp_script_state = s_down;
   1342 	ipv6cp_script(_PATH_IPV6DOWN);
   1343     }
   1344 }
   1345 
   1346 
   1347 /*
   1348  * ipv6cp_clear_addrs() - clear the interface addresses, routes,
   1349  * proxy neighbour discovery entries, etc.
   1350  */
   1351 static void
   1352 ipv6cp_clear_addrs(unit, ourid, hisid)
   1353     int unit;
   1354     eui64_t ourid;
   1355     eui64_t hisid;
   1356 {
   1357     cif6addr(unit, ourid, hisid);
   1358 }
   1359 
   1360 
   1361 /*
   1362  * ipv6cp_finished - possibly shut down the lower layers.
   1363  */
   1364 static void
   1365 ipv6cp_finished(f)
   1366     fsm *f;
   1367 {
   1368     np_finished(f->unit, PPP_IPV6);
   1369 }
   1370 
   1371 
   1372 /*
   1373  * ipv6cp_script_done - called when the ipv6-up or ipv6-down script
   1374  * has finished.
   1375  */
   1376 static void
   1377 ipv6cp_script_done(arg)
   1378     void *arg;
   1379 {
   1380     ipv6cp_script_pid = 0;
   1381     switch (ipv6cp_script_state) {
   1382     case s_up:
   1383 	if (ipv6cp_fsm[0].state != OPENED) {
   1384 	    ipv6cp_script_state = s_down;
   1385 	    ipv6cp_script(_PATH_IPV6DOWN);
   1386 	}
   1387 	break;
   1388     case s_down:
   1389 	if (ipv6cp_fsm[0].state == OPENED) {
   1390 	    ipv6cp_script_state = s_up;
   1391 	    ipv6cp_script(_PATH_IPV6UP);
   1392 	}
   1393 	break;
   1394     }
   1395 }
   1396 
   1397 
   1398 /*
   1399  * ipv6cp_script - Execute a script with arguments
   1400  * interface-name tty-name speed local-LL remote-LL.
   1401  */
   1402 static void
   1403 ipv6cp_script(script)
   1404     char *script;
   1405 {
   1406     char strspeed[32], strlocal[32], strremote[32];
   1407     char *argv[8];
   1408 
   1409     sprintf(strspeed, "%d", baud_rate);
   1410     strcpy(strlocal, llv6_ntoa(ipv6cp_gotoptions[0].ourid));
   1411     strcpy(strremote, llv6_ntoa(ipv6cp_hisoptions[0].hisid));
   1412 
   1413     argv[0] = script;
   1414     argv[1] = ifname;
   1415     argv[2] = devnam;
   1416     argv[3] = strspeed;
   1417     argv[4] = strlocal;
   1418     argv[5] = strremote;
   1419     argv[6] = ipparam;
   1420     argv[7] = NULL;
   1421 
   1422     ipv6cp_script_pid = run_program(script, argv, 0, ipv6cp_script_done, NULL);
   1423 }
   1424 
   1425 /*
   1426  * ipv6cp_printpkt - print the contents of an IPV6CP packet.
   1427  */
   1428 static char *ipv6cp_codenames[] = {
   1429     "ConfReq", "ConfAck", "ConfNak", "ConfRej",
   1430     "TermReq", "TermAck", "CodeRej"
   1431 };
   1432 
   1433 static int
   1434 ipv6cp_printpkt(p, plen, printer, arg)
   1435     u_char *p;
   1436     int plen;
   1437     void (*printer) __P((void *, char *, ...));
   1438     void *arg;
   1439 {
   1440     int code, id, len, olen;
   1441     u_char *pstart, *optend;
   1442     u_short cishort;
   1443     eui64_t ifaceid;
   1444 
   1445     if (plen < HEADERLEN)
   1446 	return 0;
   1447     pstart = p;
   1448     GETCHAR(code, p);
   1449     GETCHAR(id, p);
   1450     GETSHORT(len, p);
   1451     if (len < HEADERLEN || len > plen)
   1452 	return 0;
   1453 
   1454     if (code >= 1 && code <= sizeof(ipv6cp_codenames) / sizeof(char *))
   1455 	printer(arg, " %s", ipv6cp_codenames[code-1]);
   1456     else
   1457 	printer(arg, " code=0x%x", code);
   1458     printer(arg, " id=0x%x", id);
   1459     len -= HEADERLEN;
   1460     switch (code) {
   1461     case CONFREQ:
   1462     case CONFACK:
   1463     case CONFNAK:
   1464     case CONFREJ:
   1465 	/* print option list */
   1466 	while (len >= 2) {
   1467 	    GETCHAR(code, p);
   1468 	    GETCHAR(olen, p);
   1469 	    p -= 2;
   1470 	    if (olen < 2 || olen > len) {
   1471 		break;
   1472 	    }
   1473 	    printer(arg, " <");
   1474 	    len -= olen;
   1475 	    optend = p + olen;
   1476 	    switch (code) {
   1477 	    case CI_COMPRESSTYPE:
   1478 		if (olen >= CILEN_COMPRESS) {
   1479 		    p += 2;
   1480 		    GETSHORT(cishort, p);
   1481 		    printer(arg, "compress ");
   1482 		    printer(arg, "0x%x", cishort);
   1483 		}
   1484 		break;
   1485 	    case CI_IFACEID:
   1486 		if (olen == CILEN_IFACEID) {
   1487 		    p += 2;
   1488 		    eui64_get(ifaceid, p);
   1489 		    printer(arg, "addr %s", llv6_ntoa(ifaceid));
   1490 		}
   1491 		break;
   1492 	    }
   1493 	    while (p < optend) {
   1494 		GETCHAR(code, p);
   1495 		printer(arg, " %.2x", code);
   1496 	    }
   1497 	    printer(arg, ">");
   1498 	}
   1499 	break;
   1500 
   1501     case TERMACK:
   1502     case TERMREQ:
   1503 	if (len > 0 && *p >= ' ' && *p < 0x7f) {
   1504 	    printer(arg, " ");
   1505 	    print_string((char *)p, len, printer, arg);
   1506 	    p += len;
   1507 	    len = 0;
   1508 	}
   1509 	break;
   1510     }
   1511 
   1512     /* print the rest of the bytes in the packet */
   1513     for (; len > 0; --len) {
   1514 	GETCHAR(code, p);
   1515 	printer(arg, " %.2x", code);
   1516     }
   1517 
   1518     return p - pstart;
   1519 }
   1520 
   1521 /*
   1522  * ipv6_active_pkt - see if this IP packet is worth bringing the link up for.
   1523  * We don't bring the link up for IP fragments or for TCP FIN packets
   1524  * with no data.
   1525  */
   1526 #define IP6_HDRLEN	40	/* bytes */
   1527 #define IP6_NHDR_FRAG	44	/* fragment IPv6 header */
   1528 #define TCP_HDRLEN	20
   1529 #define TH_FIN		0x01
   1530 
   1531 /*
   1532  * We use these macros because the IP header may be at an odd address,
   1533  * and some compilers might use word loads to get th_off or ip_hl.
   1534  */
   1535 
   1536 #define get_ip6nh(x)	(((unsigned char *)(x))[6])
   1537 #define get_tcpoff(x)	(((unsigned char *)(x))[12] >> 4)
   1538 #define get_tcpflags(x)	(((unsigned char *)(x))[13])
   1539 
   1540 static int
   1541 ipv6_active_pkt(pkt, len)
   1542     u_char *pkt;
   1543     int len;
   1544 {
   1545     u_char *tcp;
   1546 
   1547     len -= PPP_HDRLEN;
   1548     pkt += PPP_HDRLEN;
   1549     if (len < IP6_HDRLEN)
   1550 	return 0;
   1551     if (get_ip6nh(pkt) == IP6_NHDR_FRAG)
   1552 	return 0;
   1553     if (get_ip6nh(pkt) != IPPROTO_TCP)
   1554 	return 1;
   1555     if (len < IP6_HDRLEN + TCP_HDRLEN)
   1556 	return 0;
   1557     tcp = pkt + IP6_HDRLEN;
   1558     if ((get_tcpflags(tcp) & TH_FIN) != 0 && len == IP6_HDRLEN + get_tcpoff(tcp) * 4)
   1559 	return 0;
   1560     return 1;
   1561 }
   1562