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