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