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