]> git.ozlabs.org Git - ppp.git/blob - pppd/ipv6cp.c
Patch from Robert Vogelgesang:
[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  * $Id: ipv6cp.c,v 1.19 2004/01/13 03:59:37 paulus Exp $ 
139  */
140
141 #define RCSID   "$Id: ipv6cp.c,v 1.19 2004/01/13 03:59:37 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));   /* 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)
674     fsm *f;
675     u_char *p;
676     int len;
677 {
678     ipv6cp_options *go = &ipv6cp_gotoptions[f->unit];
679     u_char citype, cilen, *next;
680     u_short cishort;
681     eui64_t ifaceid;
682     ipv6cp_options no;          /* options we've seen Naks for */
683     ipv6cp_options try;         /* options to request next time */
684
685     BZERO(&no, sizeof(no));
686     try = *go;
687
688     /*
689      * Any Nak'd CIs must be in exactly the same order that we sent.
690      * Check packet length and CI length at each step.
691      * If we find any deviations, then this packet is bad.
692      */
693 #define NAKCIIFACEID(opt, neg, code) \
694     if (go->neg && \
695         len >= (cilen = CILEN_IFACEID) && \
696         p[1] == cilen && \
697         p[0] == opt) { \
698         len -= cilen; \
699         INCPTR(2, p); \
700         eui64_get(ifaceid, p); \
701         no.neg = 1; \
702         code \
703     }
704
705 #define NAKCIVJ(opt, neg, code) \
706     if (go->neg && \
707         ((cilen = p[1]) == CILEN_COMPRESS) && \
708         len >= cilen && \
709         p[0] == opt) { \
710         len -= cilen; \
711         INCPTR(2, p); \
712         GETSHORT(cishort, p); \
713         no.neg = 1; \
714         code \
715     }
716
717     /*
718      * Accept the peer's idea of {our,his} interface identifier, if different
719      * from our idea, only if the accept_{local,remote} flag is set.
720      */
721     NAKCIIFACEID(CI_IFACEID, neg_ifaceid,
722               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) {
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(f, p, len)
809     fsm *f;
810     u_char *p;
811     int len;
812 {
813     ipv6cp_options *go = &ipv6cp_gotoptions[f->unit];
814     u_char cilen;
815     u_short cishort;
816     eui64_t ifaceid;
817     ipv6cp_options try;         /* options to request next time */
818
819     try = *go;
820     /*
821      * Any Rejected CIs must be in exactly the same order that we sent.
822      * Check packet length and CI length at each step.
823      * If we find any deviations, then this packet is bad.
824      */
825 #define REJCIIFACEID(opt, neg, val1) \
826     if (go->neg && \
827         len >= (cilen = CILEN_IFACEID) && \
828         p[1] == cilen && \
829         p[0] == opt) { \
830         len -= cilen; \
831         INCPTR(2, p); \
832         eui64_get(ifaceid, p); \
833         /* Check rejected value. */ \
834         if (! eui64_equals(ifaceid, val1)) \
835             goto bad; \
836         try.neg = 0; \
837     }
838
839 #define REJCIVJ(opt, neg, val) \
840     if (go->neg && \
841         p[1] == CILEN_COMPRESS && \
842         len >= p[1] && \
843         p[0] == opt) { \
844         len -= p[1]; \
845         INCPTR(2, p); \
846         GETSHORT(cishort, p); \
847         /* Check rejected value. */  \
848         if (cishort != val) \
849             goto bad; \
850         try.neg = 0; \
851      }
852
853     REJCIIFACEID(CI_IFACEID, neg_ifaceid, go->ourid);
854
855     REJCIVJ(CI_COMPRESSTYPE, neg_vj, go->vj_protocol);
856
857     /*
858      * If there are any remaining CIs, then this packet is bad.
859      */
860     if (len != 0)
861         goto bad;
862     /*
863      * Now we can update state.
864      */
865     if (f->state != OPENED)
866         *go = try;
867     return 1;
868
869 bad:
870     IPV6CPDEBUG(("ipv6cp_rejci: received bad Reject!"));
871     return 0;
872 }
873
874
875 /*
876  * ipv6cp_reqci - Check the peer's requested CIs and send appropriate response.
877  *
878  * Returns: CONFACK, CONFNAK or CONFREJ and input packet modified
879  * appropriately.  If reject_if_disagree is non-zero, doesn't return
880  * CONFNAK; returns CONFREJ if it can't return CONFACK.
881  */
882 static int
883 ipv6cp_reqci(f, inp, len, reject_if_disagree)
884     fsm *f;
885     u_char *inp;                /* Requested CIs */
886     int *len;                   /* Length of requested CIs */
887     int reject_if_disagree;
888 {
889     ipv6cp_options *wo = &ipv6cp_wantoptions[f->unit];
890     ipv6cp_options *ho = &ipv6cp_hisoptions[f->unit];
891     ipv6cp_options *ao = &ipv6cp_allowoptions[f->unit];
892     ipv6cp_options *go = &ipv6cp_gotoptions[f->unit];
893     u_char *cip, *next;         /* Pointer to current and next CIs */
894     u_short cilen, citype;      /* Parsed len, type */
895     u_short cishort;            /* Parsed short value */
896     eui64_t ifaceid;            /* Parsed interface identifier */
897     int rc = CONFACK;           /* Final packet return code */
898     int orc;                    /* Individual option return code */
899     u_char *p;                  /* Pointer to next char to parse */
900     u_char *ucp = inp;          /* Pointer to current output char */
901     int l = *len;               /* Length left */
902
903     /*
904      * Reset all his options.
905      */
906     BZERO(ho, sizeof(*ho));
907     
908     /*
909      * Process all his options.
910      */
911     next = inp;
912     while (l) {
913         orc = CONFACK;                  /* Assume success */
914         cip = p = next;                 /* Remember begining of CI */
915         if (l < 2 ||                    /* Not enough data for CI header or */
916             p[1] < 2 ||                 /*  CI length too small or */
917             p[1] > l) {                 /*  CI length too big? */
918             IPV6CPDEBUG(("ipv6cp_reqci: bad CI length!"));
919             orc = CONFREJ;              /* Reject bad CI */
920             cilen = l;                  /* Reject till end of packet */
921             l = 0;                      /* Don't loop again */
922             goto endswitch;
923         }
924         GETCHAR(citype, p);             /* Parse CI type */
925         GETCHAR(cilen, p);              /* Parse CI length */
926         l -= cilen;                     /* Adjust remaining length */
927         next += cilen;                  /* Step to next CI */
928
929         switch (citype) {               /* Check CI type */
930         case CI_IFACEID:
931             IPV6CPDEBUG(("ipv6cp: received interface identifier "));
932
933             if (!ao->neg_ifaceid ||
934                 cilen != CILEN_IFACEID) {       /* Check CI length */
935                 orc = CONFREJ;          /* Reject CI */
936                 break;
937             }
938
939             /*
940              * If he has no interface identifier, or if we both have same 
941              * identifier then NAK it with new idea.
942              * In particular, if we don't know his identifier, but he does,
943              * then accept it.
944              */
945             eui64_get(ifaceid, p);
946             IPV6CPDEBUG(("(%s)", llv6_ntoa(ifaceid)));
947             if (eui64_iszero(ifaceid) && eui64_iszero(go->ourid)) {
948                 orc = CONFREJ;          /* Reject CI */
949                 break;
950             }
951             if (!eui64_iszero(wo->hisid) && 
952                 !eui64_equals(ifaceid, wo->hisid) && 
953                 eui64_iszero(go->hisid)) {
954                     
955                 orc = CONFNAK;
956                 ifaceid = wo->hisid;
957                 go->hisid = ifaceid;
958                 DECPTR(sizeof(ifaceid), p);
959                 eui64_put(ifaceid, p);
960             } else
961             if (eui64_iszero(ifaceid) || eui64_equals(ifaceid, go->ourid)) {
962                 orc = CONFNAK;
963                 if (eui64_iszero(go->hisid))    /* first time, try option */
964                     ifaceid = wo->hisid;
965                 while (eui64_iszero(ifaceid) || 
966                        eui64_equals(ifaceid, go->ourid)) /* bad luck */
967                     eui64_magic(ifaceid);
968                 go->hisid = ifaceid;
969                 DECPTR(sizeof(ifaceid), p);
970                 eui64_put(ifaceid, p);
971             }
972
973             ho->neg_ifaceid = 1;
974             ho->hisid = ifaceid;
975             break;
976
977         case CI_COMPRESSTYPE:
978             IPV6CPDEBUG(("ipv6cp: received COMPRESSTYPE "));
979             if (!ao->neg_vj ||
980                 (cilen != CILEN_COMPRESS)) {
981                 orc = CONFREJ;
982                 break;
983             }
984             GETSHORT(cishort, p);
985             IPV6CPDEBUG(("(%d)", cishort));
986
987 #ifdef IPV6CP_COMP
988             if (!(cishort == IPV6CP_COMP)) {
989                 orc = CONFREJ;
990                 break;
991             }
992
993             ho->neg_vj = 1;
994             ho->vj_protocol = cishort;
995             break;
996 #else
997             orc = CONFREJ;
998             break;
999 #endif
1000
1001         default:
1002             orc = CONFREJ;
1003             break;
1004         }
1005
1006 endswitch:
1007         IPV6CPDEBUG((" (%s)\n", CODENAME(orc)));
1008
1009         if (orc == CONFACK &&           /* Good CI */
1010             rc != CONFACK)              /*  but prior CI wasnt? */
1011             continue;                   /* Don't send this one */
1012
1013         if (orc == CONFNAK) {           /* Nak this CI? */
1014             if (reject_if_disagree)     /* Getting fed up with sending NAKs? */
1015                 orc = CONFREJ;          /* Get tough if so */
1016             else {
1017                 if (rc == CONFREJ)      /* Rejecting prior CI? */
1018                     continue;           /* Don't send this one */
1019                 if (rc == CONFACK) {    /* Ack'd all prior CIs? */
1020                     rc = CONFNAK;       /* Not anymore... */
1021                     ucp = inp;          /* Backup */
1022                 }
1023             }
1024         }
1025
1026         if (orc == CONFREJ &&           /* Reject this CI */
1027             rc != CONFREJ) {            /*  but no prior ones? */
1028             rc = CONFREJ;
1029             ucp = inp;                  /* Backup */
1030         }
1031
1032         /* Need to move CI? */
1033         if (ucp != cip)
1034             BCOPY(cip, ucp, cilen);     /* Move it */
1035
1036         /* Update output pointer */
1037         INCPTR(cilen, ucp);
1038     }
1039
1040     /*
1041      * If we aren't rejecting this packet, and we want to negotiate
1042      * their identifier and they didn't send their identifier, then we
1043      * send a NAK with a CI_IFACEID option appended.  We assume the
1044      * input buffer is long enough that we can append the extra
1045      * option safely.
1046      */
1047     if (rc != CONFREJ && !ho->neg_ifaceid &&
1048         wo->req_ifaceid && !reject_if_disagree) {
1049         if (rc == CONFACK) {
1050             rc = CONFNAK;
1051             ucp = inp;                          /* reset pointer */
1052             wo->req_ifaceid = 0;                /* don't ask again */
1053         }
1054         PUTCHAR(CI_IFACEID, ucp);
1055         PUTCHAR(CILEN_IFACEID, ucp);
1056         eui64_put(wo->hisid, ucp);
1057     }
1058
1059     *len = ucp - inp;                   /* Compute output length */
1060     IPV6CPDEBUG(("ipv6cp: returning Configure-%s", CODENAME(rc)));
1061     return (rc);                        /* Return final code */
1062 }
1063
1064
1065 /*
1066  * ipv6_check_options - check that any IP-related options are OK,
1067  * and assign appropriate defaults.
1068  */
1069 static void
1070 ipv6_check_options()
1071 {
1072     ipv6cp_options *wo = &ipv6cp_wantoptions[0];
1073
1074     if (!ipv6cp_protent.enabled_flag)
1075         return;
1076
1077 #if defined(SOL2) || defined(__linux__)
1078     /*
1079      * Persistent link-local id is only used when user has not explicitly
1080      * configure/hard-code the id
1081      */
1082     if ((wo->use_persistent) && (!wo->opt_local) && (!wo->opt_remote)) {
1083
1084         /* 
1085          * On systems where there are no Ethernet interfaces used, there
1086          * may be other ways to obtain a persistent id. Right now, it
1087          * will fall back to using magic [see eui64_magic] below when
1088          * an EUI-48 from MAC address can't be obtained. Other possibilities
1089          * include obtaining EEPROM serial numbers, or some other unique
1090          * yet persistent number. On Sparc platforms, this is possible,
1091          * but too bad there's no standards yet for x86 machines.
1092          */
1093         if (ether_to_eui64(&wo->ourid)) {
1094             wo->opt_local = 1;
1095         }
1096     }
1097 #endif
1098
1099     if (!wo->opt_local) {       /* init interface identifier */
1100         if (wo->use_ip && eui64_iszero(wo->ourid)) {
1101             eui64_setlo32(wo->ourid, ntohl(ipcp_wantoptions[0].ouraddr));
1102             if (!eui64_iszero(wo->ourid))
1103                 wo->opt_local = 1;
1104         }
1105         
1106         while (eui64_iszero(wo->ourid))
1107             eui64_magic(wo->ourid);
1108     }
1109
1110     if (!wo->opt_remote) {
1111         if (wo->use_ip && eui64_iszero(wo->hisid)) {
1112             eui64_setlo32(wo->hisid, ntohl(ipcp_wantoptions[0].hisaddr));
1113             if (!eui64_iszero(wo->hisid))
1114                 wo->opt_remote = 1;
1115         }
1116     }
1117
1118     if (demand && (eui64_iszero(wo->ourid) || eui64_iszero(wo->hisid))) {
1119         option_error("local/remote LL address required for demand-dialling\n");
1120         exit(1);
1121     }
1122 }
1123
1124
1125 /*
1126  * ipv6_demand_conf - configure the interface as though
1127  * IPV6CP were up, for use with dial-on-demand.
1128  */
1129 static int
1130 ipv6_demand_conf(u)
1131     int u;
1132 {
1133     ipv6cp_options *wo = &ipv6cp_wantoptions[u];
1134
1135 #if defined(__linux__) || defined(SOL2) || (defined(SVR4) && (defined(SNI) || defined(__USLC__)))
1136 #if defined(SOL2)
1137     if (!sif6up(u))
1138         return 0;
1139 #else
1140     if (!sifup(u))
1141         return 0;
1142 #endif /* defined(SOL2) */
1143 #endif    
1144     if (!sif6addr(u, wo->ourid, wo->hisid))
1145         return 0;
1146 #if !defined(__linux__) && !(defined(SVR4) && (defined(SNI) || defined(__USLC__)))
1147     if (!sifup(u))
1148         return 0;
1149 #endif
1150     if (!sifnpmode(u, PPP_IPV6, NPMODE_QUEUE))
1151         return 0;
1152
1153     notice("ipv6_demand_conf");
1154     notice("local  LL address %s", llv6_ntoa(wo->ourid));
1155     notice("remote LL address %s", llv6_ntoa(wo->hisid));
1156
1157     return 1;
1158 }
1159
1160
1161 /*
1162  * ipv6cp_up - IPV6CP has come UP.
1163  *
1164  * Configure the IPv6 network interface appropriately and bring it up.
1165  */
1166 static void
1167 ipv6cp_up(f)
1168     fsm *f;
1169 {
1170     ipv6cp_options *ho = &ipv6cp_hisoptions[f->unit];
1171     ipv6cp_options *go = &ipv6cp_gotoptions[f->unit];
1172     ipv6cp_options *wo = &ipv6cp_wantoptions[f->unit];
1173
1174     IPV6CPDEBUG(("ipv6cp: up"));
1175
1176     /*
1177      * We must have a non-zero LL address for both ends of the link.
1178      */
1179     if (!ho->neg_ifaceid)
1180         ho->hisid = wo->hisid;
1181
1182     if(!no_ifaceid_neg) {
1183         if (eui64_iszero(ho->hisid)) {
1184             error("Could not determine remote LL address");
1185             ipv6cp_close(f->unit, "Could not determine remote LL address");
1186             return;
1187         }
1188         if (eui64_iszero(go->ourid)) {
1189             error("Could not determine local LL address");
1190             ipv6cp_close(f->unit, "Could not determine local LL address");
1191             return;
1192         }
1193         if (eui64_equals(go->ourid, ho->hisid)) {
1194             error("local and remote LL addresses are equal");
1195             ipv6cp_close(f->unit, "local and remote LL addresses are equal");
1196             return;
1197         }
1198     }
1199     script_setenv("LLLOCAL", llv6_ntoa(go->ourid), 0);
1200     script_setenv("LLREMOTE", llv6_ntoa(ho->hisid), 0);
1201
1202 #ifdef IPV6CP_COMP
1203     /* set tcp compression */
1204     sif6comp(f->unit, ho->neg_vj);
1205 #endif
1206
1207     /*
1208      * If we are doing dial-on-demand, the interface is already
1209      * configured, so we put out any saved-up packets, then set the
1210      * interface to pass IPv6 packets.
1211      */
1212     if (demand) {
1213         if (! eui64_equals(go->ourid, wo->ourid) || 
1214             ! eui64_equals(ho->hisid, wo->hisid)) {
1215             if (! eui64_equals(go->ourid, wo->ourid))
1216                 warn("Local LL address changed to %s", 
1217                      llv6_ntoa(go->ourid));
1218             if (! eui64_equals(ho->hisid, wo->hisid))
1219                 warn("Remote LL address changed to %s", 
1220                      llv6_ntoa(ho->hisid));
1221             ipv6cp_clear_addrs(f->unit, go->ourid, ho->hisid);
1222
1223             /* Set the interface to the new addresses */
1224             if (!sif6addr(f->unit, go->ourid, ho->hisid)) {
1225                 if (debug)
1226                     warn("sif6addr failed");
1227                 ipv6cp_close(f->unit, "Interface configuration failed");
1228                 return;
1229             }
1230
1231         }
1232         demand_rexmit(PPP_IPV6);
1233         sifnpmode(f->unit, PPP_IPV6, NPMODE_PASS);
1234
1235     } else {
1236         /*
1237          * Set LL addresses
1238          */
1239 #if !defined(__linux__) && !defined(SOL2) && !(defined(SVR4) && (defined(SNI) || defined(__USLC__)))
1240         if (!sif6addr(f->unit, go->ourid, ho->hisid)) {
1241             if (debug)
1242                 warn("sif6addr failed");
1243             ipv6cp_close(f->unit, "Interface configuration failed");
1244             return;
1245         }
1246 #endif
1247
1248         /* bring the interface up for IPv6 */
1249 #if defined(SOL2)
1250         if (!sif6up(f->unit)) {
1251             if (debug)
1252                 warn("sifup failed (IPV6)");
1253             ipv6cp_close(f->unit, "Interface configuration failed");
1254             return;
1255         }
1256 #else
1257         if (!sifup(f->unit)) {
1258             if (debug)
1259                 warn("sifup failed (IPV6)");
1260             ipv6cp_close(f->unit, "Interface configuration failed");
1261             return;
1262         }
1263 #endif /* defined(SOL2) */
1264
1265 #if defined(__linux__) || defined(SOL2) || (defined(SVR4) && (defined(SNI) || defined(__USLC__)))
1266         if (!sif6addr(f->unit, go->ourid, ho->hisid)) {
1267             if (debug)
1268                 warn("sif6addr failed");
1269             ipv6cp_close(f->unit, "Interface configuration failed");
1270             return;
1271         }
1272 #endif
1273         sifnpmode(f->unit, PPP_IPV6, NPMODE_PASS);
1274
1275         notice("local  LL address %s", llv6_ntoa(go->ourid));
1276         notice("remote LL address %s", llv6_ntoa(ho->hisid));
1277     }
1278
1279     np_up(f->unit, PPP_IPV6);
1280     ipv6cp_is_up = 1;
1281
1282     /*
1283      * Execute the ipv6-up script, like this:
1284      *  /etc/ppp/ipv6-up interface tty speed local-LL remote-LL
1285      */
1286     if (ipv6cp_script_state == s_down && ipv6cp_script_pid == 0) {
1287         ipv6cp_script_state = s_up;
1288         ipv6cp_script(_PATH_IPV6UP);
1289     }
1290 }
1291
1292
1293 /*
1294  * ipv6cp_down - IPV6CP has gone DOWN.
1295  *
1296  * Take the IPv6 network interface down, clear its addresses
1297  * and delete routes through it.
1298  */
1299 static void
1300 ipv6cp_down(f)
1301     fsm *f;
1302 {
1303     IPV6CPDEBUG(("ipv6cp: down"));
1304     update_link_stats(f->unit);
1305     if (ipv6cp_is_up) {
1306         ipv6cp_is_up = 0;
1307         np_down(f->unit, PPP_IPV6);
1308     }
1309 #ifdef IPV6CP_COMP
1310     sif6comp(f->unit, 0);
1311 #endif
1312
1313     /*
1314      * If we are doing dial-on-demand, set the interface
1315      * to queue up outgoing packets (for now).
1316      */
1317     if (demand) {
1318         sifnpmode(f->unit, PPP_IPV6, NPMODE_QUEUE);
1319     } else {
1320         sifnpmode(f->unit, PPP_IPV6, NPMODE_DROP);
1321 #if !defined(__linux__) && !(defined(SVR4) && (defined(SNI) || defined(__USLC)))
1322 #if defined(SOL2)
1323         sif6down(f->unit);
1324 #else
1325         sifdown(f->unit);
1326 #endif /* defined(SOL2) */
1327 #endif
1328         ipv6cp_clear_addrs(f->unit, 
1329                            ipv6cp_gotoptions[f->unit].ourid,
1330                            ipv6cp_hisoptions[f->unit].hisid);
1331 #if defined(__linux__) || (defined(SVR4) && (defined(SNI) || defined(__USLC)))
1332         sifdown(f->unit);
1333 #endif
1334     }
1335
1336     /* Execute the ipv6-down script */
1337     if (ipv6cp_script_state == s_up && ipv6cp_script_pid == 0) {
1338         ipv6cp_script_state = s_down;
1339         ipv6cp_script(_PATH_IPV6DOWN);
1340     }
1341 }
1342
1343
1344 /*
1345  * ipv6cp_clear_addrs() - clear the interface addresses, routes,
1346  * proxy neighbour discovery entries, etc.
1347  */
1348 static void
1349 ipv6cp_clear_addrs(unit, ourid, hisid)
1350     int unit;
1351     eui64_t ourid;
1352     eui64_t hisid;
1353 {
1354     cif6addr(unit, ourid, hisid);
1355 }
1356
1357
1358 /*
1359  * ipv6cp_finished - possibly shut down the lower layers.
1360  */
1361 static void
1362 ipv6cp_finished(f)
1363     fsm *f;
1364 {
1365     np_finished(f->unit, PPP_IPV6);
1366 }
1367
1368
1369 /*
1370  * ipv6cp_script_done - called when the ipv6-up or ipv6-down script
1371  * has finished.
1372  */
1373 static void
1374 ipv6cp_script_done(arg)
1375     void *arg;
1376 {
1377     ipv6cp_script_pid = 0;
1378     switch (ipv6cp_script_state) {
1379     case s_up:
1380         if (ipv6cp_fsm[0].state != OPENED) {
1381             ipv6cp_script_state = s_down;
1382             ipv6cp_script(_PATH_IPV6DOWN);
1383         }
1384         break;
1385     case s_down:
1386         if (ipv6cp_fsm[0].state == OPENED) {
1387             ipv6cp_script_state = s_up;
1388             ipv6cp_script(_PATH_IPV6UP);
1389         }
1390         break;
1391     }
1392 }
1393
1394
1395 /*
1396  * ipv6cp_script - Execute a script with arguments
1397  * interface-name tty-name speed local-LL remote-LL.
1398  */
1399 static void
1400 ipv6cp_script(script)
1401     char *script;
1402 {
1403     char strspeed[32], strlocal[32], strremote[32];
1404     char *argv[8];
1405
1406     sprintf(strspeed, "%d", baud_rate);
1407     strcpy(strlocal, llv6_ntoa(ipv6cp_gotoptions[0].ourid));
1408     strcpy(strremote, llv6_ntoa(ipv6cp_hisoptions[0].hisid));
1409
1410     argv[0] = script;
1411     argv[1] = ifname;
1412     argv[2] = devnam;
1413     argv[3] = strspeed;
1414     argv[4] = strlocal;
1415     argv[5] = strremote;
1416     argv[6] = ipparam;
1417     argv[7] = NULL;
1418
1419     ipv6cp_script_pid = run_program(script, argv, 0, ipv6cp_script_done, NULL);
1420 }
1421
1422 /*
1423  * ipv6cp_printpkt - print the contents of an IPV6CP packet.
1424  */
1425 static char *ipv6cp_codenames[] = {
1426     "ConfReq", "ConfAck", "ConfNak", "ConfRej",
1427     "TermReq", "TermAck", "CodeRej"
1428 };
1429
1430 static int
1431 ipv6cp_printpkt(p, plen, printer, arg)
1432     u_char *p;
1433     int plen;
1434     void (*printer) __P((void *, char *, ...));
1435     void *arg;
1436 {
1437     int code, id, len, olen;
1438     u_char *pstart, *optend;
1439     u_short cishort;
1440     eui64_t ifaceid;
1441
1442     if (plen < HEADERLEN)
1443         return 0;
1444     pstart = p;
1445     GETCHAR(code, p);
1446     GETCHAR(id, p);
1447     GETSHORT(len, p);
1448     if (len < HEADERLEN || len > plen)
1449         return 0;
1450
1451     if (code >= 1 && code <= sizeof(ipv6cp_codenames) / sizeof(char *))
1452         printer(arg, " %s", ipv6cp_codenames[code-1]);
1453     else
1454         printer(arg, " code=0x%x", code);
1455     printer(arg, " id=0x%x", id);
1456     len -= HEADERLEN;
1457     switch (code) {
1458     case CONFREQ:
1459     case CONFACK:
1460     case CONFNAK:
1461     case CONFREJ:
1462         /* print option list */
1463         while (len >= 2) {
1464             GETCHAR(code, p);
1465             GETCHAR(olen, p);
1466             p -= 2;
1467             if (olen < 2 || olen > len) {
1468                 break;
1469             }
1470             printer(arg, " <");
1471             len -= olen;
1472             optend = p + olen;
1473             switch (code) {
1474             case CI_COMPRESSTYPE:
1475                 if (olen >= CILEN_COMPRESS) {
1476                     p += 2;
1477                     GETSHORT(cishort, p);
1478                     printer(arg, "compress ");
1479                     printer(arg, "0x%x", cishort);
1480                 }
1481                 break;
1482             case CI_IFACEID:
1483                 if (olen == CILEN_IFACEID) {
1484                     p += 2;
1485                     eui64_get(ifaceid, p);
1486                     printer(arg, "addr %s", llv6_ntoa(ifaceid));
1487                 }
1488                 break;
1489             }
1490             while (p < optend) {
1491                 GETCHAR(code, p);
1492                 printer(arg, " %.2x", code);
1493             }
1494             printer(arg, ">");
1495         }
1496         break;
1497
1498     case TERMACK:
1499     case TERMREQ:
1500         if (len > 0 && *p >= ' ' && *p < 0x7f) {
1501             printer(arg, " ");
1502             print_string((char *)p, len, printer, arg);
1503             p += len;
1504             len = 0;
1505         }
1506         break;
1507     }
1508
1509     /* print the rest of the bytes in the packet */
1510     for (; len > 0; --len) {
1511         GETCHAR(code, p);
1512         printer(arg, " %.2x", code);
1513     }
1514
1515     return p - pstart;
1516 }
1517
1518 /*
1519  * ipv6_active_pkt - see if this IP packet is worth bringing the link up for.
1520  * We don't bring the link up for IP fragments or for TCP FIN packets
1521  * with no data.
1522  */
1523 #define IP6_HDRLEN      40      /* bytes */
1524 #define IP6_NHDR_FRAG   44      /* fragment IPv6 header */
1525 #define TCP_HDRLEN      20
1526 #define TH_FIN          0x01
1527
1528 /*
1529  * We use these macros because the IP header may be at an odd address,
1530  * and some compilers might use word loads to get th_off or ip_hl.
1531  */
1532
1533 #define get_ip6nh(x)    (((unsigned char *)(x))[6])
1534 #define get_tcpoff(x)   (((unsigned char *)(x))[12] >> 4)
1535 #define get_tcpflags(x) (((unsigned char *)(x))[13])
1536
1537 static int
1538 ipv6_active_pkt(pkt, len)
1539     u_char *pkt;
1540     int len;
1541 {
1542     u_char *tcp;
1543
1544     len -= PPP_HDRLEN;
1545     pkt += PPP_HDRLEN;
1546     if (len < IP6_HDRLEN)
1547         return 0;
1548     if (get_ip6nh(pkt) == IP6_NHDR_FRAG)
1549         return 0;
1550     if (get_ip6nh(pkt) != IPPROTO_TCP)
1551         return 1;
1552     if (len < IP6_HDRLEN + TCP_HDRLEN)
1553         return 0;
1554     tcp = pkt + IP6_HDRLEN;
1555     if ((get_tcpflags(tcp) & TH_FIN) != 0 && len == IP6_HDRLEN + get_tcpoff(tcp) * 4)
1556         return 0;
1557     return 1;
1558 }