1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate #include "defs.h"
30*7c478bd9Sstevel@tonic-gate #include "tables.h"
31*7c478bd9Sstevel@tonic-gate 
32*7c478bd9Sstevel@tonic-gate #include <time.h>
33*7c478bd9Sstevel@tonic-gate #include <inet/ip6.h>
34*7c478bd9Sstevel@tonic-gate 
35*7c478bd9Sstevel@tonic-gate struct phyint *phyints = NULL;
36*7c478bd9Sstevel@tonic-gate 
37*7c478bd9Sstevel@tonic-gate static void	phyint_print(struct phyint *pi);
38*7c478bd9Sstevel@tonic-gate static void	phyint_insert(struct phyint *pi);
39*7c478bd9Sstevel@tonic-gate 
40*7c478bd9Sstevel@tonic-gate static boolean_t tmptoken_isvalid(struct in6_addr *token);
41*7c478bd9Sstevel@tonic-gate 
42*7c478bd9Sstevel@tonic-gate static void	prefix_print(struct prefix *pr);
43*7c478bd9Sstevel@tonic-gate static void	prefix_insert(struct phyint *pi, struct prefix *pr);
44*7c478bd9Sstevel@tonic-gate static char	*prefix_print_state(int state, char *buf, int buflen);
45*7c478bd9Sstevel@tonic-gate static void	prefix_set(struct in6_addr *prefix, struct in6_addr addr,
46*7c478bd9Sstevel@tonic-gate 		    int bits);
47*7c478bd9Sstevel@tonic-gate 
48*7c478bd9Sstevel@tonic-gate static void	adv_prefix_print(struct adv_prefix *adv_pr);
49*7c478bd9Sstevel@tonic-gate static void	adv_prefix_insert(struct phyint *pi, struct adv_prefix *adv_pr);
50*7c478bd9Sstevel@tonic-gate static void	adv_prefix_delete(struct adv_prefix *adv_pr);
51*7c478bd9Sstevel@tonic-gate 
52*7c478bd9Sstevel@tonic-gate static void	router_print(struct router *dr);
53*7c478bd9Sstevel@tonic-gate static void	router_insert(struct phyint *pi, struct router *dr);
54*7c478bd9Sstevel@tonic-gate static void	router_delete(struct router *dr);
55*7c478bd9Sstevel@tonic-gate static void	router_add_k(struct router *dr);
56*7c478bd9Sstevel@tonic-gate static void	router_delete_k(struct router *dr);
57*7c478bd9Sstevel@tonic-gate static void	router_delete_onlink(struct phyint *pi);
58*7c478bd9Sstevel@tonic-gate 
59*7c478bd9Sstevel@tonic-gate static int	rtmseq;				/* rtm_seq sequence number */
60*7c478bd9Sstevel@tonic-gate 
61*7c478bd9Sstevel@tonic-gate /* 1 week in ms */
62*7c478bd9Sstevel@tonic-gate #define	NDP_PREFIX_DEFAULT_LIFETIME	(7*24*60*60*1000)
63*7c478bd9Sstevel@tonic-gate struct phyint *
64*7c478bd9Sstevel@tonic-gate phyint_lookup(char *name)
65*7c478bd9Sstevel@tonic-gate {
66*7c478bd9Sstevel@tonic-gate 	struct phyint *pi;
67*7c478bd9Sstevel@tonic-gate 
68*7c478bd9Sstevel@tonic-gate 	if (debug & D_PHYINT)
69*7c478bd9Sstevel@tonic-gate 		logmsg(LOG_DEBUG, "phyint_lookup(%s)\n", name);
70*7c478bd9Sstevel@tonic-gate 
71*7c478bd9Sstevel@tonic-gate 	for (pi = phyints; pi != NULL; pi = pi->pi_next) {
72*7c478bd9Sstevel@tonic-gate 		if (strcmp(pi->pi_name, name) == 0)
73*7c478bd9Sstevel@tonic-gate 			break;
74*7c478bd9Sstevel@tonic-gate 	}
75*7c478bd9Sstevel@tonic-gate 	return (pi);
76*7c478bd9Sstevel@tonic-gate }
77*7c478bd9Sstevel@tonic-gate 
78*7c478bd9Sstevel@tonic-gate struct phyint *
79*7c478bd9Sstevel@tonic-gate phyint_lookup_on_index(uint_t ifindex)
80*7c478bd9Sstevel@tonic-gate {
81*7c478bd9Sstevel@tonic-gate 	struct phyint *pi;
82*7c478bd9Sstevel@tonic-gate 
83*7c478bd9Sstevel@tonic-gate 	if (debug & D_PHYINT)
84*7c478bd9Sstevel@tonic-gate 		logmsg(LOG_DEBUG, "phyint_lookup_on_index(%d)\n", ifindex);
85*7c478bd9Sstevel@tonic-gate 
86*7c478bd9Sstevel@tonic-gate 	for (pi = phyints; pi != NULL; pi = pi->pi_next) {
87*7c478bd9Sstevel@tonic-gate 		if (pi->pi_index == ifindex)
88*7c478bd9Sstevel@tonic-gate 			break;
89*7c478bd9Sstevel@tonic-gate 	}
90*7c478bd9Sstevel@tonic-gate 	return (pi);
91*7c478bd9Sstevel@tonic-gate }
92*7c478bd9Sstevel@tonic-gate 
93*7c478bd9Sstevel@tonic-gate struct phyint *
94*7c478bd9Sstevel@tonic-gate phyint_create(char *name)
95*7c478bd9Sstevel@tonic-gate {
96*7c478bd9Sstevel@tonic-gate 	struct phyint *pi;
97*7c478bd9Sstevel@tonic-gate 	int i;
98*7c478bd9Sstevel@tonic-gate 
99*7c478bd9Sstevel@tonic-gate 	if (debug & D_PHYINT)
100*7c478bd9Sstevel@tonic-gate 		logmsg(LOG_DEBUG, "phyint_create(%s)\n", name);
101*7c478bd9Sstevel@tonic-gate 
102*7c478bd9Sstevel@tonic-gate 	pi = (struct phyint *)calloc(sizeof (struct phyint), 1);
103*7c478bd9Sstevel@tonic-gate 	if (pi == NULL) {
104*7c478bd9Sstevel@tonic-gate 		logmsg(LOG_ERR, "phyint_create: out of memory\n");
105*7c478bd9Sstevel@tonic-gate 		return (NULL);
106*7c478bd9Sstevel@tonic-gate 	}
107*7c478bd9Sstevel@tonic-gate 	(void) strncpy(pi->pi_name, name, sizeof (pi->pi_name));
108*7c478bd9Sstevel@tonic-gate 	pi->pi_name[sizeof (pi->pi_name) - 1] = '\0';
109*7c478bd9Sstevel@tonic-gate 
110*7c478bd9Sstevel@tonic-gate 	/*
111*7c478bd9Sstevel@tonic-gate 	 * Copy the defaults from the defaults array.
112*7c478bd9Sstevel@tonic-gate 	 * Do not copy the cf_notdefault fields since these have not
113*7c478bd9Sstevel@tonic-gate 	 * been explicitly set for the phyint.
114*7c478bd9Sstevel@tonic-gate 	 */
115*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < I_IFSIZE; i++)
116*7c478bd9Sstevel@tonic-gate 		pi->pi_config[i].cf_value = ifdefaults[i].cf_value;
117*7c478bd9Sstevel@tonic-gate 
118*7c478bd9Sstevel@tonic-gate 	/*
119*7c478bd9Sstevel@tonic-gate 	 * TmpDesyncFactor is used to desynchronize temporary token
120*7c478bd9Sstevel@tonic-gate 	 * generation among systems; the actual preferred lifetime value
121*7c478bd9Sstevel@tonic-gate 	 * of a temporary address will be (TmpPreferredLifetime -
122*7c478bd9Sstevel@tonic-gate 	 * TmpDesyncFactor).  It's a random value, with a user-configurable
123*7c478bd9Sstevel@tonic-gate 	 * maximum value.  The value is constant throughout the lifetime
124*7c478bd9Sstevel@tonic-gate 	 * of the in.ndpd process, but can change if the daemon is restarted,
125*7c478bd9Sstevel@tonic-gate 	 * per RFC3041.
126*7c478bd9Sstevel@tonic-gate 	 */
127*7c478bd9Sstevel@tonic-gate 	if (pi->pi_TmpMaxDesyncFactor != 0) {
128*7c478bd9Sstevel@tonic-gate 		time_t seed = time(NULL);
129*7c478bd9Sstevel@tonic-gate 		srand((uint_t)seed);
130*7c478bd9Sstevel@tonic-gate 		pi->pi_TmpDesyncFactor = rand() % pi->pi_TmpMaxDesyncFactor;
131*7c478bd9Sstevel@tonic-gate 		/* we actually want [1,max], not [0,(max-1)] */
132*7c478bd9Sstevel@tonic-gate 		pi->pi_TmpDesyncFactor++;
133*7c478bd9Sstevel@tonic-gate 	}
134*7c478bd9Sstevel@tonic-gate 	pi->pi_TmpRegenCountdown = TIMER_INFINITY;
135*7c478bd9Sstevel@tonic-gate 
136*7c478bd9Sstevel@tonic-gate 	pi->pi_sock = -1;
137*7c478bd9Sstevel@tonic-gate 	if (phyint_init_from_k(pi) == -1) {
138*7c478bd9Sstevel@tonic-gate 		if (pi->pi_group_name != NULL)
139*7c478bd9Sstevel@tonic-gate 			free(pi->pi_group_name);
140*7c478bd9Sstevel@tonic-gate 		free(pi);
141*7c478bd9Sstevel@tonic-gate 		return (NULL);
142*7c478bd9Sstevel@tonic-gate 	}
143*7c478bd9Sstevel@tonic-gate 	phyint_insert(pi);
144*7c478bd9Sstevel@tonic-gate 	if (pi->pi_sock != -1) {
145*7c478bd9Sstevel@tonic-gate 		if (poll_add(pi->pi_sock) == -1) {
146*7c478bd9Sstevel@tonic-gate 			phyint_delete(pi);
147*7c478bd9Sstevel@tonic-gate 			return (NULL);
148*7c478bd9Sstevel@tonic-gate 		}
149*7c478bd9Sstevel@tonic-gate 	}
150*7c478bd9Sstevel@tonic-gate 	return (pi);
151*7c478bd9Sstevel@tonic-gate }
152*7c478bd9Sstevel@tonic-gate 
153*7c478bd9Sstevel@tonic-gate /* Insert in linked list */
154*7c478bd9Sstevel@tonic-gate static void
155*7c478bd9Sstevel@tonic-gate phyint_insert(struct phyint *pi)
156*7c478bd9Sstevel@tonic-gate {
157*7c478bd9Sstevel@tonic-gate 	/* Insert in list */
158*7c478bd9Sstevel@tonic-gate 	pi->pi_next = phyints;
159*7c478bd9Sstevel@tonic-gate 	pi->pi_prev = NULL;
160*7c478bd9Sstevel@tonic-gate 	if (phyints)
161*7c478bd9Sstevel@tonic-gate 		phyints->pi_prev = pi;
162*7c478bd9Sstevel@tonic-gate 	phyints = pi;
163*7c478bd9Sstevel@tonic-gate }
164*7c478bd9Sstevel@tonic-gate 
165*7c478bd9Sstevel@tonic-gate /*
166*7c478bd9Sstevel@tonic-gate  * Initialize both the phyint data structure and the pi_sock for
167*7c478bd9Sstevel@tonic-gate  * sending and receving on the interface.
168*7c478bd9Sstevel@tonic-gate  * Extract information from the kernel (if present) and set pi_kernel_state.
169*7c478bd9Sstevel@tonic-gate  */
170*7c478bd9Sstevel@tonic-gate int
171*7c478bd9Sstevel@tonic-gate phyint_init_from_k(struct phyint *pi)
172*7c478bd9Sstevel@tonic-gate {
173*7c478bd9Sstevel@tonic-gate 	struct ipv6_mreq v6mcastr;
174*7c478bd9Sstevel@tonic-gate 	struct lifreq lifr;
175*7c478bd9Sstevel@tonic-gate 	int fd;
176*7c478bd9Sstevel@tonic-gate 	boolean_t newsock;
177*7c478bd9Sstevel@tonic-gate 	uint_t ttl;
178*7c478bd9Sstevel@tonic-gate 	struct sockaddr_in6 *sin6;
179*7c478bd9Sstevel@tonic-gate 
180*7c478bd9Sstevel@tonic-gate 	if (debug & D_PHYINT)
181*7c478bd9Sstevel@tonic-gate 		logmsg(LOG_DEBUG, "phyint_init_from_k(%s)\n", pi->pi_name);
182*7c478bd9Sstevel@tonic-gate 
183*7c478bd9Sstevel@tonic-gate start_over:
184*7c478bd9Sstevel@tonic-gate 
185*7c478bd9Sstevel@tonic-gate 	if (pi->pi_sock < 0) {
186*7c478bd9Sstevel@tonic-gate 		pi->pi_sock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
187*7c478bd9Sstevel@tonic-gate 		if (pi->pi_sock < 0) {
188*7c478bd9Sstevel@tonic-gate 			logperror_pi(pi, "phyint_init_from_k: socket");
189*7c478bd9Sstevel@tonic-gate 			return (-1);
190*7c478bd9Sstevel@tonic-gate 		}
191*7c478bd9Sstevel@tonic-gate 		newsock = _B_TRUE;
192*7c478bd9Sstevel@tonic-gate 	} else {
193*7c478bd9Sstevel@tonic-gate 		newsock = _B_FALSE;
194*7c478bd9Sstevel@tonic-gate 	}
195*7c478bd9Sstevel@tonic-gate 	fd = pi->pi_sock;
196*7c478bd9Sstevel@tonic-gate 
197*7c478bd9Sstevel@tonic-gate 	(void) strncpy(lifr.lifr_name, pi->pi_name, sizeof (lifr.lifr_name));
198*7c478bd9Sstevel@tonic-gate 	lifr.lifr_name[sizeof (lifr.lifr_name) - 1] = '\0';
199*7c478bd9Sstevel@tonic-gate 	if (ioctl(fd, SIOCGLIFINDEX, (char *)&lifr) < 0) {
200*7c478bd9Sstevel@tonic-gate 		if (errno == ENXIO) {
201*7c478bd9Sstevel@tonic-gate 			if (newsock) {
202*7c478bd9Sstevel@tonic-gate 				(void) close(pi->pi_sock);
203*7c478bd9Sstevel@tonic-gate 				pi->pi_sock = -1;
204*7c478bd9Sstevel@tonic-gate 			}
205*7c478bd9Sstevel@tonic-gate 			if (debug & D_PHYINT) {
206*7c478bd9Sstevel@tonic-gate 				logmsg(LOG_DEBUG, "phyint_init_from_k(%s): "
207*7c478bd9Sstevel@tonic-gate 				    "not exist\n", pi->pi_name);
208*7c478bd9Sstevel@tonic-gate 			}
209*7c478bd9Sstevel@tonic-gate 			return (0);
210*7c478bd9Sstevel@tonic-gate 		}
211*7c478bd9Sstevel@tonic-gate 		logperror_pi(pi, "phyint_init_from_k: SIOCGLIFINDEX");
212*7c478bd9Sstevel@tonic-gate 		goto error;
213*7c478bd9Sstevel@tonic-gate 	}
214*7c478bd9Sstevel@tonic-gate 
215*7c478bd9Sstevel@tonic-gate 	if (!newsock && (pi->pi_index != lifr.lifr_index)) {
216*7c478bd9Sstevel@tonic-gate 		/*
217*7c478bd9Sstevel@tonic-gate 		 * Interface has been re-plumbed, lets open a new socket.
218*7c478bd9Sstevel@tonic-gate 		 * This situation can occur if plumb/unplumb are happening
219*7c478bd9Sstevel@tonic-gate 		 * quite frequently.
220*7c478bd9Sstevel@tonic-gate 		 */
221*7c478bd9Sstevel@tonic-gate 
222*7c478bd9Sstevel@tonic-gate 		phyint_cleanup(pi);
223*7c478bd9Sstevel@tonic-gate 		goto start_over;
224*7c478bd9Sstevel@tonic-gate 	}
225*7c478bd9Sstevel@tonic-gate 
226*7c478bd9Sstevel@tonic-gate 	pi->pi_index = lifr.lifr_index;
227*7c478bd9Sstevel@tonic-gate 
228*7c478bd9Sstevel@tonic-gate 	if (ioctl(fd, SIOCGLIFFLAGS, (char *)&lifr) < 0) {
229*7c478bd9Sstevel@tonic-gate 		logperror_pi(pi, "phyint_init_from_k: ioctl (get flags)");
230*7c478bd9Sstevel@tonic-gate 		goto error;
231*7c478bd9Sstevel@tonic-gate 	}
232*7c478bd9Sstevel@tonic-gate 	pi->pi_flags = lifr.lifr_flags;
233*7c478bd9Sstevel@tonic-gate 
234*7c478bd9Sstevel@tonic-gate 	/*
235*7c478bd9Sstevel@tonic-gate 	 * If the  link local interface is not up yet or it's IFF_UP
236*7c478bd9Sstevel@tonic-gate 	 * and the flag is set to IFF_NOLOCAL as Duplicate Address
237*7c478bd9Sstevel@tonic-gate 	 * Detection is in progress.
238*7c478bd9Sstevel@tonic-gate 	 * IFF_NOLOCAL is "normal" on other prefixes.
239*7c478bd9Sstevel@tonic-gate 	 */
240*7c478bd9Sstevel@tonic-gate 
241*7c478bd9Sstevel@tonic-gate 	if (!(pi->pi_flags & IFF_UP) || (pi->pi_flags & IFF_NOLOCAL)) {
242*7c478bd9Sstevel@tonic-gate 		if (newsock) {
243*7c478bd9Sstevel@tonic-gate 			(void) close(pi->pi_sock);
244*7c478bd9Sstevel@tonic-gate 			pi->pi_sock = -1;
245*7c478bd9Sstevel@tonic-gate 		}
246*7c478bd9Sstevel@tonic-gate 		if (debug & D_PHYINT) {
247*7c478bd9Sstevel@tonic-gate 			logmsg(LOG_DEBUG, "phyint_init_from_k(%s): "
248*7c478bd9Sstevel@tonic-gate 			    "not IFF_UP\n", pi->pi_name);
249*7c478bd9Sstevel@tonic-gate 		}
250*7c478bd9Sstevel@tonic-gate 		return (0);
251*7c478bd9Sstevel@tonic-gate 	}
252*7c478bd9Sstevel@tonic-gate 	pi->pi_kernel_state |= PI_PRESENT;
253*7c478bd9Sstevel@tonic-gate 
254*7c478bd9Sstevel@tonic-gate 	bzero(lifr.lifr_groupname, sizeof (lifr.lifr_groupname));
255*7c478bd9Sstevel@tonic-gate 	if (ioctl(fd, SIOCGLIFGROUPNAME, (caddr_t)&lifr) < 0) {
256*7c478bd9Sstevel@tonic-gate 		logperror_pi(pi, "phyint_init_from_k: ioctl (get group name)");
257*7c478bd9Sstevel@tonic-gate 		goto error;
258*7c478bd9Sstevel@tonic-gate 	}
259*7c478bd9Sstevel@tonic-gate 
260*7c478bd9Sstevel@tonic-gate 	if (lifr.lifr_groupname != NULL && strlen(lifr.lifr_groupname) != 0) {
261*7c478bd9Sstevel@tonic-gate 		if (pi->pi_group_name == NULL) {
262*7c478bd9Sstevel@tonic-gate 			pi->pi_group_name = malloc(
263*7c478bd9Sstevel@tonic-gate 			    sizeof (lifr.lifr_groupname));
264*7c478bd9Sstevel@tonic-gate 			if (pi->pi_group_name == NULL) {
265*7c478bd9Sstevel@tonic-gate 				logperror_pi(pi, "phyint_init_from_k:"
266*7c478bd9Sstevel@tonic-gate 				    " malloc(group name)");
267*7c478bd9Sstevel@tonic-gate 				goto error;
268*7c478bd9Sstevel@tonic-gate 			}
269*7c478bd9Sstevel@tonic-gate 		}
270*7c478bd9Sstevel@tonic-gate 		/*
271*7c478bd9Sstevel@tonic-gate 		 * Size of the group name can only be LIFNAMESZ -1 characters
272*7c478bd9Sstevel@tonic-gate 		 * which is ensured by kernel. Thus, we don't need strncpy.
273*7c478bd9Sstevel@tonic-gate 		 */
274*7c478bd9Sstevel@tonic-gate 		(void) strncpy(pi->pi_group_name, lifr.lifr_groupname,
275*7c478bd9Sstevel@tonic-gate 		    sizeof (lifr.lifr_name));
276*7c478bd9Sstevel@tonic-gate 		pi->pi_group_name[sizeof (pi->pi_group_name) - 1] = '\0';
277*7c478bd9Sstevel@tonic-gate 	} else if (pi->pi_group_name != NULL) {
278*7c478bd9Sstevel@tonic-gate 		free(pi->pi_group_name);
279*7c478bd9Sstevel@tonic-gate 		pi->pi_group_name = NULL;
280*7c478bd9Sstevel@tonic-gate 	}
281*7c478bd9Sstevel@tonic-gate 
282*7c478bd9Sstevel@tonic-gate 	if (ioctl(fd, SIOCGLIFMTU, (caddr_t)&lifr) < 0) {
283*7c478bd9Sstevel@tonic-gate 		logperror_pi(pi, "phyint_init_from_k: ioctl (get mtu)");
284*7c478bd9Sstevel@tonic-gate 		goto error;
285*7c478bd9Sstevel@tonic-gate 	}
286*7c478bd9Sstevel@tonic-gate 	pi->pi_mtu = lifr.lifr_mtu;
287*7c478bd9Sstevel@tonic-gate 
288*7c478bd9Sstevel@tonic-gate 	if (ioctl(fd, SIOCGLIFADDR, (char *)&lifr) < 0) {
289*7c478bd9Sstevel@tonic-gate 		logperror_pi(pi, "phyint_init_from_k: SIOCGLIFADDR");
290*7c478bd9Sstevel@tonic-gate 		goto error;
291*7c478bd9Sstevel@tonic-gate 	}
292*7c478bd9Sstevel@tonic-gate 	sin6 = (struct sockaddr_in6 *)&lifr.lifr_addr;
293*7c478bd9Sstevel@tonic-gate 	pi->pi_ifaddr = sin6->sin6_addr;
294*7c478bd9Sstevel@tonic-gate 
295*7c478bd9Sstevel@tonic-gate 	if (ioctl(fd, SIOCGLIFTOKEN, (char *)&lifr) < 0) {
296*7c478bd9Sstevel@tonic-gate 		logperror_pi(pi, "phyint_init_from_k: SIOCGLIFTOKEN");
297*7c478bd9Sstevel@tonic-gate 		goto error;
298*7c478bd9Sstevel@tonic-gate 	}
299*7c478bd9Sstevel@tonic-gate 	/* Ignore interface if the token is all zeros */
300*7c478bd9Sstevel@tonic-gate 	sin6 = (struct sockaddr_in6 *)&lifr.lifr_token;
301*7c478bd9Sstevel@tonic-gate 	if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
302*7c478bd9Sstevel@tonic-gate 		logmsg(LOG_ERR, "ignoring interface %s: zero token\n",
303*7c478bd9Sstevel@tonic-gate 		    pi->pi_name);
304*7c478bd9Sstevel@tonic-gate 		goto error;
305*7c478bd9Sstevel@tonic-gate 	}
306*7c478bd9Sstevel@tonic-gate 	pi->pi_token = sin6->sin6_addr;
307*7c478bd9Sstevel@tonic-gate 	pi->pi_token_length = lifr.lifr_addrlen;
308*7c478bd9Sstevel@tonic-gate 
309*7c478bd9Sstevel@tonic-gate 	/*
310*7c478bd9Sstevel@tonic-gate 	 * Guess a remote token for POINTOPOINT by looking at
311*7c478bd9Sstevel@tonic-gate 	 * the link-local destination address.
312*7c478bd9Sstevel@tonic-gate 	 */
313*7c478bd9Sstevel@tonic-gate 	if (pi->pi_flags & IFF_POINTOPOINT) {
314*7c478bd9Sstevel@tonic-gate 		if (ioctl(fd, SIOCGLIFDSTADDR, (char *)&lifr) < 0) {
315*7c478bd9Sstevel@tonic-gate 			logperror_pi(pi, "phyint_init_from_k: SIOCGLIFDSTADDR");
316*7c478bd9Sstevel@tonic-gate 			goto error;
317*7c478bd9Sstevel@tonic-gate 		}
318*7c478bd9Sstevel@tonic-gate 		sin6 = (struct sockaddr_in6 *)&lifr.lifr_addr;
319*7c478bd9Sstevel@tonic-gate 		if (sin6->sin6_family != AF_INET6 ||
320*7c478bd9Sstevel@tonic-gate 		    IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) ||
321*7c478bd9Sstevel@tonic-gate 		    !IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
322*7c478bd9Sstevel@tonic-gate 			pi->pi_dst_token = in6addr_any;
323*7c478bd9Sstevel@tonic-gate 		} else {
324*7c478bd9Sstevel@tonic-gate 			pi->pi_dst_token = sin6->sin6_addr;
325*7c478bd9Sstevel@tonic-gate 			/* Clear link-local prefix (first 10 bits) */
326*7c478bd9Sstevel@tonic-gate 			pi->pi_dst_token.s6_addr[0] = 0;
327*7c478bd9Sstevel@tonic-gate 			pi->pi_dst_token.s6_addr[1] &= 0x3f;
328*7c478bd9Sstevel@tonic-gate 		}
329*7c478bd9Sstevel@tonic-gate 	} else {
330*7c478bd9Sstevel@tonic-gate 		pi->pi_dst_token = in6addr_any;
331*7c478bd9Sstevel@tonic-gate 	}
332*7c478bd9Sstevel@tonic-gate 
333*7c478bd9Sstevel@tonic-gate 	/* Get link-layer address */
334*7c478bd9Sstevel@tonic-gate 	if (!(pi->pi_flags & IFF_MULTICAST) ||
335*7c478bd9Sstevel@tonic-gate 	    (pi->pi_flags & IFF_POINTOPOINT)) {
336*7c478bd9Sstevel@tonic-gate 		pi->pi_hdw_addr_len = 0;
337*7c478bd9Sstevel@tonic-gate 	} else {
338*7c478bd9Sstevel@tonic-gate 		sin6 = (struct sockaddr_in6 *)&lifr.lifr_nd.lnr_addr;
339*7c478bd9Sstevel@tonic-gate 		bzero(sin6, sizeof (struct sockaddr_in6));
340*7c478bd9Sstevel@tonic-gate 		sin6->sin6_family = AF_INET6;
341*7c478bd9Sstevel@tonic-gate 		sin6->sin6_addr = pi->pi_ifaddr;
342*7c478bd9Sstevel@tonic-gate 
343*7c478bd9Sstevel@tonic-gate 		if (ioctl(fd, SIOCLIFGETND, (char *)&lifr) < 0) {
344*7c478bd9Sstevel@tonic-gate 			logperror_pi(pi, "phyint_init_from_k: SIOCLIFGETND");
345*7c478bd9Sstevel@tonic-gate 			goto error;
346*7c478bd9Sstevel@tonic-gate 		}
347*7c478bd9Sstevel@tonic-gate 
348*7c478bd9Sstevel@tonic-gate 		pi->pi_hdw_addr_len = lifr.lifr_nd.lnr_hdw_len;
349*7c478bd9Sstevel@tonic-gate 
350*7c478bd9Sstevel@tonic-gate 		if (lifr.lifr_nd.lnr_hdw_len != 0) {
351*7c478bd9Sstevel@tonic-gate 			bcopy((char *)lifr.lifr_nd.lnr_hdw_addr,
352*7c478bd9Sstevel@tonic-gate 			    (char *)pi->pi_hdw_addr,
353*7c478bd9Sstevel@tonic-gate 			    lifr.lifr_nd.lnr_hdw_len);
354*7c478bd9Sstevel@tonic-gate 		}
355*7c478bd9Sstevel@tonic-gate 	}
356*7c478bd9Sstevel@tonic-gate 
357*7c478bd9Sstevel@tonic-gate 	if (newsock) {
358*7c478bd9Sstevel@tonic-gate 		icmp6_filter_t filter;
359*7c478bd9Sstevel@tonic-gate 		int on = 1;
360*7c478bd9Sstevel@tonic-gate 
361*7c478bd9Sstevel@tonic-gate 		/* Set default values */
362*7c478bd9Sstevel@tonic-gate 		pi->pi_LinkMTU = pi->pi_mtu;
363*7c478bd9Sstevel@tonic-gate 		pi->pi_CurHopLimit = 0;
364*7c478bd9Sstevel@tonic-gate 		pi->pi_BaseReachableTime = ND_REACHABLE_TIME;
365*7c478bd9Sstevel@tonic-gate 		phyint_reach_random(pi, _B_FALSE);
366*7c478bd9Sstevel@tonic-gate 		pi->pi_RetransTimer = ND_RETRANS_TIMER;
367*7c478bd9Sstevel@tonic-gate 
368*7c478bd9Sstevel@tonic-gate 		/* Setup socket for transmission and reception */
369*7c478bd9Sstevel@tonic-gate 		if (setsockopt(fd, IPPROTO_IPV6,
370*7c478bd9Sstevel@tonic-gate 		    IPV6_BOUND_IF, (char *)&pi->pi_index,
371*7c478bd9Sstevel@tonic-gate 		    sizeof (pi->pi_index)) < 0) {
372*7c478bd9Sstevel@tonic-gate 			logperror_pi(pi, "phyint_init_from_k: setsockopt "
373*7c478bd9Sstevel@tonic-gate 			    "IPV6_BOUND_IF");
374*7c478bd9Sstevel@tonic-gate 			goto error;
375*7c478bd9Sstevel@tonic-gate 		}
376*7c478bd9Sstevel@tonic-gate 
377*7c478bd9Sstevel@tonic-gate 		ttl = IPV6_MAX_HOPS;
378*7c478bd9Sstevel@tonic-gate 		if (setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS,
379*7c478bd9Sstevel@tonic-gate 		    (char *)&ttl, sizeof (ttl)) < 0) {
380*7c478bd9Sstevel@tonic-gate 			logperror_pi(pi, "phyint_init_from_k: setsockopt "
381*7c478bd9Sstevel@tonic-gate 			    "IPV6_UNICAST_HOPS");
382*7c478bd9Sstevel@tonic-gate 			goto error;
383*7c478bd9Sstevel@tonic-gate 		}
384*7c478bd9Sstevel@tonic-gate 
385*7c478bd9Sstevel@tonic-gate 		if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
386*7c478bd9Sstevel@tonic-gate 		    (char *)&ttl, sizeof (ttl)) < 0) {
387*7c478bd9Sstevel@tonic-gate 			logperror_pi(pi, "phyint_init_from_k: setsockopt "
388*7c478bd9Sstevel@tonic-gate 			    "IPV6_MULTICAST_HOPS");
389*7c478bd9Sstevel@tonic-gate 			goto error;
390*7c478bd9Sstevel@tonic-gate 		}
391*7c478bd9Sstevel@tonic-gate 
392*7c478bd9Sstevel@tonic-gate 		v6mcastr.ipv6mr_multiaddr = all_nodes_mcast;
393*7c478bd9Sstevel@tonic-gate 		v6mcastr.ipv6mr_interface = pi->pi_index;
394*7c478bd9Sstevel@tonic-gate 		if (setsockopt(fd, IPPROTO_IPV6, IPV6_JOIN_GROUP,
395*7c478bd9Sstevel@tonic-gate 		    (char *)&v6mcastr, sizeof (v6mcastr)) < 0) {
396*7c478bd9Sstevel@tonic-gate 			logperror_pi(pi, "phyint_init_from_k: "
397*7c478bd9Sstevel@tonic-gate 			    "setsockopt IPV6_JOIN_GROUP");
398*7c478bd9Sstevel@tonic-gate 			goto error;
399*7c478bd9Sstevel@tonic-gate 		}
400*7c478bd9Sstevel@tonic-gate 		pi->pi_state |= PI_JOINED_ALLNODES;
401*7c478bd9Sstevel@tonic-gate 		pi->pi_kernel_state |= PI_JOINED_ALLNODES;
402*7c478bd9Sstevel@tonic-gate 
403*7c478bd9Sstevel@tonic-gate 		/*
404*7c478bd9Sstevel@tonic-gate 		 * Filter out so that we only receive router advertisements and
405*7c478bd9Sstevel@tonic-gate 		 * router solicitations.
406*7c478bd9Sstevel@tonic-gate 		 */
407*7c478bd9Sstevel@tonic-gate 		ICMP6_FILTER_SETBLOCKALL(&filter);
408*7c478bd9Sstevel@tonic-gate 		ICMP6_FILTER_SETPASS(ND_ROUTER_SOLICIT, &filter);
409*7c478bd9Sstevel@tonic-gate 		ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT, &filter);
410*7c478bd9Sstevel@tonic-gate 
411*7c478bd9Sstevel@tonic-gate 		if (setsockopt(fd, IPPROTO_ICMPV6, ICMP6_FILTER,
412*7c478bd9Sstevel@tonic-gate 		    (char *)&filter, sizeof (filter)) < 0) {
413*7c478bd9Sstevel@tonic-gate 			logperror_pi(pi, "phyint_init_from_k: setsockopt "
414*7c478bd9Sstevel@tonic-gate 			    "ICMP6_FILTER");
415*7c478bd9Sstevel@tonic-gate 			goto error;
416*7c478bd9Sstevel@tonic-gate 		}
417*7c478bd9Sstevel@tonic-gate 
418*7c478bd9Sstevel@tonic-gate 		/* Enable receipt of ancillary data */
419*7c478bd9Sstevel@tonic-gate 		if (setsockopt(fd, IPPROTO_IPV6, IPV6_RECVHOPLIMIT,
420*7c478bd9Sstevel@tonic-gate 		    (char *)&on, sizeof (on)) < 0) {
421*7c478bd9Sstevel@tonic-gate 			logperror_pi(pi, "phyint_init_from_k: setsockopt "
422*7c478bd9Sstevel@tonic-gate 			    "IPV6_RECVHOPLIMIT");
423*7c478bd9Sstevel@tonic-gate 			goto error;
424*7c478bd9Sstevel@tonic-gate 		}
425*7c478bd9Sstevel@tonic-gate 		if (setsockopt(fd, IPPROTO_IPV6, IPV6_RECVRTHDR,
426*7c478bd9Sstevel@tonic-gate 		    (char *)&on, sizeof (on)) < 0) {
427*7c478bd9Sstevel@tonic-gate 			logperror_pi(pi, "phyint_init_from_k: setsockopt "
428*7c478bd9Sstevel@tonic-gate 			    "IPV6_RECVRTHDR");
429*7c478bd9Sstevel@tonic-gate 			goto error;
430*7c478bd9Sstevel@tonic-gate 		}
431*7c478bd9Sstevel@tonic-gate 	}
432*7c478bd9Sstevel@tonic-gate 
433*7c478bd9Sstevel@tonic-gate 	if (pi->pi_AdvSendAdvertisements &&
434*7c478bd9Sstevel@tonic-gate 	    !(pi->pi_kernel_state & PI_JOINED_ALLROUTERS)) {
435*7c478bd9Sstevel@tonic-gate 		v6mcastr.ipv6mr_multiaddr = all_routers_mcast;
436*7c478bd9Sstevel@tonic-gate 		v6mcastr.ipv6mr_interface = pi->pi_index;
437*7c478bd9Sstevel@tonic-gate 		if (setsockopt(fd, IPPROTO_IPV6, IPV6_JOIN_GROUP,
438*7c478bd9Sstevel@tonic-gate 		    (char *)&v6mcastr, sizeof (v6mcastr)) < 0) {
439*7c478bd9Sstevel@tonic-gate 			logperror_pi(pi, "phyint_init_from_k: setsockopt "
440*7c478bd9Sstevel@tonic-gate 			    "IPV6_JOIN_GROUP");
441*7c478bd9Sstevel@tonic-gate 			goto error;
442*7c478bd9Sstevel@tonic-gate 		}
443*7c478bd9Sstevel@tonic-gate 		pi->pi_state |= PI_JOINED_ALLROUTERS;
444*7c478bd9Sstevel@tonic-gate 		pi->pi_kernel_state |= PI_JOINED_ALLROUTERS;
445*7c478bd9Sstevel@tonic-gate 	}
446*7c478bd9Sstevel@tonic-gate 	/*
447*7c478bd9Sstevel@tonic-gate 	 * If not already set, set the IFF_ROUTER interface flag based on
448*7c478bd9Sstevel@tonic-gate 	 * AdvSendAdvertisements.  Note that this will also enable IPv6
449*7c478bd9Sstevel@tonic-gate 	 * forwarding on the interface.  We don't clear IFF_ROUTER if we're
450*7c478bd9Sstevel@tonic-gate 	 * not advertising on an interface, because we could still be
451*7c478bd9Sstevel@tonic-gate 	 * forwarding on those interfaces.
452*7c478bd9Sstevel@tonic-gate 	 */
453*7c478bd9Sstevel@tonic-gate 	(void) strncpy(lifr.lifr_name, pi->pi_name, sizeof (lifr.lifr_name));
454*7c478bd9Sstevel@tonic-gate 	lifr.lifr_name[sizeof (lifr.lifr_name) - 1] = '\0';
455*7c478bd9Sstevel@tonic-gate 	if (ioctl(fd, SIOCGLIFFLAGS, (char *)&lifr) < 0) {
456*7c478bd9Sstevel@tonic-gate 		logperror_pi(pi, "phyint_init_from_k: SIOCGLIFFLAGS");
457*7c478bd9Sstevel@tonic-gate 		goto error;
458*7c478bd9Sstevel@tonic-gate 	}
459*7c478bd9Sstevel@tonic-gate 	if (!(lifr.lifr_flags & IFF_ROUTER) && pi->pi_AdvSendAdvertisements) {
460*7c478bd9Sstevel@tonic-gate 		lifr.lifr_flags |= IFF_ROUTER;
461*7c478bd9Sstevel@tonic-gate 
462*7c478bd9Sstevel@tonic-gate 		if (ioctl(fd, SIOCSLIFFLAGS, (char *)&lifr) < 0) {
463*7c478bd9Sstevel@tonic-gate 			logperror_pi(pi, "phyint_init_from_k: SIOCSLIFFLAGS");
464*7c478bd9Sstevel@tonic-gate 			goto error;
465*7c478bd9Sstevel@tonic-gate 		}
466*7c478bd9Sstevel@tonic-gate 		pi->pi_flags = lifr.lifr_flags;
467*7c478bd9Sstevel@tonic-gate 	}
468*7c478bd9Sstevel@tonic-gate 
469*7c478bd9Sstevel@tonic-gate 	/* Set linkinfo parameters */
470*7c478bd9Sstevel@tonic-gate 	(void) strncpy(lifr.lifr_name, pi->pi_name, sizeof (lifr.lifr_name));
471*7c478bd9Sstevel@tonic-gate 	lifr.lifr_name[sizeof (lifr.lifr_name) - 1] = '\0';
472*7c478bd9Sstevel@tonic-gate 	if (ioctl(fd, SIOCGLIFLNKINFO, (char *)&lifr) < 0) {
473*7c478bd9Sstevel@tonic-gate 		logperror_pi(pi, "phyint_init_from_k: SIOCGLIFLNKINFO");
474*7c478bd9Sstevel@tonic-gate 		goto error;
475*7c478bd9Sstevel@tonic-gate 	}
476*7c478bd9Sstevel@tonic-gate 	lifr.lifr_ifinfo.lir_maxhops = pi->pi_CurHopLimit;
477*7c478bd9Sstevel@tonic-gate 	lifr.lifr_ifinfo.lir_reachtime = pi->pi_ReachableTime;
478*7c478bd9Sstevel@tonic-gate 	lifr.lifr_ifinfo.lir_reachretrans = pi->pi_RetransTimer;
479*7c478bd9Sstevel@tonic-gate 	if (ioctl(fd, SIOCSLIFLNKINFO, (char *)&lifr) < 0) {
480*7c478bd9Sstevel@tonic-gate 		logperror_pi(pi, "phyint_init_from_k: SIOCSLIFLNKINFO");
481*7c478bd9Sstevel@tonic-gate 		goto error;
482*7c478bd9Sstevel@tonic-gate 	}
483*7c478bd9Sstevel@tonic-gate 	if (debug & D_PHYINT) {
484*7c478bd9Sstevel@tonic-gate 		logmsg(LOG_DEBUG, "phyint_init_from_k(%s): done\n",
485*7c478bd9Sstevel@tonic-gate 		    pi->pi_name);
486*7c478bd9Sstevel@tonic-gate 	}
487*7c478bd9Sstevel@tonic-gate 	return (0);
488*7c478bd9Sstevel@tonic-gate 
489*7c478bd9Sstevel@tonic-gate error:
490*7c478bd9Sstevel@tonic-gate 	/* Pretend the interface does not exist in the kernel */
491*7c478bd9Sstevel@tonic-gate 	pi->pi_kernel_state &= ~PI_PRESENT;
492*7c478bd9Sstevel@tonic-gate 	if (newsock) {
493*7c478bd9Sstevel@tonic-gate 		(void) close(pi->pi_sock);
494*7c478bd9Sstevel@tonic-gate 		pi->pi_sock = -1;
495*7c478bd9Sstevel@tonic-gate 	}
496*7c478bd9Sstevel@tonic-gate 	return (-1);
497*7c478bd9Sstevel@tonic-gate }
498*7c478bd9Sstevel@tonic-gate 
499*7c478bd9Sstevel@tonic-gate /*
500*7c478bd9Sstevel@tonic-gate  * Delete (unlink and free).
501*7c478bd9Sstevel@tonic-gate  * Handles delete of things that have not yet been inserted in the list.
502*7c478bd9Sstevel@tonic-gate  */
503*7c478bd9Sstevel@tonic-gate void
504*7c478bd9Sstevel@tonic-gate phyint_delete(struct phyint *pi)
505*7c478bd9Sstevel@tonic-gate {
506*7c478bd9Sstevel@tonic-gate 	if (debug & D_PHYINT)
507*7c478bd9Sstevel@tonic-gate 		logmsg(LOG_DEBUG, "phyint_delete(%s)\n", pi->pi_name);
508*7c478bd9Sstevel@tonic-gate 
509*7c478bd9Sstevel@tonic-gate 	while (pi->pi_router_list)
510*7c478bd9Sstevel@tonic-gate 		router_delete(pi->pi_router_list);
511*7c478bd9Sstevel@tonic-gate 	while (pi->pi_prefix_list)
512*7c478bd9Sstevel@tonic-gate 		prefix_delete(pi->pi_prefix_list);
513*7c478bd9Sstevel@tonic-gate 	while (pi->pi_adv_prefix_list)
514*7c478bd9Sstevel@tonic-gate 		adv_prefix_delete(pi->pi_adv_prefix_list);
515*7c478bd9Sstevel@tonic-gate 
516*7c478bd9Sstevel@tonic-gate 	if (pi->pi_sock != -1) {
517*7c478bd9Sstevel@tonic-gate 		(void) poll_remove(pi->pi_sock);
518*7c478bd9Sstevel@tonic-gate 		if (close(pi->pi_sock) < 0) {
519*7c478bd9Sstevel@tonic-gate 			logperror_pi(pi, "phyint_delete: close");
520*7c478bd9Sstevel@tonic-gate 		}
521*7c478bd9Sstevel@tonic-gate 		pi->pi_sock = -1;
522*7c478bd9Sstevel@tonic-gate 	}
523*7c478bd9Sstevel@tonic-gate 
524*7c478bd9Sstevel@tonic-gate 	if (pi->pi_prev == NULL) {
525*7c478bd9Sstevel@tonic-gate 		if (phyints == pi)
526*7c478bd9Sstevel@tonic-gate 			phyints = pi->pi_next;
527*7c478bd9Sstevel@tonic-gate 	} else {
528*7c478bd9Sstevel@tonic-gate 		pi->pi_prev->pi_next = pi->pi_next;
529*7c478bd9Sstevel@tonic-gate 	}
530*7c478bd9Sstevel@tonic-gate 	if (pi->pi_next != NULL)
531*7c478bd9Sstevel@tonic-gate 		pi->pi_next->pi_prev = pi->pi_prev;
532*7c478bd9Sstevel@tonic-gate 	pi->pi_next = pi->pi_prev = NULL;
533*7c478bd9Sstevel@tonic-gate 	if (pi->pi_group_name != NULL)
534*7c478bd9Sstevel@tonic-gate 		free(pi->pi_group_name);
535*7c478bd9Sstevel@tonic-gate 	free(pi);
536*7c478bd9Sstevel@tonic-gate }
537*7c478bd9Sstevel@tonic-gate 
538*7c478bd9Sstevel@tonic-gate /*
539*7c478bd9Sstevel@tonic-gate  * Called with the number of millseconds elapsed since the last call.
540*7c478bd9Sstevel@tonic-gate  * Determines if any timeout event has occurred and
541*7c478bd9Sstevel@tonic-gate  * returns the number of milliseconds until the next timeout event
542*7c478bd9Sstevel@tonic-gate  * for the phyint iself (excluding prefixes and routers).
543*7c478bd9Sstevel@tonic-gate  * Returns TIMER_INFINITY for "never".
544*7c478bd9Sstevel@tonic-gate  */
545*7c478bd9Sstevel@tonic-gate uint_t
546*7c478bd9Sstevel@tonic-gate phyint_timer(struct phyint *pi, uint_t elapsed)
547*7c478bd9Sstevel@tonic-gate {
548*7c478bd9Sstevel@tonic-gate 	uint_t next = TIMER_INFINITY;
549*7c478bd9Sstevel@tonic-gate 
550*7c478bd9Sstevel@tonic-gate 	if (pi->pi_AdvSendAdvertisements) {
551*7c478bd9Sstevel@tonic-gate 		if (pi->pi_adv_state != NO_ADV) {
552*7c478bd9Sstevel@tonic-gate 			int old_state = pi->pi_adv_state;
553*7c478bd9Sstevel@tonic-gate 
554*7c478bd9Sstevel@tonic-gate 			if (debug & (D_STATE|D_PHYINT)) {
555*7c478bd9Sstevel@tonic-gate 				logmsg(LOG_DEBUG, "phyint_timer ADV(%s) "
556*7c478bd9Sstevel@tonic-gate 				    "state %d\n", pi->pi_name, (int)old_state);
557*7c478bd9Sstevel@tonic-gate 			}
558*7c478bd9Sstevel@tonic-gate 			next = advertise_event(pi, ADV_TIMER, elapsed);
559*7c478bd9Sstevel@tonic-gate 			if (debug & D_STATE) {
560*7c478bd9Sstevel@tonic-gate 				logmsg(LOG_DEBUG, "phyint_timer ADV(%s) "
561*7c478bd9Sstevel@tonic-gate 				    "state %d -> %d\n",
562*7c478bd9Sstevel@tonic-gate 				    pi->pi_name, (int)old_state,
563*7c478bd9Sstevel@tonic-gate 				    (int)pi->pi_adv_state);
564*7c478bd9Sstevel@tonic-gate 			}
565*7c478bd9Sstevel@tonic-gate 		}
566*7c478bd9Sstevel@tonic-gate 	} else {
567*7c478bd9Sstevel@tonic-gate 		if (pi->pi_sol_state != NO_SOLICIT) {
568*7c478bd9Sstevel@tonic-gate 			int old_state = pi->pi_sol_state;
569*7c478bd9Sstevel@tonic-gate 
570*7c478bd9Sstevel@tonic-gate 			if (debug & (D_STATE|D_PHYINT)) {
571*7c478bd9Sstevel@tonic-gate 				logmsg(LOG_DEBUG, "phyint_timer SOL(%s) "
572*7c478bd9Sstevel@tonic-gate 				    "state %d\n", pi->pi_name, (int)old_state);
573*7c478bd9Sstevel@tonic-gate 			}
574*7c478bd9Sstevel@tonic-gate 			next = solicit_event(pi, SOL_TIMER, elapsed);
575*7c478bd9Sstevel@tonic-gate 			if (debug & D_STATE) {
576*7c478bd9Sstevel@tonic-gate 				logmsg(LOG_DEBUG, "phyint_timer SOL(%s) "
577*7c478bd9Sstevel@tonic-gate 				    "state %d -> %d\n",
578*7c478bd9Sstevel@tonic-gate 				    pi->pi_name, (int)old_state,
579*7c478bd9Sstevel@tonic-gate 				    (int)pi->pi_sol_state);
580*7c478bd9Sstevel@tonic-gate 			}
581*7c478bd9Sstevel@tonic-gate 		}
582*7c478bd9Sstevel@tonic-gate 	}
583*7c478bd9Sstevel@tonic-gate 
584*7c478bd9Sstevel@tonic-gate 	/*
585*7c478bd9Sstevel@tonic-gate 	 * If the phyint has been unplumbed, we don't want to call
586*7c478bd9Sstevel@tonic-gate 	 * phyint_reach_random. We will be in the NO_ADV or NO_SOLICIT state.
587*7c478bd9Sstevel@tonic-gate 	 */
588*7c478bd9Sstevel@tonic-gate 	if ((pi->pi_AdvSendAdvertisements && (pi->pi_adv_state != NO_ADV)) ||
589*7c478bd9Sstevel@tonic-gate 	    (!pi->pi_AdvSendAdvertisements &&
590*7c478bd9Sstevel@tonic-gate 	    (pi->pi_sol_state != NO_SOLICIT))) {
591*7c478bd9Sstevel@tonic-gate 		pi->pi_reach_time_since_random += elapsed;
592*7c478bd9Sstevel@tonic-gate 		if (pi->pi_reach_time_since_random >= MAX_REACH_RANDOM_INTERVAL)
593*7c478bd9Sstevel@tonic-gate 			phyint_reach_random(pi, _B_TRUE);
594*7c478bd9Sstevel@tonic-gate 	}
595*7c478bd9Sstevel@tonic-gate 
596*7c478bd9Sstevel@tonic-gate 	return (next);
597*7c478bd9Sstevel@tonic-gate }
598*7c478bd9Sstevel@tonic-gate 
599*7c478bd9Sstevel@tonic-gate static void
600*7c478bd9Sstevel@tonic-gate phyint_print(struct phyint *pi)
601*7c478bd9Sstevel@tonic-gate {
602*7c478bd9Sstevel@tonic-gate 	struct prefix *pr;
603*7c478bd9Sstevel@tonic-gate 	struct adv_prefix *adv_pr;
604*7c478bd9Sstevel@tonic-gate 	struct router *dr;
605*7c478bd9Sstevel@tonic-gate 	char abuf[INET6_ADDRSTRLEN];
606*7c478bd9Sstevel@tonic-gate 	char llabuf[BUFSIZ];
607*7c478bd9Sstevel@tonic-gate 
608*7c478bd9Sstevel@tonic-gate 	logmsg(LOG_DEBUG, "Phyint %s index %d state %x, kernel %x, "
609*7c478bd9Sstevel@tonic-gate 	    "onlink_def %d num routers %d\n",
610*7c478bd9Sstevel@tonic-gate 	    pi->pi_name, pi->pi_index,
611*7c478bd9Sstevel@tonic-gate 	    pi->pi_state, pi->pi_kernel_state,
612*7c478bd9Sstevel@tonic-gate 	    pi->pi_onlink_default ? 1 : 0,
613*7c478bd9Sstevel@tonic-gate 	    pi->pi_num_k_routers);
614*7c478bd9Sstevel@tonic-gate 	logmsg(LOG_DEBUG, "\taddress: %s flags %x\n",
615*7c478bd9Sstevel@tonic-gate 	    inet_ntop(AF_INET6, (void *)&pi->pi_ifaddr,
616*7c478bd9Sstevel@tonic-gate 	    abuf, sizeof (abuf)), pi->pi_flags);
617*7c478bd9Sstevel@tonic-gate 	logmsg(LOG_DEBUG, "\tsock %d mtu %d hdw_addr len %d <%s>\n",
618*7c478bd9Sstevel@tonic-gate 	    pi->pi_sock, pi->pi_mtu, pi->pi_hdw_addr_len,
619*7c478bd9Sstevel@tonic-gate 	    ((pi->pi_hdw_addr_len != 0) ?
620*7c478bd9Sstevel@tonic-gate 	    fmt_lla(llabuf, sizeof (llabuf), pi->pi_hdw_addr,
621*7c478bd9Sstevel@tonic-gate 	    pi->pi_hdw_addr_len) : "none"));
622*7c478bd9Sstevel@tonic-gate 	logmsg(LOG_DEBUG, "\ttoken: len %d %s\n",
623*7c478bd9Sstevel@tonic-gate 	    pi->pi_token_length,
624*7c478bd9Sstevel@tonic-gate 	    inet_ntop(AF_INET6, (void *)&pi->pi_token,
625*7c478bd9Sstevel@tonic-gate 	    abuf, sizeof (abuf)));
626*7c478bd9Sstevel@tonic-gate 	if (pi->pi_TmpAddrsEnabled) {
627*7c478bd9Sstevel@tonic-gate 		logmsg(LOG_DEBUG, "\ttmp_token: %s\n",
628*7c478bd9Sstevel@tonic-gate 		    inet_ntop(AF_INET6, (void *)&pi->pi_tmp_token,
629*7c478bd9Sstevel@tonic-gate 			abuf, sizeof (abuf)));
630*7c478bd9Sstevel@tonic-gate 		logmsg(LOG_DEBUG, "\ttmp config: pref %d valid %d "
631*7c478bd9Sstevel@tonic-gate 		    "maxdesync %d desync %d regen %d\n",
632*7c478bd9Sstevel@tonic-gate 		    pi->pi_TmpPreferredLifetime, pi->pi_TmpValidLifetime,
633*7c478bd9Sstevel@tonic-gate 		    pi->pi_TmpMaxDesyncFactor, pi->pi_TmpDesyncFactor,
634*7c478bd9Sstevel@tonic-gate 		    pi->pi_TmpRegenAdvance);
635*7c478bd9Sstevel@tonic-gate 	}
636*7c478bd9Sstevel@tonic-gate 	if (pi->pi_flags & IFF_POINTOPOINT) {
637*7c478bd9Sstevel@tonic-gate 		logmsg(LOG_DEBUG, "\tdst_token: %s\n",
638*7c478bd9Sstevel@tonic-gate 		    inet_ntop(AF_INET6, (void *)&pi->pi_dst_token,
639*7c478bd9Sstevel@tonic-gate 			abuf, sizeof (abuf)));
640*7c478bd9Sstevel@tonic-gate 	}
641*7c478bd9Sstevel@tonic-gate 	logmsg(LOG_DEBUG, "\tLinkMTU %d CurHopLimit %d "
642*7c478bd9Sstevel@tonic-gate 	    "BaseReachableTime %d\n\tReachableTime %d RetransTimer %d\n",
643*7c478bd9Sstevel@tonic-gate 	    pi->pi_LinkMTU, pi->pi_CurHopLimit, pi->pi_BaseReachableTime,
644*7c478bd9Sstevel@tonic-gate 	    pi->pi_ReachableTime, pi->pi_RetransTimer);
645*7c478bd9Sstevel@tonic-gate 	if (!pi->pi_AdvSendAdvertisements) {
646*7c478bd9Sstevel@tonic-gate 		/* Solicit state */
647*7c478bd9Sstevel@tonic-gate 		logmsg(LOG_DEBUG, "\tSOLICIT: time_left %d state %d count %d\n",
648*7c478bd9Sstevel@tonic-gate 		    pi->pi_sol_time_left, pi->pi_sol_state, pi->pi_sol_count);
649*7c478bd9Sstevel@tonic-gate 	} else {
650*7c478bd9Sstevel@tonic-gate 		/* Advertise state */
651*7c478bd9Sstevel@tonic-gate 		logmsg(LOG_DEBUG, "\tADVERT: time_left %d state %d count %d "
652*7c478bd9Sstevel@tonic-gate 		    "since last %d\n",
653*7c478bd9Sstevel@tonic-gate 		    pi->pi_adv_time_left, pi->pi_adv_state, pi->pi_adv_count,
654*7c478bd9Sstevel@tonic-gate 		    pi->pi_adv_time_since_sent);
655*7c478bd9Sstevel@tonic-gate 		print_iflist(pi->pi_config);
656*7c478bd9Sstevel@tonic-gate 	}
657*7c478bd9Sstevel@tonic-gate 	for (pr = pi->pi_prefix_list; pr != NULL; pr = pr->pr_next)
658*7c478bd9Sstevel@tonic-gate 		prefix_print(pr);
659*7c478bd9Sstevel@tonic-gate 
660*7c478bd9Sstevel@tonic-gate 	for (adv_pr = pi->pi_adv_prefix_list; adv_pr != NULL;
661*7c478bd9Sstevel@tonic-gate 	    adv_pr = adv_pr->adv_pr_next) {
662*7c478bd9Sstevel@tonic-gate 		adv_prefix_print(adv_pr);
663*7c478bd9Sstevel@tonic-gate 	}
664*7c478bd9Sstevel@tonic-gate 
665*7c478bd9Sstevel@tonic-gate 	for (dr = pi->pi_router_list; dr != NULL; dr = dr->dr_next)
666*7c478bd9Sstevel@tonic-gate 		router_print(dr);
667*7c478bd9Sstevel@tonic-gate 
668*7c478bd9Sstevel@tonic-gate 	logmsg(LOG_DEBUG, "\n");
669*7c478bd9Sstevel@tonic-gate }
670*7c478bd9Sstevel@tonic-gate 
671*7c478bd9Sstevel@tonic-gate /*
672*7c478bd9Sstevel@tonic-gate  * Randomize pi->pi_ReachableTime.
673*7c478bd9Sstevel@tonic-gate  * Done periodically when there are no RAs and at a maximum frequency when
674*7c478bd9Sstevel@tonic-gate  * RA's arrive.
675*7c478bd9Sstevel@tonic-gate  * Assumes that caller has determined that it is time to generate
676*7c478bd9Sstevel@tonic-gate  * a new random ReachableTime.
677*7c478bd9Sstevel@tonic-gate  */
678*7c478bd9Sstevel@tonic-gate void
679*7c478bd9Sstevel@tonic-gate phyint_reach_random(struct phyint *pi, boolean_t set_needed)
680*7c478bd9Sstevel@tonic-gate {
681*7c478bd9Sstevel@tonic-gate 	pi->pi_ReachableTime = GET_RANDOM(
682*7c478bd9Sstevel@tonic-gate 	    (int)(ND_MIN_RANDOM_FACTOR * pi->pi_BaseReachableTime),
683*7c478bd9Sstevel@tonic-gate 	    (int)(ND_MAX_RANDOM_FACTOR * pi->pi_BaseReachableTime));
684*7c478bd9Sstevel@tonic-gate 	if (set_needed) {
685*7c478bd9Sstevel@tonic-gate 		struct lifreq lifr;
686*7c478bd9Sstevel@tonic-gate 
687*7c478bd9Sstevel@tonic-gate 		(void) strncpy(lifr.lifr_name, pi->pi_name,
688*7c478bd9Sstevel@tonic-gate 		    sizeof (lifr.lifr_name));
689*7c478bd9Sstevel@tonic-gate 		pi->pi_name[sizeof (pi->pi_name) - 1] = '\0';
690*7c478bd9Sstevel@tonic-gate 		if (ioctl(pi->pi_sock, SIOCGLIFLNKINFO, (char *)&lifr) < 0) {
691*7c478bd9Sstevel@tonic-gate 			logperror_pi(pi,
692*7c478bd9Sstevel@tonic-gate 			    "phyint_reach_random: SIOCGLIFLNKINFO");
693*7c478bd9Sstevel@tonic-gate 			return;
694*7c478bd9Sstevel@tonic-gate 		}
695*7c478bd9Sstevel@tonic-gate 		lifr.lifr_ifinfo.lir_reachtime = pi->pi_ReachableTime;
696*7c478bd9Sstevel@tonic-gate 		if (ioctl(pi->pi_sock, SIOCSLIFLNKINFO, (char *)&lifr) < 0) {
697*7c478bd9Sstevel@tonic-gate 			logperror_pi(pi,
698*7c478bd9Sstevel@tonic-gate 			    "phyint_reach_random: SIOCSLIFLNKINFO");
699*7c478bd9Sstevel@tonic-gate 			return;
700*7c478bd9Sstevel@tonic-gate 		}
701*7c478bd9Sstevel@tonic-gate 	}
702*7c478bd9Sstevel@tonic-gate 	pi->pi_reach_time_since_random = 0;
703*7c478bd9Sstevel@tonic-gate }
704*7c478bd9Sstevel@tonic-gate 
705*7c478bd9Sstevel@tonic-gate /*
706*7c478bd9Sstevel@tonic-gate  * Validate a temporary token against a list of known bad values.
707*7c478bd9Sstevel@tonic-gate  * Currently assumes that token is 8 bytes long!  Current known
708*7c478bd9Sstevel@tonic-gate  * bad values include 0, reserved anycast tokens (RFC 2526), tokens
709*7c478bd9Sstevel@tonic-gate  * used by ISATAP (draft-ietf-ngtrans-isatap-N), any token already
710*7c478bd9Sstevel@tonic-gate  * assigned to this interface, or any token for which the global
711*7c478bd9Sstevel@tonic-gate  * bit is set.
712*7c478bd9Sstevel@tonic-gate  *
713*7c478bd9Sstevel@tonic-gate  * Called by tmptoken_create().
714*7c478bd9Sstevel@tonic-gate  *
715*7c478bd9Sstevel@tonic-gate  * Return _B_TRUE if token is valid (no match), _B_FALSE if not.
716*7c478bd9Sstevel@tonic-gate  */
717*7c478bd9Sstevel@tonic-gate static boolean_t
718*7c478bd9Sstevel@tonic-gate tmptoken_isvalid(struct in6_addr *token)
719*7c478bd9Sstevel@tonic-gate {
720*7c478bd9Sstevel@tonic-gate 	struct phyint *pi;
721*7c478bd9Sstevel@tonic-gate 	struct in6_addr mask;
722*7c478bd9Sstevel@tonic-gate 	struct in6_addr isatap = { 0, 0, 0, 0, 0, 0, 0, 0, \
723*7c478bd9Sstevel@tonic-gate 				    0, 0, 0x5e, 0xfe, 0, 0, 0, 0 };
724*7c478bd9Sstevel@tonic-gate 	struct in6_addr anycast = { 0, 0, 0, 0, \
725*7c478bd9Sstevel@tonic-gate 				    0, 0, 0, 0, \
726*7c478bd9Sstevel@tonic-gate 				    0xfd, 0xff, 0xff, 0xff, \
727*7c478bd9Sstevel@tonic-gate 				    0xff, 0xff, 0xff, 0x80 };
728*7c478bd9Sstevel@tonic-gate 
729*7c478bd9Sstevel@tonic-gate 	if (IN6_IS_ADDR_UNSPECIFIED(token))
730*7c478bd9Sstevel@tonic-gate 		return (_B_FALSE);
731*7c478bd9Sstevel@tonic-gate 
732*7c478bd9Sstevel@tonic-gate 	if (token->s6_addr[8] & 0x2)
733*7c478bd9Sstevel@tonic-gate 		return (_B_FALSE);
734*7c478bd9Sstevel@tonic-gate 
735*7c478bd9Sstevel@tonic-gate 	(void) memcpy(&mask, token, sizeof (mask));
736*7c478bd9Sstevel@tonic-gate 	mask._S6_un._S6_u32[3] = 0;
737*7c478bd9Sstevel@tonic-gate 	if (IN6_ARE_ADDR_EQUAL(&isatap, token))
738*7c478bd9Sstevel@tonic-gate 		return (_B_FALSE);
739*7c478bd9Sstevel@tonic-gate 
740*7c478bd9Sstevel@tonic-gate 	mask._S6_un._S6_u32[3] = token->_S6_un._S6_u32[3] & 0xffffff80;
741*7c478bd9Sstevel@tonic-gate 	if (IN6_ARE_ADDR_EQUAL(&anycast, token))
742*7c478bd9Sstevel@tonic-gate 		return (_B_FALSE);
743*7c478bd9Sstevel@tonic-gate 
744*7c478bd9Sstevel@tonic-gate 	for (pi = phyints; pi != NULL; pi = pi->pi_next) {
745*7c478bd9Sstevel@tonic-gate 		if (((pi->pi_token_length == TMP_TOKEN_BITS) &&
746*7c478bd9Sstevel@tonic-gate 		    IN6_ARE_ADDR_EQUAL(&pi->pi_token, token)) ||
747*7c478bd9Sstevel@tonic-gate 		    IN6_ARE_ADDR_EQUAL(&pi->pi_tmp_token, token))
748*7c478bd9Sstevel@tonic-gate 			return (_B_FALSE);
749*7c478bd9Sstevel@tonic-gate 	}
750*7c478bd9Sstevel@tonic-gate 
751*7c478bd9Sstevel@tonic-gate 	/* none of our tests failed, must be a good one! */
752*7c478bd9Sstevel@tonic-gate 	return (_B_TRUE);
753*7c478bd9Sstevel@tonic-gate }
754*7c478bd9Sstevel@tonic-gate 
755*7c478bd9Sstevel@tonic-gate /*
756*7c478bd9Sstevel@tonic-gate  * Generate a temporary token and set up its timer
757*7c478bd9Sstevel@tonic-gate  *
758*7c478bd9Sstevel@tonic-gate  * Called from incoming_prefix_addrconf_process() (when token is first
759*7c478bd9Sstevel@tonic-gate  * needed) and from tmptoken_timer() (when current token expires).
760*7c478bd9Sstevel@tonic-gate  *
761*7c478bd9Sstevel@tonic-gate  * Returns _B_TRUE if a token was successfully generated, _B_FALSE if not.
762*7c478bd9Sstevel@tonic-gate  */
763*7c478bd9Sstevel@tonic-gate boolean_t
764*7c478bd9Sstevel@tonic-gate tmptoken_create(struct phyint *pi)
765*7c478bd9Sstevel@tonic-gate {
766*7c478bd9Sstevel@tonic-gate 	int fd, i = 0, max_tries = 15;
767*7c478bd9Sstevel@tonic-gate 	struct in6_addr token;
768*7c478bd9Sstevel@tonic-gate 	uint32_t *tokenp = &(token._S6_un._S6_u32[2]);
769*7c478bd9Sstevel@tonic-gate 	char buf[INET6_ADDRSTRLEN];
770*7c478bd9Sstevel@tonic-gate 
771*7c478bd9Sstevel@tonic-gate 	if ((fd = open("/dev/urandom", O_RDONLY)) == -1) {
772*7c478bd9Sstevel@tonic-gate 		perror("open /dev/urandom");
773*7c478bd9Sstevel@tonic-gate 		goto no_token;
774*7c478bd9Sstevel@tonic-gate 	}
775*7c478bd9Sstevel@tonic-gate 
776*7c478bd9Sstevel@tonic-gate 	bzero((char *)&token, sizeof (token));
777*7c478bd9Sstevel@tonic-gate 	do {
778*7c478bd9Sstevel@tonic-gate 		if (read(fd, (void *)tokenp, TMP_TOKEN_BYTES) == -1) {
779*7c478bd9Sstevel@tonic-gate 			perror("read /dev/urandom");
780*7c478bd9Sstevel@tonic-gate 			(void) close(fd);
781*7c478bd9Sstevel@tonic-gate 			goto no_token;
782*7c478bd9Sstevel@tonic-gate 		}
783*7c478bd9Sstevel@tonic-gate 
784*7c478bd9Sstevel@tonic-gate 		/*
785*7c478bd9Sstevel@tonic-gate 		 * Assume EUI-64 formatting, and thus 64-bit
786*7c478bd9Sstevel@tonic-gate 		 * token len; need to clear global bit.
787*7c478bd9Sstevel@tonic-gate 		 */
788*7c478bd9Sstevel@tonic-gate 		token.s6_addr[8] &= 0xfd;
789*7c478bd9Sstevel@tonic-gate 
790*7c478bd9Sstevel@tonic-gate 		i++;
791*7c478bd9Sstevel@tonic-gate 
792*7c478bd9Sstevel@tonic-gate 	} while (!tmptoken_isvalid(&token) && i < max_tries);
793*7c478bd9Sstevel@tonic-gate 
794*7c478bd9Sstevel@tonic-gate 	(void) close(fd);
795*7c478bd9Sstevel@tonic-gate 
796*7c478bd9Sstevel@tonic-gate 	if (i == max_tries) {
797*7c478bd9Sstevel@tonic-gate no_token:
798*7c478bd9Sstevel@tonic-gate 		logmsg(LOG_WARNING, "tmptoken_create(%s): failed to create "
799*7c478bd9Sstevel@tonic-gate 		    "token; disabling temporary addresses on %s\n",
800*7c478bd9Sstevel@tonic-gate 		    pi->pi_name, pi->pi_name);
801*7c478bd9Sstevel@tonic-gate 		pi->pi_TmpAddrsEnabled = 0;
802*7c478bd9Sstevel@tonic-gate 		return (_B_FALSE);
803*7c478bd9Sstevel@tonic-gate 	}
804*7c478bd9Sstevel@tonic-gate 
805*7c478bd9Sstevel@tonic-gate 	pi->pi_tmp_token = token;
806*7c478bd9Sstevel@tonic-gate 
807*7c478bd9Sstevel@tonic-gate 	if (debug & D_TMP)
808*7c478bd9Sstevel@tonic-gate 		logmsg(LOG_DEBUG, "tmptoken_create(%s): created temporary "
809*7c478bd9Sstevel@tonic-gate 		    "token %s\n", pi->pi_name,
810*7c478bd9Sstevel@tonic-gate 		    inet_ntop(AF_INET6, &pi->pi_tmp_token, buf, sizeof (buf)));
811*7c478bd9Sstevel@tonic-gate 
812*7c478bd9Sstevel@tonic-gate 	pi->pi_TmpRegenCountdown = (pi->pi_TmpPreferredLifetime -
813*7c478bd9Sstevel@tonic-gate 	    pi->pi_TmpDesyncFactor - pi->pi_TmpRegenAdvance) * MILLISEC;
814*7c478bd9Sstevel@tonic-gate 	if (pi->pi_TmpRegenCountdown != 0)
815*7c478bd9Sstevel@tonic-gate 		timer_schedule(pi->pi_TmpRegenCountdown);
816*7c478bd9Sstevel@tonic-gate 
817*7c478bd9Sstevel@tonic-gate 	return (_B_TRUE);
818*7c478bd9Sstevel@tonic-gate }
819*7c478bd9Sstevel@tonic-gate 
820*7c478bd9Sstevel@tonic-gate /*
821*7c478bd9Sstevel@tonic-gate  * Delete a temporary token.  This is outside the normal timeout process,
822*7c478bd9Sstevel@tonic-gate  * so mark any existing addresses based on this token DEPRECATED and set
823*7c478bd9Sstevel@tonic-gate  * their preferred lifetime to 0.  Don't tamper with valid lifetime, that
824*7c478bd9Sstevel@tonic-gate  * will be used to eventually remove the address.  Also reset the current
825*7c478bd9Sstevel@tonic-gate  * pi_tmp_token value to 0.
826*7c478bd9Sstevel@tonic-gate  *
827*7c478bd9Sstevel@tonic-gate  * Called from incoming_prefix_addrconf_process() if DAD fails on a temp
828*7c478bd9Sstevel@tonic-gate  * addr.
829*7c478bd9Sstevel@tonic-gate  */
830*7c478bd9Sstevel@tonic-gate void
831*7c478bd9Sstevel@tonic-gate tmptoken_delete(struct phyint *pi)
832*7c478bd9Sstevel@tonic-gate {
833*7c478bd9Sstevel@tonic-gate 	struct prefix *pr;
834*7c478bd9Sstevel@tonic-gate 
835*7c478bd9Sstevel@tonic-gate 	for (pr = pi->pi_prefix_list; pr != NULL; pr = pr->pr_next) {
836*7c478bd9Sstevel@tonic-gate 		if (!(pr->pr_flags & IFF_TEMPORARY) ||
837*7c478bd9Sstevel@tonic-gate 		    (pr->pr_flags & IFF_DEPRECATED) ||
838*7c478bd9Sstevel@tonic-gate 		    (!token_equal(pr->pr_address, pi->pi_tmp_token,
839*7c478bd9Sstevel@tonic-gate 		    TMP_TOKEN_BITS))) {
840*7c478bd9Sstevel@tonic-gate 			continue;
841*7c478bd9Sstevel@tonic-gate 		}
842*7c478bd9Sstevel@tonic-gate 		pr->pr_PreferredLifetime = 0;
843*7c478bd9Sstevel@tonic-gate 		pr->pr_state |= PR_DEPRECATED;
844*7c478bd9Sstevel@tonic-gate 		prefix_update_k(pr);
845*7c478bd9Sstevel@tonic-gate 	}
846*7c478bd9Sstevel@tonic-gate 
847*7c478bd9Sstevel@tonic-gate 	(void) memset(&pi->pi_tmp_token, 0, sizeof (pi->pi_tmp_token));
848*7c478bd9Sstevel@tonic-gate }
849*7c478bd9Sstevel@tonic-gate 
850*7c478bd9Sstevel@tonic-gate /*
851*7c478bd9Sstevel@tonic-gate  * Called from run_timeouts() with the number of milliseconds elapsed
852*7c478bd9Sstevel@tonic-gate  * since the last call.  Determines if any timeout event has occurred
853*7c478bd9Sstevel@tonic-gate  * and returns the number of milliseconds until the next timeout event
854*7c478bd9Sstevel@tonic-gate  * for the tmp token.  Returns TIMER_INFINITY for "never".
855*7c478bd9Sstevel@tonic-gate  */
856*7c478bd9Sstevel@tonic-gate uint_t
857*7c478bd9Sstevel@tonic-gate tmptoken_timer(struct phyint *pi, uint_t elapsed)
858*7c478bd9Sstevel@tonic-gate {
859*7c478bd9Sstevel@tonic-gate 	struct nd_opt_prefix_info opt;
860*7c478bd9Sstevel@tonic-gate 	struct sockaddr_in6 sin6;
861*7c478bd9Sstevel@tonic-gate 	struct prefix *pr, *newpr;
862*7c478bd9Sstevel@tonic-gate 
863*7c478bd9Sstevel@tonic-gate 	if (debug & D_TMP) {
864*7c478bd9Sstevel@tonic-gate 		logmsg(LOG_DEBUG, "tmptoken_timer(%s, %d) regencountdown %d\n",
865*7c478bd9Sstevel@tonic-gate 		    pi->pi_name, (int)elapsed, pi->pi_TmpRegenCountdown);
866*7c478bd9Sstevel@tonic-gate 	}
867*7c478bd9Sstevel@tonic-gate 	if (!pi->pi_TmpAddrsEnabled ||
868*7c478bd9Sstevel@tonic-gate 	    (pi->pi_TmpRegenCountdown == TIMER_INFINITY))
869*7c478bd9Sstevel@tonic-gate 		return (TIMER_INFINITY);
870*7c478bd9Sstevel@tonic-gate 
871*7c478bd9Sstevel@tonic-gate 	if (pi->pi_TmpRegenCountdown > elapsed) {
872*7c478bd9Sstevel@tonic-gate 		pi->pi_TmpRegenCountdown -= elapsed;
873*7c478bd9Sstevel@tonic-gate 		return (pi->pi_TmpRegenCountdown);
874*7c478bd9Sstevel@tonic-gate 	}
875*7c478bd9Sstevel@tonic-gate 
876*7c478bd9Sstevel@tonic-gate 	/*
877*7c478bd9Sstevel@tonic-gate 	 * Tmp token timer has expired.  Start by generating a new token.
878*7c478bd9Sstevel@tonic-gate 	 * If we can't get a new token, tmp addrs are disabled on this
879*7c478bd9Sstevel@tonic-gate 	 * interface, so there's no need to continue, or to set a timer.
880*7c478bd9Sstevel@tonic-gate 	 */
881*7c478bd9Sstevel@tonic-gate 	if (!tmptoken_create(pi))
882*7c478bd9Sstevel@tonic-gate 		return (TIMER_INFINITY);
883*7c478bd9Sstevel@tonic-gate 
884*7c478bd9Sstevel@tonic-gate 	/*
885*7c478bd9Sstevel@tonic-gate 	 * Now that we have a new token, walk the list of prefixes to
886*7c478bd9Sstevel@tonic-gate 	 * find which ones need a corresponding tmp addr generated.
887*7c478bd9Sstevel@tonic-gate 	 */
888*7c478bd9Sstevel@tonic-gate 	for (pr = pi->pi_prefix_list; pr != NULL; pr = pr->pr_next) {
889*7c478bd9Sstevel@tonic-gate 
890*7c478bd9Sstevel@tonic-gate 		if (!(pr->pr_state & PR_AUTO) || pr->pr_state & PR_STATIC ||
891*7c478bd9Sstevel@tonic-gate 		    pr->pr_state & PR_DEPRECATED ||
892*7c478bd9Sstevel@tonic-gate 		    pr->pr_flags & IFF_TEMPORARY)
893*7c478bd9Sstevel@tonic-gate 			continue;
894*7c478bd9Sstevel@tonic-gate 
895*7c478bd9Sstevel@tonic-gate 		newpr = prefix_create(pi, pr->pr_prefix, pr->pr_prefix_len,
896*7c478bd9Sstevel@tonic-gate 		    IFF_TEMPORARY);
897*7c478bd9Sstevel@tonic-gate 		if (newpr == NULL) {
898*7c478bd9Sstevel@tonic-gate 			char pbuf[INET6_ADDRSTRLEN];
899*7c478bd9Sstevel@tonic-gate 			char tbuf[INET6_ADDRSTRLEN];
900*7c478bd9Sstevel@tonic-gate 			(void) inet_ntop(AF_INET6, &pr->pr_prefix, pbuf,
901*7c478bd9Sstevel@tonic-gate 			    sizeof (pbuf));
902*7c478bd9Sstevel@tonic-gate 			(void) inet_ntop(AF_INET6, &pi->pi_tmp_token, tbuf,
903*7c478bd9Sstevel@tonic-gate 			    sizeof (tbuf));
904*7c478bd9Sstevel@tonic-gate 			logmsg(LOG_ERR, "can't create new tmp addr "
905*7c478bd9Sstevel@tonic-gate 			    "(%s, %s, %s)\n", pi->pi_name, pbuf, tbuf);
906*7c478bd9Sstevel@tonic-gate 			continue;
907*7c478bd9Sstevel@tonic-gate 		}
908*7c478bd9Sstevel@tonic-gate 
909*7c478bd9Sstevel@tonic-gate 		/*
910*7c478bd9Sstevel@tonic-gate 		 * We want to use incoming_prefix_*_process() functions to
911*7c478bd9Sstevel@tonic-gate 		 * set up the new tmp addr, so cobble together a prefix
912*7c478bd9Sstevel@tonic-gate 		 * info option struct based on the existing prefix to pass
913*7c478bd9Sstevel@tonic-gate 		 * in.  The lifetimes will be based on the current time
914*7c478bd9Sstevel@tonic-gate 		 * remaining.
915*7c478bd9Sstevel@tonic-gate 		 *
916*7c478bd9Sstevel@tonic-gate 		 * The "from" param is only used for messages; pass in
917*7c478bd9Sstevel@tonic-gate 		 * ::0 for that.
918*7c478bd9Sstevel@tonic-gate 		 */
919*7c478bd9Sstevel@tonic-gate 		opt.nd_opt_pi_type = ND_OPT_PREFIX_INFORMATION;
920*7c478bd9Sstevel@tonic-gate 		opt.nd_opt_pi_len = sizeof (opt) / 8;
921*7c478bd9Sstevel@tonic-gate 		opt.nd_opt_pi_prefix_len = pr->pr_prefix_len;
922*7c478bd9Sstevel@tonic-gate 		opt.nd_opt_pi_flags_reserved = ND_OPT_PI_FLAG_AUTO;
923*7c478bd9Sstevel@tonic-gate 		opt.nd_opt_pi_valid_time =
924*7c478bd9Sstevel@tonic-gate 		    htonl(pr->pr_ValidLifetime / 1000);
925*7c478bd9Sstevel@tonic-gate 		opt.nd_opt_pi_preferred_time =
926*7c478bd9Sstevel@tonic-gate 		    htonl(pr->pr_PreferredLifetime / 1000);
927*7c478bd9Sstevel@tonic-gate 		if (pr->pr_state & PR_ONLINK)
928*7c478bd9Sstevel@tonic-gate 			opt.nd_opt_pi_flags_reserved &= ND_OPT_PI_FLAG_ONLINK;
929*7c478bd9Sstevel@tonic-gate 		opt.nd_opt_pi_prefix = pr->pr_prefix;
930*7c478bd9Sstevel@tonic-gate 
931*7c478bd9Sstevel@tonic-gate 		(void) memset(&sin6, 0, sizeof (sin6));
932*7c478bd9Sstevel@tonic-gate 
933*7c478bd9Sstevel@tonic-gate 		if (!incoming_prefix_addrconf_process(pi, newpr,
934*7c478bd9Sstevel@tonic-gate 		    (uchar_t *)&opt, &sin6, _B_FALSE, _B_TRUE)) {
935*7c478bd9Sstevel@tonic-gate 			char pbuf[INET6_ADDRSTRLEN];
936*7c478bd9Sstevel@tonic-gate 			char tbuf[INET6_ADDRSTRLEN];
937*7c478bd9Sstevel@tonic-gate 			(void) inet_ntop(AF_INET6, &pr->pr_prefix, pbuf,
938*7c478bd9Sstevel@tonic-gate 			    sizeof (pbuf));
939*7c478bd9Sstevel@tonic-gate 			(void) inet_ntop(AF_INET6, &pi->pi_tmp_token, tbuf,
940*7c478bd9Sstevel@tonic-gate 			    sizeof (tbuf));
941*7c478bd9Sstevel@tonic-gate 			logmsg(LOG_ERR, "can't create new tmp addr "
942*7c478bd9Sstevel@tonic-gate 			    "(%s, %s, %s)\n", pi->pi_name, pbuf, tbuf);
943*7c478bd9Sstevel@tonic-gate 			continue;
944*7c478bd9Sstevel@tonic-gate 		}
945*7c478bd9Sstevel@tonic-gate 
946*7c478bd9Sstevel@tonic-gate 		if (pr->pr_state & PR_ONLINK) {
947*7c478bd9Sstevel@tonic-gate 			incoming_prefix_onlink_process(newpr, (uchar_t *)&opt);
948*7c478bd9Sstevel@tonic-gate 		}
949*7c478bd9Sstevel@tonic-gate 	}
950*7c478bd9Sstevel@tonic-gate 
951*7c478bd9Sstevel@tonic-gate 	/*
952*7c478bd9Sstevel@tonic-gate 	 * appropriate timers were scheduled when
953*7c478bd9Sstevel@tonic-gate 	 * the token and addresses were created.
954*7c478bd9Sstevel@tonic-gate 	 */
955*7c478bd9Sstevel@tonic-gate 	return (TIMER_INFINITY);
956*7c478bd9Sstevel@tonic-gate }
957*7c478bd9Sstevel@tonic-gate 
958*7c478bd9Sstevel@tonic-gate /*
959*7c478bd9Sstevel@tonic-gate  * tlen specifies the token length in bits.  Compares the lower
960*7c478bd9Sstevel@tonic-gate  * tlen bits of the two addresses provided and returns _B_TRUE if
961*7c478bd9Sstevel@tonic-gate  * they match, _B_FALSE if not.  Also returns _B_FALSE for invalid
962*7c478bd9Sstevel@tonic-gate  * values of tlen.
963*7c478bd9Sstevel@tonic-gate  */
964*7c478bd9Sstevel@tonic-gate boolean_t
965*7c478bd9Sstevel@tonic-gate token_equal(struct in6_addr t1, struct in6_addr t2, int tlen)
966*7c478bd9Sstevel@tonic-gate {
967*7c478bd9Sstevel@tonic-gate 	uchar_t mask;
968*7c478bd9Sstevel@tonic-gate 	int j, abytes, tbytes, tbits;
969*7c478bd9Sstevel@tonic-gate 
970*7c478bd9Sstevel@tonic-gate 	if (tlen < 0 || tlen > IPV6_ABITS)
971*7c478bd9Sstevel@tonic-gate 		return (_B_FALSE);
972*7c478bd9Sstevel@tonic-gate 
973*7c478bd9Sstevel@tonic-gate 	abytes = IPV6_ABITS >> 3;
974*7c478bd9Sstevel@tonic-gate 	tbytes = tlen >> 3;
975*7c478bd9Sstevel@tonic-gate 	tbits = tlen & 7;
976*7c478bd9Sstevel@tonic-gate 
977*7c478bd9Sstevel@tonic-gate 	for (j = abytes - 1; j >= abytes - tbytes; j--)
978*7c478bd9Sstevel@tonic-gate 		if (t1.s6_addr[j] != t2.s6_addr[j])
979*7c478bd9Sstevel@tonic-gate 			return (_B_FALSE);
980*7c478bd9Sstevel@tonic-gate 
981*7c478bd9Sstevel@tonic-gate 	if (tbits == 0)
982*7c478bd9Sstevel@tonic-gate 		return (_B_TRUE);
983*7c478bd9Sstevel@tonic-gate 
984*7c478bd9Sstevel@tonic-gate 	/* We only care about the tbits rightmost bits */
985*7c478bd9Sstevel@tonic-gate 	mask = 0xff >> (8 - tbits);
986*7c478bd9Sstevel@tonic-gate 	if ((t1.s6_addr[j] & mask) != (t2.s6_addr[j] & mask))
987*7c478bd9Sstevel@tonic-gate 		return (_B_FALSE);
988*7c478bd9Sstevel@tonic-gate 
989*7c478bd9Sstevel@tonic-gate 	return (_B_TRUE);
990*7c478bd9Sstevel@tonic-gate }
991*7c478bd9Sstevel@tonic-gate 
992*7c478bd9Sstevel@tonic-gate /*
993*7c478bd9Sstevel@tonic-gate  * Lookup prefix structure that matches the prefix and prefix length.
994*7c478bd9Sstevel@tonic-gate  * Assumes that the bits after prefixlen might not be zero.
995*7c478bd9Sstevel@tonic-gate  */
996*7c478bd9Sstevel@tonic-gate static struct prefix *
997*7c478bd9Sstevel@tonic-gate prefix_lookup(struct phyint *pi, struct in6_addr prefix, int prefixlen)
998*7c478bd9Sstevel@tonic-gate {
999*7c478bd9Sstevel@tonic-gate 	struct prefix *pr;
1000*7c478bd9Sstevel@tonic-gate 	char abuf[INET6_ADDRSTRLEN];
1001*7c478bd9Sstevel@tonic-gate 
1002*7c478bd9Sstevel@tonic-gate 	if (debug & D_PREFIX) {
1003*7c478bd9Sstevel@tonic-gate 		logmsg(LOG_DEBUG, "prefix_lookup(%s, %s/%u)\n", pi->pi_name,
1004*7c478bd9Sstevel@tonic-gate 		    inet_ntop(AF_INET6, (void *)&prefix,
1005*7c478bd9Sstevel@tonic-gate 		    abuf, sizeof (abuf)), prefixlen);
1006*7c478bd9Sstevel@tonic-gate 	}
1007*7c478bd9Sstevel@tonic-gate 
1008*7c478bd9Sstevel@tonic-gate 	for (pr = pi->pi_prefix_list; pr != NULL; pr = pr->pr_next) {
1009*7c478bd9Sstevel@tonic-gate 		if (pr->pr_prefix_len == prefixlen &&
1010*7c478bd9Sstevel@tonic-gate 		    prefix_equal(prefix, pr->pr_prefix, prefixlen))
1011*7c478bd9Sstevel@tonic-gate 			return (pr);
1012*7c478bd9Sstevel@tonic-gate 	}
1013*7c478bd9Sstevel@tonic-gate 	return (NULL);
1014*7c478bd9Sstevel@tonic-gate }
1015*7c478bd9Sstevel@tonic-gate 
1016*7c478bd9Sstevel@tonic-gate /*
1017*7c478bd9Sstevel@tonic-gate  * Compare two prefixes that have the same prefix length.
1018*7c478bd9Sstevel@tonic-gate  * Fails if the prefix length is unreasonable.
1019*7c478bd9Sstevel@tonic-gate  */
1020*7c478bd9Sstevel@tonic-gate boolean_t
1021*7c478bd9Sstevel@tonic-gate prefix_equal(struct in6_addr p1, struct in6_addr p2, int plen)
1022*7c478bd9Sstevel@tonic-gate {
1023*7c478bd9Sstevel@tonic-gate 	uchar_t mask;
1024*7c478bd9Sstevel@tonic-gate 	int j, pbytes, pbits;
1025*7c478bd9Sstevel@tonic-gate 
1026*7c478bd9Sstevel@tonic-gate 	if (plen < 0 || plen > IPV6_ABITS)
1027*7c478bd9Sstevel@tonic-gate 		return (_B_FALSE);
1028*7c478bd9Sstevel@tonic-gate 
1029*7c478bd9Sstevel@tonic-gate 	pbytes = plen >> 3;
1030*7c478bd9Sstevel@tonic-gate 	pbits = plen & 7;
1031*7c478bd9Sstevel@tonic-gate 
1032*7c478bd9Sstevel@tonic-gate 	for (j = 0; j < pbytes; j++)
1033*7c478bd9Sstevel@tonic-gate 		if (p1.s6_addr[j] != p2.s6_addr[j])
1034*7c478bd9Sstevel@tonic-gate 			return (_B_FALSE);
1035*7c478bd9Sstevel@tonic-gate 
1036*7c478bd9Sstevel@tonic-gate 	if (pbits == 0)
1037*7c478bd9Sstevel@tonic-gate 		return (_B_TRUE);
1038*7c478bd9Sstevel@tonic-gate 
1039*7c478bd9Sstevel@tonic-gate 	/* Make the N leftmost bits one */
1040*7c478bd9Sstevel@tonic-gate 	mask = 0xff << (8 - pbits);
1041*7c478bd9Sstevel@tonic-gate 	if ((p1.s6_addr[j] & mask) != (p2.s6_addr[j] & mask))
1042*7c478bd9Sstevel@tonic-gate 		return (_B_FALSE);
1043*7c478bd9Sstevel@tonic-gate 
1044*7c478bd9Sstevel@tonic-gate 	return (_B_TRUE);
1045*7c478bd9Sstevel@tonic-gate }
1046*7c478bd9Sstevel@tonic-gate 
1047*7c478bd9Sstevel@tonic-gate /*
1048*7c478bd9Sstevel@tonic-gate  * Set a prefix from an address and a prefix length.
1049*7c478bd9Sstevel@tonic-gate  * Force all the bits after the prefix length to be zero.
1050*7c478bd9Sstevel@tonic-gate  */
1051*7c478bd9Sstevel@tonic-gate void
1052*7c478bd9Sstevel@tonic-gate prefix_set(struct in6_addr *prefix, struct in6_addr addr, int prefix_len)
1053*7c478bd9Sstevel@tonic-gate {
1054*7c478bd9Sstevel@tonic-gate 	uchar_t mask;
1055*7c478bd9Sstevel@tonic-gate 	int j;
1056*7c478bd9Sstevel@tonic-gate 
1057*7c478bd9Sstevel@tonic-gate 	if (prefix_len < 0 || prefix_len > IPV6_ABITS)
1058*7c478bd9Sstevel@tonic-gate 		return;
1059*7c478bd9Sstevel@tonic-gate 
1060*7c478bd9Sstevel@tonic-gate 	bzero((char *)prefix, sizeof (*prefix));
1061*7c478bd9Sstevel@tonic-gate 
1062*7c478bd9Sstevel@tonic-gate 	for (j = 0; prefix_len > 8; prefix_len -= 8, j++)
1063*7c478bd9Sstevel@tonic-gate 		prefix->s6_addr[j] = addr.s6_addr[j];
1064*7c478bd9Sstevel@tonic-gate 
1065*7c478bd9Sstevel@tonic-gate 	/* Make the N leftmost bits one */
1066*7c478bd9Sstevel@tonic-gate 	mask = 0xff << (8 - prefix_len);
1067*7c478bd9Sstevel@tonic-gate 	prefix->s6_addr[j] = addr.s6_addr[j] & mask;
1068*7c478bd9Sstevel@tonic-gate }
1069*7c478bd9Sstevel@tonic-gate 
1070*7c478bd9Sstevel@tonic-gate /*
1071*7c478bd9Sstevel@tonic-gate  * Lookup a prefix based on the kernel's interface name.
1072*7c478bd9Sstevel@tonic-gate  */
1073*7c478bd9Sstevel@tonic-gate struct prefix *
1074*7c478bd9Sstevel@tonic-gate prefix_lookup_name(struct phyint *pi, char *name)
1075*7c478bd9Sstevel@tonic-gate {
1076*7c478bd9Sstevel@tonic-gate 	struct prefix *pr;
1077*7c478bd9Sstevel@tonic-gate 
1078*7c478bd9Sstevel@tonic-gate 	if (debug & D_PREFIX) {
1079*7c478bd9Sstevel@tonic-gate 		logmsg(LOG_DEBUG, "prefix_lookup_name(%s, %s)\n",
1080*7c478bd9Sstevel@tonic-gate 		    pi->pi_name, name);
1081*7c478bd9Sstevel@tonic-gate 	}
1082*7c478bd9Sstevel@tonic-gate 	if (name[0] == '\0')
1083*7c478bd9Sstevel@tonic-gate 		return (NULL);
1084*7c478bd9Sstevel@tonic-gate 
1085*7c478bd9Sstevel@tonic-gate 	for (pr = pi->pi_prefix_list; pr != NULL; pr = pr->pr_next) {
1086*7c478bd9Sstevel@tonic-gate 		if (strcmp(name, pr->pr_name) == 0)
1087*7c478bd9Sstevel@tonic-gate 			return (pr);
1088*7c478bd9Sstevel@tonic-gate 	}
1089*7c478bd9Sstevel@tonic-gate 	return (NULL);
1090*7c478bd9Sstevel@tonic-gate }
1091*7c478bd9Sstevel@tonic-gate 
1092*7c478bd9Sstevel@tonic-gate /*
1093*7c478bd9Sstevel@tonic-gate  * Search the phyints list to make sure that this new prefix does
1094*7c478bd9Sstevel@tonic-gate  * not already exist in any  other physical interfaces that have
1095*7c478bd9Sstevel@tonic-gate  * the same address as this one
1096*7c478bd9Sstevel@tonic-gate  */
1097*7c478bd9Sstevel@tonic-gate struct prefix *
1098*7c478bd9Sstevel@tonic-gate prefix_lookup_addr_match(struct prefix *pr)
1099*7c478bd9Sstevel@tonic-gate {
1100*7c478bd9Sstevel@tonic-gate 	char abuf[INET6_ADDRSTRLEN];
1101*7c478bd9Sstevel@tonic-gate 	struct phyint *pi;
1102*7c478bd9Sstevel@tonic-gate 	struct prefix *otherpr = NULL;
1103*7c478bd9Sstevel@tonic-gate 	struct in6_addr prefix;
1104*7c478bd9Sstevel@tonic-gate 	int	prefixlen;
1105*7c478bd9Sstevel@tonic-gate 
1106*7c478bd9Sstevel@tonic-gate 	if (debug & D_PREFIX) {
1107*7c478bd9Sstevel@tonic-gate 		logmsg(LOG_DEBUG, "prefix_lookup_addr_match(%s/%u)\n",
1108*7c478bd9Sstevel@tonic-gate 		    inet_ntop(AF_INET6, (void *)&pr->pr_address,
1109*7c478bd9Sstevel@tonic-gate 		    abuf, sizeof (abuf)), pr->pr_prefix_len);
1110*7c478bd9Sstevel@tonic-gate 	}
1111*7c478bd9Sstevel@tonic-gate 	prefix = pr->pr_prefix;
1112*7c478bd9Sstevel@tonic-gate 	prefixlen = pr->pr_prefix_len;
1113*7c478bd9Sstevel@tonic-gate 	for (pi = phyints; pi != NULL; pi = pi->pi_next) {
1114*7c478bd9Sstevel@tonic-gate 		otherpr = prefix_lookup(pi, prefix, prefixlen);
1115*7c478bd9Sstevel@tonic-gate 		if (otherpr == pr)
1116*7c478bd9Sstevel@tonic-gate 			continue;
1117*7c478bd9Sstevel@tonic-gate 		if (otherpr != NULL && (otherpr->pr_state & PR_AUTO) &&
1118*7c478bd9Sstevel@tonic-gate 		    IN6_ARE_ADDR_EQUAL(&pr->pr_address,
1119*7c478bd9Sstevel@tonic-gate 		    &otherpr->pr_address))
1120*7c478bd9Sstevel@tonic-gate 			return (otherpr);
1121*7c478bd9Sstevel@tonic-gate 	}
1122*7c478bd9Sstevel@tonic-gate 	return (NULL);
1123*7c478bd9Sstevel@tonic-gate }
1124*7c478bd9Sstevel@tonic-gate 
1125*7c478bd9Sstevel@tonic-gate /*
1126*7c478bd9Sstevel@tonic-gate  * Initialize a new prefix without setting lifetimes etc.
1127*7c478bd9Sstevel@tonic-gate  */
1128*7c478bd9Sstevel@tonic-gate struct prefix *
1129*7c478bd9Sstevel@tonic-gate prefix_create(struct phyint *pi, struct in6_addr prefix, int prefixlen,
1130*7c478bd9Sstevel@tonic-gate     uint64_t flags)
1131*7c478bd9Sstevel@tonic-gate {
1132*7c478bd9Sstevel@tonic-gate 	struct prefix *pr;
1133*7c478bd9Sstevel@tonic-gate 	char abuf[INET6_ADDRSTRLEN];
1134*7c478bd9Sstevel@tonic-gate 
1135*7c478bd9Sstevel@tonic-gate 	if (debug & D_PREFIX) {
1136*7c478bd9Sstevel@tonic-gate 		logmsg(LOG_DEBUG, "prefix_create(%s, %s/%u, 0x%llx)\n",
1137*7c478bd9Sstevel@tonic-gate 		    pi->pi_name, inet_ntop(AF_INET6, (void *)&prefix,
1138*7c478bd9Sstevel@tonic-gate 		    abuf, sizeof (abuf)), prefixlen, flags);
1139*7c478bd9Sstevel@tonic-gate 	}
1140*7c478bd9Sstevel@tonic-gate 	pr = (struct prefix *)calloc(sizeof (struct prefix), 1);
1141*7c478bd9Sstevel@tonic-gate 	if (pr == NULL) {
1142*7c478bd9Sstevel@tonic-gate 		logmsg(LOG_ERR, "prefix_create: out of memory\n");
1143*7c478bd9Sstevel@tonic-gate 		return (NULL);
1144*7c478bd9Sstevel@tonic-gate 	}
1145*7c478bd9Sstevel@tonic-gate 	/*
1146*7c478bd9Sstevel@tonic-gate 	 * The prefix might have non-zero bits after the prefix len bits.
1147*7c478bd9Sstevel@tonic-gate 	 * Force them to be zero.
1148*7c478bd9Sstevel@tonic-gate 	 */
1149*7c478bd9Sstevel@tonic-gate 	prefix_set(&pr->pr_prefix, prefix, prefixlen);
1150*7c478bd9Sstevel@tonic-gate 	pr->pr_prefix_len = prefixlen;
1151*7c478bd9Sstevel@tonic-gate 	pr->pr_PreferredLifetime = PREFIX_INFINITY;
1152*7c478bd9Sstevel@tonic-gate 	pr->pr_ValidLifetime = PREFIX_INFINITY;
1153*7c478bd9Sstevel@tonic-gate 	pr->pr_OnLinkLifetime = PREFIX_INFINITY;
1154*7c478bd9Sstevel@tonic-gate 	pr->pr_kernel_state = 0;
1155*7c478bd9Sstevel@tonic-gate 	pr->pr_flags |= flags;
1156*7c478bd9Sstevel@tonic-gate 	prefix_insert(pi, pr);
1157*7c478bd9Sstevel@tonic-gate 	return (pr);
1158*7c478bd9Sstevel@tonic-gate }
1159*7c478bd9Sstevel@tonic-gate 
1160*7c478bd9Sstevel@tonic-gate /*
1161*7c478bd9Sstevel@tonic-gate  * Create a new named prefix. Caller should use prefix_init_from_k
1162*7c478bd9Sstevel@tonic-gate  * to initialize the content.
1163*7c478bd9Sstevel@tonic-gate  */
1164*7c478bd9Sstevel@tonic-gate struct prefix *
1165*7c478bd9Sstevel@tonic-gate prefix_create_name(struct phyint *pi, char *name)
1166*7c478bd9Sstevel@tonic-gate {
1167*7c478bd9Sstevel@tonic-gate 	struct prefix *pr;
1168*7c478bd9Sstevel@tonic-gate 
1169*7c478bd9Sstevel@tonic-gate 	if (debug & D_PREFIX) {
1170*7c478bd9Sstevel@tonic-gate 		logmsg(LOG_DEBUG, "prefix_create_name(%s, %s)\n",
1171*7c478bd9Sstevel@tonic-gate 		    pi->pi_name, name);
1172*7c478bd9Sstevel@tonic-gate 	}
1173*7c478bd9Sstevel@tonic-gate 	pr = (struct prefix *)calloc(sizeof (struct prefix), 1);
1174*7c478bd9Sstevel@tonic-gate 	if (pr == NULL) {
1175*7c478bd9Sstevel@tonic-gate 		logmsg(LOG_ERR, "prefix_create_name: out of memory\n");
1176*7c478bd9Sstevel@tonic-gate 		return (NULL);
1177*7c478bd9Sstevel@tonic-gate 	}
1178*7c478bd9Sstevel@tonic-gate 	(void) strncpy(pr->pr_name, name, sizeof (pr->pr_name));
1179*7c478bd9Sstevel@tonic-gate 	pr->pr_name[sizeof (pr->pr_name) - 1] = '\0';
1180*7c478bd9Sstevel@tonic-gate 	prefix_insert(pi, pr);
1181*7c478bd9Sstevel@tonic-gate 	return (pr);
1182*7c478bd9Sstevel@tonic-gate }
1183*7c478bd9Sstevel@tonic-gate 
1184*7c478bd9Sstevel@tonic-gate /* Insert in linked list */
1185*7c478bd9Sstevel@tonic-gate static void
1186*7c478bd9Sstevel@tonic-gate prefix_insert(struct phyint *pi, struct prefix *pr)
1187*7c478bd9Sstevel@tonic-gate {
1188*7c478bd9Sstevel@tonic-gate 	pr->pr_next = pi->pi_prefix_list;
1189*7c478bd9Sstevel@tonic-gate 	pr->pr_prev = NULL;
1190*7c478bd9Sstevel@tonic-gate 	if (pi->pi_prefix_list != NULL)
1191*7c478bd9Sstevel@tonic-gate 		pi->pi_prefix_list->pr_prev = pr;
1192*7c478bd9Sstevel@tonic-gate 	pi->pi_prefix_list = pr;
1193*7c478bd9Sstevel@tonic-gate 	pr->pr_physical = pi;
1194*7c478bd9Sstevel@tonic-gate }
1195*7c478bd9Sstevel@tonic-gate 
1196*7c478bd9Sstevel@tonic-gate /*
1197*7c478bd9Sstevel@tonic-gate  * Initialize the prefix from the content of the kernel.
1198*7c478bd9Sstevel@tonic-gate  * If IFF_ADDRCONF is set we treat it as PR_AUTO (i.e. an addrconf
1199*7c478bd9Sstevel@tonic-gate  * prefix). However, we not derive the lifetimes from
1200*7c478bd9Sstevel@tonic-gate  * the kernel thus they are set to 1 week.
1201*7c478bd9Sstevel@tonic-gate  * Ignore the prefix if the interface is not IFF_UP.
1202*7c478bd9Sstevel@tonic-gate  */
1203*7c478bd9Sstevel@tonic-gate int
1204*7c478bd9Sstevel@tonic-gate prefix_init_from_k(struct prefix *pr)
1205*7c478bd9Sstevel@tonic-gate {
1206*7c478bd9Sstevel@tonic-gate 	struct lifreq lifr;
1207*7c478bd9Sstevel@tonic-gate 	struct sockaddr_in6 *sin6;
1208*7c478bd9Sstevel@tonic-gate 	int sock = pr->pr_physical->pi_sock;
1209*7c478bd9Sstevel@tonic-gate 
1210*7c478bd9Sstevel@tonic-gate 	(void) strncpy(lifr.lifr_name, pr->pr_name, sizeof (lifr.lifr_name));
1211*7c478bd9Sstevel@tonic-gate 	lifr.lifr_name[sizeof (lifr.lifr_name) - 1] = '\0';
1212*7c478bd9Sstevel@tonic-gate 	if (ioctl(sock, SIOCGLIFADDR, (char *)&lifr) < 0) {
1213*7c478bd9Sstevel@tonic-gate 		logperror_pr(pr, "prefix_init_from_k: ioctl (get addr)");
1214*7c478bd9Sstevel@tonic-gate 		goto error;
1215*7c478bd9Sstevel@tonic-gate 	}
1216*7c478bd9Sstevel@tonic-gate 	if (lifr.lifr_addr.ss_family != AF_INET6) {
1217*7c478bd9Sstevel@tonic-gate 		logmsg(LOG_ERR, "ignoring interface %s: not AF_INET6\n",
1218*7c478bd9Sstevel@tonic-gate 		    pr->pr_name);
1219*7c478bd9Sstevel@tonic-gate 		goto error;
1220*7c478bd9Sstevel@tonic-gate 	}
1221*7c478bd9Sstevel@tonic-gate 	sin6 = (struct sockaddr_in6 *)&lifr.lifr_addr;
1222*7c478bd9Sstevel@tonic-gate 	pr->pr_address = sin6->sin6_addr;
1223*7c478bd9Sstevel@tonic-gate 
1224*7c478bd9Sstevel@tonic-gate 	if (ioctl(sock, SIOCGLIFFLAGS, (char *)&lifr) < 0) {
1225*7c478bd9Sstevel@tonic-gate 		logperror_pr(pr, "prefix_init_from_k: ioctl (get flags)");
1226*7c478bd9Sstevel@tonic-gate 		goto error;
1227*7c478bd9Sstevel@tonic-gate 	}
1228*7c478bd9Sstevel@tonic-gate 	pr->pr_flags = lifr.lifr_flags;
1229*7c478bd9Sstevel@tonic-gate 
1230*7c478bd9Sstevel@tonic-gate 	if (ioctl(sock, SIOCGLIFSUBNET, (char *)&lifr) < 0) {
1231*7c478bd9Sstevel@tonic-gate 		logperror_pr(pr, "prefix_init_from_k: ioctl (get subnet)");
1232*7c478bd9Sstevel@tonic-gate 		goto error;
1233*7c478bd9Sstevel@tonic-gate 	}
1234*7c478bd9Sstevel@tonic-gate 	if (lifr.lifr_subnet.ss_family != AF_INET6) {
1235*7c478bd9Sstevel@tonic-gate 		logmsg(LOG_ERR, "ignoring interface %s: not AF_INET6\n",
1236*7c478bd9Sstevel@tonic-gate 		    pr->pr_name);
1237*7c478bd9Sstevel@tonic-gate 		goto error;
1238*7c478bd9Sstevel@tonic-gate 	}
1239*7c478bd9Sstevel@tonic-gate 	/*
1240*7c478bd9Sstevel@tonic-gate 	 * Guard against the prefix having non-zero bits after the prefix
1241*7c478bd9Sstevel@tonic-gate 	 * len bits.
1242*7c478bd9Sstevel@tonic-gate 	 */
1243*7c478bd9Sstevel@tonic-gate 	sin6 = (struct sockaddr_in6 *)&lifr.lifr_subnet;
1244*7c478bd9Sstevel@tonic-gate 	pr->pr_prefix_len = lifr.lifr_addrlen;
1245*7c478bd9Sstevel@tonic-gate 	prefix_set(&pr->pr_prefix, sin6->sin6_addr, pr->pr_prefix_len);
1246*7c478bd9Sstevel@tonic-gate 
1247*7c478bd9Sstevel@tonic-gate 	if (pr->pr_prefix_len != IPV6_ABITS && (pr->pr_flags & IFF_UP) &&
1248*7c478bd9Sstevel@tonic-gate 	    IN6_ARE_ADDR_EQUAL(&pr->pr_address, &pr->pr_prefix)) {
1249*7c478bd9Sstevel@tonic-gate 		char abuf[INET6_ADDRSTRLEN];
1250*7c478bd9Sstevel@tonic-gate 
1251*7c478bd9Sstevel@tonic-gate 		logmsg(LOG_ERR, "ingoring interface %s: it appears to be "
1252*7c478bd9Sstevel@tonic-gate 		    "configured with an invalid interface id (%s/%u)\n",
1253*7c478bd9Sstevel@tonic-gate 		    pr->pr_name,
1254*7c478bd9Sstevel@tonic-gate 		    inet_ntop(AF_INET6, (void *)&pr->pr_address,
1255*7c478bd9Sstevel@tonic-gate 			abuf, sizeof (abuf)), pr->pr_prefix_len);
1256*7c478bd9Sstevel@tonic-gate 		goto error;
1257*7c478bd9Sstevel@tonic-gate 	}
1258*7c478bd9Sstevel@tonic-gate 	pr->pr_kernel_state = 0;
1259*7c478bd9Sstevel@tonic-gate 	if (pr->pr_prefix_len != IPV6_ABITS)
1260*7c478bd9Sstevel@tonic-gate 		pr->pr_kernel_state |= PR_ONLINK;
1261*7c478bd9Sstevel@tonic-gate 	if (!(pr->pr_flags & IFF_NOLOCAL))
1262*7c478bd9Sstevel@tonic-gate 		pr->pr_kernel_state |= PR_AUTO;
1263*7c478bd9Sstevel@tonic-gate 	if ((pr->pr_flags & IFF_DEPRECATED) && (pr->pr_kernel_state & PR_AUTO))
1264*7c478bd9Sstevel@tonic-gate 		pr->pr_kernel_state |= PR_DEPRECATED;
1265*7c478bd9Sstevel@tonic-gate 	if (!(pr->pr_flags & IFF_ADDRCONF)) {
1266*7c478bd9Sstevel@tonic-gate 		/* Prevent ndpd from stepping on this prefix */
1267*7c478bd9Sstevel@tonic-gate 		pr->pr_kernel_state |= PR_STATIC;
1268*7c478bd9Sstevel@tonic-gate 	}
1269*7c478bd9Sstevel@tonic-gate 	pr->pr_state = pr->pr_kernel_state;
1270*7c478bd9Sstevel@tonic-gate 	/* Adjust pr_prefix_len based if PR_AUTO is set */
1271*7c478bd9Sstevel@tonic-gate 	if (pr->pr_state & PR_AUTO) {
1272*7c478bd9Sstevel@tonic-gate 		pr->pr_prefix_len =
1273*7c478bd9Sstevel@tonic-gate 		    IPV6_ABITS - pr->pr_physical->pi_token_length;
1274*7c478bd9Sstevel@tonic-gate 		prefix_set(&pr->pr_prefix, pr->pr_prefix, pr->pr_prefix_len);
1275*7c478bd9Sstevel@tonic-gate 	}
1276*7c478bd9Sstevel@tonic-gate 
1277*7c478bd9Sstevel@tonic-gate 	/* Can't extract lifetimes from the kernel - use 1 week */
1278*7c478bd9Sstevel@tonic-gate 	pr->pr_ValidLifetime = NDP_PREFIX_DEFAULT_LIFETIME;
1279*7c478bd9Sstevel@tonic-gate 	pr->pr_PreferredLifetime = NDP_PREFIX_DEFAULT_LIFETIME;
1280*7c478bd9Sstevel@tonic-gate 	pr->pr_OnLinkLifetime = NDP_PREFIX_DEFAULT_LIFETIME;
1281*7c478bd9Sstevel@tonic-gate 
1282*7c478bd9Sstevel@tonic-gate 	/*
1283*7c478bd9Sstevel@tonic-gate 	 * If this is a temp addr, the creation time needs to be set.
1284*7c478bd9Sstevel@tonic-gate 	 * Though it won't be entirely accurate, the current time is
1285*7c478bd9Sstevel@tonic-gate 	 * an okay approximation.
1286*7c478bd9Sstevel@tonic-gate 	 */
1287*7c478bd9Sstevel@tonic-gate 	if (pr->pr_flags & IFF_TEMPORARY)
1288*7c478bd9Sstevel@tonic-gate 		pr->pr_CreateTime = getcurrenttime() / MILLISEC;
1289*7c478bd9Sstevel@tonic-gate 
1290*7c478bd9Sstevel@tonic-gate 	if (pr->pr_kernel_state == 0)
1291*7c478bd9Sstevel@tonic-gate 		pr->pr_name[0] = '\0';
1292*7c478bd9Sstevel@tonic-gate 	return (0);
1293*7c478bd9Sstevel@tonic-gate 
1294*7c478bd9Sstevel@tonic-gate error:
1295*7c478bd9Sstevel@tonic-gate 	/* Pretend that the prefix does not exist in the kernel */
1296*7c478bd9Sstevel@tonic-gate 	pr->pr_kernel_state = 0;
1297*7c478bd9Sstevel@tonic-gate 	pr->pr_name[0] = '\0';
1298*7c478bd9Sstevel@tonic-gate 	return (-1);
1299*7c478bd9Sstevel@tonic-gate }
1300*7c478bd9Sstevel@tonic-gate 
1301*7c478bd9Sstevel@tonic-gate /*
1302*7c478bd9Sstevel@tonic-gate  * Delete (unlink and free) and remove from kernel if the prefix
1303*7c478bd9Sstevel@tonic-gate  * was added by in.ndpd (i.e. PR_STATIC is not set).
1304*7c478bd9Sstevel@tonic-gate  * Handles delete of things that have not yet been inserted in the list
1305*7c478bd9Sstevel@tonic-gate  * i.e. pr_physical is NULL.
1306*7c478bd9Sstevel@tonic-gate  */
1307*7c478bd9Sstevel@tonic-gate void
1308*7c478bd9Sstevel@tonic-gate prefix_delete(struct prefix *pr)
1309*7c478bd9Sstevel@tonic-gate {
1310*7c478bd9Sstevel@tonic-gate 	struct phyint *pi;
1311*7c478bd9Sstevel@tonic-gate 	char abuf[INET6_ADDRSTRLEN];
1312*7c478bd9Sstevel@tonic-gate 
1313*7c478bd9Sstevel@tonic-gate 	if (debug & D_PREFIX) {
1314*7c478bd9Sstevel@tonic-gate 		logmsg(LOG_DEBUG, "prefix_delete(%s, %s, %s/%u)\n",
1315*7c478bd9Sstevel@tonic-gate 		    pr->pr_physical->pi_name, pr->pr_name,
1316*7c478bd9Sstevel@tonic-gate 		    inet_ntop(AF_INET6, (void *)&pr->pr_prefix,
1317*7c478bd9Sstevel@tonic-gate 		    abuf, sizeof (abuf)), pr->pr_prefix_len);
1318*7c478bd9Sstevel@tonic-gate 	}
1319*7c478bd9Sstevel@tonic-gate 	/* Remove non-static prefixes from the kernel. */
1320*7c478bd9Sstevel@tonic-gate 	pr->pr_state &= PR_STATIC;
1321*7c478bd9Sstevel@tonic-gate 	pi = pr->pr_physical;
1322*7c478bd9Sstevel@tonic-gate 	if (pr->pr_kernel_state != pr->pr_state)
1323*7c478bd9Sstevel@tonic-gate 		prefix_update_k(pr);
1324*7c478bd9Sstevel@tonic-gate 
1325*7c478bd9Sstevel@tonic-gate 	if (pr->pr_prev == NULL) {
1326*7c478bd9Sstevel@tonic-gate 		if (pi != NULL)
1327*7c478bd9Sstevel@tonic-gate 			pi->pi_prefix_list = pr->pr_next;
1328*7c478bd9Sstevel@tonic-gate 	} else {
1329*7c478bd9Sstevel@tonic-gate 		pr->pr_prev->pr_next = pr->pr_next;
1330*7c478bd9Sstevel@tonic-gate 	}
1331*7c478bd9Sstevel@tonic-gate 	if (pr->pr_next != NULL)
1332*7c478bd9Sstevel@tonic-gate 		pr->pr_next->pr_prev = pr->pr_prev;
1333*7c478bd9Sstevel@tonic-gate 	pr->pr_next = pr->pr_prev = NULL;
1334*7c478bd9Sstevel@tonic-gate 	free(pr);
1335*7c478bd9Sstevel@tonic-gate }
1336*7c478bd9Sstevel@tonic-gate 
1337*7c478bd9Sstevel@tonic-gate /*
1338*7c478bd9Sstevel@tonic-gate  * Toggle one or more IFF_ flags for a prefix. Turn on 'onflags' and
1339*7c478bd9Sstevel@tonic-gate  * turn off 'offflags'.
1340*7c478bd9Sstevel@tonic-gate  */
1341*7c478bd9Sstevel@tonic-gate static int
1342*7c478bd9Sstevel@tonic-gate prefix_modify_flags(struct prefix *pr, uint64_t onflags, uint64_t offflags)
1343*7c478bd9Sstevel@tonic-gate {
1344*7c478bd9Sstevel@tonic-gate 	struct lifreq lifr;
1345*7c478bd9Sstevel@tonic-gate 	struct phyint *pi = pr->pr_physical;
1346*7c478bd9Sstevel@tonic-gate 	uint64_t old_flags;
1347*7c478bd9Sstevel@tonic-gate 	char abuf[INET6_ADDRSTRLEN];
1348*7c478bd9Sstevel@tonic-gate 
1349*7c478bd9Sstevel@tonic-gate 	if (debug & D_PREFIX) {
1350*7c478bd9Sstevel@tonic-gate 		logmsg(LOG_DEBUG, "prefix_modify_flags(%s, %s, %s/%u) "
1351*7c478bd9Sstevel@tonic-gate 		    "flags %llx on %llx off %llx\n",
1352*7c478bd9Sstevel@tonic-gate 		    pr->pr_physical->pi_name,
1353*7c478bd9Sstevel@tonic-gate 		    pr->pr_name,
1354*7c478bd9Sstevel@tonic-gate 		    inet_ntop(AF_INET6, (void *)&pr->pr_prefix,
1355*7c478bd9Sstevel@tonic-gate 		    abuf, sizeof (abuf)), pr->pr_prefix_len,
1356*7c478bd9Sstevel@tonic-gate 		    pr->pr_flags, onflags, offflags);
1357*7c478bd9Sstevel@tonic-gate 	}
1358*7c478bd9Sstevel@tonic-gate 	/* Assumes that only the PR_STATIC link-local matches the pi_name */
1359*7c478bd9Sstevel@tonic-gate 	if (!(pr->pr_state & PR_STATIC) &&
1360*7c478bd9Sstevel@tonic-gate 	    strcmp(pr->pr_name, pi->pi_name) == 0) {
1361*7c478bd9Sstevel@tonic-gate 		logmsg(LOG_ERR, "prefix_modify_flags(%s, on %llx, off %llx): "
1362*7c478bd9Sstevel@tonic-gate 		    "name matches interface name\n",
1363*7c478bd9Sstevel@tonic-gate 		    pi->pi_name, onflags, offflags);
1364*7c478bd9Sstevel@tonic-gate 		return (-1);
1365*7c478bd9Sstevel@tonic-gate 	}
1366*7c478bd9Sstevel@tonic-gate 
1367*7c478bd9Sstevel@tonic-gate 	(void) strncpy(lifr.lifr_name, pr->pr_name, sizeof (lifr.lifr_name));
1368*7c478bd9Sstevel@tonic-gate 	lifr.lifr_name[sizeof (lifr.lifr_name) - 1] = '\0';
1369*7c478bd9Sstevel@tonic-gate 	if (ioctl(pi->pi_sock, SIOCGLIFFLAGS, (char *)&lifr) < 0) {
1370*7c478bd9Sstevel@tonic-gate 		logperror_pr(pr, "prefix_modify_flags: SIOCGLIFFLAGS");
1371*7c478bd9Sstevel@tonic-gate 		logmsg(LOG_ERR, "prefix_modify_flags(%s, %s) old 0x%llx "
1372*7c478bd9Sstevel@tonic-gate 		    "on 0x%llx off 0x%llx\n",
1373*7c478bd9Sstevel@tonic-gate 		    pr->pr_physical->pi_name,
1374*7c478bd9Sstevel@tonic-gate 		    pr->pr_name,
1375*7c478bd9Sstevel@tonic-gate 		    pr->pr_flags, onflags, offflags);
1376*7c478bd9Sstevel@tonic-gate 		return (-1);
1377*7c478bd9Sstevel@tonic-gate 	}
1378*7c478bd9Sstevel@tonic-gate 	old_flags = lifr.lifr_flags;
1379*7c478bd9Sstevel@tonic-gate 	lifr.lifr_flags |= onflags;
1380*7c478bd9Sstevel@tonic-gate 	lifr.lifr_flags &= ~offflags;
1381*7c478bd9Sstevel@tonic-gate 	pr->pr_flags = lifr.lifr_flags;
1382*7c478bd9Sstevel@tonic-gate 	if (ioctl(pi->pi_sock, SIOCSLIFFLAGS, (char *)&lifr) < 0) {
1383*7c478bd9Sstevel@tonic-gate 		logperror_pr(pr, "prefix_modify_flags: SIOCSLIFFLAGS");
1384*7c478bd9Sstevel@tonic-gate 		logmsg(LOG_ERR, "prefix_modify_flags(%s, %s) old 0x%llx "
1385*7c478bd9Sstevel@tonic-gate 		    "new 0x%llx on 0x%llx off 0x%llx\n",
1386*7c478bd9Sstevel@tonic-gate 		    pr->pr_physical->pi_name,
1387*7c478bd9Sstevel@tonic-gate 		    pr->pr_name,
1388*7c478bd9Sstevel@tonic-gate 		    old_flags, lifr.lifr_flags, onflags, offflags);
1389*7c478bd9Sstevel@tonic-gate 		return (-1);
1390*7c478bd9Sstevel@tonic-gate 	}
1391*7c478bd9Sstevel@tonic-gate 	return (0);
1392*7c478bd9Sstevel@tonic-gate }
1393*7c478bd9Sstevel@tonic-gate 
1394*7c478bd9Sstevel@tonic-gate /*
1395*7c478bd9Sstevel@tonic-gate  * Make the kernel state match what is in the prefix structure.
1396*7c478bd9Sstevel@tonic-gate  * This includes creating the prefix (allocating a new interface name)
1397*7c478bd9Sstevel@tonic-gate  * as well as setting the local address and on-link subnet prefix
1398*7c478bd9Sstevel@tonic-gate  * and controlling the IFF_ADDRCONF and IFF_DEPRECATED flags.
1399*7c478bd9Sstevel@tonic-gate  */
1400*7c478bd9Sstevel@tonic-gate void
1401*7c478bd9Sstevel@tonic-gate prefix_update_k(struct prefix *pr)
1402*7c478bd9Sstevel@tonic-gate {
1403*7c478bd9Sstevel@tonic-gate 	struct lifreq lifr;
1404*7c478bd9Sstevel@tonic-gate 	char abuf[INET6_ADDRSTRLEN];
1405*7c478bd9Sstevel@tonic-gate 	char buf1[PREFIX_STATESTRLEN], buf2[PREFIX_STATESTRLEN];
1406*7c478bd9Sstevel@tonic-gate 	struct phyint *pi = pr->pr_physical;
1407*7c478bd9Sstevel@tonic-gate 	struct sockaddr_in6 *sin6;
1408*7c478bd9Sstevel@tonic-gate 
1409*7c478bd9Sstevel@tonic-gate 	if (debug & D_PREFIX) {
1410*7c478bd9Sstevel@tonic-gate 		logmsg(LOG_DEBUG, "prefix_update_k(%s, %s, %s/%u) "
1411*7c478bd9Sstevel@tonic-gate 		    "from %s to %s\n", pr->pr_physical->pi_name, pr->pr_name,
1412*7c478bd9Sstevel@tonic-gate 		    inet_ntop(AF_INET6, (void *)&pr->pr_prefix,
1413*7c478bd9Sstevel@tonic-gate 		    abuf, sizeof (abuf)), pr->pr_prefix_len,
1414*7c478bd9Sstevel@tonic-gate 		    prefix_print_state(pr->pr_kernel_state, buf1,
1415*7c478bd9Sstevel@tonic-gate 		    sizeof (buf1)),
1416*7c478bd9Sstevel@tonic-gate 		    prefix_print_state(pr->pr_state, buf2, sizeof (buf2)));
1417*7c478bd9Sstevel@tonic-gate 	}
1418*7c478bd9Sstevel@tonic-gate 
1419*7c478bd9Sstevel@tonic-gate 	if (pr->pr_kernel_state == pr->pr_state)
1420*7c478bd9Sstevel@tonic-gate 		return;		/* No changes */
1421*7c478bd9Sstevel@tonic-gate 
1422*7c478bd9Sstevel@tonic-gate 	/* Skip static prefixes */
1423*7c478bd9Sstevel@tonic-gate 	if (pr->pr_state & PR_STATIC)
1424*7c478bd9Sstevel@tonic-gate 		return;
1425*7c478bd9Sstevel@tonic-gate 
1426*7c478bd9Sstevel@tonic-gate 	if (pr->pr_kernel_state == 0) {
1427*7c478bd9Sstevel@tonic-gate 		uint64_t onflags;
1428*7c478bd9Sstevel@tonic-gate 		/*
1429*7c478bd9Sstevel@tonic-gate 		 * Create a new logical interface name and store in pr_name.
1430*7c478bd9Sstevel@tonic-gate 		 * Set IFF_ADDRCONF. Do not set an address (yet).
1431*7c478bd9Sstevel@tonic-gate 		 */
1432*7c478bd9Sstevel@tonic-gate 		if (pr->pr_name[0] != '\0') {
1433*7c478bd9Sstevel@tonic-gate 			/* Name already set! */
1434*7c478bd9Sstevel@tonic-gate 			logmsg(LOG_ERR, "prefix_update_k(%s, %s, %s/%u) "
1435*7c478bd9Sstevel@tonic-gate 			    "from %s to %s name is already allocated\n",
1436*7c478bd9Sstevel@tonic-gate 			    pr->pr_physical->pi_name, pr->pr_name,
1437*7c478bd9Sstevel@tonic-gate 			    inet_ntop(AF_INET6, (void *)&pr->pr_prefix,
1438*7c478bd9Sstevel@tonic-gate 			    abuf, sizeof (abuf)), pr->pr_prefix_len,
1439*7c478bd9Sstevel@tonic-gate 			    prefix_print_state(pr->pr_kernel_state, buf1,
1440*7c478bd9Sstevel@tonic-gate 			    sizeof (buf1)),
1441*7c478bd9Sstevel@tonic-gate 			    prefix_print_state(pr->pr_state, buf2,
1442*7c478bd9Sstevel@tonic-gate 			    sizeof (buf2)));
1443*7c478bd9Sstevel@tonic-gate 			return;
1444*7c478bd9Sstevel@tonic-gate 		}
1445*7c478bd9Sstevel@tonic-gate 
1446*7c478bd9Sstevel@tonic-gate 		(void) strncpy(lifr.lifr_name, pi->pi_name,
1447*7c478bd9Sstevel@tonic-gate 		    sizeof (lifr.lifr_name));
1448*7c478bd9Sstevel@tonic-gate 		lifr.lifr_name[sizeof (lifr.lifr_name) - 1] = '\0';
1449*7c478bd9Sstevel@tonic-gate 		lifr.lifr_addr.ss_family = AF_UNSPEC;
1450*7c478bd9Sstevel@tonic-gate 		if (ioctl(pi->pi_sock, SIOCLIFADDIF, (char *)&lifr) < 0) {
1451*7c478bd9Sstevel@tonic-gate 			logperror_pr(pr, "prefix_update_k: SIOCLIFADDIF");
1452*7c478bd9Sstevel@tonic-gate 			return;
1453*7c478bd9Sstevel@tonic-gate 		}
1454*7c478bd9Sstevel@tonic-gate 		(void) strncpy(pr->pr_name, lifr.lifr_name,
1455*7c478bd9Sstevel@tonic-gate 		    sizeof (pr->pr_name));
1456*7c478bd9Sstevel@tonic-gate 		pr->pr_name[sizeof (pr->pr_name) - 1] = '\0';
1457*7c478bd9Sstevel@tonic-gate 		if (debug & D_PREFIX) {
1458*7c478bd9Sstevel@tonic-gate 			logmsg(LOG_DEBUG, "prefix_update_k: new name %s\n",
1459*7c478bd9Sstevel@tonic-gate 			    pr->pr_name);
1460*7c478bd9Sstevel@tonic-gate 		}
1461*7c478bd9Sstevel@tonic-gate 		/*
1462*7c478bd9Sstevel@tonic-gate 		 * The IFF_TEMPORARY flag might have already been set; if
1463*7c478bd9Sstevel@tonic-gate 		 * so, it needs to be or'd into the flags we're turning on.
1464*7c478bd9Sstevel@tonic-gate 		 * But be careful, we might be re-creating a manually
1465*7c478bd9Sstevel@tonic-gate 		 * removed interface, in which case we don't want to try
1466*7c478bd9Sstevel@tonic-gate 		 * to set *all* the flags we might have in our copy of the
1467*7c478bd9Sstevel@tonic-gate 		 * flags yet.
1468*7c478bd9Sstevel@tonic-gate 		 */
1469*7c478bd9Sstevel@tonic-gate 		onflags = IFF_ADDRCONF;
1470*7c478bd9Sstevel@tonic-gate 		if (pr->pr_flags & IFF_TEMPORARY)
1471*7c478bd9Sstevel@tonic-gate 			onflags |= IFF_TEMPORARY;
1472*7c478bd9Sstevel@tonic-gate 		if (prefix_modify_flags(pr, onflags, 0) == -1)
1473*7c478bd9Sstevel@tonic-gate 			return;
1474*7c478bd9Sstevel@tonic-gate 	}
1475*7c478bd9Sstevel@tonic-gate 	if ((pr->pr_state & (PR_ONLINK|PR_AUTO)) == 0) {
1476*7c478bd9Sstevel@tonic-gate 		/* Remove the interface */
1477*7c478bd9Sstevel@tonic-gate 		if (prefix_modify_flags(pr, 0, IFF_UP|IFF_DEPRECATED) == -1)
1478*7c478bd9Sstevel@tonic-gate 			return;
1479*7c478bd9Sstevel@tonic-gate 		(void) strncpy(lifr.lifr_name, pr->pr_name,
1480*7c478bd9Sstevel@tonic-gate 		    sizeof (lifr.lifr_name));
1481*7c478bd9Sstevel@tonic-gate 		lifr.lifr_name[sizeof (lifr.lifr_name) - 1] = '\0';
1482*7c478bd9Sstevel@tonic-gate 
1483*7c478bd9Sstevel@tonic-gate 		if (debug & D_PREFIX) {
1484*7c478bd9Sstevel@tonic-gate 			logmsg(LOG_DEBUG, "prefix_update_k: remove name %s\n",
1485*7c478bd9Sstevel@tonic-gate 			    pr->pr_name);
1486*7c478bd9Sstevel@tonic-gate 		}
1487*7c478bd9Sstevel@tonic-gate 
1488*7c478bd9Sstevel@tonic-gate 		/*
1489*7c478bd9Sstevel@tonic-gate 		 * Assumes that only the PR_STATIC link-local matches
1490*7c478bd9Sstevel@tonic-gate 		 * the pi_name
1491*7c478bd9Sstevel@tonic-gate 		 */
1492*7c478bd9Sstevel@tonic-gate 		if (!(pr->pr_state & PR_STATIC) &&
1493*7c478bd9Sstevel@tonic-gate 		    strcmp(pr->pr_name, pi->pi_name) == 0) {
1494*7c478bd9Sstevel@tonic-gate 			logmsg(LOG_ERR, "prefix_update_k(%s): "
1495*7c478bd9Sstevel@tonic-gate 			    "name matches if\n", pi->pi_name);
1496*7c478bd9Sstevel@tonic-gate 			return;
1497*7c478bd9Sstevel@tonic-gate 		}
1498*7c478bd9Sstevel@tonic-gate 
1499*7c478bd9Sstevel@tonic-gate 		/* Remove logical interface based on pr_name */
1500*7c478bd9Sstevel@tonic-gate 		lifr.lifr_addr.ss_family = AF_UNSPEC;
1501*7c478bd9Sstevel@tonic-gate 		if (ioctl(pi->pi_sock, SIOCLIFREMOVEIF, (char *)&lifr) < 0) {
1502*7c478bd9Sstevel@tonic-gate 			logperror_pr(pr, "prefix_update_k: SIOCLIFREMOVEIF");
1503*7c478bd9Sstevel@tonic-gate 		}
1504*7c478bd9Sstevel@tonic-gate 		pr->pr_kernel_state = 0;
1505*7c478bd9Sstevel@tonic-gate 		pr->pr_name[0] = '\0';
1506*7c478bd9Sstevel@tonic-gate 		return;
1507*7c478bd9Sstevel@tonic-gate 	}
1508*7c478bd9Sstevel@tonic-gate 	if ((pr->pr_state & PR_AUTO) && !(pr->pr_kernel_state & PR_AUTO)) {
1509*7c478bd9Sstevel@tonic-gate 		/*
1510*7c478bd9Sstevel@tonic-gate 		 * Set local address and set the prefix length to 128.
1511*7c478bd9Sstevel@tonic-gate 		 * Turn off IFF_NOLOCAL in case it was set.
1512*7c478bd9Sstevel@tonic-gate 		 * Turn on IFF_UP.
1513*7c478bd9Sstevel@tonic-gate 		 */
1514*7c478bd9Sstevel@tonic-gate 		(void) strncpy(lifr.lifr_name, pr->pr_name,
1515*7c478bd9Sstevel@tonic-gate 		    sizeof (lifr.lifr_name));
1516*7c478bd9Sstevel@tonic-gate 		lifr.lifr_name[sizeof (lifr.lifr_name) - 1] = '\0';
1517*7c478bd9Sstevel@tonic-gate 		sin6 = (struct sockaddr_in6 *)&lifr.lifr_addr;
1518*7c478bd9Sstevel@tonic-gate 		bzero(sin6, sizeof (struct sockaddr_in6));
1519*7c478bd9Sstevel@tonic-gate 		sin6->sin6_family = AF_INET6;
1520*7c478bd9Sstevel@tonic-gate 		sin6->sin6_addr = pr->pr_address;
1521*7c478bd9Sstevel@tonic-gate 		if (debug & D_PREFIX) {
1522*7c478bd9Sstevel@tonic-gate 			logmsg(LOG_DEBUG, "prefix_update_k(%s) set addr %s "
1523*7c478bd9Sstevel@tonic-gate 			    "for PR_AUTO on\n",
1524*7c478bd9Sstevel@tonic-gate 			    pr->pr_name,
1525*7c478bd9Sstevel@tonic-gate 			    inet_ntop(AF_INET6, (void *)&pr->pr_address,
1526*7c478bd9Sstevel@tonic-gate 				abuf, sizeof (abuf)));
1527*7c478bd9Sstevel@tonic-gate 		}
1528*7c478bd9Sstevel@tonic-gate 		if (ioctl(pi->pi_sock, SIOCSLIFADDR, (char *)&lifr) < 0) {
1529*7c478bd9Sstevel@tonic-gate 			logperror_pr(pr, "prefix_update_k: SIOCSLIFADDR");
1530*7c478bd9Sstevel@tonic-gate 			return;
1531*7c478bd9Sstevel@tonic-gate 		}
1532*7c478bd9Sstevel@tonic-gate 		if (pr->pr_state & PR_ONLINK) {
1533*7c478bd9Sstevel@tonic-gate 			sin6->sin6_addr = pr->pr_prefix;
1534*7c478bd9Sstevel@tonic-gate 			lifr.lifr_addrlen = pr->pr_prefix_len;
1535*7c478bd9Sstevel@tonic-gate 		} else {
1536*7c478bd9Sstevel@tonic-gate 			sin6->sin6_addr = pr->pr_address;
1537*7c478bd9Sstevel@tonic-gate 			lifr.lifr_addrlen = IPV6_ABITS;
1538*7c478bd9Sstevel@tonic-gate 		}
1539*7c478bd9Sstevel@tonic-gate 		if (debug & D_PREFIX) {
1540*7c478bd9Sstevel@tonic-gate 			logmsg(LOG_DEBUG, "prefix_update_k(%s) set subnet "
1541*7c478bd9Sstevel@tonic-gate 			    "%s/%u for PR_AUTO on\n", pr->pr_name,
1542*7c478bd9Sstevel@tonic-gate 			    inet_ntop(AF_INET6, (void *)&sin6->sin6_addr,
1543*7c478bd9Sstevel@tonic-gate 				abuf, sizeof (abuf)), lifr.lifr_addrlen);
1544*7c478bd9Sstevel@tonic-gate 		}
1545*7c478bd9Sstevel@tonic-gate 		if (ioctl(pi->pi_sock, SIOCSLIFSUBNET, (char *)&lifr) < 0) {
1546*7c478bd9Sstevel@tonic-gate 			logperror_pr(pr, "prefix_update_k: SIOCSLIFSUBNET");
1547*7c478bd9Sstevel@tonic-gate 			return;
1548*7c478bd9Sstevel@tonic-gate 		}
1549*7c478bd9Sstevel@tonic-gate 		/*
1550*7c478bd9Sstevel@tonic-gate 		 * For ptp interfaces, create a destination based on
1551*7c478bd9Sstevel@tonic-gate 		 * prefix and prefix len together with the remote token
1552*7c478bd9Sstevel@tonic-gate 		 * extracted from the remote pt-pt address.  This is used by
1553*7c478bd9Sstevel@tonic-gate 		 * ip to choose a proper source for outgoing packets.
1554*7c478bd9Sstevel@tonic-gate 		 */
1555*7c478bd9Sstevel@tonic-gate 		if (pi->pi_flags & IFF_POINTOPOINT) {
1556*7c478bd9Sstevel@tonic-gate 			int i;
1557*7c478bd9Sstevel@tonic-gate 
1558*7c478bd9Sstevel@tonic-gate 			sin6 = (struct sockaddr_in6 *)&lifr.lifr_addr;
1559*7c478bd9Sstevel@tonic-gate 			bzero(sin6, sizeof (struct sockaddr_in6));
1560*7c478bd9Sstevel@tonic-gate 			sin6->sin6_family = AF_INET6;
1561*7c478bd9Sstevel@tonic-gate 			sin6->sin6_addr = pr->pr_prefix;
1562*7c478bd9Sstevel@tonic-gate 			for (i = 0; i < 16; i++) {
1563*7c478bd9Sstevel@tonic-gate 				sin6->sin6_addr.s6_addr[i] |=
1564*7c478bd9Sstevel@tonic-gate 				    pi->pi_dst_token.s6_addr[i];
1565*7c478bd9Sstevel@tonic-gate 			}
1566*7c478bd9Sstevel@tonic-gate 			if (debug & D_PREFIX) {
1567*7c478bd9Sstevel@tonic-gate 				logmsg(LOG_DEBUG, "prefix_update_k(%s) "
1568*7c478bd9Sstevel@tonic-gate 				    "set dstaddr %s for PR_AUTO on\n",
1569*7c478bd9Sstevel@tonic-gate 				    pr->pr_name, inet_ntop(AF_INET6,
1570*7c478bd9Sstevel@tonic-gate 				    (void *)&sin6->sin6_addr,
1571*7c478bd9Sstevel@tonic-gate 				    abuf, sizeof (abuf)));
1572*7c478bd9Sstevel@tonic-gate 			}
1573*7c478bd9Sstevel@tonic-gate 			if (ioctl(pi->pi_sock, SIOCSLIFDSTADDR,
1574*7c478bd9Sstevel@tonic-gate 			    (char *)&lifr) < 0) {
1575*7c478bd9Sstevel@tonic-gate 				logperror_pr(pr,
1576*7c478bd9Sstevel@tonic-gate 				    "prefix_update_k: SIOCSLIFDSTADDR");
1577*7c478bd9Sstevel@tonic-gate 				return;
1578*7c478bd9Sstevel@tonic-gate 			}
1579*7c478bd9Sstevel@tonic-gate 		}
1580*7c478bd9Sstevel@tonic-gate 		if (prefix_modify_flags(pr, IFF_UP, IFF_NOLOCAL) == -1)
1581*7c478bd9Sstevel@tonic-gate 			return;
1582*7c478bd9Sstevel@tonic-gate 		pr->pr_kernel_state |= PR_AUTO;
1583*7c478bd9Sstevel@tonic-gate 		if (pr->pr_state & PR_ONLINK)
1584*7c478bd9Sstevel@tonic-gate 			pr->pr_kernel_state |= PR_ONLINK;
1585*7c478bd9Sstevel@tonic-gate 		else
1586*7c478bd9Sstevel@tonic-gate 			pr->pr_kernel_state &= ~PR_ONLINK;
1587*7c478bd9Sstevel@tonic-gate 	}
1588*7c478bd9Sstevel@tonic-gate 	if (!(pr->pr_state & PR_AUTO) && (pr->pr_kernel_state & PR_AUTO)) {
1589*7c478bd9Sstevel@tonic-gate 		/* Turn on IFF_NOLOCAL and set the local address to all zero */
1590*7c478bd9Sstevel@tonic-gate 		if (prefix_modify_flags(pr, IFF_NOLOCAL, 0) == -1)
1591*7c478bd9Sstevel@tonic-gate 			return;
1592*7c478bd9Sstevel@tonic-gate 		(void) strncpy(lifr.lifr_name, pr->pr_name,
1593*7c478bd9Sstevel@tonic-gate 		    sizeof (lifr.lifr_name));
1594*7c478bd9Sstevel@tonic-gate 		lifr.lifr_name[sizeof (lifr.lifr_name) - 1] = '\0';
1595*7c478bd9Sstevel@tonic-gate 		sin6 = (struct sockaddr_in6 *)&lifr.lifr_addr;
1596*7c478bd9Sstevel@tonic-gate 		bzero(sin6, sizeof (struct sockaddr_in6));
1597*7c478bd9Sstevel@tonic-gate 		sin6->sin6_family = AF_INET6;
1598*7c478bd9Sstevel@tonic-gate 		if (debug & D_PREFIX) {
1599*7c478bd9Sstevel@tonic-gate 			logmsg(LOG_DEBUG, "prefix_update_k(%s) set addr %s "
1600*7c478bd9Sstevel@tonic-gate 			    "for PR_AUTO off\n", pr->pr_name,
1601*7c478bd9Sstevel@tonic-gate 			    inet_ntop(AF_INET6, (void *)&sin6->sin6_addr,
1602*7c478bd9Sstevel@tonic-gate 				abuf, sizeof (abuf)));
1603*7c478bd9Sstevel@tonic-gate 		}
1604*7c478bd9Sstevel@tonic-gate 		if (ioctl(pi->pi_sock, SIOCSLIFADDR, (char *)&lifr) < 0) {
1605*7c478bd9Sstevel@tonic-gate 			logperror_pr(pr, "prefix_update_k: SIOCSLIFADDR");
1606*7c478bd9Sstevel@tonic-gate 			return;
1607*7c478bd9Sstevel@tonic-gate 		}
1608*7c478bd9Sstevel@tonic-gate 		pr->pr_kernel_state &= ~PR_AUTO;
1609*7c478bd9Sstevel@tonic-gate 	}
1610*7c478bd9Sstevel@tonic-gate 	if ((pr->pr_state & PR_DEPRECATED) &&
1611*7c478bd9Sstevel@tonic-gate 	    !(pr->pr_kernel_state & PR_DEPRECATED) &&
1612*7c478bd9Sstevel@tonic-gate 	    (pr->pr_kernel_state & PR_AUTO)) {
1613*7c478bd9Sstevel@tonic-gate 		/* Only applies if PR_AUTO */
1614*7c478bd9Sstevel@tonic-gate 		if (prefix_modify_flags(pr, IFF_DEPRECATED, 0) == -1)
1615*7c478bd9Sstevel@tonic-gate 			return;
1616*7c478bd9Sstevel@tonic-gate 		pr->pr_kernel_state |= PR_DEPRECATED;
1617*7c478bd9Sstevel@tonic-gate 	}
1618*7c478bd9Sstevel@tonic-gate 	if (!(pr->pr_state & PR_DEPRECATED) &&
1619*7c478bd9Sstevel@tonic-gate 	    (pr->pr_kernel_state & PR_DEPRECATED)) {
1620*7c478bd9Sstevel@tonic-gate 		if (prefix_modify_flags(pr, 0, IFF_DEPRECATED) == -1)
1621*7c478bd9Sstevel@tonic-gate 			return;
1622*7c478bd9Sstevel@tonic-gate 		pr->pr_kernel_state &= ~PR_DEPRECATED;
1623*7c478bd9Sstevel@tonic-gate 	}
1624*7c478bd9Sstevel@tonic-gate 	if ((pr->pr_state & PR_ONLINK) && !(pr->pr_kernel_state & PR_ONLINK)) {
1625*7c478bd9Sstevel@tonic-gate 		/* Set the subnet and set IFF_UP */
1626*7c478bd9Sstevel@tonic-gate 		(void) strncpy(lifr.lifr_name, pr->pr_name,
1627*7c478bd9Sstevel@tonic-gate 		    sizeof (lifr.lifr_name));
1628*7c478bd9Sstevel@tonic-gate 		lifr.lifr_name[sizeof (lifr.lifr_name) - 1] = '\0';
1629*7c478bd9Sstevel@tonic-gate 		sin6 = (struct sockaddr_in6 *)&lifr.lifr_addr;
1630*7c478bd9Sstevel@tonic-gate 		bzero(sin6, sizeof (struct sockaddr_in6));
1631*7c478bd9Sstevel@tonic-gate 		sin6->sin6_family = AF_INET6;
1632*7c478bd9Sstevel@tonic-gate 		sin6->sin6_addr = pr->pr_prefix;
1633*7c478bd9Sstevel@tonic-gate 		lifr.lifr_addrlen = pr->pr_prefix_len;
1634*7c478bd9Sstevel@tonic-gate 		if (debug & D_PREFIX) {
1635*7c478bd9Sstevel@tonic-gate 			logmsg(LOG_DEBUG, "prefix_update_k(%s) set subnet "
1636*7c478bd9Sstevel@tonic-gate 			    "%s/%d for PR_ONLINK on\n", pr->pr_name,
1637*7c478bd9Sstevel@tonic-gate 			    inet_ntop(AF_INET6, (void *)&sin6->sin6_addr,
1638*7c478bd9Sstevel@tonic-gate 				abuf, sizeof (abuf)), lifr.lifr_addrlen);
1639*7c478bd9Sstevel@tonic-gate 		}
1640*7c478bd9Sstevel@tonic-gate 		if (ioctl(pi->pi_sock, SIOCSLIFSUBNET, (char *)&lifr) < 0) {
1641*7c478bd9Sstevel@tonic-gate 			logperror_pr(pr, "prefix_update_k: SIOCSLIFSUBNET");
1642*7c478bd9Sstevel@tonic-gate 			return;
1643*7c478bd9Sstevel@tonic-gate 		}
1644*7c478bd9Sstevel@tonic-gate 		if (!(pr->pr_state & PR_AUTO)) {
1645*7c478bd9Sstevel@tonic-gate 			if (prefix_modify_flags(pr, IFF_NOLOCAL, 0) == -1)
1646*7c478bd9Sstevel@tonic-gate 				return;
1647*7c478bd9Sstevel@tonic-gate 		}
1648*7c478bd9Sstevel@tonic-gate 		if (prefix_modify_flags(pr, IFF_UP, 0) == -1)
1649*7c478bd9Sstevel@tonic-gate 			return;
1650*7c478bd9Sstevel@tonic-gate 		pr->pr_kernel_state |= PR_ONLINK;
1651*7c478bd9Sstevel@tonic-gate 	}
1652*7c478bd9Sstevel@tonic-gate 	if (!(pr->pr_state & PR_ONLINK) && (pr->pr_kernel_state & PR_ONLINK)) {
1653*7c478bd9Sstevel@tonic-gate 		/* Set the prefixlen to 128 */
1654*7c478bd9Sstevel@tonic-gate 		(void) strncpy(lifr.lifr_name, pr->pr_name,
1655*7c478bd9Sstevel@tonic-gate 		    sizeof (lifr.lifr_name));
1656*7c478bd9Sstevel@tonic-gate 		lifr.lifr_name[sizeof (lifr.lifr_name) - 1] = '\0';
1657*7c478bd9Sstevel@tonic-gate 		sin6 = (struct sockaddr_in6 *)&lifr.lifr_addr;
1658*7c478bd9Sstevel@tonic-gate 		bzero(sin6, sizeof (struct sockaddr_in6));
1659*7c478bd9Sstevel@tonic-gate 		sin6->sin6_family = AF_INET6;
1660*7c478bd9Sstevel@tonic-gate 		sin6->sin6_addr = pr->pr_address;
1661*7c478bd9Sstevel@tonic-gate 		lifr.lifr_addrlen = IPV6_ABITS;
1662*7c478bd9Sstevel@tonic-gate 		if (debug & D_PREFIX) {
1663*7c478bd9Sstevel@tonic-gate 			logmsg(LOG_DEBUG, "prefix_update_k(%s) set subnet "
1664*7c478bd9Sstevel@tonic-gate 			    "%s/%d for PR_ONLINK off\n", pr->pr_name,
1665*7c478bd9Sstevel@tonic-gate 			    inet_ntop(AF_INET6, (void *)&sin6->sin6_addr,
1666*7c478bd9Sstevel@tonic-gate 				abuf, sizeof (abuf)), lifr.lifr_addrlen);
1667*7c478bd9Sstevel@tonic-gate 		}
1668*7c478bd9Sstevel@tonic-gate 		if (ioctl(pi->pi_sock, SIOCSLIFSUBNET, (char *)&lifr) < 0) {
1669*7c478bd9Sstevel@tonic-gate 			logperror_pr(pr, "prefix_update_k: SIOCSLIFSUBNET");
1670*7c478bd9Sstevel@tonic-gate 			return;
1671*7c478bd9Sstevel@tonic-gate 		}
1672*7c478bd9Sstevel@tonic-gate 		pr->pr_kernel_state &= ~PR_ONLINK;
1673*7c478bd9Sstevel@tonic-gate 	}
1674*7c478bd9Sstevel@tonic-gate }
1675*7c478bd9Sstevel@tonic-gate 
1676*7c478bd9Sstevel@tonic-gate /*
1677*7c478bd9Sstevel@tonic-gate  * Called with the number of millseconds elapsed since the last call.
1678*7c478bd9Sstevel@tonic-gate  * Determines if any timeout event has occurred and
1679*7c478bd9Sstevel@tonic-gate  * returns the number of milliseconds until the next timeout event.
1680*7c478bd9Sstevel@tonic-gate  * Returns TIMER_INFINITY for "never".
1681*7c478bd9Sstevel@tonic-gate  */
1682*7c478bd9Sstevel@tonic-gate uint_t
1683*7c478bd9Sstevel@tonic-gate prefix_timer(struct prefix *pr, uint_t elapsed)
1684*7c478bd9Sstevel@tonic-gate {
1685*7c478bd9Sstevel@tonic-gate 	uint_t next = TIMER_INFINITY;
1686*7c478bd9Sstevel@tonic-gate 	char abuf[INET6_ADDRSTRLEN];
1687*7c478bd9Sstevel@tonic-gate 
1688*7c478bd9Sstevel@tonic-gate 	if (debug & (D_PREFIX|D_TMP)) {
1689*7c478bd9Sstevel@tonic-gate 		logmsg(LOG_DEBUG, "prefix_timer(%s, %s/%u, %d) "
1690*7c478bd9Sstevel@tonic-gate 		    "valid %d pref %d onlink %d\n",
1691*7c478bd9Sstevel@tonic-gate 		    pr->pr_name,
1692*7c478bd9Sstevel@tonic-gate 		    inet_ntop(AF_INET6, (void *)&pr->pr_prefix,
1693*7c478bd9Sstevel@tonic-gate 		    abuf, sizeof (abuf)), pr->pr_prefix_len,
1694*7c478bd9Sstevel@tonic-gate 		    elapsed, pr->pr_ValidLifetime, pr->pr_PreferredLifetime,
1695*7c478bd9Sstevel@tonic-gate 		    pr->pr_OnLinkLifetime);
1696*7c478bd9Sstevel@tonic-gate 	}
1697*7c478bd9Sstevel@tonic-gate 
1698*7c478bd9Sstevel@tonic-gate 	/* Exclude static prefixes */
1699*7c478bd9Sstevel@tonic-gate 	if (pr->pr_state & PR_STATIC)
1700*7c478bd9Sstevel@tonic-gate 		return (next);
1701*7c478bd9Sstevel@tonic-gate 
1702*7c478bd9Sstevel@tonic-gate 	if (pr->pr_AutonomousFlag &&
1703*7c478bd9Sstevel@tonic-gate 	    (pr->pr_PreferredLifetime != PREFIX_INFINITY)) {
1704*7c478bd9Sstevel@tonic-gate 		if (pr->pr_PreferredLifetime <= elapsed) {
1705*7c478bd9Sstevel@tonic-gate 			pr->pr_PreferredLifetime = 0;
1706*7c478bd9Sstevel@tonic-gate 		} else {
1707*7c478bd9Sstevel@tonic-gate 			pr->pr_PreferredLifetime -= elapsed;
1708*7c478bd9Sstevel@tonic-gate 			if (pr->pr_PreferredLifetime < next)
1709*7c478bd9Sstevel@tonic-gate 				next = pr->pr_PreferredLifetime;
1710*7c478bd9Sstevel@tonic-gate 		}
1711*7c478bd9Sstevel@tonic-gate 	}
1712*7c478bd9Sstevel@tonic-gate 	if (pr->pr_AutonomousFlag &&
1713*7c478bd9Sstevel@tonic-gate 	    (pr->pr_ValidLifetime != PREFIX_INFINITY)) {
1714*7c478bd9Sstevel@tonic-gate 		if (pr->pr_ValidLifetime <= elapsed) {
1715*7c478bd9Sstevel@tonic-gate 			pr->pr_ValidLifetime = 0;
1716*7c478bd9Sstevel@tonic-gate 		} else {
1717*7c478bd9Sstevel@tonic-gate 			pr->pr_ValidLifetime -= elapsed;
1718*7c478bd9Sstevel@tonic-gate 			if (pr->pr_ValidLifetime < next)
1719*7c478bd9Sstevel@tonic-gate 				next = pr->pr_ValidLifetime;
1720*7c478bd9Sstevel@tonic-gate 		}
1721*7c478bd9Sstevel@tonic-gate 	}
1722*7c478bd9Sstevel@tonic-gate 	if (pr->pr_OnLinkFlag &&
1723*7c478bd9Sstevel@tonic-gate 	    (pr->pr_OnLinkLifetime != PREFIX_INFINITY)) {
1724*7c478bd9Sstevel@tonic-gate 		if (pr->pr_OnLinkLifetime <= elapsed) {
1725*7c478bd9Sstevel@tonic-gate 			pr->pr_OnLinkLifetime = 0;
1726*7c478bd9Sstevel@tonic-gate 		} else {
1727*7c478bd9Sstevel@tonic-gate 			pr->pr_OnLinkLifetime -= elapsed;
1728*7c478bd9Sstevel@tonic-gate 			if (pr->pr_OnLinkLifetime < next)
1729*7c478bd9Sstevel@tonic-gate 				next = pr->pr_OnLinkLifetime;
1730*7c478bd9Sstevel@tonic-gate 		}
1731*7c478bd9Sstevel@tonic-gate 	}
1732*7c478bd9Sstevel@tonic-gate 	if (pr->pr_AutonomousFlag && pr->pr_ValidLifetime == 0)
1733*7c478bd9Sstevel@tonic-gate 		pr->pr_state &= ~(PR_AUTO|PR_DEPRECATED);
1734*7c478bd9Sstevel@tonic-gate 	if (pr->pr_AutonomousFlag && pr->pr_PreferredLifetime == 0 &&
1735*7c478bd9Sstevel@tonic-gate 	    (pr->pr_state & PR_AUTO)) {
1736*7c478bd9Sstevel@tonic-gate 		pr->pr_state |= PR_DEPRECATED;
1737*7c478bd9Sstevel@tonic-gate 		if (debug & D_TMP)
1738*7c478bd9Sstevel@tonic-gate 			logmsg(LOG_WARNING, "prefix_timer: deprecated "
1739*7c478bd9Sstevel@tonic-gate 			    "prefix(%s)\n", pr->pr_name);
1740*7c478bd9Sstevel@tonic-gate 	}
1741*7c478bd9Sstevel@tonic-gate 	if (pr->pr_OnLinkFlag && pr->pr_OnLinkLifetime == 0)
1742*7c478bd9Sstevel@tonic-gate 		pr->pr_state &= ~PR_ONLINK;
1743*7c478bd9Sstevel@tonic-gate 
1744*7c478bd9Sstevel@tonic-gate 	if (pr->pr_state != pr->pr_kernel_state) {
1745*7c478bd9Sstevel@tonic-gate 		/* Might cause prefix to be deleted! */
1746*7c478bd9Sstevel@tonic-gate 
1747*7c478bd9Sstevel@tonic-gate 		/* Log a message when an addrconf prefix goes away */
1748*7c478bd9Sstevel@tonic-gate 		if ((pr->pr_kernel_state & PR_AUTO) &&
1749*7c478bd9Sstevel@tonic-gate 		    !(pr->pr_state & PR_AUTO)) {
1750*7c478bd9Sstevel@tonic-gate 			char abuf[INET6_ADDRSTRLEN];
1751*7c478bd9Sstevel@tonic-gate 
1752*7c478bd9Sstevel@tonic-gate 			logmsg(LOG_WARNING,
1753*7c478bd9Sstevel@tonic-gate 			    "Address removed due to timeout %s\n",
1754*7c478bd9Sstevel@tonic-gate 			    inet_ntop(AF_INET6, (void *)&pr->pr_address,
1755*7c478bd9Sstevel@tonic-gate 			    abuf, sizeof (abuf)));
1756*7c478bd9Sstevel@tonic-gate 		}
1757*7c478bd9Sstevel@tonic-gate 		prefix_update_k(pr);
1758*7c478bd9Sstevel@tonic-gate 	}
1759*7c478bd9Sstevel@tonic-gate 
1760*7c478bd9Sstevel@tonic-gate 	return (next);
1761*7c478bd9Sstevel@tonic-gate }
1762*7c478bd9Sstevel@tonic-gate 
1763*7c478bd9Sstevel@tonic-gate static char *
1764*7c478bd9Sstevel@tonic-gate prefix_print_state(int state, char *buf, int buflen)
1765*7c478bd9Sstevel@tonic-gate {
1766*7c478bd9Sstevel@tonic-gate 	char *cp;
1767*7c478bd9Sstevel@tonic-gate 	int cplen = buflen;
1768*7c478bd9Sstevel@tonic-gate 
1769*7c478bd9Sstevel@tonic-gate 	cp = buf;
1770*7c478bd9Sstevel@tonic-gate 	cp[0] = '\0';
1771*7c478bd9Sstevel@tonic-gate 
1772*7c478bd9Sstevel@tonic-gate 	if (state & PR_ONLINK) {
1773*7c478bd9Sstevel@tonic-gate 		if (strlcat(cp, "ONLINK ", cplen) >= cplen)
1774*7c478bd9Sstevel@tonic-gate 			return (buf);
1775*7c478bd9Sstevel@tonic-gate 		cp += strlen(cp);
1776*7c478bd9Sstevel@tonic-gate 		cplen = buflen - (cp - buf);
1777*7c478bd9Sstevel@tonic-gate 	}
1778*7c478bd9Sstevel@tonic-gate 	if (state & PR_AUTO) {
1779*7c478bd9Sstevel@tonic-gate 		if (strlcat(cp, "AUTO ", cplen) >= cplen)
1780*7c478bd9Sstevel@tonic-gate 			return (buf);
1781*7c478bd9Sstevel@tonic-gate 		cp += strlen(cp);
1782*7c478bd9Sstevel@tonic-gate 		cplen = buflen - (cp - buf);
1783*7c478bd9Sstevel@tonic-gate 	}
1784*7c478bd9Sstevel@tonic-gate 	if (state & PR_DEPRECATED) {
1785*7c478bd9Sstevel@tonic-gate 		if (strlcat(cp, "DEPRECATED ", cplen) >= cplen)
1786*7c478bd9Sstevel@tonic-gate 			return (buf);
1787*7c478bd9Sstevel@tonic-gate 		cp += strlen(cp);
1788*7c478bd9Sstevel@tonic-gate 		cplen = buflen - (cp - buf);
1789*7c478bd9Sstevel@tonic-gate 	}
1790*7c478bd9Sstevel@tonic-gate 	if (state & PR_STATIC) {
1791*7c478bd9Sstevel@tonic-gate 		if (strlcat(cp, "STATIC ", cplen) >= cplen)
1792*7c478bd9Sstevel@tonic-gate 			return (buf);
1793*7c478bd9Sstevel@tonic-gate 		cp += strlen(cp);
1794*7c478bd9Sstevel@tonic-gate 		cplen = buflen - (cp - buf);
1795*7c478bd9Sstevel@tonic-gate 	}
1796*7c478bd9Sstevel@tonic-gate 	return (buf);
1797*7c478bd9Sstevel@tonic-gate }
1798*7c478bd9Sstevel@tonic-gate 
1799*7c478bd9Sstevel@tonic-gate static void
1800*7c478bd9Sstevel@tonic-gate prefix_print(struct prefix *pr)
1801*7c478bd9Sstevel@tonic-gate {
1802*7c478bd9Sstevel@tonic-gate 	char abuf[INET6_ADDRSTRLEN];
1803*7c478bd9Sstevel@tonic-gate 	char buf1[PREFIX_STATESTRLEN], buf2[PREFIX_STATESTRLEN];
1804*7c478bd9Sstevel@tonic-gate 
1805*7c478bd9Sstevel@tonic-gate 	logmsg(LOG_DEBUG, "Prefix name: %s prefix %s/%u state %s "
1806*7c478bd9Sstevel@tonic-gate 	    "kernel_state %s\n", pr->pr_name,
1807*7c478bd9Sstevel@tonic-gate 	    inet_ntop(AF_INET6, (void *)&pr->pr_prefix, abuf, sizeof (abuf)),
1808*7c478bd9Sstevel@tonic-gate 	    pr->pr_prefix_len,
1809*7c478bd9Sstevel@tonic-gate 	    prefix_print_state(pr->pr_state, buf2, sizeof (buf2)),
1810*7c478bd9Sstevel@tonic-gate 	    prefix_print_state(pr->pr_kernel_state, buf1, sizeof (buf1)));
1811*7c478bd9Sstevel@tonic-gate 	logmsg(LOG_DEBUG, "\tAddress: %s flags %llx in_use %d\n",
1812*7c478bd9Sstevel@tonic-gate 	    inet_ntop(AF_INET6, (void *)&pr->pr_address, abuf, sizeof (abuf)),
1813*7c478bd9Sstevel@tonic-gate 	    pr->pr_flags, pr->pr_in_use);
1814*7c478bd9Sstevel@tonic-gate 	logmsg(LOG_DEBUG, "\tValidLifetime %u PreferredLifetime %u "
1815*7c478bd9Sstevel@tonic-gate 	    "OnLinkLifetime %u\n", pr->pr_ValidLifetime,
1816*7c478bd9Sstevel@tonic-gate 	    pr->pr_PreferredLifetime, pr->pr_OnLinkLifetime);
1817*7c478bd9Sstevel@tonic-gate 	logmsg(LOG_DEBUG, "\tOnLink %d Auto %d\n",
1818*7c478bd9Sstevel@tonic-gate 	    pr->pr_OnLinkFlag, pr->pr_AutonomousFlag);
1819*7c478bd9Sstevel@tonic-gate 	logmsg(LOG_DEBUG, "\n");
1820*7c478bd9Sstevel@tonic-gate }
1821*7c478bd9Sstevel@tonic-gate 
1822*7c478bd9Sstevel@tonic-gate /*
1823*7c478bd9Sstevel@tonic-gate  * Does the address formed by pr->pr_prefix and pi->pi_token match
1824*7c478bd9Sstevel@tonic-gate  * pr->pr_address. It does not match if a failover has happened
1825*7c478bd9Sstevel@tonic-gate  * earlier (done by in.mpathd) from a different pi. Should not
1826*7c478bd9Sstevel@tonic-gate  * be called for onlink prefixes.
1827*7c478bd9Sstevel@tonic-gate  */
1828*7c478bd9Sstevel@tonic-gate boolean_t
1829*7c478bd9Sstevel@tonic-gate prefix_token_match(struct phyint *pi, struct prefix *pr, uint64_t flags)
1830*7c478bd9Sstevel@tonic-gate {
1831*7c478bd9Sstevel@tonic-gate 	int i;
1832*7c478bd9Sstevel@tonic-gate 	in6_addr_t addr, *token;
1833*7c478bd9Sstevel@tonic-gate 
1834*7c478bd9Sstevel@tonic-gate 	if (flags & IFF_TEMPORARY)
1835*7c478bd9Sstevel@tonic-gate 		token = &pi->pi_tmp_token;
1836*7c478bd9Sstevel@tonic-gate 	else
1837*7c478bd9Sstevel@tonic-gate 		token = &pi->pi_token;
1838*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < 16; i++) {
1839*7c478bd9Sstevel@tonic-gate 		/*
1840*7c478bd9Sstevel@tonic-gate 		 * prefix_create ensures that pr_prefix has all-zero
1841*7c478bd9Sstevel@tonic-gate 		 * bits after prefixlen.
1842*7c478bd9Sstevel@tonic-gate 		 */
1843*7c478bd9Sstevel@tonic-gate 		addr.s6_addr[i] = pr->pr_prefix.s6_addr[i] | token->s6_addr[i];
1844*7c478bd9Sstevel@tonic-gate 	}
1845*7c478bd9Sstevel@tonic-gate 	if (IN6_ARE_ADDR_EQUAL(&pr->pr_address, &addr)) {
1846*7c478bd9Sstevel@tonic-gate 		return (_B_TRUE);
1847*7c478bd9Sstevel@tonic-gate 	} else {
1848*7c478bd9Sstevel@tonic-gate 		return (_B_FALSE);
1849*7c478bd9Sstevel@tonic-gate 	}
1850*7c478bd9Sstevel@tonic-gate }
1851*7c478bd9Sstevel@tonic-gate 
1852*7c478bd9Sstevel@tonic-gate /*
1853*7c478bd9Sstevel@tonic-gate  * Lookup advertisement prefix structure that matches the prefix and
1854*7c478bd9Sstevel@tonic-gate  * prefix length.
1855*7c478bd9Sstevel@tonic-gate  * Assumes that the bits after prefixlen might not be zero.
1856*7c478bd9Sstevel@tonic-gate  */
1857*7c478bd9Sstevel@tonic-gate struct adv_prefix *
1858*7c478bd9Sstevel@tonic-gate adv_prefix_lookup(struct phyint *pi, struct in6_addr prefix, int prefixlen)
1859*7c478bd9Sstevel@tonic-gate {
1860*7c478bd9Sstevel@tonic-gate 	struct adv_prefix *adv_pr;
1861*7c478bd9Sstevel@tonic-gate 	char abuf[INET6_ADDRSTRLEN];
1862*7c478bd9Sstevel@tonic-gate 
1863*7c478bd9Sstevel@tonic-gate 	if (debug & D_PREFIX) {
1864*7c478bd9Sstevel@tonic-gate 		logmsg(LOG_DEBUG, "adv_prefix_lookup(%s, %s/%u)\n",
1865*7c478bd9Sstevel@tonic-gate 		    pi->pi_name, inet_ntop(AF_INET6, (void *)&prefix,
1866*7c478bd9Sstevel@tonic-gate 		    abuf, sizeof (abuf)), prefixlen);
1867*7c478bd9Sstevel@tonic-gate 	}
1868*7c478bd9Sstevel@tonic-gate 
1869*7c478bd9Sstevel@tonic-gate 	for (adv_pr = pi->pi_adv_prefix_list; adv_pr != NULL;
1870*7c478bd9Sstevel@tonic-gate 	    adv_pr = adv_pr->adv_pr_next) {
1871*7c478bd9Sstevel@tonic-gate 		if (adv_pr->adv_pr_prefix_len == prefixlen &&
1872*7c478bd9Sstevel@tonic-gate 		    prefix_equal(prefix, adv_pr->adv_pr_prefix, prefixlen))
1873*7c478bd9Sstevel@tonic-gate 			return (adv_pr);
1874*7c478bd9Sstevel@tonic-gate 	}
1875*7c478bd9Sstevel@tonic-gate 	return (NULL);
1876*7c478bd9Sstevel@tonic-gate }
1877*7c478bd9Sstevel@tonic-gate 
1878*7c478bd9Sstevel@tonic-gate /*
1879*7c478bd9Sstevel@tonic-gate  * Initialize a new advertisement prefix.
1880*7c478bd9Sstevel@tonic-gate  */
1881*7c478bd9Sstevel@tonic-gate struct adv_prefix *
1882*7c478bd9Sstevel@tonic-gate adv_prefix_create(struct phyint *pi, struct in6_addr prefix, int prefixlen)
1883*7c478bd9Sstevel@tonic-gate {
1884*7c478bd9Sstevel@tonic-gate 	struct adv_prefix *adv_pr;
1885*7c478bd9Sstevel@tonic-gate 	char abuf[INET6_ADDRSTRLEN];
1886*7c478bd9Sstevel@tonic-gate 
1887*7c478bd9Sstevel@tonic-gate 	if (debug & D_PREFIX) {
1888*7c478bd9Sstevel@tonic-gate 		logmsg(LOG_DEBUG, "adv_prefix_create(%s, %s/%u)\n",
1889*7c478bd9Sstevel@tonic-gate 		    pi->pi_name, inet_ntop(AF_INET6, (void *)&prefix,
1890*7c478bd9Sstevel@tonic-gate 		    abuf, sizeof (abuf)), prefixlen);
1891*7c478bd9Sstevel@tonic-gate 	}
1892*7c478bd9Sstevel@tonic-gate 	adv_pr = (struct adv_prefix *)calloc(sizeof (struct adv_prefix), 1);
1893*7c478bd9Sstevel@tonic-gate 	if (adv_pr == NULL) {
1894*7c478bd9Sstevel@tonic-gate 		logmsg(LOG_ERR, "adv_prefix_create: calloc\n");
1895*7c478bd9Sstevel@tonic-gate 		return (NULL);
1896*7c478bd9Sstevel@tonic-gate 	}
1897*7c478bd9Sstevel@tonic-gate 	/*
1898*7c478bd9Sstevel@tonic-gate 	 * The prefix might have non-zero bits after the prefix len bits.
1899*7c478bd9Sstevel@tonic-gate 	 * Force them to be zero.
1900*7c478bd9Sstevel@tonic-gate 	 */
1901*7c478bd9Sstevel@tonic-gate 	prefix_set(&adv_pr->adv_pr_prefix, prefix, prefixlen);
1902*7c478bd9Sstevel@tonic-gate 	adv_pr->adv_pr_prefix_len = prefixlen;
1903*7c478bd9Sstevel@tonic-gate 	adv_prefix_insert(pi, adv_pr);
1904*7c478bd9Sstevel@tonic-gate 	return (adv_pr);
1905*7c478bd9Sstevel@tonic-gate }
1906*7c478bd9Sstevel@tonic-gate 
1907*7c478bd9Sstevel@tonic-gate /* Insert in linked list */
1908*7c478bd9Sstevel@tonic-gate static void
1909*7c478bd9Sstevel@tonic-gate adv_prefix_insert(struct phyint *pi, struct adv_prefix *adv_pr)
1910*7c478bd9Sstevel@tonic-gate {
1911*7c478bd9Sstevel@tonic-gate 	adv_pr->adv_pr_next = pi->pi_adv_prefix_list;
1912*7c478bd9Sstevel@tonic-gate 	adv_pr->adv_pr_prev = NULL;
1913*7c478bd9Sstevel@tonic-gate 	if (pi->pi_adv_prefix_list != NULL)
1914*7c478bd9Sstevel@tonic-gate 		pi->pi_adv_prefix_list->adv_pr_prev = adv_pr;
1915*7c478bd9Sstevel@tonic-gate 	pi->pi_adv_prefix_list = adv_pr;
1916*7c478bd9Sstevel@tonic-gate 	adv_pr->adv_pr_physical = pi;
1917*7c478bd9Sstevel@tonic-gate }
1918*7c478bd9Sstevel@tonic-gate 
1919*7c478bd9Sstevel@tonic-gate /*
1920*7c478bd9Sstevel@tonic-gate  * Delete (unlink and free) from our tables. There should be
1921*7c478bd9Sstevel@tonic-gate  * a corresponding "struct prefix *" which will clean up the kernel
1922*7c478bd9Sstevel@tonic-gate  * if necessary. adv_prefix is just used for sending out advertisements.
1923*7c478bd9Sstevel@tonic-gate  */
1924*7c478bd9Sstevel@tonic-gate static void
1925*7c478bd9Sstevel@tonic-gate adv_prefix_delete(struct adv_prefix *adv_pr)
1926*7c478bd9Sstevel@tonic-gate {
1927*7c478bd9Sstevel@tonic-gate 	struct phyint *pi;
1928*7c478bd9Sstevel@tonic-gate 	char abuf[INET6_ADDRSTRLEN];
1929*7c478bd9Sstevel@tonic-gate 
1930*7c478bd9Sstevel@tonic-gate 	if (debug & D_PREFIX) {
1931*7c478bd9Sstevel@tonic-gate 		logmsg(LOG_DEBUG, "adv_prefix_delete(%s, %s/%u)\n",
1932*7c478bd9Sstevel@tonic-gate 		    adv_pr->adv_pr_physical->pi_name,
1933*7c478bd9Sstevel@tonic-gate 		    inet_ntop(AF_INET6, (void *)&adv_pr->adv_pr_prefix,
1934*7c478bd9Sstevel@tonic-gate 		    abuf, sizeof (abuf)), adv_pr->adv_pr_prefix_len);
1935*7c478bd9Sstevel@tonic-gate 	}
1936*7c478bd9Sstevel@tonic-gate 	pi = adv_pr->adv_pr_physical;
1937*7c478bd9Sstevel@tonic-gate 
1938*7c478bd9Sstevel@tonic-gate 	if (adv_pr->adv_pr_prev == NULL) {
1939*7c478bd9Sstevel@tonic-gate 		if (pi != NULL)
1940*7c478bd9Sstevel@tonic-gate 			pi->pi_adv_prefix_list = adv_pr->adv_pr_next;
1941*7c478bd9Sstevel@tonic-gate 	} else {
1942*7c478bd9Sstevel@tonic-gate 		adv_pr->adv_pr_prev->adv_pr_next = adv_pr->adv_pr_next;
1943*7c478bd9Sstevel@tonic-gate 	}
1944*7c478bd9Sstevel@tonic-gate 	if (adv_pr->adv_pr_next != NULL)
1945*7c478bd9Sstevel@tonic-gate 		adv_pr->adv_pr_next->adv_pr_prev = adv_pr->adv_pr_prev;
1946*7c478bd9Sstevel@tonic-gate 	adv_pr->adv_pr_next = adv_pr->adv_pr_prev = NULL;
1947*7c478bd9Sstevel@tonic-gate 	free(adv_pr);
1948*7c478bd9Sstevel@tonic-gate }
1949*7c478bd9Sstevel@tonic-gate 
1950*7c478bd9Sstevel@tonic-gate /*
1951*7c478bd9Sstevel@tonic-gate  * Called with the number of millseconds elapsed since the last call.
1952*7c478bd9Sstevel@tonic-gate  * Determines if any timeout event has occurred and
1953*7c478bd9Sstevel@tonic-gate  * returns the number of milliseconds until the next timeout event.
1954*7c478bd9Sstevel@tonic-gate  * Returns TIMER_INFINITY for "never".
1955*7c478bd9Sstevel@tonic-gate  */
1956*7c478bd9Sstevel@tonic-gate uint_t
1957*7c478bd9Sstevel@tonic-gate adv_prefix_timer(struct adv_prefix *adv_pr, uint_t elapsed)
1958*7c478bd9Sstevel@tonic-gate {
1959*7c478bd9Sstevel@tonic-gate 	int seconds_elapsed = (elapsed + 500) / 1000;	/* Rounded */
1960*7c478bd9Sstevel@tonic-gate 	char abuf[INET6_ADDRSTRLEN];
1961*7c478bd9Sstevel@tonic-gate 
1962*7c478bd9Sstevel@tonic-gate 	if (debug & D_PREFIX) {
1963*7c478bd9Sstevel@tonic-gate 		logmsg(LOG_DEBUG, "adv_prefix_timer(%s, %s/%u, %d)\n",
1964*7c478bd9Sstevel@tonic-gate 		    adv_pr->adv_pr_physical->pi_name,
1965*7c478bd9Sstevel@tonic-gate 		    inet_ntop(AF_INET6, (void *)&adv_pr->adv_pr_prefix,
1966*7c478bd9Sstevel@tonic-gate 		    abuf, sizeof (abuf)), adv_pr->adv_pr_prefix_len,
1967*7c478bd9Sstevel@tonic-gate 		    elapsed);
1968*7c478bd9Sstevel@tonic-gate 	}
1969*7c478bd9Sstevel@tonic-gate 
1970*7c478bd9Sstevel@tonic-gate 	/* Decrement Expire time left for real-time lifetimes */
1971*7c478bd9Sstevel@tonic-gate 	if (adv_pr->adv_pr_AdvValidRealTime) {
1972*7c478bd9Sstevel@tonic-gate 		if (adv_pr->adv_pr_AdvValidExpiration > seconds_elapsed)
1973*7c478bd9Sstevel@tonic-gate 			adv_pr->adv_pr_AdvValidExpiration -= seconds_elapsed;
1974*7c478bd9Sstevel@tonic-gate 		else
1975*7c478bd9Sstevel@tonic-gate 			adv_pr->adv_pr_AdvValidExpiration = 0;
1976*7c478bd9Sstevel@tonic-gate 	}
1977*7c478bd9Sstevel@tonic-gate 	if (adv_pr->adv_pr_AdvPreferredRealTime) {
1978*7c478bd9Sstevel@tonic-gate 		if (adv_pr->adv_pr_AdvPreferredExpiration > seconds_elapsed) {
1979*7c478bd9Sstevel@tonic-gate 			adv_pr->adv_pr_AdvPreferredExpiration -=
1980*7c478bd9Sstevel@tonic-gate 			    seconds_elapsed;
1981*7c478bd9Sstevel@tonic-gate 		} else {
1982*7c478bd9Sstevel@tonic-gate 			adv_pr->adv_pr_AdvPreferredExpiration = 0;
1983*7c478bd9Sstevel@tonic-gate 		}
1984*7c478bd9Sstevel@tonic-gate 	}
1985*7c478bd9Sstevel@tonic-gate 	return (TIMER_INFINITY);
1986*7c478bd9Sstevel@tonic-gate }
1987*7c478bd9Sstevel@tonic-gate 
1988*7c478bd9Sstevel@tonic-gate static void
1989*7c478bd9Sstevel@tonic-gate adv_prefix_print(struct adv_prefix *adv_pr)
1990*7c478bd9Sstevel@tonic-gate {
1991*7c478bd9Sstevel@tonic-gate 	print_prefixlist(adv_pr->adv_pr_config);
1992*7c478bd9Sstevel@tonic-gate }
1993*7c478bd9Sstevel@tonic-gate 
1994*7c478bd9Sstevel@tonic-gate /* Lookup router on its link-local IPv6 address */
1995*7c478bd9Sstevel@tonic-gate struct router *
1996*7c478bd9Sstevel@tonic-gate router_lookup(struct phyint *pi, struct in6_addr addr)
1997*7c478bd9Sstevel@tonic-gate {
1998*7c478bd9Sstevel@tonic-gate 	struct router *dr;
1999*7c478bd9Sstevel@tonic-gate 	char abuf[INET6_ADDRSTRLEN];
2000*7c478bd9Sstevel@tonic-gate 
2001*7c478bd9Sstevel@tonic-gate 	if (debug & D_ROUTER) {
2002*7c478bd9Sstevel@tonic-gate 		logmsg(LOG_DEBUG, "router_lookup(%s, %s)\n", pi->pi_name,
2003*7c478bd9Sstevel@tonic-gate 		    inet_ntop(AF_INET6, (void *)&addr,
2004*7c478bd9Sstevel@tonic-gate 		    abuf, sizeof (abuf)));
2005*7c478bd9Sstevel@tonic-gate 	}
2006*7c478bd9Sstevel@tonic-gate 
2007*7c478bd9Sstevel@tonic-gate 	for (dr = pi->pi_router_list; dr != NULL; dr = dr->dr_next) {
2008*7c478bd9Sstevel@tonic-gate 		if (bcmp((char *)&addr, (char *)&dr->dr_address,
2009*7c478bd9Sstevel@tonic-gate 		    sizeof (addr)) == 0)
2010*7c478bd9Sstevel@tonic-gate 			return (dr);
2011*7c478bd9Sstevel@tonic-gate 	}
2012*7c478bd9Sstevel@tonic-gate 	return (NULL);
2013*7c478bd9Sstevel@tonic-gate }
2014*7c478bd9Sstevel@tonic-gate 
2015*7c478bd9Sstevel@tonic-gate /*
2016*7c478bd9Sstevel@tonic-gate  * Create a default router entry.
2017*7c478bd9Sstevel@tonic-gate  * The lifetime parameter is in seconds.
2018*7c478bd9Sstevel@tonic-gate  */
2019*7c478bd9Sstevel@tonic-gate struct router *
2020*7c478bd9Sstevel@tonic-gate router_create(struct phyint *pi, struct in6_addr addr, uint_t lifetime)
2021*7c478bd9Sstevel@tonic-gate {
2022*7c478bd9Sstevel@tonic-gate 	struct router *dr;
2023*7c478bd9Sstevel@tonic-gate 	char abuf[INET6_ADDRSTRLEN];
2024*7c478bd9Sstevel@tonic-gate 
2025*7c478bd9Sstevel@tonic-gate 	if (debug & D_ROUTER) {
2026*7c478bd9Sstevel@tonic-gate 		logmsg(LOG_DEBUG, "router_create(%s, %s, %u)\n", pi->pi_name,
2027*7c478bd9Sstevel@tonic-gate 		    inet_ntop(AF_INET6, (void *)&addr,
2028*7c478bd9Sstevel@tonic-gate 		    abuf, sizeof (abuf)), lifetime);
2029*7c478bd9Sstevel@tonic-gate 	}
2030*7c478bd9Sstevel@tonic-gate 
2031*7c478bd9Sstevel@tonic-gate 	dr = (struct router *)calloc(sizeof (struct router), 1);
2032*7c478bd9Sstevel@tonic-gate 	if (dr == NULL) {
2033*7c478bd9Sstevel@tonic-gate 		logmsg(LOG_ERR, "router_create: out of memory\n");
2034*7c478bd9Sstevel@tonic-gate 		return (NULL);
2035*7c478bd9Sstevel@tonic-gate 	}
2036*7c478bd9Sstevel@tonic-gate 	dr->dr_address = addr;
2037*7c478bd9Sstevel@tonic-gate 	dr->dr_lifetime = lifetime;
2038*7c478bd9Sstevel@tonic-gate 	router_insert(pi, dr);
2039*7c478bd9Sstevel@tonic-gate 	if (dr->dr_lifetime != 0) {
2040*7c478bd9Sstevel@tonic-gate 		/*
2041*7c478bd9Sstevel@tonic-gate 		 * Delete an onlink default if it exists since we now have
2042*7c478bd9Sstevel@tonic-gate 		 * at least one default router.
2043*7c478bd9Sstevel@tonic-gate 		 */
2044*7c478bd9Sstevel@tonic-gate 		if (pi->pi_onlink_default)
2045*7c478bd9Sstevel@tonic-gate 			router_delete_onlink(dr->dr_physical);
2046*7c478bd9Sstevel@tonic-gate 		router_add_k(dr);
2047*7c478bd9Sstevel@tonic-gate 	}
2048*7c478bd9Sstevel@tonic-gate 	return (dr);
2049*7c478bd9Sstevel@tonic-gate }
2050*7c478bd9Sstevel@tonic-gate 
2051*7c478bd9Sstevel@tonic-gate /* Insert in linked list */
2052*7c478bd9Sstevel@tonic-gate static void
2053*7c478bd9Sstevel@tonic-gate router_insert(struct phyint *pi, struct router *dr)
2054*7c478bd9Sstevel@tonic-gate {
2055*7c478bd9Sstevel@tonic-gate 	dr->dr_next = pi->pi_router_list;
2056*7c478bd9Sstevel@tonic-gate 	dr->dr_prev = NULL;
2057*7c478bd9Sstevel@tonic-gate 	if (pi->pi_router_list != NULL)
2058*7c478bd9Sstevel@tonic-gate 		pi->pi_router_list->dr_prev = dr;
2059*7c478bd9Sstevel@tonic-gate 	pi->pi_router_list = dr;
2060*7c478bd9Sstevel@tonic-gate 	dr->dr_physical = pi;
2061*7c478bd9Sstevel@tonic-gate }
2062*7c478bd9Sstevel@tonic-gate 
2063*7c478bd9Sstevel@tonic-gate /*
2064*7c478bd9Sstevel@tonic-gate  * Delete (unlink and free).
2065*7c478bd9Sstevel@tonic-gate  * Handles delete of things that have not yet been inserted in the list
2066*7c478bd9Sstevel@tonic-gate  * i.e. dr_physical is NULL.
2067*7c478bd9Sstevel@tonic-gate  */
2068*7c478bd9Sstevel@tonic-gate static void
2069*7c478bd9Sstevel@tonic-gate router_delete(struct router *dr)
2070*7c478bd9Sstevel@tonic-gate {
2071*7c478bd9Sstevel@tonic-gate 	struct phyint *pi;
2072*7c478bd9Sstevel@tonic-gate 	char abuf[INET6_ADDRSTRLEN];
2073*7c478bd9Sstevel@tonic-gate 
2074*7c478bd9Sstevel@tonic-gate 	if (debug & D_ROUTER) {
2075*7c478bd9Sstevel@tonic-gate 		logmsg(LOG_DEBUG, "router_delete(%s, %s, %u)\n",
2076*7c478bd9Sstevel@tonic-gate 		    dr->dr_physical->pi_name,
2077*7c478bd9Sstevel@tonic-gate 		    inet_ntop(AF_INET6, (void *)&dr->dr_address,
2078*7c478bd9Sstevel@tonic-gate 		    abuf, sizeof (abuf)), dr->dr_lifetime);
2079*7c478bd9Sstevel@tonic-gate 	}
2080*7c478bd9Sstevel@tonic-gate 	pi = dr->dr_physical;
2081*7c478bd9Sstevel@tonic-gate 	if (dr->dr_inkernel) {
2082*7c478bd9Sstevel@tonic-gate 		/*
2083*7c478bd9Sstevel@tonic-gate 		 * Create a on-link default route only if the interface
2084*7c478bd9Sstevel@tonic-gate 		 * is present in the kernel. This function is called
2085*7c478bd9Sstevel@tonic-gate 		 * to clean up the routes when the interface is
2086*7c478bd9Sstevel@tonic-gate 		 * unplumbed. In that case, don't try to create one
2087*7c478bd9Sstevel@tonic-gate 		 * in the kernel.
2088*7c478bd9Sstevel@tonic-gate 		 */
2089*7c478bd9Sstevel@tonic-gate 		if (pi->pi_kernel_state & PI_PRESENT) {
2090*7c478bd9Sstevel@tonic-gate 			if (!dr->dr_onlink &&
2091*7c478bd9Sstevel@tonic-gate 			    dr->dr_physical->pi_num_k_routers == 1) {
2092*7c478bd9Sstevel@tonic-gate 				(void) router_create_onlink(dr->dr_physical);
2093*7c478bd9Sstevel@tonic-gate 			}
2094*7c478bd9Sstevel@tonic-gate 			router_delete_k(dr);
2095*7c478bd9Sstevel@tonic-gate 		}
2096*7c478bd9Sstevel@tonic-gate 	}
2097*7c478bd9Sstevel@tonic-gate 	if (dr->dr_onlink)
2098*7c478bd9Sstevel@tonic-gate 		pi->pi_onlink_default = _B_FALSE;
2099*7c478bd9Sstevel@tonic-gate 
2100*7c478bd9Sstevel@tonic-gate 	if (dr->dr_prev == NULL) {
2101*7c478bd9Sstevel@tonic-gate 		if (pi != NULL)
2102*7c478bd9Sstevel@tonic-gate 			pi->pi_router_list = dr->dr_next;
2103*7c478bd9Sstevel@tonic-gate 	} else {
2104*7c478bd9Sstevel@tonic-gate 		dr->dr_prev->dr_next = dr->dr_next;
2105*7c478bd9Sstevel@tonic-gate 	}
2106*7c478bd9Sstevel@tonic-gate 	if (dr->dr_next != NULL)
2107*7c478bd9Sstevel@tonic-gate 		dr->dr_next->dr_prev = dr->dr_prev;
2108*7c478bd9Sstevel@tonic-gate 	dr->dr_next = dr->dr_prev = NULL;
2109*7c478bd9Sstevel@tonic-gate 	free(dr);
2110*7c478bd9Sstevel@tonic-gate }
2111*7c478bd9Sstevel@tonic-gate 
2112*7c478bd9Sstevel@tonic-gate 
2113*7c478bd9Sstevel@tonic-gate /* Create an onlink default route */
2114*7c478bd9Sstevel@tonic-gate struct router *
2115*7c478bd9Sstevel@tonic-gate router_create_onlink(struct phyint *pi)
2116*7c478bd9Sstevel@tonic-gate {
2117*7c478bd9Sstevel@tonic-gate 	struct router *dr;
2118*7c478bd9Sstevel@tonic-gate 	struct prefix *pr;
2119*7c478bd9Sstevel@tonic-gate 
2120*7c478bd9Sstevel@tonic-gate 	if (debug & D_ROUTER) {
2121*7c478bd9Sstevel@tonic-gate 		logmsg(LOG_DEBUG, "router_create_onlink(%s)\n", pi->pi_name);
2122*7c478bd9Sstevel@tonic-gate 	}
2123*7c478bd9Sstevel@tonic-gate 
2124*7c478bd9Sstevel@tonic-gate 	if (pi->pi_onlink_default) {
2125*7c478bd9Sstevel@tonic-gate 		logmsg(LOG_ERR, "router_create_onlink: already an onlink "
2126*7c478bd9Sstevel@tonic-gate 		    "default: %s\n", pi->pi_name);
2127*7c478bd9Sstevel@tonic-gate 		return (NULL);
2128*7c478bd9Sstevel@tonic-gate 	}
2129*7c478bd9Sstevel@tonic-gate 
2130*7c478bd9Sstevel@tonic-gate 	/*
2131*7c478bd9Sstevel@tonic-gate 	 * Find the interface address to use for the route gateway.
2132*7c478bd9Sstevel@tonic-gate 	 * We need to use the link-local since the others ones might be
2133*7c478bd9Sstevel@tonic-gate 	 * deleted when the prefixes get invalidated.
2134*7c478bd9Sstevel@tonic-gate 	 */
2135*7c478bd9Sstevel@tonic-gate 	for (pr = pi->pi_prefix_list; pr != NULL; pr = pr->pr_next) {
2136*7c478bd9Sstevel@tonic-gate 		if ((pr->pr_state & PR_AUTO) &&
2137*7c478bd9Sstevel@tonic-gate 		    IN6_IS_ADDR_LINKLOCAL(&pr->pr_address))
2138*7c478bd9Sstevel@tonic-gate 			break;
2139*7c478bd9Sstevel@tonic-gate 	}
2140*7c478bd9Sstevel@tonic-gate 	if (pr == NULL) {
2141*7c478bd9Sstevel@tonic-gate 		logmsg(LOG_ERR, "router_create_onlink: no source address\n");
2142*7c478bd9Sstevel@tonic-gate 		return (NULL);
2143*7c478bd9Sstevel@tonic-gate 	}
2144*7c478bd9Sstevel@tonic-gate 	dr = (struct router *)calloc(sizeof (struct router), 1);
2145*7c478bd9Sstevel@tonic-gate 	if (dr == NULL) {
2146*7c478bd9Sstevel@tonic-gate 		logmsg(LOG_ERR, "router_create_onlink: out of memory\n");
2147*7c478bd9Sstevel@tonic-gate 		return (NULL);
2148*7c478bd9Sstevel@tonic-gate 	}
2149*7c478bd9Sstevel@tonic-gate 	dr->dr_address = pr->pr_address;
2150*7c478bd9Sstevel@tonic-gate 	dr->dr_lifetime = 1;	/* Not used */
2151*7c478bd9Sstevel@tonic-gate 	dr->dr_onlink = _B_TRUE;
2152*7c478bd9Sstevel@tonic-gate 	router_insert(pi, dr);
2153*7c478bd9Sstevel@tonic-gate 
2154*7c478bd9Sstevel@tonic-gate 	router_add_k(dr);
2155*7c478bd9Sstevel@tonic-gate 	pi->pi_onlink_default = _B_TRUE;
2156*7c478bd9Sstevel@tonic-gate 	return (dr);
2157*7c478bd9Sstevel@tonic-gate }
2158*7c478bd9Sstevel@tonic-gate 
2159*7c478bd9Sstevel@tonic-gate /* Remove an onlink default route */
2160*7c478bd9Sstevel@tonic-gate static void
2161*7c478bd9Sstevel@tonic-gate router_delete_onlink(struct phyint *pi)
2162*7c478bd9Sstevel@tonic-gate {
2163*7c478bd9Sstevel@tonic-gate 	struct router *dr, *next_dr;
2164*7c478bd9Sstevel@tonic-gate 
2165*7c478bd9Sstevel@tonic-gate 	if (debug & D_ROUTER) {
2166*7c478bd9Sstevel@tonic-gate 		logmsg(LOG_DEBUG, "router_delete_onlink(%s)\n", pi->pi_name);
2167*7c478bd9Sstevel@tonic-gate 	}
2168*7c478bd9Sstevel@tonic-gate 
2169*7c478bd9Sstevel@tonic-gate 	if (!pi->pi_onlink_default) {
2170*7c478bd9Sstevel@tonic-gate 		logmsg(LOG_ERR, "router_delete_onlink: no onlink default: "
2171*7c478bd9Sstevel@tonic-gate 		    "%s\n", pi->pi_name);
2172*7c478bd9Sstevel@tonic-gate 		return;
2173*7c478bd9Sstevel@tonic-gate 	}
2174*7c478bd9Sstevel@tonic-gate 	/* Find all onlink routes */
2175*7c478bd9Sstevel@tonic-gate 	for (dr = pi->pi_router_list; dr != NULL; dr = next_dr) {
2176*7c478bd9Sstevel@tonic-gate 		next_dr = dr->dr_next;
2177*7c478bd9Sstevel@tonic-gate 		if (dr->dr_onlink)
2178*7c478bd9Sstevel@tonic-gate 			router_delete(dr);
2179*7c478bd9Sstevel@tonic-gate 	}
2180*7c478bd9Sstevel@tonic-gate }
2181*7c478bd9Sstevel@tonic-gate 
2182*7c478bd9Sstevel@tonic-gate /*
2183*7c478bd9Sstevel@tonic-gate  * Update the kernel to match dr_lifetime
2184*7c478bd9Sstevel@tonic-gate  */
2185*7c478bd9Sstevel@tonic-gate void
2186*7c478bd9Sstevel@tonic-gate router_update_k(struct router *dr)
2187*7c478bd9Sstevel@tonic-gate {
2188*7c478bd9Sstevel@tonic-gate 	char abuf[INET6_ADDRSTRLEN];
2189*7c478bd9Sstevel@tonic-gate 
2190*7c478bd9Sstevel@tonic-gate 	if (debug & D_ROUTER) {
2191*7c478bd9Sstevel@tonic-gate 		logmsg(LOG_DEBUG, "router_update_k(%s, %s, %u)\n",
2192*7c478bd9Sstevel@tonic-gate 		    dr->dr_physical->pi_name,
2193*7c478bd9Sstevel@tonic-gate 		    inet_ntop(AF_INET6, (void *)&dr->dr_address,
2194*7c478bd9Sstevel@tonic-gate 		    abuf, sizeof (abuf)), dr->dr_lifetime);
2195*7c478bd9Sstevel@tonic-gate 	}
2196*7c478bd9Sstevel@tonic-gate 
2197*7c478bd9Sstevel@tonic-gate 	if (dr->dr_lifetime == 0 && dr->dr_inkernel) {
2198*7c478bd9Sstevel@tonic-gate 		/* Log a message when last router goes away */
2199*7c478bd9Sstevel@tonic-gate 		if (dr->dr_physical->pi_num_k_routers == 1) {
2200*7c478bd9Sstevel@tonic-gate 			logmsg(LOG_WARNING,
2201*7c478bd9Sstevel@tonic-gate 			    "Last default router (%s) removed on %s\n",
2202*7c478bd9Sstevel@tonic-gate 			    inet_ntop(AF_INET6, (void *)&dr->dr_address,
2203*7c478bd9Sstevel@tonic-gate 			    abuf, sizeof (abuf)), dr->dr_physical->pi_name);
2204*7c478bd9Sstevel@tonic-gate 		}
2205*7c478bd9Sstevel@tonic-gate 		router_delete(dr);
2206*7c478bd9Sstevel@tonic-gate 	} else if (dr->dr_lifetime != 0 && !dr->dr_inkernel) {
2207*7c478bd9Sstevel@tonic-gate 		/*
2208*7c478bd9Sstevel@tonic-gate 		 * Delete an onlink default if it exists since we now have
2209*7c478bd9Sstevel@tonic-gate 		 * at least one default router.
2210*7c478bd9Sstevel@tonic-gate 		 */
2211*7c478bd9Sstevel@tonic-gate 		if (dr->dr_physical->pi_onlink_default)
2212*7c478bd9Sstevel@tonic-gate 			router_delete_onlink(dr->dr_physical);
2213*7c478bd9Sstevel@tonic-gate 		router_add_k(dr);
2214*7c478bd9Sstevel@tonic-gate 	}
2215*7c478bd9Sstevel@tonic-gate }
2216*7c478bd9Sstevel@tonic-gate 
2217*7c478bd9Sstevel@tonic-gate 
2218*7c478bd9Sstevel@tonic-gate /*
2219*7c478bd9Sstevel@tonic-gate  * Called with the number of millseconds elapsed since the last call.
2220*7c478bd9Sstevel@tonic-gate  * Determines if any timeout event has occurred and
2221*7c478bd9Sstevel@tonic-gate  * returns the number of milliseconds until the next timeout event.
2222*7c478bd9Sstevel@tonic-gate  * Returns TIMER_INFINITY for "never".
2223*7c478bd9Sstevel@tonic-gate  */
2224*7c478bd9Sstevel@tonic-gate uint_t
2225*7c478bd9Sstevel@tonic-gate router_timer(struct router *dr, uint_t elapsed)
2226*7c478bd9Sstevel@tonic-gate {
2227*7c478bd9Sstevel@tonic-gate 	uint_t next = TIMER_INFINITY;
2228*7c478bd9Sstevel@tonic-gate 	char abuf[INET6_ADDRSTRLEN];
2229*7c478bd9Sstevel@tonic-gate 
2230*7c478bd9Sstevel@tonic-gate 	if (debug & D_ROUTER) {
2231*7c478bd9Sstevel@tonic-gate 		logmsg(LOG_DEBUG, "router_timer(%s, %s, %u, %d)\n",
2232*7c478bd9Sstevel@tonic-gate 		    dr->dr_physical->pi_name,
2233*7c478bd9Sstevel@tonic-gate 		    inet_ntop(AF_INET6, (void *)&dr->dr_address,
2234*7c478bd9Sstevel@tonic-gate 		    abuf, sizeof (abuf)), dr->dr_lifetime, elapsed);
2235*7c478bd9Sstevel@tonic-gate 	}
2236*7c478bd9Sstevel@tonic-gate 	if (dr->dr_onlink) {
2237*7c478bd9Sstevel@tonic-gate 		/* No timeout */
2238*7c478bd9Sstevel@tonic-gate 		return (next);
2239*7c478bd9Sstevel@tonic-gate 	}
2240*7c478bd9Sstevel@tonic-gate 	if (dr->dr_lifetime <= elapsed) {
2241*7c478bd9Sstevel@tonic-gate 		dr->dr_lifetime = 0;
2242*7c478bd9Sstevel@tonic-gate 	} else {
2243*7c478bd9Sstevel@tonic-gate 		dr->dr_lifetime -= elapsed;
2244*7c478bd9Sstevel@tonic-gate 		if (dr->dr_lifetime < next)
2245*7c478bd9Sstevel@tonic-gate 			next = dr->dr_lifetime;
2246*7c478bd9Sstevel@tonic-gate 	}
2247*7c478bd9Sstevel@tonic-gate 
2248*7c478bd9Sstevel@tonic-gate 	if (dr->dr_lifetime == 0) {
2249*7c478bd9Sstevel@tonic-gate 		/* Log a message when last router goes away */
2250*7c478bd9Sstevel@tonic-gate 		if (dr->dr_physical->pi_num_k_routers == 1) {
2251*7c478bd9Sstevel@tonic-gate 			logmsg(LOG_WARNING,
2252*7c478bd9Sstevel@tonic-gate 			    "Last default router (%s) timed out on %s\n",
2253*7c478bd9Sstevel@tonic-gate 			    inet_ntop(AF_INET6, (void *)&dr->dr_address,
2254*7c478bd9Sstevel@tonic-gate 			    abuf, sizeof (abuf)), dr->dr_physical->pi_name);
2255*7c478bd9Sstevel@tonic-gate 		}
2256*7c478bd9Sstevel@tonic-gate 		router_delete(dr);
2257*7c478bd9Sstevel@tonic-gate 	}
2258*7c478bd9Sstevel@tonic-gate 	return (next);
2259*7c478bd9Sstevel@tonic-gate }
2260*7c478bd9Sstevel@tonic-gate 
2261*7c478bd9Sstevel@tonic-gate /*
2262*7c478bd9Sstevel@tonic-gate  * Add a default route to the kernel (unless the lifetime is zero)
2263*7c478bd9Sstevel@tonic-gate  * Handles onlink default routes.
2264*7c478bd9Sstevel@tonic-gate  */
2265*7c478bd9Sstevel@tonic-gate static void
2266*7c478bd9Sstevel@tonic-gate router_add_k(struct router *dr)
2267*7c478bd9Sstevel@tonic-gate {
2268*7c478bd9Sstevel@tonic-gate 	struct phyint *pi = dr->dr_physical;
2269*7c478bd9Sstevel@tonic-gate 	char abuf[INET6_ADDRSTRLEN];
2270*7c478bd9Sstevel@tonic-gate 	int rlen;
2271*7c478bd9Sstevel@tonic-gate 
2272*7c478bd9Sstevel@tonic-gate 	if (debug & D_ROUTER) {
2273*7c478bd9Sstevel@tonic-gate 		logmsg(LOG_DEBUG, "router_add_k(%s, %s, %u)\n",
2274*7c478bd9Sstevel@tonic-gate 		    dr->dr_physical->pi_name,
2275*7c478bd9Sstevel@tonic-gate 		    inet_ntop(AF_INET6, (void *)&dr->dr_address,
2276*7c478bd9Sstevel@tonic-gate 		    abuf, sizeof (abuf)), dr->dr_lifetime);
2277*7c478bd9Sstevel@tonic-gate 	}
2278*7c478bd9Sstevel@tonic-gate 
2279*7c478bd9Sstevel@tonic-gate 	if (dr->dr_onlink)
2280*7c478bd9Sstevel@tonic-gate 		rt_msg->rtm_flags = 0;
2281*7c478bd9Sstevel@tonic-gate 	else
2282*7c478bd9Sstevel@tonic-gate 		rt_msg->rtm_flags = RTF_GATEWAY;
2283*7c478bd9Sstevel@tonic-gate 
2284*7c478bd9Sstevel@tonic-gate 	rta_gateway->sin6_addr = dr->dr_address;
2285*7c478bd9Sstevel@tonic-gate 
2286*7c478bd9Sstevel@tonic-gate 	rta_ifp->sdl_index = if_nametoindex(pi->pi_name);
2287*7c478bd9Sstevel@tonic-gate 	if (rta_ifp->sdl_index == 0) {
2288*7c478bd9Sstevel@tonic-gate 		logperror_pi(pi, "router_add_k: if_nametoindex");
2289*7c478bd9Sstevel@tonic-gate 		return;
2290*7c478bd9Sstevel@tonic-gate 	}
2291*7c478bd9Sstevel@tonic-gate 
2292*7c478bd9Sstevel@tonic-gate 	rt_msg->rtm_type = RTM_ADD;
2293*7c478bd9Sstevel@tonic-gate 	rt_msg->rtm_seq = ++rtmseq;
2294*7c478bd9Sstevel@tonic-gate 	rlen = write(rtsock, rt_msg, rt_msg->rtm_msglen);
2295*7c478bd9Sstevel@tonic-gate 	if (rlen < 0) {
2296*7c478bd9Sstevel@tonic-gate 		if (errno != EEXIST) {
2297*7c478bd9Sstevel@tonic-gate 			logperror_pi(pi, "router_add_k: RTM_ADD");
2298*7c478bd9Sstevel@tonic-gate 			return;
2299*7c478bd9Sstevel@tonic-gate 		}
2300*7c478bd9Sstevel@tonic-gate 	} else if (rlen < rt_msg->rtm_msglen) {
2301*7c478bd9Sstevel@tonic-gate 		logmsg(LOG_ERR, "router_add_k: write to routing socket got "
2302*7c478bd9Sstevel@tonic-gate 		    "only %d for rlen (interface %s)\n", rlen, pi->pi_name);
2303*7c478bd9Sstevel@tonic-gate 		return;
2304*7c478bd9Sstevel@tonic-gate 	}
2305*7c478bd9Sstevel@tonic-gate 	dr->dr_inkernel = _B_TRUE;
2306*7c478bd9Sstevel@tonic-gate 	if (!dr->dr_onlink)
2307*7c478bd9Sstevel@tonic-gate 		pi->pi_num_k_routers++;
2308*7c478bd9Sstevel@tonic-gate }
2309*7c478bd9Sstevel@tonic-gate 
2310*7c478bd9Sstevel@tonic-gate /*
2311*7c478bd9Sstevel@tonic-gate  * Delete a route from the kernel.
2312*7c478bd9Sstevel@tonic-gate  * Handles onlink default routes.
2313*7c478bd9Sstevel@tonic-gate  */
2314*7c478bd9Sstevel@tonic-gate static void
2315*7c478bd9Sstevel@tonic-gate router_delete_k(struct router *dr)
2316*7c478bd9Sstevel@tonic-gate {
2317*7c478bd9Sstevel@tonic-gate 	struct phyint *pi = dr->dr_physical;
2318*7c478bd9Sstevel@tonic-gate 	char abuf[INET6_ADDRSTRLEN];
2319*7c478bd9Sstevel@tonic-gate 	int rlen;
2320*7c478bd9Sstevel@tonic-gate 
2321*7c478bd9Sstevel@tonic-gate 	if (debug & D_ROUTER) {
2322*7c478bd9Sstevel@tonic-gate 		logmsg(LOG_DEBUG, "router_delete_k(%s, %s, %u)\n",
2323*7c478bd9Sstevel@tonic-gate 		    dr->dr_physical->pi_name,
2324*7c478bd9Sstevel@tonic-gate 		    inet_ntop(AF_INET6, (void *)&dr->dr_address,
2325*7c478bd9Sstevel@tonic-gate 		    abuf, sizeof (abuf)), dr->dr_lifetime);
2326*7c478bd9Sstevel@tonic-gate 	}
2327*7c478bd9Sstevel@tonic-gate 
2328*7c478bd9Sstevel@tonic-gate 	if (dr->dr_onlink)
2329*7c478bd9Sstevel@tonic-gate 		rt_msg->rtm_flags = 0;
2330*7c478bd9Sstevel@tonic-gate 	else
2331*7c478bd9Sstevel@tonic-gate 		rt_msg->rtm_flags = RTF_GATEWAY;
2332*7c478bd9Sstevel@tonic-gate 
2333*7c478bd9Sstevel@tonic-gate 	rta_gateway->sin6_addr = dr->dr_address;
2334*7c478bd9Sstevel@tonic-gate 
2335*7c478bd9Sstevel@tonic-gate 	rta_ifp->sdl_index = if_nametoindex(pi->pi_name);
2336*7c478bd9Sstevel@tonic-gate 	if (rta_ifp->sdl_index == 0) {
2337*7c478bd9Sstevel@tonic-gate 		logperror_pi(pi, "router_delete_k: if_nametoindex");
2338*7c478bd9Sstevel@tonic-gate 		return;
2339*7c478bd9Sstevel@tonic-gate 	}
2340*7c478bd9Sstevel@tonic-gate 
2341*7c478bd9Sstevel@tonic-gate 	rt_msg->rtm_type = RTM_DELETE;
2342*7c478bd9Sstevel@tonic-gate 	rt_msg->rtm_seq = ++rtmseq;
2343*7c478bd9Sstevel@tonic-gate 	rlen = write(rtsock, rt_msg, rt_msg->rtm_msglen);
2344*7c478bd9Sstevel@tonic-gate 	if (rlen < 0) {
2345*7c478bd9Sstevel@tonic-gate 		if (errno != ESRCH) {
2346*7c478bd9Sstevel@tonic-gate 			logperror_pi(pi, "router_delete_k: RTM_DELETE");
2347*7c478bd9Sstevel@tonic-gate 		}
2348*7c478bd9Sstevel@tonic-gate 	} else if (rlen < rt_msg->rtm_msglen) {
2349*7c478bd9Sstevel@tonic-gate 		logmsg(LOG_ERR, "router_delete_k: write to routing socket got "
2350*7c478bd9Sstevel@tonic-gate 		    "only %d for rlen (interface %s)\n", rlen, pi->pi_name);
2351*7c478bd9Sstevel@tonic-gate 	}
2352*7c478bd9Sstevel@tonic-gate 	dr->dr_inkernel = _B_FALSE;
2353*7c478bd9Sstevel@tonic-gate 	if (!dr->dr_onlink)
2354*7c478bd9Sstevel@tonic-gate 		pi->pi_num_k_routers--;
2355*7c478bd9Sstevel@tonic-gate }
2356*7c478bd9Sstevel@tonic-gate 
2357*7c478bd9Sstevel@tonic-gate 
2358*7c478bd9Sstevel@tonic-gate static void
2359*7c478bd9Sstevel@tonic-gate router_print(struct router *dr)
2360*7c478bd9Sstevel@tonic-gate {
2361*7c478bd9Sstevel@tonic-gate 	char abuf[INET6_ADDRSTRLEN];
2362*7c478bd9Sstevel@tonic-gate 
2363*7c478bd9Sstevel@tonic-gate 	logmsg(LOG_DEBUG, "Router %s on %s inkernel %d onlink %d lifetime %u\n",
2364*7c478bd9Sstevel@tonic-gate 	    inet_ntop(AF_INET6, (void *)&dr->dr_address,
2365*7c478bd9Sstevel@tonic-gate 	    abuf, sizeof (abuf)),
2366*7c478bd9Sstevel@tonic-gate 	    dr->dr_physical->pi_name,
2367*7c478bd9Sstevel@tonic-gate 	    dr->dr_inkernel, dr->dr_onlink, dr->dr_lifetime);
2368*7c478bd9Sstevel@tonic-gate }
2369*7c478bd9Sstevel@tonic-gate 
2370*7c478bd9Sstevel@tonic-gate 
2371*7c478bd9Sstevel@tonic-gate void
2372*7c478bd9Sstevel@tonic-gate phyint_print_all(void)
2373*7c478bd9Sstevel@tonic-gate {
2374*7c478bd9Sstevel@tonic-gate 	struct phyint *pi;
2375*7c478bd9Sstevel@tonic-gate 
2376*7c478bd9Sstevel@tonic-gate 	for (pi = phyints; pi != NULL; pi = pi->pi_next) {
2377*7c478bd9Sstevel@tonic-gate 		phyint_print(pi);
2378*7c478bd9Sstevel@tonic-gate 	}
2379*7c478bd9Sstevel@tonic-gate }
2380*7c478bd9Sstevel@tonic-gate 
2381*7c478bd9Sstevel@tonic-gate void
2382*7c478bd9Sstevel@tonic-gate phyint_cleanup(pi)
2383*7c478bd9Sstevel@tonic-gate 	struct phyint *pi;
2384*7c478bd9Sstevel@tonic-gate {
2385*7c478bd9Sstevel@tonic-gate 	pi->pi_state = 0;
2386*7c478bd9Sstevel@tonic-gate 	pi->pi_kernel_state = 0;
2387*7c478bd9Sstevel@tonic-gate 
2388*7c478bd9Sstevel@tonic-gate 	if (pi->pi_AdvSendAdvertisements) {
2389*7c478bd9Sstevel@tonic-gate 		check_to_advertise(pi, ADV_OFF);
2390*7c478bd9Sstevel@tonic-gate 	} else {
2391*7c478bd9Sstevel@tonic-gate 		check_to_solicit(pi, SOLICIT_OFF);
2392*7c478bd9Sstevel@tonic-gate 	}
2393*7c478bd9Sstevel@tonic-gate 
2394*7c478bd9Sstevel@tonic-gate 	while (pi->pi_router_list)
2395*7c478bd9Sstevel@tonic-gate 		router_delete(pi->pi_router_list);
2396*7c478bd9Sstevel@tonic-gate 	(void) poll_remove(pi->pi_sock);
2397*7c478bd9Sstevel@tonic-gate 	(void) close(pi->pi_sock);
2398*7c478bd9Sstevel@tonic-gate 	pi->pi_sock = -1;
2399*7c478bd9Sstevel@tonic-gate }
2400