17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
500834081Spwernau  * Common Development and Distribution License (the "License").
600834081Spwernau  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22*6e91bba0SGirish Moodalbail  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate #include "defs.h"
277c478bd9Sstevel@tonic-gate #include "tables.h"
287c478bd9Sstevel@tonic-gate 
297c478bd9Sstevel@tonic-gate #include <time.h>
303173664eSapersson #include <assert.h>
317c478bd9Sstevel@tonic-gate 
327c478bd9Sstevel@tonic-gate struct phyint *phyints = NULL;
333173664eSapersson int num_of_phyints = 0;
347c478bd9Sstevel@tonic-gate 
357c478bd9Sstevel@tonic-gate static void	phyint_print(struct phyint *pi);
367c478bd9Sstevel@tonic-gate static void	phyint_insert(struct phyint *pi);
377c478bd9Sstevel@tonic-gate 
387c478bd9Sstevel@tonic-gate static boolean_t tmptoken_isvalid(struct in6_addr *token);
397c478bd9Sstevel@tonic-gate 
407c478bd9Sstevel@tonic-gate static void	prefix_print(struct prefix *pr);
417c478bd9Sstevel@tonic-gate static void	prefix_insert(struct phyint *pi, struct prefix *pr);
427c478bd9Sstevel@tonic-gate static char	*prefix_print_state(int state, char *buf, int buflen);
437c478bd9Sstevel@tonic-gate static void	prefix_set(struct in6_addr *prefix, struct in6_addr addr,
447c478bd9Sstevel@tonic-gate 		    int bits);
457c478bd9Sstevel@tonic-gate 
467c478bd9Sstevel@tonic-gate static void	adv_prefix_print(struct adv_prefix *adv_pr);
477c478bd9Sstevel@tonic-gate static void	adv_prefix_insert(struct phyint *pi, struct adv_prefix *adv_pr);
487c478bd9Sstevel@tonic-gate static void	adv_prefix_delete(struct adv_prefix *adv_pr);
497c478bd9Sstevel@tonic-gate 
507c478bd9Sstevel@tonic-gate static void	router_print(struct router *dr);
517c478bd9Sstevel@tonic-gate static void	router_insert(struct phyint *pi, struct router *dr);
527c478bd9Sstevel@tonic-gate static void	router_delete(struct router *dr);
537c478bd9Sstevel@tonic-gate static void	router_add_k(struct router *dr);
547c478bd9Sstevel@tonic-gate static void	router_delete_k(struct router *dr);
557c478bd9Sstevel@tonic-gate 
567c478bd9Sstevel@tonic-gate static int	rtmseq;				/* rtm_seq sequence number */
577c478bd9Sstevel@tonic-gate 
587c478bd9Sstevel@tonic-gate /* 1 week in ms */
597c478bd9Sstevel@tonic-gate #define	NDP_PREFIX_DEFAULT_LIFETIME	(7*24*60*60*1000)
607c478bd9Sstevel@tonic-gate struct phyint *
phyint_lookup(char * name)617c478bd9Sstevel@tonic-gate phyint_lookup(char *name)
627c478bd9Sstevel@tonic-gate {
637c478bd9Sstevel@tonic-gate 	struct phyint *pi;
647c478bd9Sstevel@tonic-gate 
657c478bd9Sstevel@tonic-gate 	if (debug & D_PHYINT)
667c478bd9Sstevel@tonic-gate 		logmsg(LOG_DEBUG, "phyint_lookup(%s)\n", name);
677c478bd9Sstevel@tonic-gate 
687c478bd9Sstevel@tonic-gate 	for (pi = phyints; pi != NULL; pi = pi->pi_next) {
697c478bd9Sstevel@tonic-gate 		if (strcmp(pi->pi_name, name) == 0)
707c478bd9Sstevel@tonic-gate 			break;
717c478bd9Sstevel@tonic-gate 	}
727c478bd9Sstevel@tonic-gate 	return (pi);
737c478bd9Sstevel@tonic-gate }
747c478bd9Sstevel@tonic-gate 
757c478bd9Sstevel@tonic-gate struct phyint *
phyint_lookup_on_index(uint_t ifindex)767c478bd9Sstevel@tonic-gate phyint_lookup_on_index(uint_t ifindex)
777c478bd9Sstevel@tonic-gate {
787c478bd9Sstevel@tonic-gate 	struct phyint *pi;
797c478bd9Sstevel@tonic-gate 
807c478bd9Sstevel@tonic-gate 	if (debug & D_PHYINT)
817c478bd9Sstevel@tonic-gate 		logmsg(LOG_DEBUG, "phyint_lookup_on_index(%d)\n", ifindex);
827c478bd9Sstevel@tonic-gate 
837c478bd9Sstevel@tonic-gate 	for (pi = phyints; pi != NULL; pi = pi->pi_next) {
847c478bd9Sstevel@tonic-gate 		if (pi->pi_index == ifindex)
857c478bd9Sstevel@tonic-gate 			break;
867c478bd9Sstevel@tonic-gate 	}
877c478bd9Sstevel@tonic-gate 	return (pi);
887c478bd9Sstevel@tonic-gate }
897c478bd9Sstevel@tonic-gate 
907c478bd9Sstevel@tonic-gate struct phyint *
phyint_create(char * name)917c478bd9Sstevel@tonic-gate phyint_create(char *name)
927c478bd9Sstevel@tonic-gate {
937c478bd9Sstevel@tonic-gate 	struct phyint *pi;
947c478bd9Sstevel@tonic-gate 	int i;
957c478bd9Sstevel@tonic-gate 
967c478bd9Sstevel@tonic-gate 	if (debug & D_PHYINT)
977c478bd9Sstevel@tonic-gate 		logmsg(LOG_DEBUG, "phyint_create(%s)\n", name);
987c478bd9Sstevel@tonic-gate 
997c478bd9Sstevel@tonic-gate 	pi = (struct phyint *)calloc(sizeof (struct phyint), 1);
1007c478bd9Sstevel@tonic-gate 	if (pi == NULL) {
1017c478bd9Sstevel@tonic-gate 		logmsg(LOG_ERR, "phyint_create: out of memory\n");
1027c478bd9Sstevel@tonic-gate 		return (NULL);
1037c478bd9Sstevel@tonic-gate 	}
1047c478bd9Sstevel@tonic-gate 	(void) strncpy(pi->pi_name, name, sizeof (pi->pi_name));
1057c478bd9Sstevel@tonic-gate 	pi->pi_name[sizeof (pi->pi_name) - 1] = '\0';
1067c478bd9Sstevel@tonic-gate 
1077c478bd9Sstevel@tonic-gate 	/*
1087c478bd9Sstevel@tonic-gate 	 * Copy the defaults from the defaults array.
1097c478bd9Sstevel@tonic-gate 	 * Do not copy the cf_notdefault fields since these have not
1107c478bd9Sstevel@tonic-gate 	 * been explicitly set for the phyint.
1117c478bd9Sstevel@tonic-gate 	 */
1127c478bd9Sstevel@tonic-gate 	for (i = 0; i < I_IFSIZE; i++)
1137c478bd9Sstevel@tonic-gate 		pi->pi_config[i].cf_value = ifdefaults[i].cf_value;
1147c478bd9Sstevel@tonic-gate 
1157c478bd9Sstevel@tonic-gate 	/*
1167c478bd9Sstevel@tonic-gate 	 * TmpDesyncFactor is used to desynchronize temporary token
1177c478bd9Sstevel@tonic-gate 	 * generation among systems; the actual preferred lifetime value
1187c478bd9Sstevel@tonic-gate 	 * of a temporary address will be (TmpPreferredLifetime -
1197c478bd9Sstevel@tonic-gate 	 * TmpDesyncFactor).  It's a random value, with a user-configurable
1207c478bd9Sstevel@tonic-gate 	 * maximum value.  The value is constant throughout the lifetime
1217c478bd9Sstevel@tonic-gate 	 * of the in.ndpd process, but can change if the daemon is restarted,
1227c478bd9Sstevel@tonic-gate 	 * per RFC3041.
1237c478bd9Sstevel@tonic-gate 	 */
1247c478bd9Sstevel@tonic-gate 	if (pi->pi_TmpMaxDesyncFactor != 0) {
1257c478bd9Sstevel@tonic-gate 		time_t seed = time(NULL);
1267c478bd9Sstevel@tonic-gate 		srand((uint_t)seed);
1277c478bd9Sstevel@tonic-gate 		pi->pi_TmpDesyncFactor = rand() % pi->pi_TmpMaxDesyncFactor;
1287c478bd9Sstevel@tonic-gate 		/* we actually want [1,max], not [0,(max-1)] */
1297c478bd9Sstevel@tonic-gate 		pi->pi_TmpDesyncFactor++;
1307c478bd9Sstevel@tonic-gate 	}
1317c478bd9Sstevel@tonic-gate 	pi->pi_TmpRegenCountdown = TIMER_INFINITY;
1327c478bd9Sstevel@tonic-gate 
1337c478bd9Sstevel@tonic-gate 	pi->pi_sock = -1;
134*6e91bba0SGirish Moodalbail 	pi->pi_stateless = pi->pi_StatelessAddrConf;
135*6e91bba0SGirish Moodalbail 	pi->pi_stateful = pi->pi_StatefulAddrConf;
136*6e91bba0SGirish Moodalbail 	pi->pi_autoconf = _B_TRUE;
137*6e91bba0SGirish Moodalbail 	pi->pi_default_token = _B_TRUE;
1387c478bd9Sstevel@tonic-gate 	if (phyint_init_from_k(pi) == -1) {
1397c478bd9Sstevel@tonic-gate 		free(pi);
1407c478bd9Sstevel@tonic-gate 		return (NULL);
1417c478bd9Sstevel@tonic-gate 	}
1427c478bd9Sstevel@tonic-gate 	phyint_insert(pi);
1437c478bd9Sstevel@tonic-gate 	if (pi->pi_sock != -1) {
1447c478bd9Sstevel@tonic-gate 		if (poll_add(pi->pi_sock) == -1) {
1457c478bd9Sstevel@tonic-gate 			phyint_delete(pi);
1467c478bd9Sstevel@tonic-gate 			return (NULL);
1477c478bd9Sstevel@tonic-gate 		}
1487c478bd9Sstevel@tonic-gate 	}
1497c478bd9Sstevel@tonic-gate 	return (pi);
1507c478bd9Sstevel@tonic-gate }
1517c478bd9Sstevel@tonic-gate 
1527c478bd9Sstevel@tonic-gate /* Insert in linked list */
1537c478bd9Sstevel@tonic-gate static void
phyint_insert(struct phyint * pi)1547c478bd9Sstevel@tonic-gate phyint_insert(struct phyint *pi)
1557c478bd9Sstevel@tonic-gate {
1567c478bd9Sstevel@tonic-gate 	/* Insert in list */
1577c478bd9Sstevel@tonic-gate 	pi->pi_next = phyints;
1587c478bd9Sstevel@tonic-gate 	pi->pi_prev = NULL;
1597c478bd9Sstevel@tonic-gate 	if (phyints)
1607c478bd9Sstevel@tonic-gate 		phyints->pi_prev = pi;
1617c478bd9Sstevel@tonic-gate 	phyints = pi;
1623173664eSapersson 	num_of_phyints++;
1637c478bd9Sstevel@tonic-gate }
1647c478bd9Sstevel@tonic-gate 
1657c478bd9Sstevel@tonic-gate /*
1667c478bd9Sstevel@tonic-gate  * Initialize both the phyint data structure and the pi_sock for
1677c478bd9Sstevel@tonic-gate  * sending and receving on the interface.
1687c478bd9Sstevel@tonic-gate  * Extract information from the kernel (if present) and set pi_kernel_state.
1697c478bd9Sstevel@tonic-gate  */
1707c478bd9Sstevel@tonic-gate int
phyint_init_from_k(struct phyint * pi)1717c478bd9Sstevel@tonic-gate phyint_init_from_k(struct phyint *pi)
1727c478bd9Sstevel@tonic-gate {
1737c478bd9Sstevel@tonic-gate 	struct ipv6_mreq v6mcastr;
1747c478bd9Sstevel@tonic-gate 	struct lifreq lifr;
1757c478bd9Sstevel@tonic-gate 	int fd;
176e11c3f44Smeem 	int save_errno;
1777c478bd9Sstevel@tonic-gate 	boolean_t newsock;
1787c478bd9Sstevel@tonic-gate 	uint_t ttl;
1797c478bd9Sstevel@tonic-gate 	struct sockaddr_in6 *sin6;
1807c478bd9Sstevel@tonic-gate 
1817c478bd9Sstevel@tonic-gate 	if (debug & D_PHYINT)
1827c478bd9Sstevel@tonic-gate 		logmsg(LOG_DEBUG, "phyint_init_from_k(%s)\n", pi->pi_name);
1837c478bd9Sstevel@tonic-gate 
1847c478bd9Sstevel@tonic-gate start_over:
1857c478bd9Sstevel@tonic-gate 
1867c478bd9Sstevel@tonic-gate 	if (pi->pi_sock < 0) {
1877c478bd9Sstevel@tonic-gate 		pi->pi_sock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
1887c478bd9Sstevel@tonic-gate 		if (pi->pi_sock < 0) {
1897c478bd9Sstevel@tonic-gate 			logperror_pi(pi, "phyint_init_from_k: socket");
1907c478bd9Sstevel@tonic-gate 			return (-1);
1917c478bd9Sstevel@tonic-gate 		}
1927c478bd9Sstevel@tonic-gate 		newsock = _B_TRUE;
1937c478bd9Sstevel@tonic-gate 	} else {
1947c478bd9Sstevel@tonic-gate 		newsock = _B_FALSE;
1957c478bd9Sstevel@tonic-gate 	}
1967c478bd9Sstevel@tonic-gate 	fd = pi->pi_sock;
1977c478bd9Sstevel@tonic-gate 
1987c478bd9Sstevel@tonic-gate 	(void) strncpy(lifr.lifr_name, pi->pi_name, sizeof (lifr.lifr_name));
1997c478bd9Sstevel@tonic-gate 	lifr.lifr_name[sizeof (lifr.lifr_name) - 1] = '\0';
2007c478bd9Sstevel@tonic-gate 	if (ioctl(fd, SIOCGLIFINDEX, (char *)&lifr) < 0) {
2017c478bd9Sstevel@tonic-gate 		if (errno == ENXIO) {
2027c478bd9Sstevel@tonic-gate 			if (newsock) {
2037c478bd9Sstevel@tonic-gate 				(void) close(pi->pi_sock);
2047c478bd9Sstevel@tonic-gate 				pi->pi_sock = -1;
2057c478bd9Sstevel@tonic-gate 			}
2067c478bd9Sstevel@tonic-gate 			if (debug & D_PHYINT) {
2077c478bd9Sstevel@tonic-gate 				logmsg(LOG_DEBUG, "phyint_init_from_k(%s): "
2087c478bd9Sstevel@tonic-gate 				    "not exist\n", pi->pi_name);
2097c478bd9Sstevel@tonic-gate 			}
2107c478bd9Sstevel@tonic-gate 			return (0);
2117c478bd9Sstevel@tonic-gate 		}
2127c478bd9Sstevel@tonic-gate 		logperror_pi(pi, "phyint_init_from_k: SIOCGLIFINDEX");
2137c478bd9Sstevel@tonic-gate 		goto error;
2147c478bd9Sstevel@tonic-gate 	}
2157c478bd9Sstevel@tonic-gate 
2167c478bd9Sstevel@tonic-gate 	if (!newsock && (pi->pi_index != lifr.lifr_index)) {
2177c478bd9Sstevel@tonic-gate 		/*
2187c478bd9Sstevel@tonic-gate 		 * Interface has been re-plumbed, lets open a new socket.
2197c478bd9Sstevel@tonic-gate 		 * This situation can occur if plumb/unplumb are happening
2207c478bd9Sstevel@tonic-gate 		 * quite frequently.
2217c478bd9Sstevel@tonic-gate 		 */
2227c478bd9Sstevel@tonic-gate 
2237c478bd9Sstevel@tonic-gate 		phyint_cleanup(pi);
2247c478bd9Sstevel@tonic-gate 		goto start_over;
2257c478bd9Sstevel@tonic-gate 	}
2267c478bd9Sstevel@tonic-gate 
2277c478bd9Sstevel@tonic-gate 	pi->pi_index = lifr.lifr_index;
2287c478bd9Sstevel@tonic-gate 
2297c478bd9Sstevel@tonic-gate 	if (ioctl(fd, SIOCGLIFFLAGS, (char *)&lifr) < 0) {
2307c478bd9Sstevel@tonic-gate 		logperror_pi(pi, "phyint_init_from_k: ioctl (get flags)");
2317c478bd9Sstevel@tonic-gate 		goto error;
2327c478bd9Sstevel@tonic-gate 	}
2337c478bd9Sstevel@tonic-gate 	pi->pi_flags = lifr.lifr_flags;
2347c478bd9Sstevel@tonic-gate 
2357c478bd9Sstevel@tonic-gate 	/*
23669bb4bb4Scarlsonj 	 * If the link local interface is not up yet or it's IFF_UP and the
23769bb4bb4Scarlsonj 	 * IFF_NOLOCAL flag is set, then ignore the interface.
2387c478bd9Sstevel@tonic-gate 	 */
2397c478bd9Sstevel@tonic-gate 	if (!(pi->pi_flags & IFF_UP) || (pi->pi_flags & IFF_NOLOCAL)) {
2407c478bd9Sstevel@tonic-gate 		if (newsock) {
2417c478bd9Sstevel@tonic-gate 			(void) close(pi->pi_sock);
2427c478bd9Sstevel@tonic-gate 			pi->pi_sock = -1;
2437c478bd9Sstevel@tonic-gate 		}
244*6e91bba0SGirish Moodalbail 
2457c478bd9Sstevel@tonic-gate 		if (debug & D_PHYINT) {
2467c478bd9Sstevel@tonic-gate 			logmsg(LOG_DEBUG, "phyint_init_from_k(%s): "
24769bb4bb4Scarlsonj 			    "IFF_NOLOCAL or not IFF_UP\n", pi->pi_name);
2487c478bd9Sstevel@tonic-gate 		}
2497c478bd9Sstevel@tonic-gate 		return (0);
2507c478bd9Sstevel@tonic-gate 	}
2517c478bd9Sstevel@tonic-gate 	pi->pi_kernel_state |= PI_PRESENT;
2527c478bd9Sstevel@tonic-gate 
2537c478bd9Sstevel@tonic-gate 	if (ioctl(fd, SIOCGLIFMTU, (caddr_t)&lifr) < 0) {
2547c478bd9Sstevel@tonic-gate 		logperror_pi(pi, "phyint_init_from_k: ioctl (get mtu)");
2557c478bd9Sstevel@tonic-gate 		goto error;
2567c478bd9Sstevel@tonic-gate 	}
2577c478bd9Sstevel@tonic-gate 	pi->pi_mtu = lifr.lifr_mtu;
2587c478bd9Sstevel@tonic-gate 
2597c478bd9Sstevel@tonic-gate 	if (ioctl(fd, SIOCGLIFADDR, (char *)&lifr) < 0) {
2607c478bd9Sstevel@tonic-gate 		logperror_pi(pi, "phyint_init_from_k: SIOCGLIFADDR");
2617c478bd9Sstevel@tonic-gate 		goto error;
2627c478bd9Sstevel@tonic-gate 	}
2637c478bd9Sstevel@tonic-gate 	sin6 = (struct sockaddr_in6 *)&lifr.lifr_addr;
2647c478bd9Sstevel@tonic-gate 	pi->pi_ifaddr = sin6->sin6_addr;
2657c478bd9Sstevel@tonic-gate 
266*6e91bba0SGirish Moodalbail 	if (pi->pi_autoconf && pi->pi_default_token) {
267*6e91bba0SGirish Moodalbail 		if (ioctl(fd, SIOCGLIFTOKEN, (char *)&lifr) < 0) {
268*6e91bba0SGirish Moodalbail 			logperror_pi(pi, "phyint_init_from_k: SIOCGLIFTOKEN");
269*6e91bba0SGirish Moodalbail 			goto error;
270*6e91bba0SGirish Moodalbail 		}
271*6e91bba0SGirish Moodalbail 		/* Ignore interface if the token is all zeros */
272*6e91bba0SGirish Moodalbail 		sin6 = (struct sockaddr_in6 *)&lifr.lifr_token;
273*6e91bba0SGirish Moodalbail 		if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
274*6e91bba0SGirish Moodalbail 			logmsg(LOG_ERR, "ignoring interface %s: zero token\n",
275*6e91bba0SGirish Moodalbail 			    pi->pi_name);
276*6e91bba0SGirish Moodalbail 			goto error;
277*6e91bba0SGirish Moodalbail 		}
278*6e91bba0SGirish Moodalbail 		pi->pi_token = sin6->sin6_addr;
279*6e91bba0SGirish Moodalbail 		pi->pi_token_length = lifr.lifr_addrlen;
2807c478bd9Sstevel@tonic-gate 	}
2817c478bd9Sstevel@tonic-gate 
2827c478bd9Sstevel@tonic-gate 	/*
2837c478bd9Sstevel@tonic-gate 	 * Guess a remote token for POINTOPOINT by looking at
2847c478bd9Sstevel@tonic-gate 	 * the link-local destination address.
2857c478bd9Sstevel@tonic-gate 	 */
2867c478bd9Sstevel@tonic-gate 	if (pi->pi_flags & IFF_POINTOPOINT) {
2877c478bd9Sstevel@tonic-gate 		if (ioctl(fd, SIOCGLIFDSTADDR, (char *)&lifr) < 0) {
2887c478bd9Sstevel@tonic-gate 			logperror_pi(pi, "phyint_init_from_k: SIOCGLIFDSTADDR");
2897c478bd9Sstevel@tonic-gate 			goto error;
2907c478bd9Sstevel@tonic-gate 		}
2917c478bd9Sstevel@tonic-gate 		sin6 = (struct sockaddr_in6 *)&lifr.lifr_addr;
2927c478bd9Sstevel@tonic-gate 		if (sin6->sin6_family != AF_INET6 ||
2937c478bd9Sstevel@tonic-gate 		    IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) ||
2947c478bd9Sstevel@tonic-gate 		    !IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
2957c478bd9Sstevel@tonic-gate 			pi->pi_dst_token = in6addr_any;
2967c478bd9Sstevel@tonic-gate 		} else {
2977c478bd9Sstevel@tonic-gate 			pi->pi_dst_token = sin6->sin6_addr;
2987c478bd9Sstevel@tonic-gate 			/* Clear link-local prefix (first 10 bits) */
2997c478bd9Sstevel@tonic-gate 			pi->pi_dst_token.s6_addr[0] = 0;
3007c478bd9Sstevel@tonic-gate 			pi->pi_dst_token.s6_addr[1] &= 0x3f;
3017c478bd9Sstevel@tonic-gate 		}
3027c478bd9Sstevel@tonic-gate 	} else {
3037c478bd9Sstevel@tonic-gate 		pi->pi_dst_token = in6addr_any;
3047c478bd9Sstevel@tonic-gate 	}
3057c478bd9Sstevel@tonic-gate 
3067c478bd9Sstevel@tonic-gate 	if (newsock) {
3077c478bd9Sstevel@tonic-gate 		icmp6_filter_t filter;
3087c478bd9Sstevel@tonic-gate 		int on = 1;
3097c478bd9Sstevel@tonic-gate 
3107c478bd9Sstevel@tonic-gate 		/* Set default values */
3117c478bd9Sstevel@tonic-gate 		pi->pi_LinkMTU = pi->pi_mtu;
3127c478bd9Sstevel@tonic-gate 		pi->pi_CurHopLimit = 0;
3137c478bd9Sstevel@tonic-gate 		pi->pi_BaseReachableTime = ND_REACHABLE_TIME;
3147c478bd9Sstevel@tonic-gate 		phyint_reach_random(pi, _B_FALSE);
3157c478bd9Sstevel@tonic-gate 		pi->pi_RetransTimer = ND_RETRANS_TIMER;
3167c478bd9Sstevel@tonic-gate 
3177c478bd9Sstevel@tonic-gate 		/* Setup socket for transmission and reception */
3187c478bd9Sstevel@tonic-gate 		if (setsockopt(fd, IPPROTO_IPV6,
3197c478bd9Sstevel@tonic-gate 		    IPV6_BOUND_IF, (char *)&pi->pi_index,
3207c478bd9Sstevel@tonic-gate 		    sizeof (pi->pi_index)) < 0) {
3217c478bd9Sstevel@tonic-gate 			logperror_pi(pi, "phyint_init_from_k: setsockopt "
3227c478bd9Sstevel@tonic-gate 			    "IPV6_BOUND_IF");
3237c478bd9Sstevel@tonic-gate 			goto error;
3247c478bd9Sstevel@tonic-gate 		}
3257c478bd9Sstevel@tonic-gate 
3267c478bd9Sstevel@tonic-gate 		ttl = IPV6_MAX_HOPS;
3277c478bd9Sstevel@tonic-gate 		if (setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS,
3287c478bd9Sstevel@tonic-gate 		    (char *)&ttl, sizeof (ttl)) < 0) {
3297c478bd9Sstevel@tonic-gate 			logperror_pi(pi, "phyint_init_from_k: setsockopt "
3307c478bd9Sstevel@tonic-gate 			    "IPV6_UNICAST_HOPS");
3317c478bd9Sstevel@tonic-gate 			goto error;
3327c478bd9Sstevel@tonic-gate 		}
3337c478bd9Sstevel@tonic-gate 
3347c478bd9Sstevel@tonic-gate 		if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
3357c478bd9Sstevel@tonic-gate 		    (char *)&ttl, sizeof (ttl)) < 0) {
3367c478bd9Sstevel@tonic-gate 			logperror_pi(pi, "phyint_init_from_k: setsockopt "
3377c478bd9Sstevel@tonic-gate 			    "IPV6_MULTICAST_HOPS");
3387c478bd9Sstevel@tonic-gate 			goto error;
3397c478bd9Sstevel@tonic-gate 		}
3407c478bd9Sstevel@tonic-gate 
3417c478bd9Sstevel@tonic-gate 		v6mcastr.ipv6mr_multiaddr = all_nodes_mcast;
3427c478bd9Sstevel@tonic-gate 		v6mcastr.ipv6mr_interface = pi->pi_index;
3437c478bd9Sstevel@tonic-gate 		if (setsockopt(fd, IPPROTO_IPV6, IPV6_JOIN_GROUP,
3447c478bd9Sstevel@tonic-gate 		    (char *)&v6mcastr, sizeof (v6mcastr)) < 0) {
345e11c3f44Smeem 			/*
346e11c3f44Smeem 			 * One benign reason IPV6_JOIN_GROUP could fail is
347e11c3f44Smeem 			 * when `pi' has been placed into an IPMP group and we
348e11c3f44Smeem 			 * haven't yet processed the routing socket message
349e11c3f44Smeem 			 * informing us of its disappearance.  As such, if
350e11c3f44Smeem 			 * it's now in a group, don't print an error.
351e11c3f44Smeem 			 */
352e11c3f44Smeem 			save_errno = errno;
353e11c3f44Smeem 			(void) strlcpy(lifr.lifr_name, pi->pi_name, LIFNAMSIZ);
354e11c3f44Smeem 			if (ioctl(fd, SIOCGLIFGROUPNAME, &lifr) == -1 ||
355e11c3f44Smeem 			    lifr.lifr_groupname[0] == '\0') {
356e11c3f44Smeem 				errno = save_errno;
357e11c3f44Smeem 				logperror_pi(pi, "phyint_init_from_k: "
358e11c3f44Smeem 				    "setsockopt IPV6_JOIN_GROUP");
359e11c3f44Smeem 			}
3607c478bd9Sstevel@tonic-gate 			goto error;
3617c478bd9Sstevel@tonic-gate 		}
3627c478bd9Sstevel@tonic-gate 		pi->pi_state |= PI_JOINED_ALLNODES;
3637c478bd9Sstevel@tonic-gate 		pi->pi_kernel_state |= PI_JOINED_ALLNODES;
3647c478bd9Sstevel@tonic-gate 
3657c478bd9Sstevel@tonic-gate 		/*
3667c478bd9Sstevel@tonic-gate 		 * Filter out so that we only receive router advertisements and
3677c478bd9Sstevel@tonic-gate 		 * router solicitations.
3687c478bd9Sstevel@tonic-gate 		 */
3697c478bd9Sstevel@tonic-gate 		ICMP6_FILTER_SETBLOCKALL(&filter);
3707c478bd9Sstevel@tonic-gate 		ICMP6_FILTER_SETPASS(ND_ROUTER_SOLICIT, &filter);
3717c478bd9Sstevel@tonic-gate 		ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT, &filter);
3727c478bd9Sstevel@tonic-gate 
3737c478bd9Sstevel@tonic-gate 		if (setsockopt(fd, IPPROTO_ICMPV6, ICMP6_FILTER,
3747c478bd9Sstevel@tonic-gate 		    (char *)&filter, sizeof (filter)) < 0) {
3757c478bd9Sstevel@tonic-gate 			logperror_pi(pi, "phyint_init_from_k: setsockopt "
3767c478bd9Sstevel@tonic-gate 			    "ICMP6_FILTER");
3777c478bd9Sstevel@tonic-gate 			goto error;
3787c478bd9Sstevel@tonic-gate 		}
3797c478bd9Sstevel@tonic-gate 
3807c478bd9Sstevel@tonic-gate 		/* Enable receipt of ancillary data */
3817c478bd9Sstevel@tonic-gate 		if (setsockopt(fd, IPPROTO_IPV6, IPV6_RECVHOPLIMIT,
3827c478bd9Sstevel@tonic-gate 		    (char *)&on, sizeof (on)) < 0) {
3837c478bd9Sstevel@tonic-gate 			logperror_pi(pi, "phyint_init_from_k: setsockopt "
3847c478bd9Sstevel@tonic-gate 			    "IPV6_RECVHOPLIMIT");
3857c478bd9Sstevel@tonic-gate 			goto error;
3867c478bd9Sstevel@tonic-gate 		}
3877c478bd9Sstevel@tonic-gate 		if (setsockopt(fd, IPPROTO_IPV6, IPV6_RECVRTHDR,
3887c478bd9Sstevel@tonic-gate 		    (char *)&on, sizeof (on)) < 0) {
3897c478bd9Sstevel@tonic-gate 			logperror_pi(pi, "phyint_init_from_k: setsockopt "
3907c478bd9Sstevel@tonic-gate 			    "IPV6_RECVRTHDR");
3917c478bd9Sstevel@tonic-gate 			goto error;
3927c478bd9Sstevel@tonic-gate 		}
3937c478bd9Sstevel@tonic-gate 	}
3947c478bd9Sstevel@tonic-gate 
3957c478bd9Sstevel@tonic-gate 	if (pi->pi_AdvSendAdvertisements &&
3967c478bd9Sstevel@tonic-gate 	    !(pi->pi_kernel_state & PI_JOINED_ALLROUTERS)) {
3977c478bd9Sstevel@tonic-gate 		v6mcastr.ipv6mr_multiaddr = all_routers_mcast;
3987c478bd9Sstevel@tonic-gate 		v6mcastr.ipv6mr_interface = pi->pi_index;
3997c478bd9Sstevel@tonic-gate 		if (setsockopt(fd, IPPROTO_IPV6, IPV6_JOIN_GROUP,
4007c478bd9Sstevel@tonic-gate 		    (char *)&v6mcastr, sizeof (v6mcastr)) < 0) {
401e11c3f44Smeem 			/*
402e11c3f44Smeem 			 * See IPV6_JOIN_GROUP comment above.
403e11c3f44Smeem 			 */
404e11c3f44Smeem 			save_errno = errno;
405e11c3f44Smeem 			(void) strlcpy(lifr.lifr_name, pi->pi_name, LIFNAMSIZ);
406e11c3f44Smeem 			if (ioctl(fd, SIOCGLIFGROUPNAME, &lifr) == -1 ||
407e11c3f44Smeem 			    lifr.lifr_groupname[0] == '\0') {
408e11c3f44Smeem 				errno = save_errno;
409e11c3f44Smeem 				logperror_pi(pi, "phyint_init_from_k: "
410e11c3f44Smeem 				    "setsockopt IPV6_JOIN_GROUP");
411e11c3f44Smeem 			}
4127c478bd9Sstevel@tonic-gate 			goto error;
4137c478bd9Sstevel@tonic-gate 		}
4147c478bd9Sstevel@tonic-gate 		pi->pi_state |= PI_JOINED_ALLROUTERS;
4157c478bd9Sstevel@tonic-gate 		pi->pi_kernel_state |= PI_JOINED_ALLROUTERS;
4167c478bd9Sstevel@tonic-gate 	}
4177c478bd9Sstevel@tonic-gate 	/*
4187c478bd9Sstevel@tonic-gate 	 * If not already set, set the IFF_ROUTER interface flag based on
4197c478bd9Sstevel@tonic-gate 	 * AdvSendAdvertisements.  Note that this will also enable IPv6
4207c478bd9Sstevel@tonic-gate 	 * forwarding on the interface.  We don't clear IFF_ROUTER if we're
4217c478bd9Sstevel@tonic-gate 	 * not advertising on an interface, because we could still be
4227c478bd9Sstevel@tonic-gate 	 * forwarding on those interfaces.
4237c478bd9Sstevel@tonic-gate 	 */
4247c478bd9Sstevel@tonic-gate 	(void) strncpy(lifr.lifr_name, pi->pi_name, sizeof (lifr.lifr_name));
4257c478bd9Sstevel@tonic-gate 	lifr.lifr_name[sizeof (lifr.lifr_name) - 1] = '\0';
4267c478bd9Sstevel@tonic-gate 	if (ioctl(fd, SIOCGLIFFLAGS, (char *)&lifr) < 0) {
4277c478bd9Sstevel@tonic-gate 		logperror_pi(pi, "phyint_init_from_k: SIOCGLIFFLAGS");
4287c478bd9Sstevel@tonic-gate 		goto error;
4297c478bd9Sstevel@tonic-gate 	}
4307c478bd9Sstevel@tonic-gate 	if (!(lifr.lifr_flags & IFF_ROUTER) && pi->pi_AdvSendAdvertisements) {
4317c478bd9Sstevel@tonic-gate 		lifr.lifr_flags |= IFF_ROUTER;
4327c478bd9Sstevel@tonic-gate 
4337c478bd9Sstevel@tonic-gate 		if (ioctl(fd, SIOCSLIFFLAGS, (char *)&lifr) < 0) {
4347c478bd9Sstevel@tonic-gate 			logperror_pi(pi, "phyint_init_from_k: SIOCSLIFFLAGS");
4357c478bd9Sstevel@tonic-gate 			goto error;
4367c478bd9Sstevel@tonic-gate 		}
4377c478bd9Sstevel@tonic-gate 		pi->pi_flags = lifr.lifr_flags;
4387c478bd9Sstevel@tonic-gate 	}
4397c478bd9Sstevel@tonic-gate 
4407c478bd9Sstevel@tonic-gate 	/* Set linkinfo parameters */
4417c478bd9Sstevel@tonic-gate 	(void) strncpy(lifr.lifr_name, pi->pi_name, sizeof (lifr.lifr_name));
4427c478bd9Sstevel@tonic-gate 	lifr.lifr_name[sizeof (lifr.lifr_name) - 1] = '\0';
4437c478bd9Sstevel@tonic-gate 	lifr.lifr_ifinfo.lir_maxhops = pi->pi_CurHopLimit;
4447c478bd9Sstevel@tonic-gate 	lifr.lifr_ifinfo.lir_reachtime = pi->pi_ReachableTime;
4457c478bd9Sstevel@tonic-gate 	lifr.lifr_ifinfo.lir_reachretrans = pi->pi_RetransTimer;
44600834081Spwernau 	/* Setting maxmtu to 0 means that we're leaving the MTU alone */
44700834081Spwernau 	lifr.lifr_ifinfo.lir_maxmtu = 0;
4487c478bd9Sstevel@tonic-gate 	if (ioctl(fd, SIOCSLIFLNKINFO, (char *)&lifr) < 0) {
4497c478bd9Sstevel@tonic-gate 		logperror_pi(pi, "phyint_init_from_k: SIOCSLIFLNKINFO");
4507c478bd9Sstevel@tonic-gate 		goto error;
4517c478bd9Sstevel@tonic-gate 	}
4527c478bd9Sstevel@tonic-gate 	if (debug & D_PHYINT) {
4537c478bd9Sstevel@tonic-gate 		logmsg(LOG_DEBUG, "phyint_init_from_k(%s): done\n",
4547c478bd9Sstevel@tonic-gate 		    pi->pi_name);
4557c478bd9Sstevel@tonic-gate 	}
4567c478bd9Sstevel@tonic-gate 	return (0);
4577c478bd9Sstevel@tonic-gate 
4587c478bd9Sstevel@tonic-gate error:
4597c478bd9Sstevel@tonic-gate 	/* Pretend the interface does not exist in the kernel */
4607c478bd9Sstevel@tonic-gate 	pi->pi_kernel_state &= ~PI_PRESENT;
4617c478bd9Sstevel@tonic-gate 	if (newsock) {
4627c478bd9Sstevel@tonic-gate 		(void) close(pi->pi_sock);
4637c478bd9Sstevel@tonic-gate 		pi->pi_sock = -1;
4647c478bd9Sstevel@tonic-gate 	}
4657c478bd9Sstevel@tonic-gate 	return (-1);
4667c478bd9Sstevel@tonic-gate }
4677c478bd9Sstevel@tonic-gate 
4687c478bd9Sstevel@tonic-gate /*
4697c478bd9Sstevel@tonic-gate  * Delete (unlink and free).
4707c478bd9Sstevel@tonic-gate  * Handles delete of things that have not yet been inserted in the list.
4717c478bd9Sstevel@tonic-gate  */
4727c478bd9Sstevel@tonic-gate void
phyint_delete(struct phyint * pi)4737c478bd9Sstevel@tonic-gate phyint_delete(struct phyint *pi)
4747c478bd9Sstevel@tonic-gate {
4757c478bd9Sstevel@tonic-gate 	if (debug & D_PHYINT)
4767c478bd9Sstevel@tonic-gate 		logmsg(LOG_DEBUG, "phyint_delete(%s)\n", pi->pi_name);
4777c478bd9Sstevel@tonic-gate 
4783173664eSapersson 	assert(num_of_phyints > 0);
4793173664eSapersson 
4807c478bd9Sstevel@tonic-gate 	while (pi->pi_router_list)
4817c478bd9Sstevel@tonic-gate 		router_delete(pi->pi_router_list);
482*6e91bba0SGirish Moodalbail 	while (pi->pi_prefix_list) {
483*6e91bba0SGirish Moodalbail 		prefix_update_ipadm_addrobj(pi->pi_prefix_list, _B_FALSE);
4847c478bd9Sstevel@tonic-gate 		prefix_delete(pi->pi_prefix_list);
485*6e91bba0SGirish Moodalbail 	}
4867c478bd9Sstevel@tonic-gate 	while (pi->pi_adv_prefix_list)
4877c478bd9Sstevel@tonic-gate 		adv_prefix_delete(pi->pi_adv_prefix_list);
4887c478bd9Sstevel@tonic-gate 
4897c478bd9Sstevel@tonic-gate 	if (pi->pi_sock != -1) {
4907c478bd9Sstevel@tonic-gate 		(void) poll_remove(pi->pi_sock);
4917c478bd9Sstevel@tonic-gate 		if (close(pi->pi_sock) < 0) {
4927c478bd9Sstevel@tonic-gate 			logperror_pi(pi, "phyint_delete: close");
4937c478bd9Sstevel@tonic-gate 		}
4947c478bd9Sstevel@tonic-gate 		pi->pi_sock = -1;
4957c478bd9Sstevel@tonic-gate 	}
4967c478bd9Sstevel@tonic-gate 
4977c478bd9Sstevel@tonic-gate 	if (pi->pi_prev == NULL) {
4987c478bd9Sstevel@tonic-gate 		if (phyints == pi)
4997c478bd9Sstevel@tonic-gate 			phyints = pi->pi_next;
5007c478bd9Sstevel@tonic-gate 	} else {
5017c478bd9Sstevel@tonic-gate 		pi->pi_prev->pi_next = pi->pi_next;
5027c478bd9Sstevel@tonic-gate 	}
5037c478bd9Sstevel@tonic-gate 	if (pi->pi_next != NULL)
5047c478bd9Sstevel@tonic-gate 		pi->pi_next->pi_prev = pi->pi_prev;
5057c478bd9Sstevel@tonic-gate 	pi->pi_next = pi->pi_prev = NULL;
5067c478bd9Sstevel@tonic-gate 	free(pi);
5073173664eSapersson 	num_of_phyints--;
5087c478bd9Sstevel@tonic-gate }
5097c478bd9Sstevel@tonic-gate 
5107c478bd9Sstevel@tonic-gate /*
511b12d9c4eSmeem  * Called with the number of milliseconds elapsed since the last call.
5127c478bd9Sstevel@tonic-gate  * Determines if any timeout event has occurred and
5137c478bd9Sstevel@tonic-gate  * returns the number of milliseconds until the next timeout event
514b12d9c4eSmeem  * for the phyint itself (excluding prefixes and routers).
5157c478bd9Sstevel@tonic-gate  * Returns TIMER_INFINITY for "never".
5167c478bd9Sstevel@tonic-gate  */
5177c478bd9Sstevel@tonic-gate uint_t
phyint_timer(struct phyint * pi,uint_t elapsed)5187c478bd9Sstevel@tonic-gate phyint_timer(struct phyint *pi, uint_t elapsed)
5197c478bd9Sstevel@tonic-gate {
5207c478bd9Sstevel@tonic-gate 	uint_t next = TIMER_INFINITY;
5217c478bd9Sstevel@tonic-gate 
5227c478bd9Sstevel@tonic-gate 	if (pi->pi_AdvSendAdvertisements) {
5237c478bd9Sstevel@tonic-gate 		if (pi->pi_adv_state != NO_ADV) {
5247c478bd9Sstevel@tonic-gate 			int old_state = pi->pi_adv_state;
5257c478bd9Sstevel@tonic-gate 
5267c478bd9Sstevel@tonic-gate 			if (debug & (D_STATE|D_PHYINT)) {
5277c478bd9Sstevel@tonic-gate 				logmsg(LOG_DEBUG, "phyint_timer ADV(%s) "
5287c478bd9Sstevel@tonic-gate 				    "state %d\n", pi->pi_name, (int)old_state);
5297c478bd9Sstevel@tonic-gate 			}
5307c478bd9Sstevel@tonic-gate 			next = advertise_event(pi, ADV_TIMER, elapsed);
5317c478bd9Sstevel@tonic-gate 			if (debug & D_STATE) {
5327c478bd9Sstevel@tonic-gate 				logmsg(LOG_DEBUG, "phyint_timer ADV(%s) "
5337c478bd9Sstevel@tonic-gate 				    "state %d -> %d\n",
5347c478bd9Sstevel@tonic-gate 				    pi->pi_name, (int)old_state,
5357c478bd9Sstevel@tonic-gate 				    (int)pi->pi_adv_state);
5367c478bd9Sstevel@tonic-gate 			}
5377c478bd9Sstevel@tonic-gate 		}
5387c478bd9Sstevel@tonic-gate 	} else {
5397c478bd9Sstevel@tonic-gate 		if (pi->pi_sol_state != NO_SOLICIT) {
5407c478bd9Sstevel@tonic-gate 			int old_state = pi->pi_sol_state;
5417c478bd9Sstevel@tonic-gate 
5427c478bd9Sstevel@tonic-gate 			if (debug & (D_STATE|D_PHYINT)) {
5437c478bd9Sstevel@tonic-gate 				logmsg(LOG_DEBUG, "phyint_timer SOL(%s) "
5447c478bd9Sstevel@tonic-gate 				    "state %d\n", pi->pi_name, (int)old_state);
5457c478bd9Sstevel@tonic-gate 			}
5467c478bd9Sstevel@tonic-gate 			next = solicit_event(pi, SOL_TIMER, elapsed);
5477c478bd9Sstevel@tonic-gate 			if (debug & D_STATE) {
5487c478bd9Sstevel@tonic-gate 				logmsg(LOG_DEBUG, "phyint_timer SOL(%s) "
5497c478bd9Sstevel@tonic-gate 				    "state %d -> %d\n",
5507c478bd9Sstevel@tonic-gate 				    pi->pi_name, (int)old_state,
5517c478bd9Sstevel@tonic-gate 				    (int)pi->pi_sol_state);
5527c478bd9Sstevel@tonic-gate 			}
5537c478bd9Sstevel@tonic-gate 		}
5547c478bd9Sstevel@tonic-gate 	}
5557c478bd9Sstevel@tonic-gate 
5567c478bd9Sstevel@tonic-gate 	/*
5577c478bd9Sstevel@tonic-gate 	 * If the phyint has been unplumbed, we don't want to call
5587c478bd9Sstevel@tonic-gate 	 * phyint_reach_random. We will be in the NO_ADV or NO_SOLICIT state.
5597c478bd9Sstevel@tonic-gate 	 */
5607c478bd9Sstevel@tonic-gate 	if ((pi->pi_AdvSendAdvertisements && (pi->pi_adv_state != NO_ADV)) ||
5617c478bd9Sstevel@tonic-gate 	    (!pi->pi_AdvSendAdvertisements &&
5627c478bd9Sstevel@tonic-gate 	    (pi->pi_sol_state != NO_SOLICIT))) {
5637c478bd9Sstevel@tonic-gate 		pi->pi_reach_time_since_random += elapsed;
5647c478bd9Sstevel@tonic-gate 		if (pi->pi_reach_time_since_random >= MAX_REACH_RANDOM_INTERVAL)
5657c478bd9Sstevel@tonic-gate 			phyint_reach_random(pi, _B_TRUE);
5667c478bd9Sstevel@tonic-gate 	}
5677c478bd9Sstevel@tonic-gate 
5687c478bd9Sstevel@tonic-gate 	return (next);
5697c478bd9Sstevel@tonic-gate }
5707c478bd9Sstevel@tonic-gate 
5717c478bd9Sstevel@tonic-gate static void
phyint_print(struct phyint * pi)5727c478bd9Sstevel@tonic-gate phyint_print(struct phyint *pi)
5737c478bd9Sstevel@tonic-gate {
5747c478bd9Sstevel@tonic-gate 	struct prefix *pr;
5757c478bd9Sstevel@tonic-gate 	struct adv_prefix *adv_pr;
5767c478bd9Sstevel@tonic-gate 	struct router *dr;
5777c478bd9Sstevel@tonic-gate 	char abuf[INET6_ADDRSTRLEN];
5787c478bd9Sstevel@tonic-gate 
5797c478bd9Sstevel@tonic-gate 	logmsg(LOG_DEBUG, "Phyint %s index %d state %x, kernel %x, "
5808121d73fSseb 	    "num routers %d\n",
5818121d73fSseb 	    pi->pi_name, pi->pi_index, pi->pi_state, pi->pi_kernel_state,
5827c478bd9Sstevel@tonic-gate 	    pi->pi_num_k_routers);
583e11c3f44Smeem 	logmsg(LOG_DEBUG, "\taddress: %s flags %llx\n",
5847c478bd9Sstevel@tonic-gate 	    inet_ntop(AF_INET6, (void *)&pi->pi_ifaddr,
5857c478bd9Sstevel@tonic-gate 	    abuf, sizeof (abuf)), pi->pi_flags);
586e11c3f44Smeem 	logmsg(LOG_DEBUG, "\tsock %d mtu %d\n", pi->pi_sock, pi->pi_mtu);
587e11c3f44Smeem 	logmsg(LOG_DEBUG, "\ttoken: len %d %s\n", pi->pi_token_length,
5887c478bd9Sstevel@tonic-gate 	    inet_ntop(AF_INET6, (void *)&pi->pi_token,
5897c478bd9Sstevel@tonic-gate 	    abuf, sizeof (abuf)));
5907c478bd9Sstevel@tonic-gate 	if (pi->pi_TmpAddrsEnabled) {
5917c478bd9Sstevel@tonic-gate 		logmsg(LOG_DEBUG, "\ttmp_token: %s\n",
5927c478bd9Sstevel@tonic-gate 		    inet_ntop(AF_INET6, (void *)&pi->pi_tmp_token,
593b12d9c4eSmeem 		    abuf, sizeof (abuf)));
5947c478bd9Sstevel@tonic-gate 		logmsg(LOG_DEBUG, "\ttmp config: pref %d valid %d "
5957c478bd9Sstevel@tonic-gate 		    "maxdesync %d desync %d regen %d\n",
5967c478bd9Sstevel@tonic-gate 		    pi->pi_TmpPreferredLifetime, pi->pi_TmpValidLifetime,
5977c478bd9Sstevel@tonic-gate 		    pi->pi_TmpMaxDesyncFactor, pi->pi_TmpDesyncFactor,
5987c478bd9Sstevel@tonic-gate 		    pi->pi_TmpRegenAdvance);
5997c478bd9Sstevel@tonic-gate 	}
6007c478bd9Sstevel@tonic-gate 	if (pi->pi_flags & IFF_POINTOPOINT) {
6017c478bd9Sstevel@tonic-gate 		logmsg(LOG_DEBUG, "\tdst_token: %s\n",
6027c478bd9Sstevel@tonic-gate 		    inet_ntop(AF_INET6, (void *)&pi->pi_dst_token,
603b12d9c4eSmeem 		    abuf, sizeof (abuf)));
6047c478bd9Sstevel@tonic-gate 	}
6057c478bd9Sstevel@tonic-gate 	logmsg(LOG_DEBUG, "\tLinkMTU %d CurHopLimit %d "
6067c478bd9Sstevel@tonic-gate 	    "BaseReachableTime %d\n\tReachableTime %d RetransTimer %d\n",
6077c478bd9Sstevel@tonic-gate 	    pi->pi_LinkMTU, pi->pi_CurHopLimit, pi->pi_BaseReachableTime,
6087c478bd9Sstevel@tonic-gate 	    pi->pi_ReachableTime, pi->pi_RetransTimer);
6097c478bd9Sstevel@tonic-gate 	if (!pi->pi_AdvSendAdvertisements) {
6107c478bd9Sstevel@tonic-gate 		/* Solicit state */
6117c478bd9Sstevel@tonic-gate 		logmsg(LOG_DEBUG, "\tSOLICIT: time_left %d state %d count %d\n",
6127c478bd9Sstevel@tonic-gate 		    pi->pi_sol_time_left, pi->pi_sol_state, pi->pi_sol_count);
6137c478bd9Sstevel@tonic-gate 	} else {
6147c478bd9Sstevel@tonic-gate 		/* Advertise state */
6157c478bd9Sstevel@tonic-gate 		logmsg(LOG_DEBUG, "\tADVERT: time_left %d state %d count %d "
6167c478bd9Sstevel@tonic-gate 		    "since last %d\n",
6177c478bd9Sstevel@tonic-gate 		    pi->pi_adv_time_left, pi->pi_adv_state, pi->pi_adv_count,
6187c478bd9Sstevel@tonic-gate 		    pi->pi_adv_time_since_sent);
6197c478bd9Sstevel@tonic-gate 		print_iflist(pi->pi_config);
6207c478bd9Sstevel@tonic-gate 	}
6217c478bd9Sstevel@tonic-gate 	for (pr = pi->pi_prefix_list; pr != NULL; pr = pr->pr_next)
6227c478bd9Sstevel@tonic-gate 		prefix_print(pr);
6237c478bd9Sstevel@tonic-gate 
6247c478bd9Sstevel@tonic-gate 	for (adv_pr = pi->pi_adv_prefix_list; adv_pr != NULL;
6257c478bd9Sstevel@tonic-gate 	    adv_pr = adv_pr->adv_pr_next) {
6267c478bd9Sstevel@tonic-gate 		adv_prefix_print(adv_pr);
6277c478bd9Sstevel@tonic-gate 	}
6287c478bd9Sstevel@tonic-gate 
6297c478bd9Sstevel@tonic-gate 	for (dr = pi->pi_router_list; dr != NULL; dr = dr->dr_next)
6307c478bd9Sstevel@tonic-gate 		router_print(dr);
6317c478bd9Sstevel@tonic-gate 
6327c478bd9Sstevel@tonic-gate 	logmsg(LOG_DEBUG, "\n");
6337c478bd9Sstevel@tonic-gate }
6347c478bd9Sstevel@tonic-gate 
635e11c3f44Smeem 
636e11c3f44Smeem /*
637e11c3f44Smeem  * Store the LLA for the phyint `pi' `lifrp'.  Returns 0 on success, or
638e11c3f44Smeem  * -1 on failure.
639e11c3f44Smeem  *
640e11c3f44Smeem  * Note that we do not cache the hardware address since there's no reliable
641e11c3f44Smeem  * mechanism to determine when it's become stale.
642e11c3f44Smeem  */
643e11c3f44Smeem int
phyint_get_lla(struct phyint * pi,struct lifreq * lifrp)644e11c3f44Smeem phyint_get_lla(struct phyint *pi, struct lifreq *lifrp)
645e11c3f44Smeem {
646e11c3f44Smeem 	struct sockaddr_in6 *sin6;
647e11c3f44Smeem 
648e11c3f44Smeem 	/* If this phyint doesn't have a link-layer address, bail */
649