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