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