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