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