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