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