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