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