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