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