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