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