]> git.ozlabs.org Git - ppp.git/blob - pppd/ipv6cp.c
ef03e1015503220db596ef2e3045ae5eb65af0df
[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_wantoptions[0].accept_local,
243       "Accept peer's interface identifier for us", 1 },
244     { "ipv6cp-accept-remote", o_bool, &ipv6cp_wantoptions[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         if (!demand)
532             eui64_magic_nz(wo->ourid);
533     }
534     if (!wo->opt_remote)
535         wo->accept_remote = 1;
536     
537     *go = *wo;
538     eui64_zero(go->hisid);      /* last proposed interface identifier */
539 }
540
541
542 /*
543  * ipv6cp_cilen - Return length of our CI.
544  */
545 static int
546 ipv6cp_cilen(fsm *f)
547 {
548     ipv6cp_options *go = &ipv6cp_gotoptions[f->unit];
549
550 #define LENCIVJ(neg)            (neg ? CILEN_COMPRESS : 0)
551 #define LENCIIFACEID(neg)       (neg ? CILEN_IFACEID : 0)
552
553     return (LENCIIFACEID(go->neg_ifaceid) +
554             LENCIVJ(go->neg_vj));
555 }
556
557
558 /*
559  * ipv6cp_addci - Add our desired CIs to a packet.
560  */
561 static void
562 ipv6cp_addci(fsm *f, u_char *ucp, int *lenp)
563 {
564     ipv6cp_options *go = &ipv6cp_gotoptions[f->unit];
565     int len = *lenp;
566
567 #define ADDCIVJ(opt, neg, val) \
568     if (neg) { \
569         int vjlen = CILEN_COMPRESS; \
570         if (len >= vjlen) { \
571             PUTCHAR(opt, ucp); \
572             PUTCHAR(vjlen, ucp); \
573             PUTSHORT(val, ucp); \
574             len -= vjlen; \
575         } else \
576             neg = 0; \
577     }
578
579 #define ADDCIIFACEID(opt, neg, val1) \
580     if (neg) { \
581         int idlen = CILEN_IFACEID; \
582         if (len >= idlen) { \
583             PUTCHAR(opt, ucp); \
584             PUTCHAR(idlen, ucp); \
585             eui64_put(val1, ucp); \
586             len -= idlen; \
587         } else \
588             neg = 0; \
589     }
590
591     ADDCIIFACEID(CI_IFACEID, go->neg_ifaceid, go->ourid);
592
593     ADDCIVJ(CI_COMPRESSTYPE, go->neg_vj, go->vj_protocol);
594
595     *lenp -= len;
596 }
597
598
599 /*
600  * ipv6cp_ackci - Ack our CIs.
601  *
602  * Returns:
603  *      0 - Ack was bad.
604  *      1 - Ack was good.
605  */
606 static int
607 ipv6cp_ackci(fsm *f, u_char *p, int len)
608 {
609     ipv6cp_options *go = &ipv6cp_gotoptions[f->unit];
610     u_short cilen, citype, cishort;
611     eui64_t ifaceid;
612
613     /*
614      * CIs must be in exactly the same order that we sent...
615      * Check packet length and CI length at each step.
616      * If we find any deviations, then this packet is bad.
617      */
618
619 #define ACKCIVJ(opt, neg, val) \
620     if (neg) { \
621         int vjlen = CILEN_COMPRESS; \
622         if ((len -= vjlen) < 0) \
623             goto bad; \
624         GETCHAR(citype, p); \
625         GETCHAR(cilen, p); \
626         if (cilen != vjlen || \
627             citype != opt)  \
628             goto bad; \
629         GETSHORT(cishort, p); \
630         if (cishort != val) \
631             goto bad; \
632     }
633
634 #define ACKCIIFACEID(opt, neg, val1) \
635     if (neg) { \
636         int idlen = CILEN_IFACEID; \
637         if ((len -= idlen) < 0) \
638             goto bad; \
639         GETCHAR(citype, p); \
640         GETCHAR(cilen, p); \
641         if (cilen != idlen || \
642             citype != opt) \
643             goto bad; \
644         eui64_get(ifaceid, p); \
645         if (! eui64_equals(val1, ifaceid)) \
646             goto bad; \
647     }
648
649     ACKCIIFACEID(CI_IFACEID, go->neg_ifaceid, go->ourid);
650
651     ACKCIVJ(CI_COMPRESSTYPE, go->neg_vj, go->vj_protocol);
652
653     /*
654      * If there are any remaining CIs, then this packet is bad.
655      */
656     if (len != 0)
657         goto bad;
658     return (1);
659
660 bad:
661     IPV6CPDEBUG(("ipv6cp_ackci: received bad Ack!"));
662     return (0);
663 }
664
665 /*
666  * ipv6cp_nakci - Peer has sent a NAK for some of our CIs.
667  * This should not modify any state if the Nak is bad
668  * or if IPV6CP is in the OPENED state.
669  *
670  * Returns:
671  *      0 - Nak was bad.
672  *      1 - Nak was good.
673  */
674 static int
675 ipv6cp_nakci(fsm *f, u_char *p, int len, int treat_as_reject)
676 {
677     ipv6cp_options *go = &ipv6cp_gotoptions[f->unit];
678     u_char citype, cilen, *next;
679     u_short cishort;
680     eui64_t ifaceid;
681     ipv6cp_options no;          /* options we've seen Naks for */
682     ipv6cp_options try;         /* options to request next time */
683
684     BZERO(&no, sizeof(no));
685     try = *go;
686
687     /*
688      * Any Nak'd CIs must be in exactly the same order that we sent.
689      * Check packet length and CI length at each step.
690      * If we find any deviations, then this packet is bad.
691      */
692 #define NAKCIIFACEID(opt, neg, code) \
693     if (go->neg && \
694         len >= (cilen = CILEN_IFACEID) && \
695         p[1] == cilen && \
696         p[0] == opt) { \
697         len -= cilen; \
698         INCPTR(2, p); \
699         eui64_get(ifaceid, p); \
700         no.neg = 1; \
701         code \
702     }
703
704 #define NAKCIVJ(opt, neg, code) \
705     if (go->neg && \
706         ((cilen = p[1]) == CILEN_COMPRESS) && \
707         len >= cilen && \
708         p[0] == opt) { \
709         len -= cilen; \
710         INCPTR(2, p); \
711         GETSHORT(cishort, p); \
712         no.neg = 1; \
713         code \
714     }
715
716     /*
717      * Accept the peer's idea of {our,his} interface identifier, if different
718      * from our idea, only if the accept_{local,remote} flag is set.
719      */
720     NAKCIIFACEID(CI_IFACEID, neg_ifaceid,
721                  if (treat_as_reject) {
722                      try.neg_ifaceid = 0;
723                  } else if (go->accept_local && !eui64_iszero(ifaceid) && !eui64_equals(ifaceid, go->hisid)) {
724                      try.ourid = ifaceid;
725                  } else if (eui64_iszero(ifaceid) && !go->opt_local) {
726                      while (eui64_iszero(ifaceid) || 
727                             eui64_equals(ifaceid, go->hisid)) /* bad luck */
728                          eui64_magic(ifaceid);
729                      try.ourid = ifaceid;
730                      IPV6CPDEBUG(("local LL address %s", llv6_ntoa(ifaceid)));
731                  }
732                  );
733
734 #ifdef IPV6CP_COMP
735     NAKCIVJ(CI_COMPRESSTYPE, neg_vj,
736             {
737                 if (cishort == IPV6CP_COMP && !treat_as_reject) {
738                     try.vj_protocol = cishort;
739                 } else {
740                     try.neg_vj = 0;
741                 }
742             }
743             );
744 #else
745     NAKCIVJ(CI_COMPRESSTYPE, neg_vj,
746             {
747                 try.neg_vj = 0;
748             }
749             );
750 #endif
751
752     /*
753      * There may be remaining CIs, if the peer is requesting negotiation
754      * on an option that we didn't include in our request packet.
755      * If they want to negotiate about interface identifier, we comply.
756      * If they want us to ask for compression, we refuse.
757      */
758     while (len >= CILEN_VOID) {
759         GETCHAR(citype, p);
760         GETCHAR(cilen, p);
761         if ( cilen < CILEN_VOID || (len -= cilen) < 0 )
762             goto bad;
763         next = p + cilen - 2;
764
765         switch (citype) {
766         case CI_COMPRESSTYPE:
767             if (go->neg_vj || no.neg_vj ||
768                 (cilen != CILEN_COMPRESS))
769                 goto bad;
770             no.neg_vj = 1;
771             break;
772         case CI_IFACEID:
773             if (go->neg_ifaceid || no.neg_ifaceid || cilen != CILEN_IFACEID)
774                 goto bad;
775             try.neg_ifaceid = 1;
776             eui64_get(ifaceid, p);
777             if (go->accept_local && !eui64_iszero(ifaceid) && !eui64_equals(ifaceid, go->hisid)) {
778                 try.ourid = ifaceid;
779             } else if (eui64_iszero(ifaceid) && !go->opt_local) {
780                 while (eui64_iszero(ifaceid) || 
781                        eui64_equals(ifaceid, go->hisid)) /* bad luck */
782                     eui64_magic(ifaceid);
783                 try.ourid = ifaceid;
784             } else {
785                 try.neg_ifaceid = 0;
786             }
787             no.neg_ifaceid = 1;
788             break;
789         }
790         p = next;
791     }
792
793     /* If there is still anything left, this packet is bad. */
794     if (len != 0)
795         goto bad;
796
797     /*
798      * OK, the Nak is good.  Now we can update state.
799      */
800     if (f->state != OPENED)
801         *go = try;
802
803     return 1;
804
805 bad:
806     IPV6CPDEBUG(("ipv6cp_nakci: received bad Nak!"));
807     return 0;
808 }
809
810
811 /*
812  * ipv6cp_rejci - Reject some of our CIs.
813  */
814 static int
815 ipv6cp_rejci(fsm *f, u_char *p, int len)
816 {
817     ipv6cp_options *go = &ipv6cp_gotoptions[f->unit];
818     u_char cilen;
819     u_short cishort;
820     eui64_t ifaceid;
821     ipv6cp_options try;         /* options to request next time */
822
823     try = *go;
824     /*
825      * Any Rejected CIs must be in exactly the same order that we sent.
826      * Check packet length and CI length at each step.
827      * If we find any deviations, then this packet is bad.
828      */
829 #define REJCIIFACEID(opt, neg, val1) \
830     if (go->neg && \
831         len >= (cilen = CILEN_IFACEID) && \
832         p[1] == cilen && \
833         p[0] == opt) { \
834         len -= cilen; \
835         INCPTR(2, p); \
836         eui64_get(ifaceid, p); \
837         /* Check rejected value. */ \
838         if (! eui64_equals(ifaceid, val1)) \
839             goto bad; \
840         try.neg = 0; \
841     }
842
843 #define REJCIVJ(opt, neg, val) \
844     if (go->neg && \
845         p[1] == CILEN_COMPRESS && \
846         len >= p[1] && \
847         p[0] == opt) { \
848         len -= p[1]; \
849         INCPTR(2, p); \
850         GETSHORT(cishort, p); \
851         /* Check rejected value. */  \
852         if (cishort != val) \
853             goto bad; \
854         try.neg = 0; \
855      }
856
857     REJCIIFACEID(CI_IFACEID, neg_ifaceid, go->ourid);
858
859     REJCIVJ(CI_COMPRESSTYPE, neg_vj, go->vj_protocol);
860
861     /*
862      * If there are any remaining CIs, then this packet is bad.
863      */
864     if (len != 0)
865         goto bad;
866     /*
867      * Now we can update state.
868      */
869     if (f->state != OPENED)
870         *go = try;
871     return 1;
872
873 bad:
874     IPV6CPDEBUG(("ipv6cp_rejci: received bad Reject!"));
875     return 0;
876 }
877
878
879 /*
880  * ipv6cp_reqci - Check the peer's requested CIs and send appropriate response.
881  *
882  * Returns: CONFACK, CONFNAK or CONFREJ and input packet modified
883  * appropriately.  If reject_if_disagree is non-zero, doesn't return
884  * CONFNAK; returns CONFREJ if it can't return CONFACK.
885  */
886 static int
887 ipv6cp_reqci(fsm *f, u_char *inp, int *len, 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) && !wo->accept_remote &&
952                 !eui64_equals(ifaceid, wo->hisid)) {
953                     
954                 orc = CONFNAK;
955                 ifaceid = wo->hisid;
956                 go->hisid = ifaceid;
957                 DECPTR(sizeof(ifaceid), p);
958                 eui64_put(ifaceid, p);
959             } else
960             if (eui64_iszero(ifaceid) || eui64_equals(ifaceid, go->ourid)) {
961                 orc = CONFNAK;
962                 if (eui64_iszero(go->hisid))    /* first time, try option */
963                     ifaceid = wo->hisid;
964                 if (eui64_equals(ifaceid, go->ourid)) /* bad luck */
965                     eui64_zero(ifaceid);
966                 if (eui64_iszero(ifaceid)) {
967                     if (wo->opt_remote)
968                         ifaceid = wo->hisid;
969                     else {
970                         while (eui64_iszero(ifaceid) ||
971                                eui64_equals(ifaceid, go->ourid)) /* bad luck */
972                             eui64_magic(ifaceid);
973                     }
974                 }
975                 go->hisid = ifaceid;
976                 DECPTR(sizeof(ifaceid), p);
977                 eui64_put(ifaceid, p);
978             }
979
980             ho->neg_ifaceid = 1;
981             ho->hisid = ifaceid;
982             break;
983
984         case CI_COMPRESSTYPE:
985             IPV6CPDEBUG(("ipv6cp: received COMPRESSTYPE "));
986             if (!ao->neg_vj ||
987                 (cilen != CILEN_COMPRESS)) {
988                 orc = CONFREJ;
989                 break;
990             }
991             GETSHORT(cishort, p);
992             IPV6CPDEBUG(("(%d)", cishort));
993
994 #ifdef IPV6CP_COMP
995             if (!(cishort == IPV6CP_COMP)) {
996                 orc = CONFREJ;
997                 break;
998             }
999
1000             ho->neg_vj = 1;
1001             ho->vj_protocol = cishort;
1002             break;
1003 #else
1004             orc = CONFREJ;
1005             break;
1006 #endif
1007
1008         default:
1009             orc = CONFREJ;
1010             break;
1011         }
1012
1013 endswitch:
1014         IPV6CPDEBUG((" (%s)\n", CODENAME(orc)));
1015
1016         if (orc == CONFACK &&           /* Good CI */
1017             rc != CONFACK)              /*  but prior CI wasnt? */
1018             continue;                   /* Don't send this one */
1019
1020         if (orc == CONFNAK) {           /* Nak this CI? */
1021             if (reject_if_disagree)     /* Getting fed up with sending NAKs? */
1022                 orc = CONFREJ;          /* Get tough if so */
1023             else {
1024                 if (rc == CONFREJ)      /* Rejecting prior CI? */
1025                     continue;           /* Don't send this one */
1026                 if (rc == CONFACK) {    /* Ack'd all prior CIs? */
1027                     rc = CONFNAK;       /* Not anymore... */
1028                     ucp = inp;          /* Backup */
1029                 }
1030             }
1031         }
1032
1033         if (orc == CONFREJ &&           /* Reject this CI */
1034             rc != CONFREJ) {            /*  but no prior ones? */
1035             rc = CONFREJ;
1036             ucp = inp;                  /* Backup */
1037         }
1038
1039         /* Need to move CI? */
1040         if (ucp != cip)
1041             BCOPY(cip, ucp, cilen);     /* Move it */
1042
1043         /* Update output pointer */
1044         INCPTR(cilen, ucp);
1045     }
1046
1047     /*
1048      * If we aren't rejecting this packet, and we want to negotiate
1049      * their identifier and they didn't send their identifier, then we
1050      * send a NAK with a CI_IFACEID option appended.  We assume the
1051      * input buffer is long enough that we can append the extra
1052      * option safely.
1053      */
1054     if (rc != CONFREJ && !ho->neg_ifaceid &&
1055         wo->req_ifaceid && !reject_if_disagree) {
1056         if (rc == CONFACK) {
1057             rc = CONFNAK;
1058             ucp = inp;                          /* reset pointer */
1059             wo->req_ifaceid = 0;                /* don't ask again */
1060         }
1061         PUTCHAR(CI_IFACEID, ucp);
1062         PUTCHAR(CILEN_IFACEID, ucp);
1063         eui64_put(wo->hisid, ucp);
1064     }
1065
1066     *len = ucp - inp;                   /* Compute output length */
1067     IPV6CPDEBUG(("ipv6cp: returning Configure-%s", CODENAME(rc)));
1068     return (rc);                        /* Return final code */
1069 }
1070
1071
1072 /*
1073  * ether_to_eui64 - Convert 48-bit Ethernet address into 64-bit EUI
1074  *
1075  * walks the list of valid ethernet interfaces, starting with devnam
1076  * (for PPPoE it is ethernet interface), and convert the first
1077  * found 48-bit MAC address into EUI 64. caller also assumes that
1078  * the system has a properly configured Ethernet interface for this
1079  * function to return non-zero.
1080  */
1081 static int
1082 ether_to_eui64(eui64_t *p_eui64)
1083 {
1084     u_char addr[6];
1085
1086     if (get_if_hwaddr(addr, devnam) < 0 && get_first_ether_hwaddr(addr) < 0) {
1087         error("ipv6cp: no persistent id can be found");
1088         return 0;
1089     }
1090
1091     /*
1092      * And convert the EUI-48 into EUI-64, per RFC 2472 [sec 4.1]
1093      */
1094     p_eui64->e8[0] = addr[0] | 0x02;
1095     p_eui64->e8[1] = addr[1];
1096     p_eui64->e8[2] = addr[2];
1097     p_eui64->e8[3] = 0xFF;
1098     p_eui64->e8[4] = 0xFE;
1099     p_eui64->e8[5] = addr[3];
1100     p_eui64->e8[6] = addr[4];
1101     p_eui64->e8[7] = addr[5];
1102
1103     return 1;
1104 }
1105
1106
1107 /*
1108  * ipv6_check_options - check that any IP-related options are OK,
1109  * and assign appropriate defaults.
1110  */
1111 static void
1112 ipv6_check_options(void)
1113 {
1114     ipv6cp_options *wo = &ipv6cp_wantoptions[0];
1115
1116     if (!ipv6cp_protent.enabled_flag)
1117         return;
1118
1119     /*
1120      * Persistent link-local id is only used when user has not explicitly
1121      * configure/hard-code the id
1122      */
1123     if ((wo->use_persistent) && (!wo->opt_local)) {
1124
1125         /* 
1126          * On systems where there are no Ethernet interfaces used, there
1127          * may be other ways to obtain a persistent id. Right now, it
1128          * will fall back to using magic [see eui64_magic] below when
1129          * an EUI-48 from MAC address can't be obtained. Other possibilities
1130          * include obtaining EEPROM serial numbers, or some other unique
1131          * yet persistent number. On Sparc platforms, this is possible,
1132          * but too bad there's no standards yet for x86 machines.
1133          */
1134         if (ether_to_eui64(&wo->ourid)) {
1135             wo->opt_local = 1;
1136         }
1137     }
1138
1139     if (!wo->opt_local) {       /* init interface identifier */
1140         if (wo->use_ip && eui64_iszero(wo->ourid)) {
1141             eui64_setlo32(wo->ourid, ntohl(ipcp_wantoptions[0].ouraddr));
1142             if (!eui64_iszero(wo->ourid))
1143                 wo->opt_local = 1;
1144         }
1145         
1146         while (eui64_iszero(wo->ourid))
1147             eui64_magic(wo->ourid);
1148     }
1149
1150     if (!wo->opt_remote) {
1151         if (wo->use_ip && eui64_iszero(wo->hisid)) {
1152             eui64_setlo32(wo->hisid, ntohl(ipcp_wantoptions[0].hisaddr));
1153             if (!eui64_iszero(wo->hisid))
1154                 wo->opt_remote = 1;
1155         }
1156     }
1157 }
1158
1159
1160 /*
1161  * ipv6_demand_conf - configure the interface as though
1162  * IPV6CP were up, for use with dial-on-demand.
1163  */
1164 static int
1165 ipv6_demand_conf(int u)
1166 {
1167     ipv6cp_options *wo = &ipv6cp_wantoptions[u];
1168
1169     if (eui64_iszero(wo->hisid)) {
1170         /* make up an arbitrary identifier for the peer */
1171         eui64_magic_nz(wo->hisid);
1172     }
1173     if (eui64_iszero(wo->ourid)) {
1174         /* make up an arbitrary identifier for us */
1175         eui64_magic_nz(wo->ourid);
1176     }
1177
1178     if (!sif6up(u))
1179         return 0;
1180     if (!sif6addr(u, wo->ourid, wo->hisid))
1181         return 0;
1182 #if !defined(__linux__) && !(defined(SVR4) && (defined(SNI) || defined(__USLC__)))
1183     if (!sifup(u))
1184         return 0;
1185 #endif
1186     if (!sifnpmode(u, PPP_IPV6, NPMODE_QUEUE))
1187         return 0;
1188     if (wo->default_route)
1189         if (sif6defaultroute(u, wo->ourid, wo->hisid))
1190             default_route_set[u] = 1;
1191
1192     notice("local  LL address %s", llv6_ntoa(wo->ourid));
1193     notice("remote LL address %s", llv6_ntoa(wo->hisid));
1194
1195     return 1;
1196 }
1197
1198
1199 /*
1200  * ipv6cp_up - IPV6CP has come UP.
1201  *
1202  * Configure the IPv6 network interface appropriately and bring it up.
1203  */
1204 static void
1205 ipv6cp_up(fsm *f)
1206 {
1207     ipv6cp_options *ho = &ipv6cp_hisoptions[f->unit];
1208     ipv6cp_options *go = &ipv6cp_gotoptions[f->unit];
1209     ipv6cp_options *wo = &ipv6cp_wantoptions[f->unit];
1210
1211     IPV6CPDEBUG(("ipv6cp: up"));
1212
1213     /*
1214      * We must have a non-zero LL address for both ends of the link.
1215      */
1216
1217     if (!eui64_iszero(wo->hisid) && !wo->accept_remote && (!ho->neg_ifaceid || !eui64_equals(ho->hisid, wo->hisid))) {
1218         error("Peer refused to agree to his interface identifier");
1219         ipv6cp_close(f->unit, "Refused his interface identifier");
1220         return;
1221     }
1222     if (!ho->neg_ifaceid)
1223         ho->hisid = wo->hisid;
1224
1225     if(!no_ifaceid_neg) {
1226         if (eui64_iszero(ho->hisid)) {
1227             error("Could not determine remote LL address");
1228             ipv6cp_close(f->unit, "Could not determine remote LL address");
1229             return;
1230         }
1231         if (eui64_iszero(go->ourid)) {
1232             error("Could not determine local LL address");
1233             ipv6cp_close(f->unit, "Could not determine local LL address");
1234             return;
1235         }
1236         if (eui64_equals(go->ourid, ho->hisid)) {
1237             error("local and remote LL addresses are equal");
1238             ipv6cp_close(f->unit, "local and remote LL addresses are equal");
1239             return;
1240         }
1241     }
1242     script_setenv("LLLOCAL", llv6_ntoa(go->ourid), 0);
1243     script_setenv("LLREMOTE", llv6_ntoa(ho->hisid), 0);
1244
1245 #ifdef IPV6CP_COMP
1246     /* set tcp compression */
1247     sif6comp(f->unit, ho->neg_vj);
1248 #endif
1249
1250     /*
1251      * If we are doing dial-on-demand, the interface is already
1252      * configured, so we put out any saved-up packets, then set the
1253      * interface to pass IPv6 packets.
1254      */
1255     if (demand) {
1256         if (! eui64_equals(go->ourid, wo->ourid) || 
1257             ! eui64_equals(ho->hisid, wo->hisid)) {
1258             if (! eui64_equals(go->ourid, wo->ourid))
1259                 warn("Local LL address changed to %s", 
1260                      llv6_ntoa(go->ourid));
1261             if (! eui64_equals(ho->hisid, wo->hisid))
1262                 warn("Remote LL address changed to %s", 
1263                      llv6_ntoa(ho->hisid));
1264             ipv6cp_clear_addrs(f->unit, wo->ourid, wo->hisid);
1265
1266             /* Set the interface to the new addresses */
1267             if (!sif6addr(f->unit, go->ourid, ho->hisid)) {
1268                 if (debug)
1269                     warn("sif6addr failed");
1270                 ipv6cp_close(f->unit, "Interface configuration failed");
1271                 return;
1272             }
1273
1274             /* assign a default route through the interface if required */
1275             if (ipv6cp_wantoptions[f->unit].default_route)
1276                 if (sif6defaultroute(f->unit, go->ourid, ho->hisid))
1277                     default_route_set[f->unit] = 1;
1278         }
1279         demand_rexmit(PPP_IPV6);
1280         sifnpmode(f->unit, PPP_IPV6, NPMODE_PASS);
1281
1282     } else {
1283         /* bring the interface up for IPv6 */
1284         if (!sif6up(f->unit)) {
1285             if (debug)
1286                 warn("sif6up failed (IPV6)");
1287             ipv6cp_close(f->unit, "Interface configuration failed");
1288             return;
1289         }
1290
1291         if (!sif6addr(f->unit, go->ourid, ho->hisid)) {
1292             if (debug)
1293                 warn("sif6addr failed");
1294             ipv6cp_close(f->unit, "Interface configuration failed");
1295             return;
1296         }
1297         sifnpmode(f->unit, PPP_IPV6, NPMODE_PASS);
1298
1299         /* assign a default route through the interface if required */
1300         if (ipv6cp_wantoptions[f->unit].default_route)
1301             if (sif6defaultroute(f->unit, go->ourid, ho->hisid))
1302                 default_route_set[f->unit] = 1;
1303
1304         notice("local  LL address %s", llv6_ntoa(go->ourid));
1305         notice("remote LL address %s", llv6_ntoa(ho->hisid));
1306     }
1307
1308     np_up(f->unit, PPP_IPV6);
1309     ipv6cp_is_up = 1;
1310
1311     notify(ipv6_up_notifier, 0);
1312     if (ipv6_up_hook)
1313        ipv6_up_hook();
1314
1315     /*
1316      * Execute the ipv6-up script, like this:
1317      *  /etc/ppp/ipv6-up interface tty speed local-LL remote-LL
1318      */
1319     if (ipv6cp_script_state == s_down && ipv6cp_script_pid == 0) {
1320         ipv6cp_script_state = s_up;
1321         ipv6cp_script(_PATH_IPV6UP);
1322     }
1323 }
1324
1325
1326 /*
1327  * ipv6cp_down - IPV6CP has gone DOWN.
1328  *
1329  * Take the IPv6 network interface down, clear its addresses
1330  * and delete routes through it.
1331  */
1332 static void
1333 ipv6cp_down(fsm *f)
1334 {
1335     IPV6CPDEBUG(("ipv6cp: down"));
1336     update_link_stats(f->unit);
1337     notify(ipv6_down_notifier, 0);
1338     if (ipv6_down_hook)
1339        ipv6_down_hook();
1340     if (ipv6cp_is_up) {
1341         ipv6cp_is_up = 0;
1342         np_down(f->unit, PPP_IPV6);
1343     }
1344 #ifdef IPV6CP_COMP
1345     sif6comp(f->unit, 0);
1346 #endif
1347
1348     /*
1349      * If we are doing dial-on-demand, set the interface
1350      * to queue up outgoing packets (for now).
1351      */
1352     if (demand) {
1353         sifnpmode(f->unit, PPP_IPV6, NPMODE_QUEUE);
1354     } else {
1355         sifnpmode(f->unit, PPP_IPV6, NPMODE_DROP);
1356 #if !defined(__linux__) && !(defined(SVR4) && (defined(SNI) || defined(__USLC)))
1357         sif6down(f->unit);
1358 #endif
1359         ipv6cp_clear_addrs(f->unit, 
1360                            ipv6cp_gotoptions[f->unit].ourid,
1361                            ipv6cp_hisoptions[f->unit].hisid);
1362 #if defined(__linux__)
1363         sif6down(f->unit);
1364 #elif defined(SVR4) && (defined(SNI) || defined(__USLC))
1365         sifdown(f->unit);
1366 #endif
1367     }
1368
1369     /* Execute the ipv6-down script */
1370     if (ipv6cp_script_state == s_up && ipv6cp_script_pid == 0) {
1371         ipv6cp_script_state = s_down;
1372         ipv6cp_script(_PATH_IPV6DOWN);
1373     }
1374 }
1375
1376
1377 /*
1378  * ipv6cp_clear_addrs() - clear the interface addresses, routes,
1379  * proxy neighbour discovery entries, etc.
1380  */
1381 static void
1382 ipv6cp_clear_addrs(int unit, eui64_t ourid, eui64_t hisid)
1383 {
1384     cif6addr(unit, ourid, hisid);
1385 }
1386
1387
1388 /*
1389  * ipv6cp_finished - possibly shut down the lower layers.
1390  */
1391 static void
1392 ipv6cp_finished(fsm *f)
1393 {
1394     np_finished(f->unit, PPP_IPV6);
1395 }
1396
1397
1398 /*
1399  * ipv6cp_script_done - called when the ipv6-up or ipv6-down script
1400  * has finished.
1401  */
1402 static void
1403 ipv6cp_script_done(void *arg)
1404 {
1405     ipv6cp_script_pid = 0;
1406     switch (ipv6cp_script_state) {
1407     case s_up:
1408         if (ipv6cp_fsm[0].state != OPENED) {
1409             ipv6cp_script_state = s_down;
1410             ipv6cp_script(_PATH_IPV6DOWN);
1411         }
1412         break;
1413     case s_down:
1414         if (ipv6cp_fsm[0].state == OPENED) {
1415             ipv6cp_script_state = s_up;
1416             ipv6cp_script(_PATH_IPV6UP);
1417         }
1418         break;
1419     }
1420 }
1421
1422
1423 /*
1424  * ipv6cp_script - Execute a script with arguments
1425  * interface-name tty-name speed local-LL remote-LL.
1426  */
1427 static void
1428 ipv6cp_script(char *script)
1429 {
1430     char strspeed[32], strlocal[32], strremote[32];
1431     char *argv[8];
1432
1433     sprintf(strspeed, "%d", baud_rate);
1434     strcpy(strlocal, llv6_ntoa(ipv6cp_gotoptions[0].ourid));
1435     strcpy(strremote, llv6_ntoa(ipv6cp_hisoptions[0].hisid));
1436
1437     argv[0] = script;
1438     argv[1] = ifname;
1439     argv[2] = devnam;
1440     argv[3] = strspeed;
1441     argv[4] = strlocal;
1442     argv[5] = strremote;
1443     argv[6] = ipparam;
1444     argv[7] = NULL;
1445
1446     ipv6cp_script_pid = run_program(script, argv, 0, ipv6cp_script_done,
1447                                     NULL, 0);
1448 }
1449
1450 /*
1451  * ipv6cp_printpkt - print the contents of an IPV6CP packet.
1452  */
1453 static char *ipv6cp_codenames[] = {
1454     "ConfReq", "ConfAck", "ConfNak", "ConfRej",
1455     "TermReq", "TermAck", "CodeRej"
1456 };
1457
1458 static int
1459 ipv6cp_printpkt(u_char *p, int plen,
1460                 void (*printer) (void *, char *, ...), void *arg)
1461 {
1462     int code, id, len, olen;
1463     u_char *pstart, *optend;
1464     u_short cishort;
1465     eui64_t ifaceid;
1466
1467     if (plen < HEADERLEN)
1468         return 0;
1469     pstart = p;
1470     GETCHAR(code, p);
1471     GETCHAR(id, p);
1472     GETSHORT(len, p);
1473     if (len < HEADERLEN || len > plen)
1474         return 0;
1475
1476     if (code >= 1 && code <= sizeof(ipv6cp_codenames) / sizeof(char *))
1477         printer(arg, " %s", ipv6cp_codenames[code-1]);
1478     else
1479         printer(arg, " code=0x%x", code);
1480     printer(arg, " id=0x%x", id);
1481     len -= HEADERLEN;
1482     switch (code) {
1483     case CONFREQ:
1484     case CONFACK:
1485     case CONFNAK:
1486     case CONFREJ:
1487         /* print option list */
1488         while (len >= 2) {
1489             GETCHAR(code, p);
1490             GETCHAR(olen, p);
1491             p -= 2;
1492             if (olen < 2 || olen > len) {
1493                 break;
1494             }
1495             printer(arg, " <");
1496             len -= olen;
1497             optend = p + olen;
1498             switch (code) {
1499             case CI_COMPRESSTYPE:
1500                 if (olen >= CILEN_COMPRESS) {
1501                     p += 2;
1502                     GETSHORT(cishort, p);
1503                     printer(arg, "compress ");
1504                     printer(arg, "0x%x", cishort);
1505                 }
1506                 break;
1507             case CI_IFACEID:
1508                 if (olen == CILEN_IFACEID) {
1509                     p += 2;
1510                     eui64_get(ifaceid, p);
1511                     printer(arg, "addr %s", llv6_ntoa(ifaceid));
1512                 }
1513                 break;
1514             }
1515             while (p < optend) {
1516                 GETCHAR(code, p);
1517                 printer(arg, " %.2x", code);
1518             }
1519             printer(arg, ">");
1520         }
1521         break;
1522
1523     case TERMACK:
1524     case TERMREQ:
1525         if (len > 0 && *p >= ' ' && *p < 0x7f) {
1526             printer(arg, " ");
1527             print_string((char *)p, len, printer, arg);
1528             p += len;
1529             len = 0;
1530         }
1531         break;
1532     }
1533
1534     /* print the rest of the bytes in the packet */
1535     for (; len > 0; --len) {
1536         GETCHAR(code, p);
1537         printer(arg, " %.2x", code);
1538     }
1539
1540     return p - pstart;
1541 }
1542
1543 /*
1544  * ipv6_active_pkt - see if this IP packet is worth bringing the link up for.
1545  * We don't bring the link up for IP fragments or for TCP FIN packets
1546  * with no data.
1547  */
1548 #define IP6_HDRLEN      40      /* bytes */
1549 #define IP6_NHDR_FRAG   44      /* fragment IPv6 header */
1550 #define TCP_HDRLEN      20
1551 #define TH_FIN          0x01
1552
1553 /*
1554  * We use these macros because the IP header may be at an odd address,
1555  * and some compilers might use word loads to get th_off or ip_hl.
1556  */
1557
1558 #define get_ip6nh(x)    (((unsigned char *)(x))[6])
1559 #define get_tcpoff(x)   (((unsigned char *)(x))[12] >> 4)
1560 #define get_tcpflags(x) (((unsigned char *)(x))[13])
1561
1562 static int
1563 ipv6_active_pkt(u_char *pkt, int len)
1564 {
1565     u_char *tcp;
1566
1567     len -= PPP_HDRLEN;
1568     pkt += PPP_HDRLEN;
1569     if (len < IP6_HDRLEN)
1570         return 0;
1571     if (get_ip6nh(pkt) == IP6_NHDR_FRAG)
1572         return 0;
1573     if (get_ip6nh(pkt) != IPPROTO_TCP)
1574         return 1;
1575     if (len < IP6_HDRLEN + TCP_HDRLEN)
1576         return 0;
1577     tcp = pkt + IP6_HDRLEN;
1578     if ((get_tcpflags(tcp) & TH_FIN) != 0 && len == IP6_HDRLEN + get_tcpoff(tcp) * 4)
1579         return 0;
1580     return 1;
1581 }