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