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