]> git.ozlabs.org Git - ppp.git/blob - pppd/ipv6cp.c
pppd: Notify IPv6 up/down as we do for IPv4
[ppp.git] / pppd / ipv6cp.c
1 /*
2  * ipv6cp.c - PPP IPV6 Control Protocol.
3  *
4  * Copyright (c) 1999 Tommi Komulainen.  All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  *
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in
15  *    the documentation and/or other materials provided with the
16  *    distribution.
17  *
18  * 3. The name(s) of the authors of this software must not be used to
19  *    endorse or promote products derived from this software without
20  *    prior written permission.
21  *
22  * 4. Redistributions of any form whatsoever must retain the following
23  *    acknowledgment:
24  *    "This product includes software developed by Tommi Komulainen
25  *     <Tommi.Komulainen@iki.fi>".
26  *
27  * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO
28  * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
29  * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
30  * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
31  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
32  * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
33  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
34  *
35  */
36
37 /*  Original version, based on RFC2023 :
38
39     Copyright (c) 1995, 1996, 1997 Francis.Dupont@inria.fr, INRIA Rocquencourt,
40     Alain.Durand@imag.fr, IMAG,
41     Jean-Luc.Richier@imag.fr, IMAG-LSR.
42
43     Copyright (c) 1998, 1999 Francis.Dupont@inria.fr, GIE DYADE,
44     Alain.Durand@imag.fr, IMAG,
45     Jean-Luc.Richier@imag.fr, IMAG-LSR.
46
47     Ce travail a été fait au sein du GIE DYADE (Groupement d'Intérêt
48     Économique ayant pour membres BULL S.A. et l'INRIA).
49
50     Ce logiciel informatique est disponible aux conditions
51     usuelles dans la recherche, c'est-à-dire qu'il peut
52     être utilisé, copié, modifié, distribué à l'unique
53     condition que ce texte soit conservé afin que
54     l'origine de ce logiciel soit reconnue.
55
56     Le nom de l'Institut National de Recherche en Informatique
57     et en Automatique (INRIA), de l'IMAG, ou d'une personne morale
58     ou physique ayant participé à l'élaboration de ce logiciel ne peut
59     être utilisé sans son accord préalable explicite.
60
61     Ce logiciel est fourni tel quel sans aucune garantie,
62     support ou responsabilité d'aucune sorte.
63     Ce logiciel est dérivé de sources d'origine
64     "University of California at Berkeley" et
65     "Digital Equipment Corporation" couvertes par des copyrights.
66
67     L'Institut d'Informatique et de Mathématiques Appliquées de Grenoble (IMAG)
68     est une fédération d'unités mixtes de recherche du CNRS, de l'Institut National
69     Polytechnique de Grenoble et de l'Université Joseph Fourier regroupant
70     sept laboratoires dont le laboratoire Logiciels, Systèmes, Réseaux (LSR).
71
72     This work has been done in the context of GIE DYADE (joint R & D venture
73     between BULL S.A. and INRIA).
74
75     This software is available with usual "research" terms
76     with the aim of retain credits of the software. 
77     Permission to use, copy, modify and distribute this software for any
78     purpose and without fee is hereby granted, provided that the above
79     copyright notice and this permission notice appear in all copies,
80     and the name of INRIA, IMAG, or any contributor not be used in advertising
81     or publicity pertaining to this material without the prior explicit
82     permission. The software is provided "as is" without any
83     warranties, support or liabilities of any kind.
84     This software is derived from source code from
85     "University of California at Berkeley" and
86     "Digital Equipment Corporation" protected by copyrights.
87
88     Grenoble's Institute of Computer Science and Applied Mathematics (IMAG)
89     is a federation of seven research units funded by the CNRS, National
90     Polytechnic Institute of Grenoble and University Joseph Fourier.
91     The research unit in Software, Systems, Networks (LSR) is member of IMAG.
92 */
93
94 /*
95  * Derived from :
96  *
97  *
98  * ipcp.c - PPP IP Control Protocol.
99  *
100  * Copyright (c) 1984-2000 Carnegie Mellon University. All rights reserved.
101  *
102  * Redistribution and use in source and binary forms, with or without
103  * modification, are permitted provided that the following conditions
104  * are met:
105  *
106  * 1. Redistributions of source code must retain the above copyright
107  *    notice, this list of conditions and the following disclaimer.
108  *
109  * 2. Redistributions in binary form must reproduce the above copyright
110  *    notice, this list of conditions and the following disclaimer in
111  *    the documentation and/or other materials provided with the
112  *    distribution.
113  *
114  * 3. The name "Carnegie Mellon University" must not be used to
115  *    endorse or promote products derived from this software without
116  *    prior written permission. For permission or any legal
117  *    details, please contact
118  *      Office of Technology Transfer
119  *      Carnegie Mellon University
120  *      5000 Forbes Avenue
121  *      Pittsburgh, PA  15213-3890
122  *      (412) 268-4387, fax: (412) 268-7395
123  *      tech-transfer@andrew.cmu.edu
124  *
125  * 4. Redistributions of any form whatsoever must retain the following
126  *    acknowledgment:
127  *    "This product includes software developed by Computing Services
128  *     at Carnegie Mellon University (http://www.cmu.edu/computing/)."
129  *
130  * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
131  * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
132  * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
133  * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
134  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
135  * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
136  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
137  *
138  * $Id: ipv6cp.c,v 1.21 2005/08/25 23:59:34 paulus Exp $ 
139  */
140
141 #define RCSID   "$Id: ipv6cp.c,v 1.21 2005/08/25 23:59:34 paulus Exp $"
142
143 /*
144  * TODO: 
145  *
146  * Proxy Neighbour Discovery.
147  *
148  * Better defines for selecting the ordering of
149  *   interface up / set address. (currently checks for __linux__,
150  *   since SVR4 && (SNI || __USLC__) didn't work properly)
151  */
152
153 #include <stdio.h>
154 #include <string.h>
155 #include <unistd.h>
156 #include <netdb.h>
157 #include <sys/param.h>
158 #include <sys/types.h>
159 #include <sys/socket.h>
160 #include <netinet/in.h>
161 #include <arpa/inet.h>
162
163 #include "pppd.h"
164 #include "fsm.h"
165 #include "ipcp.h"
166 #include "ipv6cp.h"
167 #include "magic.h"
168 #include "pathnames.h"
169
170 static const char rcsid[] = RCSID;
171
172 /* global vars */
173 ipv6cp_options ipv6cp_wantoptions[NUM_PPP];     /* Options that we want to request */
174 ipv6cp_options ipv6cp_gotoptions[NUM_PPP];      /* Options that peer ack'd */
175 ipv6cp_options ipv6cp_allowoptions[NUM_PPP];    /* Options we allow peer to request */
176 ipv6cp_options ipv6cp_hisoptions[NUM_PPP];      /* Options that we ack'd */
177 int no_ifaceid_neg = 0;
178
179 /* local vars */
180 static int ipv6cp_is_up;
181
182 /* Hook for a plugin to know when IPv6 protocol has come up */
183 void (*ipv6_up_hook) __P((void)) = NULL;
184
185 /* Hook for a plugin to know when IPv6 protocol has come down */
186 void (*ipv6_down_hook) __P((void)) = NULL;
187
188 /* Notifiers for when IPCPv6 goes up and down */
189 struct notifier *ipv6_up_notifier = NULL;
190 struct notifier *ipv6_down_notifier = NULL;
191
192 /*
193  * Callbacks for fsm code.  (CI = Configuration Information)
194  */
195 static void ipv6cp_resetci __P((fsm *));        /* Reset our CI */
196 static int  ipv6cp_cilen __P((fsm *));          /* Return length of our CI */
197 static void ipv6cp_addci __P((fsm *, u_char *, int *)); /* Add our CI */
198 static int  ipv6cp_ackci __P((fsm *, u_char *, int));   /* Peer ack'd our CI */
199 static int  ipv6cp_nakci __P((fsm *, u_char *, int, int));/* Peer nak'd our CI */
200 static int  ipv6cp_rejci __P((fsm *, u_char *, int));   /* Peer rej'd our CI */
201 static int  ipv6cp_reqci __P((fsm *, u_char *, int *, int)); /* Rcv CI */
202 static void ipv6cp_up __P((fsm *));             /* We're UP */
203 static void ipv6cp_down __P((fsm *));           /* We're DOWN */
204 static void ipv6cp_finished __P((fsm *));       /* Don't need lower layer */
205
206 fsm ipv6cp_fsm[NUM_PPP];                /* IPV6CP fsm structure */
207
208 static fsm_callbacks ipv6cp_callbacks = { /* IPV6CP callback routines */
209     ipv6cp_resetci,             /* Reset our Configuration Information */
210     ipv6cp_cilen,               /* Length of our Configuration Information */
211     ipv6cp_addci,               /* Add our Configuration Information */
212     ipv6cp_ackci,               /* ACK our Configuration Information */
213     ipv6cp_nakci,               /* NAK our Configuration Information */
214     ipv6cp_rejci,               /* Reject our Configuration Information */
215     ipv6cp_reqci,               /* Request peer's Configuration Information */
216     ipv6cp_up,                  /* Called when fsm reaches OPENED state */
217     ipv6cp_down,                /* Called when fsm leaves OPENED state */
218     NULL,                       /* Called when we want the lower layer up */
219     ipv6cp_finished,            /* Called when we want the lower layer down */
220     NULL,                       /* Called when Protocol-Reject received */
221     NULL,                       /* Retransmission is necessary */
222     NULL,                       /* Called to handle protocol-specific codes */
223     "IPV6CP"                    /* String name of protocol */
224 };
225
226 /*
227  * Command-line options.
228  */
229 static int setifaceid __P((char **arg));
230 static void printifaceid __P((option_t *,
231                               void (*)(void *, char *, ...), void *));
232
233 static option_t ipv6cp_option_list[] = {
234     { "ipv6", o_special, (void *)setifaceid,
235       "Set interface identifiers for IPV6",
236       OPT_A2PRINTER, (void *)printifaceid },
237
238     { "+ipv6", o_bool, &ipv6cp_protent.enabled_flag,
239       "Enable IPv6 and IPv6CP", OPT_PRIO | 1 },
240     { "noipv6", o_bool, &ipv6cp_protent.enabled_flag,
241       "Disable IPv6 and IPv6CP", OPT_PRIOSUB },
242     { "-ipv6", o_bool, &ipv6cp_protent.enabled_flag,
243       "Disable IPv6 and IPv6CP", OPT_PRIOSUB | OPT_ALIAS },
244
245     { "ipv6cp-accept-local", o_bool, &ipv6cp_allowoptions[0].accept_local,
246       "Accept peer's interface identifier for us", 1 },
247
248     { "ipv6cp-use-ipaddr", o_bool, &ipv6cp_allowoptions[0].use_ip,
249       "Use (default) IPv4 address as interface identifier", 1 },
250
251 #if defined(SOL2) || defined(__linux__)
252     { "ipv6cp-use-persistent", o_bool, &ipv6cp_wantoptions[0].use_persistent,
253       "Use uniquely-available persistent value for link local address", 1 },
254 #endif /* defined(SOL2) */
255
256     { "ipv6cp-restart", o_int, &ipv6cp_fsm[0].timeouttime,
257       "Set timeout for IPv6CP", OPT_PRIO },
258     { "ipv6cp-max-terminate", o_int, &ipv6cp_fsm[0].maxtermtransmits,
259       "Set max #xmits for term-reqs", OPT_PRIO },
260     { "ipv6cp-max-configure", o_int, &ipv6cp_fsm[0].maxconfreqtransmits,
261       "Set max #xmits for conf-reqs", OPT_PRIO },
262     { "ipv6cp-max-failure", o_int, &ipv6cp_fsm[0].maxnakloops,
263       "Set max #conf-naks for IPv6CP", OPT_PRIO },
264
265    { NULL }
266 };
267
268
269 /*
270  * Protocol entry points from main code.
271  */
272 static void ipv6cp_init __P((int));
273 static void ipv6cp_open __P((int));
274 static void ipv6cp_close __P((int, char *));
275 static void ipv6cp_lowerup __P((int));
276 static void ipv6cp_lowerdown __P((int));
277 static void ipv6cp_input __P((int, u_char *, int));
278 static void ipv6cp_protrej __P((int));
279 static int  ipv6cp_printpkt __P((u_char *, int,
280                                void (*) __P((void *, char *, ...)), void *));
281 static void ipv6_check_options __P((void));
282 static int  ipv6_demand_conf __P((int));
283 static int  ipv6_active_pkt __P((u_char *, int));
284
285 struct protent ipv6cp_protent = {
286     PPP_IPV6CP,
287     ipv6cp_init,
288     ipv6cp_input,
289     ipv6cp_protrej,
290     ipv6cp_lowerup,
291     ipv6cp_lowerdown,
292     ipv6cp_open,
293     ipv6cp_close,
294     ipv6cp_printpkt,
295     NULL,
296     0,
297     "IPV6CP",
298     "IPV6",
299     ipv6cp_option_list,
300     ipv6_check_options,
301     ipv6_demand_conf,
302     ipv6_active_pkt
303 };
304
305 static void ipv6cp_clear_addrs __P((int, eui64_t, eui64_t));
306 static void ipv6cp_script __P((char *));
307 static void ipv6cp_script_done __P((void *));
308
309 /*
310  * Lengths of configuration options.
311  */
312 #define CILEN_VOID      2
313 #define CILEN_COMPRESS  4       /* length for RFC2023 compress opt. */
314 #define CILEN_IFACEID   10      /* RFC2472, interface identifier    */
315
316 #define CODENAME(x)     ((x) == CONFACK ? "ACK" : \
317                          (x) == CONFNAK ? "NAK" : "REJ")
318
319 /*
320  * This state variable is used to ensure that we don't
321  * run an ipcp-up/down script while one is already running.
322  */
323 static enum script_state {
324     s_down,
325     s_up,
326 } ipv6cp_script_state;
327 static pid_t ipv6cp_script_pid;
328
329 /*
330  * setifaceid - set the interface identifiers manually
331  */
332 static int
333 setifaceid(argv)
334     char **argv;
335 {
336     char *comma, *arg, c;
337     ipv6cp_options *wo = &ipv6cp_wantoptions[0];
338     struct in6_addr addr;
339     static int prio_local, prio_remote;
340
341 #define VALIDID(a) ( (((a).s6_addr32[0] == 0) && ((a).s6_addr32[1] == 0)) && \
342                         (((a).s6_addr32[2] != 0) || ((a).s6_addr32[3] != 0)) )
343     
344     arg = *argv;
345     if ((comma = strchr(arg, ',')) == NULL)
346         comma = arg + strlen(arg);
347     
348     /* 
349      * If comma first character, then no local identifier
350      */
351     if (comma != arg) {
352         c = *comma;
353         *comma = '\0';
354
355         if (inet_pton(AF_INET6, arg, &addr) == 0 || !VALIDID(addr)) {
356             option_error("Illegal interface identifier (local): %s", arg);
357             return 0;
358         }
359
360         if (option_priority >= prio_local) {
361             eui64_copy(addr.s6_addr32[2], wo->ourid);
362             wo->opt_local = 1;
363             prio_local = option_priority;
364         }
365         *comma = c;
366     }
367     
368     /*
369      * If comma last character, the no remote identifier
370      */
371     if (*comma != 0 && *++comma != '\0') {
372         if (inet_pton(AF_INET6, comma, &addr) == 0 || !VALIDID(addr)) {
373             option_error("Illegal interface identifier (remote): %s", comma);
374             return 0;
375         }
376         if (option_priority >= prio_remote) {
377             eui64_copy(addr.s6_addr32[2], wo->hisid);
378             wo->opt_remote = 1;
379             prio_remote = option_priority;
380         }
381     }
382
383     if (override_value("+ipv6", option_priority, option_source))
384         ipv6cp_protent.enabled_flag = 1;
385     return 1;
386 }
387
388 char *llv6_ntoa(eui64_t ifaceid);
389
390 static void
391 printifaceid(opt, printer, arg)
392     option_t *opt;
393     void (*printer) __P((void *, char *, ...));
394     void *arg;
395 {
396         ipv6cp_options *wo = &ipv6cp_wantoptions[0];
397
398         if (wo->opt_local)
399                 printer(arg, "%s", llv6_ntoa(wo->ourid));
400         printer(arg, ",");
401         if (wo->opt_remote)
402                 printer(arg, "%s", llv6_ntoa(wo->hisid));
403 }
404
405 /*
406  * Make a string representation of a network address.
407  */
408 char *
409 llv6_ntoa(ifaceid)
410     eui64_t ifaceid;
411 {
412     static char b[64];
413
414     sprintf(b, "fe80::%s", eui64_ntoa(ifaceid));
415     return b;
416 }
417
418
419 /*
420  * ipv6cp_init - Initialize IPV6CP.
421  */
422 static void
423 ipv6cp_init(unit)
424     int unit;
425 {
426     fsm *f = &ipv6cp_fsm[unit];
427     ipv6cp_options *wo = &ipv6cp_wantoptions[unit];
428     ipv6cp_options *ao = &ipv6cp_allowoptions[unit];
429
430     f->unit = unit;
431     f->protocol = PPP_IPV6CP;
432     f->callbacks = &ipv6cp_callbacks;
433     fsm_init(&ipv6cp_fsm[unit]);
434
435     memset(wo, 0, sizeof(*wo));
436     memset(ao, 0, sizeof(*ao));
437
438     wo->accept_local = 1;
439     wo->neg_ifaceid = 1;
440     ao->neg_ifaceid = 1;
441
442 #ifdef IPV6CP_COMP
443     wo->neg_vj = 1;
444     ao->neg_vj = 1;
445     wo->vj_protocol = IPV6CP_COMP;
446 #endif
447
448 }
449
450
451 /*
452  * ipv6cp_open - IPV6CP is allowed to come up.
453  */
454 static void
455 ipv6cp_open(unit)
456     int unit;
457 {
458     fsm_open(&ipv6cp_fsm[unit]);
459 }
460
461
462 /*
463  * ipv6cp_close - Take IPV6CP down.
464  */
465 static void
466 ipv6cp_close(unit, reason)
467     int unit;
468     char *reason;
469 {
470     fsm_close(&ipv6cp_fsm[unit], reason);
471 }
472
473
474 /*
475  * ipv6cp_lowerup - The lower layer is up.
476  */
477 static void
478 ipv6cp_lowerup(unit)
479     int unit;
480 {
481     fsm_lowerup(&ipv6cp_fsm[unit]);
482 }
483
484
485 /*
486  * ipv6cp_lowerdown - The lower layer is down.
487  */
488 static void
489 ipv6cp_lowerdown(unit)
490     int unit;
491 {
492     fsm_lowerdown(&ipv6cp_fsm[unit]);
493 }
494
495
496 /*
497  * ipv6cp_input - Input IPV6CP packet.
498  */
499 static void
500 ipv6cp_input(unit, p, len)
501     int unit;
502     u_char *p;
503     int len;
504 {
505     fsm_input(&ipv6cp_fsm[unit], p, len);
506 }
507
508
509 /*
510  * ipv6cp_protrej - A Protocol-Reject was received for IPV6CP.
511  *
512  * Pretend the lower layer went down, so we shut up.
513  */
514 static void
515 ipv6cp_protrej(unit)
516     int unit;
517 {
518     fsm_lowerdown(&ipv6cp_fsm[unit]);
519 }
520
521
522 /*
523  * ipv6cp_resetci - Reset our CI.
524  */
525 static void
526 ipv6cp_resetci(f)
527     fsm *f;
528 {
529     ipv6cp_options *wo = &ipv6cp_wantoptions[f->unit];
530     ipv6cp_options *go = &ipv6cp_gotoptions[f->unit];
531
532     wo->req_ifaceid = wo->neg_ifaceid && ipv6cp_allowoptions[f->unit].neg_ifaceid;
533     
534     if (!wo->opt_local) {
535         eui64_magic_nz(wo->ourid);
536     }
537     
538     *go = *wo;
539     eui64_zero(go->hisid);      /* last proposed interface identifier */
540 }
541
542
543 /*
544  * ipv6cp_cilen - Return length of our CI.
545  */
546 static int
547 ipv6cp_cilen(f)
548     fsm *f;
549 {
550     ipv6cp_options *go = &ipv6cp_gotoptions[f->unit];
551
552 #define LENCIVJ(neg)            (neg ? CILEN_COMPRESS : 0)
553 #define LENCIIFACEID(neg)       (neg ? CILEN_IFACEID : 0)
554
555     return (LENCIIFACEID(go->neg_ifaceid) +
556             LENCIVJ(go->neg_vj));
557 }
558
559
560 /*
561  * ipv6cp_addci - Add our desired CIs to a packet.
562  */
563 static void
564 ipv6cp_addci(f, ucp, lenp)
565     fsm *f;
566     u_char *ucp;
567     int *lenp;
568 {
569     ipv6cp_options *go = &ipv6cp_gotoptions[f->unit];
570     int len = *lenp;
571
572 #define ADDCIVJ(opt, neg, val) \
573     if (neg) { \
574         int vjlen = CILEN_COMPRESS; \
575         if (len >= vjlen) { \
576             PUTCHAR(opt, ucp); \
577             PUTCHAR(vjlen, ucp); \
578             PUTSHORT(val, ucp); \
579             len -= vjlen; \
580         } else \
581             neg = 0; \
582     }
583
584 #define ADDCIIFACEID(opt, neg, val1) \
585     if (neg) { \
586         int idlen = CILEN_IFACEID; \
587         if (len >= idlen) { \
588             PUTCHAR(opt, ucp); \
589             PUTCHAR(idlen, ucp); \
590             eui64_put(val1, ucp); \
591             len -= idlen; \
592         } else \
593             neg = 0; \
594     }
595
596     ADDCIIFACEID(CI_IFACEID, go->neg_ifaceid, go->ourid);
597
598     ADDCIVJ(CI_COMPRESSTYPE, go->neg_vj, go->vj_protocol);
599
600     *lenp -= len;
601 }
602
603
604 /*
605  * ipv6cp_ackci - Ack our CIs.
606  *
607  * Returns:
608  *      0 - Ack was bad.
609  *      1 - Ack was good.
610  */
611 static int
612 ipv6cp_ackci(f, p, len)
613     fsm *f;
614     u_char *p;
615     int len;
616 {
617     ipv6cp_options *go = &ipv6cp_gotoptions[f->unit];
618     u_short cilen, citype, cishort;
619     eui64_t ifaceid;
620
621     /*
622      * CIs must be in exactly the same order that we sent...
623      * Check packet length and CI length at each step.
624      * If we find any deviations, then this packet is bad.
625      */
626
627 #define ACKCIVJ(opt, neg, val) \
628     if (neg) { \
629         int vjlen = CILEN_COMPRESS; \
630         if ((len -= vjlen) < 0) \
631             goto bad; \
632         GETCHAR(citype, p); \
633         GETCHAR(cilen, p); \
634         if (cilen != vjlen || \
635             citype != opt)  \
636             goto bad; \
637         GETSHORT(cishort, p); \
638         if (cishort != val) \
639             goto bad; \
640     }
641
642 #define ACKCIIFACEID(opt, neg, val1) \
643     if (neg) { \
644         int idlen = CILEN_IFACEID; \
645         if ((len -= idlen) < 0) \
646             goto bad; \
647         GETCHAR(citype, p); \
648         GETCHAR(cilen, p); \
649         if (cilen != idlen || \
650             citype != opt) \
651             goto bad; \
652         eui64_get(ifaceid, p); \
653         if (! eui64_equals(val1, ifaceid)) \
654             goto bad; \
655     }
656
657     ACKCIIFACEID(CI_IFACEID, go->neg_ifaceid, go->ourid);
658
659     ACKCIVJ(CI_COMPRESSTYPE, go->neg_vj, go->vj_protocol);
660
661     /*
662      * If there are any remaining CIs, then this packet is bad.
663      */
664     if (len != 0)
665         goto bad;
666     return (1);
667
668 bad:
669     IPV6CPDEBUG(("ipv6cp_ackci: received bad Ack!"));
670     return (0);
671 }
672
673 /*
674  * ipv6cp_nakci - Peer has sent a NAK for some of our CIs.
675  * This should not modify any state if the Nak is bad
676  * or if IPV6CP is in the OPENED state.
677  *
678  * Returns:
679  *      0 - Nak was bad.
680  *      1 - Nak was good.
681  */
682 static int
683 ipv6cp_nakci(f, p, len, treat_as_reject)
684     fsm *f;
685     u_char *p;
686     int len;
687     int treat_as_reject;
688 {
689     ipv6cp_options *go = &ipv6cp_gotoptions[f->unit];
690     u_char citype, cilen, *next;
691     u_short cishort;
692     eui64_t ifaceid;
693     ipv6cp_options no;          /* options we've seen Naks for */
694     ipv6cp_options try;         /* options to request next time */
695
696     BZERO(&no, sizeof(no));
697     try = *go;
698
699     /*
700      * Any Nak'd CIs must be in exactly the same order that we sent.
701      * Check packet length and CI length at each step.
702      * If we find any deviations, then this packet is bad.
703      */
704 #define NAKCIIFACEID(opt, neg, code) \
705     if (go->neg && \
706         len >= (cilen = CILEN_IFACEID) && \
707         p[1] == cilen && \
708         p[0] == opt) { \
709         len -= cilen; \
710         INCPTR(2, p); \
711         eui64_get(ifaceid, p); \
712         no.neg = 1; \
713         code \
714     }
715
716 #define NAKCIVJ(opt, neg, code) \
717     if (go->neg && \
718         ((cilen = p[1]) == CILEN_COMPRESS) && \
719         len >= cilen && \
720         p[0] == opt) { \
721         len -= cilen; \
722         INCPTR(2, p); \
723         GETSHORT(cishort, p); \
724         no.neg = 1; \
725         code \
726     }
727
728     /*
729      * Accept the peer's idea of {our,his} interface identifier, if different
730      * from our idea, only if the accept_{local,remote} flag is set.
731      */
732     NAKCIIFACEID(CI_IFACEID, neg_ifaceid,
733                  if (treat_as_reject) {
734                      try.neg_ifaceid = 0;
735                  } else if (go->accept_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) {
788                 while (eui64_iszero(ifaceid) || 
789                        eui64_equals(ifaceid, go->hisid)) /* bad luck */
790                     eui64_magic(ifaceid);
791                 try.ourid = ifaceid;
792             }
793             no.neg_ifaceid = 1;
794             break;
795         }
796         p = next;
797     }
798
799     /* If there is still anything left, this packet is bad. */
800     if (len != 0)
801         goto bad;
802
803     /*
804      * OK, the Nak is good.  Now we can update state.
805      */
806     if (f->state != OPENED)
807         *go = try;
808
809     return 1;
810
811 bad:
812     IPV6CPDEBUG(("ipv6cp_nakci: received bad Nak!"));
813     return 0;
814 }
815
816
817 /*
818  * ipv6cp_rejci - Reject some of our CIs.
819  */
820 static int
821 ipv6cp_rejci(f, p, len)
822     fsm *f;
823     u_char *p;
824     int len;
825 {
826     ipv6cp_options *go = &ipv6cp_gotoptions[f->unit];
827     u_char cilen;
828     u_short cishort;
829     eui64_t ifaceid;
830     ipv6cp_options try;         /* options to request next time */
831
832     try = *go;
833     /*
834      * Any Rejected CIs must be in exactly the same order that we sent.
835      * Check packet length and CI length at each step.
836      * If we find any deviations, then this packet is bad.
837      */
838 #define REJCIIFACEID(opt, neg, val1) \
839     if (go->neg && \
840         len >= (cilen = CILEN_IFACEID) && \
841         p[1] == cilen && \
842         p[0] == opt) { \
843         len -= cilen; \
844         INCPTR(2, p); \
845         eui64_get(ifaceid, p); \
846         /* Check rejected value. */ \
847         if (! eui64_equals(ifaceid, val1)) \
848             goto bad; \
849         try.neg = 0; \
850     }
851
852 #define REJCIVJ(opt, neg, val) \
853     if (go->neg && \
854         p[1] == CILEN_COMPRESS && \
855         len >= p[1] && \
856         p[0] == opt) { \
857         len -= p[1]; \
858         INCPTR(2, p); \
859         GETSHORT(cishort, p); \
860         /* Check rejected value. */  \
861         if (cishort != val) \
862             goto bad; \
863         try.neg = 0; \
864      }
865
866     REJCIIFACEID(CI_IFACEID, neg_ifaceid, go->ourid);
867
868     REJCIVJ(CI_COMPRESSTYPE, neg_vj, go->vj_protocol);
869
870     /*
871      * If there are any remaining CIs, then this packet is bad.
872      */
873     if (len != 0)
874         goto bad;
875     /*
876      * Now we can update state.
877      */
878     if (f->state != OPENED)
879         *go = try;
880     return 1;
881
882 bad:
883     IPV6CPDEBUG(("ipv6cp_rejci: received bad Reject!"));
884     return 0;
885 }
886
887
888 /*
889  * ipv6cp_reqci - Check the peer's requested CIs and send appropriate response.
890  *
891  * Returns: CONFACK, CONFNAK or CONFREJ and input packet modified
892  * appropriately.  If reject_if_disagree is non-zero, doesn't return
893  * CONFNAK; returns CONFREJ if it can't return CONFACK.
894  */
895 static int
896 ipv6cp_reqci(f, inp, len, reject_if_disagree)
897     fsm *f;
898     u_char *inp;                /* Requested CIs */
899     int *len;                   /* Length of requested CIs */
900     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) && 
965                 !eui64_equals(ifaceid, wo->hisid) && 
966                 eui64_iszero(go->hisid)) {
967                     
968                 orc = CONFNAK;
969                 ifaceid = wo->hisid;
970                 go->hisid = ifaceid;
971                 DECPTR(sizeof(ifaceid), p);
972                 eui64_put(ifaceid, p);
973             } else
974             if (eui64_iszero(ifaceid) || eui64_equals(ifaceid, go->ourid)) {
975                 orc = CONFNAK;
976                 if (eui64_iszero(go->hisid))    /* first time, try option */
977                     ifaceid = wo->hisid;
978                 while (eui64_iszero(ifaceid) || 
979                        eui64_equals(ifaceid, go->ourid)) /* bad luck */
980                     eui64_magic(ifaceid);
981                 go->hisid = ifaceid;
982                 DECPTR(sizeof(ifaceid), p);
983                 eui64_put(ifaceid, p);
984             }
985
986             ho->neg_ifaceid = 1;
987             ho->hisid = ifaceid;
988             break;
989
990         case CI_COMPRESSTYPE:
991             IPV6CPDEBUG(("ipv6cp: received COMPRESSTYPE "));
992             if (!ao->neg_vj ||
993                 (cilen != CILEN_COMPRESS)) {
994                 orc = CONFREJ;
995                 break;
996             }
997             GETSHORT(cishort, p);
998             IPV6CPDEBUG(("(%d)", cishort));
999
1000 #ifdef IPV6CP_COMP
1001             if (!(cishort == IPV6CP_COMP)) {
1002                 orc = CONFREJ;
1003                 break;
1004             }
1005
1006             ho->neg_vj = 1;
1007             ho->vj_protocol = cishort;
1008             break;
1009 #else
1010             orc = CONFREJ;
1011             break;
1012 #endif
1013
1014         default:
1015             orc = CONFREJ;
1016             break;
1017         }
1018
1019 endswitch:
1020         IPV6CPDEBUG((" (%s)\n", CODENAME(orc)));
1021
1022         if (orc == CONFACK &&           /* Good CI */
1023             rc != CONFACK)              /*  but prior CI wasnt? */
1024             continue;                   /* Don't send this one */
1025
1026         if (orc == CONFNAK) {           /* Nak this CI? */
1027             if (reject_if_disagree)     /* Getting fed up with sending NAKs? */
1028                 orc = CONFREJ;          /* Get tough if so */
1029             else {
1030                 if (rc == CONFREJ)      /* Rejecting prior CI? */
1031                     continue;           /* Don't send this one */
1032                 if (rc == CONFACK) {    /* Ack'd all prior CIs? */
1033                     rc = CONFNAK;       /* Not anymore... */
1034                     ucp = inp;          /* Backup */
1035                 }
1036             }
1037         }
1038
1039         if (orc == CONFREJ &&           /* Reject this CI */
1040             rc != CONFREJ) {            /*  but no prior ones? */
1041             rc = CONFREJ;
1042             ucp = inp;                  /* Backup */
1043         }
1044
1045         /* Need to move CI? */
1046         if (ucp != cip)
1047             BCOPY(cip, ucp, cilen);     /* Move it */
1048
1049         /* Update output pointer */
1050         INCPTR(cilen, ucp);
1051     }
1052
1053     /*
1054      * If we aren't rejecting this packet, and we want to negotiate
1055      * their identifier and they didn't send their identifier, then we
1056      * send a NAK with a CI_IFACEID option appended.  We assume the
1057      * input buffer is long enough that we can append the extra
1058      * option safely.
1059      */
1060     if (rc != CONFREJ && !ho->neg_ifaceid &&
1061         wo->req_ifaceid && !reject_if_disagree) {
1062         if (rc == CONFACK) {
1063             rc = CONFNAK;
1064             ucp = inp;                          /* reset pointer */
1065             wo->req_ifaceid = 0;                /* don't ask again */
1066         }
1067         PUTCHAR(CI_IFACEID, ucp);
1068         PUTCHAR(CILEN_IFACEID, ucp);
1069         eui64_put(wo->hisid, ucp);
1070     }
1071
1072     *len = ucp - inp;                   /* Compute output length */
1073     IPV6CPDEBUG(("ipv6cp: returning Configure-%s", CODENAME(rc)));
1074     return (rc);                        /* Return final code */
1075 }
1076
1077
1078 /*
1079  * ipv6_check_options - check that any IP-related options are OK,
1080  * and assign appropriate defaults.
1081  */
1082 static void
1083 ipv6_check_options()
1084 {
1085     ipv6cp_options *wo = &ipv6cp_wantoptions[0];
1086
1087     if (!ipv6cp_protent.enabled_flag)
1088         return;
1089
1090 #if defined(SOL2) || defined(__linux__)
1091     /*
1092      * Persistent link-local id is only used when user has not explicitly
1093      * configure/hard-code the id
1094      */
1095     if ((wo->use_persistent) && (!wo->opt_local) && (!wo->opt_remote)) {
1096
1097         /* 
1098          * On systems where there are no Ethernet interfaces used, there
1099          * may be other ways to obtain a persistent id. Right now, it
1100          * will fall back to using magic [see eui64_magic] below when
1101          * an EUI-48 from MAC address can't be obtained. Other possibilities
1102          * include obtaining EEPROM serial numbers, or some other unique
1103          * yet persistent number. On Sparc platforms, this is possible,
1104          * but too bad there's no standards yet for x86 machines.
1105          */
1106         if (ether_to_eui64(&wo->ourid)) {
1107             wo->opt_local = 1;
1108         }
1109     }
1110 #endif
1111
1112     if (!wo->opt_local) {       /* init interface identifier */
1113         if (wo->use_ip && eui64_iszero(wo->ourid)) {
1114             eui64_setlo32(wo->ourid, ntohl(ipcp_wantoptions[0].ouraddr));
1115             if (!eui64_iszero(wo->ourid))
1116                 wo->opt_local = 1;
1117         }
1118         
1119         while (eui64_iszero(wo->ourid))
1120             eui64_magic(wo->ourid);
1121     }
1122
1123     if (!wo->opt_remote) {
1124         if (wo->use_ip && eui64_iszero(wo->hisid)) {
1125             eui64_setlo32(wo->hisid, ntohl(ipcp_wantoptions[0].hisaddr));
1126             if (!eui64_iszero(wo->hisid))
1127                 wo->opt_remote = 1;
1128         }
1129     }
1130
1131     if (demand && (eui64_iszero(wo->ourid) || eui64_iszero(wo->hisid))) {
1132         option_error("local/remote LL address required for demand-dialling\n");
1133         exit(1);
1134     }
1135 }
1136
1137
1138 /*
1139  * ipv6_demand_conf - configure the interface as though
1140  * IPV6CP were up, for use with dial-on-demand.
1141  */
1142 static int
1143 ipv6_demand_conf(u)
1144     int u;
1145 {
1146     ipv6cp_options *wo = &ipv6cp_wantoptions[u];
1147
1148 #if defined(__linux__) || defined(SOL2) || (defined(SVR4) && (defined(SNI) || defined(__USLC__)))
1149 #if defined(SOL2)
1150     if (!sif6up(u))
1151         return 0;
1152 #else
1153     if (!sifup(u))
1154         return 0;
1155 #endif /* defined(SOL2) */
1156 #endif    
1157     if (!sif6addr(u, wo->ourid, wo->hisid))
1158         return 0;
1159 #if !defined(__linux__) && !(defined(SVR4) && (defined(SNI) || defined(__USLC__)))
1160     if (!sifup(u))
1161         return 0;
1162 #endif
1163     if (!sifnpmode(u, PPP_IPV6, NPMODE_QUEUE))
1164         return 0;
1165
1166     notice("ipv6_demand_conf");
1167     notice("local  LL address %s", llv6_ntoa(wo->ourid));
1168     notice("remote LL address %s", llv6_ntoa(wo->hisid));
1169
1170     return 1;
1171 }
1172
1173
1174 /*
1175  * ipv6cp_up - IPV6CP has come UP.
1176  *
1177  * Configure the IPv6 network interface appropriately and bring it up.
1178  */
1179 static void
1180 ipv6cp_up(f)
1181     fsm *f;
1182 {
1183     ipv6cp_options *ho = &ipv6cp_hisoptions[f->unit];
1184     ipv6cp_options *go = &ipv6cp_gotoptions[f->unit];
1185     ipv6cp_options *wo = &ipv6cp_wantoptions[f->unit];
1186
1187     IPV6CPDEBUG(("ipv6cp: up"));
1188
1189     /*
1190      * We must have a non-zero LL address for both ends of the link.
1191      */
1192     if (!ho->neg_ifaceid)
1193         ho->hisid = wo->hisid;
1194
1195     if(!no_ifaceid_neg) {
1196         if (eui64_iszero(ho->hisid)) {
1197             error("Could not determine remote LL address");
1198             ipv6cp_close(f->unit, "Could not determine remote LL address");
1199             return;
1200         }
1201         if (eui64_iszero(go->ourid)) {
1202             error("Could not determine local LL address");
1203             ipv6cp_close(f->unit, "Could not determine local LL address");
1204             return;
1205         }
1206         if (eui64_equals(go->ourid, ho->hisid)) {
1207             error("local and remote LL addresses are equal");
1208             ipv6cp_close(f->unit, "local and remote LL addresses are equal");
1209             return;
1210         }
1211     }
1212     script_setenv("LLLOCAL", llv6_ntoa(go->ourid), 0);
1213     script_setenv("LLREMOTE", llv6_ntoa(ho->hisid), 0);
1214
1215 #ifdef IPV6CP_COMP
1216     /* set tcp compression */
1217     sif6comp(f->unit, ho->neg_vj);
1218 #endif
1219
1220     /*
1221      * If we are doing dial-on-demand, the interface is already
1222      * configured, so we put out any saved-up packets, then set the
1223      * interface to pass IPv6 packets.
1224      */
1225     if (demand) {
1226         if (! eui64_equals(go->ourid, wo->ourid) || 
1227             ! eui64_equals(ho->hisid, wo->hisid)) {
1228             if (! eui64_equals(go->ourid, wo->ourid))
1229                 warn("Local LL address changed to %s", 
1230                      llv6_ntoa(go->ourid));
1231             if (! eui64_equals(ho->hisid, wo->hisid))
1232                 warn("Remote LL address changed to %s", 
1233                      llv6_ntoa(ho->hisid));
1234             ipv6cp_clear_addrs(f->unit, go->ourid, ho->hisid);
1235
1236             /* Set the interface to the new addresses */
1237             if (!sif6addr(f->unit, go->ourid, ho->hisid)) {
1238                 if (debug)
1239                     warn("sif6addr failed");
1240                 ipv6cp_close(f->unit, "Interface configuration failed");
1241                 return;
1242             }
1243
1244         }
1245         demand_rexmit(PPP_IPV6);
1246         sifnpmode(f->unit, PPP_IPV6, NPMODE_PASS);
1247
1248     } else {
1249         /*
1250          * Set LL addresses
1251          */
1252 #if !defined(__linux__) && !defined(SOL2) && !(defined(SVR4) && (defined(SNI) || defined(__USLC__)))
1253         if (!sif6addr(f->unit, go->ourid, ho->hisid)) {
1254             if (debug)
1255                 warn("sif6addr failed");
1256             ipv6cp_close(f->unit, "Interface configuration failed");
1257             return;
1258         }
1259 #endif
1260
1261         /* bring the interface up for IPv6 */
1262 #if defined(SOL2)
1263         if (!sif6up(f->unit)) {
1264             if (debug)
1265                 warn("sifup failed (IPV6)");
1266             ipv6cp_close(f->unit, "Interface configuration failed");
1267             return;
1268         }
1269 #else
1270         if (!sifup(f->unit)) {
1271             if (debug)
1272                 warn("sifup failed (IPV6)");
1273             ipv6cp_close(f->unit, "Interface configuration failed");
1274             return;
1275         }
1276 #endif /* defined(SOL2) */
1277
1278 #if defined(__linux__) || defined(SOL2) || (defined(SVR4) && (defined(SNI) || defined(__USLC__)))
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 #endif
1286         sifnpmode(f->unit, PPP_IPV6, NPMODE_PASS);
1287
1288         notice("local  LL address %s", llv6_ntoa(go->ourid));
1289         notice("remote LL address %s", llv6_ntoa(ho->hisid));
1290     }
1291
1292     np_up(f->unit, PPP_IPV6);
1293     ipv6cp_is_up = 1;
1294
1295     notify(ipv6_up_notifier, 0);
1296     if (ipv6_up_hook)
1297        ipv6_up_hook();
1298
1299     /*
1300      * Execute the ipv6-up script, like this:
1301      *  /etc/ppp/ipv6-up interface tty speed local-LL remote-LL
1302      */
1303     if (ipv6cp_script_state == s_down && ipv6cp_script_pid == 0) {
1304         ipv6cp_script_state = s_up;
1305         ipv6cp_script(_PATH_IPV6UP);
1306     }
1307 }
1308
1309
1310 /*
1311  * ipv6cp_down - IPV6CP has gone DOWN.
1312  *
1313  * Take the IPv6 network interface down, clear its addresses
1314  * and delete routes through it.
1315  */
1316 static void
1317 ipv6cp_down(f)
1318     fsm *f;
1319 {
1320     IPV6CPDEBUG(("ipv6cp: down"));
1321     update_link_stats(f->unit);
1322     notify(ipv6_down_notifier, 0);
1323     if (ipv6_down_hook)
1324        ipv6_down_hook();
1325     if (ipv6cp_is_up) {
1326         ipv6cp_is_up = 0;
1327         np_down(f->unit, PPP_IPV6);
1328     }
1329 #ifdef IPV6CP_COMP
1330     sif6comp(f->unit, 0);
1331 #endif
1332
1333     /*
1334      * If we are doing dial-on-demand, set the interface
1335      * to queue up outgoing packets (for now).
1336      */
1337     if (demand) {
1338         sifnpmode(f->unit, PPP_IPV6, NPMODE_QUEUE);
1339     } else {
1340         sifnpmode(f->unit, PPP_IPV6, NPMODE_DROP);
1341 #if !defined(__linux__) && !(defined(SVR4) && (defined(SNI) || defined(__USLC)))
1342 #if defined(SOL2)
1343         sif6down(f->unit);
1344 #else
1345         sifdown(f->unit);
1346 #endif /* defined(SOL2) */
1347 #endif
1348         ipv6cp_clear_addrs(f->unit, 
1349                            ipv6cp_gotoptions[f->unit].ourid,
1350                            ipv6cp_hisoptions[f->unit].hisid);
1351 #if defined(__linux__) || (defined(SVR4) && (defined(SNI) || defined(__USLC)))
1352         sifdown(f->unit);
1353 #endif
1354     }
1355
1356     /* Execute the ipv6-down script */
1357     if (ipv6cp_script_state == s_up && ipv6cp_script_pid == 0) {
1358         ipv6cp_script_state = s_down;
1359         ipv6cp_script(_PATH_IPV6DOWN);
1360     }
1361 }
1362
1363
1364 /*
1365  * ipv6cp_clear_addrs() - clear the interface addresses, routes,
1366  * proxy neighbour discovery entries, etc.
1367  */
1368 static void
1369 ipv6cp_clear_addrs(unit, ourid, hisid)
1370     int unit;
1371     eui64_t ourid;
1372     eui64_t hisid;
1373 {
1374     cif6addr(unit, ourid, hisid);
1375 }
1376
1377
1378 /*
1379  * ipv6cp_finished - possibly shut down the lower layers.
1380  */
1381 static void
1382 ipv6cp_finished(f)
1383     fsm *f;
1384 {
1385     np_finished(f->unit, PPP_IPV6);
1386 }
1387
1388
1389 /*
1390  * ipv6cp_script_done - called when the ipv6-up or ipv6-down script
1391  * has finished.
1392  */
1393 static void
1394 ipv6cp_script_done(arg)
1395     void *arg;
1396 {
1397     ipv6cp_script_pid = 0;
1398     switch (ipv6cp_script_state) {
1399     case s_up:
1400         if (ipv6cp_fsm[0].state != OPENED) {
1401             ipv6cp_script_state = s_down;
1402             ipv6cp_script(_PATH_IPV6DOWN);
1403         }
1404         break;
1405     case s_down:
1406         if (ipv6cp_fsm[0].state == OPENED) {
1407             ipv6cp_script_state = s_up;
1408             ipv6cp_script(_PATH_IPV6UP);
1409         }
1410         break;
1411     }
1412 }
1413
1414
1415 /*
1416  * ipv6cp_script - Execute a script with arguments
1417  * interface-name tty-name speed local-LL remote-LL.
1418  */
1419 static void
1420 ipv6cp_script(script)
1421     char *script;
1422 {
1423     char strspeed[32], strlocal[32], strremote[32];
1424     char *argv[8];
1425
1426     sprintf(strspeed, "%d", baud_rate);
1427     strcpy(strlocal, llv6_ntoa(ipv6cp_gotoptions[0].ourid));
1428     strcpy(strremote, llv6_ntoa(ipv6cp_hisoptions[0].hisid));
1429
1430     argv[0] = script;
1431     argv[1] = ifname;
1432     argv[2] = devnam;
1433     argv[3] = strspeed;
1434     argv[4] = strlocal;
1435     argv[5] = strremote;
1436     argv[6] = ipparam;
1437     argv[7] = NULL;
1438
1439     ipv6cp_script_pid = run_program(script, argv, 0, ipv6cp_script_done,
1440                                     NULL, 0);
1441 }
1442
1443 /*
1444  * ipv6cp_printpkt - print the contents of an IPV6CP packet.
1445  */
1446 static char *ipv6cp_codenames[] = {
1447     "ConfReq", "ConfAck", "ConfNak", "ConfRej",
1448     "TermReq", "TermAck", "CodeRej"
1449 };
1450
1451 static int
1452 ipv6cp_printpkt(p, plen, printer, arg)
1453     u_char *p;
1454     int plen;
1455     void (*printer) __P((void *, char *, ...));
1456     void *arg;
1457 {
1458     int code, id, len, olen;
1459     u_char *pstart, *optend;
1460     u_short cishort;
1461     eui64_t ifaceid;
1462
1463     if (plen < HEADERLEN)
1464         return 0;
1465     pstart = p;
1466     GETCHAR(code, p);
1467     GETCHAR(id, p);
1468     GETSHORT(len, p);
1469     if (len < HEADERLEN || len > plen)
1470         return 0;
1471
1472     if (code >= 1 && code <= sizeof(ipv6cp_codenames) / sizeof(char *))
1473         printer(arg, " %s", ipv6cp_codenames[code-1]);
1474     else
1475         printer(arg, " code=0x%x", code);
1476     printer(arg, " id=0x%x", id);
1477     len -= HEADERLEN;
1478     switch (code) {
1479     case CONFREQ:
1480     case CONFACK:
1481     case CONFNAK:
1482     case CONFREJ:
1483         /* print option list */
1484         while (len >= 2) {
1485             GETCHAR(code, p);
1486             GETCHAR(olen, p);
1487             p -= 2;
1488             if (olen < 2 || olen > len) {
1489                 break;
1490             }
1491             printer(arg, " <");
1492             len -= olen;
1493             optend = p + olen;
1494             switch (code) {
1495             case CI_COMPRESSTYPE:
1496                 if (olen >= CILEN_COMPRESS) {
1497                     p += 2;
1498                     GETSHORT(cishort, p);
1499                     printer(arg, "compress ");
1500                     printer(arg, "0x%x", cishort);
1501                 }
1502                 break;
1503             case CI_IFACEID:
1504                 if (olen == CILEN_IFACEID) {
1505                     p += 2;
1506                     eui64_get(ifaceid, p);
1507                     printer(arg, "addr %s", llv6_ntoa(ifaceid));
1508                 }
1509                 break;
1510             }
1511             while (p < optend) {
1512                 GETCHAR(code, p);
1513                 printer(arg, " %.2x", code);
1514             }
1515             printer(arg, ">");
1516         }
1517         break;
1518
1519     case TERMACK:
1520     case TERMREQ:
1521         if (len > 0 && *p >= ' ' && *p < 0x7f) {
1522             printer(arg, " ");
1523             print_string((char *)p, len, printer, arg);
1524             p += len;
1525             len = 0;
1526         }
1527         break;
1528     }
1529
1530     /* print the rest of the bytes in the packet */
1531     for (; len > 0; --len) {
1532         GETCHAR(code, p);
1533         printer(arg, " %.2x", code);
1534     }
1535
1536     return p - pstart;
1537 }
1538
1539 /*
1540  * ipv6_active_pkt - see if this IP packet is worth bringing the link up for.
1541  * We don't bring the link up for IP fragments or for TCP FIN packets
1542  * with no data.
1543  */
1544 #define IP6_HDRLEN      40      /* bytes */
1545 #define IP6_NHDR_FRAG   44      /* fragment IPv6 header */
1546 #define TCP_HDRLEN      20
1547 #define TH_FIN          0x01
1548
1549 /*
1550  * We use these macros because the IP header may be at an odd address,
1551  * and some compilers might use word loads to get th_off or ip_hl.
1552  */
1553
1554 #define get_ip6nh(x)    (((unsigned char *)(x))[6])
1555 #define get_tcpoff(x)   (((unsigned char *)(x))[12] >> 4)
1556 #define get_tcpflags(x) (((unsigned char *)(x))[13])
1557
1558 static int
1559 ipv6_active_pkt(pkt, len)
1560     u_char *pkt;
1561     int len;
1562 {
1563     u_char *tcp;
1564
1565     len -= PPP_HDRLEN;
1566     pkt += PPP_HDRLEN;
1567     if (len < IP6_HDRLEN)
1568         return 0;
1569     if (get_ip6nh(pkt) == IP6_NHDR_FRAG)
1570         return 0;
1571     if (get_ip6nh(pkt) != IPPROTO_TCP)
1572         return 1;
1573     if (len < IP6_HDRLEN + TCP_HDRLEN)
1574         return 0;
1575     tcp = pkt + IP6_HDRLEN;
1576     if ((get_tcpflags(tcp) & TH_FIN) != 0 && len == IP6_HDRLEN + get_tcpoff(tcp) * 4)
1577         return 0;
1578     return 1;
1579 }