17c478bd9Sstevel@tonic-gate /*
2f53eecf5SJames Carlson  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
37c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
448bbca81SDaniel Hoffman  * Copyright (c) 2016 by Delphix. All rights reserved.
548bbca81SDaniel Hoffman  *
67c478bd9Sstevel@tonic-gate  *
77c478bd9Sstevel@tonic-gate     ipv6cp.c - PPP IPV6 Control Protocol.
87c478bd9Sstevel@tonic-gate     Copyright (C) 1999  Tommi Komulainen <Tommi.Komulainen@iki.fi>
97c478bd9Sstevel@tonic-gate 
107c478bd9Sstevel@tonic-gate     Redistribution and use in source and binary forms are permitted
117c478bd9Sstevel@tonic-gate     provided that the above copyright notice and this paragraph are
127c478bd9Sstevel@tonic-gate     duplicated in all such forms.  The name of the author may not be
137c478bd9Sstevel@tonic-gate     used to endorse or promote products derived from this software
147c478bd9Sstevel@tonic-gate     without specific prior written permission.
157c478bd9Sstevel@tonic-gate     THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
167c478bd9Sstevel@tonic-gate     IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
177c478bd9Sstevel@tonic-gate     WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
187c478bd9Sstevel@tonic-gate */
197c478bd9Sstevel@tonic-gate 
207c478bd9Sstevel@tonic-gate /*  Original version, based on RFC2023 :
217c478bd9Sstevel@tonic-gate 
227c478bd9Sstevel@tonic-gate     Copyright (c) 1995, 1996, 1997 Francis.Dupont@inria.fr, INRIA Rocquencourt,
237c478bd9Sstevel@tonic-gate     Alain.Durand@imag.fr, IMAG,
247c478bd9Sstevel@tonic-gate     Jean-Luc.Richier@imag.fr, IMAG-LSR.
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate     Copyright (c) 1998, 1999 Francis.Dupont@inria.fr, GIE DYADE,
277c478bd9Sstevel@tonic-gate     Alain.Durand@imag.fr, IMAG,
287c478bd9Sstevel@tonic-gate     Jean-Luc.Richier@imag.fr, IMAG-LSR.
297c478bd9Sstevel@tonic-gate 
307c478bd9Sstevel@tonic-gate     Ce travail a �t� fait au sein du GIE DYADE (Groupement d'Int�r�t
317c478bd9Sstevel@tonic-gate     �conomique ayant pour membres BULL S.A. et l'INRIA).
327c478bd9Sstevel@tonic-gate 
337c478bd9Sstevel@tonic-gate     Ce logiciel informatique est disponible aux conditions
347c478bd9Sstevel@tonic-gate     usuelles dans la recherche, c'est-�-dire qu'il peut
357c478bd9Sstevel@tonic-gate     �tre utilis�, copi�, modifi�, distribu� � l'unique
367c478bd9Sstevel@tonic-gate     condition que ce texte soit conserv� afin que
377c478bd9Sstevel@tonic-gate     l'origine de ce logiciel soit reconnue.
387c478bd9Sstevel@tonic-gate 
397c478bd9Sstevel@tonic-gate     Le nom de l'Institut National de Recherche en Informatique
407c478bd9Sstevel@tonic-gate     et en Automatique (INRIA), de l'IMAG, ou d'une personne morale
417c478bd9Sstevel@tonic-gate     ou physique ayant particip� � l'�laboration de ce logiciel ne peut
427c478bd9Sstevel@tonic-gate     �tre utilis� sans son accord pr�alable explicite.
437c478bd9Sstevel@tonic-gate 
447c478bd9Sstevel@tonic-gate     Ce logiciel est fourni tel quel sans aucune garantie,
457c478bd9Sstevel@tonic-gate     support ou responsabilit� d'aucune sorte.
467c478bd9Sstevel@tonic-gate     Ce logiciel est d�riv� de sources d'origine
477c478bd9Sstevel@tonic-gate     "University of California at Berkeley" et
487c478bd9Sstevel@tonic-gate     "Digital Equipment Corporation" couvertes par des copyrights.
497c478bd9Sstevel@tonic-gate 
507c478bd9Sstevel@tonic-gate     L'Institut d'Informatique et de Math�matiques Appliqu�es de Grenoble (IMAG)
517c478bd9Sstevel@tonic-gate     est une f�d�ration d'unit�s mixtes de recherche du CNRS, de l'Institut National
527c478bd9Sstevel@tonic-gate     Polytechnique de Grenoble et de l'Universit� Joseph Fourier regroupant
537c478bd9Sstevel@tonic-gate     sept laboratoires dont le laboratoire Logiciels, Syst�mes, R�seaux (LSR).
547c478bd9Sstevel@tonic-gate 
557c478bd9Sstevel@tonic-gate     This work has been done in the context of GIE DYADE (joint R & D venture
567c478bd9Sstevel@tonic-gate     between BULL S.A. and INRIA).
577c478bd9Sstevel@tonic-gate 
587c478bd9Sstevel@tonic-gate     This software is available with usual "research" terms
5948bbca81SDaniel Hoffman     with the aim of retain credits of the software.
607c478bd9Sstevel@tonic-gate     Permission to use, copy, modify and distribute this software for any
617c478bd9Sstevel@tonic-gate     purpose and without fee is hereby granted, provided that the above
627c478bd9Sstevel@tonic-gate     copyright notice and this permission notice appear in all copies,
637c478bd9Sstevel@tonic-gate     and the name of INRIA, IMAG, or any contributor not be used in advertising
647c478bd9Sstevel@tonic-gate     or publicity pertaining to this material without the prior explicit
657c478bd9Sstevel@tonic-gate     permission. The software is provided "as is" without any
667c478bd9Sstevel@tonic-gate     warranties, support or liabilities of any kind.
677c478bd9Sstevel@tonic-gate     This software is derived from source code from
687c478bd9Sstevel@tonic-gate     "University of California at Berkeley" and
697c478bd9Sstevel@tonic-gate     "Digital Equipment Corporation" protected by copyrights.
707c478bd9Sstevel@tonic-gate 
717c478bd9Sstevel@tonic-gate     Grenoble's Institute of Computer Science and Applied Mathematics (IMAG)
727c478bd9Sstevel@tonic-gate     is a federation of seven research units funded by the CNRS, National
737c478bd9Sstevel@tonic-gate     Polytechnic Institute of Grenoble and University Joseph Fourier.
747c478bd9Sstevel@tonic-gate     The research unit in Software, Systems, Networks (LSR) is member of IMAG.
757c478bd9Sstevel@tonic-gate */
767c478bd9Sstevel@tonic-gate 
777c478bd9Sstevel@tonic-gate /*
787c478bd9Sstevel@tonic-gate  * Derived from :
797c478bd9Sstevel@tonic-gate  *
807c478bd9Sstevel@tonic-gate  *
817c478bd9Sstevel@tonic-gate  * ipcp.c - PPP IP Control Protocol.
827c478bd9Sstevel@tonic-gate  *
837c478bd9Sstevel@tonic-gate  * Copyright (c) 1989 Carnegie Mellon University.
847c478bd9Sstevel@tonic-gate  * All rights reserved.
857c478bd9Sstevel@tonic-gate  *
867c478bd9Sstevel@tonic-gate  * Redistribution and use in source and binary forms are permitted
877c478bd9Sstevel@tonic-gate  * provided that the above copyright notice and this paragraph are
887c478bd9Sstevel@tonic-gate  * duplicated in all such forms and that any documentation,
897c478bd9Sstevel@tonic-gate  * advertising materials, and other materials related to such
907c478bd9Sstevel@tonic-gate  * distribution and use acknowledge that the software was developed
917c478bd9Sstevel@tonic-gate  * by Carnegie Mellon University.  The name of the
927c478bd9Sstevel@tonic-gate  * University may not be used to endorse or promote products derived
937c478bd9Sstevel@tonic-gate  * from this software without specific prior written permission.
947c478bd9Sstevel@tonic-gate  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
957c478bd9Sstevel@tonic-gate  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
967c478bd9Sstevel@tonic-gate  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
977c478bd9Sstevel@tonic-gate  *
9848bbca81SDaniel Hoffman  * $Id: ipv6cp.c,v 1.9 2000/04/15 01:27:11 masputra Exp $
997c478bd9Sstevel@tonic-gate  */
1007c478bd9Sstevel@tonic-gate 
1017c478bd9Sstevel@tonic-gate /*
10248bbca81SDaniel Hoffman  * TODO:
1037c478bd9Sstevel@tonic-gate  *
1047c478bd9Sstevel@tonic-gate  * Proxy Neighbour Discovery.
1057c478bd9Sstevel@tonic-gate  *
1067c478bd9Sstevel@tonic-gate  * Better defines for selecting the ordering of
1077c478bd9Sstevel@tonic-gate  *   interface up / set address. (currently checks for __linux__,
1087c478bd9Sstevel@tonic-gate  *   since SVR4 && (SNI || __USLC__) didn't work properly)
1097c478bd9Sstevel@tonic-gate  */
1107c478bd9Sstevel@tonic-gate 
1117c478bd9Sstevel@tonic-gate #include <stdio.h>
1127c478bd9Sstevel@tonic-gate #include <string.h>
1137c478bd9Sstevel@tonic-gate #include <stdlib.h>
1147c478bd9Sstevel@tonic-gate #include <unistd.h>
1157c478bd9Sstevel@tonic-gate #include <netdb.h>
1167c478bd9Sstevel@tonic-gate #include <sys/param.h>
1177c478bd9Sstevel@tonic-gate #include <sys/types.h>
1187c478bd9Sstevel@tonic-gate #include <sys/socket.h>
1197c478bd9Sstevel@tonic-gate #include <netinet/in.h>
1207c478bd9Sstevel@tonic-gate #include <arpa/inet.h>
1217c478bd9Sstevel@tonic-gate 
1227c478bd9Sstevel@tonic-gate #include "pppd.h"
1237c478bd9Sstevel@tonic-gate #include "eui64.h"
1247c478bd9Sstevel@tonic-gate #include "fsm.h"
1257c478bd9Sstevel@tonic-gate #include "ipcp.h"
1267c478bd9Sstevel@tonic-gate #include "ipv6cp.h"
1277c478bd9Sstevel@tonic-gate #include "magic.h"
1287c478bd9Sstevel@tonic-gate #include "pathnames.h"
1297c478bd9Sstevel@tonic-gate 
1307c478bd9Sstevel@tonic-gate /* global vars */
1317c478bd9Sstevel@tonic-gate ipv6cp_options ipv6cp_wantoptions[NUM_PPP];     /* Options that we want to request */
1327c478bd9Sstevel@tonic-gate ipv6cp_options ipv6cp_gotoptions[NUM_PPP];	/* Options that peer ack'd */
1337c478bd9Sstevel@tonic-gate ipv6cp_options ipv6cp_allowoptions[NUM_PPP];	/* Options we allow peer to request */
1347c478bd9Sstevel@tonic-gate ipv6cp_options ipv6cp_hisoptions[NUM_PPP];	/* Options that we ack'd */
1357c478bd9Sstevel@tonic-gate int no_ifaceid_neg = 0;
1367c478bd9Sstevel@tonic-gate 
1377c478bd9Sstevel@tonic-gate /* local vars */
1387c478bd9Sstevel@tonic-gate static bool ipv6cp_is_up;
1397c478bd9Sstevel@tonic-gate 
1407c478bd9Sstevel@tonic-gate /*
1417c478bd9Sstevel@tonic-gate  * Callbacks for fsm code.  (CI = Configuration Information)
1427c478bd9Sstevel@tonic-gate  */
1437c478bd9Sstevel@tonic-gate static void ipv6cp_resetci __P((fsm *));	/* Reset our CI */
1447c478bd9Sstevel@tonic-gate static int  ipv6cp_cilen __P((fsm *));	        /* Return length of our CI */
1457c478bd9Sstevel@tonic-gate static void ipv6cp_addci __P((fsm *, u_char *, int *)); /* Add our CI */
1467c478bd9Sstevel@tonic-gate static int  ipv6cp_ackci __P((fsm *, u_char *, int));	/* Peer ack'd our CI */
1477c478bd9Sstevel@tonic-gate static int  ipv6cp_nakci __P((fsm *, u_char *, int));	/* Peer nak'd our CI */
1487c478bd9Sstevel@tonic-gate static int  ipv6cp_rejci __P((fsm *, u_char *, int));	/* Peer rej'd our CI */
1497c478bd9Sstevel@tonic-gate static int  ipv6cp_reqci __P((fsm *, u_char *, int *, int)); /* Rcv CI */
1507c478bd9Sstevel@tonic-gate static void ipv6cp_up __P((fsm *));		/* We're UP */
1517c478bd9Sstevel@tonic-gate static void ipv6cp_down __P((fsm *));		/* We're DOWN */
1527c478bd9Sstevel@tonic-gate static void ipv6cp_finished __P((fsm *));	/* Don't need lower layer */
1537c478bd9Sstevel@tonic-gate 
1547c478bd9Sstevel@tonic-gate fsm ipv6cp_fsm[NUM_PPP];		/* IPV6CP fsm structure */
1557c478bd9Sstevel@tonic-gate 
1567c478bd9Sstevel@tonic-gate static fsm_callbacks ipv6cp_callbacks = { /* IPV6CP callback routines */
1577c478bd9Sstevel@tonic-gate     ipv6cp_resetci,		/* Reset our Configuration Information */
1587c478bd9Sstevel@tonic-gate     ipv6cp_cilen,		/* Length of our Configuration Information */
1597c478bd9Sstevel@tonic-gate     ipv6cp_addci,		/* Add our Configuration Information */
1607c478bd9Sstevel@tonic-gate     ipv6cp_ackci,		/* ACK our Configuration Information */
1617c478bd9Sstevel@tonic-gate     ipv6cp_nakci,		/* NAK our Configuration Information */
1627c478bd9Sstevel@tonic-gate     ipv6cp_rejci,		/* Reject our Configuration Information */
1637c478bd9Sstevel@tonic-gate     ipv6cp_reqci,		/* Request peer's Configuration Information */
1647c478bd9Sstevel@tonic-gate     ipv6cp_up,			/* Called when fsm reaches OPENED state */
1657c478bd9Sstevel@tonic-gate     ipv6cp_down,		/* Called when fsm leaves OPENED state */
1667c478bd9Sstevel@tonic-gate     NULL,			/* Called when we want the lower layer up */
1677c478bd9Sstevel@tonic-gate     ipv6cp_finished,		/* Called when we want the lower layer down */
1687c478bd9Sstevel@tonic-gate     NULL,			/* Retransmission is necessary */
1697c478bd9Sstevel@tonic-gate     NULL,			/* Called to handle protocol-specific codes */
1707c478bd9Sstevel@tonic-gate     "IPV6CP",			/* String name of protocol */
1717c478bd9Sstevel@tonic-gate     NULL			/* Peer rejected a code number */
1727c478bd9Sstevel@tonic-gate };
1737c478bd9Sstevel@tonic-gate 
1747c478bd9Sstevel@tonic-gate static int setifaceid __P((char **arg, option_t *));
1757c478bd9Sstevel@tonic-gate 
1767c478bd9Sstevel@tonic-gate /*
1777c478bd9Sstevel@tonic-gate  * Command-line options.
1787c478bd9Sstevel@tonic-gate  */
1797c478bd9Sstevel@tonic-gate static option_t ipv6cp_option_list[] = {
1807c478bd9Sstevel@tonic-gate     { "ipv6", o_special, (void *)setifaceid,
1817c478bd9Sstevel@tonic-gate       "Set interface identifiers for IPV6" },
1827c478bd9Sstevel@tonic-gate     { "noipv6", o_bool, &ipv6cp_protent.enabled_flag,
1837c478bd9Sstevel@tonic-gate       "Disable IPv6 and IPv6CP" },
1847c478bd9Sstevel@tonic-gate     { "-ipv6", o_bool, &ipv6cp_protent.enabled_flag,
1857c478bd9Sstevel@tonic-gate       "Disable IPv6 and IPv6CP" },
1867c478bd9Sstevel@tonic-gate     { "+ipv6", o_bool, &ipv6cp_protent.enabled_flag,
1877c478bd9Sstevel@tonic-gate       "Enable IPv6 and IPv6CP", 1 },
1887c478bd9Sstevel@tonic-gate     { "ipv6cp-accept-local", o_bool, &ipv6cp_wantoptions[0].accept_local,
1897c478bd9Sstevel@tonic-gate       "Accept peer's interface identifier for us", 1 },
1907c478bd9Sstevel@tonic-gate     { "ipv6cp-use-ipaddr", o_bool, &ipv6cp_wantoptions[0].use_ip,
1917c478bd9Sstevel@tonic-gate       "Use (default) IPv4 address as interface identifier", 1 },
1927c478bd9Sstevel@tonic-gate #if defined(SOL2)
1937c478bd9Sstevel@tonic-gate     { "ipv6cp-use-persistent", o_bool, &ipv6cp_wantoptions[0].use_persistent,
1947c478bd9Sstevel@tonic-gate       "Use unique persistent value for link local address", 1 },
1957c478bd9Sstevel@tonic-gate #endif /* defined(SOL2) */
1967c478bd9Sstevel@tonic-gate     { "ipv6cp-restart", o_int, &ipv6cp_fsm[0].timeouttime,
1977c478bd9Sstevel@tonic-gate       "Set timeout for IPv6CP" },
1987c478bd9Sstevel@tonic-gate     { "ipv6cp-max-terminate", o_int, &ipv6cp_fsm[0].maxtermtransmits,
1997c478bd9Sstevel@tonic-gate       "Maximum number of IPV6CP Terminate-Request" },
2007c478bd9Sstevel@tonic-gate     { "ipv6cp-max-configure", o_int, &ipv6cp_fsm[0].maxconfreqtransmits,
2017c478bd9Sstevel@tonic-gate       "Maximum number of IPV6CP Configure-Request" },
2027c478bd9Sstevel@tonic-gate     { "ipv6cp-max-failure", o_int, &ipv6cp_fsm[0].maxnakloops,
2037c478bd9Sstevel@tonic-gate       "Maximum number of IPV6CP Configure-Nak" },
2047c478bd9Sstevel@tonic-gate     { NULL }
2057c478bd9Sstevel@tonic-gate };
2067c478bd9Sstevel@tonic-gate 
2077c478bd9Sstevel@tonic-gate 
2087c478bd9Sstevel@tonic-gate /*
2097c478bd9Sstevel@tonic-gate  * Protocol entry points from main code.
2107c478bd9Sstevel@tonic-gate  */
2117c478bd9Sstevel@tonic-gate static void ipv6cp_init __P((int));
2127c478bd9Sstevel@tonic-gate static void ipv6cp_open __P((int));
2137c478bd9Sstevel@tonic-gate static void ipv6cp_close __P((int, char *));
2147c478bd9Sstevel@tonic-gate static void ipv6cp_lowerup __P((int));
2157c478bd9Sstevel@tonic-gate static void ipv6cp_lowerdown __P((int));
2167c478bd9Sstevel@tonic-gate static void ipv6cp_input __P((int, u_char *, int));
2177c478bd9Sstevel@tonic-gate static void ipv6cp_protrej __P((int));
2187c478bd9Sstevel@tonic-gate static int  ipv6cp_printpkt __P((u_char *, int,
2197c478bd9Sstevel@tonic-gate     void (*) __P((void *, const char *, ...)), void *));
2207c478bd9Sstevel@tonic-gate static void ipv6_check_options __P((void));
2217c478bd9Sstevel@tonic-gate static int  ipv6_demand_conf __P((int));
2227c478bd9Sstevel@tonic-gate static int  ipv6_active_pkt __P((u_char *, int));
2237c478bd9Sstevel@tonic-gate 
2247c478bd9Sstevel@tonic-gate struct protent ipv6cp_protent = {
2257c478bd9Sstevel@tonic-gate     PPP_IPV6CP,			/* Protocol Number for IPV6CP */
2267c478bd9Sstevel@tonic-gate     ipv6cp_init,		/* Initializes IPV6CP */
2277c478bd9Sstevel@tonic-gate     ipv6cp_input,		/* Processes a received IPV6CP packet */
2287c478bd9Sstevel@tonic-gate     ipv6cp_protrej,		/* Process a received Protocol-reject */
2297c478bd9Sstevel@tonic-gate     ipv6cp_lowerup,		/* Called when LCP is brought up */
2307c478bd9Sstevel@tonic-gate     ipv6cp_lowerdown,		/* Called when LCP has gone down */
2317c478bd9Sstevel@tonic-gate     ipv6cp_open,		/* Called when link is established */
2327c478bd9Sstevel@tonic-gate     ipv6cp_close,		/* Called when link has gone down */
2337c478bd9Sstevel@tonic-gate     ipv6cp_printpkt,		/* Print a packet in human readable form */
2347c478bd9Sstevel@tonic-gate     NULL,			/* Process a received data packet */
2357c478bd9Sstevel@tonic-gate     0,				/* IPV6CP is disabled by default */
2367c478bd9Sstevel@tonic-gate     "IPV6CP",			/* Name of the protocol */
2377c478bd9Sstevel@tonic-gate     "IPV6",			/* Name of the corresponding data protocol */
2387c478bd9Sstevel@tonic-gate     ipv6cp_option_list,		/* List of IPV6CP command-line options */
2397c478bd9Sstevel@tonic-gate     ipv6_check_options,		/* Assigns default values for options */
2407c478bd9Sstevel@tonic-gate     ipv6_demand_conf,		/* Configures demand-dial */
2417c478bd9Sstevel@tonic-gate     ipv6_active_pkt		/* Bring up the link for this packet? */
2427c478bd9Sstevel@tonic-gate };
2437c478bd9Sstevel@tonic-gate 
2447c478bd9Sstevel@tonic-gate /*
2457c478bd9Sstevel@tonic-gate  * Local forward function declarations.
2467c478bd9Sstevel@tonic-gate  */
2477c478bd9Sstevel@tonic-gate static void ipv6cp_clear_addrs __P((int, eui64_t, eui64_t));
2487c478bd9Sstevel@tonic-gate static void ipv6cp_script __P((char *));
2497c478bd9Sstevel@tonic-gate static void ipv6cp_script_done __P((void *, int));
2507c478bd9Sstevel@tonic-gate 
2517c478bd9Sstevel@tonic-gate /*
2527c478bd9Sstevel@tonic-gate  * Lengths of configuration options.
2537c478bd9Sstevel@tonic-gate  */
2547c478bd9Sstevel@tonic-gate #define CILEN_VOID	2
2557c478bd9Sstevel@tonic-gate #define CILEN_COMPRESS	4	/* length for RFC2023 compress opt. */
2567c478bd9Sstevel@tonic-gate #define CILEN_IFACEID   10	/* RFC2472, interface identifier    */
2577c478bd9Sstevel@tonic-gate 
2587c478bd9Sstevel@tonic-gate #define CODENAME(x)	((x) == CODE_CONFACK ? "ACK" : \
2597c478bd9Sstevel@tonic-gate 			 (x) == CODE_CONFNAK ? "NAK" : "REJ")
2607c478bd9Sstevel@tonic-gate 
2617c478bd9Sstevel@tonic-gate /*
2627c478bd9Sstevel@tonic-gate  * This state variable is used to ensure that we don't
2637c478bd9Sstevel@tonic-gate  * run an ipcp-up/down script while one is already running.
2647c478bd9Sstevel@tonic-gate  */
2657c478bd9Sstevel@tonic-gate static enum script_state {
2667c478bd9Sstevel@tonic-gate     s_down,
2677c478bd9Sstevel@tonic-gate     s_up
2687c478bd9Sstevel@tonic-gate } ipv6cp_script_state;
2697c478bd9Sstevel@tonic-gate static pid_t ipv6cp_script_pid;
2707c478bd9Sstevel@tonic-gate 
2717c478bd9Sstevel@tonic-gate /*
2727c478bd9Sstevel@tonic-gate  * setifaceid - set the interface identifiers manually
2737c478bd9Sstevel@tonic-gate  */
2747c478bd9Sstevel@tonic-gate /*ARGSUSED*/
2757c478bd9Sstevel@tonic-gate static int
setifaceid(argv,opt)2767c478bd9Sstevel@tonic-gate setifaceid(argv, opt)
2777c478bd9Sstevel@tonic-gate     char **argv;
2787c478bd9Sstevel@tonic-gate     option_t *opt;
2797c478bd9Sstevel@tonic-gate {
2807c478bd9Sstevel@tonic-gate     char *comma, *arg;
2817c478bd9Sstevel@tonic-gate     ipv6cp_options *wo = &ipv6cp_wantoptions[0];
2827c478bd9Sstevel@tonic-gate     struct in6_addr addr;
28348bbca81SDaniel Hoffman 
2847c478bd9Sstevel@tonic-gate #define VALIDID(a) ( (((a).s6_addr32[0] == 0) && ((a).s6_addr32[1] == 0)) && \
2857c478bd9Sstevel@tonic-gate 			(((a).s6_addr32[2] != 0) || ((a).s6_addr32[3] != 0)) )
28648bbca81SDaniel Hoffman 
2877c478bd9Sstevel@tonic-gate 
2887c478bd9Sstevel@tonic-gate     arg = *argv;
2897c478bd9Sstevel@tonic-gate 
2907c478bd9Sstevel@tonic-gate     comma = strchr(arg, ',');
29148bbca81SDaniel Hoffman 
29248bbca81SDaniel Hoffman     /*
2937c478bd9Sstevel@tonic-gate      * If comma first character, then no local identifier
2947c478bd9Sstevel@tonic-gate      */
2957c478bd9Sstevel@tonic-gate     if (comma != arg) {
2967c478bd9Sstevel@tonic-gate 	if (comma != NULL)
2977c478bd9Sstevel@tonic-gate 	    *comma = '\0';
2987c478bd9Sstevel@tonic-gate 
2997c478bd9Sstevel@tonic-gate 	if (inet_pton(AF_INET6, arg, &addr) != 1 || !VALIDID(addr)) {
3007c478bd9Sstevel@tonic-gate 	    option_error("Illegal interface identifier (local): %s", arg);
3017c478bd9Sstevel@tonic-gate 	    return 0;
3027c478bd9Sstevel@tonic-gate 	}
30348bbca81SDaniel Hoffman 
3047c478bd9Sstevel@tonic-gate 	eui64_copy(addr.s6_addr32[2], wo->ourid);
3057c478bd9Sstevel@tonic-gate 	wo->opt_local = 1;
3067c478bd9Sstevel@tonic-gate     }
30748bbca81SDaniel Hoffman 
3087c478bd9Sstevel@tonic-gate     /*
3097c478bd9Sstevel@tonic-gate      * If comma last character, then no remote identifier
3107c478bd9Sstevel@tonic-gate      */
3117c478bd9Sstevel@tonic-gate     if (comma != NULL && *++comma != '\0') {
3127c478bd9Sstevel@tonic-gate 	if (inet_pton(AF_INET6, comma, &addr) != 1 || !VALIDID(addr)) {
3137c478bd9Sstevel@tonic-gate 	    option_error("Illegal interface identifier (remote): %s", comma);
3147c478bd9Sstevel@tonic-gate 	    return 0;
3157c478bd9Sstevel@tonic-gate 	}
3167c478bd9Sstevel@tonic-gate 	eui64_copy(addr.s6_addr32[2], wo->hisid);
3177c478bd9Sstevel@tonic-gate 	wo->opt_remote = 1;
3187c478bd9Sstevel@tonic-gate     }
3197c478bd9Sstevel@tonic-gate 
3207c478bd9Sstevel@tonic-gate     ipv6cp_protent.enabled_flag = 1;
3217c478bd9Sstevel@tonic-gate     return 1;
3227c478bd9Sstevel@tonic-gate }
3237c478bd9Sstevel@tonic-gate 
3247c478bd9Sstevel@tonic-gate /*
3257c478bd9Sstevel@tonic-gate  * Given an interface identifier, return a string representation of the
3267c478bd9Sstevel@tonic-gate  * link local address associated with that identifier.
3277c478bd9Sstevel@tonic-gate  * string will be at most 26 characters (including null terminator).
3287c478bd9Sstevel@tonic-gate  */
3297c478bd9Sstevel@tonic-gate static char *
llv6_ntoa(ifaceid)3307c478bd9Sstevel@tonic-gate llv6_ntoa(ifaceid)
3317c478bd9Sstevel@tonic-gate     eui64_t ifaceid;
3327c478bd9Sstevel@tonic-gate {
3337c478bd9Sstevel@tonic-gate     struct in6_addr addr;
3347c478bd9Sstevel@tonic-gate     static char addrstr[26];
3357c478bd9Sstevel@tonic-gate 
3367c478bd9Sstevel@tonic-gate     BZERO(&addr, sizeof (addr));
3377c478bd9Sstevel@tonic-gate     addr.s6_addr[0] = 0xfe;
3387c478bd9Sstevel@tonic-gate     addr.s6_addr[1] = 0x80;
3397c478bd9Sstevel@tonic-gate     eui64_copy(ifaceid, addr.s6_addr[8]);
3407c478bd9Sstevel@tonic-gate 
3417c478bd9Sstevel@tonic-gate     (void) inet_ntop(AF_INET6, &addr, addrstr, 26);
3427c478bd9Sstevel@tonic-gate 
3437c478bd9Sstevel@tonic-gate     return addrstr;
3447c478bd9Sstevel@tonic-gate }
3457c478bd9Sstevel@tonic-gate 
3467c478bd9Sstevel@tonic-gate 
3477c478bd9Sstevel@tonic-gate /*
3487c478bd9Sstevel@tonic-gate  * ipv6cp_init - Initialize IPV6CP.
3497c478bd9Sstevel@tonic-gate  */
3507c478bd9Sstevel@tonic-gate static void
ipv6cp_init(unit)3517c478bd9Sstevel@tonic-gate ipv6cp_init(unit)
3527c478bd9Sstevel@tonic-gate     int unit;
3537c478bd9Sstevel@tonic-gate {
3547c478bd9Sstevel@tonic-gate     fsm *f = &ipv6cp_fsm[unit];
3557c478bd9Sstevel@tonic-gate     ipv6cp_options *wo = &ipv6cp_wantoptions[unit];
3567c478bd9Sstevel@tonic-gate     ipv6cp_options *ao = &ipv6cp_allowoptions[unit];
3577c478bd9Sstevel@tonic-gate 
3587c478bd9Sstevel@tonic-gate     f->unit = unit;
3597c478bd9Sstevel@tonic-gate     f->protocol = PPP_IPV6CP;
3607c478bd9Sstevel@tonic-gate     f->callbacks = &ipv6cp_callbacks;
3617c478bd9Sstevel@tonic-gate     fsm_init(&ipv6cp_fsm[unit]);
3627c478bd9Sstevel@tonic-gate 
3637c478bd9Sstevel@tonic-gate     BZERO(wo, sizeof(*wo));
3647c478bd9Sstevel@tonic-gate     BZERO(ao, sizeof(*ao));
3657c478bd9Sstevel@tonic-gate 
3667c478bd9Sstevel@tonic-gate     wo->neg_ifaceid = 1;
3677c478bd9Sstevel@tonic-gate     ao->neg_ifaceid = 1;
3687c478bd9Sstevel@tonic-gate 
3697c478bd9Sstevel@tonic-gate #ifdef IPV6CP_COMP
3707c478bd9Sstevel@tonic-gate     wo->neg_vj = 1;
3717c478bd9Sstevel@tonic-gate     ao->neg_vj = 1;
3727c478bd9Sstevel@tonic-gate     wo->vj_protocol = IPV6CP_COMP;
3737c478bd9Sstevel@tonic-gate #endif
3747c478bd9Sstevel@tonic-gate 
3757c478bd9Sstevel@tonic-gate }
3767c478bd9Sstevel@tonic-gate 
3777c478bd9Sstevel@tonic-gate 
3787c478bd9Sstevel@tonic-gate /*
3797c478bd9Sstevel@tonic-gate  * ipv6cp_open - IPV6CP is allowed to come up.
3807c478bd9Sstevel@tonic-gate  */
3817c478bd9Sstevel@tonic-gate static void
ipv6cp_open(unit)3827c478bd9Sstevel@tonic-gate ipv6cp_open(unit)
3837c478bd9Sstevel@tonic-gate     int unit;
3847c478bd9Sstevel@tonic-gate {
3857c478bd9Sstevel@tonic-gate     fsm_open(&ipv6cp_fsm[unit]);
3867c478bd9Sstevel@tonic-gate }
3877c478bd9Sstevel@tonic-gate 
3887c478bd9Sstevel@tonic-gate 
3897c478bd9Sstevel@tonic-gate /*
3907c478bd9Sstevel@tonic-gate  * ipv6cp_close - Take IPV6CP down.
3917c478bd9Sstevel@tonic-gate  */
3927c478bd9Sstevel@tonic-gate static void
ipv6cp_close(unit,reason)3937c478bd9Sstevel@tonic-gate ipv6cp_close(unit, reason)
3947c478bd9Sstevel@tonic-gate     int unit;
3957c478bd9Sstevel@tonic-gate     char *reason;
3967c478bd9Sstevel@tonic-gate {
3977c478bd9Sstevel@tonic-gate     fsm_close(&ipv6cp_fsm[unit], reason);
3987c478bd9Sstevel@tonic-gate }
3997c478bd9Sstevel@tonic-gate 
4007c478bd9Sstevel@tonic-gate 
4017c478bd9Sstevel@tonic-gate /*
4027c478bd9Sstevel@tonic-gate  * ipv6cp_lowerup - The lower layer is up.
4037c478bd9Sstevel@tonic-gate  */
4047c478bd9Sstevel@tonic-gate static void
ipv6cp_lowerup(unit)4057c478bd9Sstevel@tonic-gate ipv6cp_lowerup(unit)
4067c478bd9Sstevel@tonic-gate     int unit;
4077c478bd9Sstevel@tonic-gate {
4087c478bd9Sstevel@tonic-gate     fsm_lowerup(&ipv6cp_fsm[unit]);
4097c478bd9Sstevel@tonic-gate }
4107c478bd9Sstevel@tonic-gate 
4117c478bd9Sstevel@tonic-gate 
4127c478bd9Sstevel@tonic-gate /*
4137c478bd9Sstevel@tonic-gate  * ipv6cp_lowerdown - The lower layer is down.
4147c478bd9Sstevel@tonic-gate  */
4157c478bd9Sstevel@tonic-gate static void
ipv6cp_lowerdown(unit)4167c478bd9Sstevel@tonic-gate ipv6cp_lowerdown(unit)
4177c478bd9Sstevel@tonic-gate     int unit;
4187c478bd9Sstevel@tonic-gate {
4197c478bd9Sstevel@tonic-gate     fsm_lowerdown(&ipv6cp_fsm[unit]);
4207c478bd9Sstevel@tonic-gate }
4217c478bd9Sstevel@tonic-gate 
4227c478bd9Sstevel@tonic-gate 
4237c478bd9Sstevel@tonic-gate /*
4247c478bd9Sstevel@tonic-gate  * ipv6cp_input - Input IPV6CP packet.
4257c478bd9Sstevel@tonic-gate  */
4267c478bd9Sstevel@tonic-gate static void
ipv6cp_input(unit,p,len)4277c478bd9Sstevel@tonic-gate ipv6cp_input(unit, p, len)
4287c478bd9Sstevel@tonic-gate     int unit;
4297c478bd9Sstevel@tonic-gate     u_char *p;
4307c478bd9Sstevel@tonic-gate     int len;
4317c478bd9Sstevel@tonic-gate {
4327c478bd9Sstevel@tonic-gate     fsm_input(&ipv6cp_fsm[unit], p, len);
4337c478bd9Sstevel@tonic-gate }
4347c478bd9Sstevel@tonic-gate 
4357c478bd9Sstevel@tonic-gate 
4367c478bd9Sstevel@tonic-gate /*
4377c478bd9Sstevel@tonic-gate  * ipv6cp_protrej - A Protocol-Reject was received for IPV6CP.
4387c478bd9Sstevel@tonic-gate  */
4397c478bd9Sstevel@tonic-gate static void
ipv6cp_protrej(unit)4407c478bd9Sstevel@tonic-gate ipv6cp_protrej(unit)
4417c478bd9Sstevel@tonic-gate     int unit;
4427c478bd9Sstevel@tonic-gate {
4437c478bd9Sstevel@tonic-gate     fsm_protreject(&ipv6cp_fsm[unit]);
4447c478bd9Sstevel@tonic-gate }
4457c478bd9Sstevel@tonic-gate 
4467c478bd9Sstevel@tonic-gate 
4477c478bd9Sstevel@tonic-gate /*
4487c478bd9Sstevel@tonic-gate  * ipv6cp_resetci - Reset our CI.
4497c478bd9Sstevel@tonic-gate  */
4507c478bd9Sstevel@tonic-gate static void
ipv6cp_resetci(f)4517c478bd9Sstevel@tonic-gate ipv6cp_resetci(f)
4527c478bd9Sstevel@tonic-gate     fsm *f;
4537c478bd9Sstevel@tonic-gate {
4547c478bd9Sstevel@tonic-gate     ipv6cp_options *wo = &ipv6cp_wantoptions[f->unit];
4557c478bd9Sstevel@tonic-gate     ipv6cp_options *go = &ipv6cp_gotoptions[f->unit];
4567c478bd9Sstevel@tonic-gate 
4577c478bd9Sstevel@tonic-gate     wo->req_ifaceid = wo->neg_ifaceid && ipv6cp_allowoptions[f->unit].neg_ifaceid;
45848bbca81SDaniel Hoffman 
4597c478bd9Sstevel@tonic-gate     if (!wo->opt_local) {
4607c478bd9Sstevel@tonic-gate 	eui64_magic_nz(wo->ourid);
4617c478bd9Sstevel@tonic-gate     }
46248bbca81SDaniel Hoffman 
4637c478bd9Sstevel@tonic-gate     *go = *wo;
4647c478bd9Sstevel@tonic-gate     eui64_zero(go->hisid);	/* last proposed interface identifier */
4657c478bd9Sstevel@tonic-gate }
4667c478bd9Sstevel@tonic-gate 
4677c478bd9Sstevel@tonic-gate 
4687c478bd9Sstevel@tonic-gate /*
4697c478bd9Sstevel@tonic-gate  * ipv6cp_cilen - Return length of our CI.
4707c478bd9Sstevel@tonic-gate  */
4717c478bd9Sstevel@tonic-gate static int
ipv6cp_cilen(f)4727c478bd9Sstevel@tonic-gate ipv6cp_cilen(f)
4737c478bd9Sstevel@tonic-gate     fsm *f;
4747c478bd9Sstevel@tonic-gate {
4757c478bd9Sstevel@tonic-gate     ipv6cp_options *go = &ipv6cp_gotoptions[f->unit];
4767c478bd9Sstevel@tonic-gate 
4777c478bd9Sstevel@tonic-gate #define LENCIVJ(neg)		(neg ? CILEN_COMPRESS : 0)
4787c478bd9Sstevel@tonic-gate #define LENCIIFACEID(neg)	(neg ? CILEN_IFACEID : 0)
4797c478bd9Sstevel@tonic-gate 
4807c478bd9Sstevel@tonic-gate     return (LENCIIFACEID(go->neg_ifaceid) +
4817c478bd9Sstevel@tonic-gate 	    LENCIVJ(go->neg_vj));
4827c478bd9Sstevel@tonic-gate }
4837c478bd9Sstevel@tonic-gate 
4847c478bd9Sstevel@tonic-gate 
4857c478bd9Sstevel@tonic-gate /*
4867c478bd9Sstevel@tonic-gate  * ipv6cp_addci - Add our desired CIs to a packet.
4877c478bd9Sstevel@tonic-gate  */
4887c478bd9Sstevel@tonic-gate static void
ipv6cp_addci(f,ucp,lenp)4897c478bd9Sstevel@tonic-gate ipv6cp_addci(f, ucp, lenp)
4907c478bd9Sstevel@tonic-gate     fsm *f;
4917c478bd9Sstevel@tonic-gate     u_char *ucp;
4927c478bd9Sstevel@tonic-gate     int *lenp;
4937c478bd9Sstevel@tonic-gate {
4947c478bd9Sstevel@tonic-gate     ipv6cp_options *go = &ipv6cp_gotoptions[f->unit];
4957c478bd9Sstevel@tonic-gate     int len = *lenp;
4967c478bd9Sstevel@tonic-gate 
4977c478bd9Sstevel@tonic-gate #define ADDCIVJ(opt, neg, val) \
4987c478bd9Sstevel@tonic-gate     if (neg) { \
4997c478bd9Sstevel@tonic-gate 	int vjlen = CILEN_COMPRESS; \
5007c478bd9Sstevel@tonic-gate 	if (len >= vjlen) { \
5017c478bd9Sstevel@tonic-gate 	    PUTCHAR(opt, ucp); \
5027c478bd9Sstevel@tonic-gate 	    PUTCHAR(vjlen, ucp); \
5037c478bd9Sstevel@tonic-gate 	    PUTSHORT(val, ucp); \
5047c478bd9Sstevel@tonic-gate 	    len -= vjlen; \
5057c478bd9Sstevel@tonic-gate 	} else \
5067c478bd9Sstevel@tonic-gate 	    neg = 0; \
5077c478bd9Sstevel@tonic-gate     }
5087c478bd9Sstevel@tonic-gate 
5097c478bd9Sstevel@tonic-gate #define ADDCIIFACEID(opt, neg, val1) \
5107c478bd9Sstevel@tonic-gate     if (neg) { \
5117c478bd9Sstevel@tonic-gate 	int idlen = CILEN_IFACEID; \
5127c478bd9Sstevel@tonic-gate 	if (len >= idlen) { \
5137c478bd9Sstevel@tonic-gate 	    PUTCHAR(opt, ucp); \
5147c478bd9Sstevel@tonic-gate 	    PUTCHAR(idlen, ucp); \
5157c478bd9Sstevel@tonic-gate 	    eui64_put(val1, ucp); \
5167c478bd9Sstevel@tonic-gate 	    len -= idlen; \
5177c478bd9Sstevel@tonic-gate 	} else \
5187c478bd9Sstevel@tonic-gate 	    neg = 0; \
5197c478bd9Sstevel@tonic-gate     }
5207c478bd9Sstevel@tonic-gate 
5217c478bd9Sstevel@tonic-gate     ADDCIIFACEID(CI_IFACEID, go->neg_ifaceid, go->ourid);
5227c478bd9Sstevel@tonic-gate 
5237c478bd9Sstevel@tonic-gate     ADDCIVJ(CI_COMPRESSTYPE, go->neg_vj, go->vj_protocol);
5247c478bd9Sstevel@tonic-gate 
5257c478bd9Sstevel@tonic-gate     *lenp -= len;
5267c478bd9Sstevel@tonic-gate }
5277c478bd9Sstevel@tonic-gate 
5287c478bd9Sstevel@tonic-gate 
5297c478bd9Sstevel@tonic-gate /*
5307c478bd9Sstevel@tonic-gate  * ipv6cp_ackci - Ack our CIs.
5317c478bd9Sstevel@tonic-gate  *
5327c478bd9Sstevel@tonic-gate  * Returns:
5337c478bd9Sstevel@tonic-gate  *	0 - Ack was bad.
5347c478bd9Sstevel@tonic-gate  *	1 - Ack was good.
5357c478bd9Sstevel@tonic-gate  */
5367c478bd9Sstevel@tonic-gate static int
ipv6cp_ackci(f,p,len)5377c478bd9Sstevel@tonic-gate ipv6cp_ackci(f, p, len)
5387c478bd9Sstevel@tonic-gate     fsm *f;
5397c478bd9Sstevel@tonic-gate     u_char *p;
5407c478bd9Sstevel@tonic-gate     int len;
5417c478bd9Sstevel@tonic-gate {
5427c478bd9Sstevel@tonic-gate     ipv6cp_options *go = &ipv6cp_gotoptions[f->unit];
5437c478bd9Sstevel@tonic-gate     u_short cilen, citype, cishort;
5447c478bd9Sstevel@tonic-gate     eui64_t ifaceid;
5457c478bd9Sstevel@tonic-gate 
5467c478bd9Sstevel@tonic-gate     /*
5477c478bd9Sstevel@tonic-gate      * CIs must be in exactly the same order that we sent...
5487c478bd9Sstevel@tonic-gate      * Check packet length and CI length at each step.
5497c478bd9Sstevel@tonic-gate      * If we find any deviations, then this packet is bad.
5507c478bd9Sstevel@tonic-gate      */
5517c478bd9Sstevel@tonic-gate 
5527c478bd9Sstevel@tonic-gate #define ACKCIVJ(opt, neg, val) \
5537c478bd9Sstevel@tonic-gate     if (neg) { \
5547c478bd9Sstevel@tonic-gate 	int vjlen = CILEN_COMPRESS; \
5557c478bd9Sstevel@tonic-gate 	if ((len -= vjlen) < 0) \
5567c478bd9Sstevel@tonic-gate 	    goto bad; \
5577c478bd9Sstevel@tonic-gate 	GETCHAR(citype, p); \
5587c478bd9Sstevel@tonic-gate 	GETCHAR(cilen, p); \
5597c478bd9Sstevel@tonic-gate 	if (cilen != vjlen || \
5607c478bd9Sstevel@tonic-gate 	    citype != opt)  \
5617c478bd9Sstevel@tonic-gate 	    goto bad; \
5627c478bd9Sstevel@tonic-gate 	GETSHORT(cishort, p); \
5637c478bd9Sstevel@tonic-gate 	if (cishort != val) \
5647c478bd9Sstevel@tonic-gate 	    goto bad; \
5657c478bd9Sstevel@tonic-gate     }
5667c478bd9Sstevel@tonic-gate 
5677c478bd9Sstevel@tonic-gate #define ACKCIIFACEID(opt, neg, val1) \
5687c478bd9Sstevel@tonic-gate     if (neg) { \
5697c478bd9Sstevel@tonic-gate 	int idlen = CILEN_IFACEID; \
5707c478bd9Sstevel@tonic-gate 	if ((len -= idlen) < 0) \
5717c478bd9Sstevel@tonic-gate 	    goto bad; \
5727c478bd9Sstevel@tonic-gate 	GETCHAR(citype, p); \
5737c478bd9Sstevel@tonic-gate 	GETCHAR(cilen, p); \
5747c478bd9Sstevel@tonic-gate 	if (cilen != idlen || \
5757c478bd9Sstevel@tonic-gate 	    citype != opt) \
5767c478bd9Sstevel@tonic-gate 	    goto bad; \
5777c478bd9Sstevel@tonic-gate 	eui64_get(ifaceid, p); \
5787c478bd9Sstevel@tonic-gate 	if (! eui64_equals(val1, ifaceid)) \
5797c478bd9Sstevel@tonic-gate 	    goto bad; \
5807c478bd9Sstevel@tonic-gate     }
5817c478bd9Sstevel@tonic-gate 
5827c478bd9Sstevel@tonic-gate     ACKCIIFACEID(CI_IFACEID, go->neg_ifaceid, go->ourid);
5837c478bd9Sstevel@tonic-gate 
5847c478bd9Sstevel@tonic-gate     ACKCIVJ(CI_COMPRESSTYPE, go->neg_vj, go->vj_protocol);
5857c478bd9Sstevel@tonic-gate 
5867c478bd9Sstevel@tonic-gate     /*
5877c478bd9Sstevel@tonic-gate      * If there are any remaining CIs, then this packet is bad.
5887c478bd9Sstevel@tonic-gate      */
5897c478bd9Sstevel@tonic-gate     if (len != 0)
5907c478bd9Sstevel@tonic-gate 	goto bad;
5917c478bd9Sstevel@tonic-gate     return (1);
5927c478bd9Sstevel@tonic-gate 
5937c478bd9Sstevel@tonic-gate bad:
5947c478bd9Sstevel@tonic-gate     IPV6CPDEBUG(("ipv6cp_ackci: received bad Ack!"));
5957c478bd9Sstevel@tonic-gate     return (0);
5967c478bd9Sstevel@tonic-gate }
5977c478bd9Sstevel@tonic-gate 
5987c478bd9Sstevel@tonic-gate /*
5997c478bd9Sstevel@tonic-gate  * ipv6cp_nakci - Peer has sent a NAK for some of our CIs.
6007c478bd9Sstevel@tonic-gate  * This should not modify any state if the Nak is bad
6017c478bd9Sstevel@tonic-gate  * or if IPV6CP is in the OPENED state.
6027c478bd9Sstevel@tonic-gate  *
6037c478bd9Sstevel@tonic-gate  * Returns:
6047c478bd9Sstevel@tonic-gate  *	0 - Nak was bad.
6057c478bd9Sstevel@tonic-gate  *	1 - Nak was good.
6067c478bd9Sstevel@tonic-gate  */
6077c478bd9Sstevel@tonic-gate static int
ipv6cp_nakci(f,p,len)6087c478bd9Sstevel@tonic-gate ipv6cp_nakci(f, p, len)
6097c478bd9Sstevel@tonic-gate     fsm *f;
6107c478bd9Sstevel@tonic-gate     u_char *p;
6117c478bd9Sstevel@tonic-gate     int len;
6127c478bd9Sstevel@tonic-gate {
6137c478bd9Sstevel@tonic-gate     ipv6cp_options *go = &ipv6cp_gotoptions[f->unit];
6147c478bd9Sstevel@tonic-gate     u_char citype, cilen, *next;
6157c478bd9Sstevel@tonic-gate     u_short cishort;
6167c478bd9Sstevel@tonic-gate     eui64_t ifaceid;
6177c478bd9Sstevel@tonic-gate     ipv6cp_options no;		/* options we've seen Naks for */
6187c478bd9Sstevel@tonic-gate     ipv6cp_options try;		/* options to request next time */
6197c478bd9Sstevel@tonic-gate 
6207c478bd9Sstevel@tonic-gate     BZERO(&no, sizeof(no));
6217c478bd9Sstevel@tonic-gate     try = *go;
6227c478bd9Sstevel@tonic-gate 
6237c478bd9Sstevel@tonic-gate     /*
6247c478bd9Sstevel@tonic-gate      * Any Nak'd CIs must be in exactly the same order that we sent.
6257c478bd9Sstevel@tonic-gate      * Check packet length and CI length at each step.
6267c478bd9Sstevel@tonic-gate      * If we find any deviations, then this packet is bad.
6277c478bd9Sstevel@tonic-gate      */
6287c478bd9Sstevel@tonic-gate #define NAKCIIFACEID(opt, neg, code) \
6297c478bd9Sstevel@tonic-gate     if (go->neg && \
6307c478bd9Sstevel@tonic-gate 	len >= (cilen = CILEN_IFACEID) && \
6317c478bd9Sstevel@tonic-gate 	p[1] == cilen && \
6327c478bd9Sstevel@tonic-gate 	p[0] == opt) { \
6337c478bd9Sstevel@tonic-gate 	len -= cilen; \
6347c478bd9Sstevel@tonic-gate 	INCPTR(2, p); \
6357c478bd9Sstevel@tonic-gate 	eui64_get(ifaceid, p); \
6367c478bd9Sstevel@tonic-gate 	no.neg = 1; \
6377c478bd9Sstevel@tonic-gate 	code \
6387c478bd9Sstevel@tonic-gate     }
6397c478bd9Sstevel@tonic-gate 
6407c478bd9Sstevel@tonic-gate #define NAKCIVJ(opt, neg, code) \
6417c478bd9Sstevel@tonic-gate     if (go->neg && \
6427c478bd9Sstevel@tonic-gate 	((cilen = p[1]) == CILEN_COMPRESS) && \
6437c478bd9Sstevel@tonic-gate 	len >= cilen && \
6447c478bd9Sstevel@tonic-gate 	p[0] == opt) { \
6457c478bd9Sstevel@tonic-gate 	len -= cilen; \
6467c478bd9Sstevel@tonic-gate 	INCPTR(2, p); \
6477c478bd9Sstevel@tonic-gate 	GETSHORT(cishort, p); \
6487c478bd9Sstevel@tonic-gate 	no.neg = 1; \
6497c478bd9Sstevel@tonic-gate         code \
6507c478bd9Sstevel@tonic-gate     }
6517c478bd9Sstevel@tonic-gate 
6527c478bd9Sstevel@tonic-gate     /*
65348bbca81SDaniel Hoffman      * Accept the peer's idea of {our,its} interface identifier, if different
6547c478bd9Sstevel@tonic-gate      * from our idea, only if the accept_{local,remote} flag is set.
6557c478bd9Sstevel@tonic-gate      */
6567c478bd9Sstevel@tonic-gate     NAKCIIFACEID(CI_IFACEID, neg_ifaceid,
6577c478bd9Sstevel@tonic-gate 	      if (go->accept_local) {
65848bbca81SDaniel Hoffman 		  while (eui64_iszero(ifaceid) ||
6597c478bd9Sstevel@tonic-gate 			 eui64_equals(ifaceid, go->hisid)) /* bad luck */
6607c478bd9Sstevel@tonic-gate 		      eui64_magic(ifaceid);
6617c478bd9Sstevel@tonic-gate 		  try.ourid = ifaceid;
6627c478bd9Sstevel@tonic-gate 		  IPV6CPDEBUG(("local LL address %s", llv6_ntoa(ifaceid)));
6637c478bd9Sstevel@tonic-gate 	      }
6647c478bd9Sstevel@tonic-gate 	      );
6657c478bd9Sstevel@tonic-gate 
6667c478bd9Sstevel@tonic-gate #ifdef IPV6CP_COMP
6677c478bd9Sstevel@tonic-gate     NAKCIVJ(CI_COMPRESSTYPE, neg_vj,
6687c478bd9Sstevel@tonic-gate 	    {
6697c478bd9Sstevel@tonic-gate 		if (cishort == IPV6CP_COMP) {
6707c478bd9Sstevel@tonic-gate 		    try.vj_protocol = cishort;
6717c478bd9Sstevel@tonic-gate 		} else {
6727c478bd9Sstevel@tonic-gate 		    try.neg_vj = 0;
6737c478bd9Sstevel@tonic-gate 		}
6747c478bd9Sstevel@tonic-gate 	    }
6757c478bd9Sstevel@tonic-gate 	    );
6767c478bd9Sstevel@tonic-gate #else
6777c478bd9Sstevel@tonic-gate     NAKCIVJ(CI_COMPRESSTYPE, neg_vj,
6787c478bd9Sstevel@tonic-gate 	    {
6797c478bd9Sstevel@tonic-gate 		try.neg_vj = 0;
6807c478bd9Sstevel@tonic-gate 	    }
6817c478bd9Sstevel@tonic-gate 	    );
6827c478bd9Sstevel@tonic-gate #endif
6837c478bd9Sstevel@tonic-gate 
6847c478bd9Sstevel@tonic-gate     /*
6857c478bd9Sstevel@tonic-gate      * There may be remaining CIs, if the peer is requesting negotiation
6867c478bd9Sstevel@tonic-gate      * on an option that we didn't include in our request packet.
6877c478bd9Sstevel@tonic-gate      * If they want to negotiate about interface identifier, we comply.
6887c478bd9Sstevel@tonic-gate      * If they want us to ask for compression, we refuse.
6897c478bd9Sstevel@tonic-gate      */
6907c478bd9Sstevel@tonic-gate     while (len > CILEN_VOID) {
6917c478bd9Sstevel@tonic-gate 	GETCHAR(citype, p);
6927c478bd9Sstevel@tonic-gate 	GETCHAR(cilen, p);
6937c478bd9Sstevel@tonic-gate 	if( (len -= cilen) < 0 )
6947c478bd9Sstevel@tonic-gate 	    goto bad;
6957c478bd9Sstevel@tonic-gate 	next = p + cilen - 2;
6967c478bd9Sstevel@tonic-gate 
6977c478bd9Sstevel@tonic-gate 	switch (citype) {
6987c478bd9Sstevel@tonic-gate 	case CI_COMPRESSTYPE:
6997c478bd9Sstevel@tonic-gate 	    if (go->neg_vj || no.neg_vj ||
7007c478bd9Sstevel@tonic-gate 		(cilen != CILEN_COMPRESS))
7017c478bd9Sstevel@tonic-gate 		goto bad;
7027c478bd9Sstevel@tonic-gate 	    no.neg_vj = 1;
7037c478bd9Sstevel@tonic-gate 	    break;
7047c478bd9Sstevel@tonic-gate 	case CI_IFACEID:
7057c478bd9Sstevel@tonic-gate 	    if (go->neg_ifaceid || no.neg_ifaceid || cilen != CILEN_IFACEID)
7067c478bd9Sstevel@tonic-gate 		goto bad;
7077c478bd9Sstevel@tonic-gate 	    try.neg_ifaceid = 1;
7087c478bd9Sstevel@tonic-gate 	    eui64_get(ifaceid, p);
7097c478bd9Sstevel@tonic-gate 	    if (go->accept_local) {
71048bbca81SDaniel Hoffman 		while (eui64_iszero(ifaceid) ||
7117c478bd9Sstevel@tonic-gate 		       eui64_equals(ifaceid, go->hisid)) /* bad luck */
7127c478bd9Sstevel@tonic-gate 		    eui64_magic(ifaceid);
7137c478bd9Sstevel@tonic-gate 		try.ourid = ifaceid;
7147c478bd9Sstevel@tonic-gate 	    }
7157c478bd9Sstevel@tonic-gate 	    no.neg_ifaceid = 1;
7167c478bd9Sstevel@tonic-gate 	    break;
7177c478bd9Sstevel@tonic-gate 	}
7187c478bd9Sstevel@tonic-gate 	p = next;
7197c478bd9Sstevel@tonic-gate     }
7207c478bd9Sstevel@tonic-gate 
7217c478bd9Sstevel@tonic-gate     /* If there is still anything left, this packet is bad. */
7227c478bd9Sstevel@tonic-gate     if (len != 0)
7237c478bd9Sstevel@tonic-gate 	goto bad;
7247c478bd9Sstevel@tonic-gate 
7257c478bd9Sstevel@tonic-gate     /*
7267c478bd9Sstevel@tonic-gate      * OK, the Nak is good.  Now we can update state.
7277c478bd9Sstevel@tonic-gate      */
7287c478bd9Sstevel@tonic-gate     if (f->state != OPENED)
7297c478bd9Sstevel@tonic-gate 	*go = try;
7307c478bd9Sstevel@tonic-gate 
7317c478bd9Sstevel@tonic-gate     return 1;
7327c478bd9Sstevel@tonic-gate 
7337c478bd9Sstevel@tonic-gate bad:
7347c478bd9Sstevel@tonic-gate     IPV6CPDEBUG(("ipv6cp_nakci: received bad Nak!"));
7357c478bd9Sstevel@tonic-gate     return 0;
7367c478bd9Sstevel@tonic-gate }
7377c478bd9Sstevel@tonic-gate 
7387c478bd9Sstevel@tonic-gate 
7397c478bd9Sstevel@tonic-gate /*
7407c478bd9Sstevel@tonic-gate  * ipv6cp_rejci - Reject some of our CIs.
7417c478bd9Sstevel@tonic-gate  */
7427c478bd9Sstevel@tonic-gate static int
ipv6cp_rejci(f,p,len)7437c478bd9Sstevel@tonic-gate ipv6cp_rejci(f, p, len)
7447c478bd9Sstevel@tonic-gate     fsm *f;
7457c478bd9Sstevel@tonic-gate     u_char *p;
7467c478bd9Sstevel@tonic-gate     int len;
7477c478bd9Sstevel@tonic-gate {
7487c478bd9Sstevel@tonic-gate     ipv6cp_options *go = &ipv6cp_gotoptions[f->unit];
7497c478bd9Sstevel@tonic-gate     u_char cilen;
7507c478bd9Sstevel@tonic-gate     u_short cishort;
7517c478bd9Sstevel@tonic-gate     eui64_t ifaceid;
7527c478bd9Sstevel@tonic-gate     ipv6cp_options try;		/* options to request next time */
7537c478bd9Sstevel@tonic-gate 
7547c478bd9Sstevel@tonic-gate     try = *go;
7557c478bd9Sstevel@tonic-gate     /*
7567c478bd9Sstevel@tonic-gate      * Any Rejected CIs must be in exactly the same order that we sent.
7577c478bd9Sstevel@tonic-gate      * Check packet length and CI length at each step.
7587c478bd9Sstevel@tonic-gate      * If we find any deviations, then this packet is bad.
7597c478bd9Sstevel@tonic-gate      */
7607c478bd9Sstevel@tonic-gate #define REJCIIFACEID(opt, neg, val1) \
7617c478bd9Sstevel@tonic-gate     if (go->neg && \
7627c478bd9Sstevel@tonic-gate 	len >= (cilen = CILEN_IFACEID) && \
7637c478bd9Sstevel@tonic-gate 	p[1] == cilen && \
7647c478bd9Sstevel@tonic-gate 	p[0] == opt) { \
7657c478bd9Sstevel@tonic-gate 	len -= cilen; \
7667c478bd9Sstevel@tonic-gate 	INCPTR(2, p); \
7677c478bd9Sstevel@tonic-gate 	eui64_get(ifaceid, p); \
7687c478bd9Sstevel@tonic-gate 	/* Check rejected value. */ \
7697c478bd9Sstevel@tonic-gate 	if (! eui64_equals(ifaceid, val1)) \
7707c478bd9Sstevel@tonic-gate 	    goto bad; \
7717c478bd9Sstevel@tonic-gate 	try.neg = 0; \
7727c478bd9Sstevel@tonic-gate     }
7737c478bd9Sstevel@tonic-gate 
7747c478bd9Sstevel@tonic-gate #define REJCIVJ(opt, neg, val) \
7757c478bd9Sstevel@tonic-gate     if (go->neg && \
7767c478bd9Sstevel@tonic-gate 	p[1] == CILEN_COMPRESS && \
7777c478bd9Sstevel@tonic-gate 	len >= p[1] && \
7787c478bd9Sstevel@tonic-gate 	p[0] == opt) { \
7797c478bd9Sstevel@tonic-gate 	len -= p[1]; \
7807c478bd9Sstevel@tonic-gate 	INCPTR(2, p); \
7817c478bd9Sstevel@tonic-gate 	GETSHORT(cishort, p); \
7827c478bd9Sstevel@tonic-gate 	/* Check rejected value. */  \
7837c478bd9Sstevel@tonic-gate 	if (cishort != val) \
7847c478bd9Sstevel@tonic-gate 	    goto bad; \
7857c478bd9Sstevel@tonic-gate 	try.neg = 0; \
7867c478bd9Sstevel@tonic-gate      }
7877c478bd9Sstevel@tonic-gate 
7887c478bd9Sstevel@tonic-gate     REJCIIFACEID(CI_IFACEID, neg_ifaceid, go->ourid);
7897c478bd9Sstevel@tonic-gate 
7907c478bd9Sstevel@tonic-gate     REJCIVJ(CI_COMPRESSTYPE, neg_vj, go->vj_protocol);
7917c478bd9Sstevel@tonic-gate 
7927c478bd9Sstevel@tonic-gate     /*
7937c478bd9Sstevel@tonic-gate      * If there are any remaining CIs, then this packet is bad.
7947c478bd9Sstevel@tonic-gate      */
7957c478bd9Sstevel@tonic-gate     if (len != 0)
7967c478bd9Sstevel@tonic-gate 	goto bad;
7977c478bd9Sstevel@tonic-gate     /*
7987c478bd9Sstevel@tonic-gate      * Now we can update state.
7997c478bd9Sstevel@tonic-gate      */
8007c478bd9Sstevel@tonic-gate     if (f->state != OPENED)
8017c478bd9Sstevel@tonic-gate 	*go = try;
8027c478bd9Sstevel@tonic-gate     return 1;
8037c478bd9Sstevel@tonic-gate 
8047c478bd9Sstevel@tonic-gate bad:
8057c478bd9Sstevel@tonic-gate     IPV6CPDEBUG(("ipv6cp_rejci: received bad Reject!"));
8067c478bd9Sstevel@tonic-gate     return 0;
8077c478bd9Sstevel@tonic-gate }
8087c478bd9Sstevel@tonic-gate 
8097c478bd9Sstevel@tonic-gate 
8107c478bd9Sstevel@tonic-gate /*
8117c478bd9Sstevel@tonic-gate  * ipv6cp_reqci - Check the peer's requested CIs and send appropriate response.
8127c478bd9Sstevel@tonic-gate  *
8137c478bd9Sstevel@tonic-gate  * Returns: CODE_CONFACK, CODE_CONFNAK or CODE_CONFREJ and input packet modified
8147c478bd9Sstevel@tonic-gate  * appropriately.  If reject_if_disagree is non-zero, doesn't return
8157c478bd9Sstevel@tonic-gate  * CODE_CONFNAK; returns CODE_CONFREJ if it can't return CODE_CONFACK.
8167c478bd9Sstevel@tonic-gate  */
8177c478bd9Sstevel@tonic-gate static int
ipv6cp_reqci(f,p,lenp,dont_nak)8187c478bd9Sstevel@tonic-gate ipv6cp_reqci(f, p, lenp, dont_nak)
8197c478bd9Sstevel@tonic-gate     fsm *f;
8207c478bd9Sstevel@tonic-gate     u_char *p;		/* Requested CIs */
8217c478bd9Sstevel@tonic-gate     int *lenp;			/* Length of requested CIs */
8227c478bd9Sstevel@tonic-gate     int dont_nak;
8237c478bd9Sstevel@tonic-gate {
8247c478bd9Sstevel@tonic-gate     ipv6cp_options *wo = &ipv6cp_wantoptions[f->unit];
8257c478bd9Sstevel@tonic-gate     ipv6cp_options *ho = &ipv6cp_hisoptions[f->unit];
8267c478bd9Sstevel@tonic-gate     ipv6cp_options *ao = &ipv6cp_allowoptions[f->unit];
8277c478bd9Sstevel@tonic-gate     ipv6cp_options *go = &ipv6cp_gotoptions[f->unit];
8287c478bd9Sstevel@tonic-gate     u_char *p0, *nakp, *rejp, *prev;
8297c478bd9Sstevel@tonic-gate     int ret, newret;
8307c478bd9Sstevel@tonic-gate     int len, cilen, type;
8317c478bd9Sstevel@tonic-gate     eui64_t ifaceid;
8327c478bd9Sstevel@tonic-gate     u_short cishort;
8337c478bd9Sstevel@tonic-gate 
8347c478bd9Sstevel@tonic-gate     ret = CODE_CONFACK;
8357c478bd9Sstevel@tonic-gate     rejp = p0 = p;
8367c478bd9Sstevel@tonic-gate     nakp = nak_buffer;
8377c478bd9Sstevel@tonic-gate 
8387c478bd9Sstevel@tonic-gate     /*
83948bbca81SDaniel Hoffman      * Reset all its options.
8407c478bd9Sstevel@tonic-gate      */
8417c478bd9Sstevel@tonic-gate     BZERO(ho, sizeof(*ho));
84248bbca81SDaniel Hoffman 
8437c478bd9Sstevel@tonic-gate     /*
84448bbca81SDaniel Hoffman      * Process all its options.
8457c478bd9Sstevel@tonic-gate      */
8467c478bd9Sstevel@tonic-gate     for (len = *lenp; len > 0; len -= cilen, p = prev + cilen) {
8477c478bd9Sstevel@tonic-gate 	newret = CODE_CONFACK;
8487c478bd9Sstevel@tonic-gate 
8497c478bd9Sstevel@tonic-gate 	if ((len < 2) || p[1] > len) {
8507c478bd9Sstevel@tonic-gate 	    /*
8517c478bd9Sstevel@tonic-gate 	     * RFC 1661 page 40 -- if the option extends beyond the
8527c478bd9Sstevel@tonic-gate 	     * packet, then discard the entire packet.
8537c478bd9Sstevel@tonic-gate 	     */
8547c478bd9Sstevel@tonic-gate 	    return (0);
8557c478bd9Sstevel@tonic-gate 	}
8567c478bd9Sstevel@tonic-gate 
8577c478bd9Sstevel@tonic-gate 	prev = p;
8587c478bd9Sstevel@tonic-gate 	GETCHAR(type, p);
8597c478bd9Sstevel@tonic-gate 	GETCHAR(cilen, p);
8607c478bd9Sstevel@tonic-gate 
8617c478bd9Sstevel@tonic-gate 	switch (type) {		/* Check CI type */
8627c478bd9Sstevel@tonic-gate 	case CI_IFACEID:
8637c478bd9Sstevel@tonic-gate 	    IPV6CPDEBUG(("ipv6cp: received interface identifier "));
8647c478bd9Sstevel@tonic-gate 
8657c478bd9Sstevel@tonic-gate 	    if (!ao->neg_ifaceid) {
8667c478bd9Sstevel@tonic-gate 		newret = CODE_CONFREJ;
8677c478bd9Sstevel@tonic-gate 		break;
8687c478bd9Sstevel@tonic-gate 	    }
8697c478bd9Sstevel@tonic-gate 
8707c478bd9Sstevel@tonic-gate 	    if (cilen != CILEN_IFACEID) {
8717c478bd9Sstevel@tonic-gate 		/*
8727c478bd9Sstevel@tonic-gate 		 * rfc1661, page 40 -- a recongnized option with an
8737c478bd9Sstevel@tonic-gate 		 * invalid length should be Nak'ed.
8747c478bd9Sstevel@tonic-gate 		 */
8757c478bd9Sstevel@tonic-gate 		newret = CODE_CONFNAK;
8767c478bd9Sstevel@tonic-gate 		eui64_copy(wo->hisid, ifaceid);
8777c478bd9Sstevel@tonic-gate 	    } else {
8787c478bd9Sstevel@tonic-gate 
8797c478bd9Sstevel@tonic-gate 		/*
88048bbca81SDaniel Hoffman 		 * If it has no interface identifier, or if we both
8817c478bd9Sstevel@tonic-gate 		 * have same identifier then NAK it with new idea.  In
882*a141dbd6SAlison C 		 * particular, if we don't know its identifier, but it
88348bbca81SDaniel Hoffman 		 * does, then accept that identifier.
8847c478bd9Sstevel@tonic-gate 		 */
8857c478bd9Sstevel@tonic-gate 		eui64_get(ifaceid, p);
8867c478bd9Sstevel@tonic-gate 		IPV6CPDEBUG(("(%s)", llv6_ntoa(ifaceid)));
8877c478bd9Sstevel@tonic-gate 		if (eui64_iszero(ifaceid) && eui64_iszero(go->ourid)) {
8887c478bd9Sstevel@tonic-gate 		    newret = CODE_CONFREJ;		/* Reject CI */
8897c478bd9Sstevel@tonic-gate 		    break;
8907c478bd9Sstevel@tonic-gate 		}
89148bbca81SDaniel Hoffman 		/* If we don't like its ID, then nak that ID. */
89248bbca81SDaniel Hoffman 		if (!eui64_iszero(wo->hisid) &&
89348bbca81SDaniel Hoffman 		    !eui64_equals(ifaceid, wo->hisid) &&
8947c478bd9Sstevel@tonic-gate 		    eui64_iszero(go->hisid)) {
8957c478bd9Sstevel@tonic-gate 		    newret = CODE_CONFNAK;
8967c478bd9Sstevel@tonic-gate 		    eui64_copy(wo->hisid, ifaceid);
8977c478bd9Sstevel@tonic-gate 		} else if (eui64_iszero(ifaceid) ||
8987c478bd9Sstevel@tonic-gate 		    eui64_equals(ifaceid, go->ourid)) {
8997c478bd9Sstevel@tonic-gate 		    newret = CODE_CONFNAK;
9007c478bd9Sstevel@tonic-gate 		    /* first time, try option */
9017c478bd9Sstevel@tonic-gate 		    if (eui64_iszero(go->hisid))
9027c478bd9Sstevel@tonic-gate 			eui64_copy(wo->hisid, ifaceid);
90348bbca81SDaniel Hoffman 		    while (eui64_iszero(ifaceid) ||
9047c478bd9Sstevel@tonic-gate 			eui64_equals(ifaceid, go->ourid)) /* bad luck */
9057c478bd9Sstevel@tonic-gate 			eui64_magic(ifaceid);
9067c478bd9Sstevel@tonic-gate 		}
9077c478bd9Sstevel@tonic-gate 	    }
9087c478bd9Sstevel@tonic-gate 	    if (newret == CODE_CONFNAK) {
9097c478bd9Sstevel@tonic-gate 		PUTCHAR(type, nakp);
9107c478bd9Sstevel@tonic-gate 		PUTCHAR(CILEN_IFACEID, nakp);
9117c478bd9Sstevel@tonic-gate 		eui64_put(ifaceid, nakp);
9127c478bd9Sstevel@tonic-gate 	    }
9137c478bd9Sstevel@tonic-gate 
9147c478bd9Sstevel@tonic-gate 	    ho->neg_ifaceid = 1;
9157c478bd9Sstevel@tonic-gate 	    eui64_copy(ifaceid, ho->hisid);
9167c478bd9Sstevel@tonic-gate 	    break;
9177c478bd9Sstevel@tonic-gate 
9187c478bd9Sstevel@tonic-gate 	case CI_COMPRESSTYPE:
9197c478bd9Sstevel@tonic-gate 	    IPV6CPDEBUG(("ipv6cp: received COMPRESSTYPE "));
9207c478bd9Sstevel@tonic-gate 
9217c478bd9Sstevel@tonic-gate 	    if (!ao->neg_vj) {
9227c478bd9Sstevel@tonic-gate 		newret = CODE_CONFREJ;
9237c478bd9Sstevel@tonic-gate 		break;
9247c478bd9Sstevel@tonic-gate 	    }
9257c478bd9Sstevel@tonic-gate 
9267c478bd9Sstevel@tonic-gate 	    if (cilen != CILEN_COMPRESS) {
9277c478bd9Sstevel@tonic-gate 		newret = CODE_CONFNAK;
9287c478bd9Sstevel@tonic-gate 		cishort = ao->vj_protocol;
9297c478bd9Sstevel@tonic-gate 	    } else {
9307c478bd9Sstevel@tonic-gate 		GETSHORT(cishort, p);
9317c478bd9Sstevel@tonic-gate 		IPV6CPDEBUG(("(%d)", cishort));
9327c478bd9Sstevel@tonic-gate 
9337c478bd9Sstevel@tonic-gate #ifdef IPV6CP_COMP
9347c478bd9Sstevel@tonic-gate 		if (cishort != IPV6CP_COMP) {
9357c478bd9Sstevel@tonic-gate 		    newret = CODE_CONFNAK;
9367c478bd9Sstevel@tonic-gate 		    cishort = IPV6CP_COMP;
9377c478bd9Sstevel@tonic-gate 		}
9387c478bd9Sstevel@tonic-gate #else
9397c478bd9Sstevel@tonic-gate 		newret = CODE_CONFREJ;
9407c478bd9Sstevel@tonic-gate 		break;
9417c478bd9Sstevel@tonic-gate #endif
9427c478bd9Sstevel@tonic-gate 	    }
9437c478bd9Sstevel@tonic-gate 
9447c478bd9Sstevel@tonic-gate 	    ho->neg_vj = 1;
9457c478bd9Sstevel@tonic-gate 	    ho->vj_protocol = cishort;
9467c478bd9Sstevel@tonic-gate 	    break;
9477c478bd9Sstevel@tonic-gate 
9487c478bd9Sstevel@tonic-gate 	default:
9497c478bd9Sstevel@tonic-gate 	    newret = CODE_CONFREJ;
9507c478bd9Sstevel@tonic-gate 	    break;
9517c478bd9Sstevel@tonic-gate 	}
9527c478bd9Sstevel@tonic-gate 
9537c478bd9Sstevel@tonic-gate 	IPV6CPDEBUG((" (%s)\n", CODENAME(newret)));
9547c478bd9Sstevel@tonic-gate 
9557c478bd9Sstevel@tonic-gate 	/* Cope with confused peers. */
9567c478bd9Sstevel@tonic-gate 	if (cilen < 2)
9577c478bd9Sstevel@tonic-gate 	    cilen = 2;
9587c478bd9Sstevel@tonic-gate 
9597c478bd9Sstevel@tonic-gate 	/*
9607c478bd9Sstevel@tonic-gate 	 * If this is an Ack'able CI, but we're sending back a Nak,
9617c478bd9Sstevel@tonic-gate 	 * don't include this CI.
9627c478bd9Sstevel@tonic-gate 	 */
9637c478bd9Sstevel@tonic-gate 	if (newret == CODE_CONFACK && ret != CODE_CONFACK)
9647c478bd9Sstevel@tonic-gate 	    continue;
9657c478bd9Sstevel@tonic-gate 
9667c478bd9Sstevel@tonic-gate 	if (newret == CODE_CONFNAK) {
9677c478bd9Sstevel@tonic-gate 	    if (dont_nak) {
9687c478bd9Sstevel@tonic-gate 		newret = CODE_CONFREJ;
9697c478bd9Sstevel@tonic-gate 	    } else {
9707c478bd9Sstevel@tonic-gate 		/* Ignore subsequent Nak'able things if rejecting. */
9717c478bd9Sstevel@tonic-gate 		if (ret == CODE_CONFREJ)
9727c478bd9Sstevel@tonic-gate 		    continue;
9737c478bd9Sstevel@tonic-gate 		ret = CODE_CONFNAK;
9747c478bd9Sstevel@tonic-gate 	    }
9757c478bd9Sstevel@tonic-gate 	}
9767c478bd9Sstevel@tonic-gate 
9777c478bd9Sstevel@tonic-gate 	if (newret == CODE_CONFREJ) {
9787c478bd9Sstevel@tonic-gate 	    ret = CODE_CONFREJ;
9797c478bd9Sstevel@tonic-gate 	    if (prev != rejp)
9807c478bd9Sstevel@tonic-gate 		(void) BCOPY(prev, rejp, cilen);
9817c478bd9Sstevel@tonic-gate 	    rejp += cilen;
9827c478bd9Sstevel@tonic-gate 	}
9837c478bd9Sstevel@tonic-gate     }
9847c478bd9Sstevel@tonic-gate 
9857c478bd9Sstevel@tonic-gate     /*
9867c478bd9Sstevel@tonic-gate      * If we aren't rejecting this packet, and we want to negotiate
9877c478bd9Sstevel@tonic-gate      * their identifier and they didn't send their identifier, then we
9887c478bd9Sstevel@tonic-gate      * send a NAK with a CI_IFACEID option appended.  We assume the
9897c478bd9Sstevel@tonic-gate      * input buffer is long enough that we can append the extra
9907c478bd9Sstevel@tonic-gate      * option safely.
9917c478bd9Sstevel@tonic-gate      */
9927c478bd9Sstevel@tonic-gate     if (ret != CODE_CONFREJ && !ho->neg_ifaceid &&
9937c478bd9Sstevel@tonic-gate 	wo->req_ifaceid && !dont_nak) {
9947c478bd9Sstevel@tonic-gate 	if (ret == CODE_CONFACK)
9957c478bd9Sstevel@tonic-gate 	    wo->req_ifaceid = 0;
9967c478bd9Sstevel@tonic-gate 	ret = CODE_CONFNAK;
9977c478bd9Sstevel@tonic-gate 	PUTCHAR(CI_IFACEID, nakp);
9987c478bd9Sstevel@tonic-gate 	PUTCHAR(CILEN_IFACEID, nakp);
9997c478bd9Sstevel@tonic-gate 	eui64_put(wo->hisid, nakp);
10007c478bd9Sstevel@tonic-gate     }
10017c478bd9Sstevel@tonic-gate 
10027c478bd9Sstevel@tonic-gate     switch (ret) {
10037c478bd9Sstevel@tonic-gate     case CODE_CONFACK:
10047c478bd9Sstevel@tonic-gate 	*lenp = p - p0;
100548bbca81SDaniel Hoffman 	sys_block_proto(PPP_IPV6);
10067c478bd9Sstevel@tonic-gate 	break;
10077c478bd9Sstevel@tonic-gate     case CODE_CONFNAK:
10087c478bd9Sstevel@tonic-gate 	*lenp = nakp - nak_buffer;
10097c478bd9Sstevel@tonic-gate 	(void) BCOPY(nak_buffer, p0, *lenp);
10107c478bd9Sstevel@tonic-gate 	break;
10117c478bd9Sstevel@tonic-gate     case CODE_CONFREJ:
10127c478bd9Sstevel@tonic-gate 	*lenp = rejp - p0;
10137c478bd9Sstevel@tonic-gate 	break;
10147c478bd9Sstevel@tonic-gate     }
10157c478bd9Sstevel@tonic-gate 
10167c478bd9Sstevel@tonic-gate     IPV6CPDEBUG(("ipv6cp: returning Configure-%s", CODENAME(ret)));
10177c478bd9Sstevel@tonic-gate     return (ret);			/* Return final code */
10187c478bd9Sstevel@tonic-gate }
10197c478bd9Sstevel@tonic-gate 
10207c478bd9Sstevel@tonic-gate 
10217c478bd9Sstevel@tonic-gate /*
10227c478bd9Sstevel@tonic-gate  * ipv6_check_options - check that any IP-related options are OK,
10237c478bd9Sstevel@tonic-gate  * and assign appropriate defaults.
10247c478bd9Sstevel@tonic-gate  */
10257c478bd9Sstevel@tonic-gate static void
ipv6_check_options()10267c478bd9Sstevel@tonic-gate ipv6_check_options()
10277c478bd9Sstevel@tonic-gate {
10287c478bd9Sstevel@tonic-gate     ipv6cp_options *wo = &ipv6cp_wantoptions[0];
10297c478bd9Sstevel@tonic-gate 
10307c478bd9Sstevel@tonic-gate #if defined(SOL2)
10317c478bd9Sstevel@tonic-gate     /*
10327c478bd9Sstevel@tonic-gate      * Persistent link-local id is only used when user has not explicitly
10337c478bd9Sstevel@tonic-gate      * configure/hard-code the id
10347c478bd9Sstevel@tonic-gate      */
10357c478bd9Sstevel@tonic-gate     if ((wo->use_persistent) && (!wo->opt_local) && (!wo->opt_remote)) {
10367c478bd9Sstevel@tonic-gate 
103748bbca81SDaniel Hoffman 	/*
10387c478bd9Sstevel@tonic-gate 	 * On systems where there are no Ethernet interfaces used, there
10397c478bd9Sstevel@tonic-gate 	 * may be other ways to obtain a persistent id. Right now, it
10407c478bd9Sstevel@tonic-gate 	 * will fall back to using magic [see eui64_magic] below when
10417c478bd9Sstevel@tonic-gate 	 * an EUI-48 from MAC address can't be obtained. Other possibilities
10427c478bd9Sstevel@tonic-gate 	 * include obtaining EEPROM serial numbers, or some other unique
10437c478bd9Sstevel@tonic-gate 	 * yet persistent number. On Sparc platforms, this is possible,
10447c478bd9Sstevel@tonic-gate 	 * but too bad there's no standards yet for x86 machines.
10457c478bd9Sstevel@tonic-gate 	 */
10467c478bd9Sstevel@tonic-gate 	if (ether_to_eui64(&wo->ourid)) {
10477c478bd9Sstevel@tonic-gate 	    wo->opt_local = 1;
10487c478bd9Sstevel@tonic-gate 	}
10497c478bd9Sstevel@tonic-gate     }
10507c478bd9Sstevel@tonic-gate #endif
10517c478bd9Sstevel@tonic-gate 
10527c478bd9Sstevel@tonic-gate     /*
10537c478bd9Sstevel@tonic-gate      * If ipv6cp-use-ipaddr is used, then both local and remote IPv4
10547c478bd9Sstevel@tonic-gate      * addresses should be specified as options.  Otherwise, since
10557c478bd9Sstevel@tonic-gate      * ipcp has yet to negotiate the IPv4 addresses, the interface
10567c478bd9Sstevel@tonic-gate      * identifiers will be based on meaningless values.
10577c478bd9Sstevel@tonic-gate      */
10587c478bd9Sstevel@tonic-gate     if (wo->use_ip) {
10597c478bd9Sstevel@tonic-gate 	if ((ipcp_wantoptions[0].accept_local ||
10607c478bd9Sstevel@tonic-gate 	    ipcp_wantoptions[0].ouraddr == 0) && eui64_iszero(wo->ourid)) {
10617c478bd9Sstevel@tonic-gate 	    warn("either IPv4 or IPv6 local address should be non-zero for ipv6cp-use-ipaddr");
10627c478bd9Sstevel@tonic-gate 	}
10637c478bd9Sstevel@tonic-gate 	if ((ipcp_wantoptions[0].accept_remote ||
10647c478bd9Sstevel@tonic-gate 	    ipcp_wantoptions[0].hisaddr == 0) && eui64_iszero(wo->hisid)) {
10657c478bd9Sstevel@tonic-gate 	    warn("either IPv4 or IPv6 remote address should be non-zero for ipv6cp-use-ipaddr");
10667c478bd9Sstevel@tonic-gate 	}
10677c478bd9Sstevel@tonic-gate     }
10687c478bd9Sstevel@tonic-gate 
10697c478bd9Sstevel@tonic-gate     if (!wo->opt_local) {	/* init interface identifier */
10707c478bd9Sstevel@tonic-gate 	if (wo->use_ip && eui64_iszero(wo->ourid)) {
10717c478bd9Sstevel@tonic-gate 	    eui64_setlo32(wo->ourid, ntohl(ipcp_wantoptions[0].ouraddr));
10727c478bd9Sstevel@tonic-gate 	    if (!eui64_iszero(wo->ourid))
10737c478bd9Sstevel@tonic-gate 		wo->opt_local = 1;
10747c478bd9Sstevel@tonic-gate 	}
10757c478bd9Sstevel@tonic-gate 
10767c478bd9Sstevel@tonic-gate 	while (eui64_iszero(wo->ourid))
10777c478bd9Sstevel@tonic-gate 	    eui64_magic(wo->ourid);
10787c478bd9Sstevel@tonic-gate     }
10797c478bd9Sstevel@tonic-gate 
10807c478bd9Sstevel@tonic-gate     if (!wo->opt_remote) {
10817c478bd9Sstevel@tonic-gate 	if (wo->use_ip && eui64_iszero(wo->hisid)) {
10827c478bd9Sstevel@tonic-gate 	    eui64_setlo32(wo->hisid, ntohl(ipcp_wantoptions[0].hisaddr));
10837c478bd9Sstevel@tonic-gate 	    if (!eui64_iszero(wo->hisid))
10847c478bd9Sstevel@tonic-gate 		wo->opt_remote = 1;
10857c478bd9Sstevel@tonic-gate 	}
10867c478bd9Sstevel@tonic-gate     }
10877c478bd9Sstevel@tonic-gate 
10887c478bd9Sstevel@tonic-gate     if (demand && (eui64_iszero(wo->ourid) || eui64_iszero(wo->hisid))) {
10897c478bd9Sstevel@tonic-gate 	fatal("local/remote LL address required for demand-dialling\n");
10907c478bd9Sstevel@tonic-gate     }
10917c478bd9Sstevel@tonic-gate }
10927c478bd9Sstevel@tonic-gate 
10937c478bd9Sstevel@tonic-gate 
10947c478bd9Sstevel@tonic-gate /*
10957c478bd9Sstevel@tonic-gate  * ipv6_demand_conf - configure the interface as though
10967c478bd9Sstevel@tonic-gate  * IPV6CP were up, for use with dial-on-demand.
10977c478bd9Sstevel@tonic-gate  */
10987c478bd9Sstevel@tonic-gate static int
ipv6_demand_conf(u)10997c478bd9Sstevel@tonic-gate ipv6_demand_conf(u)
11007c478bd9Sstevel@tonic-gate     int u;
11017c478bd9Sstevel@tonic-gate {
11027c478bd9Sstevel@tonic-gate     ipv6cp_options *wo = &ipv6cp_wantoptions[u];
11037c478bd9Sstevel@tonic-gate 
11047c478bd9Sstevel@tonic-gate #if SIF6UPFIRST
11057c478bd9Sstevel@tonic-gate     if (!sif6up(u))
11067c478bd9Sstevel@tonic-gate 	return 0;
110748bbca81SDaniel Hoffman #endif
11087c478bd9Sstevel@tonic-gate     if (!sif6addr(u, wo->ourid, wo->hisid))
11097c478bd9Sstevel@tonic-gate 	return 0;
11107c478bd9Sstevel@tonic-gate #if !SIF6UPFIRST
11117c478bd9Sstevel@tonic-gate     if (!sif6up(u))
11127c478bd9Sstevel@tonic-gate 	return 0;
11137c478bd9Sstevel@tonic-gate #endif
11147c478bd9Sstevel@tonic-gate     if (!sifnpmode(u, PPP_IPV6, NPMODE_QUEUE))
11157c478bd9Sstevel@tonic-gate 	return 0;
11167c478bd9Sstevel@tonic-gate 
11177c478bd9Sstevel@tonic-gate     notice("local  LL address %s", llv6_ntoa(wo->ourid));
11187c478bd9Sstevel@tonic-gate     notice("remote LL address %s", llv6_ntoa(wo->hisid));
11197c478bd9Sstevel@tonic-gate 
11207c478bd9Sstevel@tonic-gate     return 1;
11217c478bd9Sstevel@tonic-gate }
11227c478bd9Sstevel@tonic-gate 
11237c478bd9Sstevel@tonic-gate 
11247c478bd9Sstevel@tonic-gate /*
11257c478bd9Sstevel@tonic-gate  * ipv6cp_up - IPV6CP has come UP.
11267c478bd9Sstevel@tonic-gate  *
11277c478bd9Sstevel@tonic-gate  * Configure the IPv6 network interface appropriately and bring it up.
11287c478bd9Sstevel@tonic-gate  */
11297c478bd9Sstevel@tonic-gate static void
ipv6cp_up(f)11307c478bd9Sstevel@tonic-gate ipv6cp_up(f)
11317c478bd9Sstevel@tonic-gate     fsm *f;
11327c478bd9Sstevel@tonic-gate {
11337c478bd9Sstevel@tonic-gate     ipv6cp_options *ho = &ipv6cp_hisoptions[f->unit];
11347c478bd9Sstevel@tonic-gate     ipv6cp_options *go = &ipv6cp_gotoptions[f->unit];
11357c478bd9Sstevel@tonic-gate     ipv6cp_options *wo = &ipv6cp_wantoptions[f->unit];
11367c478bd9Sstevel@tonic-gate 
11377c478bd9Sstevel@tonic-gate     IPV6CPDEBUG(("ipv6cp: up"));
11387c478bd9Sstevel@tonic-gate 
11397c478bd9Sstevel@tonic-gate     /*
11407c478bd9Sstevel@tonic-gate      * We must have a non-zero LL address for both ends of the link.
11417c478bd9Sstevel@tonic-gate      */
11427c478bd9Sstevel@tonic-gate     if (!ho->neg_ifaceid)
11437c478bd9Sstevel@tonic-gate 	ho->hisid = wo->hisid;
11447c478bd9Sstevel@tonic-gate 
11457c478bd9Sstevel@tonic-gate     if(!no_ifaceid_neg) {
11467c478bd9Sstevel@tonic-gate 	if (eui64_iszero(ho->hisid)) {
11477c478bd9Sstevel@tonic-gate 	    error("Could not determine remote LL address");
11487c478bd9Sstevel@tonic-gate 	    ipv6cp_close(f->unit, "Could not determine remote LL address");
11497c478bd9Sstevel@tonic-gate 	    return;
11507c478bd9Sstevel@tonic-gate 	}
11517c478bd9Sstevel@tonic-gate 	if (eui64_iszero(go->ourid)) {
11527c478bd9Sstevel@tonic-gate 	    error("Could not determine local LL address");
11537c478bd9Sstevel@tonic-gate 	    ipv6cp_close(f->unit, "Could not determine local LL address");
11547c478bd9Sstevel@tonic-gate 	    return;
11557c478bd9Sstevel@tonic-gate 	}
11567c478bd9Sstevel@tonic-gate 	if (eui64_equals(go->ourid, ho->hisid)) {
11577c478bd9Sstevel@tonic-gate 	    error("local and remote LL addresses are equal");
11587c478bd9Sstevel@tonic-gate 	    ipv6cp_close(f->unit, "local and remote LL addresses are equal");
11597c478bd9Sstevel@tonic-gate 	    return;
11607c478bd9Sstevel@tonic-gate 	}
11617c478bd9Sstevel@tonic-gate     }
11627c478bd9Sstevel@tonic-gate 
11637c478bd9Sstevel@tonic-gate #ifdef IPV6CP_COMP
11647c478bd9Sstevel@tonic-gate     /* set tcp compression */
11657c478bd9Sstevel@tonic-gate     if (sif6comp(f->unit, ho->neg_vj) != 1) {
11667c478bd9Sstevel@tonic-gate 	ipv6cp_close(f->unit, "Could not enable TCP compression");
11677c478bd9Sstevel@tonic-gate 	return;
11687c478bd9Sstevel@tonic-gate     }
11697c478bd9Sstevel@tonic-gate #endif
11707c478bd9Sstevel@tonic-gate 
11717c478bd9Sstevel@tonic-gate     /*
11727c478bd9Sstevel@tonic-gate      * If we are doing dial-on-demand, the interface is already
11737c478bd9Sstevel@tonic-gate      * configured, so we put out any saved-up packets, then set the
11747c478bd9Sstevel@tonic-gate      * interface to pass IPv6 packets.
11757c478bd9Sstevel@tonic-gate      */
11767c478bd9Sstevel@tonic-gate     if (demand) {
11777c478bd9Sstevel@tonic-gate 	if (! eui64_equals(go->ourid, wo->ourid) ||
11787c478bd9Sstevel@tonic-gate 	    ! eui64_equals(ho->hisid, wo->hisid)) {
11797c478bd9Sstevel@tonic-gate 	    if (! eui64_equals(go->ourid, wo->ourid))
11807c478bd9Sstevel@tonic-gate 		warn("Local LL address changed to %s",
11817c478bd9Sstevel@tonic-gate 		     llv6_ntoa(go->ourid));
11827c478bd9Sstevel@tonic-gate 	    if (! eui64_equals(ho->hisid, wo->hisid))
11837c478bd9Sstevel@tonic-gate 		warn("Remote LL address changed to %s",
11847c478bd9Sstevel@tonic-gate 		     llv6_ntoa(ho->hisid));
11857c478bd9Sstevel@tonic-gate 	    ipv6cp_clear_addrs(f->unit, go->ourid, ho->hisid);
11867c478bd9Sstevel@tonic-gate 
11877c478bd9Sstevel@tonic-gate 	    /* Set the interface to the new addresses */
11887c478bd9Sstevel@tonic-gate 	    if (!sif6addr(f->unit, go->ourid, ho->hisid)) {
11897c478bd9Sstevel@tonic-gate 		if (debug)
11907c478bd9Sstevel@tonic-gate 		    warn("sif6addr failed");
11917c478bd9Sstevel@tonic-gate 		ipv6cp_close(f->unit, "Interface configuration failed");
11927c478bd9Sstevel@tonic-gate 		return;
11937c478bd9Sstevel@tonic-gate 	    }
11947c478bd9Sstevel@tonic-gate 
11957c478bd9Sstevel@tonic-gate 	}
11967c478bd9Sstevel@tonic-gate 	demand_rexmit(PPP_IPV6);
11977c478bd9Sstevel@tonic-gate 	if (sifnpmode(f->unit, PPP_IPV6, NPMODE_PASS) != 1) {
11987c478bd9Sstevel@tonic-gate 	    ipv6cp_close(f->unit, "Interface configuration failed");
11997c478bd9Sstevel@tonic-gate 	    return;
12007c478bd9Sstevel@tonic-gate 	}
12017c478bd9Sstevel@tonic-gate 
12027c478bd9Sstevel@tonic-gate     } else {
12037c478bd9Sstevel@tonic-gate 	/*
12047c478bd9Sstevel@tonic-gate 	 * Set LL addresses
12057c478bd9Sstevel@tonic-gate 	 */
12067c478bd9Sstevel@tonic-gate #if !SIF6UPFIRST
12077c478bd9Sstevel@tonic-gate 	if (!sif6addr(f->unit, go->ourid, ho->hisid)) {
12087c478bd9Sstevel@tonic-gate 	    if (debug)
12097c478bd9Sstevel@tonic-gate 		warn("sif6addr failed");
12107c478bd9Sstevel@tonic-gate 	    ipv6cp_close(f->unit, "Interface configuration failed");
12117c478bd9Sstevel@tonic-gate 	    return;
12127c478bd9Sstevel@tonic-gate 	}
12137c478bd9Sstevel@tonic-gate #endif
12147c478bd9Sstevel@tonic-gate #if defined(SOL2)
12157c478bd9Sstevel@tonic-gate 	/* bring the interface up for IPv6 */
12167c478bd9Sstevel@tonic-gate 	if (!sif6up(f->unit)) {
12177c478bd9Sstevel@tonic-gate 	    if (debug)
12187c478bd9Sstevel@tonic-gate 		warn("sifup failed (IPV6)");
12197c478bd9Sstevel@tonic-gate 	    ipv6cp_close(f->unit, "Interface configuration failed");
12207c478bd9Sstevel@tonic-gate 	    return;
12217c478bd9Sstevel@tonic-gate 	}
12227c478bd9Sstevel@tonic-gate #else
12237c478bd9Sstevel@tonic-gate 	if (!sifup(f->unit)) {
12247c478bd9Sstevel@tonic-gate 	    if (debug)
12257c478bd9Sstevel@tonic-gate 		warn("sifup failed (IPV6)");
12267c478bd9Sstevel@tonic-gate 	    ipv6cp_close(f->unit, "Interface configuration failed");
12277c478bd9Sstevel@tonic-gate 	    return;
12287c478bd9Sstevel@tonic-gate 	}
12297c478bd9Sstevel@tonic-gate #endif
12307c478bd9Sstevel@tonic-gate #if SIF6UPFIRST
12317c478bd9Sstevel@tonic-gate 	if (!sif6addr(f->unit, go->ourid, ho->hisid)) {
12327c478bd9Sstevel@tonic-gate 	    if (debug)
12337c478bd9Sstevel@tonic-gate 		warn("sif6addr failed");
12347c478bd9Sstevel@tonic-gate 	    ipv6cp_close(f->unit, "Interface configuration failed");
12357c478bd9Sstevel@tonic-gate 	    return;
12367c478bd9Sstevel@tonic-gate 	}
12377c478bd9Sstevel@tonic-gate #endif
12387c478bd9Sstevel@tonic-gate 	if (sifnpmode(f->unit, PPP_IPV6, NPMODE_PASS) != 1) {
12397c478bd9Sstevel@tonic-gate 	    ipv6cp_close(f->unit, "Interface configuration failed");
12407c478bd9Sstevel@tonic-gate 	    return;
12417c478bd9Sstevel@tonic-gate 	}
12427c478bd9Sstevel@tonic-gate 
12437c478bd9Sstevel@tonic-gate 	notice("local  LL address %s", llv6_ntoa(go->ourid));
12447c478bd9Sstevel@tonic-gate 	notice("remote LL address %s", llv6_ntoa(ho->hisid));
12457c478bd9Sstevel@tonic-gate     }
12467c478bd9Sstevel@tonic-gate 
12477c478bd9Sstevel@tonic-gate     np_up(f->unit, PPP_IPV6);
12487c478bd9Sstevel@tonic-gate     ipv6cp_is_up = 1;
12497c478bd9Sstevel@tonic-gate 
12507c478bd9Sstevel@tonic-gate     /*
12517c478bd9Sstevel@tonic-gate      * Execute the ipv6-up script, like this:
12527c478bd9Sstevel@tonic-gate      *	/etc/ppp/ipv6-up interface tty speed local-LL remote-LL
12537c478bd9Sstevel@tonic-gate      */
12547c478bd9Sstevel@tonic-gate     script_setenv("LLLOCAL", llv6_ntoa(go->ourid), 0);
12557c478bd9Sstevel@tonic-gate     script_setenv("LLREMOTE", llv6_ntoa(ho->hisid), 0);
12567c478bd9Sstevel@tonic-gate     if (ipv6cp_script_state == s_down && ipv6cp_script_pid == 0) {
12577c478bd9Sstevel@tonic-gate 	ipv6cp_script_state = s_up;
12587c478bd9Sstevel@tonic-gate 	ipv6cp_script(_PATH_IPV6UP);
12597c478bd9Sstevel@tonic-gate     }
12607c478bd9Sstevel@tonic-gate     sys_unblock_proto(PPP_IPV6);
12617c478bd9Sstevel@tonic-gate }
12627c478bd9Sstevel@tonic-gate 
12637c478bd9Sstevel@tonic-gate 
12647c478bd9Sstevel@tonic-gate /*
12657c478bd9Sstevel@tonic-gate  * ipv6cp_down - IPV6CP has gone DOWN.
12667c478bd9Sstevel@tonic-gate  *
12677c478bd9Sstevel@tonic-gate  * Take the IPv6 network interface down, clear its addresses
12687c478bd9Sstevel@tonic-gate  * and delete routes through it.
12697c478bd9Sstevel@tonic-gate  */
12707c478bd9Sstevel@tonic-gate static void
ipv6cp_down(f)12717c478bd9Sstevel@tonic-gate ipv6cp_down(f)
12727c478bd9Sstevel@tonic-gate     fsm *f;
12737c478bd9Sstevel@tonic-gate {
12747c478bd9Sstevel@tonic-gate     IPV6CPDEBUG(("ipv6cp: down"));
12757c478bd9Sstevel@tonic-gate     update_link_stats(f->unit);
12767c478bd9Sstevel@tonic-gate     if (ipv6cp_is_up) {
12777c478bd9Sstevel@tonic-gate 	ipv6cp_is_up = 0;
12787c478bd9Sstevel@tonic-gate 	np_down(f->unit, PPP_IPV6);
12797c478bd9Sstevel@tonic-gate     }
12807c478bd9Sstevel@tonic-gate #ifdef IPV6CP_COMP
12817c478bd9Sstevel@tonic-gate     if (sif6comp(f->unit, 0) != 1) {
12827c478bd9Sstevel@tonic-gate 	if (debug)
12837c478bd9Sstevel@tonic-gate 	    warn("Failed to disable TCP compression.");
12847c478bd9Sstevel@tonic-gate     }
12857c478bd9Sstevel@tonic-gate #endif
12867c478bd9Sstevel@tonic-gate 
12877c478bd9Sstevel@tonic-gate     /*
12887c478bd9Sstevel@tonic-gate      * If we are doing dial-on-demand, set the interface
12897c478bd9Sstevel@tonic-gate      * to queue up outgoing packets (for now).
12907c478bd9Sstevel@tonic-gate      */
12917c478bd9Sstevel@tonic-gate     if (demand) {
12927c478bd9Sstevel@tonic-gate 	if (sifnpmode(f->unit, PPP_IPV6, NPMODE_QUEUE) != 1) {
12937c478bd9Sstevel@tonic-gate 	    if (debug)
12947c478bd9Sstevel@tonic-gate 		warn("Failed to enable queueing on outgoing packets.");
12957c478bd9Sstevel@tonic-gate 	}
12967c478bd9Sstevel@tonic-gate     } else {
12977c478bd9Sstevel@tonic-gate 	if (sifnpmode(f->unit, PPP_IPV6, NPMODE_ERROR) != 1) {
12987c478bd9Sstevel@tonic-gate 	    if (debug)
12997c478bd9Sstevel@tonic-gate 		warn("Could not set interface to drop packets.");
13007c478bd9Sstevel@tonic-gate 	}
13017c478bd9Sstevel@tonic-gate #if !defined(__linux__) && !(defined(SVR4) && (defined(SNI) || defined(__USLC)))
13027c478bd9Sstevel@tonic-gate #if defined(SOL2)
13037c478bd9Sstevel@tonic-gate 	if (sif6down(f->unit) != 1)
13047c478bd9Sstevel@tonic-gate 	    warn("Couldn not bring interface down.");
13057c478bd9Sstevel@tonic-gate #else
13067c478bd9Sstevel@tonic-gate 	if (sifdown(f->unit) != 1)
13077c478bd9Sstevel@tonic-gate 	    warn("Could not bring interface down.");
13087c478bd9Sstevel@tonic-gate #endif /* defined(SOL2) */
13097c478bd9Sstevel@tonic-gate #endif
13107c478bd9Sstevel@tonic-gate 	ipv6cp_clear_addrs(f->unit,
13117c478bd9Sstevel@tonic-gate 			   ipv6cp_gotoptions[f->unit].ourid,
13127c478bd9Sstevel@tonic-gate 			   ipv6cp_hisoptions[f->unit].hisid);
13137c478bd9Sstevel@tonic-gate #if defined(__linux__) || (defined(SVR4) && (defined(SNI) || defined(__USLC)))
13147c478bd9Sstevel@tonic-gate 	if (sifdown(f->unit) != 1)
13157c478bd9Sstevel@tonic-gate 	    warn("Could not bring interface down.");
13167c478bd9Sstevel@tonic-gate #endif
13177c478bd9Sstevel@tonic-gate     }
13187c478bd9Sstevel@tonic-gate 
13197c478bd9Sstevel@tonic-gate     /* Execute the ipv6-down script */
13207c478bd9Sstevel@tonic-gate     if (ipv6cp_script_state == s_up && ipv6cp_script_pid == 0) {
13217c478bd9Sstevel@tonic-gate 	ipv6cp_script_state = s_down;
13227c478bd9Sstevel@tonic-gate 	ipv6cp_script(_PATH_IPV6DOWN);
13237c478bd9Sstevel@tonic-gate     }
13247c478bd9Sstevel@tonic-gate }
13257c478bd9Sstevel@tonic-gate 
13267c478bd9Sstevel@tonic-gate 
13277c478bd9Sstevel@tonic-gate /*
13287c478bd9Sstevel@tonic-gate  * ipv6cp_clear_addrs() - clear the interface addresses, routes,
13297c478bd9Sstevel@tonic-gate  * proxy neighbour discovery entries, etc.
13307c478bd9Sstevel@tonic-gate  */
13317c478bd9Sstevel@tonic-gate static void
ipv6cp_clear_addrs(unit,ourid,hisid)13327c478bd9Sstevel@tonic-gate ipv6cp_clear_addrs(unit, ourid, hisid)
13337c478bd9Sstevel@tonic-gate     int unit;
13347c478bd9Sstevel@tonic-gate     eui64_t ourid;
13357c478bd9Sstevel@tonic-gate     eui64_t hisid;
13367c478bd9Sstevel@tonic-gate {
13377c478bd9Sstevel@tonic-gate     if (cif6addr(unit, ourid, hisid) != 1)
13387c478bd9Sstevel@tonic-gate 	warn("Could not clear addresses");
13397c478bd9Sstevel@tonic-gate }
13407c478bd9Sstevel@tonic-gate 
13417c478bd9Sstevel@tonic-gate 
13427c478bd9Sstevel@tonic-gate /*
13437c478bd9Sstevel@tonic-gate  * ipv6cp_finished - possibly shut down the lower layers.
13447c478bd9Sstevel@tonic-gate  */
13457c478bd9Sstevel@tonic-gate static void
ipv6cp_finished(f)13467c478bd9Sstevel@tonic-gate ipv6cp_finished(f)
13477c478bd9Sstevel@tonic-gate     fsm *f;
13487c478bd9Sstevel@tonic-gate {
13497c478bd9Sstevel@tonic-gate     np_finished(f->unit, PPP_IPV6);
13507c478bd9Sstevel@tonic-gate }
13517c478bd9Sstevel@tonic-gate 
13527c478bd9Sstevel@tonic-gate 
13537c478bd9Sstevel@tonic-gate /*
13547c478bd9Sstevel@tonic-gate  * ipv6cp_script_done - called when the ipv6-up or ipv6-down script
13557c478bd9Sstevel@tonic-gate  * has finished.
13567c478bd9Sstevel@tonic-gate  */
13577c478bd9Sstevel@tonic-gate /*ARGSUSED*/
13587c478bd9Sstevel@tonic-gate static void
ipv6cp_script_done(arg,status)13597c478bd9Sstevel@tonic-gate ipv6cp_script_done(arg, status)
13607c478bd9Sstevel@tonic-gate     void *arg;
13617c478bd9Sstevel@tonic-gate     int status;
13627c478bd9Sstevel@tonic-gate {
13637c478bd9Sstevel@tonic-gate     ipv6cp_script_pid = 0;
13647c478bd9Sstevel@tonic-gate     switch (ipv6cp_script_state) {
13657c478bd9Sstevel@tonic-gate     case s_up:
13667c478bd9Sstevel@tonic-gate 	if (ipv6cp_fsm[0].state != OPENED) {
13677c478bd9Sstevel@tonic-gate 	    ipv6cp_script_state = s_down;
13687c478bd9Sstevel@tonic-gate 	    ipv6cp_script(_PATH_IPV6DOWN);
13697c478bd9Sstevel@tonic-gate 	}
13707c478bd9Sstevel@tonic-gate 	break;
13717c478bd9Sstevel@tonic-gate     case s_down:
13727c478bd9Sstevel@tonic-gate 	if (ipv6cp_fsm[0].state == OPENED) {
13737c478bd9Sstevel@tonic-gate 	    ipv6cp_script_state = s_up;
13747c478bd9Sstevel@tonic-gate 	    ipv6cp_script(_PATH_IPV6UP);
13757c478bd9Sstevel@tonic-gate 	}
13767c478bd9Sstevel@tonic-gate 	break;
13777c478bd9Sstevel@tonic-gate     }
13787c478bd9Sstevel@tonic-gate }
13797c478bd9Sstevel@tonic-gate 
13807c478bd9Sstevel@tonic-gate 
13817c478bd9Sstevel@tonic-gate /*
13827c478bd9Sstevel@tonic-gate  * ipv6cp_script - Execute a script with arguments
13837c478bd9Sstevel@tonic-gate  * interface-name tty-name speed local-LL remote-LL.
13847c478bd9Sstevel@tonic-gate  */
13857c478bd9Sstevel@tonic-gate static void
ipv6cp_script(script)13867c478bd9Sstevel@tonic-gate ipv6cp_script(script)
13877c478bd9Sstevel@tonic-gate     char *script;
13887c478bd9Sstevel@tonic-gate {
13897c478bd9Sstevel@tonic-gate     char strspeed[32], strlocal[26], strremote[26];
13907c478bd9Sstevel@tonic-gate     char *argv[8];
13917c478bd9Sstevel@tonic-gate 
13927c478bd9Sstevel@tonic-gate     (void) slprintf(strspeed, sizeof (strspeed), "%d", baud_rate);
13937c478bd9Sstevel@tonic-gate     (void) strlcpy(strlocal, llv6_ntoa(ipv6cp_gotoptions[0].ourid),
13947c478bd9Sstevel@tonic-gate 	sizeof (strlocal));
13957c478bd9Sstevel@tonic-gate     (void) strlcpy(strremote, llv6_ntoa(ipv6cp_hisoptions[0].hisid),
13967c478bd9Sstevel@tonic-gate 	sizeof (strremote));
13977c478bd9Sstevel@tonic-gate 
13987c478bd9Sstevel@tonic-gate     argv[0] = script;
13997c478bd9Sstevel@tonic-gate     argv[1] = ifname;
14007c478bd9Sstevel@tonic-gate     argv[2] = devnam;
14017c478bd9Sstevel@tonic-gate     argv[3] = strspeed;
14027c478bd9Sstevel@tonic-gate     argv[4] = strlocal;
14037c478bd9Sstevel@tonic-gate     argv[5] = strremote;
14047c478bd9Sstevel@tonic-gate     argv[6] = ipparam;
14057c478bd9Sstevel@tonic-gate     argv[7] = NULL;
14067c478bd9Sstevel@tonic-gate 
14077c478bd9Sstevel@tonic-gate     ipv6cp_script_pid = run_program(script, argv, 0, ipv6cp_script_done, NULL);
14087c478bd9Sstevel@tonic-gate }
14097c478bd9Sstevel@tonic-gate 
14107c478bd9Sstevel@tonic-gate static int
ipv6cp_printpkt(p,plen,printer,arg)14117c478bd9Sstevel@tonic-gate ipv6cp_printpkt(p, plen, printer, arg)
14127c478bd9Sstevel@tonic-gate     u_char *p;
14137c478bd9Sstevel@tonic-gate     int plen;
14147c478bd9Sstevel@tonic-gate     void (*printer) __P((void *, const char *, ...));
14157c478bd9Sstevel@tonic-gate     void *arg;
14167c478bd9Sstevel@tonic-gate {
14177c478bd9Sstevel@tonic-gate     int code, id, len, olen;
14187c478bd9Sstevel@tonic-gate     u_char *pstart, *optend;
14197c478bd9Sstevel@tonic-gate     u_short cishort;
14207c478bd9Sstevel@tonic-gate     eui64_t ifaceid;
14217c478bd9Sstevel@tonic-gate 
14227c478bd9Sstevel@tonic-gate     if (plen < HEADERLEN)
14237c478bd9Sstevel@tonic-gate 	return 0;
14247c478bd9Sstevel@tonic-gate     pstart = p;
14257c478bd9Sstevel@tonic-gate     GETCHAR(code, p);
14267c478bd9Sstevel@tonic-gate     GETCHAR(id, p);
14277c478bd9Sstevel@tonic-gate     GETSHORT(len, p);
14287c478bd9Sstevel@tonic-gate     if (len < HEADERLEN || len > plen)
14297c478bd9Sstevel@tonic-gate 	return 0;
14307c478bd9Sstevel@tonic-gate 
143148bbca81SDaniel Hoffman 
14327c478bd9Sstevel@tonic-gate     printer(arg, " %s id=0x%x", code_name(code, 1), id);
14337c478bd9Sstevel@tonic-gate     len -= HEADERLEN;
14347c478bd9Sstevel@tonic-gate     switch (code) {
14357c478bd9Sstevel@tonic-gate     case CODE_CONFREQ:
14367c478bd9Sstevel@tonic-gate     case CODE_CONFACK:
14377c478bd9Sstevel@tonic-gate     case CODE_CONFNAK:
14387c478bd9Sstevel@tonic-gate     case CODE_CONFREJ:
14397c478bd9Sstevel@tonic-gate 	/* print option list */
14407c478bd9Sstevel@tonic-gate 	while (len >= 2) {
14417c478bd9Sstevel@tonic-gate 	    GETCHAR(code, p);
14427c478bd9Sstevel@tonic-gate 	    GETCHAR(olen, p);
14437c478bd9Sstevel@tonic-gate 	    p -= 2;
14447c478bd9Sstevel@tonic-gate 	    if (olen < 2 || olen > len) {
14457c478bd9Sstevel@tonic-gate 		break;
14467c478bd9Sstevel@tonic-gate 	    }
14477c478bd9Sstevel@tonic-gate 	    printer(arg, " <");
14487c478bd9Sstevel@tonic-gate 	    len -= olen;
14497c478bd9Sstevel@tonic-gate 	    optend = p + olen;
14507c478bd9Sstevel@tonic-gate 	    switch (code) {
14517c478bd9Sstevel@tonic-gate 	    case CI_COMPRESSTYPE:
14527c478bd9Sstevel@tonic-gate 		if (olen >= CILEN_COMPRESS) {
14537c478bd9Sstevel@tonic-gate 		    p += 2;
14547c478bd9Sstevel@tonic-gate 		    GETSHORT(cishort, p);
14557c478bd9Sstevel@tonic-gate 		    printer(arg, "compress 0x%x", cishort);
14567c478bd9Sstevel@tonic-gate 		}
14577c478bd9Sstevel@tonic-gate 		break;
14587c478bd9Sstevel@tonic-gate 	    case CI_IFACEID:
14597c478bd9Sstevel@tonic-gate 		if (olen == CILEN_IFACEID) {
14607c478bd9Sstevel@tonic-gate 		    p += 2;
14617c478bd9Sstevel@tonic-gate 		    eui64_get(ifaceid, p);
14627c478bd9Sstevel@tonic-gate 		    printer(arg, "addr %s", llv6_ntoa(ifaceid));
14637c478bd9Sstevel@tonic-gate 		}
14647c478bd9Sstevel@tonic-gate 		break;
14657c478bd9Sstevel@tonic-gate 	    }
14667c478bd9Sstevel@tonic-gate 	    printer(arg, "%8.*B>", optend-p, p);
14677c478bd9Sstevel@tonic-gate 	    p = optend;
14687c478bd9Sstevel@tonic-gate 	}
14697c478bd9Sstevel@tonic-gate 	break;
14707c478bd9Sstevel@tonic-gate 
14717c478bd9Sstevel@tonic-gate     case CODE_TERMACK:
14727c478bd9Sstevel@tonic-gate     case CODE_TERMREQ:
14737c478bd9Sstevel@tonic-gate 	if (len > 0 && *p >= ' ' && *p < 0x7f) {
14747c478bd9Sstevel@tonic-gate 	    printer(arg, " ");
14757c478bd9Sstevel@tonic-gate 	    print_string((char *)p, len, printer, arg);
14767c478bd9Sstevel@tonic-gate 	    p += len;
14777c478bd9Sstevel@tonic-gate 	    len = 0;
14787c478bd9Sstevel@tonic-gate 	}
14797c478bd9Sstevel@tonic-gate 	break;
14807c478bd9Sstevel@tonic-gate     }
14817c478bd9Sstevel@tonic-gate 
14827c478bd9Sstevel@tonic-gate     /* print the rest of the bytes in the packet */
14837c478bd9Sstevel@tonic-gate     printer(arg, " %32.*B", len, p);
14847c478bd9Sstevel@tonic-gate 
14857c478bd9Sstevel@tonic-gate     return p - pstart;
14867c478bd9Sstevel@tonic-gate }
14877c478bd9Sstevel@tonic-gate 
14887c478bd9Sstevel@tonic-gate /*
14897c478bd9Sstevel@tonic-gate  * ipv6_active_pkt - see if this IP packet is worth bringing the link up for.
14907c478bd9Sstevel@tonic-gate  * We don't bring the link up for IP fragments or for TCP FIN packets
14917c478bd9Sstevel@tonic-gate  * with no data.
14927c478bd9Sstevel@tonic-gate  */
14937c478bd9Sstevel@tonic-gate #define TCP_HDRLEN	20
14947c478bd9Sstevel@tonic-gate #define TH_FIN		0x01
14957c478bd9Sstevel@tonic-gate 
14967c478bd9Sstevel@tonic-gate static int
ipv6_active_pkt(pkt,len)14977c478bd9Sstevel@tonic-gate ipv6_active_pkt(pkt, len)
14987c478bd9Sstevel@tonic-gate     u_char *pkt;
14997c478bd9Sstevel@tonic-gate     int len;
15007c478bd9Sstevel@tonic-gate {
15017c478bd9Sstevel@tonic-gate     u_char *tcp;
1502f53eecf5SJames Carlson     struct in6_addr addr;
1503f53eecf5SJames Carlson     char fromstr[26];
1504f53eecf5SJames Carlson     char tostr[26];
15057c478bd9Sstevel@tonic-gate 
15067c478bd9Sstevel@tonic-gate     len -= PPP_HDRLEN;
15077c478bd9Sstevel@tonic-gate     pkt += PPP_HDRLEN;
1508f53eecf5SJames Carlson     if (len < IP6_HDRLEN) {
1509f53eecf5SJames Carlson 	dbglog("IPv6 packet of length %d is not activity", len);
15107c478bd9Sstevel@tonic-gate 	return 0;
1511f53eecf5SJames Carlson     }
1512f53eecf5SJames Carlson     (void) BCOPY(get_ip6src(pkt), &addr, sizeof (addr));
1513f53eecf5SJames Carlson     (void) inet_ntop(AF_INET6, &addr, fromstr, 26);
1514f53eecf5SJames Carlson     (void) BCOPY(get_ip6dst(pkt), &addr, sizeof (addr));
1515f53eecf5SJames Carlson     (void) inet_ntop(AF_INET6, &addr, tostr, 26);
1516f53eecf5SJames Carlson     if (get_ip6nh(pkt) == IPPROTO_FRAGMENT) {
1517f53eecf5SJames Carlson 	dbglog("IPv6 fragment from %s->%s is not activity", fromstr, tostr);
15187c478bd9Sstevel@tonic-gate 	return 0;
1519f53eecf5SJames Carlson     }
1520f53eecf5SJames Carlson     if (get_ip6nh(pkt) != IPPROTO_TCP) {
1521f53eecf5SJames Carlson 	info("IPv6 proto %d from %s->%s is activity", get_ip6nh(pkt), fromstr,
1522f53eecf5SJames Carlson 	    tostr);
15237c478bd9Sstevel@tonic-gate 	return 1;
1524f53eecf5SJames Carlson     }
1525f53eecf5SJames Carlson     if (len < IP6_HDRLEN + TCP_HDRLEN) {
1526f53eecf5SJames Carlson 	dbglog("Bad TCP length %d<%d+%d %s->%s is not activity", len,
1527f53eecf5SJames Carlson 	    IP6_HDRLEN, TCP_HDRLEN, fromstr, tostr);
15287c478bd9Sstevel@tonic-gate 	return 0;
1529f53eecf5SJames Carlson     }
15307c478bd9Sstevel@tonic-gate     tcp = pkt + IP6_HDRLEN;
15317c478bd9Sstevel@tonic-gate     if ((get_tcpflags(tcp) & TH_FIN) != 0 &&
1532f53eecf5SJames Carlson 	len == IP6_HDRLEN + get_tcpoff(tcp) * 4) {
1533f53eecf5SJames Carlson 	dbglog("Empty TCP FIN %s->%s is not activity", fromstr, tostr);
15347c478bd9Sstevel@tonic-gate 	return 0;
1535f53eecf5SJames Carlson     }
1536f53eecf5SJames Carlson     info("TCP %d data %s%s->%s is activity", len - IP6_HDRLEN - TCP_HDRLEN,
1537f53eecf5SJames Carlson 	tcp_flag_decode(get_tcpflags(tcp)), fromstr, tostr);
15387c478bd9Sstevel@tonic-gate     return 1;
15397c478bd9Sstevel@tonic-gate }
1540