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