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