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