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