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