]> git.ozlabs.org Git - ppp.git/blob - pppd/ipv6cp.c
New options system with priorities for option values, with options
[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.13 2001/03/08 05:11:12 paulus Exp $ 
94  */
95
96 #define RCSID   "$Id: ipv6cp.c,v 1.13 2001/03/08 05:11:12 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 printipaddr(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 defined(SOL2)
1028     /*
1029      * Persistent link-local id is only used when user has not explicitly
1030      * configure/hard-code the id
1031      */
1032     if ((wo->use_persistent) && (!wo->opt_local) && (!wo->opt_remote)) {
1033
1034         /* 
1035          * On systems where there are no Ethernet interfaces used, there
1036          * may be other ways to obtain a persistent id. Right now, it
1037          * will fall back to using magic [see eui64_magic] below when
1038          * an EUI-48 from MAC address can't be obtained. Other possibilities
1039          * include obtaining EEPROM serial numbers, or some other unique
1040          * yet persistent number. On Sparc platforms, this is possible,
1041          * but too bad there's no standards yet for x86 machines.
1042          */
1043         if (ether_to_eui64(&wo->ourid)) {
1044             wo->opt_local = 1;
1045         }
1046     }
1047 #endif
1048
1049     if (!wo->opt_local) {       /* init interface identifier */
1050         if (wo->use_ip && eui64_iszero(wo->ourid)) {
1051             eui64_setlo32(wo->ourid, ntohl(ipcp_wantoptions[0].ouraddr));
1052             if (!eui64_iszero(wo->ourid))
1053                 wo->opt_local = 1;
1054         }
1055         
1056         while (eui64_iszero(wo->ourid))
1057             eui64_magic(wo->ourid);
1058     }
1059
1060     if (!wo->opt_remote) {
1061         if (wo->use_ip && eui64_iszero(wo->hisid)) {
1062             eui64_setlo32(wo->hisid, ntohl(ipcp_wantoptions[0].hisaddr));
1063             if (!eui64_iszero(wo->hisid))
1064                 wo->opt_remote = 1;
1065         }
1066     }
1067
1068     if (demand && (eui64_iszero(wo->ourid) || eui64_iszero(wo->hisid))) {
1069         option_error("local/remote LL address required for demand-dialling\n");
1070         exit(1);
1071     }
1072 }
1073
1074
1075 /*
1076  * ipv6_demand_conf - configure the interface as though
1077  * IPV6CP were up, for use with dial-on-demand.
1078  */
1079 static int
1080 ipv6_demand_conf(u)
1081     int u;
1082 {
1083     ipv6cp_options *wo = &ipv6cp_wantoptions[u];
1084
1085 #if defined(__linux__) || defined(SOL2) || (defined(SVR4) && (defined(SNI) || defined(__USLC__)))
1086 #if defined(SOL2)
1087     if (!sif6up(u))
1088         return 0;
1089 #else
1090     if (!sifup(u))
1091         return 0;
1092 #endif /* defined(SOL2) */
1093 #endif    
1094     if (!sif6addr(u, wo->ourid, wo->hisid))
1095         return 0;
1096 #if !defined(__linux__) && !(defined(SVR4) && (defined(SNI) || defined(__USLC__)))
1097     if (!sifup(u))
1098         return 0;
1099 #endif
1100     if (!sifnpmode(u, PPP_IPV6, NPMODE_QUEUE))
1101         return 0;
1102
1103     notice("ipv6_demand_conf");
1104     notice("local  LL address %s", llv6_ntoa(wo->ourid));
1105     notice("remote LL address %s", llv6_ntoa(wo->hisid));
1106
1107     return 1;
1108 }
1109
1110
1111 /*
1112  * ipv6cp_up - IPV6CP has come UP.
1113  *
1114  * Configure the IPv6 network interface appropriately and bring it up.
1115  */
1116 static void
1117 ipv6cp_up(f)
1118     fsm *f;
1119 {
1120     ipv6cp_options *ho = &ipv6cp_hisoptions[f->unit];
1121     ipv6cp_options *go = &ipv6cp_gotoptions[f->unit];
1122     ipv6cp_options *wo = &ipv6cp_wantoptions[f->unit];
1123
1124     IPV6CPDEBUG(("ipv6cp: up"));
1125
1126     /*
1127      * We must have a non-zero LL address for both ends of the link.
1128      */
1129     if (!ho->neg_ifaceid)
1130         ho->hisid = wo->hisid;
1131
1132     if(!no_ifaceid_neg) {
1133         if (eui64_iszero(ho->hisid)) {
1134             error("Could not determine remote LL address");
1135             ipv6cp_close(f->unit, "Could not determine remote LL address");
1136             return;
1137         }
1138         if (eui64_iszero(go->ourid)) {
1139             error("Could not determine local LL address");
1140             ipv6cp_close(f->unit, "Could not determine local LL address");
1141             return;
1142         }
1143         if (eui64_equals(go->ourid, ho->hisid)) {
1144             error("local and remote LL addresses are equal");
1145             ipv6cp_close(f->unit, "local and remote LL addresses are equal");
1146             return;
1147         }
1148     }
1149     script_setenv("LLLOCAL", llv6_ntoa(go->ourid), 0);
1150     script_setenv("LLREMOTE", llv6_ntoa(ho->hisid), 0);
1151
1152 #ifdef IPV6CP_COMP
1153     /* set tcp compression */
1154     sif6comp(f->unit, ho->neg_vj);
1155 #endif
1156
1157     /*
1158      * If we are doing dial-on-demand, the interface is already
1159      * configured, so we put out any saved-up packets, then set the
1160      * interface to pass IPv6 packets.
1161      */
1162     if (demand) {
1163         if (! eui64_equals(go->ourid, wo->ourid) || 
1164             ! eui64_equals(ho->hisid, wo->hisid)) {
1165             if (! eui64_equals(go->ourid, wo->ourid))
1166                 warn("Local LL address changed to %s", 
1167                      llv6_ntoa(go->ourid));
1168             if (! eui64_equals(ho->hisid, wo->hisid))
1169                 warn("Remote LL address changed to %s", 
1170                      llv6_ntoa(ho->hisid));
1171             ipv6cp_clear_addrs(f->unit, go->ourid, ho->hisid);
1172
1173             /* Set the interface to the new addresses */
1174             if (!sif6addr(f->unit, go->ourid, ho->hisid)) {
1175                 if (debug)
1176                     warn("sif6addr failed");
1177                 ipv6cp_close(f->unit, "Interface configuration failed");
1178                 return;
1179             }
1180
1181         }
1182         demand_rexmit(PPP_IPV6);
1183         sifnpmode(f->unit, PPP_IPV6, NPMODE_PASS);
1184
1185     } else {
1186         /*
1187          * Set LL addresses
1188          */
1189 #if !defined(__linux__) && !defined(SOL2) && !(defined(SVR4) && (defined(SNI) || defined(__USLC__)))
1190         if (!sif6addr(f->unit, go->ourid, ho->hisid)) {
1191             if (debug)
1192                 warn("sif6addr failed");
1193             ipv6cp_close(f->unit, "Interface configuration failed");
1194             return;
1195         }
1196 #endif
1197
1198         /* bring the interface up for IPv6 */
1199 #if defined(SOL2)
1200         if (!sif6up(f->unit)) {
1201             if (debug)
1202                 warn("sifup failed (IPV6)");
1203             ipv6cp_close(f->unit, "Interface configuration failed");
1204             return;
1205         }
1206 #else
1207         if (!sifup(f->unit)) {
1208             if (debug)
1209                 warn("sifup failed (IPV6)");
1210             ipv6cp_close(f->unit, "Interface configuration failed");
1211             return;
1212         }
1213 #endif /* defined(SOL2) */
1214
1215 #if defined(__linux__) || defined(SOL2) || (defined(SVR4) && (defined(SNI) || defined(__USLC__)))
1216         if (!sif6addr(f->unit, go->ourid, ho->hisid)) {
1217             if (debug)
1218                 warn("sif6addr failed");
1219             ipv6cp_close(f->unit, "Interface configuration failed");
1220             return;
1221         }
1222 #endif
1223         sifnpmode(f->unit, PPP_IPV6, NPMODE_PASS);
1224
1225         notice("local  LL address %s", llv6_ntoa(go->ourid));
1226         notice("remote LL address %s", llv6_ntoa(ho->hisid));
1227     }
1228
1229     np_up(f->unit, PPP_IPV6);
1230     ipv6cp_is_up = 1;
1231
1232     /*
1233      * Execute the ipv6-up script, like this:
1234      *  /etc/ppp/ipv6-up interface tty speed local-LL remote-LL
1235      */
1236     if (ipv6cp_script_state == s_down && ipv6cp_script_pid == 0) {
1237         ipv6cp_script_state = s_up;
1238         ipv6cp_script(_PATH_IPV6UP);
1239     }
1240 }
1241
1242
1243 /*
1244  * ipv6cp_down - IPV6CP has gone DOWN.
1245  *
1246  * Take the IPv6 network interface down, clear its addresses
1247  * and delete routes through it.
1248  */
1249 static void
1250 ipv6cp_down(f)
1251     fsm *f;
1252 {
1253     IPV6CPDEBUG(("ipv6cp: down"));
1254     update_link_stats(f->unit);
1255     if (ipv6cp_is_up) {
1256         ipv6cp_is_up = 0;
1257         np_down(f->unit, PPP_IPV6);
1258     }
1259 #ifdef IPV6CP_COMP
1260     sif6comp(f->unit, 0);
1261 #endif
1262
1263     /*
1264      * If we are doing dial-on-demand, set the interface
1265      * to queue up outgoing packets (for now).
1266      */
1267     if (demand) {
1268         sifnpmode(f->unit, PPP_IPV6, NPMODE_QUEUE);
1269     } else {
1270         sifnpmode(f->unit, PPP_IPV6, NPMODE_DROP);
1271 #if !defined(__linux__) && !(defined(SVR4) && (defined(SNI) || defined(__USLC)))
1272 #if defined(SOL2)
1273         sif6down(f->unit);
1274 #else
1275         sifdown(f->unit);
1276 #endif /* defined(SOL2) */
1277 #endif
1278         ipv6cp_clear_addrs(f->unit, 
1279                            ipv6cp_gotoptions[f->unit].ourid,
1280                            ipv6cp_hisoptions[f->unit].hisid);
1281 #if defined(__linux__) || (defined(SVR4) && (defined(SNI) || defined(__USLC)))
1282         sifdown(f->unit);
1283 #endif
1284     }
1285
1286     /* Execute the ipv6-down script */
1287     if (ipv6cp_script_state == s_up && ipv6cp_script_pid == 0) {
1288         ipv6cp_script_state = s_down;
1289         ipv6cp_script(_PATH_IPV6DOWN);
1290     }
1291 }
1292
1293
1294 /*
1295  * ipv6cp_clear_addrs() - clear the interface addresses, routes,
1296  * proxy neighbour discovery entries, etc.
1297  */
1298 static void
1299 ipv6cp_clear_addrs(unit, ourid, hisid)
1300     int unit;
1301     eui64_t ourid;
1302     eui64_t hisid;
1303 {
1304     cif6addr(unit, ourid, hisid);
1305 }
1306
1307
1308 /*
1309  * ipv6cp_finished - possibly shut down the lower layers.
1310  */
1311 static void
1312 ipv6cp_finished(f)
1313     fsm *f;
1314 {
1315     np_finished(f->unit, PPP_IPV6);
1316 }
1317
1318
1319 /*
1320  * ipv6cp_script_done - called when the ipv6-up or ipv6-down script
1321  * has finished.
1322  */
1323 static void
1324 ipv6cp_script_done(arg)
1325     void *arg;
1326 {
1327     ipv6cp_script_pid = 0;
1328     switch (ipv6cp_script_state) {
1329     case s_up:
1330         if (ipv6cp_fsm[0].state != OPENED) {
1331             ipv6cp_script_state = s_down;
1332             ipv6cp_script(_PATH_IPV6DOWN);
1333         }
1334         break;
1335     case s_down:
1336         if (ipv6cp_fsm[0].state == OPENED) {
1337             ipv6cp_script_state = s_up;
1338             ipv6cp_script(_PATH_IPV6UP);
1339         }
1340         break;
1341     }
1342 }
1343
1344
1345 /*
1346  * ipv6cp_script - Execute a script with arguments
1347  * interface-name tty-name speed local-LL remote-LL.
1348  */
1349 static void
1350 ipv6cp_script(script)
1351     char *script;
1352 {
1353     char strspeed[32], strlocal[32], strremote[32];
1354     char *argv[8];
1355
1356     sprintf(strspeed, "%d", baud_rate);
1357     strcpy(strlocal, llv6_ntoa(ipv6cp_gotoptions[0].ourid));
1358     strcpy(strremote, llv6_ntoa(ipv6cp_hisoptions[0].hisid));
1359
1360     argv[0] = script;
1361     argv[1] = ifname;
1362     argv[2] = devnam;
1363     argv[3] = strspeed;
1364     argv[4] = strlocal;
1365     argv[5] = strremote;
1366     argv[6] = ipparam;
1367     argv[7] = NULL;
1368
1369     ipv6cp_script_pid = run_program(script, argv, 0, ipv6cp_script_done, NULL);
1370 }
1371
1372 /*
1373  * ipv6cp_printpkt - print the contents of an IPV6CP packet.
1374  */
1375 static char *ipv6cp_codenames[] = {
1376     "ConfReq", "ConfAck", "ConfNak", "ConfRej",
1377     "TermReq", "TermAck", "CodeRej"
1378 };
1379
1380 static int
1381 ipv6cp_printpkt(p, plen, printer, arg)
1382     u_char *p;
1383     int plen;
1384     void (*printer) __P((void *, char *, ...));
1385     void *arg;
1386 {
1387     int code, id, len, olen;
1388     u_char *pstart, *optend;
1389     u_short cishort;
1390     eui64_t ifaceid;
1391
1392     if (plen < HEADERLEN)
1393         return 0;
1394     pstart = p;
1395     GETCHAR(code, p);
1396     GETCHAR(id, p);
1397     GETSHORT(len, p);
1398     if (len < HEADERLEN || len > plen)
1399         return 0;
1400
1401     if (code >= 1 && code <= sizeof(ipv6cp_codenames) / sizeof(char *))
1402         printer(arg, " %s", ipv6cp_codenames[code-1]);
1403     else
1404         printer(arg, " code=0x%x", code);
1405     printer(arg, " id=0x%x", id);
1406     len -= HEADERLEN;
1407     switch (code) {
1408     case CONFREQ:
1409     case CONFACK:
1410     case CONFNAK:
1411     case CONFREJ:
1412         /* print option list */
1413         while (len >= 2) {
1414             GETCHAR(code, p);
1415             GETCHAR(olen, p);
1416             p -= 2;
1417             if (olen < 2 || olen > len) {
1418                 break;
1419             }
1420             printer(arg, " <");
1421             len -= olen;
1422             optend = p + olen;
1423             switch (code) {
1424             case CI_COMPRESSTYPE:
1425                 if (olen >= CILEN_COMPRESS) {
1426                     p += 2;
1427                     GETSHORT(cishort, p);
1428                     printer(arg, "compress ");
1429                     printer(arg, "0x%x", cishort);
1430                 }
1431                 break;
1432             case CI_IFACEID:
1433                 if (olen == CILEN_IFACEID) {
1434                     p += 2;
1435                     eui64_get(ifaceid, p);
1436                     printer(arg, "addr %s", llv6_ntoa(ifaceid));
1437                 }
1438                 break;
1439             }
1440             while (p < optend) {
1441                 GETCHAR(code, p);
1442                 printer(arg, " %.2x", code);
1443             }
1444             printer(arg, ">");
1445         }
1446         break;
1447
1448     case TERMACK:
1449     case TERMREQ:
1450         if (len > 0 && *p >= ' ' && *p < 0x7f) {
1451             printer(arg, " ");
1452             print_string((char *)p, len, printer, arg);
1453             p += len;
1454             len = 0;
1455         }
1456         break;
1457     }
1458
1459     /* print the rest of the bytes in the packet */
1460     for (; len > 0; --len) {
1461         GETCHAR(code, p);
1462         printer(arg, " %.2x", code);
1463     }
1464
1465     return p - pstart;
1466 }
1467
1468 /*
1469  * ipv6_active_pkt - see if this IP packet is worth bringing the link up for.
1470  * We don't bring the link up for IP fragments or for TCP FIN packets
1471  * with no data.
1472  */
1473 #define IP6_HDRLEN      40      /* bytes */
1474 #define IP6_NHDR_FRAG   44      /* fragment IPv6 header */
1475 #define IPPROTO_TCP     6
1476 #define TCP_HDRLEN      20
1477 #define TH_FIN          0x01
1478
1479 /*
1480  * We use these macros because the IP header may be at an odd address,
1481  * and some compilers might use word loads to get th_off or ip_hl.
1482  */
1483
1484 #define get_ip6nh(x)    (((unsigned char *)(x))[6])
1485 #define get_tcpoff(x)   (((unsigned char *)(x))[12] >> 4)
1486 #define get_tcpflags(x) (((unsigned char *)(x))[13])
1487
1488 static int
1489 ipv6_active_pkt(pkt, len)
1490     u_char *pkt;
1491     int len;
1492 {
1493     u_char *tcp;
1494
1495     len -= PPP_HDRLEN;
1496     pkt += PPP_HDRLEN;
1497     if (len < IP6_HDRLEN)
1498         return 0;
1499     if (get_ip6nh(pkt) == IP6_NHDR_FRAG)
1500         return 0;
1501     if (get_ip6nh(pkt) != IPPROTO_TCP)
1502         return 1;
1503     if (len < IP6_HDRLEN + TCP_HDRLEN)
1504         return 0;
1505     tcp = pkt + IP6_HDRLEN;
1506     if ((get_tcpflags(tcp) & TH_FIN) != 0 && len == IP6_HDRLEN + get_tcpoff(tcp) * 4)
1507         return 0;
1508     return 1;
1509 }