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