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