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 5*00834081Spwernau * Common Development and Distribution License (the "License"). 6*00834081Spwernau * 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*00834081Spwernau * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 277c478bd9Sstevel@tonic-gate 287c478bd9Sstevel@tonic-gate #include "defs.h" 297c478bd9Sstevel@tonic-gate #include "tables.h" 307c478bd9Sstevel@tonic-gate 317c478bd9Sstevel@tonic-gate #include <time.h> 327c478bd9Sstevel@tonic-gate #include <inet/ip6.h> 337c478bd9Sstevel@tonic-gate 347c478bd9Sstevel@tonic-gate struct phyint *phyints = NULL; 357c478bd9Sstevel@tonic-gate 367c478bd9Sstevel@tonic-gate static void phyint_print(struct phyint *pi); 377c478bd9Sstevel@tonic-gate static void phyint_insert(struct phyint *pi); 387c478bd9Sstevel@tonic-gate 397c478bd9Sstevel@tonic-gate static boolean_t tmptoken_isvalid(struct in6_addr *token); 407c478bd9Sstevel@tonic-gate 417c478bd9Sstevel@tonic-gate static void prefix_print(struct prefix *pr); 427c478bd9Sstevel@tonic-gate static void prefix_insert(struct phyint *pi, struct prefix *pr); 437c478bd9Sstevel@tonic-gate static char *prefix_print_state(int state, char *buf, int buflen); 447c478bd9Sstevel@tonic-gate static void prefix_set(struct in6_addr *prefix, struct in6_addr addr, 457c478bd9Sstevel@tonic-gate int bits); 467c478bd9Sstevel@tonic-gate 477c478bd9Sstevel@tonic-gate static void adv_prefix_print(struct adv_prefix *adv_pr); 487c478bd9Sstevel@tonic-gate static void adv_prefix_insert(struct phyint *pi, struct adv_prefix *adv_pr); 497c478bd9Sstevel@tonic-gate static void adv_prefix_delete(struct adv_prefix *adv_pr); 507c478bd9Sstevel@tonic-gate 517c478bd9Sstevel@tonic-gate static void router_print(struct router *dr); 527c478bd9Sstevel@tonic-gate static void router_insert(struct phyint *pi, struct router *dr); 537c478bd9Sstevel@tonic-gate static void router_delete(struct router *dr); 547c478bd9Sstevel@tonic-gate static void router_add_k(struct router *dr); 557c478bd9Sstevel@tonic-gate static void router_delete_k(struct router *dr); 567c478bd9Sstevel@tonic-gate static void router_delete_onlink(struct phyint *pi); 577c478bd9Sstevel@tonic-gate 587c478bd9Sstevel@tonic-gate static int rtmseq; /* rtm_seq sequence number */ 597c478bd9Sstevel@tonic-gate 607c478bd9Sstevel@tonic-gate /* 1 week in ms */ 617c478bd9Sstevel@tonic-gate #define NDP_PREFIX_DEFAULT_LIFETIME (7*24*60*60*1000) 627c478bd9Sstevel@tonic-gate struct phyint * 637c478bd9Sstevel@tonic-gate phyint_lookup(char *name) 647c478bd9Sstevel@tonic-gate { 657c478bd9Sstevel@tonic-gate struct phyint *pi; 667c478bd9Sstevel@tonic-gate 677c478bd9Sstevel@tonic-gate if (debug & D_PHYINT) 687c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "phyint_lookup(%s)\n", name); 697c478bd9Sstevel@tonic-gate 707c478bd9Sstevel@tonic-gate for (pi = phyints; pi != NULL; pi = pi->pi_next) { 717c478bd9Sstevel@tonic-gate if (strcmp(pi->pi_name, name) == 0) 727c478bd9Sstevel@tonic-gate break; 737c478bd9Sstevel@tonic-gate } 747c478bd9Sstevel@tonic-gate return (pi); 757c478bd9Sstevel@tonic-gate } 767c478bd9Sstevel@tonic-gate 777c478bd9Sstevel@tonic-gate struct phyint * 787c478bd9Sstevel@tonic-gate phyint_lookup_on_index(uint_t ifindex) 797c478bd9Sstevel@tonic-gate { 807c478bd9Sstevel@tonic-gate struct phyint *pi; 817c478bd9Sstevel@tonic-gate 827c478bd9Sstevel@tonic-gate if (debug & D_PHYINT) 837c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "phyint_lookup_on_index(%d)\n", ifindex); 847c478bd9Sstevel@tonic-gate 857c478bd9Sstevel@tonic-gate for (pi = phyints; pi != NULL; pi = pi->pi_next) { 867c478bd9Sstevel@tonic-gate if (pi->pi_index == ifindex) 877c478bd9Sstevel@tonic-gate break; 887c478bd9Sstevel@tonic-gate } 897c478bd9Sstevel@tonic-gate return (pi); 907c478bd9Sstevel@tonic-gate } 917c478bd9Sstevel@tonic-gate 927c478bd9Sstevel@tonic-gate struct phyint * 937c478bd9Sstevel@tonic-gate phyint_create(char *name) 947c478bd9Sstevel@tonic-gate { 957c478bd9Sstevel@tonic-gate struct phyint *pi; 967c478bd9Sstevel@tonic-gate int i; 977c478bd9Sstevel@tonic-gate 987c478bd9Sstevel@tonic-gate if (debug & D_PHYINT) 997c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "phyint_create(%s)\n", name); 1007c478bd9Sstevel@tonic-gate 1017c478bd9Sstevel@tonic-gate pi = (struct phyint *)calloc(sizeof (struct phyint), 1); 1027c478bd9Sstevel@tonic-gate if (pi == NULL) { 1037c478bd9Sstevel@tonic-gate logmsg(LOG_ERR, "phyint_create: out of memory\n"); 1047c478bd9Sstevel@tonic-gate return (NULL); 1057c478bd9Sstevel@tonic-gate } 1067c478bd9Sstevel@tonic-gate (void) strncpy(pi->pi_name, name, sizeof (pi->pi_name)); 1077c478bd9Sstevel@tonic-gate pi->pi_name[sizeof (pi->pi_name) - 1] = '\0'; 1087c478bd9Sstevel@tonic-gate 1097c478bd9Sstevel@tonic-gate /* 1107c478bd9Sstevel@tonic-gate * Copy the defaults from the defaults array. 1117c478bd9Sstevel@tonic-gate * Do not copy the cf_notdefault fields since these have not 1127c478bd9Sstevel@tonic-gate * been explicitly set for the phyint. 1137c478bd9Sstevel@tonic-gate */ 1147c478bd9Sstevel@tonic-gate for (i = 0; i < I_IFSIZE; i++) 1157c478bd9Sstevel@tonic-gate pi->pi_config[i].cf_value = ifdefaults[i].cf_value; 1167c478bd9Sstevel@tonic-gate 1177c478bd9Sstevel@tonic-gate /* 1187c478bd9Sstevel@tonic-gate * TmpDesyncFactor is used to desynchronize temporary token 1197c478bd9Sstevel@tonic-gate * generation among systems; the actual preferred lifetime value 1207c478bd9Sstevel@tonic-gate * of a temporary address will be (TmpPreferredLifetime - 1217c478bd9Sstevel@tonic-gate * TmpDesyncFactor). It's a random value, with a user-configurable 1227c478bd9Sstevel@tonic-gate * maximum value. The value is constant throughout the lifetime 1237c478bd9Sstevel@tonic-gate * of the in.ndpd process, but can change if the daemon is restarted, 1247c478bd9Sstevel@tonic-gate * per RFC3041. 1257c478bd9Sstevel@tonic-gate */ 1267c478bd9Sstevel@tonic-gate if (pi->pi_TmpMaxDesyncFactor != 0) { 1277c478bd9Sstevel@tonic-gate time_t seed = time(NULL); 1287c478bd9Sstevel@tonic-gate srand((uint_t)seed); 1297c478bd9Sstevel@tonic-gate pi->pi_TmpDesyncFactor = rand() % pi->pi_TmpMaxDesyncFactor; 1307c478bd9Sstevel@tonic-gate /* we actually want [1,max], not [0,(max-1)] */ 1317c478bd9Sstevel@tonic-gate pi->pi_TmpDesyncFactor++; 1327c478bd9Sstevel@tonic-gate } 1337c478bd9Sstevel@tonic-gate pi->pi_TmpRegenCountdown = TIMER_INFINITY; 1347c478bd9Sstevel@tonic-gate 1357c478bd9Sstevel@tonic-gate pi->pi_sock = -1; 1367c478bd9Sstevel@tonic-gate if (phyint_init_from_k(pi) == -1) { 1377c478bd9Sstevel@tonic-gate if (pi->pi_group_name != NULL) 1387c478bd9Sstevel@tonic-gate free(pi->pi_group_name); 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 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; 1627c478bd9Sstevel@tonic-gate } 1637c478bd9Sstevel@tonic-gate 1647c478bd9Sstevel@tonic-gate /* 1657c478bd9Sstevel@tonic-gate * Initialize both the phyint data structure and the pi_sock for 1667c478bd9Sstevel@tonic-gate * sending and receving on the interface. 1677c478bd9Sstevel@tonic-gate * Extract information from the kernel (if present) and set pi_kernel_state. 1687c478bd9Sstevel@tonic-gate */ 1697c478bd9Sstevel@tonic-gate int 1707c478bd9Sstevel@tonic-gate phyint_init_from_k(struct phyint *pi) 1717c478bd9Sstevel@tonic-gate { 1727c478bd9Sstevel@tonic-gate struct ipv6_mreq v6mcastr; 1737c478bd9Sstevel@tonic-gate struct lifreq lifr; 1747c478bd9Sstevel@tonic-gate int fd; 1757c478bd9Sstevel@tonic-gate boolean_t newsock; 1767c478bd9Sstevel@tonic-gate uint_t ttl; 1777c478bd9Sstevel@tonic-gate struct sockaddr_in6 *sin6; 1787c478bd9Sstevel@tonic-gate 1797c478bd9Sstevel@tonic-gate if (debug & D_PHYINT) 1807c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "phyint_init_from_k(%s)\n", pi->pi_name); 1817c478bd9Sstevel@tonic-gate 1827c478bd9Sstevel@tonic-gate start_over: 1837c478bd9Sstevel@tonic-gate 1847c478bd9Sstevel@tonic-gate if (pi->pi_sock < 0) { 1857c478bd9Sstevel@tonic-gate pi->pi_sock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6); 1867c478bd9Sstevel@tonic-gate if (pi->pi_sock < 0) { 1877c478bd9Sstevel@tonic-gate logperror_pi(pi, "phyint_init_from_k: socket"); 1887c478bd9Sstevel@tonic-gate return (-1); 1897c478bd9Sstevel@tonic-gate } 1907c478bd9Sstevel@tonic-gate newsock = _B_TRUE; 1917c478bd9Sstevel@tonic-gate } else { 1927c478bd9Sstevel@tonic-gate newsock = _B_FALSE; 1937c478bd9Sstevel@tonic-gate } 1947c478bd9Sstevel@tonic-gate fd = pi->pi_sock; 1957c478bd9Sstevel@tonic-gate 1967c478bd9Sstevel@tonic-gate (void) strncpy(lifr.lifr_name, pi->pi_name, sizeof (lifr.lifr_name)); 1977c478bd9Sstevel@tonic-gate lifr.lifr_name[sizeof (lifr.lifr_name) - 1] = '\0'; 1987c478bd9Sstevel@tonic-gate if (ioctl(fd, SIOCGLIFINDEX, (char *)&lifr) < 0) { 1997c478bd9Sstevel@tonic-gate if (errno == ENXIO) { 2007c478bd9Sstevel@tonic-gate if (newsock) { 2017c478bd9Sstevel@tonic-gate (void) close(pi->pi_sock); 2027c478bd9Sstevel@tonic-gate pi->pi_sock = -1; 2037c478bd9Sstevel@tonic-gate } 2047c478bd9Sstevel@tonic-gate if (debug & D_PHYINT) { 2057c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "phyint_init_from_k(%s): " 2067c478bd9Sstevel@tonic-gate "not exist\n", pi->pi_name); 2077c478bd9Sstevel@tonic-gate } 2087c478bd9Sstevel@tonic-gate return (0); 2097c478bd9Sstevel@tonic-gate } 2107c478bd9Sstevel@tonic-gate logperror_pi(pi, "phyint_init_from_k: SIOCGLIFINDEX"); 2117c478bd9Sstevel@tonic-gate goto error; 2127c478bd9Sstevel@tonic-gate } 2137c478bd9Sstevel@tonic-gate 2147c478bd9Sstevel@tonic-gate if (!newsock && (pi->pi_index != lifr.lifr_index)) { 2157c478bd9Sstevel@tonic-gate /* 2167c478bd9Sstevel@tonic-gate * Interface has been re-plumbed, lets open a new socket. 2177c478bd9Sstevel@tonic-gate * This situation can occur if plumb/unplumb are happening 2187c478bd9Sstevel@tonic-gate * quite frequently. 2197c478bd9Sstevel@tonic-gate */ 2207c478bd9Sstevel@tonic-gate 2217c478bd9Sstevel@tonic-gate phyint_cleanup(pi); 2227c478bd9Sstevel@tonic-gate goto start_over; 2237c478bd9Sstevel@tonic-gate } 2247c478bd9Sstevel@tonic-gate 2257c478bd9Sstevel@tonic-gate pi->pi_index = lifr.lifr_index; 2267c478bd9Sstevel@tonic-gate 2277c478bd9Sstevel@tonic-gate if (ioctl(fd, SIOCGLIFFLAGS, (char *)&lifr) < 0) { 2287c478bd9Sstevel@tonic-gate logperror_pi(pi, "phyint_init_from_k: ioctl (get flags)"); 2297c478bd9Sstevel@tonic-gate goto error; 2307c478bd9Sstevel@tonic-gate } 2317c478bd9Sstevel@tonic-gate pi->pi_flags = lifr.lifr_flags; 2327c478bd9Sstevel@tonic-gate 2337c478bd9Sstevel@tonic-gate /* 2347c478bd9Sstevel@tonic-gate * If the link local interface is not up yet or it's IFF_UP 2357c478bd9Sstevel@tonic-gate * and the flag is set to IFF_NOLOCAL as Duplicate Address 2367c478bd9Sstevel@tonic-gate * Detection is in progress. 2377c478bd9Sstevel@tonic-gate * IFF_NOLOCAL is "normal" on other prefixes. 2387c478bd9Sstevel@tonic-gate */ 2397c478bd9Sstevel@tonic-gate 2407c478bd9Sstevel@tonic-gate if (!(pi->pi_flags & IFF_UP) || (pi->pi_flags & IFF_NOLOCAL)) { 2417c478bd9Sstevel@tonic-gate if (newsock) { 2427c478bd9Sstevel@tonic-gate (void) close(pi->pi_sock); 2437c478bd9Sstevel@tonic-gate pi->pi_sock = -1; 2447c478bd9Sstevel@tonic-gate } 2457c478bd9Sstevel@tonic-gate if (debug & D_PHYINT) { 2467c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "phyint_init_from_k(%s): " 2477c478bd9Sstevel@tonic-gate "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 bzero(lifr.lifr_groupname, sizeof (lifr.lifr_groupname)); 2547c478bd9Sstevel@tonic-gate if (ioctl(fd, SIOCGLIFGROUPNAME, (caddr_t)&lifr) < 0) { 2557c478bd9Sstevel@tonic-gate logperror_pi(pi, "phyint_init_from_k: ioctl (get group name)"); 2567c478bd9Sstevel@tonic-gate goto error; 2577c478bd9Sstevel@tonic-gate } 2587c478bd9Sstevel@tonic-gate 2597c478bd9Sstevel@tonic-gate if (lifr.lifr_groupname != NULL && strlen(lifr.lifr_groupname) != 0) { 2607c478bd9Sstevel@tonic-gate if (pi->pi_group_name == NULL) { 2617c478bd9Sstevel@tonic-gate pi->pi_group_name = malloc( 2627c478bd9Sstevel@tonic-gate sizeof (lifr.lifr_groupname)); 2637c478bd9Sstevel@tonic-gate if (pi->pi_group_name == NULL) { 2647c478bd9Sstevel@tonic-gate logperror_pi(pi, "phyint_init_from_k:" 2657c478bd9Sstevel@tonic-gate " malloc(group name)"); 2667c478bd9Sstevel@tonic-gate goto error; 2677c478bd9Sstevel@tonic-gate } 2687c478bd9Sstevel@tonic-gate } 2697c478bd9Sstevel@tonic-gate /* 2707c478bd9Sstevel@tonic-gate * Size of the group name can only be LIFNAMESZ -1 characters 2717c478bd9Sstevel@tonic-gate * which is ensured by kernel. Thus, we don't need strncpy. 2727c478bd9Sstevel@tonic-gate */ 2737c478bd9Sstevel@tonic-gate (void) strncpy(pi->pi_group_name, lifr.lifr_groupname, 2747c478bd9Sstevel@tonic-gate sizeof (lifr.lifr_name)); 2757c478bd9Sstevel@tonic-gate pi->pi_group_name[sizeof (pi->pi_group_name) - 1] = '\0'; 2767c478bd9Sstevel@tonic-gate } else if (pi->pi_group_name != NULL) { 2777c478bd9Sstevel@tonic-gate free(pi->pi_group_name); 2787c478bd9Sstevel@tonic-gate pi->pi_group_name = NULL; 2797c478bd9Sstevel@tonic-gate } 2807c478bd9Sstevel@tonic-gate 2817c478bd9Sstevel@tonic-gate if (ioctl(fd, SIOCGLIFMTU, (caddr_t)&lifr) < 0) { 2827c478bd9Sstevel@tonic-gate logperror_pi(pi, "phyint_init_from_k: ioctl (get mtu)"); 2837c478bd9Sstevel@tonic-gate goto error; 2847c478bd9Sstevel@tonic-gate } 2857c478bd9Sstevel@tonic-gate pi->pi_mtu = lifr.lifr_mtu; 2867c478bd9Sstevel@tonic-gate 2877c478bd9Sstevel@tonic-gate if (ioctl(fd, SIOCGLIFADDR, (char *)&lifr) < 0) { 2887c478bd9Sstevel@tonic-gate logperror_pi(pi, "phyint_init_from_k: SIOCGLIFADDR"); 2897c478bd9Sstevel@tonic-gate goto error; 2907c478bd9Sstevel@tonic-gate } 2917c478bd9Sstevel@tonic-gate sin6 = (struct sockaddr_in6 *)&lifr.lifr_addr; 2927c478bd9Sstevel@tonic-gate pi->pi_ifaddr = sin6->sin6_addr; 2937c478bd9Sstevel@tonic-gate 2947c478bd9Sstevel@tonic-gate if (ioctl(fd, SIOCGLIFTOKEN, (char *)&lifr) < 0) { 2957c478bd9Sstevel@tonic-gate logperror_pi(pi, "phyint_init_from_k: SIOCGLIFTOKEN"); 2967c478bd9Sstevel@tonic-gate goto error; 2977c478bd9Sstevel@tonic-gate } 2987c478bd9Sstevel@tonic-gate /* Ignore interface if the token is all zeros */ 2997c478bd9Sstevel@tonic-gate sin6 = (struct sockaddr_in6 *)&lifr.lifr_token; 3007c478bd9Sstevel@tonic-gate if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { 3017c478bd9Sstevel@tonic-gate logmsg(LOG_ERR, "ignoring interface %s: zero token\n", 3027c478bd9Sstevel@tonic-gate pi->pi_name); 3037c478bd9Sstevel@tonic-gate goto error; 3047c478bd9Sstevel@tonic-gate } 3057c478bd9Sstevel@tonic-gate pi->pi_token = sin6->sin6_addr; 3067c478bd9Sstevel@tonic-gate pi->pi_token_length = lifr.lifr_addrlen; 3077c478bd9Sstevel@tonic-gate 3087c478bd9Sstevel@tonic-gate /* 3097c478bd9Sstevel@tonic-gate * Guess a remote token for POINTOPOINT by looking at 3107c478bd9Sstevel@tonic-gate * the link-local destination address. 3117c478bd9Sstevel@tonic-gate */ 3127c478bd9Sstevel@tonic-gate if (pi->pi_flags & IFF_POINTOPOINT) { 3137c478bd9Sstevel@tonic-gate if (ioctl(fd, SIOCGLIFDSTADDR, (char *)&lifr) < 0) { 3147c478bd9Sstevel@tonic-gate logperror_pi(pi, "phyint_init_from_k: SIOCGLIFDSTADDR"); 3157c478bd9Sstevel@tonic-gate goto error; 3167c478bd9Sstevel@tonic-gate } 3177c478bd9Sstevel@tonic-gate sin6 = (struct sockaddr_in6 *)&lifr.lifr_addr; 3187c478bd9Sstevel@tonic-gate if (sin6->sin6_family != AF_INET6 || 3197c478bd9Sstevel@tonic-gate IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) || 3207c478bd9Sstevel@tonic-gate !IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) { 3217c478bd9Sstevel@tonic-gate pi->pi_dst_token = in6addr_any; 3227c478bd9Sstevel@tonic-gate } else { 3237c478bd9Sstevel@tonic-gate pi->pi_dst_token = sin6->sin6_addr; 3247c478bd9Sstevel@tonic-gate /* Clear link-local prefix (first 10 bits) */ 3257c478bd9Sstevel@tonic-gate pi->pi_dst_token.s6_addr[0] = 0; 3267c478bd9Sstevel@tonic-gate pi->pi_dst_token.s6_addr[1] &= 0x3f; 3277c478bd9Sstevel@tonic-gate } 3287c478bd9Sstevel@tonic-gate } else { 3297c478bd9Sstevel@tonic-gate pi->pi_dst_token = in6addr_any; 3307c478bd9Sstevel@tonic-gate } 3317c478bd9Sstevel@tonic-gate 3327c478bd9Sstevel@tonic-gate /* Get link-layer address */ 3337c478bd9Sstevel@tonic-gate if (!(pi->pi_flags & IFF_MULTICAST) || 3347c478bd9Sstevel@tonic-gate (pi->pi_flags & IFF_POINTOPOINT)) { 3357c478bd9Sstevel@tonic-gate pi->pi_hdw_addr_len = 0; 3367c478bd9Sstevel@tonic-gate } else { 3377c478bd9Sstevel@tonic-gate sin6 = (struct sockaddr_in6 *)&lifr.lifr_nd.lnr_addr; 3387c478bd9Sstevel@tonic-gate bzero(sin6, sizeof (struct sockaddr_in6)); 3397c478bd9Sstevel@tonic-gate sin6->sin6_family = AF_INET6; 3407c478bd9Sstevel@tonic-gate sin6->sin6_addr = pi->pi_ifaddr; 3417c478bd9Sstevel@tonic-gate 3427c478bd9Sstevel@tonic-gate if (ioctl(fd, SIOCLIFGETND, (char *)&lifr) < 0) { 3437c478bd9Sstevel@tonic-gate logperror_pi(pi, "phyint_init_from_k: SIOCLIFGETND"); 3447c478bd9Sstevel@tonic-gate goto error; 3457c478bd9Sstevel@tonic-gate } 3467c478bd9Sstevel@tonic-gate 3477c478bd9Sstevel@tonic-gate pi->pi_hdw_addr_len = lifr.lifr_nd.lnr_hdw_len; 3487c478bd9Sstevel@tonic-gate 3497c478bd9Sstevel@tonic-gate if (lifr.lifr_nd.lnr_hdw_len != 0) { 3507c478bd9Sstevel@tonic-gate bcopy((char *)lifr.lifr_nd.lnr_hdw_addr, 3517c478bd9Sstevel@tonic-gate (char *)pi->pi_hdw_addr, 3527c478bd9Sstevel@tonic-gate lifr.lifr_nd.lnr_hdw_len); 3537c478bd9Sstevel@tonic-gate } 3547c478bd9Sstevel@tonic-gate } 3557c478bd9Sstevel@tonic-gate 3567c478bd9Sstevel@tonic-gate if (newsock) { 3577c478bd9Sstevel@tonic-gate icmp6_filter_t filter; 3587c478bd9Sstevel@tonic-gate int on = 1; 3597c478bd9Sstevel@tonic-gate 3607c478bd9Sstevel@tonic-gate /* Set default values */ 3617c478bd9Sstevel@tonic-gate pi->pi_LinkMTU = pi->pi_mtu; 3627c478bd9Sstevel@tonic-gate pi->pi_CurHopLimit = 0; 3637c478bd9Sstevel@tonic-gate pi->pi_BaseReachableTime = ND_REACHABLE_TIME; 3647c478bd9Sstevel@tonic-gate phyint_reach_random(pi, _B_FALSE); 3657c478bd9Sstevel@tonic-gate pi->pi_RetransTimer = ND_RETRANS_TIMER; 3667c478bd9Sstevel@tonic-gate 3677c478bd9Sstevel@tonic-gate /* Setup socket for transmission and reception */ 3687c478bd9Sstevel@tonic-gate if (setsockopt(fd, IPPROTO_IPV6, 3697c478bd9Sstevel@tonic-gate IPV6_BOUND_IF, (char *)&pi->pi_index, 3707c478bd9Sstevel@tonic-gate sizeof (pi->pi_index)) < 0) { 3717c478bd9Sstevel@tonic-gate logperror_pi(pi, "phyint_init_from_k: setsockopt " 3727c478bd9Sstevel@tonic-gate "IPV6_BOUND_IF"); 3737c478bd9Sstevel@tonic-gate goto error; 3747c478bd9Sstevel@tonic-gate } 3757c478bd9Sstevel@tonic-gate 3767c478bd9Sstevel@tonic-gate ttl = IPV6_MAX_HOPS; 3777c478bd9Sstevel@tonic-gate if (setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, 3787c478bd9Sstevel@tonic-gate (char *)&ttl, sizeof (ttl)) < 0) { 3797c478bd9Sstevel@tonic-gate logperror_pi(pi, "phyint_init_from_k: setsockopt " 3807c478bd9Sstevel@tonic-gate "IPV6_UNICAST_HOPS"); 3817c478bd9Sstevel@tonic-gate goto error; 3827c478bd9Sstevel@tonic-gate } 3837c478bd9Sstevel@tonic-gate 3847c478bd9Sstevel@tonic-gate if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, 3857c478bd9Sstevel@tonic-gate (char *)&ttl, sizeof (ttl)) < 0) { 3867c478bd9Sstevel@tonic-gate logperror_pi(pi, "phyint_init_from_k: setsockopt " 3877c478bd9Sstevel@tonic-gate "IPV6_MULTICAST_HOPS"); 3887c478bd9Sstevel@tonic-gate goto error; 3897c478bd9Sstevel@tonic-gate } 3907c478bd9Sstevel@tonic-gate 3917c478bd9Sstevel@tonic-gate v6mcastr.ipv6mr_multiaddr = all_nodes_mcast; 3927c478bd9Sstevel@tonic-gate v6mcastr.ipv6mr_interface = pi->pi_index; 3937c478bd9Sstevel@tonic-gate if (setsockopt(fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, 3947c478bd9Sstevel@tonic-gate (char *)&v6mcastr, sizeof (v6mcastr)) < 0) { 3957c478bd9Sstevel@tonic-gate logperror_pi(pi, "phyint_init_from_k: " 3967c478bd9Sstevel@tonic-gate "setsockopt IPV6_JOIN_GROUP"); 3977c478bd9Sstevel@tonic-gate goto error; 3987c478bd9Sstevel@tonic-gate } 3997c478bd9Sstevel@tonic-gate pi->pi_state |= PI_JOINED_ALLNODES; 4007c478bd9Sstevel@tonic-gate pi->pi_kernel_state |= PI_JOINED_ALLNODES; 4017c478bd9Sstevel@tonic-gate 4027c478bd9Sstevel@tonic-gate /* 4037c478bd9Sstevel@tonic-gate * Filter out so that we only receive router advertisements and 4047c478bd9Sstevel@tonic-gate * router solicitations. 4057c478bd9Sstevel@tonic-gate */ 4067c478bd9Sstevel@tonic-gate ICMP6_FILTER_SETBLOCKALL(&filter); 4077c478bd9Sstevel@tonic-gate ICMP6_FILTER_SETPASS(ND_ROUTER_SOLICIT, &filter); 4087c478bd9Sstevel@tonic-gate ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT, &filter); 4097c478bd9Sstevel@tonic-gate 4107c478bd9Sstevel@tonic-gate if (setsockopt(fd, IPPROTO_ICMPV6, ICMP6_FILTER, 4117c478bd9Sstevel@tonic-gate (char *)&filter, sizeof (filter)) < 0) { 4127c478bd9Sstevel@tonic-gate logperror_pi(pi, "phyint_init_from_k: setsockopt " 4137c478bd9Sstevel@tonic-gate "ICMP6_FILTER"); 4147c478bd9Sstevel@tonic-gate goto error; 4157c478bd9Sstevel@tonic-gate } 4167c478bd9Sstevel@tonic-gate 4177c478bd9Sstevel@tonic-gate /* Enable receipt of ancillary data */ 4187c478bd9Sstevel@tonic-gate if (setsockopt(fd, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, 4197c478bd9Sstevel@tonic-gate (char *)&on, sizeof (on)) < 0) { 4207c478bd9Sstevel@tonic-gate logperror_pi(pi, "phyint_init_from_k: setsockopt " 4217c478bd9Sstevel@tonic-gate "IPV6_RECVHOPLIMIT"); 4227c478bd9Sstevel@tonic-gate goto error; 4237c478bd9Sstevel@tonic-gate } 4247c478bd9Sstevel@tonic-gate if (setsockopt(fd, IPPROTO_IPV6, IPV6_RECVRTHDR, 4257c478bd9Sstevel@tonic-gate (char *)&on, sizeof (on)) < 0) { 4267c478bd9Sstevel@tonic-gate logperror_pi(pi, "phyint_init_from_k: setsockopt " 4277c478bd9Sstevel@tonic-gate "IPV6_RECVRTHDR"); 4287c478bd9Sstevel@tonic-gate goto error; 4297c478bd9Sstevel@tonic-gate } 4307c478bd9Sstevel@tonic-gate } 4317c478bd9Sstevel@tonic-gate 4327c478bd9Sstevel@tonic-gate if (pi->pi_AdvSendAdvertisements && 4337c478bd9Sstevel@tonic-gate !(pi->pi_kernel_state & PI_JOINED_ALLROUTERS)) { 4347c478bd9Sstevel@tonic-gate v6mcastr.ipv6mr_multiaddr = all_routers_mcast; 4357c478bd9Sstevel@tonic-gate v6mcastr.ipv6mr_interface = pi->pi_index; 4367c478bd9Sstevel@tonic-gate if (setsockopt(fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, 4377c478bd9Sstevel@tonic-gate (char *)&v6mcastr, sizeof (v6mcastr)) < 0) { 4387c478bd9Sstevel@tonic-gate logperror_pi(pi, "phyint_init_from_k: setsockopt " 4397c478bd9Sstevel@tonic-gate "IPV6_JOIN_GROUP"); 4407c478bd9Sstevel@tonic-gate goto error; 4417c478bd9Sstevel@tonic-gate } 4427c478bd9Sstevel@tonic-gate pi->pi_state |= PI_JOINED_ALLROUTERS; 4437c478bd9Sstevel@tonic-gate pi->pi_kernel_state |= PI_JOINED_ALLROUTERS; 4447c478bd9Sstevel@tonic-gate } 4457c478bd9Sstevel@tonic-gate /* 4467c478bd9Sstevel@tonic-gate * If not already set, set the IFF_ROUTER interface flag based on 4477c478bd9Sstevel@tonic-gate * AdvSendAdvertisements. Note that this will also enable IPv6 4487c478bd9Sstevel@tonic-gate * forwarding on the interface. We don't clear IFF_ROUTER if we're 4497c478bd9Sstevel@tonic-gate * not advertising on an interface, because we could still be 4507c478bd9Sstevel@tonic-gate * forwarding on those interfaces. 4517c478bd9Sstevel@tonic-gate */ 4527c478bd9Sstevel@tonic-gate (void) strncpy(lifr.lifr_name, pi->pi_name, sizeof (lifr.lifr_name)); 4537c478bd9Sstevel@tonic-gate lifr.lifr_name[sizeof (lifr.lifr_name) - 1] = '\0'; 4547c478bd9Sstevel@tonic-gate if (ioctl(fd, SIOCGLIFFLAGS, (char *)&lifr) < 0) { 4557c478bd9Sstevel@tonic-gate logperror_pi(pi, "phyint_init_from_k: SIOCGLIFFLAGS"); 4567c478bd9Sstevel@tonic-gate goto error; 4577c478bd9Sstevel@tonic-gate } 4587c478bd9Sstevel@tonic-gate if (!(lifr.lifr_flags & IFF_ROUTER) && pi->pi_AdvSendAdvertisements) { 4597c478bd9Sstevel@tonic-gate lifr.lifr_flags |= IFF_ROUTER; 4607c478bd9Sstevel@tonic-gate 4617c478bd9Sstevel@tonic-gate if (ioctl(fd, SIOCSLIFFLAGS, (char *)&lifr) < 0) { 4627c478bd9Sstevel@tonic-gate logperror_pi(pi, "phyint_init_from_k: SIOCSLIFFLAGS"); 4637c478bd9Sstevel@tonic-gate goto error; 4647c478bd9Sstevel@tonic-gate } 4657c478bd9Sstevel@tonic-gate pi->pi_flags = lifr.lifr_flags; 4667c478bd9Sstevel@tonic-gate } 4677c478bd9Sstevel@tonic-gate 4687c478bd9Sstevel@tonic-gate /* Set linkinfo parameters */ 4697c478bd9Sstevel@tonic-gate (void) strncpy(lifr.lifr_name, pi->pi_name, sizeof (lifr.lifr_name)); 4707c478bd9Sstevel@tonic-gate lifr.lifr_name[sizeof (lifr.lifr_name) - 1] = '\0'; 4717c478bd9Sstevel@tonic-gate lifr.lifr_ifinfo.lir_maxhops = pi->pi_CurHopLimit; 4727c478bd9Sstevel@tonic-gate lifr.lifr_ifinfo.lir_reachtime = pi->pi_ReachableTime; 4737c478bd9Sstevel@tonic-gate lifr.lifr_ifinfo.lir_reachretrans = pi->pi_RetransTimer; 474*00834081Spwernau /* Setting maxmtu to 0 means that we're leaving the MTU alone */ 475*00834081Spwernau lifr.lifr_ifinfo.lir_maxmtu = 0; 4767c478bd9Sstevel@tonic-gate if (ioctl(fd, SIOCSLIFLNKINFO, (char *)&lifr) < 0) { 4777c478bd9Sstevel@tonic-gate logperror_pi(pi, "phyint_init_from_k: SIOCSLIFLNKINFO"); 4787c478bd9Sstevel@tonic-gate goto error; 4797c478bd9Sstevel@tonic-gate } 4807c478bd9Sstevel@tonic-gate if (debug & D_PHYINT) { 4817c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "phyint_init_from_k(%s): done\n", 4827c478bd9Sstevel@tonic-gate pi->pi_name); 4837c478bd9Sstevel@tonic-gate } 4847c478bd9Sstevel@tonic-gate return (0); 4857c478bd9Sstevel@tonic-gate 4867c478bd9Sstevel@tonic-gate error: 4877c478bd9Sstevel@tonic-gate /* Pretend the interface does not exist in the kernel */ 4887c478bd9Sstevel@tonic-gate pi->pi_kernel_state &= ~PI_PRESENT; 4897c478bd9Sstevel@tonic-gate if (newsock) { 4907c478bd9Sstevel@tonic-gate (void) close(pi->pi_sock); 4917c478bd9Sstevel@tonic-gate pi->pi_sock = -1; 4927c478bd9Sstevel@tonic-gate } 4937c478bd9Sstevel@tonic-gate return (-1); 4947c478bd9Sstevel@tonic-gate } 4957c478bd9Sstevel@tonic-gate 4967c478bd9Sstevel@tonic-gate /* 4977c478bd9Sstevel@tonic-gate * Delete (unlink and free). 4987c478bd9Sstevel@tonic-gate * Handles delete of things that have not yet been inserted in the list. 4997c478bd9Sstevel@tonic-gate */ 5007c478bd9Sstevel@tonic-gate void 5017c478bd9Sstevel@tonic-gate phyint_delete(struct phyint *pi) 5027c478bd9Sstevel@tonic-gate { 5037c478bd9Sstevel@tonic-gate if (debug & D_PHYINT) 5047c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "phyint_delete(%s)\n", pi->pi_name); 5057c478bd9Sstevel@tonic-gate 5067c478bd9Sstevel@tonic-gate while (pi->pi_router_list) 5077c478bd9Sstevel@tonic-gate router_delete(pi->pi_router_list); 5087c478bd9Sstevel@tonic-gate while (pi->pi_prefix_list) 5097c478bd9Sstevel@tonic-gate prefix_delete(pi->pi_prefix_list); 5107c478bd9Sstevel@tonic-gate while (pi->pi_adv_prefix_list) 5117c478bd9Sstevel@tonic-gate adv_prefix_delete(pi->pi_adv_prefix_list); 5127c478bd9Sstevel@tonic-gate 5137c478bd9Sstevel@tonic-gate if (pi->pi_sock != -1) { 5147c478bd9Sstevel@tonic-gate (void) poll_remove(pi->pi_sock); 5157c478bd9Sstevel@tonic-gate if (close(pi->pi_sock) < 0) { 5167c478bd9Sstevel@tonic-gate logperror_pi(pi, "phyint_delete: close"); 5177c478bd9Sstevel@tonic-gate } 5187c478bd9Sstevel@tonic-gate pi->pi_sock = -1; 5197c478bd9Sstevel@tonic-gate } 5207c478bd9Sstevel@tonic-gate 5217c478bd9Sstevel@tonic-gate if (pi->pi_prev == NULL) { 5227c478bd9Sstevel@tonic-gate if (phyints == pi) 5237c478bd9Sstevel@tonic-gate phyints = pi->pi_next; 5247c478bd9Sstevel@tonic-gate } else { 5257c478bd9Sstevel@tonic-gate pi->pi_prev->pi_next = pi->pi_next; 5267c478bd9Sstevel@tonic-gate } 5277c478bd9Sstevel@tonic-gate if (pi->pi_next != NULL) 5287c478bd9Sstevel@tonic-gate pi->pi_next->pi_prev = pi->pi_prev; 5297c478bd9Sstevel@tonic-gate pi->pi_next = pi->pi_prev = NULL; 5307c478bd9Sstevel@tonic-gate if (pi->pi_group_name != NULL) 5317c478bd9Sstevel@tonic-gate free(pi->pi_group_name); 5327c478bd9Sstevel@tonic-gate free(pi); 5337c478bd9Sstevel@tonic-gate } 5347c478bd9Sstevel@tonic-gate 5357c478bd9Sstevel@tonic-gate /* 5367c478bd9Sstevel@tonic-gate * Called with the number of millseconds elapsed since the last call. 5377c478bd9Sstevel@tonic-gate * Determines if any timeout event has occurred and 5387c478bd9Sstevel@tonic-gate * returns the number of milliseconds until the next timeout event 5397c478bd9Sstevel@tonic-gate * for the phyint iself (excluding prefixes and routers). 5407c478bd9Sstevel@tonic-gate * Returns TIMER_INFINITY for "never". 5417c478bd9Sstevel@tonic-gate */ 5427c478bd9Sstevel@tonic-gate uint_t 5437c478bd9Sstevel@tonic-gate phyint_timer(struct phyint *pi, uint_t elapsed) 5447c478bd9Sstevel@tonic-gate { 5457c478bd9Sstevel@tonic-gate uint_t next = TIMER_INFINITY; 5467c478bd9Sstevel@tonic-gate 5477c478bd9Sstevel@tonic-gate if (pi->pi_AdvSendAdvertisements) { 5487c478bd9Sstevel@tonic-gate if (pi->pi_adv_state != NO_ADV) { 5497c478bd9Sstevel@tonic-gate int old_state = pi->pi_adv_state; 5507c478bd9Sstevel@tonic-gate 5517c478bd9Sstevel@tonic-gate if (debug & (D_STATE|D_PHYINT)) { 5527c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "phyint_timer ADV(%s) " 5537c478bd9Sstevel@tonic-gate "state %d\n", pi->pi_name, (int)old_state); 5547c478bd9Sstevel@tonic-gate } 5557c478bd9Sstevel@tonic-gate next = advertise_event(pi, ADV_TIMER, elapsed); 5567c478bd9Sstevel@tonic-gate if (debug & D_STATE) { 5577c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "phyint_timer ADV(%s) " 5587c478bd9Sstevel@tonic-gate "state %d -> %d\n", 5597c478bd9Sstevel@tonic-gate pi->pi_name, (int)old_state, 5607c478bd9Sstevel@tonic-gate (int)pi->pi_adv_state); 5617c478bd9Sstevel@tonic-gate } 5627c478bd9Sstevel@tonic-gate } 5637c478bd9Sstevel@tonic-gate } else { 5647c478bd9Sstevel@tonic-gate if (pi->pi_sol_state != NO_SOLICIT) { 5657c478bd9Sstevel@tonic-gate int old_state = pi->pi_sol_state; 5667c478bd9Sstevel@tonic-gate 5677c478bd9Sstevel@tonic-gate if (debug & (D_STATE|D_PHYINT)) { 5687c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "phyint_timer SOL(%s) " 5697c478bd9Sstevel@tonic-gate "state %d\n", pi->pi_name, (int)old_state); 5707c478bd9Sstevel@tonic-gate } 5717c478bd9Sstevel@tonic-gate next = solicit_event(pi, SOL_TIMER, elapsed); 5727c478bd9Sstevel@tonic-gate if (debug & D_STATE) { 5737c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "phyint_timer SOL(%s) " 5747c478bd9Sstevel@tonic-gate "state %d -> %d\n", 5757c478bd9Sstevel@tonic-gate pi->pi_name, (int)old_state, 5767c478bd9Sstevel@tonic-gate (int)pi->pi_sol_state); 5777c478bd9Sstevel@tonic-gate } 5787c478bd9Sstevel@tonic-gate } 5797c478bd9Sstevel@tonic-gate } 5807c478bd9Sstevel@tonic-gate 5817c478bd9Sstevel@tonic-gate /* 5827c478bd9Sstevel@tonic-gate * If the phyint has been unplumbed, we don't want to call 5837c478bd9Sstevel@tonic-gate * phyint_reach_random. We will be in the NO_ADV or NO_SOLICIT state. 5847c478bd9Sstevel@tonic-gate */ 5857c478bd9Sstevel@tonic-gate if ((pi->pi_AdvSendAdvertisements && (pi->pi_adv_state != NO_ADV)) || 5867c478bd9Sstevel@tonic-gate (!pi->pi_AdvSendAdvertisements && 5877c478bd9Sstevel@tonic-gate (pi->pi_sol_state != NO_SOLICIT))) { 5887c478bd9Sstevel@tonic-gate pi->pi_reach_time_since_random += elapsed; 5897c478bd9Sstevel@tonic-gate if (pi->pi_reach_time_since_random >= MAX_REACH_RANDOM_INTERVAL) 5907c478bd9Sstevel@tonic-gate phyint_reach_random(pi, _B_TRUE); 5917c478bd9Sstevel@tonic-gate } 5927c478bd9Sstevel@tonic-gate 5937c478bd9Sstevel@tonic-gate return (next); 5947c478bd9Sstevel@tonic-gate } 5957c478bd9Sstevel@tonic-gate 5967c478bd9Sstevel@tonic-gate static void 5977c478bd9Sstevel@tonic-gate phyint_print(struct phyint *pi) 5987c478bd9Sstevel@tonic-gate { 5997c478bd9Sstevel@tonic-gate struct prefix *pr; 6007c478bd9Sstevel@tonic-gate struct adv_prefix *adv_pr; 6017c478bd9Sstevel@tonic-gate struct router *dr; 6027c478bd9Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 6037c478bd9Sstevel@tonic-gate char llabuf[BUFSIZ]; 6047c478bd9Sstevel@tonic-gate 6057c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "Phyint %s index %d state %x, kernel %x, " 6067c478bd9Sstevel@tonic-gate "onlink_def %d num routers %d\n", 6077c478bd9Sstevel@tonic-gate pi->pi_name, pi->pi_index, 6087c478bd9Sstevel@tonic-gate pi->pi_state, pi->pi_kernel_state, 6097c478bd9Sstevel@tonic-gate pi->pi_onlink_default ? 1 : 0, 6107c478bd9Sstevel@tonic-gate pi->pi_num_k_routers); 6117c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "\taddress: %s flags %x\n", 6127c478bd9Sstevel@tonic-gate inet_ntop(AF_INET6, (void *)&pi->pi_ifaddr, 6137c478bd9Sstevel@tonic-gate abuf, sizeof (abuf)), pi->pi_flags); 6147c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "\tsock %d mtu %d hdw_addr len %d <%s>\n", 6157c478bd9Sstevel@tonic-gate pi->pi_sock, pi->pi_mtu, pi->pi_hdw_addr_len, 6167c478bd9Sstevel@tonic-gate ((pi->pi_hdw_addr_len != 0) ? 6177c478bd9Sstevel@tonic-gate fmt_lla(llabuf, sizeof (llabuf), pi->pi_hdw_addr, 6187c478bd9Sstevel@tonic-gate pi->pi_hdw_addr_len) : "none")); 6197c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "\ttoken: len %d %s\n", 6207c478bd9Sstevel@tonic-gate pi->pi_token_length, 6217c478bd9Sstevel@tonic-gate inet_ntop(AF_INET6, (void *)&pi->pi_token, 6227c478bd9Sstevel@tonic-gate abuf, sizeof (abuf))); 6237c478bd9Sstevel@tonic-gate if (pi->pi_TmpAddrsEnabled) { 6247c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "\ttmp_token: %s\n", 6257c478bd9Sstevel@tonic-gate inet_ntop(AF_INET6, (void *)&pi->pi_tmp_token, 6267c478bd9Sstevel@tonic-gate abuf, sizeof (abuf))); 6277c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "\ttmp config: pref %d valid %d " 6287c478bd9Sstevel@tonic-gate "maxdesync %d desync %d regen %d\n", 6297c478bd9Sstevel@tonic-gate pi->pi_TmpPreferredLifetime, pi->pi_TmpValidLifetime, 6307c478bd9Sstevel@tonic-gate pi->pi_TmpMaxDesyncFactor, pi->pi_TmpDesyncFactor, 6317c478bd9Sstevel@tonic-gate pi->pi_TmpRegenAdvance); 6327c478bd9Sstevel@tonic-gate } 6337c478bd9Sstevel@tonic-gate if (pi->pi_flags & IFF_POINTOPOINT) { 6347c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "\tdst_token: %s\n", 6357c478bd9Sstevel@tonic-gate inet_ntop(AF_INET6, (void *)&pi->pi_dst_token, 6367c478bd9Sstevel@tonic-gate abuf, sizeof (abuf))); 6377c478bd9Sstevel@tonic-gate } 6387c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "\tLinkMTU %d CurHopLimit %d " 6397c478bd9Sstevel@tonic-gate "BaseReachableTime %d\n\tReachableTime %d RetransTimer %d\n", 6407c478bd9Sstevel@tonic-gate pi->pi_LinkMTU, pi->pi_CurHopLimit, pi->pi_BaseReachableTime, 6417c478bd9Sstevel@tonic-gate pi->pi_ReachableTime, pi->pi_RetransTimer); 6427c478bd9Sstevel@tonic-gate if (!pi->pi_AdvSendAdvertisements) { 6437c478bd9Sstevel@tonic-gate /* Solicit state */ 6447c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "\tSOLICIT: time_left %d state %d count %d\n", 6457c478bd9Sstevel@tonic-gate pi->pi_sol_time_left, pi->pi_sol_state, pi->pi_sol_count); 6467c478bd9Sstevel@tonic-gate } else { 6477c478bd9Sstevel@tonic-gate /* Advertise state */ 6487c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "\tADVERT: time_left %d state %d count %d " 6497c478bd9Sstevel@tonic-gate "since last %d\n", 6507c478bd9Sstevel@tonic-gate pi->pi_adv_time_left, pi->pi_adv_state, pi->pi_adv_count, 6517c478bd9Sstevel@tonic-gate pi->pi_adv_time_since_sent); 6527c478bd9Sstevel@tonic-gate print_iflist(pi->pi_config); 6537c478bd9Sstevel@tonic-gate } 6547c478bd9Sstevel@tonic-gate for (pr = pi->pi_prefix_list; pr != NULL; pr = pr->pr_next) 6557c478bd9Sstevel@tonic-gate prefix_print(pr); 6567c478bd9Sstevel@tonic-gate 6577c478bd9Sstevel@tonic-gate for (adv_pr = pi->pi_adv_prefix_list; adv_pr != NULL; 6587c478bd9Sstevel@tonic-gate adv_pr = adv_pr->adv_pr_next) { 6597c478bd9Sstevel@tonic-gate adv_prefix_print(adv_pr); 6607c478bd9Sstevel@tonic-gate } 6617c478bd9Sstevel@tonic-gate 6627c478bd9Sstevel@tonic-gate for (dr = pi->pi_router_list; dr != NULL; dr = dr->dr_next) 6637c478bd9Sstevel@tonic-gate router_print(dr); 6647c478bd9Sstevel@tonic-gate 6657c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "\n"); 6667c478bd9Sstevel@tonic-gate } 6677c478bd9Sstevel@tonic-gate 6687c478bd9Sstevel@tonic-gate /* 6697c478bd9Sstevel@tonic-gate * Randomize pi->pi_ReachableTime. 6707c478bd9Sstevel@tonic-gate * Done periodically when there are no RAs and at a maximum frequency when 6717c478bd9Sstevel@tonic-gate * RA's arrive. 6727c478bd9Sstevel@tonic-gate * Assumes that caller has determined that it is time to generate 6737c478bd9Sstevel@tonic-gate * a new random ReachableTime. 6747c478bd9Sstevel@tonic-gate */ 6757c478bd9Sstevel@tonic-gate void 6767c478bd9Sstevel@tonic-gate phyint_reach_random(struct phyint *pi, boolean_t set_needed) 6777c478bd9Sstevel@tonic-gate { 6787c478bd9Sstevel@tonic-gate pi->pi_ReachableTime = GET_RANDOM( 6797c478bd9Sstevel@tonic-gate (int)(ND_MIN_RANDOM_FACTOR * pi->pi_BaseReachableTime), 6807c478bd9Sstevel@tonic-gate (int)(ND_MAX_RANDOM_FACTOR * pi->pi_BaseReachableTime)); 6817c478bd9Sstevel@tonic-gate if (set_needed) { 6827c478bd9Sstevel@tonic-gate struct lifreq lifr; 6837c478bd9Sstevel@tonic-gate 6847c478bd9Sstevel@tonic-gate (void) strncpy(lifr.lifr_name, pi->pi_name, 6857c478bd9Sstevel@tonic-gate sizeof (lifr.lifr_name)); 6867c478bd9Sstevel@tonic-gate pi->pi_name[sizeof (pi->pi_name) - 1] = '\0'; 6877c478bd9Sstevel@tonic-gate if (ioctl(pi->pi_sock, SIOCGLIFLNKINFO, (char *)&lifr) < 0) { 6887c478bd9Sstevel@tonic-gate logperror_pi(pi, 6897c478bd9Sstevel@tonic-gate "phyint_reach_random: SIOCGLIFLNKINFO"); 6907c478bd9Sstevel@tonic-gate return; 6917c478bd9Sstevel@tonic-gate } 6927c478bd9Sstevel@tonic-gate lifr.lifr_ifinfo.lir_reachtime = pi->pi_ReachableTime; 6937c478bd9Sstevel@tonic-gate if (ioctl(pi->pi_sock, SIOCSLIFLNKINFO, (char *)&lifr) < 0) { 6947c478bd9Sstevel@tonic-gate logperror_pi(pi, 6957c478bd9Sstevel@tonic-gate "phyint_reach_random: SIOCSLIFLNKINFO"); 6967c478bd9Sstevel@tonic-gate return; 6977c478bd9Sstevel@tonic-gate } 6987c478bd9Sstevel@tonic-gate } 6997c478bd9Sstevel@tonic-gate pi->pi_reach_time_since_random = 0; 7007c478bd9Sstevel@tonic-gate } 7017c478bd9Sstevel@tonic-gate 7027c478bd9Sstevel@tonic-gate /* 7037c478bd9Sstevel@tonic-gate * Validate a temporary token against a list of known bad values. 7047c478bd9Sstevel@tonic-gate * Currently assumes that token is 8 bytes long! Current known 7057c478bd9Sstevel@tonic-gate * bad values include 0, reserved anycast tokens (RFC 2526), tokens 7067c478bd9Sstevel@tonic-gate * used by ISATAP (draft-ietf-ngtrans-isatap-N), any token already 7077c478bd9Sstevel@tonic-gate * assigned to this interface, or any token for which the global 7087c478bd9Sstevel@tonic-gate * bit is set. 7097c478bd9Sstevel@tonic-gate * 7107c478bd9Sstevel@tonic-gate * Called by tmptoken_create(). 7117c478bd9Sstevel@tonic-gate * 7127c478bd9Sstevel@tonic-gate * Return _B_TRUE if token is valid (no match), _B_FALSE if not. 7137c478bd9Sstevel@tonic-gate */ 7147c478bd9Sstevel@tonic-gate static boolean_t 7157c478bd9Sstevel@tonic-gate tmptoken_isvalid(struct in6_addr *token) 7167c478bd9Sstevel@tonic-gate { 7177c478bd9Sstevel@tonic-gate struct phyint *pi; 7187c478bd9Sstevel@tonic-gate struct in6_addr mask; 7197c478bd9Sstevel@tonic-gate struct in6_addr isatap = { 0, 0, 0, 0, 0, 0, 0, 0, \ 7207c478bd9Sstevel@tonic-gate 0, 0, 0x5e, 0xfe, 0, 0, 0, 0 }; 7217c478bd9Sstevel@tonic-gate struct in6_addr anycast = { 0, 0, 0, 0, \ 7227c478bd9Sstevel@tonic-gate 0, 0, 0, 0, \ 7237c478bd9Sstevel@tonic-gate 0xfd, 0xff, 0xff, 0xff, \ 7247c478bd9Sstevel@tonic-gate 0xff, 0xff, 0xff, 0x80 }; 7257c478bd9Sstevel@tonic-gate 7267c478bd9Sstevel@tonic-gate if (IN6_IS_ADDR_UNSPECIFIED(token)) 7277c478bd9Sstevel@tonic-gate return (_B_FALSE); 7287c478bd9Sstevel@tonic-gate 7297c478bd9Sstevel@tonic-gate if (token->s6_addr[8] & 0x2) 7307c478bd9Sstevel@tonic-gate return (_B_FALSE); 7317c478bd9Sstevel@tonic-gate 7327c478bd9Sstevel@tonic-gate (void) memcpy(&mask, token, sizeof (mask)); 7337c478bd9Sstevel@tonic-gate mask._S6_un._S6_u32[3] = 0; 7347c478bd9Sstevel@tonic-gate if (IN6_ARE_ADDR_EQUAL(&isatap, token)) 7357c478bd9Sstevel@tonic-gate return (_B_FALSE); 7367c478bd9Sstevel@tonic-gate 7377c478bd9Sstevel@tonic-gate mask._S6_un._S6_u32[3] = token->_S6_un._S6_u32[3] & 0xffffff80; 7387c478bd9Sstevel@tonic-gate if (IN6_ARE_ADDR_EQUAL(&anycast, token)) 7397c478bd9Sstevel@tonic-gate return (_B_FALSE); 7407c478bd9Sstevel@tonic-gate 7417c478bd9Sstevel@tonic-gate for (pi = phyints; pi != NULL; pi = pi->pi_next) { 7427c478bd9Sstevel@tonic-gate if (((pi->pi_token_length == TMP_TOKEN_BITS) && 7437c478bd9Sstevel@tonic-gate IN6_ARE_ADDR_EQUAL(&pi->pi_token, token)) || 7447c478bd9Sstevel@tonic-gate IN6_ARE_ADDR_EQUAL(&pi->pi_tmp_token, token)) 7457c478bd9Sstevel@tonic-gate return (_B_FALSE); 7467c478bd9Sstevel@tonic-gate } 7477c478bd9Sstevel@tonic-gate 7487c478bd9Sstevel@tonic-gate /* none of our tests failed, must be a good one! */ 7497c478bd9Sstevel@tonic-gate return (_B_TRUE); 7507c478bd9Sstevel@tonic-gate } 7517c478bd9Sstevel@tonic-gate 7527c478bd9Sstevel@tonic-gate /* 7537c478bd9Sstevel@tonic-gate * Generate a temporary token and set up its timer 7547c478bd9Sstevel@tonic-gate * 7557c478bd9Sstevel@tonic-gate * Called from incoming_prefix_addrconf_process() (when token is first 7567c478bd9Sstevel@tonic-gate * needed) and from tmptoken_timer() (when current token expires). 7577c478bd9Sstevel@tonic-gate * 7587c478bd9Sstevel@tonic-gate * Returns _B_TRUE if a token was successfully generated, _B_FALSE if not. 7597c478bd9Sstevel@tonic-gate */ 7607c478bd9Sstevel@tonic-gate boolean_t 7617c478bd9Sstevel@tonic-gate tmptoken_create(struct phyint *pi) 7627c478bd9Sstevel@tonic-gate { 7637c478bd9Sstevel@tonic-gate int fd, i = 0, max_tries = 15; 7647c478bd9Sstevel@tonic-gate struct in6_addr token; 7657c478bd9Sstevel@tonic-gate uint32_t *tokenp = &(token._S6_un._S6_u32[2]); 7667c478bd9Sstevel@tonic-gate char buf[INET6_ADDRSTRLEN]; 7677c478bd9Sstevel@tonic-gate 7687c478bd9Sstevel@tonic-gate if ((fd = open("/dev/urandom", O_RDONLY)) == -1) { 7697c478bd9Sstevel@tonic-gate perror("open /dev/urandom"); 7707c478bd9Sstevel@tonic-gate goto no_token; 7717c478bd9Sstevel@tonic-gate } 7727c478bd9Sstevel@tonic-gate 7737c478bd9Sstevel@tonic-gate bzero((char *)&token, sizeof (token)); 7747c478bd9Sstevel@tonic-gate do { 7757c478bd9Sstevel@tonic-gate if (read(fd, (void *)tokenp, TMP_TOKEN_BYTES) == -1) { 7767c478bd9Sstevel@tonic-gate perror("read /dev/urandom"); 7777c478bd9Sstevel@tonic-gate (void) close(fd); 7787c478bd9Sstevel@tonic-gate goto no_token; 7797c478bd9Sstevel@tonic-gate } 7807c478bd9Sstevel@tonic-gate 7817c478bd9Sstevel@tonic-gate /* 7827c478bd9Sstevel@tonic-gate * Assume EUI-64 formatting, and thus 64-bit 7837c478bd9Sstevel@tonic-gate * token len; need to clear global bit. 7847c478bd9Sstevel@tonic-gate */ 7857c478bd9Sstevel@tonic-gate token.s6_addr[8] &= 0xfd; 7867c478bd9Sstevel@tonic-gate 7877c478bd9Sstevel@tonic-gate i++; 7887c478bd9Sstevel@tonic-gate 7897c478bd9Sstevel@tonic-gate } while (!tmptoken_isvalid(&token) && i < max_tries); 7907c478bd9Sstevel@tonic-gate 7917c478bd9Sstevel@tonic-gate (void) close(fd); 7927c478bd9Sstevel@tonic-gate 7937c478bd9Sstevel@tonic-gate if (i == max_tries) { 7947c478bd9Sstevel@tonic-gate no_token: 7957c478bd9Sstevel@tonic-gate logmsg(LOG_WARNING, "tmptoken_create(%s): failed to create " 7967c478bd9Sstevel@tonic-gate "token; disabling temporary addresses on %s\n", 7977c478bd9Sstevel@tonic-gate pi->pi_name, pi->pi_name); 7987c478bd9Sstevel@tonic-gate pi->pi_TmpAddrsEnabled = 0; 7997c478bd9Sstevel@tonic-gate return (_B_FALSE); 8007c478bd9Sstevel@tonic-gate } 8017c478bd9Sstevel@tonic-gate 8027c478bd9Sstevel@tonic-gate pi->pi_tmp_token = token; 8037c478bd9Sstevel@tonic-gate 8047c478bd9Sstevel@tonic-gate if (debug & D_TMP) 8057c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "tmptoken_create(%s): created temporary " 8067c478bd9Sstevel@tonic-gate "token %s\n", pi->pi_name, 8077c478bd9Sstevel@tonic-gate inet_ntop(AF_INET6, &pi->pi_tmp_token, buf, sizeof (buf))); 8087c478bd9Sstevel@tonic-gate 8097c478bd9Sstevel@tonic-gate pi->pi_TmpRegenCountdown = (pi->pi_TmpPreferredLifetime - 8107c478bd9Sstevel@tonic-gate pi->pi_TmpDesyncFactor - pi->pi_TmpRegenAdvance) * MILLISEC; 8117c478bd9Sstevel@tonic-gate if (pi->pi_TmpRegenCountdown != 0) 8127c478bd9Sstevel@tonic-gate timer_schedule(pi->pi_TmpRegenCountdown); 8137c478bd9Sstevel@tonic-gate 8147c478bd9Sstevel@tonic-gate return (_B_TRUE); 8157c478bd9Sstevel@tonic-gate } 8167c478bd9Sstevel@tonic-gate 8177c478bd9Sstevel@tonic-gate /* 8187c478bd9Sstevel@tonic-gate * Delete a temporary token. This is outside the normal timeout process, 8197c478bd9Sstevel@tonic-gate * so mark any existing addresses based on this token DEPRECATED and set 8207c478bd9Sstevel@tonic-gate * their preferred lifetime to 0. Don't tamper with valid lifetime, that 8217c478bd9Sstevel@tonic-gate * will be used to eventually remove the address. Also reset the current 8227c478bd9Sstevel@tonic-gate * pi_tmp_token value to 0. 8237c478bd9Sstevel@tonic-gate * 8247c478bd9Sstevel@tonic-gate * Called from incoming_prefix_addrconf_process() if DAD fails on a temp 8257c478bd9Sstevel@tonic-gate * addr. 8267c478bd9Sstevel@tonic-gate */ 8277c478bd9Sstevel@tonic-gate void 8287c478bd9Sstevel@tonic-gate tmptoken_delete(struct phyint *pi) 8297c478bd9Sstevel@tonic-gate { 8307c478bd9Sstevel@tonic-gate struct prefix *pr; 8317c478bd9Sstevel@tonic-gate 8327c478bd9Sstevel@tonic-gate for (pr = pi->pi_prefix_list; pr != NULL; pr = pr->pr_next) { 8337c478bd9Sstevel@tonic-gate if (!(pr->pr_flags & IFF_TEMPORARY) || 8347c478bd9Sstevel@tonic-gate (pr->pr_flags & IFF_DEPRECATED) || 8357c478bd9Sstevel@tonic-gate (!token_equal(pr->pr_address, pi->pi_tmp_token, 8367c478bd9Sstevel@tonic-gate TMP_TOKEN_BITS))) { 8377c478bd9Sstevel@tonic-gate continue; 8387c478bd9Sstevel@tonic-gate } 8397c478bd9Sstevel@tonic-gate pr->pr_PreferredLifetime = 0; 8407c478bd9Sstevel@tonic-gate pr->pr_state |= PR_DEPRECATED; 8417c478bd9Sstevel@tonic-gate prefix_update_k(pr); 8427c478bd9Sstevel@tonic-gate } 8437c478bd9Sstevel@tonic-gate 8447c478bd9Sstevel@tonic-gate (void) memset(&pi->pi_tmp_token, 0, sizeof (pi->pi_tmp_token)); 8457c478bd9Sstevel@tonic-gate } 8467c478bd9Sstevel@tonic-gate 8477c478bd9Sstevel@tonic-gate /* 8487c478bd9Sstevel@tonic-gate * Called from run_timeouts() with the number of milliseconds elapsed 8497c478bd9Sstevel@tonic-gate * since the last call. Determines if any timeout event has occurred 8507c478bd9Sstevel@tonic-gate * and returns the number of milliseconds until the next timeout event 8517c478bd9Sstevel@tonic-gate * for the tmp token. Returns TIMER_INFINITY for "never". 8527c478bd9Sstevel@tonic-gate */ 8537c478bd9Sstevel@tonic-gate uint_t 8547c478bd9Sstevel@tonic-gate tmptoken_timer(struct phyint *pi, uint_t elapsed) 8557c478bd9Sstevel@tonic-gate { 8567c478bd9Sstevel@tonic-gate struct nd_opt_prefix_info opt; 8577c478bd9Sstevel@tonic-gate struct sockaddr_in6 sin6; 8587c478bd9Sstevel@tonic-gate struct prefix *pr, *newpr; 8597c478bd9Sstevel@tonic-gate 8607c478bd9Sstevel@tonic-gate if (debug & D_TMP) { 8617c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "tmptoken_timer(%s, %d) regencountdown %d\n", 8627c478bd9Sstevel@tonic-gate pi->pi_name, (int)elapsed, pi->pi_TmpRegenCountdown); 8637c478bd9Sstevel@tonic-gate } 8647c478bd9Sstevel@tonic-gate if (!pi->pi_TmpAddrsEnabled || 8657c478bd9Sstevel@tonic-gate (pi->pi_TmpRegenCountdown == TIMER_INFINITY)) 8667c478bd9Sstevel@tonic-gate return (TIMER_INFINITY); 8677c478bd9Sstevel@tonic-gate 8687c478bd9Sstevel@tonic-gate if (pi->pi_TmpRegenCountdown > elapsed) { 8697c478bd9Sstevel@tonic-gate pi->pi_TmpRegenCountdown -= elapsed; 8707c478bd9Sstevel@tonic-gate return (pi->pi_TmpRegenCountdown); 8717c478bd9Sstevel@tonic-gate } 8727c478bd9Sstevel@tonic-gate 8737c478bd9Sstevel@tonic-gate /* 8747c478bd9Sstevel@tonic-gate * Tmp token timer has expired. Start by generating a new token. 8757c478bd9Sstevel@tonic-gate * If we can't get a new token, tmp addrs are disabled on this 8767c478bd9Sstevel@tonic-gate * interface, so there's no need to continue, or to set a timer. 8777c478bd9Sstevel@tonic-gate */ 8787c478bd9Sstevel@tonic-gate if (!tmptoken_create(pi)) 8797c478bd9Sstevel@tonic-gate return (TIMER_INFINITY); 8807c478bd9Sstevel@tonic-gate 8817c478bd9Sstevel@tonic-gate /* 8827c478bd9Sstevel@tonic-gate * Now that we have a new token, walk the list of prefixes to 8837c478bd9Sstevel@tonic-gate * find which ones need a corresponding tmp addr generated. 8847c478bd9Sstevel@tonic-gate */ 8857c478bd9Sstevel@tonic-gate for (pr = pi->pi_prefix_list; pr != NULL; pr = pr->pr_next) { 8867c478bd9Sstevel@tonic-gate 8877c478bd9Sstevel@tonic-gate if (!(pr->pr_state & PR_AUTO) || pr->pr_state & PR_STATIC || 8887c478bd9Sstevel@tonic-gate pr->pr_state & PR_DEPRECATED || 8897c478bd9Sstevel@tonic-gate pr->pr_flags & IFF_TEMPORARY) 8907c478bd9Sstevel@tonic-gate continue; 8917c478bd9Sstevel@tonic-gate 8927c478bd9Sstevel@tonic-gate newpr = prefix_create(pi, pr->pr_prefix, pr->pr_prefix_len, 8937c478bd9Sstevel@tonic-gate IFF_TEMPORARY); 8947c478bd9Sstevel@tonic-gate if (newpr == NULL) { 8957c478bd9Sstevel@tonic-gate char pbuf[INET6_ADDRSTRLEN]; 8967c478bd9Sstevel@tonic-gate char tbuf[INET6_ADDRSTRLEN]; 8977c478bd9Sstevel@tonic-gate (void) inet_ntop(AF_INET6, &pr->pr_prefix, pbuf, 8987c478bd9Sstevel@tonic-gate sizeof (pbuf)); 8997c478bd9Sstevel@tonic-gate (void) inet_ntop(AF_INET6, &pi->pi_tmp_token, tbuf, 9007c478bd9Sstevel@tonic-gate sizeof (tbuf)); 9017c478bd9Sstevel@tonic-gate logmsg(LOG_ERR, "can't create new tmp addr " 9027c478bd9Sstevel@tonic-gate "(%s, %s, %s)\n", pi->pi_name, pbuf, tbuf); 9037c478bd9Sstevel@tonic-gate continue; 9047c478bd9Sstevel@tonic-gate } 9057c478bd9Sstevel@tonic-gate 9067c478bd9Sstevel@tonic-gate /* 9077c478bd9Sstevel@tonic-gate * We want to use incoming_prefix_*_process() functions to 9087c478bd9Sstevel@tonic-gate * set up the new tmp addr, so cobble together a prefix 9097c478bd9Sstevel@tonic-gate * info option struct based on the existing prefix to pass 9107c478bd9Sstevel@tonic-gate * in. The lifetimes will be based on the current time 9117c478bd9Sstevel@tonic-gate * remaining. 9127c478bd9Sstevel@tonic-gate * 9137c478bd9Sstevel@tonic-gate * The "from" param is only used for messages; pass in 9147c478bd9Sstevel@tonic-gate * ::0 for that. 9157c478bd9Sstevel@tonic-gate */ 9167c478bd9Sstevel@tonic-gate opt.nd_opt_pi_type = ND_OPT_PREFIX_INFORMATION; 9177c478bd9Sstevel@tonic-gate opt.nd_opt_pi_len = sizeof (opt) / 8; 9187c478bd9Sstevel@tonic-gate opt.nd_opt_pi_prefix_len = pr->pr_prefix_len; 9197c478bd9Sstevel@tonic-gate opt.nd_opt_pi_flags_reserved = ND_OPT_PI_FLAG_AUTO; 9207c478bd9Sstevel@tonic-gate opt.nd_opt_pi_valid_time = 9217c478bd9Sstevel@tonic-gate htonl(pr->pr_ValidLifetime / 1000); 9227c478bd9Sstevel@tonic-gate opt.nd_opt_pi_preferred_time = 9237c478bd9Sstevel@tonic-gate htonl(pr->pr_PreferredLifetime / 1000); 9247c478bd9Sstevel@tonic-gate if (pr->pr_state & PR_ONLINK) 9257c478bd9Sstevel@tonic-gate opt.nd_opt_pi_flags_reserved &= ND_OPT_PI_FLAG_ONLINK; 9267c478bd9Sstevel@tonic-gate opt.nd_opt_pi_prefix = pr->pr_prefix; 9277c478bd9Sstevel@tonic-gate 9287c478bd9Sstevel@tonic-gate (void) memset(&sin6, 0, sizeof (sin6)); 9297c478bd9Sstevel@tonic-gate 9307c478bd9Sstevel@tonic-gate if (!incoming_prefix_addrconf_process(pi, newpr, 9317c478bd9Sstevel@tonic-gate (uchar_t *)&opt, &sin6, _B_FALSE, _B_TRUE)) { 9327c478bd9Sstevel@tonic-gate char pbuf[INET6_ADDRSTRLEN]; 9337c478bd9Sstevel@tonic-gate char tbuf[INET6_ADDRSTRLEN]; 9347c478bd9Sstevel@tonic-gate (void) inet_ntop(AF_INET6, &pr->pr_prefix, pbuf, 9357c478bd9Sstevel@tonic-gate sizeof (pbuf)); 9367c478bd9Sstevel@tonic-gate (void) inet_ntop(AF_INET6, &pi->pi_tmp_token, tbuf, 9377c478bd9Sstevel@tonic-gate sizeof (tbuf)); 9387c478bd9Sstevel@tonic-gate logmsg(LOG_ERR, "can't create new tmp addr " 9397c478bd9Sstevel@tonic-gate "(%s, %s, %s)\n", pi->pi_name, pbuf, tbuf); 9407c478bd9Sstevel@tonic-gate continue; 9417c478bd9Sstevel@tonic-gate } 9427c478bd9Sstevel@tonic-gate 9437c478bd9Sstevel@tonic-gate if (pr->pr_state & PR_ONLINK) { 9447c478bd9Sstevel@tonic-gate incoming_prefix_onlink_process(newpr, (uchar_t *)&opt); 9457c478bd9Sstevel@tonic-gate } 9467c478bd9Sstevel@tonic-gate } 9477c478bd9Sstevel@tonic-gate 9487c478bd9Sstevel@tonic-gate /* 9497c478bd9Sstevel@tonic-gate * appropriate timers were scheduled when 9507c478bd9Sstevel@tonic-gate * the token and addresses were created. 9517c478bd9Sstevel@tonic-gate */ 9527c478bd9Sstevel@tonic-gate return (TIMER_INFINITY); 9537c478bd9Sstevel@tonic-gate } 9547c478bd9Sstevel@tonic-gate 9557c478bd9Sstevel@tonic-gate /* 9567c478bd9Sstevel@tonic-gate * tlen specifies the token length in bits. Compares the lower 9577c478bd9Sstevel@tonic-gate * tlen bits of the two addresses provided and returns _B_TRUE if 9587c478bd9Sstevel@tonic-gate * they match, _B_FALSE if not. Also returns _B_FALSE for invalid 9597c478bd9Sstevel@tonic-gate * values of tlen. 9607c478bd9Sstevel@tonic-gate */ 9617c478bd9Sstevel@tonic-gate boolean_t 9627c478bd9Sstevel@tonic-gate token_equal(struct in6_addr t1, struct in6_addr t2, int tlen) 9637c478bd9Sstevel@tonic-gate { 9647c478bd9Sstevel@tonic-gate uchar_t mask; 9657c478bd9Sstevel@tonic-gate int j, abytes, tbytes, tbits; 9667c478bd9Sstevel@tonic-gate 9677c478bd9Sstevel@tonic-gate if (tlen < 0 || tlen > IPV6_ABITS) 9687c478bd9Sstevel@tonic-gate return (_B_FALSE); 9697c478bd9Sstevel@tonic-gate 9707c478bd9Sstevel@tonic-gate abytes = IPV6_ABITS >> 3; 9717c478bd9Sstevel@tonic-gate tbytes = tlen >> 3; 9727c478bd9Sstevel@tonic-gate tbits = tlen & 7; 9737c478bd9Sstevel@tonic-gate 9747c478bd9Sstevel@tonic-gate for (j = abytes - 1; j >= abytes - tbytes; j--) 9757c478bd9Sstevel@tonic-gate if (t1.s6_addr[j] != t2.s6_addr[j]) 9767c478bd9Sstevel@tonic-gate return (_B_FALSE); 9777c478bd9Sstevel@tonic-gate 9787c478bd9Sstevel@tonic-gate if (tbits == 0) 9797c478bd9Sstevel@tonic-gate return (_B_TRUE); 9807c478bd9Sstevel@tonic-gate 9817c478bd9Sstevel@tonic-gate /* We only care about the tbits rightmost bits */ 9827c478bd9Sstevel@tonic-gate mask = 0xff >> (8 - tbits); 9837c478bd9Sstevel@tonic-gate if ((t1.s6_addr[j] & mask) != (t2.s6_addr[j] & mask)) 9847c478bd9Sstevel@tonic-gate return (_B_FALSE); 9857c478bd9Sstevel@tonic-gate 9867c478bd9Sstevel@tonic-gate return (_B_TRUE); 9877c478bd9Sstevel@tonic-gate } 9887c478bd9Sstevel@tonic-gate 9897c478bd9Sstevel@tonic-gate /* 9907c478bd9Sstevel@tonic-gate * Lookup prefix structure that matches the prefix and prefix length. 9917c478bd9Sstevel@tonic-gate * Assumes that the bits after prefixlen might not be zero. 9927c478bd9Sstevel@tonic-gate */ 9937c478bd9Sstevel@tonic-gate static struct prefix * 9947c478bd9Sstevel@tonic-gate prefix_lookup(struct phyint *pi, struct in6_addr prefix, int prefixlen) 9957c478bd9Sstevel@tonic-gate { 9967c478bd9Sstevel@tonic-gate struct prefix *pr; 9977c478bd9Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 9987c478bd9Sstevel@tonic-gate 9997c478bd9Sstevel@tonic-gate if (debug & D_PREFIX) { 10007c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "prefix_lookup(%s, %s/%u)\n", pi->pi_name, 10017c478bd9Sstevel@tonic-gate inet_ntop(AF_INET6, (void *)&prefix, 10027c478bd9Sstevel@tonic-gate abuf, sizeof (abuf)), prefixlen); 10037c478bd9Sstevel@tonic-gate } 10047c478bd9Sstevel@tonic-gate 10057c478bd9Sstevel@tonic-gate for (pr = pi->pi_prefix_list; pr != NULL; pr = pr->pr_next) { 10067c478bd9Sstevel@tonic-gate if (pr->pr_prefix_len == prefixlen && 10077c478bd9Sstevel@tonic-gate prefix_equal(prefix, pr->pr_prefix, prefixlen)) 10087c478bd9Sstevel@tonic-gate return (pr); 10097c478bd9Sstevel@tonic-gate } 10107c478bd9Sstevel@tonic-gate return (NULL); 10117c478bd9Sstevel@tonic-gate } 10127c478bd9Sstevel@tonic-gate 10137c478bd9Sstevel@tonic-gate /* 10147c478bd9Sstevel@tonic-gate * Compare two prefixes that have the same prefix length. 10157c478bd9Sstevel@tonic-gate * Fails if the prefix length is unreasonable. 10167c478bd9Sstevel@tonic-gate */ 10177c478bd9Sstevel@tonic-gate boolean_t 10187c478bd9Sstevel@tonic-gate prefix_equal(struct in6_addr p1, struct in6_addr p2, int plen) 10197c478bd9Sstevel@tonic-gate { 10207c478bd9Sstevel@tonic-gate uchar_t mask; 10217c478bd9Sstevel@tonic-gate int j, pbytes, pbits; 10227c478bd9Sstevel@tonic-gate 10237c478bd9Sstevel@tonic-gate if (plen < 0 || plen > IPV6_ABITS) 10247c478bd9Sstevel@tonic-gate return (_B_FALSE); 10257c478bd9Sstevel@tonic-gate 10267c478bd9Sstevel@tonic-gate pbytes = plen >> 3; 10277c478bd9Sstevel@tonic-gate pbits = plen & 7; 10287c478bd9Sstevel@tonic-gate 10297c478bd9Sstevel@tonic-gate for (j = 0; j < pbytes; j++) 10307c478bd9Sstevel@tonic-gate if (p1.s6_addr[j] != p2.s6_addr[j]) 10317c478bd9Sstevel@tonic-gate return (_B_FALSE); 10327c478bd9Sstevel@tonic-gate 10337c478bd9Sstevel@tonic-gate if (pbits == 0) 10347c478bd9Sstevel@tonic-gate return (_B_TRUE); 10357c478bd9Sstevel@tonic-gate 10367c478bd9Sstevel@tonic-gate /* Make the N leftmost bits one */ 10377c478bd9Sstevel@tonic-gate mask = 0xff << (8 - pbits); 10387c478bd9Sstevel@tonic-gate if ((p1.s6_addr[j] & mask) != (p2.s6_addr[j] & mask)) 10397c478bd9Sstevel@tonic-gate return (_B_FALSE); 10407c478bd9Sstevel@tonic-gate 10417c478bd9Sstevel@tonic-gate return (_B_TRUE); 10427c478bd9Sstevel@tonic-gate } 10437c478bd9Sstevel@tonic-gate 10447c478bd9Sstevel@tonic-gate /* 10457c478bd9Sstevel@tonic-gate * Set a prefix from an address and a prefix length. 10467c478bd9Sstevel@tonic-gate * Force all the bits after the prefix length to be zero. 10477c478bd9Sstevel@tonic-gate */ 10487c478bd9Sstevel@tonic-gate void 10497c478bd9Sstevel@tonic-gate prefix_set(struct in6_addr *prefix, struct in6_addr addr, int prefix_len) 10507c478bd9Sstevel@tonic-gate { 10517c478bd9Sstevel@tonic-gate uchar_t mask; 10527c478bd9Sstevel@tonic-gate int j; 10537c478bd9Sstevel@tonic-gate 10547c478bd9Sstevel@tonic-gate if (prefix_len < 0 || prefix_len > IPV6_ABITS) 10557c478bd9Sstevel@tonic-gate return; 10567c478bd9Sstevel@tonic-gate 10577c478bd9Sstevel@tonic-gate bzero((char *)prefix, sizeof (*prefix)); 10587c478bd9Sstevel@tonic-gate 10597c478bd9Sstevel@tonic-gate for (j = 0; prefix_len > 8; prefix_len -= 8, j++) 10607c478bd9Sstevel@tonic-gate prefix->s6_addr[j] = addr.s6_addr[j]; 10617c478bd9Sstevel@tonic-gate 10627c478bd9Sstevel@tonic-gate /* Make the N leftmost bits one */ 10637c478bd9Sstevel@tonic-gate mask = 0xff << (8 - prefix_len); 10647c478bd9Sstevel@tonic-gate prefix->s6_addr[j] = addr.s6_addr[j] & mask; 10657c478bd9Sstevel@tonic-gate } 10667c478bd9Sstevel@tonic-gate 10677c478bd9Sstevel@tonic-gate /* 10687c478bd9Sstevel@tonic-gate * Lookup a prefix based on the kernel's interface name. 10697c478bd9Sstevel@tonic-gate */ 10707c478bd9Sstevel@tonic-gate struct prefix * 10717c478bd9Sstevel@tonic-gate prefix_lookup_name(struct phyint *pi, char *name) 10727c478bd9Sstevel@tonic-gate { 10737c478bd9Sstevel@tonic-gate struct prefix *pr; 10747c478bd9Sstevel@tonic-gate 10757c478bd9Sstevel@tonic-gate if (debug & D_PREFIX) { 10767c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "prefix_lookup_name(%s, %s)\n", 10777c478bd9Sstevel@tonic-gate pi->pi_name, name); 10787c478bd9Sstevel@tonic-gate } 10797c478bd9Sstevel@tonic-gate if (name[0] == '\0') 10807c478bd9Sstevel@tonic-gate return (NULL); 10817c478bd9Sstevel@tonic-gate 10827c478bd9Sstevel@tonic-gate for (pr = pi->pi_prefix_list; pr != NULL; pr = pr->pr_next) { 10837c478bd9Sstevel@tonic-gate if (strcmp(name, pr->pr_name) == 0) 10847c478bd9Sstevel@tonic-gate return (pr); 10857c478bd9Sstevel@tonic-gate } 10867c478bd9Sstevel@tonic-gate return (NULL); 10877c478bd9Sstevel@tonic-gate } 10887c478bd9Sstevel@tonic-gate 10897c478bd9Sstevel@tonic-gate /* 10907c478bd9Sstevel@tonic-gate * Search the phyints list to make sure that this new prefix does 10917c478bd9Sstevel@tonic-gate * not already exist in any other physical interfaces that have 10927c478bd9Sstevel@tonic-gate * the same address as this one 10937c478bd9Sstevel@tonic-gate */ 10947c478bd9Sstevel@tonic-gate struct prefix * 10957c478bd9Sstevel@tonic-gate prefix_lookup_addr_match(struct prefix *pr) 10967c478bd9Sstevel@tonic-gate { 10977c478bd9Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 10987c478bd9Sstevel@tonic-gate struct phyint *pi; 10997c478bd9Sstevel@tonic-gate struct prefix *otherpr = NULL; 11007c478bd9Sstevel@tonic-gate struct in6_addr prefix; 11017c478bd9Sstevel@tonic-gate int prefixlen; 11027c478bd9Sstevel@tonic-gate 11037c478bd9Sstevel@tonic-gate if (debug & D_PREFIX) { 11047c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "prefix_lookup_addr_match(%s/%u)\n", 11057c478bd9Sstevel@tonic-gate inet_ntop(AF_INET6, (void *)&pr->pr_address, 11067c478bd9Sstevel@tonic-gate abuf, sizeof (abuf)), pr->pr_prefix_len); 11077c478bd9Sstevel@tonic-gate } 11087c478bd9Sstevel@tonic-gate prefix = pr->pr_prefix; 11097c478bd9Sstevel@tonic-gate prefixlen = pr->pr_prefix_len; 11107c478bd9Sstevel@tonic-gate for (pi = phyints; pi != NULL; pi = pi->pi_next) { 11117c478bd9Sstevel@tonic-gate otherpr = prefix_lookup(pi, prefix, prefixlen); 11127c478bd9Sstevel@tonic-gate if (otherpr == pr) 11137c478bd9Sstevel@tonic-gate continue; 11147c478bd9Sstevel@tonic-gate if (otherpr != NULL && (otherpr->pr_state & PR_AUTO) && 11157c478bd9Sstevel@tonic-gate IN6_ARE_ADDR_EQUAL(&pr->pr_address, 11167c478bd9Sstevel@tonic-gate &otherpr->pr_address)) 11177c478bd9Sstevel@tonic-gate return (otherpr); 11187c478bd9Sstevel@tonic-gate } 11197c478bd9Sstevel@tonic-gate return (NULL); 11207c478bd9Sstevel@tonic-gate } 11217c478bd9Sstevel@tonic-gate 11227c478bd9Sstevel@tonic-gate /* 11237c478bd9Sstevel@tonic-gate * Initialize a new prefix without setting lifetimes etc. 11247c478bd9Sstevel@tonic-gate */ 11257c478bd9Sstevel@tonic-gate struct prefix * 11267c478bd9Sstevel@tonic-gate prefix_create(struct phyint *pi, struct in6_addr prefix, int prefixlen, 11277c478bd9Sstevel@tonic-gate uint64_t flags) 11287c478bd9Sstevel@tonic-gate { 11297c478bd9Sstevel@tonic-gate struct prefix *pr; 11307c478bd9Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 11317c478bd9Sstevel@tonic-gate 11327c478bd9Sstevel@tonic-gate if (debug & D_PREFIX) { 11337c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "prefix_create(%s, %s/%u, 0x%llx)\n", 11347c478bd9Sstevel@tonic-gate pi->pi_name, inet_ntop(AF_INET6, (void *)&prefix, 11357c478bd9Sstevel@tonic-gate abuf, sizeof (abuf)), prefixlen, flags); 11367c478bd9Sstevel@tonic-gate } 11377c478bd9Sstevel@tonic-gate pr = (struct prefix *)calloc(sizeof (struct prefix), 1); 11387c478bd9Sstevel@tonic-gate if (pr == NULL) { 11397c478bd9Sstevel@tonic-gate logmsg(LOG_ERR, "prefix_create: out of memory\n"); 11407c478bd9Sstevel@tonic-gate return (NULL); 11417c478bd9Sstevel@tonic-gate } 11427c478bd9Sstevel@tonic-gate /* 11437c478bd9Sstevel@tonic-gate * The prefix might have non-zero bits after the prefix len bits. 11447c478bd9Sstevel@tonic-gate * Force them to be zero. 11457c478bd9Sstevel@tonic-gate */ 11467c478bd9Sstevel@tonic-gate prefix_set(&pr->pr_prefix, prefix, prefixlen); 11477c478bd9Sstevel@tonic-gate pr->pr_prefix_len = prefixlen; 11487c478bd9Sstevel@tonic-gate pr->pr_PreferredLifetime = PREFIX_INFINITY; 11497c478bd9Sstevel@tonic-gate pr->pr_ValidLifetime = PREFIX_INFINITY; 11507c478bd9Sstevel@tonic-gate pr->pr_OnLinkLifetime = PREFIX_INFINITY; 11517c478bd9Sstevel@tonic-gate pr->pr_kernel_state = 0; 11527c478bd9Sstevel@tonic-gate pr->pr_flags |= flags; 11537c478bd9Sstevel@tonic-gate prefix_insert(pi, pr); 11547c478bd9Sstevel@tonic-gate return (pr); 11557c478bd9Sstevel@tonic-gate } 11567c478bd9Sstevel@tonic-gate 11577c478bd9Sstevel@tonic-gate /* 11587c478bd9Sstevel@tonic-gate * Create a new named prefix. Caller should use prefix_init_from_k 11597c478bd9Sstevel@tonic-gate * to initialize the content. 11607c478bd9Sstevel@tonic-gate */ 11617c478bd9Sstevel@tonic-gate struct prefix * 11627c478bd9Sstevel@tonic-gate prefix_create_name(struct phyint *pi, char *name) 11637c478bd9Sstevel@tonic-gate { 11647c478bd9Sstevel@tonic-gate struct prefix *pr; 11657c478bd9Sstevel@tonic-gate 11667c478bd9Sstevel@tonic-gate if (debug & D_PREFIX) { 11677c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "prefix_create_name(%s, %s)\n", 11687c478bd9Sstevel@tonic-gate pi->pi_name, name); 11697c478bd9Sstevel@tonic-gate } 11707c478bd9Sstevel@tonic-gate pr = (struct prefix *)calloc(sizeof (struct prefix), 1); 11717c478bd9Sstevel@tonic-gate if (pr == NULL) { 11727c478bd9Sstevel@tonic-gate logmsg(LOG_ERR, "prefix_create_name: out of memory\n"); 11737c478bd9Sstevel@tonic-gate return (NULL); 11747c478bd9Sstevel@tonic-gate } 11757c478bd9Sstevel@tonic-gate (void) strncpy(pr->pr_name, name, sizeof (pr->pr_name)); 11767c478bd9Sstevel@tonic-gate pr->pr_name[sizeof (pr->pr_name) - 1] = '\0'; 11777c478bd9Sstevel@tonic-gate prefix_insert(pi, pr); 11787c478bd9Sstevel@tonic-gate return (pr); 11797c478bd9Sstevel@tonic-gate } 11807c478bd9Sstevel@tonic-gate 11817c478bd9Sstevel@tonic-gate /* Insert in linked list */ 11827c478bd9Sstevel@tonic-gate static void 11837c478bd9Sstevel@tonic-gate prefix_insert(struct phyint *pi, struct prefix *pr) 11847c478bd9Sstevel@tonic-gate { 11857c478bd9Sstevel@tonic-gate pr->pr_next = pi->pi_prefix_list; 11867c478bd9Sstevel@tonic-gate pr->pr_prev = NULL; 11877c478bd9Sstevel@tonic-gate if (pi->pi_prefix_list != NULL) 11887c478bd9Sstevel@tonic-gate pi->pi_prefix_list->pr_prev = pr; 11897c478bd9Sstevel@tonic-gate pi->pi_prefix_list = pr; 11907c478bd9Sstevel@tonic-gate pr->pr_physical = pi; 11917c478bd9Sstevel@tonic-gate } 11927c478bd9Sstevel@tonic-gate 11937c478bd9Sstevel@tonic-gate /* 11947c478bd9Sstevel@tonic-gate * Initialize the prefix from the content of the kernel. 11957c478bd9Sstevel@tonic-gate * If IFF_ADDRCONF is set we treat it as PR_AUTO (i.e. an addrconf 11967c478bd9Sstevel@tonic-gate * prefix). However, we not derive the lifetimes from 11977c478bd9Sstevel@tonic-gate * the kernel thus they are set to 1 week. 11987c478bd9Sstevel@tonic-gate * Ignore the prefix if the interface is not IFF_UP. 11997c478bd9Sstevel@tonic-gate */ 12007c478bd9Sstevel@tonic-gate int 12017c478bd9Sstevel@tonic-gate prefix_init_from_k(struct prefix *pr) 12027c478bd9Sstevel@tonic-gate { 12037c478bd9Sstevel@tonic-gate struct lifreq lifr; 12047c478bd9Sstevel@tonic-gate struct sockaddr_in6 *sin6; 12057c478bd9Sstevel@tonic-gate int sock = pr->pr_physical->pi_sock; 12067c478bd9Sstevel@tonic-gate 12077c478bd9Sstevel@tonic-gate (void) strncpy(lifr.lifr_name, pr->pr_name, sizeof (lifr.lifr_name)); 12087c478bd9Sstevel@tonic-gate lifr.lifr_name[sizeof (lifr.lifr_name) - 1] = '\0'; 12097c478bd9Sstevel@tonic-gate if (ioctl(sock, SIOCGLIFADDR, (char *)&lifr) < 0) { 12107c478bd9Sstevel@tonic-gate logperror_pr(pr, "prefix_init_from_k: ioctl (get addr)"); 12117c478bd9Sstevel@tonic-gate goto error; 12127c478bd9Sstevel@tonic-gate } 12137c478bd9Sstevel@tonic-gate if (lifr.lifr_addr.ss_family != AF_INET6) { 12147c478bd9Sstevel@tonic-gate logmsg(LOG_ERR, "ignoring interface %s: not AF_INET6\n", 12157c478bd9Sstevel@tonic-gate pr->pr_name); 12167c478bd9Sstevel@tonic-gate goto error; 12177c478bd9Sstevel@tonic-gate } 12187c478bd9Sstevel@tonic-gate sin6 = (struct sockaddr_in6 *)&lifr.lifr_addr; 12197c478bd9Sstevel@tonic-gate pr->pr_address = sin6->sin6_addr; 12207c478bd9Sstevel@tonic-gate 12217c478bd9Sstevel@tonic-gate if (ioctl(sock, SIOCGLIFFLAGS, (char *)&lifr) < 0) { 12227c478bd9Sstevel@tonic-gate logperror_pr(pr, "prefix_init_from_k: ioctl (get flags)"); 12237c478bd9Sstevel@tonic-gate goto error; 12247c478bd9Sstevel@tonic-gate } 12257c478bd9Sstevel@tonic-gate pr->pr_flags = lifr.lifr_flags; 12267c478bd9Sstevel@tonic-gate 12277c478bd9Sstevel@tonic-gate if (ioctl(sock, SIOCGLIFSUBNET, (char *)&lifr) < 0) { 12287c478bd9Sstevel@tonic-gate logperror_pr(pr, "prefix_init_from_k: ioctl (get subnet)"); 12297c478bd9Sstevel@tonic-gate goto error; 12307c478bd9Sstevel@tonic-gate } 12317c478bd9Sstevel@tonic-gate if (lifr.lifr_subnet.ss_family != AF_INET6) { 12327c478bd9Sstevel@tonic-gate logmsg(LOG_ERR, "ignoring interface %s: not AF_INET6\n", 12337c478bd9Sstevel@tonic-gate pr->pr_name); 12347c478bd9Sstevel@tonic-gate goto error; 12357c478bd9Sstevel@tonic-gate } 12367c478bd9Sstevel@tonic-gate /* 12377c478bd9Sstevel@tonic-gate * Guard against the prefix having non-zero bits after the prefix 12387c478bd9Sstevel@tonic-gate * len bits. 12397c478bd9Sstevel@tonic-gate */ 12407c478bd9Sstevel@tonic-gate sin6 = (struct sockaddr_in6 *)&lifr.lifr_subnet; 12417c478bd9Sstevel@tonic-gate pr->pr_prefix_len = lifr.lifr_addrlen; 12427c478bd9Sstevel@tonic-gate prefix_set(&pr->pr_prefix, sin6->sin6_addr, pr->pr_prefix_len); 12437c478bd9Sstevel@tonic-gate 12447c478bd9Sstevel@tonic-gate if (pr->pr_prefix_len != IPV6_ABITS && (pr->pr_flags & IFF_UP) && 12457c478bd9Sstevel@tonic-gate IN6_ARE_ADDR_EQUAL(&pr->pr_address, &pr->pr_prefix)) { 12467c478bd9Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 12477c478bd9Sstevel@tonic-gate 12487c478bd9Sstevel@tonic-gate logmsg(LOG_ERR, "ingoring interface %s: it appears to be " 12497c478bd9Sstevel@tonic-gate "configured with an invalid interface id (%s/%u)\n", 12507c478bd9Sstevel@tonic-gate pr->pr_name, 12517c478bd9Sstevel@tonic-gate inet_ntop(AF_INET6, (void *)&pr->pr_address, 12527c478bd9Sstevel@tonic-gate abuf, sizeof (abuf)), pr->pr_prefix_len); 12537c478bd9Sstevel@tonic-gate goto error; 12547c478bd9Sstevel@tonic-gate } 12557c478bd9Sstevel@tonic-gate pr->pr_kernel_state = 0; 12567c478bd9Sstevel@tonic-gate if (pr->pr_prefix_len != IPV6_ABITS) 12577c478bd9Sstevel@tonic-gate pr->pr_kernel_state |= PR_ONLINK; 12587c478bd9Sstevel@tonic-gate if (!(pr->pr_flags & IFF_NOLOCAL)) 12597c478bd9Sstevel@tonic-gate pr->pr_kernel_state |= PR_AUTO; 12607c478bd9Sstevel@tonic-gate if ((pr->pr_flags & IFF_DEPRECATED) && (pr->pr_kernel_state & PR_AUTO)) 12617c478bd9Sstevel@tonic-gate pr->pr_kernel_state |= PR_DEPRECATED; 12627c478bd9Sstevel@tonic-gate if (!(pr->pr_flags & IFF_ADDRCONF)) { 12637c478bd9Sstevel@tonic-gate /* Prevent ndpd from stepping on this prefix */ 12647c478bd9Sstevel@tonic-gate pr->pr_kernel_state |= PR_STATIC; 12657c478bd9Sstevel@tonic-gate } 12667c478bd9Sstevel@tonic-gate pr->pr_state = pr->pr_kernel_state; 12677c478bd9Sstevel@tonic-gate /* Adjust pr_prefix_len based if PR_AUTO is set */ 12687c478bd9Sstevel@tonic-gate if (pr->pr_state & PR_AUTO) { 12697c478bd9Sstevel@tonic-gate pr->pr_prefix_len = 12707c478bd9Sstevel@tonic-gate IPV6_ABITS - pr->pr_physical->pi_token_length; 12717c478bd9Sstevel@tonic-gate prefix_set(&pr->pr_prefix, pr->pr_prefix, pr->pr_prefix_len); 12727c478bd9Sstevel@tonic-gate } 12737c478bd9Sstevel@tonic-gate 12747c478bd9Sstevel@tonic-gate /* Can't extract lifetimes from the kernel - use 1 week */ 12757c478bd9Sstevel@tonic-gate pr->pr_ValidLifetime = NDP_PREFIX_DEFAULT_LIFETIME; 12767c478bd9Sstevel@tonic-gate pr->pr_PreferredLifetime = NDP_PREFIX_DEFAULT_LIFETIME; 12777c478bd9Sstevel@tonic-gate pr->pr_OnLinkLifetime = NDP_PREFIX_DEFAULT_LIFETIME; 12787c478bd9Sstevel@tonic-gate 12797c478bd9Sstevel@tonic-gate /* 12807c478bd9Sstevel@tonic-gate * If this is a temp addr, the creation time needs to be set. 12817c478bd9Sstevel@tonic-gate * Though it won't be entirely accurate, the current time is 12827c478bd9Sstevel@tonic-gate * an okay approximation. 12837c478bd9Sstevel@tonic-gate */ 12847c478bd9Sstevel@tonic-gate if (pr->pr_flags & IFF_TEMPORARY) 12857c478bd9Sstevel@tonic-gate pr->pr_CreateTime = getcurrenttime() / MILLISEC; 12867c478bd9Sstevel@tonic-gate 12877c478bd9Sstevel@tonic-gate if (pr->pr_kernel_state == 0) 12887c478bd9Sstevel@tonic-gate pr->pr_name[0] = '\0'; 12897c478bd9Sstevel@tonic-gate return (0); 12907c478bd9Sstevel@tonic-gate 12917c478bd9Sstevel@tonic-gate error: 12927c478bd9Sstevel@tonic-gate /* Pretend that the prefix does not exist in the kernel */ 12937c478bd9Sstevel@tonic-gate pr->pr_kernel_state = 0; 12947c478bd9Sstevel@tonic-gate pr->pr_name[0] = '\0'; 12957c478bd9Sstevel@tonic-gate return (-1); 12967c478bd9Sstevel@tonic-gate } 12977c478bd9Sstevel@tonic-gate 12987c478bd9Sstevel@tonic-gate /* 12997c478bd9Sstevel@tonic-gate * Delete (unlink and free) and remove from kernel if the prefix 13007c478bd9Sstevel@tonic-gate * was added by in.ndpd (i.e. PR_STATIC is not set). 13017c478bd9Sstevel@tonic-gate * Handles delete of things that have not yet been inserted in the list 13027c478bd9Sstevel@tonic-gate * i.e. pr_physical is NULL. 13037c478bd9Sstevel@tonic-gate */ 13047c478bd9Sstevel@tonic-gate void 13057c478bd9Sstevel@tonic-gate prefix_delete(struct prefix *pr) 13067c478bd9Sstevel@tonic-gate { 13077c478bd9Sstevel@tonic-gate struct phyint *pi; 13087c478bd9Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 13097c478bd9Sstevel@tonic-gate 13107c478bd9Sstevel@tonic-gate if (debug & D_PREFIX) { 13117c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "prefix_delete(%s, %s, %s/%u)\n", 13127c478bd9Sstevel@tonic-gate pr->pr_physical->pi_name, pr->pr_name, 13137c478bd9Sstevel@tonic-gate inet_ntop(AF_INET6, (void *)&pr->pr_prefix, 13147c478bd9Sstevel@tonic-gate abuf, sizeof (abuf)), pr->pr_prefix_len); 13157c478bd9Sstevel@tonic-gate } 13167c478bd9Sstevel@tonic-gate /* Remove non-static prefixes from the kernel. */ 13177c478bd9Sstevel@tonic-gate pr->pr_state &= PR_STATIC; 13187c478bd9Sstevel@tonic-gate pi = pr->pr_physical; 13197c478bd9Sstevel@tonic-gate if (pr->pr_kernel_state != pr->pr_state) 13207c478bd9Sstevel@tonic-gate prefix_update_k(pr); 13217c478bd9Sstevel@tonic-gate 13227c478bd9Sstevel@tonic-gate if (pr->pr_prev == NULL) { 13237c478bd9Sstevel@tonic-gate if (pi != NULL) 13247c478bd9Sstevel@tonic-gate pi->pi_prefix_list = pr->pr_next; 13257c478bd9Sstevel@tonic-gate } else { 13267c478bd9Sstevel@tonic-gate pr->pr_prev->pr_next = pr->pr_next; 13277c478bd9Sstevel@tonic-gate } 13287c478bd9Sstevel@tonic-gate if (pr->pr_next != NULL) 13297c478bd9Sstevel@tonic-gate pr->pr_next->pr_prev = pr->pr_prev; 13307c478bd9Sstevel@tonic-gate pr->pr_next = pr->pr_prev = NULL; 13317c478bd9Sstevel@tonic-gate free(pr); 13327c478bd9Sstevel@tonic-gate } 13337c478bd9Sstevel@tonic-gate 13347c478bd9Sstevel@tonic-gate /* 13357c478bd9Sstevel@tonic-gate * Toggle one or more IFF_ flags for a prefix. Turn on 'onflags' and 13367c478bd9Sstevel@tonic-gate * turn off 'offflags'. 13377c478bd9Sstevel@tonic-gate */ 13387c478bd9Sstevel@tonic-gate static int 13397c478bd9Sstevel@tonic-gate prefix_modify_flags(struct prefix *pr, uint64_t onflags, uint64_t offflags) 13407c478bd9Sstevel@tonic-gate { 13417c478bd9Sstevel@tonic-gate struct lifreq lifr; 13427c478bd9Sstevel@tonic-gate struct phyint *pi = pr->pr_physical; 13437c478bd9Sstevel@tonic-gate uint64_t old_flags; 13447c478bd9Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 13457c478bd9Sstevel@tonic-gate 13467c478bd9Sstevel@tonic-gate if (debug & D_PREFIX) { 13477c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "prefix_modify_flags(%s, %s, %s/%u) " 13487c478bd9Sstevel@tonic-gate "flags %llx on %llx off %llx\n", 13497c478bd9Sstevel@tonic-gate pr->pr_physical->pi_name, 13507c478bd9Sstevel@tonic-gate pr->pr_name, 13517c478bd9Sstevel@tonic-gate inet_ntop(AF_INET6, (void *)&pr->pr_prefix, 13527c478bd9Sstevel@tonic-gate abuf, sizeof (abuf)), pr->pr_prefix_len, 13537c478bd9Sstevel@tonic-gate pr->pr_flags, onflags, offflags); 13547c478bd9Sstevel@tonic-gate } 13557c478bd9Sstevel@tonic-gate /* Assumes that only the PR_STATIC link-local matches the pi_name */ 13567c478bd9Sstevel@tonic-gate if (!(pr->pr_state & PR_STATIC) && 13577c478bd9Sstevel@tonic-gate strcmp(pr->pr_name, pi->pi_name) == 0) { 13587c478bd9Sstevel@tonic-gate logmsg(LOG_ERR, "prefix_modify_flags(%s, on %llx, off %llx): " 13597c478bd9Sstevel@tonic-gate "name matches interface name\n", 13607c478bd9Sstevel@tonic-gate pi->pi_name, onflags, offflags); 13617c478bd9Sstevel@tonic-gate return (-1); 13627c478bd9Sstevel@tonic-gate } 13637c478bd9Sstevel@tonic-gate 13647c478bd9Sstevel@tonic-gate (void) strncpy(lifr.lifr_name, pr->pr_name, sizeof (lifr.lifr_name)); 13657c478bd9Sstevel@tonic-gate lifr.lifr_name[sizeof (lifr.lifr_name) - 1] = '\0'; 13667c478bd9Sstevel@tonic-gate if (ioctl(pi->pi_sock, SIOCGLIFFLAGS, (char *)&lifr) < 0) { 13677c478bd9Sstevel@tonic-gate logperror_pr(pr, "prefix_modify_flags: SIOCGLIFFLAGS"); 13687c478bd9Sstevel@tonic-gate logmsg(LOG_ERR, "prefix_modify_flags(%s, %s) old 0x%llx " 13697c478bd9Sstevel@tonic-gate "on 0x%llx off 0x%llx\n", 13707c478bd9Sstevel@tonic-gate pr->pr_physical->pi_name, 13717c478bd9Sstevel@tonic-gate pr->pr_name, 13727c478bd9Sstevel@tonic-gate pr->pr_flags, onflags, offflags); 13737c478bd9Sstevel@tonic-gate return (-1); 13747c478bd9Sstevel@tonic-gate } 13757c478bd9Sstevel@tonic-gate old_flags = lifr.lifr_flags; 13767c478bd9Sstevel@tonic-gate lifr.lifr_flags |= onflags; 13777c478bd9Sstevel@tonic-gate lifr.lifr_flags &= ~offflags; 13787c478bd9Sstevel@tonic-gate pr->pr_flags = lifr.lifr_flags; 13797c478bd9Sstevel@tonic-gate if (ioctl(pi->pi_sock, SIOCSLIFFLAGS, (char *)&lifr) < 0) { 13807c478bd9Sstevel@tonic-gate logperror_pr(pr, "prefix_modify_flags: SIOCSLIFFLAGS"); 13817c478bd9Sstevel@tonic-gate logmsg(LOG_ERR, "prefix_modify_flags(%s, %s) old 0x%llx " 13827c478bd9Sstevel@tonic-gate "new 0x%llx on 0x%llx off 0x%llx\n", 13837c478bd9Sstevel@tonic-gate pr->pr_physical->pi_name, 13847c478bd9Sstevel@tonic-gate pr->pr_name, 13857c478bd9Sstevel@tonic-gate old_flags, lifr.lifr_flags, onflags, offflags); 13867c478bd9Sstevel@tonic-gate return (-1); 13877c478bd9Sstevel@tonic-gate } 13887c478bd9Sstevel@tonic-gate return (0); 13897c478bd9Sstevel@tonic-gate } 13907c478bd9Sstevel@tonic-gate 13917c478bd9Sstevel@tonic-gate /* 13927c478bd9Sstevel@tonic-gate * Make the kernel state match what is in the prefix structure. 13937c478bd9Sstevel@tonic-gate * This includes creating the prefix (allocating a new interface name) 13947c478bd9Sstevel@tonic-gate * as well as setting the local address and on-link subnet prefix 13957c478bd9Sstevel@tonic-gate * and controlling the IFF_ADDRCONF and IFF_DEPRECATED flags. 13967c478bd9Sstevel@tonic-gate */ 13977c478bd9Sstevel@tonic-gate void 13987c478bd9Sstevel@tonic-gate prefix_update_k(struct prefix *pr) 13997c478bd9Sstevel@tonic-gate { 14007c478bd9Sstevel@tonic-gate struct lifreq lifr; 14017c478bd9Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 14027c478bd9Sstevel@tonic-gate char buf1[PREFIX_STATESTRLEN], buf2[PREFIX_STATESTRLEN]; 14037c478bd9Sstevel@tonic-gate struct phyint *pi = pr->pr_physical; 14047c478bd9Sstevel@tonic-gate struct sockaddr_in6 *sin6; 14057c478bd9Sstevel@tonic-gate 14067c478bd9Sstevel@tonic-gate if (debug & D_PREFIX) { 14077c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "prefix_update_k(%s, %s, %s/%u) " 14087c478bd9Sstevel@tonic-gate "from %s to %s\n", pr->pr_physical->pi_name, pr->pr_name, 14097c478bd9Sstevel@tonic-gate inet_ntop(AF_INET6, (void *)&pr->pr_prefix, 14107c478bd9Sstevel@tonic-gate abuf, sizeof (abuf)), pr->pr_prefix_len, 14117c478bd9Sstevel@tonic-gate prefix_print_state(pr->pr_kernel_state, buf1, 14127c478bd9Sstevel@tonic-gate sizeof (buf1)), 14137c478bd9Sstevel@tonic-gate prefix_print_state(pr->pr_state, buf2, sizeof (buf2))); 14147c478bd9Sstevel@tonic-gate } 14157c478bd9Sstevel@tonic-gate 14167c478bd9Sstevel@tonic-gate if (pr->pr_kernel_state == pr->pr_state) 14177c478bd9Sstevel@tonic-gate return; /* No changes */ 14187c478bd9Sstevel@tonic-gate 14197c478bd9Sstevel@tonic-gate /* Skip static prefixes */ 14207c478bd9Sstevel@tonic-gate if (pr->pr_state & PR_STATIC) 14217c478bd9Sstevel@tonic-gate return; 14227c478bd9Sstevel@tonic-gate 14237c478bd9Sstevel@tonic-gate if (pr->pr_kernel_state == 0) { 14247c478bd9Sstevel@tonic-gate uint64_t onflags; 14257c478bd9Sstevel@tonic-gate /* 14267c478bd9Sstevel@tonic-gate * Create a new logical interface name and store in pr_name. 14277c478bd9Sstevel@tonic-gate * Set IFF_ADDRCONF. Do not set an address (yet). 14287c478bd9Sstevel@tonic-gate */ 14297c478bd9Sstevel@tonic-gate if (pr->pr_name[0] != '\0') { 14307c478bd9Sstevel@tonic-gate /* Name already set! */ 14317c478bd9Sstevel@tonic-gate logmsg(LOG_ERR, "prefix_update_k(%s, %s, %s/%u) " 14327c478bd9Sstevel@tonic-gate "from %s to %s name is already allocated\n", 14337c478bd9Sstevel@tonic-gate pr->pr_physical->pi_name, pr->pr_name, 14347c478bd9Sstevel@tonic-gate inet_ntop(AF_INET6, (void *)&pr->pr_prefix, 14357c478bd9Sstevel@tonic-gate abuf, sizeof (abuf)), pr->pr_prefix_len, 14367c478bd9Sstevel@tonic-gate prefix_print_state(pr->pr_kernel_state, buf1, 14377c478bd9Sstevel@tonic-gate sizeof (buf1)), 14387c478bd9Sstevel@tonic-gate prefix_print_state(pr->pr_state, buf2, 14397c478bd9Sstevel@tonic-gate sizeof (buf2))); 14407c478bd9Sstevel@tonic-gate return; 14417c478bd9Sstevel@tonic-gate } 14427c478bd9Sstevel@tonic-gate 14437c478bd9Sstevel@tonic-gate (void) strncpy(lifr.lifr_name, pi->pi_name, 14447c478bd9Sstevel@tonic-gate sizeof (lifr.lifr_name)); 14457c478bd9Sstevel@tonic-gate lifr.lifr_name[sizeof (lifr.lifr_name) - 1] = '\0'; 14467c478bd9Sstevel@tonic-gate lifr.lifr_addr.ss_family = AF_UNSPEC; 14477c478bd9Sstevel@tonic-gate if (ioctl(pi->pi_sock, SIOCLIFADDIF, (char *)&lifr) < 0) { 14487c478bd9Sstevel@tonic-gate logperror_pr(pr, "prefix_update_k: SIOCLIFADDIF"); 14497c478bd9Sstevel@tonic-gate return; 14507c478bd9Sstevel@tonic-gate } 14517c478bd9Sstevel@tonic-gate (void) strncpy(pr->pr_name, lifr.lifr_name, 14527c478bd9Sstevel@tonic-gate sizeof (pr->pr_name)); 14537c478bd9Sstevel@tonic-gate pr->pr_name[sizeof (pr->pr_name) - 1] = '\0'; 14547c478bd9Sstevel@tonic-gate if (debug & D_PREFIX) { 14557c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "prefix_update_k: new name %s\n", 14567c478bd9Sstevel@tonic-gate pr->pr_name); 14577c478bd9Sstevel@tonic-gate } 14587c478bd9Sstevel@tonic-gate /* 14597c478bd9Sstevel@tonic-gate * The IFF_TEMPORARY flag might have already been set; if 14607c478bd9Sstevel@tonic-gate * so, it needs to be or'd into the flags we're turning on. 14617c478bd9Sstevel@tonic-gate * But be careful, we might be re-creating a manually 14627c478bd9Sstevel@tonic-gate * removed interface, in which case we don't want to try 14637c478bd9Sstevel@tonic-gate * to set *all* the flags we might have in our copy of the 14647c478bd9Sstevel@tonic-gate * flags yet. 14657c478bd9Sstevel@tonic-gate */ 14667c478bd9Sstevel@tonic-gate onflags = IFF_ADDRCONF; 14677c478bd9Sstevel@tonic-gate if (pr->pr_flags & IFF_TEMPORARY) 14687c478bd9Sstevel@tonic-gate onflags |= IFF_TEMPORARY; 14697c478bd9Sstevel@tonic-gate if (prefix_modify_flags(pr, onflags, 0) == -1) 14707c478bd9Sstevel@tonic-gate return; 14717c478bd9Sstevel@tonic-gate } 14727c478bd9Sstevel@tonic-gate if ((pr->pr_state & (PR_ONLINK|PR_AUTO)) == 0) { 14737c478bd9Sstevel@tonic-gate /* Remove the interface */ 14747c478bd9Sstevel@tonic-gate if (prefix_modify_flags(pr, 0, IFF_UP|IFF_DEPRECATED) == -1) 14757c478bd9Sstevel@tonic-gate return; 14767c478bd9Sstevel@tonic-gate (void) strncpy(lifr.lifr_name, pr->pr_name, 14777c478bd9Sstevel@tonic-gate sizeof (lifr.lifr_name)); 14787c478bd9Sstevel@tonic-gate lifr.lifr_name[sizeof (lifr.lifr_name) - 1] = '\0'; 14797c478bd9Sstevel@tonic-gate 14807c478bd9Sstevel@tonic-gate if (debug & D_PREFIX) { 14817c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "prefix_update_k: remove name %s\n", 14827c478bd9Sstevel@tonic-gate pr->pr_name); 14837c478bd9Sstevel@tonic-gate } 14847c478bd9Sstevel@tonic-gate 14857c478bd9Sstevel@tonic-gate /* 14867c478bd9Sstevel@tonic-gate * Assumes that only the PR_STATIC link-local matches 14877c478bd9Sstevel@tonic-gate * the pi_name 14887c478bd9Sstevel@tonic-gate */ 14897c478bd9Sstevel@tonic-gate if (!(pr->pr_state & PR_STATIC) && 14907c478bd9Sstevel@tonic-gate strcmp(pr->pr_name, pi->pi_name) == 0) { 14917c478bd9Sstevel@tonic-gate logmsg(LOG_ERR, "prefix_update_k(%s): " 14927c478bd9Sstevel@tonic-gate "name matches if\n", pi->pi_name); 14937c478bd9Sstevel@tonic-gate return; 14947c478bd9Sstevel@tonic-gate } 14957c478bd9Sstevel@tonic-gate 14967c478bd9Sstevel@tonic-gate /* Remove logical interface based on pr_name */ 14977c478bd9Sstevel@tonic-gate lifr.lifr_addr.ss_family = AF_UNSPEC; 14987c478bd9Sstevel@tonic-gate if (ioctl(pi->pi_sock, SIOCLIFREMOVEIF, (char *)&lifr) < 0) { 14997c478bd9Sstevel@tonic-gate logperror_pr(pr, "prefix_update_k: SIOCLIFREMOVEIF"); 15007c478bd9Sstevel@tonic-gate } 15017c478bd9Sstevel@tonic-gate pr->pr_kernel_state = 0; 15027c478bd9Sstevel@tonic-gate pr->pr_name[0] = '\0'; 15037c478bd9Sstevel@tonic-gate return; 15047c478bd9Sstevel@tonic-gate } 15057c478bd9Sstevel@tonic-gate if ((pr->pr_state & PR_AUTO) && !(pr->pr_kernel_state & PR_AUTO)) { 15067c478bd9Sstevel@tonic-gate /* 15077c478bd9Sstevel@tonic-gate * Set local address and set the prefix length to 128. 15087c478bd9Sstevel@tonic-gate * Turn off IFF_NOLOCAL in case it was set. 15097c478bd9Sstevel@tonic-gate * Turn on IFF_UP. 15107c478bd9Sstevel@tonic-gate */ 15117c478bd9Sstevel@tonic-gate (void) strncpy(lifr.lifr_name, pr->pr_name, 15127c478bd9Sstevel@tonic-gate sizeof (lifr.lifr_name)); 15137c478bd9Sstevel@tonic-gate lifr.lifr_name[sizeof (lifr.lifr_name) - 1] = '\0'; 15147c478bd9Sstevel@tonic-gate sin6 = (struct sockaddr_in6 *)&lifr.lifr_addr; 15157c478bd9Sstevel@tonic-gate bzero(sin6, sizeof (struct sockaddr_in6)); 15167c478bd9Sstevel@tonic-gate sin6->sin6_family = AF_INET6; 15177c478bd9Sstevel@tonic-gate sin6->sin6_addr = pr->pr_address; 15187c478bd9Sstevel@tonic-gate if (debug & D_PREFIX) { 15197c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "prefix_update_k(%s) set addr %s " 15207c478bd9Sstevel@tonic-gate "for PR_AUTO on\n", 15217c478bd9Sstevel@tonic-gate pr->pr_name, 15227c478bd9Sstevel@tonic-gate inet_ntop(AF_INET6, (void *)&pr->pr_address, 15237c478bd9Sstevel@tonic-gate abuf, sizeof (abuf))); 15247c478bd9Sstevel@tonic-gate } 15257c478bd9Sstevel@tonic-gate if (ioctl(pi->pi_sock, SIOCSLIFADDR, (char *)&lifr) < 0) { 15267c478bd9Sstevel@tonic-gate logperror_pr(pr, "prefix_update_k: SIOCSLIFADDR"); 15277c478bd9Sstevel@tonic-gate return; 15287c478bd9Sstevel@tonic-gate } 15297c478bd9Sstevel@tonic-gate if (pr->pr_state & PR_ONLINK) { 15307c478bd9Sstevel@tonic-gate sin6->sin6_addr = pr->pr_prefix; 15317c478bd9Sstevel@tonic-gate lifr.lifr_addrlen = pr->pr_prefix_len; 15327c478bd9Sstevel@tonic-gate } else { 15337c478bd9Sstevel@tonic-gate sin6->sin6_addr = pr->pr_address; 15347c478bd9Sstevel@tonic-gate lifr.lifr_addrlen = IPV6_ABITS; 15357c478bd9Sstevel@tonic-gate } 15367c478bd9Sstevel@tonic-gate if (debug & D_PREFIX) { 15377c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "prefix_update_k(%s) set subnet " 15387c478bd9Sstevel@tonic-gate "%s/%u for PR_AUTO on\n", pr->pr_name, 15397c478bd9Sstevel@tonic-gate inet_ntop(AF_INET6, (void *)&sin6->sin6_addr, 15407c478bd9Sstevel@tonic-gate abuf, sizeof (abuf)), lifr.lifr_addrlen); 15417c478bd9Sstevel@tonic-gate } 15427c478bd9Sstevel@tonic-gate if (ioctl(pi->pi_sock, SIOCSLIFSUBNET, (char *)&lifr) < 0) { 15437c478bd9Sstevel@tonic-gate logperror_pr(pr, "prefix_update_k: SIOCSLIFSUBNET"); 15447c478bd9Sstevel@tonic-gate return; 15457c478bd9Sstevel@tonic-gate } 15467c478bd9Sstevel@tonic-gate /* 15477c478bd9Sstevel@tonic-gate * For ptp interfaces, create a destination based on 15487c478bd9Sstevel@tonic-gate * prefix and prefix len together with the remote token 15497c478bd9Sstevel@tonic-gate * extracted from the remote pt-pt address. This is used by 15507c478bd9Sstevel@tonic-gate * ip to choose a proper source for outgoing packets. 15517c478bd9Sstevel@tonic-gate */ 15527c478bd9Sstevel@tonic-gate if (pi->pi_flags & IFF_POINTOPOINT) { 15537c478bd9Sstevel@tonic-gate int i; 15547c478bd9Sstevel@tonic-gate 15557c478bd9Sstevel@tonic-gate sin6 = (struct sockaddr_in6 *)&lifr.lifr_addr; 15567c478bd9Sstevel@tonic-gate bzero(sin6, sizeof (struct sockaddr_in6)); 15577c478bd9Sstevel@tonic-gate sin6->sin6_family = AF_INET6; 15587c478bd9Sstevel@tonic-gate sin6->sin6_addr = pr->pr_prefix; 15597c478bd9Sstevel@tonic-gate for (i = 0; i < 16; i++) { 15607c478bd9Sstevel@tonic-gate sin6->sin6_addr.s6_addr[i] |= 15617c478bd9Sstevel@tonic-gate pi->pi_dst_token.s6_addr[i]; 15627c478bd9Sstevel@tonic-gate } 15637c478bd9Sstevel@tonic-gate if (debug & D_PREFIX) { 15647c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "prefix_update_k(%s) " 15657c478bd9Sstevel@tonic-gate "set dstaddr %s for PR_AUTO on\n", 15667c478bd9Sstevel@tonic-gate pr->pr_name, inet_ntop(AF_INET6, 15677c478bd9Sstevel@tonic-gate (void *)&sin6->sin6_addr, 15687c478bd9Sstevel@tonic-gate abuf, sizeof (abuf))); 15697c478bd9Sstevel@tonic-gate } 15707c478bd9Sstevel@tonic-gate if (ioctl(pi->pi_sock, SIOCSLIFDSTADDR, 15717c478bd9Sstevel@tonic-gate (char *)&lifr) < 0) { 15727c478bd9Sstevel@tonic-gate logperror_pr(pr, 15737c478bd9Sstevel@tonic-gate "prefix_update_k: SIOCSLIFDSTADDR"); 15747c478bd9Sstevel@tonic-gate return; 15757c478bd9Sstevel@tonic-gate } 15767c478bd9Sstevel@tonic-gate } 15777c478bd9Sstevel@tonic-gate if (prefix_modify_flags(pr, IFF_UP, IFF_NOLOCAL) == -1) 15787c478bd9Sstevel@tonic-gate return; 15797c478bd9Sstevel@tonic-gate pr->pr_kernel_state |= PR_AUTO; 15807c478bd9Sstevel@tonic-gate if (pr->pr_state & PR_ONLINK) 15817c478bd9Sstevel@tonic-gate pr->pr_kernel_state |= PR_ONLINK; 15827c478bd9Sstevel@tonic-gate else 15837c478bd9Sstevel@tonic-gate pr->pr_kernel_state &= ~PR_ONLINK; 15847c478bd9Sstevel@tonic-gate } 15857c478bd9Sstevel@tonic-gate if (!(pr->pr_state & PR_AUTO) && (pr->pr_kernel_state & PR_AUTO)) { 15867c478bd9Sstevel@tonic-gate /* Turn on IFF_NOLOCAL and set the local address to all zero */ 15877c478bd9Sstevel@tonic-gate if (prefix_modify_flags(pr, IFF_NOLOCAL, 0) == -1) 15887c478bd9Sstevel@tonic-gate return; 15897c478bd9Sstevel@tonic-gate (void) strncpy(lifr.lifr_name, pr->pr_name, 15907c478bd9Sstevel@tonic-gate sizeof (lifr.lifr_name)); 15917c478bd9Sstevel@tonic-gate lifr.lifr_name[sizeof (lifr.lifr_name) - 1] = '\0'; 15927c478bd9Sstevel@tonic-gate sin6 = (struct sockaddr_in6 *)&lifr.lifr_addr; 15937c478bd9Sstevel@tonic-gate bzero(sin6, sizeof (struct sockaddr_in6)); 15947c478bd9Sstevel@tonic-gate sin6->sin6_family = AF_INET6; 15957c478bd9Sstevel@tonic-gate if (debug & D_PREFIX) { 15967c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "prefix_update_k(%s) set addr %s " 15977c478bd9Sstevel@tonic-gate "for PR_AUTO off\n", pr->pr_name, 15987c478bd9Sstevel@tonic-gate inet_ntop(AF_INET6, (void *)&sin6->sin6_addr, 15997c478bd9Sstevel@tonic-gate abuf, sizeof (abuf))); 16007c478bd9Sstevel@tonic-gate } 16017c478bd9Sstevel@tonic-gate if (ioctl(pi->pi_sock, SIOCSLIFADDR, (char *)&lifr) < 0) { 16027c478bd9Sstevel@tonic-gate logperror_pr(pr, "prefix_update_k: SIOCSLIFADDR"); 16037c478bd9Sstevel@tonic-gate return; 16047c478bd9Sstevel@tonic-gate } 16057c478bd9Sstevel@tonic-gate pr->pr_kernel_state &= ~PR_AUTO; 16067c478bd9Sstevel@tonic-gate } 16077c478bd9Sstevel@tonic-gate if ((pr->pr_state & PR_DEPRECATED) && 16087c478bd9Sstevel@tonic-gate !(pr->pr_kernel_state & PR_DEPRECATED) && 16097c478bd9Sstevel@tonic-gate (pr->pr_kernel_state & PR_AUTO)) { 16107c478bd9Sstevel@tonic-gate /* Only applies if PR_AUTO */ 16117c478bd9Sstevel@tonic-gate if (prefix_modify_flags(pr, IFF_DEPRECATED, 0) == -1) 16127c478bd9Sstevel@tonic-gate return; 16137c478bd9Sstevel@tonic-gate pr->pr_kernel_state |= PR_DEPRECATED; 16147c478bd9Sstevel@tonic-gate } 16157c478bd9Sstevel@tonic-gate if (!(pr->pr_state & PR_DEPRECATED) && 16167c478bd9Sstevel@tonic-gate (pr->pr_kernel_state & PR_DEPRECATED)) { 16177c478bd9Sstevel@tonic-gate if (prefix_modify_flags(pr, 0, IFF_DEPRECATED) == -1) 16187c478bd9Sstevel@tonic-gate return; 16197c478bd9Sstevel@tonic-gate pr->pr_kernel_state &= ~PR_DEPRECATED; 16207c478bd9Sstevel@tonic-gate } 16217c478bd9Sstevel@tonic-gate if ((pr->pr_state & PR_ONLINK) && !(pr->pr_kernel_state & PR_ONLINK)) { 16227c478bd9Sstevel@tonic-gate /* Set the subnet and set IFF_UP */ 16237c478bd9Sstevel@tonic-gate (void) strncpy(lifr.lifr_name, pr->pr_name, 16247c478bd9Sstevel@tonic-gate sizeof (lifr.lifr_name)); 16257c478bd9Sstevel@tonic-gate lifr.lifr_name[sizeof (lifr.lifr_name) - 1] = '\0'; 16267c478bd9Sstevel@tonic-gate sin6 = (struct sockaddr_in6 *)&lifr.lifr_addr; 16277c478bd9Sstevel@tonic-gate bzero(sin6, sizeof (struct sockaddr_in6)); 16287c478bd9Sstevel@tonic-gate sin6->sin6_family = AF_INET6; 16297c478bd9Sstevel@tonic-gate sin6->sin6_addr = pr->pr_prefix; 16307c478bd9Sstevel@tonic-gate lifr.lifr_addrlen = pr->pr_prefix_len; 16317c478bd9Sstevel@tonic-gate if (debug & D_PREFIX) { 16327c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "prefix_update_k(%s) set subnet " 16337c478bd9Sstevel@tonic-gate "%s/%d for PR_ONLINK on\n", pr->pr_name, 16347c478bd9Sstevel@tonic-gate inet_ntop(AF_INET6, (void *)&sin6->sin6_addr, 16357c478bd9Sstevel@tonic-gate abuf, sizeof (abuf)), lifr.lifr_addrlen); 16367c478bd9Sstevel@tonic-gate } 16377c478bd9Sstevel@tonic-gate if (ioctl(pi->pi_sock, SIOCSLIFSUBNET, (char *)&lifr) < 0) { 16387c478bd9Sstevel@tonic-gate logperror_pr(pr, "prefix_update_k: SIOCSLIFSUBNET"); 16397c478bd9Sstevel@tonic-gate return; 16407c478bd9Sstevel@tonic-gate } 16417c478bd9Sstevel@tonic-gate if (!(pr->pr_state & PR_AUTO)) { 16427c478bd9Sstevel@tonic-gate if (prefix_modify_flags(pr, IFF_NOLOCAL, 0) == -1) 16437c478bd9Sstevel@tonic-gate return; 16447c478bd9Sstevel@tonic-gate } 16457c478bd9Sstevel@tonic-gate if (prefix_modify_flags(pr, IFF_UP, 0) == -1) 16467c478bd9Sstevel@tonic-gate return; 16477c478bd9Sstevel@tonic-gate pr->pr_kernel_state |= PR_ONLINK; 16487c478bd9Sstevel@tonic-gate } 16497c478bd9Sstevel@tonic-gate if (!(pr->pr_state & PR_ONLINK) && (pr->pr_kernel_state & PR_ONLINK)) { 16507c478bd9Sstevel@tonic-gate /* Set the prefixlen to 128 */ 16517c478bd9Sstevel@tonic-gate (void) strncpy(lifr.lifr_name, pr->pr_name, 16527c478bd9Sstevel@tonic-gate sizeof (lifr.lifr_name)); 16537c478bd9Sstevel@tonic-gate lifr.lifr_name[sizeof (lifr.lifr_name) - 1] = '\0'; 16547c478bd9Sstevel@tonic-gate sin6 = (struct sockaddr_in6 *)&lifr.lifr_addr; 16557c478bd9Sstevel@tonic-gate bzero(sin6, sizeof (struct sockaddr_in6)); 16567c478bd9Sstevel@tonic-gate sin6->sin6_family = AF_INET6; 16577c478bd9Sstevel@tonic-gate sin6->sin6_addr = pr->pr_address; 16587c478bd9Sstevel@tonic-gate lifr.lifr_addrlen = IPV6_ABITS; 16597c478bd9Sstevel@tonic-gate if (debug & D_PREFIX) { 16607c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "prefix_update_k(%s) set subnet " 16617c478bd9Sstevel@tonic-gate "%s/%d for PR_ONLINK off\n", pr->pr_name, 16627c478bd9Sstevel@tonic-gate inet_ntop(AF_INET6, (void *)&sin6->sin6_addr, 16637c478bd9Sstevel@tonic-gate abuf, sizeof (abuf)), lifr.lifr_addrlen); 16647c478bd9Sstevel@tonic-gate } 16657c478bd9Sstevel@tonic-gate if (ioctl(pi->pi_sock, SIOCSLIFSUBNET, (char *)&lifr) < 0) { 16667c478bd9Sstevel@tonic-gate logperror_pr(pr, "prefix_update_k: SIOCSLIFSUBNET"); 16677c478bd9Sstevel@tonic-gate return; 16687c478bd9Sstevel@tonic-gate } 16697c478bd9Sstevel@tonic-gate pr->pr_kernel_state &= ~PR_ONLINK; 16707c478bd9Sstevel@tonic-gate } 16717c478bd9Sstevel@tonic-gate } 16727c478bd9Sstevel@tonic-gate 16737c478bd9Sstevel@tonic-gate /* 16747c478bd9Sstevel@tonic-gate * Called with the number of millseconds elapsed since the last call. 16757c478bd9Sstevel@tonic-gate * Determines if any timeout event has occurred and 16767c478bd9Sstevel@tonic-gate * returns the number of milliseconds until the next timeout event. 16777c478bd9Sstevel@tonic-gate * Returns TIMER_INFINITY for "never". 16787c478bd9Sstevel@tonic-gate */ 16797c478bd9Sstevel@tonic-gate uint_t 16807c478bd9Sstevel@tonic-gate prefix_timer(struct prefix *pr, uint_t elapsed) 16817c478bd9Sstevel@tonic-gate { 16827c478bd9Sstevel@tonic-gate uint_t next = TIMER_INFINITY; 16837c478bd9Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 16847c478bd9Sstevel@tonic-gate 16857c478bd9Sstevel@tonic-gate if (debug & (D_PREFIX|D_TMP)) { 16867c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "prefix_timer(%s, %s/%u, %d) " 16877c478bd9Sstevel@tonic-gate "valid %d pref %d onlink %d\n", 16887c478bd9Sstevel@tonic-gate pr->pr_name, 16897c478bd9Sstevel@tonic-gate inet_ntop(AF_INET6, (void *)&pr->pr_prefix, 16907c478bd9Sstevel@tonic-gate abuf, sizeof (abuf)), pr->pr_prefix_len, 16917c478bd9Sstevel@tonic-gate elapsed, pr->pr_ValidLifetime, pr->pr_PreferredLifetime, 16927c478bd9Sstevel@tonic-gate pr->pr_OnLinkLifetime); 16937c478bd9Sstevel@tonic-gate } 16947c478bd9Sstevel@tonic-gate 16957c478bd9Sstevel@tonic-gate /* Exclude static prefixes */ 16967c478bd9Sstevel@tonic-gate if (pr->pr_state & PR_STATIC) 16977c478bd9Sstevel@tonic-gate return (next); 16987c478bd9Sstevel@tonic-gate 16997c478bd9Sstevel@tonic-gate if (pr->pr_AutonomousFlag && 17007c478bd9Sstevel@tonic-gate (pr->pr_PreferredLifetime != PREFIX_INFINITY)) { 17017c478bd9Sstevel@tonic-gate if (pr->pr_PreferredLifetime <= elapsed) { 17027c478bd9Sstevel@tonic-gate pr->pr_PreferredLifetime = 0; 17037c478bd9Sstevel@tonic-gate } else { 17047c478bd9Sstevel@tonic-gate pr->pr_PreferredLifetime -= elapsed; 17057c478bd9Sstevel@tonic-gate if (pr->pr_PreferredLifetime < next) 17067c478bd9Sstevel@tonic-gate next = pr->pr_PreferredLifetime; 17077c478bd9Sstevel@tonic-gate } 17087c478bd9Sstevel@tonic-gate } 17097c478bd9Sstevel@tonic-gate if (pr->pr_AutonomousFlag && 17107c478bd9Sstevel@tonic-gate (pr->pr_ValidLifetime != PREFIX_INFINITY)) { 17117c478bd9Sstevel@tonic-gate if (pr->pr_ValidLifetime <= elapsed) { 17127c478bd9Sstevel@tonic-gate pr->pr_ValidLifetime = 0; 17137c478bd9Sstevel@tonic-gate } else { 17147c478bd9Sstevel@tonic-gate pr->pr_ValidLifetime -= elapsed; 17157c478bd9Sstevel@tonic-gate if (pr->pr_ValidLifetime < next) 17167c478bd9Sstevel@tonic-gate next = pr->pr_ValidLifetime; 17177c478bd9Sstevel@tonic-gate } 17187c478bd9Sstevel@tonic-gate } 17197c478bd9Sstevel@tonic-gate if (pr->pr_OnLinkFlag && 17207c478bd9Sstevel@tonic-gate (pr->pr_OnLinkLifetime != PREFIX_INFINITY)) { 17217c478bd9Sstevel@tonic-gate if (pr->pr_OnLinkLifetime <= elapsed) { 17227c478bd9Sstevel@tonic-gate pr->pr_OnLinkLifetime = 0; 17237c478bd9Sstevel@tonic-gate } else { 17247c478bd9Sstevel@tonic-gate pr->pr_OnLinkLifetime -= elapsed; 17257c478bd9Sstevel@tonic-gate if (pr->pr_OnLinkLifetime < next) 17267c478bd9Sstevel@tonic-gate next = pr->pr_OnLinkLifetime; 17277c478bd9Sstevel@tonic-gate } 17287c478bd9Sstevel@tonic-gate } 17297c478bd9Sstevel@tonic-gate if (pr->pr_AutonomousFlag && pr->pr_ValidLifetime == 0) 17307c478bd9Sstevel@tonic-gate pr->pr_state &= ~(PR_AUTO|PR_DEPRECATED); 17317c478bd9Sstevel@tonic-gate if (pr->pr_AutonomousFlag && pr->pr_PreferredLifetime == 0 && 17327c478bd9Sstevel@tonic-gate (pr->pr_state & PR_AUTO)) { 17337c478bd9Sstevel@tonic-gate pr->pr_state |= PR_DEPRECATED; 17347c478bd9Sstevel@tonic-gate if (debug & D_TMP) 17357c478bd9Sstevel@tonic-gate logmsg(LOG_WARNING, "prefix_timer: deprecated " 17367c478bd9Sstevel@tonic-gate "prefix(%s)\n", pr->pr_name); 17377c478bd9Sstevel@tonic-gate } 17387c478bd9Sstevel@tonic-gate if (pr->pr_OnLinkFlag && pr->pr_OnLinkLifetime == 0) 17397c478bd9Sstevel@tonic-gate pr->pr_state &= ~PR_ONLINK; 17407c478bd9Sstevel@tonic-gate 17417c478bd9Sstevel@tonic-gate if (pr->pr_state != pr->pr_kernel_state) { 17427c478bd9Sstevel@tonic-gate /* Might cause prefix to be deleted! */ 17437c478bd9Sstevel@tonic-gate 17447c478bd9Sstevel@tonic-gate /* Log a message when an addrconf prefix goes away */ 17457c478bd9Sstevel@tonic-gate if ((pr->pr_kernel_state & PR_AUTO) && 17467c478bd9Sstevel@tonic-gate !(pr->pr_state & PR_AUTO)) { 17477c478bd9Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 17487c478bd9Sstevel@tonic-gate 17497c478bd9Sstevel@tonic-gate logmsg(LOG_WARNING, 17507c478bd9Sstevel@tonic-gate "Address removed due to timeout %s\n", 17517c478bd9Sstevel@tonic-gate inet_ntop(AF_INET6, (void *)&pr->pr_address, 17527c478bd9Sstevel@tonic-gate abuf, sizeof (abuf))); 17537c478bd9Sstevel@tonic-gate } 17547c478bd9Sstevel@tonic-gate prefix_update_k(pr); 17557c478bd9Sstevel@tonic-gate } 17567c478bd9Sstevel@tonic-gate 17577c478bd9Sstevel@tonic-gate return (next); 17587c478bd9Sstevel@tonic-gate } 17597c478bd9Sstevel@tonic-gate 17607c478bd9Sstevel@tonic-gate static char * 17617c478bd9Sstevel@tonic-gate prefix_print_state(int state, char *buf, int buflen) 17627c478bd9Sstevel@tonic-gate { 17637c478bd9Sstevel@tonic-gate char *cp; 17647c478bd9Sstevel@tonic-gate int cplen = buflen; 17657c478bd9Sstevel@tonic-gate 17667c478bd9Sstevel@tonic-gate cp = buf; 17677c478bd9Sstevel@tonic-gate cp[0] = '\0'; 17687c478bd9Sstevel@tonic-gate 17697c478bd9Sstevel@tonic-gate if (state & PR_ONLINK) { 17707c478bd9Sstevel@tonic-gate if (strlcat(cp, "ONLINK ", cplen) >= cplen) 17717c478bd9Sstevel@tonic-gate return (buf); 17727c478bd9Sstevel@tonic-gate cp += strlen(cp); 17737c478bd9Sstevel@tonic-gate cplen = buflen - (cp - buf); 17747c478bd9Sstevel@tonic-gate } 17757c478bd9Sstevel@tonic-gate if (state & PR_AUTO) { 17767c478bd9Sstevel@tonic-gate if (strlcat(cp, "AUTO ", cplen) >= cplen) 17777c478bd9Sstevel@tonic-gate return (buf); 17787c478bd9Sstevel@tonic-gate cp += strlen(cp); 17797c478bd9Sstevel@tonic-gate cplen = buflen - (cp - buf); 17807c478bd9Sstevel@tonic-gate } 17817c478bd9Sstevel@tonic-gate if (state & PR_DEPRECATED) { 17827c478bd9Sstevel@tonic-gate if (strlcat(cp, "DEPRECATED ", cplen) >= cplen) 17837c478bd9Sstevel@tonic-gate return (buf); 17847c478bd9Sstevel@tonic-gate cp += strlen(cp); 17857c478bd9Sstevel@tonic-gate cplen = buflen - (cp - buf); 17867c478bd9Sstevel@tonic-gate } 17877c478bd9Sstevel@tonic-gate if (state & PR_STATIC) { 17887c478bd9Sstevel@tonic-gate if (strlcat(cp, "STATIC ", cplen) >= cplen) 17897c478bd9Sstevel@tonic-gate return (buf); 17907c478bd9Sstevel@tonic-gate cp += strlen(cp); 17917c478bd9Sstevel@tonic-gate cplen = buflen - (cp - buf); 17927c478bd9Sstevel@tonic-gate } 17937c478bd9Sstevel@tonic-gate return (buf); 17947c478bd9Sstevel@tonic-gate } 17957c478bd9Sstevel@tonic-gate 17967c478bd9Sstevel@tonic-gate static void 17977c478bd9Sstevel@tonic-gate prefix_print(struct prefix *pr) 17987c478bd9Sstevel@tonic-gate { 17997c478bd9Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 18007c478bd9Sstevel@tonic-gate char buf1[PREFIX_STATESTRLEN], buf2[PREFIX_STATESTRLEN]; 18017c478bd9Sstevel@tonic-gate 18027c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "Prefix name: %s prefix %s/%u state %s " 18037c478bd9Sstevel@tonic-gate "kernel_state %s\n", pr->pr_name, 18047c478bd9Sstevel@tonic-gate inet_ntop(AF_INET6, (void *)&pr->pr_prefix, abuf, sizeof (abuf)), 18057c478bd9Sstevel@tonic-gate pr->pr_prefix_len, 18067c478bd9Sstevel@tonic-gate prefix_print_state(pr->pr_state, buf2, sizeof (buf2)), 18077c478bd9Sstevel@tonic-gate prefix_print_state(pr->pr_kernel_state, buf1, sizeof (buf1))); 18087c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "\tAddress: %s flags %llx in_use %d\n", 18097c478bd9Sstevel@tonic-gate inet_ntop(AF_INET6, (void *)&pr->pr_address, abuf, sizeof (abuf)), 18107c478bd9Sstevel@tonic-gate pr->pr_flags, pr->pr_in_use); 18117c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "\tValidLifetime %u PreferredLifetime %u " 18127c478bd9Sstevel@tonic-gate "OnLinkLifetime %u\n", pr->pr_ValidLifetime, 18137c478bd9Sstevel@tonic-gate pr->pr_PreferredLifetime, pr->pr_OnLinkLifetime); 18147c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "\tOnLink %d Auto %d\n", 18157c478bd9Sstevel@tonic-gate pr->pr_OnLinkFlag, pr->pr_AutonomousFlag); 18167c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "\n"); 18177c478bd9Sstevel@tonic-gate } 18187c478bd9Sstevel@tonic-gate 18197c478bd9Sstevel@tonic-gate /* 18207c478bd9Sstevel@tonic-gate * Does the address formed by pr->pr_prefix and pi->pi_token match 18217c478bd9Sstevel@tonic-gate * pr->pr_address. It does not match if a failover has happened 18227c478bd9Sstevel@tonic-gate * earlier (done by in.mpathd) from a different pi. Should not 18237c478bd9Sstevel@tonic-gate * be called for onlink prefixes. 18247c478bd9Sstevel@tonic-gate */ 18257c478bd9Sstevel@tonic-gate boolean_t 18267c478bd9Sstevel@tonic-gate prefix_token_match(struct phyint *pi, struct prefix *pr, uint64_t flags) 18277c478bd9Sstevel@tonic-gate { 18287c478bd9Sstevel@tonic-gate int i; 18297c478bd9Sstevel@tonic-gate in6_addr_t addr, *token; 18307c478bd9Sstevel@tonic-gate 18317c478bd9Sstevel@tonic-gate if (flags & IFF_TEMPORARY) 18327c478bd9Sstevel@tonic-gate token = &pi->pi_tmp_token; 18337c478bd9Sstevel@tonic-gate else 18347c478bd9Sstevel@tonic-gate token = &pi->pi_token; 18357c478bd9Sstevel@tonic-gate for (i = 0; i < 16; i++) { 18367c478bd9Sstevel@tonic-gate /* 18377c478bd9Sstevel@tonic-gate * prefix_create ensures that pr_prefix has all-zero 18387c478bd9Sstevel@tonic-gate * bits after prefixlen. 18397c478bd9Sstevel@tonic-gate */ 18407c478bd9Sstevel@tonic-gate addr.s6_addr[i] = pr->pr_prefix.s6_addr[i] | token->s6_addr[i]; 18417c478bd9Sstevel@tonic-gate } 18427c478bd9Sstevel@tonic-gate if (IN6_ARE_ADDR_EQUAL(&pr->pr_address, &addr)) { 18437c478bd9Sstevel@tonic-gate return (_B_TRUE); 18447c478bd9Sstevel@tonic-gate } else { 18457c478bd9Sstevel@tonic-gate return (_B_FALSE); 18467c478bd9Sstevel@tonic-gate } 18477c478bd9Sstevel@tonic-gate } 18487c478bd9Sstevel@tonic-gate 18497c478bd9Sstevel@tonic-gate /* 18507c478bd9Sstevel@tonic-gate * Lookup advertisement prefix structure that matches the prefix and 18517c478bd9Sstevel@tonic-gate * prefix length. 18527c478bd9Sstevel@tonic-gate * Assumes that the bits after prefixlen might not be zero. 18537c478bd9Sstevel@tonic-gate */ 18547c478bd9Sstevel@tonic-gate struct adv_prefix * 18557c478bd9Sstevel@tonic-gate adv_prefix_lookup(struct phyint *pi, struct in6_addr prefix, int prefixlen) 18567c478bd9Sstevel@tonic-gate { 18577c478bd9Sstevel@tonic-gate struct adv_prefix *adv_pr; 18587c478bd9Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 18597c478bd9Sstevel@tonic-gate 18607c478bd9Sstevel@tonic-gate if (debug & D_PREFIX) { 18617c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "adv_prefix_lookup(%s, %s/%u)\n", 18627c478bd9Sstevel@tonic-gate pi->pi_name, inet_ntop(AF_INET6, (void *)&prefix, 18637c478bd9Sstevel@tonic-gate abuf, sizeof (abuf)), prefixlen); 18647c478bd9Sstevel@tonic-gate } 18657c478bd9Sstevel@tonic-gate 18667c478bd9Sstevel@tonic-gate for (adv_pr = pi->pi_adv_prefix_list; adv_pr != NULL; 18677c478bd9Sstevel@tonic-gate adv_pr = adv_pr->adv_pr_next) { 18687c478bd9Sstevel@tonic-gate if (adv_pr->adv_pr_prefix_len == prefixlen && 18697c478bd9Sstevel@tonic-gate prefix_equal(prefix, adv_pr->adv_pr_prefix, prefixlen)) 18707c478bd9Sstevel@tonic-gate return (adv_pr); 18717c478bd9Sstevel@tonic-gate } 18727c478bd9Sstevel@tonic-gate return (NULL); 18737c478bd9Sstevel@tonic-gate } 18747c478bd9Sstevel@tonic-gate 18757c478bd9Sstevel@tonic-gate /* 18767c478bd9Sstevel@tonic-gate * Initialize a new advertisement prefix. 18777c478bd9Sstevel@tonic-gate */ 18787c478bd9Sstevel@tonic-gate struct adv_prefix * 18797c478bd9Sstevel@tonic-gate adv_prefix_create(struct phyint *pi, struct in6_addr prefix, int prefixlen) 18807c478bd9Sstevel@tonic-gate { 18817c478bd9Sstevel@tonic-gate struct adv_prefix *adv_pr; 18827c478bd9Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 18837c478bd9Sstevel@tonic-gate 18847c478bd9Sstevel@tonic-gate if (debug & D_PREFIX) { 18857c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "adv_prefix_create(%s, %s/%u)\n", 18867c478bd9Sstevel@tonic-gate pi->pi_name, inet_ntop(AF_INET6, (void *)&prefix, 18877c478bd9Sstevel@tonic-gate abuf, sizeof (abuf)), prefixlen); 18887c478bd9Sstevel@tonic-gate } 18897c478bd9Sstevel@tonic-gate adv_pr = (struct adv_prefix *)calloc(sizeof (struct adv_prefix), 1); 18907c478bd9Sstevel@tonic-gate if (adv_pr == NULL) { 18917c478bd9Sstevel@tonic-gate logmsg(LOG_ERR, "adv_prefix_create: calloc\n"); 18927c478bd9Sstevel@tonic-gate return (NULL); 18937c478bd9Sstevel@tonic-gate } 18947c478bd9Sstevel@tonic-gate /* 18957c478bd9Sstevel@tonic-gate * The prefix might have non-zero bits after the prefix len bits. 18967c478bd9Sstevel@tonic-gate * Force them to be zero. 18977c478bd9Sstevel@tonic-gate */ 18987c478bd9Sstevel@tonic-gate prefix_set(&adv_pr->adv_pr_prefix, prefix, prefixlen); 18997c478bd9Sstevel@tonic-gate adv_pr->adv_pr_prefix_len = prefixlen; 19007c478bd9Sstevel@tonic-gate adv_prefix_insert(pi, adv_pr); 19017c478bd9Sstevel@tonic-gate return (adv_pr); 19027c478bd9Sstevel@tonic-gate } 19037c478bd9Sstevel@tonic-gate 19047c478bd9Sstevel@tonic-gate /* Insert in linked list */ 19057c478bd9Sstevel@tonic-gate static void 19067c478bd9Sstevel@tonic-gate adv_prefix_insert(struct phyint *pi, struct adv_prefix *adv_pr) 19077c478bd9Sstevel@tonic-gate { 19087c478bd9Sstevel@tonic-gate adv_pr->adv_pr_next = pi->pi_adv_prefix_list; 19097c478bd9Sstevel@tonic-gate adv_pr->adv_pr_prev = NULL; 19107c478bd9Sstevel@tonic-gate if (pi->pi_adv_prefix_list != NULL) 19117c478bd9Sstevel@tonic-gate pi->pi_adv_prefix_list->adv_pr_prev = adv_pr; 19127c478bd9Sstevel@tonic-gate pi->pi_adv_prefix_list = adv_pr; 19137c478bd9Sstevel@tonic-gate adv_pr->adv_pr_physical = pi; 19147c478bd9Sstevel@tonic-gate } 19157c478bd9Sstevel@tonic-gate 19167c478bd9Sstevel@tonic-gate /* 19177c478bd9Sstevel@tonic-gate * Delete (unlink and free) from our tables. There should be 19187c478bd9Sstevel@tonic-gate * a corresponding "struct prefix *" which will clean up the kernel 19197c478bd9Sstevel@tonic-gate * if necessary. adv_prefix is just used for sending out advertisements. 19207c478bd9Sstevel@tonic-gate */ 19217c478bd9Sstevel@tonic-gate static void 19227c478bd9Sstevel@tonic-gate adv_prefix_delete(struct adv_prefix *adv_pr) 19237c478bd9Sstevel@tonic-gate { 19247c478bd9Sstevel@tonic-gate struct phyint *pi; 19257c478bd9Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 19267c478bd9Sstevel@tonic-gate 19277c478bd9Sstevel@tonic-gate if (debug & D_PREFIX) { 19287c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "adv_prefix_delete(%s, %s/%u)\n", 19297c478bd9Sstevel@tonic-gate adv_pr->adv_pr_physical->pi_name, 19307c478bd9Sstevel@tonic-gate inet_ntop(AF_INET6, (void *)&adv_pr->adv_pr_prefix, 19317c478bd9Sstevel@tonic-gate abuf, sizeof (abuf)), adv_pr->adv_pr_prefix_len); 19327c478bd9Sstevel@tonic-gate } 19337c478bd9Sstevel@tonic-gate pi = adv_pr->adv_pr_physical; 19347c478bd9Sstevel@tonic-gate 19357c478bd9Sstevel@tonic-gate if (adv_pr->adv_pr_prev == NULL) { 19367c478bd9Sstevel@tonic-gate if (pi != NULL) 19377c478bd9Sstevel@tonic-gate pi->pi_adv_prefix_list = adv_pr->adv_pr_next; 19387c478bd9Sstevel@tonic-gate } else { 19397c478bd9Sstevel@tonic-gate adv_pr->adv_pr_prev->adv_pr_next = adv_pr->adv_pr_next; 19407c478bd9Sstevel@tonic-gate } 19417c478bd9Sstevel@tonic-gate if (adv_pr->adv_pr_next != NULL) 19427c478bd9Sstevel@tonic-gate adv_pr->adv_pr_next->adv_pr_prev = adv_pr->adv_pr_prev; 19437c478bd9Sstevel@tonic-gate adv_pr->adv_pr_next = adv_pr->adv_pr_prev = NULL; 19447c478bd9Sstevel@tonic-gate free(adv_pr); 19457c478bd9Sstevel@tonic-gate } 19467c478bd9Sstevel@tonic-gate 19477c478bd9Sstevel@tonic-gate /* 19487c478bd9Sstevel@tonic-gate * Called with the number of millseconds elapsed since the last call. 19497c478bd9Sstevel@tonic-gate * Determines if any timeout event has occurred and 19507c478bd9Sstevel@tonic-gate * returns the number of milliseconds until the next timeout event. 19517c478bd9Sstevel@tonic-gate * Returns TIMER_INFINITY for "never". 19527c478bd9Sstevel@tonic-gate */ 19537c478bd9Sstevel@tonic-gate uint_t 19547c478bd9Sstevel@tonic-gate adv_prefix_timer(struct adv_prefix *adv_pr, uint_t elapsed) 19557c478bd9Sstevel@tonic-gate { 19567c478bd9Sstevel@tonic-gate int seconds_elapsed = (elapsed + 500) / 1000; /* Rounded */ 19577c478bd9Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 19587c478bd9Sstevel@tonic-gate 19597c478bd9Sstevel@tonic-gate if (debug & D_PREFIX) { 19607c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "adv_prefix_timer(%s, %s/%u, %d)\n", 19617c478bd9Sstevel@tonic-gate adv_pr->adv_pr_physical->pi_name, 19627c478bd9Sstevel@tonic-gate inet_ntop(AF_INET6, (void *)&adv_pr->adv_pr_prefix, 19637c478bd9Sstevel@tonic-gate abuf, sizeof (abuf)), adv_pr->adv_pr_prefix_len, 19647c478bd9Sstevel@tonic-gate elapsed); 19657c478bd9Sstevel@tonic-gate } 19667c478bd9Sstevel@tonic-gate 19677c478bd9Sstevel@tonic-gate /* Decrement Expire time left for real-time lifetimes */ 19687c478bd9Sstevel@tonic-gate if (adv_pr->adv_pr_AdvValidRealTime) { 19697c478bd9Sstevel@tonic-gate if (adv_pr->adv_pr_AdvValidExpiration > seconds_elapsed) 19707c478bd9Sstevel@tonic-gate adv_pr->adv_pr_AdvValidExpiration -= seconds_elapsed; 19717c478bd9Sstevel@tonic-gate else 19727c478bd9Sstevel@tonic-gate adv_pr->adv_pr_AdvValidExpiration = 0; 19737c478bd9Sstevel@tonic-gate } 19747c478bd9Sstevel@tonic-gate if (adv_pr->adv_pr_AdvPreferredRealTime) { 19757c478bd9Sstevel@tonic-gate if (adv_pr->adv_pr_AdvPreferredExpiration > seconds_elapsed) { 19767c478bd9Sstevel@tonic-gate adv_pr->adv_pr_AdvPreferredExpiration -= 19777c478bd9Sstevel@tonic-gate seconds_elapsed; 19787c478bd9Sstevel@tonic-gate } else { 19797c478bd9Sstevel@tonic-gate adv_pr->adv_pr_AdvPreferredExpiration = 0; 19807c478bd9Sstevel@tonic-gate } 19817c478bd9Sstevel@tonic-gate } 19827c478bd9Sstevel@tonic-gate return (TIMER_INFINITY); 19837c478bd9Sstevel@tonic-gate } 19847c478bd9Sstevel@tonic-gate 19857c478bd9Sstevel@tonic-gate static void 19867c478bd9Sstevel@tonic-gate adv_prefix_print(struct adv_prefix *adv_pr) 19877c478bd9Sstevel@tonic-gate { 19887c478bd9Sstevel@tonic-gate print_prefixlist(adv_pr->adv_pr_config); 19897c478bd9Sstevel@tonic-gate } 19907c478bd9Sstevel@tonic-gate 19917c478bd9Sstevel@tonic-gate /* Lookup router on its link-local IPv6 address */ 19927c478bd9Sstevel@tonic-gate struct router * 19937c478bd9Sstevel@tonic-gate router_lookup(struct phyint *pi, struct in6_addr addr) 19947c478bd9Sstevel@tonic-gate { 19957c478bd9Sstevel@tonic-gate struct router *dr; 19967c478bd9Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 19977c478bd9Sstevel@tonic-gate 19987c478bd9Sstevel@tonic-gate if (debug & D_ROUTER) { 19997c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "router_lookup(%s, %s)\n", pi->pi_name, 20007c478bd9Sstevel@tonic-gate inet_ntop(AF_INET6, (void *)&addr, 20017c478bd9Sstevel@tonic-gate abuf, sizeof (abuf))); 20027c478bd9Sstevel@tonic-gate } 20037c478bd9Sstevel@tonic-gate 20047c478bd9Sstevel@tonic-gate for (dr = pi->pi_router_list; dr != NULL; dr = dr->dr_next) { 20057c478bd9Sstevel@tonic-gate if (bcmp((char *)&addr, (char *)&dr->dr_address, 20067c478bd9Sstevel@tonic-gate sizeof (addr)) == 0) 20077c478bd9Sstevel@tonic-gate return (dr); 20087c478bd9Sstevel@tonic-gate } 20097c478bd9Sstevel@tonic-gate return (NULL); 20107c478bd9Sstevel@tonic-gate } 20117c478bd9Sstevel@tonic-gate 20127c478bd9Sstevel@tonic-gate /* 20137c478bd9Sstevel@tonic-gate * Create a default router entry. 20147c478bd9Sstevel@tonic-gate * The lifetime parameter is in seconds. 20157c478bd9Sstevel@tonic-gate */ 20167c478bd9Sstevel@tonic-gate struct router * 20177c478bd9Sstevel@tonic-gate router_create(struct phyint *pi, struct in6_addr addr, uint_t lifetime) 20187c478bd9Sstevel@tonic-gate { 20197c478bd9Sstevel@tonic-gate struct router *dr; 20207c478bd9Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 20217c478bd9Sstevel@tonic-gate 20227c478bd9Sstevel@tonic-gate if (debug & D_ROUTER) { 20237c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "router_create(%s, %s, %u)\n", pi->pi_name, 20247c478bd9Sstevel@tonic-gate inet_ntop(AF_INET6, (void *)&addr, 20257c478bd9Sstevel@tonic-gate abuf, sizeof (abuf)), lifetime); 20267c478bd9Sstevel@tonic-gate } 20277c478bd9Sstevel@tonic-gate 20287c478bd9Sstevel@tonic-gate dr = (struct router *)calloc(sizeof (struct router), 1); 20297c478bd9Sstevel@tonic-gate if (dr == NULL) { 20307c478bd9Sstevel@tonic-gate logmsg(LOG_ERR, "router_create: out of memory\n"); 20317c478bd9Sstevel@tonic-gate return (NULL); 20327c478bd9Sstevel@tonic-gate } 20337c478bd9Sstevel@tonic-gate dr->dr_address = addr; 20347c478bd9Sstevel@tonic-gate dr->dr_lifetime = lifetime; 20357c478bd9Sstevel@tonic-gate router_insert(pi, dr); 20367c478bd9Sstevel@tonic-gate if (dr->dr_lifetime != 0) { 20377c478bd9Sstevel@tonic-gate /* 20387c478bd9Sstevel@tonic-gate * Delete an onlink default if it exists since we now have 20397c478bd9Sstevel@tonic-gate * at least one default router. 20407c478bd9Sstevel@tonic-gate */ 20417c478bd9Sstevel@tonic-gate if (pi->pi_onlink_default) 20427c478bd9Sstevel@tonic-gate router_delete_onlink(dr->dr_physical); 20437c478bd9Sstevel@tonic-gate router_add_k(dr); 20447c478bd9Sstevel@tonic-gate } 20457c478bd9Sstevel@tonic-gate return (dr); 20467c478bd9Sstevel@tonic-gate } 20477c478bd9Sstevel@tonic-gate 20487c478bd9Sstevel@tonic-gate /* Insert in linked list */ 20497c478bd9Sstevel@tonic-gate static void 20507c478bd9Sstevel@tonic-gate router_insert(struct phyint *pi, struct router *dr) 20517c478bd9Sstevel@tonic-gate { 20527c478bd9Sstevel@tonic-gate dr->dr_next = pi->pi_router_list; 20537c478bd9Sstevel@tonic-gate dr->dr_prev = NULL; 20547c478bd9Sstevel@tonic-gate if (pi->pi_router_list != NULL) 20557c478bd9Sstevel@tonic-gate pi->pi_router_list->dr_prev = dr; 20567c478bd9Sstevel@tonic-gate pi->pi_router_list = dr; 20577c478bd9Sstevel@tonic-gate dr->dr_physical = pi; 20587c478bd9Sstevel@tonic-gate } 20597c478bd9Sstevel@tonic-gate 20607c478bd9Sstevel@tonic-gate /* 20617c478bd9Sstevel@tonic-gate * Delete (unlink and free). 20627c478bd9Sstevel@tonic-gate * Handles delete of things that have not yet been inserted in the list 20637c478bd9Sstevel@tonic-gate * i.e. dr_physical is NULL. 20647c478bd9Sstevel@tonic-gate */ 20657c478bd9Sstevel@tonic-gate static void 20667c478bd9Sstevel@tonic-gate router_delete(struct router *dr) 20677c478bd9Sstevel@tonic-gate { 20687c478bd9Sstevel@tonic-gate struct phyint *pi; 20697c478bd9Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 20707c478bd9Sstevel@tonic-gate 20717c478bd9Sstevel@tonic-gate if (debug & D_ROUTER) { 20727c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "router_delete(%s, %s, %u)\n", 20737c478bd9Sstevel@tonic-gate dr->dr_physical->pi_name, 20747c478bd9Sstevel@tonic-gate inet_ntop(AF_INET6, (void *)&dr->dr_address, 20757c478bd9Sstevel@tonic-gate abuf, sizeof (abuf)), dr->dr_lifetime); 20767c478bd9Sstevel@tonic-gate } 20777c478bd9Sstevel@tonic-gate pi = dr->dr_physical; 20787c478bd9Sstevel@tonic-gate if (dr->dr_inkernel) { 20797c478bd9Sstevel@tonic-gate /* 20807c478bd9Sstevel@tonic-gate * Create a on-link default route only if the interface 20817c478bd9Sstevel@tonic-gate * is present in the kernel. This function is called 20827c478bd9Sstevel@tonic-gate * to clean up the routes when the interface is 20837c478bd9Sstevel@tonic-gate * unplumbed. In that case, don't try to create one 20847c478bd9Sstevel@tonic-gate * in the kernel. 20857c478bd9Sstevel@tonic-gate */ 20867c478bd9Sstevel@tonic-gate if (pi->pi_kernel_state & PI_PRESENT) { 20877c478bd9Sstevel@tonic-gate if (!dr->dr_onlink && 20887c478bd9Sstevel@tonic-gate dr->dr_physical->pi_num_k_routers == 1) { 20897c478bd9Sstevel@tonic-gate (void) router_create_onlink(dr->dr_physical); 20907c478bd9Sstevel@tonic-gate } 20917c478bd9Sstevel@tonic-gate router_delete_k(dr); 20927c478bd9Sstevel@tonic-gate } 20937c478bd9Sstevel@tonic-gate } 20947c478bd9Sstevel@tonic-gate if (dr->dr_onlink) 20957c478bd9Sstevel@tonic-gate pi->pi_onlink_default = _B_FALSE; 20967c478bd9Sstevel@tonic-gate 20977c478bd9Sstevel@tonic-gate if (dr->dr_prev == NULL) { 20987c478bd9Sstevel@tonic-gate if (pi != NULL) 20997c478bd9Sstevel@tonic-gate pi->pi_router_list = dr->dr_next; 21007c478bd9Sstevel@tonic-gate } else { 21017c478bd9Sstevel@tonic-gate dr->dr_prev->dr_next = dr->dr_next; 21027c478bd9Sstevel@tonic-gate } 21037c478bd9Sstevel@tonic-gate if (dr->dr_next != NULL) 21047c478bd9Sstevel@tonic-gate dr->dr_next->dr_prev = dr->dr_prev; 21057c478bd9Sstevel@tonic-gate dr->dr_next = dr->dr_prev = NULL; 21067c478bd9Sstevel@tonic-gate free(dr); 21077c478bd9Sstevel@tonic-gate } 21087c478bd9Sstevel@tonic-gate 21097c478bd9Sstevel@tonic-gate 21107c478bd9Sstevel@tonic-gate /* Create an onlink default route */ 21117c478bd9Sstevel@tonic-gate struct router * 21127c478bd9Sstevel@tonic-gate router_create_onlink(struct phyint *pi) 21137c478bd9Sstevel@tonic-gate { 21147c478bd9Sstevel@tonic-gate struct router *dr; 21157c478bd9Sstevel@tonic-gate struct prefix *pr; 21167c478bd9Sstevel@tonic-gate 21177c478bd9Sstevel@tonic-gate if (debug & D_ROUTER) { 21187c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "router_create_onlink(%s)\n", pi->pi_name); 21197c478bd9Sstevel@tonic-gate } 21207c478bd9Sstevel@tonic-gate 21217c478bd9Sstevel@tonic-gate if (pi->pi_onlink_default) { 21227c478bd9Sstevel@tonic-gate logmsg(LOG_ERR, "router_create_onlink: already an onlink " 21237c478bd9Sstevel@tonic-gate "default: %s\n", pi->pi_name); 21247c478bd9Sstevel@tonic-gate return (NULL); 21257c478bd9Sstevel@tonic-gate } 21267c478bd9Sstevel@tonic-gate 21277c478bd9Sstevel@tonic-gate /* 21287c478bd9Sstevel@tonic-gate * Find the interface address to use for the route gateway. 21297c478bd9Sstevel@tonic-gate * We need to use the link-local since the others ones might be 21307c478bd9Sstevel@tonic-gate * deleted when the prefixes get invalidated. 21317c478bd9Sstevel@tonic-gate */ 21327c478bd9Sstevel@tonic-gate for (pr = pi->pi_prefix_list; pr != NULL; pr = pr->pr_next) { 21337c478bd9Sstevel@tonic-gate if ((pr->pr_state & PR_AUTO) && 21347c478bd9Sstevel@tonic-gate IN6_IS_ADDR_LINKLOCAL(&pr->pr_address)) 21357c478bd9Sstevel@tonic-gate break; 21367c478bd9Sstevel@tonic-gate } 21377c478bd9Sstevel@tonic-gate if (pr == NULL) { 21387c478bd9Sstevel@tonic-gate logmsg(LOG_ERR, "router_create_onlink: no source address\n"); 21397c478bd9Sstevel@tonic-gate return (NULL); 21407c478bd9Sstevel@tonic-gate } 21417c478bd9Sstevel@tonic-gate dr = (struct router *)calloc(sizeof (struct router), 1); 21427c478bd9Sstevel@tonic-gate if (dr == NULL) { 21437c478bd9Sstevel@tonic-gate logmsg(LOG_ERR, "router_create_onlink: out of memory\n"); 21447c478bd9Sstevel@tonic-gate return (NULL); 21457c478bd9Sstevel@tonic-gate } 21467c478bd9Sstevel@tonic-gate dr->dr_address = pr->pr_address; 21477c478bd9Sstevel@tonic-gate dr->dr_lifetime = 1; /* Not used */ 21487c478bd9Sstevel@tonic-gate dr->dr_onlink = _B_TRUE; 21497c478bd9Sstevel@tonic-gate router_insert(pi, dr); 21507c478bd9Sstevel@tonic-gate 21517c478bd9Sstevel@tonic-gate router_add_k(dr); 21527c478bd9Sstevel@tonic-gate pi->pi_onlink_default = _B_TRUE; 21537c478bd9Sstevel@tonic-gate return (dr); 21547c478bd9Sstevel@tonic-gate } 21557c478bd9Sstevel@tonic-gate 21567c478bd9Sstevel@tonic-gate /* Remove an onlink default route */ 21577c478bd9Sstevel@tonic-gate static void 21587c478bd9Sstevel@tonic-gate router_delete_onlink(struct phyint *pi) 21597c478bd9Sstevel@tonic-gate { 21607c478bd9Sstevel@tonic-gate struct router *dr, *next_dr; 21617c478bd9Sstevel@tonic-gate 21627c478bd9Sstevel@tonic-gate if (debug & D_ROUTER) { 21637c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "router_delete_onlink(%s)\n", pi->pi_name); 21647c478bd9Sstevel@tonic-gate } 21657c478bd9Sstevel@tonic-gate 21667c478bd9Sstevel@tonic-gate if (!pi->pi_onlink_default) { 21677c478bd9Sstevel@tonic-gate logmsg(LOG_ERR, "router_delete_onlink: no onlink default: " 21687c478bd9Sstevel@tonic-gate "%s\n", pi->pi_name); 21697c478bd9Sstevel@tonic-gate return; 21707c478bd9Sstevel@tonic-gate } 21717c478bd9Sstevel@tonic-gate /* Find all onlink routes */ 21727c478bd9Sstevel@tonic-gate for (dr = pi->pi_router_list; dr != NULL; dr = next_dr) { 21737c478bd9Sstevel@tonic-gate next_dr = dr->dr_next; 21747c478bd9Sstevel@tonic-gate if (dr->dr_onlink) 21757c478bd9Sstevel@tonic-gate router_delete(dr); 21767c478bd9Sstevel@tonic-gate } 21777c478bd9Sstevel@tonic-gate } 21787c478bd9Sstevel@tonic-gate 21797c478bd9Sstevel@tonic-gate /* 21807c478bd9Sstevel@tonic-gate * Update the kernel to match dr_lifetime 21817c478bd9Sstevel@tonic-gate */ 21827c478bd9Sstevel@tonic-gate void 21837c478bd9Sstevel@tonic-gate router_update_k(struct router *dr) 21847c478bd9Sstevel@tonic-gate { 21857c478bd9Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 21867c478bd9Sstevel@tonic-gate 21877c478bd9Sstevel@tonic-gate if (debug & D_ROUTER) { 21887c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "router_update_k(%s, %s, %u)\n", 21897c478bd9Sstevel@tonic-gate dr->dr_physical->pi_name, 21907c478bd9Sstevel@tonic-gate inet_ntop(AF_INET6, (void *)&dr->dr_address, 21917c478bd9Sstevel@tonic-gate abuf, sizeof (abuf)), dr->dr_lifetime); 21927c478bd9Sstevel@tonic-gate } 21937c478bd9Sstevel@tonic-gate 21947c478bd9Sstevel@tonic-gate if (dr->dr_lifetime == 0 && dr->dr_inkernel) { 21957c478bd9Sstevel@tonic-gate /* Log a message when last router goes away */ 21967c478bd9Sstevel@tonic-gate if (dr->dr_physical->pi_num_k_routers == 1) { 21977c478bd9Sstevel@tonic-gate logmsg(LOG_WARNING, 21987c478bd9Sstevel@tonic-gate "Last default router (%s) removed on %s\n", 21997c478bd9Sstevel@tonic-gate inet_ntop(AF_INET6, (void *)&dr->dr_address, 22007c478bd9Sstevel@tonic-gate abuf, sizeof (abuf)), dr->dr_physical->pi_name); 22017c478bd9Sstevel@tonic-gate } 22027c478bd9Sstevel@tonic-gate router_delete(dr); 22037c478bd9Sstevel@tonic-gate } else if (dr->dr_lifetime != 0 && !dr->dr_inkernel) { 22047c478bd9Sstevel@tonic-gate /* 22057c478bd9Sstevel@tonic-gate * Delete an onlink default if it exists since we now have 22067c478bd9Sstevel@tonic-gate * at least one default router. 22077c478bd9Sstevel@tonic-gate */ 22087c478bd9Sstevel@tonic-gate if (dr->dr_physical->pi_onlink_default) 22097c478bd9Sstevel@tonic-gate router_delete_onlink(dr->dr_physical); 22107c478bd9Sstevel@tonic-gate router_add_k(dr); 22117c478bd9Sstevel@tonic-gate } 22127c478bd9Sstevel@tonic-gate } 22137c478bd9Sstevel@tonic-gate 22147c478bd9Sstevel@tonic-gate 22157c478bd9Sstevel@tonic-gate /* 22167c478bd9Sstevel@tonic-gate * Called with the number of millseconds elapsed since the last call. 22177c478bd9Sstevel@tonic-gate * Determines if any timeout event has occurred and 22187c478bd9Sstevel@tonic-gate * returns the number of milliseconds until the next timeout event. 22197c478bd9Sstevel@tonic-gate * Returns TIMER_INFINITY for "never". 22207c478bd9Sstevel@tonic-gate */ 22217c478bd9Sstevel@tonic-gate uint_t 22227c478bd9Sstevel@tonic-gate router_timer(struct router *dr, uint_t elapsed) 22237c478bd9Sstevel@tonic-gate { 22247c478bd9Sstevel@tonic-gate uint_t next = TIMER_INFINITY; 22257c478bd9Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 22267c478bd9Sstevel@tonic-gate 22277c478bd9Sstevel@tonic-gate if (debug & D_ROUTER) { 22287c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "router_timer(%s, %s, %u, %d)\n", 22297c478bd9Sstevel@tonic-gate dr->dr_physical->pi_name, 22307c478bd9Sstevel@tonic-gate inet_ntop(AF_INET6, (void *)&dr->dr_address, 22317c478bd9Sstevel@tonic-gate abuf, sizeof (abuf)), dr->dr_lifetime, elapsed); 22327c478bd9Sstevel@tonic-gate } 22337c478bd9Sstevel@tonic-gate if (dr->dr_onlink) { 22347c478bd9Sstevel@tonic-gate /* No timeout */ 22357c478bd9Sstevel@tonic-gate return (next); 22367c478bd9Sstevel@tonic-gate } 22377c478bd9Sstevel@tonic-gate if (dr->dr_lifetime <= elapsed) { 22387c478bd9Sstevel@tonic-gate dr->dr_lifetime = 0; 22397c478bd9Sstevel@tonic-gate } else { 22407c478bd9Sstevel@tonic-gate dr->dr_lifetime -= elapsed; 22417c478bd9Sstevel@tonic-gate if (dr->dr_lifetime < next) 22427c478bd9Sstevel@tonic-gate next = dr->dr_lifetime; 22437c478bd9Sstevel@tonic-gate } 22447c478bd9Sstevel@tonic-gate 22457c478bd9Sstevel@tonic-gate if (dr->dr_lifetime == 0) { 22467c478bd9Sstevel@tonic-gate /* Log a message when last router goes away */ 22477c478bd9Sstevel@tonic-gate if (dr->dr_physical->pi_num_k_routers == 1) { 22487c478bd9Sstevel@tonic-gate logmsg(LOG_WARNING, 22497c478bd9Sstevel@tonic-gate "Last default router (%s) timed out on %s\n", 22507c478bd9Sstevel@tonic-gate inet_ntop(AF_INET6, (void *)&dr->dr_address, 22517c478bd9Sstevel@tonic-gate abuf, sizeof (abuf)), dr->dr_physical->pi_name); 22527c478bd9Sstevel@tonic-gate } 22537c478bd9Sstevel@tonic-gate router_delete(dr); 22547c478bd9Sstevel@tonic-gate } 22557c478bd9Sstevel@tonic-gate return (next); 22567c478bd9Sstevel@tonic-gate } 22577c478bd9Sstevel@tonic-gate 22587c478bd9Sstevel@tonic-gate /* 22597c478bd9Sstevel@tonic-gate * Add a default route to the kernel (unless the lifetime is zero) 22607c478bd9Sstevel@tonic-gate * Handles onlink default routes. 22617c478bd9Sstevel@tonic-gate */ 22627c478bd9Sstevel@tonic-gate static void 22637c478bd9Sstevel@tonic-gate router_add_k(struct router *dr) 22647c478bd9Sstevel@tonic-gate { 22657c478bd9Sstevel@tonic-gate struct phyint *pi = dr->dr_physical; 22667c478bd9Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 22677c478bd9Sstevel@tonic-gate int rlen; 22687c478bd9Sstevel@tonic-gate 22697c478bd9Sstevel@tonic-gate if (debug & D_ROUTER) { 22707c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "router_add_k(%s, %s, %u)\n", 22717c478bd9Sstevel@tonic-gate dr->dr_physical->pi_name, 22727c478bd9Sstevel@tonic-gate inet_ntop(AF_INET6, (void *)&dr->dr_address, 22737c478bd9Sstevel@tonic-gate abuf, sizeof (abuf)), dr->dr_lifetime); 22747c478bd9Sstevel@tonic-gate } 22757c478bd9Sstevel@tonic-gate 22767c478bd9Sstevel@tonic-gate if (dr->dr_onlink) 22777c478bd9Sstevel@tonic-gate rt_msg->rtm_flags = 0; 22787c478bd9Sstevel@tonic-gate else 22797c478bd9Sstevel@tonic-gate rt_msg->rtm_flags = RTF_GATEWAY; 22807c478bd9Sstevel@tonic-gate 22817c478bd9Sstevel@tonic-gate rta_gateway->sin6_addr = dr->dr_address; 22827c478bd9Sstevel@tonic-gate 22837c478bd9Sstevel@tonic-gate rta_ifp->sdl_index = if_nametoindex(pi->pi_name); 22847c478bd9Sstevel@tonic-gate if (rta_ifp->sdl_index == 0) { 22857c478bd9Sstevel@tonic-gate logperror_pi(pi, "router_add_k: if_nametoindex"); 22867c478bd9Sstevel@tonic-gate return; 22877c478bd9Sstevel@tonic-gate } 22887c478bd9Sstevel@tonic-gate 22897c478bd9Sstevel@tonic-gate rt_msg->rtm_type = RTM_ADD; 22907c478bd9Sstevel@tonic-gate rt_msg->rtm_seq = ++rtmseq; 22917c478bd9Sstevel@tonic-gate rlen = write(rtsock, rt_msg, rt_msg->rtm_msglen); 22927c478bd9Sstevel@tonic-gate if (rlen < 0) { 22937c478bd9Sstevel@tonic-gate if (errno != EEXIST) { 22947c478bd9Sstevel@tonic-gate logperror_pi(pi, "router_add_k: RTM_ADD"); 22957c478bd9Sstevel@tonic-gate return; 22967c478bd9Sstevel@tonic-gate } 22977c478bd9Sstevel@tonic-gate } else if (rlen < rt_msg->rtm_msglen) { 22987c478bd9Sstevel@tonic-gate logmsg(LOG_ERR, "router_add_k: write to routing socket got " 22997c478bd9Sstevel@tonic-gate "only %d for rlen (interface %s)\n", rlen, pi->pi_name); 23007c478bd9Sstevel@tonic-gate return; 23017c478bd9Sstevel@tonic-gate } 23027c478bd9Sstevel@tonic-gate dr->dr_inkernel = _B_TRUE; 23037c478bd9Sstevel@tonic-gate if (!dr->dr_onlink) 23047c478bd9Sstevel@tonic-gate pi->pi_num_k_routers++; 23057c478bd9Sstevel@tonic-gate } 23067c478bd9Sstevel@tonic-gate 23077c478bd9Sstevel@tonic-gate /* 23087c478bd9Sstevel@tonic-gate * Delete a route from the kernel. 23097c478bd9Sstevel@tonic-gate * Handles onlink default routes. 23107c478bd9Sstevel@tonic-gate */ 23117c478bd9Sstevel@tonic-gate static void 23127c478bd9Sstevel@tonic-gate router_delete_k(struct router *dr) 23137c478bd9Sstevel@tonic-gate { 23147c478bd9Sstevel@tonic-gate struct phyint *pi = dr->dr_physical; 23157c478bd9Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 23167c478bd9Sstevel@tonic-gate int rlen; 23177c478bd9Sstevel@tonic-gate 23187c478bd9Sstevel@tonic-gate if (debug & D_ROUTER) { 23197c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "router_delete_k(%s, %s, %u)\n", 23207c478bd9Sstevel@tonic-gate dr->dr_physical->pi_name, 23217c478bd9Sstevel@tonic-gate inet_ntop(AF_INET6, (void *)&dr->dr_address, 23227c478bd9Sstevel@tonic-gate abuf, sizeof (abuf)), dr->dr_lifetime); 23237c478bd9Sstevel@tonic-gate } 23247c478bd9Sstevel@tonic-gate 23257c478bd9Sstevel@tonic-gate if (dr->dr_onlink) 23267c478bd9Sstevel@tonic-gate rt_msg->rtm_flags = 0; 23277c478bd9Sstevel@tonic-gate else 23287c478bd9Sstevel@tonic-gate rt_msg->rtm_flags = RTF_GATEWAY; 23297c478bd9Sstevel@tonic-gate 23307c478bd9Sstevel@tonic-gate rta_gateway->sin6_addr = dr->dr_address; 23317c478bd9Sstevel@tonic-gate 23327c478bd9Sstevel@tonic-gate rta_ifp->sdl_index = if_nametoindex(pi->pi_name); 23337c478bd9Sstevel@tonic-gate if (rta_ifp->sdl_index == 0) { 23347c478bd9Sstevel@tonic-gate logperror_pi(pi, "router_delete_k: if_nametoindex"); 23357c478bd9Sstevel@tonic-gate return; 23367c478bd9Sstevel@tonic-gate } 23377c478bd9Sstevel@tonic-gate 23387c478bd9Sstevel@tonic-gate rt_msg->rtm_type = RTM_DELETE; 23397c478bd9Sstevel@tonic-gate rt_msg->rtm_seq = ++rtmseq; 23407c478bd9Sstevel@tonic-gate rlen = write(rtsock, rt_msg, rt_msg->rtm_msglen); 23417c478bd9Sstevel@tonic-gate if (rlen < 0) { 23427c478bd9Sstevel@tonic-gate if (errno != ESRCH) { 23437c478bd9Sstevel@tonic-gate logperror_pi(pi, "router_delete_k: RTM_DELETE"); 23447c478bd9Sstevel@tonic-gate } 23457c478bd9Sstevel@tonic-gate } else if (rlen < rt_msg->rtm_msglen) { 23467c478bd9Sstevel@tonic-gate logmsg(LOG_ERR, "router_delete_k: write to routing socket got " 23477c478bd9Sstevel@tonic-gate "only %d for rlen (interface %s)\n", rlen, pi->pi_name); 23487c478bd9Sstevel@tonic-gate } 23497c478bd9Sstevel@tonic-gate dr->dr_inkernel = _B_FALSE; 23507c478bd9Sstevel@tonic-gate if (!dr->dr_onlink) 23517c478bd9Sstevel@tonic-gate pi->pi_num_k_routers--; 23527c478bd9Sstevel@tonic-gate } 23537c478bd9Sstevel@tonic-gate 23547c478bd9Sstevel@tonic-gate 23557c478bd9Sstevel@tonic-gate static void 23567c478bd9Sstevel@tonic-gate router_print(struct router *dr) 23577c478bd9Sstevel@tonic-gate { 23587c478bd9Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 23597c478bd9Sstevel@tonic-gate 23607c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "Router %s on %s inkernel %d onlink %d lifetime %u\n", 23617c478bd9Sstevel@tonic-gate inet_ntop(AF_INET6, (void *)&dr->dr_address, 23627c478bd9Sstevel@tonic-gate abuf, sizeof (abuf)), 23637c478bd9Sstevel@tonic-gate dr->dr_physical->pi_name, 23647c478bd9Sstevel@tonic-gate dr->dr_inkernel, dr->dr_onlink, dr->dr_lifetime); 23657c478bd9Sstevel@tonic-gate } 23667c478bd9Sstevel@tonic-gate 23677c478bd9Sstevel@tonic-gate 23687c478bd9Sstevel@tonic-gate void 23697c478bd9Sstevel@tonic-gate phyint_print_all(void) 23707c478bd9Sstevel@tonic-gate { 23717c478bd9Sstevel@tonic-gate struct phyint *pi; 23727c478bd9Sstevel@tonic-gate 23737c478bd9Sstevel@tonic-gate for (pi = phyints; pi != NULL; pi = pi->pi_next) { 23747c478bd9Sstevel@tonic-gate phyint_print(pi); 23757c478bd9Sstevel@tonic-gate } 23767c478bd9Sstevel@tonic-gate } 23777c478bd9Sstevel@tonic-gate 23787c478bd9Sstevel@tonic-gate void 23797c478bd9Sstevel@tonic-gate phyint_cleanup(pi) 23807c478bd9Sstevel@tonic-gate struct phyint *pi; 23817c478bd9Sstevel@tonic-gate { 23827c478bd9Sstevel@tonic-gate pi->pi_state = 0; 23837c478bd9Sstevel@tonic-gate pi->pi_kernel_state = 0; 23847c478bd9Sstevel@tonic-gate 23857c478bd9Sstevel@tonic-gate if (pi->pi_AdvSendAdvertisements) { 23867c478bd9Sstevel@tonic-gate check_to_advertise(pi, ADV_OFF); 23877c478bd9Sstevel@tonic-gate } else { 23887c478bd9Sstevel@tonic-gate check_to_solicit(pi, SOLICIT_OFF); 23897c478bd9Sstevel@tonic-gate } 23907c478bd9Sstevel@tonic-gate 23917c478bd9Sstevel@tonic-gate while (pi->pi_router_list) 23927c478bd9Sstevel@tonic-gate router_delete(pi->pi_router_list); 23937c478bd9Sstevel@tonic-gate (void) poll_remove(pi->pi_sock); 23947c478bd9Sstevel@tonic-gate (void) close(pi->pi_sock); 23957c478bd9Sstevel@tonic-gate pi->pi_sock = -1; 23967c478bd9Sstevel@tonic-gate } 2397