17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 500834081Spwernau * Common Development and Distribution License (the "License"). 600834081Spwernau * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 22*e11c3f44Smeem * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate #include "defs.h" 277c478bd9Sstevel@tonic-gate #include "tables.h" 287c478bd9Sstevel@tonic-gate 297c478bd9Sstevel@tonic-gate #include <time.h> 303173664eSapersson #include <assert.h> 317c478bd9Sstevel@tonic-gate 327c478bd9Sstevel@tonic-gate struct phyint *phyints = NULL; 333173664eSapersson int num_of_phyints = 0; 347c478bd9Sstevel@tonic-gate 357c478bd9Sstevel@tonic-gate static void phyint_print(struct phyint *pi); 367c478bd9Sstevel@tonic-gate static void phyint_insert(struct phyint *pi); 377c478bd9Sstevel@tonic-gate 387c478bd9Sstevel@tonic-gate static boolean_t tmptoken_isvalid(struct in6_addr *token); 397c478bd9Sstevel@tonic-gate 407c478bd9Sstevel@tonic-gate static void prefix_print(struct prefix *pr); 417c478bd9Sstevel@tonic-gate static void prefix_insert(struct phyint *pi, struct prefix *pr); 427c478bd9Sstevel@tonic-gate static char *prefix_print_state(int state, char *buf, int buflen); 437c478bd9Sstevel@tonic-gate static void prefix_set(struct in6_addr *prefix, struct in6_addr addr, 447c478bd9Sstevel@tonic-gate int bits); 457c478bd9Sstevel@tonic-gate 467c478bd9Sstevel@tonic-gate static void adv_prefix_print(struct adv_prefix *adv_pr); 477c478bd9Sstevel@tonic-gate static void adv_prefix_insert(struct phyint *pi, struct adv_prefix *adv_pr); 487c478bd9Sstevel@tonic-gate static void adv_prefix_delete(struct adv_prefix *adv_pr); 497c478bd9Sstevel@tonic-gate 507c478bd9Sstevel@tonic-gate static void router_print(struct router *dr); 517c478bd9Sstevel@tonic-gate static void router_insert(struct phyint *pi, struct router *dr); 527c478bd9Sstevel@tonic-gate static void router_delete(struct router *dr); 537c478bd9Sstevel@tonic-gate static void router_add_k(struct router *dr); 547c478bd9Sstevel@tonic-gate static void router_delete_k(struct router *dr); 557c478bd9Sstevel@tonic-gate 567c478bd9Sstevel@tonic-gate static int rtmseq; /* rtm_seq sequence number */ 577c478bd9Sstevel@tonic-gate 587c478bd9Sstevel@tonic-gate /* 1 week in ms */ 597c478bd9Sstevel@tonic-gate #define NDP_PREFIX_DEFAULT_LIFETIME (7*24*60*60*1000) 607c478bd9Sstevel@tonic-gate struct phyint * 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 free(pi); 1367c478bd9Sstevel@tonic-gate return (NULL); 1377c478bd9Sstevel@tonic-gate } 1387c478bd9Sstevel@tonic-gate phyint_insert(pi); 1397c478bd9Sstevel@tonic-gate if (pi->pi_sock != -1) { 1407c478bd9Sstevel@tonic-gate if (poll_add(pi->pi_sock) == -1) { 1417c478bd9Sstevel@tonic-gate phyint_delete(pi); 1427c478bd9Sstevel@tonic-gate return (NULL); 1437c478bd9Sstevel@tonic-gate } 1447c478bd9Sstevel@tonic-gate } 1457c478bd9Sstevel@tonic-gate return (pi); 1467c478bd9Sstevel@tonic-gate } 1477c478bd9Sstevel@tonic-gate 1487c478bd9Sstevel@tonic-gate /* Insert in linked list */ 1497c478bd9Sstevel@tonic-gate static void 1507c478bd9Sstevel@tonic-gate phyint_insert(struct phyint *pi) 1517c478bd9Sstevel@tonic-gate { 1527c478bd9Sstevel@tonic-gate /* Insert in list */ 1537c478bd9Sstevel@tonic-gate pi->pi_next = phyints; 1547c478bd9Sstevel@tonic-gate pi->pi_prev = NULL; 1557c478bd9Sstevel@tonic-gate if (phyints) 1567c478bd9Sstevel@tonic-gate phyints->pi_prev = pi; 1577c478bd9Sstevel@tonic-gate phyints = pi; 1583173664eSapersson num_of_phyints++; 1597c478bd9Sstevel@tonic-gate } 1607c478bd9Sstevel@tonic-gate 1617c478bd9Sstevel@tonic-gate /* 1627c478bd9Sstevel@tonic-gate * Initialize both the phyint data structure and the pi_sock for 1637c478bd9Sstevel@tonic-gate * sending and receving on the interface. 1647c478bd9Sstevel@tonic-gate * Extract information from the kernel (if present) and set pi_kernel_state. 1657c478bd9Sstevel@tonic-gate */ 1667c478bd9Sstevel@tonic-gate int 1677c478bd9Sstevel@tonic-gate phyint_init_from_k(struct phyint *pi) 1687c478bd9Sstevel@tonic-gate { 1697c478bd9Sstevel@tonic-gate struct ipv6_mreq v6mcastr; 1707c478bd9Sstevel@tonic-gate struct lifreq lifr; 1717c478bd9Sstevel@tonic-gate int fd; 172*e11c3f44Smeem int save_errno; 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 /* 23269bb4bb4Scarlsonj * If the link local interface is not up yet or it's IFF_UP and the 23369bb4bb4Scarlsonj * 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): " 24269bb4bb4Scarlsonj "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 if (ioctl(fd, SIOCGLIFMTU, (caddr_t)&lifr) < 0) { 2497c478bd9Sstevel@tonic-gate logperror_pi(pi, "phyint_init_from_k: ioctl (get mtu)"); 2507c478bd9Sstevel@tonic-gate goto error; 2517c478bd9Sstevel@tonic-gate } 2527c478bd9Sstevel@tonic-gate pi->pi_mtu = lifr.lifr_mtu; 2537c478bd9Sstevel@tonic-gate 2547c478bd9Sstevel@tonic-gate if (ioctl(fd, SIOCGLIFADDR, (char *)&lifr) < 0) { 2557c478bd9Sstevel@tonic-gate logperror_pi(pi, "phyint_init_from_k: SIOCGLIFADDR"); 2567c478bd9Sstevel@tonic-gate goto error; 2577c478bd9Sstevel@tonic-gate } 2587c478bd9Sstevel@tonic-gate sin6 = (struct sockaddr_in6 *)&lifr.lifr_addr; 2597c478bd9Sstevel@tonic-gate pi->pi_ifaddr = sin6->sin6_addr; 2607c478bd9Sstevel@tonic-gate 2617c478bd9Sstevel@tonic-gate if (ioctl(fd, SIOCGLIFTOKEN, (char *)&lifr) < 0) { 2627c478bd9Sstevel@tonic-gate logperror_pi(pi, "phyint_init_from_k: SIOCGLIFTOKEN"); 2637c478bd9Sstevel@tonic-gate goto error; 2647c478bd9Sstevel@tonic-gate } 2657c478bd9Sstevel@tonic-gate /* Ignore interface if the token is all zeros */ 2667c478bd9Sstevel@tonic-gate sin6 = (struct sockaddr_in6 *)&lifr.lifr_token; 2677c478bd9Sstevel@tonic-gate if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { 2687c478bd9Sstevel@tonic-gate logmsg(LOG_ERR, "ignoring interface %s: zero token\n", 2697c478bd9Sstevel@tonic-gate pi->pi_name); 2707c478bd9Sstevel@tonic-gate goto error; 2717c478bd9Sstevel@tonic-gate } 2727c478bd9Sstevel@tonic-gate pi->pi_token = sin6->sin6_addr; 2737c478bd9Sstevel@tonic-gate pi->pi_token_length = lifr.lifr_addrlen; 2747c478bd9Sstevel@tonic-gate 2757c478bd9Sstevel@tonic-gate /* 2767c478bd9Sstevel@tonic-gate * Guess a remote token for POINTOPOINT by looking at 2777c478bd9Sstevel@tonic-gate * the link-local destination address. 2787c478bd9Sstevel@tonic-gate */ 2797c478bd9Sstevel@tonic-gate if (pi->pi_flags & IFF_POINTOPOINT) { 2807c478bd9Sstevel@tonic-gate if (ioctl(fd, SIOCGLIFDSTADDR, (char *)&lifr) < 0) { 2817c478bd9Sstevel@tonic-gate logperror_pi(pi, "phyint_init_from_k: SIOCGLIFDSTADDR"); 2827c478bd9Sstevel@tonic-gate goto error; 2837c478bd9Sstevel@tonic-gate } 2847c478bd9Sstevel@tonic-gate sin6 = (struct sockaddr_in6 *)&lifr.lifr_addr; 2857c478bd9Sstevel@tonic-gate if (sin6->sin6_family != AF_INET6 || 2867c478bd9Sstevel@tonic-gate IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) || 2877c478bd9Sstevel@tonic-gate !IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) { 2887c478bd9Sstevel@tonic-gate pi->pi_dst_token = in6addr_any; 2897c478bd9Sstevel@tonic-gate } else { 2907c478bd9Sstevel@tonic-gate pi->pi_dst_token = sin6->sin6_addr; 2917c478bd9Sstevel@tonic-gate /* Clear link-local prefix (first 10 bits) */ 2927c478bd9Sstevel@tonic-gate pi->pi_dst_token.s6_addr[0] = 0; 2937c478bd9Sstevel@tonic-gate pi->pi_dst_token.s6_addr[1] &= 0x3f; 2947c478bd9Sstevel@tonic-gate } 2957c478bd9Sstevel@tonic-gate } else { 2967c478bd9Sstevel@tonic-gate pi->pi_dst_token = in6addr_any; 2977c478bd9Sstevel@tonic-gate } 2987c478bd9Sstevel@tonic-gate 2997c478bd9Sstevel@tonic-gate if (newsock) { 3007c478bd9Sstevel@tonic-gate icmp6_filter_t filter; 3017c478bd9Sstevel@tonic-gate int on = 1; 3027c478bd9Sstevel@tonic-gate 3037c478bd9Sstevel@tonic-gate /* Set default values */ 3047c478bd9Sstevel@tonic-gate pi->pi_LinkMTU = pi->pi_mtu; 3057c478bd9Sstevel@tonic-gate pi->pi_CurHopLimit = 0; 3067c478bd9Sstevel@tonic-gate pi->pi_BaseReachableTime = ND_REACHABLE_TIME; 3077c478bd9Sstevel@tonic-gate phyint_reach_random(pi, _B_FALSE); 3087c478bd9Sstevel@tonic-gate pi->pi_RetransTimer = ND_RETRANS_TIMER; 3097c478bd9Sstevel@tonic-gate 3107c478bd9Sstevel@tonic-gate /* Setup socket for transmission and reception */ 3117c478bd9Sstevel@tonic-gate if (setsockopt(fd, IPPROTO_IPV6, 3127c478bd9Sstevel@tonic-gate IPV6_BOUND_IF, (char *)&pi->pi_index, 3137c478bd9Sstevel@tonic-gate sizeof (pi->pi_index)) < 0) { 3147c478bd9Sstevel@tonic-gate logperror_pi(pi, "phyint_init_from_k: setsockopt " 3157c478bd9Sstevel@tonic-gate "IPV6_BOUND_IF"); 3167c478bd9Sstevel@tonic-gate goto error; 3177c478bd9Sstevel@tonic-gate } 3187c478bd9Sstevel@tonic-gate 3197c478bd9Sstevel@tonic-gate ttl = IPV6_MAX_HOPS; 3207c478bd9Sstevel@tonic-gate if (setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, 3217c478bd9Sstevel@tonic-gate (char *)&ttl, sizeof (ttl)) < 0) { 3227c478bd9Sstevel@tonic-gate logperror_pi(pi, "phyint_init_from_k: setsockopt " 3237c478bd9Sstevel@tonic-gate "IPV6_UNICAST_HOPS"); 3247c478bd9Sstevel@tonic-gate goto error; 3257c478bd9Sstevel@tonic-gate } 3267c478bd9Sstevel@tonic-gate 3277c478bd9Sstevel@tonic-gate if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, 3287c478bd9Sstevel@tonic-gate (char *)&ttl, sizeof (ttl)) < 0) { 3297c478bd9Sstevel@tonic-gate logperror_pi(pi, "phyint_init_from_k: setsockopt " 3307c478bd9Sstevel@tonic-gate "IPV6_MULTICAST_HOPS"); 3317c478bd9Sstevel@tonic-gate goto error; 3327c478bd9Sstevel@tonic-gate } 3337c478bd9Sstevel@tonic-gate 3347c478bd9Sstevel@tonic-gate v6mcastr.ipv6mr_multiaddr = all_nodes_mcast; 3357c478bd9Sstevel@tonic-gate v6mcastr.ipv6mr_interface = pi->pi_index; 3367c478bd9Sstevel@tonic-gate if (setsockopt(fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, 3377c478bd9Sstevel@tonic-gate (char *)&v6mcastr, sizeof (v6mcastr)) < 0) { 338*e11c3f44Smeem /* 339*e11c3f44Smeem * One benign reason IPV6_JOIN_GROUP could fail is 340*e11c3f44Smeem * when `pi' has been placed into an IPMP group and we 341*e11c3f44Smeem * haven't yet processed the routing socket message 342*e11c3f44Smeem * informing us of its disappearance. As such, if 343*e11c3f44Smeem * it's now in a group, don't print an error. 344*e11c3f44Smeem */ 345*e11c3f44Smeem save_errno = errno; 346*e11c3f44Smeem (void) strlcpy(lifr.lifr_name, pi->pi_name, LIFNAMSIZ); 347*e11c3f44Smeem if (ioctl(fd, SIOCGLIFGROUPNAME, &lifr) == -1 || 348*e11c3f44Smeem lifr.lifr_groupname[0] == '\0') { 349*e11c3f44Smeem errno = save_errno; 350*e11c3f44Smeem logperror_pi(pi, "phyint_init_from_k: " 351*e11c3f44Smeem "setsockopt IPV6_JOIN_GROUP"); 352*e11c3f44Smeem } 3537c478bd9Sstevel@tonic-gate goto error; 3547c478bd9Sstevel@tonic-gate } 3557c478bd9Sstevel@tonic-gate pi->pi_state |= PI_JOINED_ALLNODES; 3567c478bd9Sstevel@tonic-gate pi->pi_kernel_state |= PI_JOINED_ALLNODES; 3577c478bd9Sstevel@tonic-gate 3587c478bd9Sstevel@tonic-gate /* 3597c478bd9Sstevel@tonic-gate * Filter out so that we only receive router advertisements and 3607c478bd9Sstevel@tonic-gate * router solicitations. 3617c478bd9Sstevel@tonic-gate */ 3627c478bd9Sstevel@tonic-gate ICMP6_FILTER_SETBLOCKALL(&filter); 3637c478bd9Sstevel@tonic-gate ICMP6_FILTER_SETPASS(ND_ROUTER_SOLICIT, &filter); 3647c478bd9Sstevel@tonic-gate ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT, &filter); 3657c478bd9Sstevel@tonic-gate 3667c478bd9Sstevel@tonic-gate if (setsockopt(fd, IPPROTO_ICMPV6, ICMP6_FILTER, 3677c478bd9Sstevel@tonic-gate (char *)&filter, sizeof (filter)) < 0) { 3687c478bd9Sstevel@tonic-gate logperror_pi(pi, "phyint_init_from_k: setsockopt " 3697c478bd9Sstevel@tonic-gate "ICMP6_FILTER"); 3707c478bd9Sstevel@tonic-gate goto error; 3717c478bd9Sstevel@tonic-gate } 3727c478bd9Sstevel@tonic-gate 3737c478bd9Sstevel@tonic-gate /* Enable receipt of ancillary data */ 3747c478bd9Sstevel@tonic-gate if (setsockopt(fd, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, 3757c478bd9Sstevel@tonic-gate (char *)&on, sizeof (on)) < 0) { 3767c478bd9Sstevel@tonic-gate logperror_pi(pi, "phyint_init_from_k: setsockopt " 3777c478bd9Sstevel@tonic-gate "IPV6_RECVHOPLIMIT"); 3787c478bd9Sstevel@tonic-gate goto error; 3797c478bd9Sstevel@tonic-gate } 3807c478bd9Sstevel@tonic-gate if (setsockopt(fd, IPPROTO_IPV6, IPV6_RECVRTHDR, 3817c478bd9Sstevel@tonic-gate (char *)&on, sizeof (on)) < 0) { 3827c478bd9Sstevel@tonic-gate logperror_pi(pi, "phyint_init_from_k: setsockopt " 3837c478bd9Sstevel@tonic-gate "IPV6_RECVRTHDR"); 3847c478bd9Sstevel@tonic-gate goto error; 3857c478bd9Sstevel@tonic-gate } 3867c478bd9Sstevel@tonic-gate } 3877c478bd9Sstevel@tonic-gate 3887c478bd9Sstevel@tonic-gate if (pi->pi_AdvSendAdvertisements && 3897c478bd9Sstevel@tonic-gate !(pi->pi_kernel_state & PI_JOINED_ALLROUTERS)) { 3907c478bd9Sstevel@tonic-gate v6mcastr.ipv6mr_multiaddr = all_routers_mcast; 3917c478bd9Sstevel@tonic-gate v6mcastr.ipv6mr_interface = pi->pi_index; 3927c478bd9Sstevel@tonic-gate if (setsockopt(fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, 3937c478bd9Sstevel@tonic-gate (char *)&v6mcastr, sizeof (v6mcastr)) < 0) { 394*e11c3f44Smeem /* 395*e11c3f44Smeem * See IPV6_JOIN_GROUP comment above. 396*e11c3f44Smeem */ 397*e11c3f44Smeem save_errno = errno; 398*e11c3f44Smeem (void) strlcpy(lifr.lifr_name, pi->pi_name, LIFNAMSIZ); 399*e11c3f44Smeem if (ioctl(fd, SIOCGLIFGROUPNAME, &lifr) == -1 || 400*e11c3f44Smeem lifr.lifr_groupname[0] == '\0') { 401*e11c3f44Smeem errno = save_errno; 402*e11c3f44Smeem logperror_pi(pi, "phyint_init_from_k: " 403*e11c3f44Smeem "setsockopt IPV6_JOIN_GROUP"); 404*e11c3f44Smeem } 4057c478bd9Sstevel@tonic-gate goto error; 4067c478bd9Sstevel@tonic-gate } 4077c478bd9Sstevel@tonic-gate pi->pi_state |= PI_JOINED_ALLROUTERS; 4087c478bd9Sstevel@tonic-gate pi->pi_kernel_state |= PI_JOINED_ALLROUTERS; 4097c478bd9Sstevel@tonic-gate } 4107c478bd9Sstevel@tonic-gate /* 4117c478bd9Sstevel@tonic-gate * If not already set, set the IFF_ROUTER interface flag based on 4127c478bd9Sstevel@tonic-gate * AdvSendAdvertisements. Note that this will also enable IPv6 4137c478bd9Sstevel@tonic-gate * forwarding on the interface. We don't clear IFF_ROUTER if we're 4147c478bd9Sstevel@tonic-gate * not advertising on an interface, because we could still be 4157c478bd9Sstevel@tonic-gate * forwarding on those interfaces. 4167c478bd9Sstevel@tonic-gate */ 4177c478bd9Sstevel@tonic-gate (void) strncpy(lifr.lifr_name, pi->pi_name, sizeof (lifr.lifr_name)); 4187c478bd9Sstevel@tonic-gate lifr.lifr_name[sizeof (lifr.lifr_name) - 1] = '\0'; 4197c478bd9Sstevel@tonic-gate if (ioctl(fd, SIOCGLIFFLAGS, (char *)&lifr) < 0) { 4207c478bd9Sstevel@tonic-gate logperror_pi(pi, "phyint_init_from_k: SIOCGLIFFLAGS"); 4217c478bd9Sstevel@tonic-gate goto error; 4227c478bd9Sstevel@tonic-gate } 4237c478bd9Sstevel@tonic-gate if (!(lifr.lifr_flags & IFF_ROUTER) && pi->pi_AdvSendAdvertisements) { 4247c478bd9Sstevel@tonic-gate lifr.lifr_flags |= IFF_ROUTER; 4257c478bd9Sstevel@tonic-gate 4267c478bd9Sstevel@tonic-gate if (ioctl(fd, SIOCSLIFFLAGS, (char *)&lifr) < 0) { 4277c478bd9Sstevel@tonic-gate logperror_pi(pi, "phyint_init_from_k: SIOCSLIFFLAGS"); 4287c478bd9Sstevel@tonic-gate goto error; 4297c478bd9Sstevel@tonic-gate } 4307c478bd9Sstevel@tonic-gate pi->pi_flags = lifr.lifr_flags; 4317c478bd9Sstevel@tonic-gate } 4327c478bd9Sstevel@tonic-gate 4337c478bd9Sstevel@tonic-gate /* Set linkinfo parameters */ 4347c478bd9Sstevel@tonic-gate (void) strncpy(lifr.lifr_name, pi->pi_name, sizeof (lifr.lifr_name)); 4357c478bd9Sstevel@tonic-gate lifr.lifr_name[sizeof (lifr.lifr_name) - 1] = '\0'; 4367c478bd9Sstevel@tonic-gate lifr.lifr_ifinfo.lir_maxhops = pi->pi_CurHopLimit; 4377c478bd9Sstevel@tonic-gate lifr.lifr_ifinfo.lir_reachtime = pi->pi_ReachableTime; 4387c478bd9Sstevel@tonic-gate lifr.lifr_ifinfo.lir_reachretrans = pi->pi_RetransTimer; 43900834081Spwernau /* Setting maxmtu to 0 means that we're leaving the MTU alone */ 44000834081Spwernau lifr.lifr_ifinfo.lir_maxmtu = 0; 4417c478bd9Sstevel@tonic-gate if (ioctl(fd, SIOCSLIFLNKINFO, (char *)&lifr) < 0) { 4427c478bd9Sstevel@tonic-gate logperror_pi(pi, "phyint_init_from_k: SIOCSLIFLNKINFO"); 4437c478bd9Sstevel@tonic-gate goto error; 4447c478bd9Sstevel@tonic-gate } 4457c478bd9Sstevel@tonic-gate if (debug & D_PHYINT) { 4467c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "phyint_init_from_k(%s): done\n", 4477c478bd9Sstevel@tonic-gate pi->pi_name); 4487c478bd9Sstevel@tonic-gate } 4497c478bd9Sstevel@tonic-gate return (0); 4507c478bd9Sstevel@tonic-gate 4517c478bd9Sstevel@tonic-gate error: 4527c478bd9Sstevel@tonic-gate /* Pretend the interface does not exist in the kernel */ 4537c478bd9Sstevel@tonic-gate pi->pi_kernel_state &= ~PI_PRESENT; 4547c478bd9Sstevel@tonic-gate if (newsock) { 4557c478bd9Sstevel@tonic-gate (void) close(pi->pi_sock); 4567c478bd9Sstevel@tonic-gate pi->pi_sock = -1; 4577c478bd9Sstevel@tonic-gate } 4587c478bd9Sstevel@tonic-gate return (-1); 4597c478bd9Sstevel@tonic-gate } 4607c478bd9Sstevel@tonic-gate 4617c478bd9Sstevel@tonic-gate /* 4627c478bd9Sstevel@tonic-gate * Delete (unlink and free). 4637c478bd9Sstevel@tonic-gate * Handles delete of things that have not yet been inserted in the list. 4647c478bd9Sstevel@tonic-gate */ 4657c478bd9Sstevel@tonic-gate void 4667c478bd9Sstevel@tonic-gate phyint_delete(struct phyint *pi) 4677c478bd9Sstevel@tonic-gate { 4687c478bd9Sstevel@tonic-gate if (debug & D_PHYINT) 4697c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "phyint_delete(%s)\n", pi->pi_name); 4707c478bd9Sstevel@tonic-gate 4713173664eSapersson assert(num_of_phyints > 0); 4723173664eSapersson 4737c478bd9Sstevel@tonic-gate while (pi->pi_router_list) 4747c478bd9Sstevel@tonic-gate router_delete(pi->pi_router_list); 4757c478bd9Sstevel@tonic-gate while (pi->pi_prefix_list) 4767c478bd9Sstevel@tonic-gate prefix_delete(pi->pi_prefix_list); 4777c478bd9Sstevel@tonic-gate while (pi->pi_adv_prefix_list) 4787c478bd9Sstevel@tonic-gate adv_prefix_delete(pi->pi_adv_prefix_list); 4797c478bd9Sstevel@tonic-gate 4807c478bd9Sstevel@tonic-gate if (pi->pi_sock != -1) { 4817c478bd9Sstevel@tonic-gate (void) poll_remove(pi->pi_sock); 4827c478bd9Sstevel@tonic-gate if (close(pi->pi_sock) < 0) { 4837c478bd9Sstevel@tonic-gate logperror_pi(pi, "phyint_delete: close"); 4847c478bd9Sstevel@tonic-gate } 4857c478bd9Sstevel@tonic-gate pi->pi_sock = -1; 4867c478bd9Sstevel@tonic-gate } 4877c478bd9Sstevel@tonic-gate 4887c478bd9Sstevel@tonic-gate if (pi->pi_prev == NULL) { 4897c478bd9Sstevel@tonic-gate if (phyints == pi) 4907c478bd9Sstevel@tonic-gate phyints = pi->pi_next; 4917c478bd9Sstevel@tonic-gate } else { 4927c478bd9Sstevel@tonic-gate pi->pi_prev->pi_next = pi->pi_next; 4937c478bd9Sstevel@tonic-gate } 4947c478bd9Sstevel@tonic-gate if (pi->pi_next != NULL) 4957c478bd9Sstevel@tonic-gate pi->pi_next->pi_prev = pi->pi_prev; 4967c478bd9Sstevel@tonic-gate pi->pi_next = pi->pi_prev = NULL; 4977c478bd9Sstevel@tonic-gate free(pi); 4983173664eSapersson num_of_phyints--; 4997c478bd9Sstevel@tonic-gate } 5007c478bd9Sstevel@tonic-gate 5017c478bd9Sstevel@tonic-gate /* 502b12d9c4eSmeem * Called with the number of milliseconds elapsed since the last call. 5037c478bd9Sstevel@tonic-gate * Determines if any timeout event has occurred and 5047c478bd9Sstevel@tonic-gate * returns the number of milliseconds until the next timeout event 505b12d9c4eSmeem * for the phyint itself (excluding prefixes and routers). 5067c478bd9Sstevel@tonic-gate * Returns TIMER_INFINITY for "never". 5077c478bd9Sstevel@tonic-gate */ 5087c478bd9Sstevel@tonic-gate uint_t 5097c478bd9Sstevel@tonic-gate phyint_timer(struct phyint *pi, uint_t elapsed) 5107c478bd9Sstevel@tonic-gate { 5117c478bd9Sstevel@tonic-gate uint_t next = TIMER_INFINITY; 5127c478bd9Sstevel@tonic-gate 5137c478bd9Sstevel@tonic-gate if (pi->pi_AdvSendAdvertisements) { 5147c478bd9Sstevel@tonic-gate if (pi->pi_adv_state != NO_ADV) { 5157c478bd9Sstevel@tonic-gate int old_state = pi->pi_adv_state; 5167c478bd9Sstevel@tonic-gate 5177c478bd9Sstevel@tonic-gate if (debug & (D_STATE|D_PHYINT)) { 5187c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "phyint_timer ADV(%s) " 5197c478bd9Sstevel@tonic-gate "state %d\n", pi->pi_name, (int)old_state); 5207c478bd9Sstevel@tonic-gate } 5217c478bd9Sstevel@tonic-gate next = advertise_event(pi, ADV_TIMER, elapsed); 5227c478bd9Sstevel@tonic-gate if (debug & D_STATE) { 5237c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "phyint_timer ADV(%s) " 5247c478bd9Sstevel@tonic-gate "state %d -> %d\n", 5257c478bd9Sstevel@tonic-gate pi->pi_name, (int)old_state, 5267c478bd9Sstevel@tonic-gate (int)pi->pi_adv_state); 5277c478bd9Sstevel@tonic-gate } 5287c478bd9Sstevel@tonic-gate } 5297c478bd9Sstevel@tonic-gate } else { 5307c478bd9Sstevel@tonic-gate if (pi->pi_sol_state != NO_SOLICIT) { 5317c478bd9Sstevel@tonic-gate int old_state = pi->pi_sol_state; 5327c478bd9Sstevel@tonic-gate 5337c478bd9Sstevel@tonic-gate if (debug & (D_STATE|D_PHYINT)) { 5347c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "phyint_timer SOL(%s) " 5357c478bd9Sstevel@tonic-gate "state %d\n", pi->pi_name, (int)old_state); 5367c478bd9Sstevel@tonic-gate } 5377c478bd9Sstevel@tonic-gate next = solicit_event(pi, SOL_TIMER, elapsed); 5387c478bd9Sstevel@tonic-gate if (debug & D_STATE) { 5397c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "phyint_timer SOL(%s) " 5407c478bd9Sstevel@tonic-gate "state %d -> %d\n", 5417c478bd9Sstevel@tonic-gate pi->pi_name, (int)old_state, 5427c478bd9Sstevel@tonic-gate (int)pi->pi_sol_state); 5437c478bd9Sstevel@tonic-gate } 5447c478bd9Sstevel@tonic-gate } 5457c478bd9Sstevel@tonic-gate } 5467c478bd9Sstevel@tonic-gate 5477c478bd9Sstevel@tonic-gate /* 5487c478bd9Sstevel@tonic-gate * If the phyint has been unplumbed, we don't want to call 5497c478bd9Sstevel@tonic-gate * phyint_reach_random. We will be in the NO_ADV or NO_SOLICIT state. 5507c478bd9Sstevel@tonic-gate */ 5517c478bd9Sstevel@tonic-gate if ((pi->pi_AdvSendAdvertisements && (pi->pi_adv_state != NO_ADV)) || 5527c478bd9Sstevel@tonic-gate (!pi->pi_AdvSendAdvertisements && 5537c478bd9Sstevel@tonic-gate (pi->pi_sol_state != NO_SOLICIT))) { 5547c478bd9Sstevel@tonic-gate pi->pi_reach_time_since_random += elapsed; 5557c478bd9Sstevel@tonic-gate if (pi->pi_reach_time_since_random >= MAX_REACH_RANDOM_INTERVAL) 5567c478bd9Sstevel@tonic-gate phyint_reach_random(pi, _B_TRUE); 5577c478bd9Sstevel@tonic-gate } 5587c478bd9Sstevel@tonic-gate 5597c478bd9Sstevel@tonic-gate return (next); 5607c478bd9Sstevel@tonic-gate } 5617c478bd9Sstevel@tonic-gate 5627c478bd9Sstevel@tonic-gate static void 5637c478bd9Sstevel@tonic-gate phyint_print(struct phyint *pi) 5647c478bd9Sstevel@tonic-gate { 5657c478bd9Sstevel@tonic-gate struct prefix *pr; 5667c478bd9Sstevel@tonic-gate struct adv_prefix *adv_pr; 5677c478bd9Sstevel@tonic-gate struct router *dr; 5687c478bd9Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 5697c478bd9Sstevel@tonic-gate 5707c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "Phyint %s index %d state %x, kernel %x, " 5718121d73fSseb "num routers %d\n", 5728121d73fSseb pi->pi_name, pi->pi_index, pi->pi_state, pi->pi_kernel_state, 5737c478bd9Sstevel@tonic-gate pi->pi_num_k_routers); 574*e11c3f44Smeem logmsg(LOG_DEBUG, "\taddress: %s flags %llx\n", 5757c478bd9Sstevel@tonic-gate inet_ntop(AF_INET6, (void *)&pi->pi_ifaddr, 5767c478bd9Sstevel@tonic-gate abuf, sizeof (abuf)), pi->pi_flags); 577*e11c3f44Smeem logmsg(LOG_DEBUG, "\tsock %d mtu %d\n", pi->pi_sock, pi->pi_mtu); 578*e11c3f44Smeem logmsg(LOG_DEBUG, "\ttoken: len %d %s\n", pi->pi_token_length, 5797c478bd9Sstevel@tonic-gate inet_ntop(AF_INET6, (void *)&pi->pi_token, 5807c478bd9Sstevel@tonic-gate abuf, sizeof (abuf))); 5817c478bd9Sstevel@tonic-gate if (pi->pi_TmpAddrsEnabled) { 5827c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "\ttmp_token: %s\n", 5837c478bd9Sstevel@tonic-gate inet_ntop(AF_INET6, (void *)&pi->pi_tmp_token, 584b12d9c4eSmeem abuf, sizeof (abuf))); 5857c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "\ttmp config: pref %d valid %d " 5867c478bd9Sstevel@tonic-gate "maxdesync %d desync %d regen %d\n", 5877c478bd9Sstevel@tonic-gate pi->pi_TmpPreferredLifetime, pi->pi_TmpValidLifetime, 5887c478bd9Sstevel@tonic-gate pi->pi_TmpMaxDesyncFactor, pi->pi_TmpDesyncFactor, 5897c478bd9Sstevel@tonic-gate pi->pi_TmpRegenAdvance); 5907c478bd9Sstevel@tonic-gate } 5917c478bd9Sstevel@tonic-gate if (pi->pi_flags & IFF_POINTOPOINT) { 5927c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "\tdst_token: %s\n", 5937c478bd9Sstevel@tonic-gate inet_ntop(AF_INET6, (void *)&pi->pi_dst_token, 594b12d9c4eSmeem abuf, sizeof (abuf))); 5957c478bd9Sstevel@tonic-gate } 5967c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "\tLinkMTU %d CurHopLimit %d " 5977c478bd9Sstevel@tonic-gate "BaseReachableTime %d\n\tReachableTime %d RetransTimer %d\n", 5987c478bd9Sstevel@tonic-gate pi->pi_LinkMTU, pi->pi_CurHopLimit, pi->pi_BaseReachableTime, 5997c478bd9Sstevel@tonic-gate pi->pi_ReachableTime, pi->pi_RetransTimer); 6007c478bd9Sstevel@tonic-gate if (!pi->pi_AdvSendAdvertisements) { 6017c478bd9Sstevel@tonic-gate /* Solicit state */ 6027c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "\tSOLICIT: time_left %d state %d count %d\n", 6037c478bd9Sstevel@tonic-gate pi->pi_sol_time_left, pi->pi_sol_state, pi->pi_sol_count); 6047c478bd9Sstevel@tonic-gate } else { 6057c478bd9Sstevel@tonic-gate /* Advertise state */ 6067c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "\tADVERT: time_left %d state %d count %d " 6077c478bd9Sstevel@tonic-gate "since last %d\n", 6087c478bd9Sstevel@tonic-gate pi->pi_adv_time_left, pi->pi_adv_state, pi->pi_adv_count, 6097c478bd9Sstevel@tonic-gate pi->pi_adv_time_since_sent); 6107c478bd9Sstevel@tonic-gate print_iflist(pi->pi_config); 6117c478bd9Sstevel@tonic-gate } 6127c478bd9Sstevel@tonic-gate for (pr = pi->pi_prefix_list; pr != NULL; pr = pr->pr_next) 6137c478bd9Sstevel@tonic-gate prefix_print(pr); 6147c478bd9Sstevel@tonic-gate 6157c478bd9Sstevel@tonic-gate for (adv_pr = pi->pi_adv_prefix_list; adv_pr != NULL; 6167c478bd9Sstevel@tonic-gate adv_pr = adv_pr->adv_pr_next) { 6177c478bd9Sstevel@tonic-gate adv_prefix_print(adv_pr); 6187c478bd9Sstevel@tonic-gate } 6197c478bd9Sstevel@tonic-gate 6207c478bd9Sstevel@tonic-gate for (dr = pi->pi_router_list; dr != NULL; dr = dr->dr_next) 6217c478bd9Sstevel@tonic-gate router_print(dr); 6227c478bd9Sstevel@tonic-gate 6237c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "\n"); 6247c478bd9Sstevel@tonic-gate } 6257c478bd9Sstevel@tonic-gate 626*e11c3f44Smeem 627*e11c3f44Smeem /* 628*e11c3f44Smeem * Store the LLA for the phyint `pi' `lifrp'. Returns 0 on success, or 629*e11c3f44Smeem * -1 on failure. 630*e11c3f44Smeem * 631*e11c3f44Smeem * Note that we do not cache the hardware address since there's no reliable 632*e11c3f44Smeem * mechanism to determine when it's become stale. 633*e11c3f44Smeem */ 634*e11c3f44Smeem int 635*e11c3f44Smeem phyint_get_lla(struct phyint *pi, struct lifreq *lifrp) 636*e11c3f44Smeem { 637*e11c3f44Smeem struct sockaddr_in6 *sin6; 638*e11c3f44Smeem 639*e11c3f44Smeem /* If this phyint doesn't have a link-layer address, bail */ 640*e11c3f44Smeem if (!(pi->pi_flags & IFF_MULTICAST) || 641*e11c3f44Smeem (pi->pi_flags & IFF_POINTOPOINT)) { 642*e11c3f44Smeem return (-1); 643*e11c3f44Smeem } 644*e11c3f44Smeem 645*e11c3f44Smeem (void) strlcpy(lifrp->lifr_name, pi->pi_name, LIFNAMSIZ); 646*e11c3f44Smeem sin6 = (struct sockaddr_in6 *)&(lifrp->lifr_nd.lnr_addr); 647*e11c3f44Smeem sin6->sin6_family = AF_INET6; 648*e11c3f44Smeem sin6->sin6_addr = pi->pi_ifaddr; 649*e11c3f44Smeem if (ioctl(pi->pi_sock, SIOCLIFGETND, lifrp) < 0) { 650*e11c3f44Smeem /* 651*e11c3f44Smeem * For IPMP interfaces, don't report ESRCH errors since that 652*e11c3f44Smeem * merely indicates that there are no active interfaces in the 653*e11c3f44Smeem * IPMP group (and thus there's no working hardware address), 654*e11c3f44Smeem * and the packet will thus never make it out anyway. 655*e11c3f44Smeem */ 656*e11c3f44Smeem if (!(pi->pi_flags & IFF_IPMP) || errno != ESRCH) 657*e11c3f44Smeem logperror_pi(pi, "phyint_get_lla: SIOCLIFGETND"); 658*e11c3f44Smeem return (-1); 659*e11c3f44Smeem } 660*e11c3f44Smeem return (0); 661*e11c3f44Smeem } 662*e11c3f44Smeem 6637c478bd9Sstevel@tonic-gate /* 6647c478bd9Sstevel@tonic-gate * Randomize pi->pi_ReachableTime. 6657c478bd9Sstevel@tonic-gate * Done periodically when there are no RAs and at a maximum frequency when 6667c478bd9Sstevel@tonic-gate * RA's arrive. 6677c478bd9Sstevel@tonic-gate * Assumes that caller has determined that it is time to generate 6687c478bd9Sstevel@tonic-gate * a new random ReachableTime. 6697c478bd9Sstevel@tonic-gate */ 6707c478bd9Sstevel@tonic-gate void 6717c478bd9Sstevel@tonic-gate phyint_reach_random(struct phyint *pi, boolean_t set_needed) 6727c478bd9Sstevel@tonic-gate { 673*e11c3f44Smeem struct lifreq lifr; 674*e11c3f44Smeem 6757c478bd9Sstevel@tonic-gate pi->pi_ReachableTime = GET_RANDOM( 6767c478bd9Sstevel@tonic-gate (int)(ND_MIN_RANDOM_FACTOR * pi->pi_BaseReachableTime), 6777c478bd9Sstevel@tonic-gate (int)(ND_MAX_RANDOM_FACTOR * pi->pi_BaseReachableTime)); 6787c478bd9Sstevel@tonic-gate if (set_needed) { 679*e11c3f44Smeem bzero(&lifr, sizeof (lifr)); 680*e11c3f44Smeem (void) strlcpy(lifr.lifr_name, pi->pi_name, LIFNAMSIZ); 6817c478bd9Sstevel@tonic-gate lifr.lifr_ifinfo.lir_reachtime = pi->pi_ReachableTime; 6827c478bd9Sstevel@tonic-gate if (ioctl(pi->pi_sock, SIOCSLIFLNKINFO, (char *)&lifr) < 0) { 6837c478bd9Sstevel@tonic-gate logperror_pi(pi, 6847c478bd9Sstevel@tonic-gate "phyint_reach_random: SIOCSLIFLNKINFO"); 6857c478bd9Sstevel@tonic-gate return; 6867c478bd9Sstevel@tonic-gate } 6877c478bd9Sstevel@tonic-gate } 6887c478bd9Sstevel@tonic-gate pi->pi_reach_time_since_random = 0; 6897c478bd9Sstevel@tonic-gate } 6907c478bd9Sstevel@tonic-gate 6917c478bd9Sstevel@tonic-gate /* 6927c478bd9Sstevel@tonic-gate * Validate a temporary token against a list of known bad values. 6937c478bd9Sstevel@tonic-gate * Currently assumes that token is 8 bytes long! Current known 6947c478bd9Sstevel@tonic-gate * bad values include 0, reserved anycast tokens (RFC 2526), tokens 6957c478bd9Sstevel@tonic-gate * used by ISATAP (draft-ietf-ngtrans-isatap-N), any token already 6967c478bd9Sstevel@tonic-gate * assigned to this interface, or any token for which the global 6977c478bd9Sstevel@tonic-gate * bit is set. 6987c478bd9Sstevel@tonic-gate * 6997c478bd9Sstevel@tonic-gate * Called by tmptoken_create(). 7007c478bd9Sstevel@tonic-gate * 7017c478bd9Sstevel@tonic-gate * Return _B_TRUE if token is valid (no match), _B_FALSE if not. 7027c478bd9Sstevel@tonic-gate */ 7037c478bd9Sstevel@tonic-gate static boolean_t 7047c478bd9Sstevel@tonic-gate tmptoken_isvalid(struct in6_addr *token) 7057c478bd9Sstevel@tonic-gate { 7067c478bd9Sstevel@tonic-gate struct phyint *pi; 7077c478bd9Sstevel@tonic-gate struct in6_addr mask; 7087c478bd9Sstevel@tonic-gate struct in6_addr isatap = { 0, 0, 0, 0, 0, 0, 0, 0, \ 7097c478bd9Sstevel@tonic-gate 0, 0, 0x5e, 0xfe, 0, 0, 0, 0 }; 7107c478bd9Sstevel@tonic-gate struct in6_addr anycast = { 0, 0, 0, 0, \ 7117c478bd9Sstevel@tonic-gate 0, 0, 0, 0, \ 7127c478bd9Sstevel@tonic-gate 0xfd, 0xff, 0xff, 0xff, \ 7137c478bd9Sstevel@tonic-gate 0xff, 0xff, 0xff, 0x80 }; 7147c478bd9Sstevel@tonic-gate 7157c478bd9Sstevel@tonic-gate if (IN6_IS_ADDR_UNSPECIFIED(token)) 7167c478bd9Sstevel@tonic-gate return (_B_FALSE); 7177c478bd9Sstevel@tonic-gate 7187c478bd9Sstevel@tonic-gate if (token->s6_addr[8] & 0x2) 7197c478bd9Sstevel@tonic-gate return (_B_FALSE); 7207c478bd9Sstevel@tonic-gate 7217c478bd9Sstevel@tonic-gate (void) memcpy(&mask, token, sizeof (mask)); 7227c478bd9Sstevel@tonic-gate mask._S6_un._S6_u32[3] = 0; 7237c478bd9Sstevel@tonic-gate if (IN6_ARE_ADDR_EQUAL(&isatap, token)) 7247c478bd9Sstevel@tonic-gate return (_B_FALSE); 7257c478bd9Sstevel@tonic-gate 7267c478bd9Sstevel@tonic-gate mask._S6_un._S6_u32[3] = token->_S6_un._S6_u32[3] & 0xffffff80; 7277c478bd9Sstevel@tonic-gate if (IN6_ARE_ADDR_EQUAL(&anycast, token)) 7287c478bd9Sstevel@tonic-gate return (_B_FALSE); 7297c478bd9Sstevel@tonic-gate 7307c478bd9Sstevel@tonic-gate for (pi = phyints; pi != NULL; pi = pi->pi_next) { 7317c478bd9Sstevel@tonic-gate if (((pi->pi_token_length == TMP_TOKEN_BITS) && 7327c478bd9Sstevel@tonic-gate IN6_ARE_ADDR_EQUAL(&pi->pi_token, token)) || 7337c478bd9Sstevel@tonic-gate IN6_ARE_ADDR_EQUAL(&pi->pi_tmp_token, token)) 7347c478bd9Sstevel@tonic-gate return (_B_FALSE); 7357c478bd9Sstevel@tonic-gate } 7367c478bd9Sstevel@tonic-gate 7377c478bd9Sstevel@tonic-gate /* none of our tests failed, must be a good one! */ 7387c478bd9Sstevel@tonic-gate return (_B_TRUE); 7397c478bd9Sstevel@tonic-gate } 7407c478bd9Sstevel@tonic-gate 7417c478bd9Sstevel@tonic-gate /* 7427c478bd9Sstevel@tonic-gate * Generate a temporary token and set up its timer 7437c478bd9Sstevel@tonic-gate * 7447c478bd9Sstevel@tonic-gate * Called from incoming_prefix_addrconf_process() (when token is first 7457c478bd9Sstevel@tonic-gate * needed) and from tmptoken_timer() (when current token expires). 7467c478bd9Sstevel@tonic-gate * 7477c478bd9Sstevel@tonic-gate * Returns _B_TRUE if a token was successfully generated, _B_FALSE if not. 7487c478bd9Sstevel@tonic-gate */ 7497c478bd9Sstevel@tonic-gate boolean_t 7507c478bd9Sstevel@tonic-gate tmptoken_create(struct phyint *pi) 7517c478bd9Sstevel@tonic-gate { 7527c478bd9Sstevel@tonic-gate int fd, i = 0, max_tries = 15; 7537c478bd9Sstevel@tonic-gate struct in6_addr token; 7547c478bd9Sstevel@tonic-gate uint32_t *tokenp = &(token._S6_un._S6_u32[2]); 7557c478bd9Sstevel@tonic-gate char buf[INET6_ADDRSTRLEN]; 7567c478bd9Sstevel@tonic-gate 7577c478bd9Sstevel@tonic-gate if ((fd = open("/dev/urandom", O_RDONLY)) == -1) { 7587c478bd9Sstevel@tonic-gate perror("open /dev/urandom"); 7597c478bd9Sstevel@tonic-gate goto no_token; 7607c478bd9Sstevel@tonic-gate } 7617c478bd9Sstevel@tonic-gate 7627c478bd9Sstevel@tonic-gate bzero((char *)&token, sizeof (token)); 7637c478bd9Sstevel@tonic-gate do { 7647c478bd9Sstevel@tonic-gate if (read(fd, (void *)tokenp, TMP_TOKEN_BYTES) == -1) { 7657c478bd9Sstevel@tonic-gate perror("read /dev/urandom"); 7667c478bd9Sstevel@tonic-gate (void) close(fd); 7677c478bd9Sstevel@tonic-gate goto no_token; 7687c478bd9Sstevel@tonic-gate } 7697c478bd9Sstevel@tonic-gate 7707c478bd9Sstevel@tonic-gate /* 7717c478bd9Sstevel@tonic-gate * Assume EUI-64 formatting, and thus 64-bit 7727c478bd9Sstevel@tonic-gate * token len; need to clear global bit. 7737c478bd9Sstevel@tonic-gate */ 7747c478bd9Sstevel@tonic-gate token.s6_addr[8] &= 0xfd; 7757c478bd9Sstevel@tonic-gate 7767c478bd9Sstevel@tonic-gate i++; 7777c478bd9Sstevel@tonic-gate 7787c478bd9Sstevel@tonic-gate } while (!tmptoken_isvalid(&token) && i < max_tries); 7797c478bd9Sstevel@tonic-gate 7807c478bd9Sstevel@tonic-gate (void) close(fd); 7817c478bd9Sstevel@tonic-gate 7827c478bd9Sstevel@tonic-gate if (i == max_tries) { 7837c478bd9Sstevel@tonic-gate no_token: 7847c478bd9Sstevel@tonic-gate logmsg(LOG_WARNING, "tmptoken_create(%s): failed to create " 7857c478bd9Sstevel@tonic-gate "token; disabling temporary addresses on %s\n", 7867c478bd9Sstevel@tonic-gate pi->pi_name, pi->pi_name); 7877c478bd9Sstevel@tonic-gate pi->pi_TmpAddrsEnabled = 0; 7887c478bd9Sstevel@tonic-gate return (_B_FALSE); 7897c478bd9Sstevel@tonic-gate } 7907c478bd9Sstevel@tonic-gate 7917c478bd9Sstevel@tonic-gate pi->pi_tmp_token = token; 7927c478bd9Sstevel@tonic-gate 7937c478bd9Sstevel@tonic-gate if (debug & D_TMP) 7947c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "tmptoken_create(%s): created temporary " 7957c478bd9Sstevel@tonic-gate "token %s\n", pi->pi_name, 7967c478bd9Sstevel@tonic-gate inet_ntop(AF_INET6, &pi->pi_tmp_token, buf, sizeof (buf))); 7977c478bd9Sstevel@tonic-gate 7987c478bd9Sstevel@tonic-gate pi->pi_TmpRegenCountdown = (pi->pi_TmpPreferredLifetime - 7997c478bd9Sstevel@tonic-gate pi->pi_TmpDesyncFactor - pi->pi_TmpRegenAdvance) * MILLISEC; 8007c478bd9Sstevel@tonic-gate if (pi->pi_TmpRegenCountdown != 0) 8017c478bd9Sstevel@tonic-gate timer_schedule(pi->pi_TmpRegenCountdown); 8027c478bd9Sstevel@tonic-gate 8037c478bd9Sstevel@tonic-gate return (_B_TRUE); 8047c478bd9Sstevel@tonic-gate } 8057c478bd9Sstevel@tonic-gate 8067c478bd9Sstevel@tonic-gate /* 8077c478bd9Sstevel@tonic-gate * Delete a temporary token. This is outside the normal timeout process, 8087c478bd9Sstevel@tonic-gate * so mark any existing addresses based on this token DEPRECATED and set 8097c478bd9Sstevel@tonic-gate * their preferred lifetime to 0. Don't tamper with valid lifetime, that 8107c478bd9Sstevel@tonic-gate * will be used to eventually remove the address. Also reset the current 8117c478bd9Sstevel@tonic-gate * pi_tmp_token value to 0. 8127c478bd9Sstevel@tonic-gate * 8137c478bd9Sstevel@tonic-gate * Called from incoming_prefix_addrconf_process() if DAD fails on a temp 8147c478bd9Sstevel@tonic-gate * addr. 8157c478bd9Sstevel@tonic-gate */ 8167c478bd9Sstevel@tonic-gate void 8177c478bd9Sstevel@tonic-gate tmptoken_delete(struct phyint *pi) 8187c478bd9Sstevel@tonic-gate { 8197c478bd9Sstevel@tonic-gate struct prefix *pr; 8207c478bd9Sstevel@tonic-gate 8217c478bd9Sstevel@tonic-gate for (pr = pi->pi_prefix_list; pr != NULL; pr = pr->pr_next) { 8227c478bd9Sstevel@tonic-gate if (!(pr->pr_flags & IFF_TEMPORARY) || 8237c478bd9Sstevel@tonic-gate (pr->pr_flags & IFF_DEPRECATED) || 8247c478bd9Sstevel@tonic-gate (!token_equal(pr->pr_address, pi->pi_tmp_token, 8257c478bd9Sstevel@tonic-gate TMP_TOKEN_BITS))) { 8267c478bd9Sstevel@tonic-gate continue; 8277c478bd9Sstevel@tonic-gate } 8287c478bd9Sstevel@tonic-gate pr->pr_PreferredLifetime = 0; 8297c478bd9Sstevel@tonic-gate pr->pr_state |= PR_DEPRECATED; 8307c478bd9Sstevel@tonic-gate prefix_update_k(pr); 8317c478bd9Sstevel@tonic-gate } 8327c478bd9Sstevel@tonic-gate 8337c478bd9Sstevel@tonic-gate (void) memset(&pi->pi_tmp_token, 0, sizeof (pi->pi_tmp_token)); 8347c478bd9Sstevel@tonic-gate } 8357c478bd9Sstevel@tonic-gate 8367c478bd9Sstevel@tonic-gate /* 8377c478bd9Sstevel@tonic-gate * Called from run_timeouts() with the number of milliseconds elapsed 8387c478bd9Sstevel@tonic-gate * since the last call. Determines if any timeout event has occurred 8397c478bd9Sstevel@tonic-gate * and returns the number of milliseconds until the next timeout event 8407c478bd9Sstevel@tonic-gate * for the tmp token. Returns TIMER_INFINITY for "never". 8417c478bd9Sstevel@tonic-gate */ 8427c478bd9Sstevel@tonic-gate uint_t 8437c478bd9Sstevel@tonic-gate tmptoken_timer(struct phyint *pi, uint_t elapsed) 8447c478bd9Sstevel@tonic-gate { 8457c478bd9Sstevel@tonic-gate struct nd_opt_prefix_info opt; 8467c478bd9Sstevel@tonic-gate struct sockaddr_in6 sin6; 8477c478bd9Sstevel@tonic-gate struct prefix *pr, *newpr; 8487c478bd9Sstevel@tonic-gate 8497c478bd9Sstevel@tonic-gate if (debug & D_TMP) { 8507c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "tmptoken_timer(%s, %d) regencountdown %d\n", 8517c478bd9Sstevel@tonic-gate pi->pi_name, (int)elapsed, pi->pi_TmpRegenCountdown); 8527c478bd9Sstevel@tonic-gate } 8537c478bd9Sstevel@tonic-gate if (!pi->pi_TmpAddrsEnabled || 8547c478bd9Sstevel@tonic-gate (pi->pi_TmpRegenCountdown == TIMER_INFINITY)) 8557c478bd9Sstevel@tonic-gate return (TIMER_INFINITY); 8567c478bd9Sstevel@tonic-gate 8577c478bd9Sstevel@tonic-gate if (pi->pi_TmpRegenCountdown > elapsed) { 8587c478bd9Sstevel@tonic-gate pi->pi_TmpRegenCountdown -= elapsed; 8597c478bd9Sstevel@tonic-gate return (pi->pi_TmpRegenCountdown); 8607c478bd9Sstevel@tonic-gate } 8617c478bd9Sstevel@tonic-gate 8627c478bd9Sstevel@tonic-gate /* 8637c478bd9Sstevel@tonic-gate * Tmp token timer has expired. Start by generating a new token. 8647c478bd9Sstevel@tonic-gate * If we can't get a new token, tmp addrs are disabled on this 8657c478bd9Sstevel@tonic-gate * interface, so there's no need to continue, or to set a timer. 8667c478bd9Sstevel@tonic-gate */ 8677c478bd9Sstevel@tonic-gate if (!tmptoken_create(pi)) 8687c478bd9Sstevel@tonic-gate return (TIMER_INFINITY); 8697c478bd9Sstevel@tonic-gate 8707c478bd9Sstevel@tonic-gate /* 8717c478bd9Sstevel@tonic-gate * Now that we have a new token, walk the list of prefixes to 8727c478bd9Sstevel@tonic-gate * find which ones need a corresponding tmp addr generated. 8737c478bd9Sstevel@tonic-gate */ 8747c478bd9Sstevel@tonic-gate for (pr = pi->pi_prefix_list; pr != NULL; pr = pr->pr_next) { 8757c478bd9Sstevel@tonic-gate 8767c478bd9Sstevel@tonic-gate if (!(pr->pr_state & PR_AUTO) || pr->pr_state & PR_STATIC || 8777c478bd9Sstevel@tonic-gate pr->pr_state & PR_DEPRECATED || 8787c478bd9Sstevel@tonic-gate pr->pr_flags & IFF_TEMPORARY) 8797c478bd9Sstevel@tonic-gate continue; 8807c478bd9Sstevel@tonic-gate 8817c478bd9Sstevel@tonic-gate newpr = prefix_create(pi, pr->pr_prefix, pr->pr_prefix_len, 8827c478bd9Sstevel@tonic-gate IFF_TEMPORARY); 8837c478bd9Sstevel@tonic-gate if (newpr == NULL) { 8847c478bd9Sstevel@tonic-gate char pbuf[INET6_ADDRSTRLEN]; 8857c478bd9Sstevel@tonic-gate char tbuf[INET6_ADDRSTRLEN]; 8867c478bd9Sstevel@tonic-gate (void) inet_ntop(AF_INET6, &pr->pr_prefix, pbuf, 8877c478bd9Sstevel@tonic-gate sizeof (pbuf)); 8887c478bd9Sstevel@tonic-gate (void) inet_ntop(AF_INET6, &pi->pi_tmp_token, tbuf, 8897c478bd9Sstevel@tonic-gate sizeof (tbuf)); 8907c478bd9Sstevel@tonic-gate logmsg(LOG_ERR, "can't create new tmp addr " 8917c478bd9Sstevel@tonic-gate "(%s, %s, %s)\n", pi->pi_name, pbuf, tbuf); 8927c478bd9Sstevel@tonic-gate continue; 8937c478bd9Sstevel@tonic-gate } 8947c478bd9Sstevel@tonic-gate 8957c478bd9Sstevel@tonic-gate /* 8967c478bd9Sstevel@tonic-gate * We want to use incoming_prefix_*_process() functions to 8977c478bd9Sstevel@tonic-gate * set up the new tmp addr, so cobble together a prefix 8987c478bd9Sstevel@tonic-gate * info option struct based on the existing prefix to pass 8997c478bd9Sstevel@tonic-gate * in. The lifetimes will be based on the current time 9007c478bd9Sstevel@tonic-gate * remaining. 9017c478bd9Sstevel@tonic-gate * 9027c478bd9Sstevel@tonic-gate * The "from" param is only used for messages; pass in 9037c478bd9Sstevel@tonic-gate * ::0 for that. 9047c478bd9Sstevel@tonic-gate */ 9057c478bd9Sstevel@tonic-gate opt.nd_opt_pi_type = ND_OPT_PREFIX_INFORMATION; 9067c478bd9Sstevel@tonic-gate opt.nd_opt_pi_len = sizeof (opt) / 8; 9077c478bd9Sstevel@tonic-gate opt.nd_opt_pi_prefix_len = pr->pr_prefix_len; 9087c478bd9Sstevel@tonic-gate opt.nd_opt_pi_flags_reserved = ND_OPT_PI_FLAG_AUTO; 9097c478bd9Sstevel@tonic-gate opt.nd_opt_pi_valid_time = 9107c478bd9Sstevel@tonic-gate htonl(pr->pr_ValidLifetime / 1000); 9117c478bd9Sstevel@tonic-gate opt.nd_opt_pi_preferred_time = 9127c478bd9Sstevel@tonic-gate htonl(pr->pr_PreferredLifetime / 1000); 9137c478bd9Sstevel@tonic-gate if (pr->pr_state & PR_ONLINK) 9147c478bd9Sstevel@tonic-gate opt.nd_opt_pi_flags_reserved &= ND_OPT_PI_FLAG_ONLINK; 9157c478bd9Sstevel@tonic-gate opt.nd_opt_pi_prefix = pr->pr_prefix; 9167c478bd9Sstevel@tonic-gate 9177c478bd9Sstevel@tonic-gate (void) memset(&sin6, 0, sizeof (sin6)); 9187c478bd9Sstevel@tonic-gate 9197c478bd9Sstevel@tonic-gate if (!incoming_prefix_addrconf_process(pi, newpr, 9207c478bd9Sstevel@tonic-gate (uchar_t *)&opt, &sin6, _B_FALSE, _B_TRUE)) { 9217c478bd9Sstevel@tonic-gate char pbuf[INET6_ADDRSTRLEN]; 9227c478bd9Sstevel@tonic-gate char tbuf[INET6_ADDRSTRLEN]; 9237c478bd9Sstevel@tonic-gate (void) inet_ntop(AF_INET6, &pr->pr_prefix, pbuf, 9247c478bd9Sstevel@tonic-gate sizeof (pbuf)); 9257c478bd9Sstevel@tonic-gate (void) inet_ntop(AF_INET6, &pi->pi_tmp_token, tbuf, 9267c478bd9Sstevel@tonic-gate sizeof (tbuf)); 9277c478bd9Sstevel@tonic-gate logmsg(LOG_ERR, "can't create new tmp addr " 9287c478bd9Sstevel@tonic-gate "(%s, %s, %s)\n", pi->pi_name, pbuf, tbuf); 9297c478bd9Sstevel@tonic-gate continue; 9307c478bd9Sstevel@tonic-gate } 9317c478bd9Sstevel@tonic-gate 9327c478bd9Sstevel@tonic-gate if (pr->pr_state & PR_ONLINK) { 9337c478bd9Sstevel@tonic-gate incoming_prefix_onlink_process(newpr, (uchar_t *)&opt); 9347c478bd9Sstevel@tonic-gate } 9357c478bd9Sstevel@tonic-gate } 9367c478bd9Sstevel@tonic-gate 9377c478bd9Sstevel@tonic-gate /* 9387c478bd9Sstevel@tonic-gate * appropriate timers were scheduled when 9397c478bd9Sstevel@tonic-gate * the token and addresses were created. 9407c478bd9Sstevel@tonic-gate */ 9417c478bd9Sstevel@tonic-gate return (TIMER_INFINITY); 9427c478bd9Sstevel@tonic-gate } 9437c478bd9Sstevel@tonic-gate 9447c478bd9Sstevel@tonic-gate /* 9457c478bd9Sstevel@tonic-gate * tlen specifies the token length in bits. Compares the lower 9467c478bd9Sstevel@tonic-gate * tlen bits of the two addresses provided and returns _B_TRUE if 9477c478bd9Sstevel@tonic-gate * they match, _B_FALSE if not. Also returns _B_FALSE for invalid 9487c478bd9Sstevel@tonic-gate * values of tlen. 9497c478bd9Sstevel@tonic-gate */ 9507c478bd9Sstevel@tonic-gate boolean_t 9517c478bd9Sstevel@tonic-gate token_equal(struct in6_addr t1, struct in6_addr t2, int tlen) 9527c478bd9Sstevel@tonic-gate { 9537c478bd9Sstevel@tonic-gate uchar_t mask; 9547c478bd9Sstevel@tonic-gate int j, abytes, tbytes, tbits; 9557c478bd9Sstevel@tonic-gate 9567c478bd9Sstevel@tonic-gate if (tlen < 0 || tlen > IPV6_ABITS) 9577c478bd9Sstevel@tonic-gate return (_B_FALSE); 9587c478bd9Sstevel@tonic-gate 9597c478bd9Sstevel@tonic-gate abytes = IPV6_ABITS >> 3; 9607c478bd9Sstevel@tonic-gate tbytes = tlen >> 3; 9617c478bd9Sstevel@tonic-gate tbits = tlen & 7; 9627c478bd9Sstevel@tonic-gate 9637c478bd9Sstevel@tonic-gate for (j = abytes - 1; j >= abytes - tbytes; j--) 9647c478bd9Sstevel@tonic-gate if (t1.s6_addr[j] != t2.s6_addr[j]) 9657c478bd9Sstevel@tonic-gate return (_B_FALSE); 9667c478bd9Sstevel@tonic-gate 9677c478bd9Sstevel@tonic-gate if (tbits == 0) 9687c478bd9Sstevel@tonic-gate return (_B_TRUE); 9697c478bd9Sstevel@tonic-gate 9707c478bd9Sstevel@tonic-gate /* We only care about the tbits rightmost bits */ 9717c478bd9Sstevel@tonic-gate mask = 0xff >> (8 - tbits); 9727c478bd9Sstevel@tonic-gate if ((t1.s6_addr[j] & mask) != (t2.s6_addr[j] & mask)) 9737c478bd9Sstevel@tonic-gate return (_B_FALSE); 9747c478bd9Sstevel@tonic-gate 9757c478bd9Sstevel@tonic-gate return (_B_TRUE); 9767c478bd9Sstevel@tonic-gate } 9777c478bd9Sstevel@tonic-gate 9787c478bd9Sstevel@tonic-gate /* 9797c478bd9Sstevel@tonic-gate * Lookup prefix structure that matches the prefix and prefix length. 9807c478bd9Sstevel@tonic-gate * Assumes that the bits after prefixlen might not be zero. 9817c478bd9Sstevel@tonic-gate */ 9827c478bd9Sstevel@tonic-gate static struct prefix * 9837c478bd9Sstevel@tonic-gate prefix_lookup(struct phyint *pi, struct in6_addr prefix, int prefixlen) 9847c478bd9Sstevel@tonic-gate { 9857c478bd9Sstevel@tonic-gate struct prefix *pr; 9867c478bd9Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 9877c478bd9Sstevel@tonic-gate 9887c478bd9Sstevel@tonic-gate if (debug & D_PREFIX) { 9897c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "prefix_lookup(%s, %s/%u)\n", pi->pi_name, 9907c478bd9Sstevel@tonic-gate inet_ntop(AF_INET6, (void *)&prefix, 9917c478bd9Sstevel@tonic-gate abuf, sizeof (abuf)), prefixlen); 9927c478bd9Sstevel@tonic-gate } 9937c478bd9Sstevel@tonic-gate 9947c478bd9Sstevel@tonic-gate for (pr = pi->pi_prefix_list; pr != NULL; pr = pr->pr_next) { 9957c478bd9Sstevel@tonic-gate if (pr->pr_prefix_len == prefixlen && 9967c478bd9Sstevel@tonic-gate prefix_equal(prefix, pr->pr_prefix, prefixlen)) 9977c478bd9Sstevel@tonic-gate return (pr); 9987c478bd9Sstevel@tonic-gate } 9997c478bd9Sstevel@tonic-gate return (NULL); 10007c478bd9Sstevel@tonic-gate } 10017c478bd9Sstevel@tonic-gate 10027c478bd9Sstevel@tonic-gate /* 10037c478bd9Sstevel@tonic-gate * Compare two prefixes that have the same prefix length. 10047c478bd9Sstevel@tonic-gate * Fails if the prefix length is unreasonable. 10057c478bd9Sstevel@tonic-gate */ 10067c478bd9Sstevel@tonic-gate boolean_t 10077c478bd9Sstevel@tonic-gate prefix_equal(struct in6_addr p1, struct in6_addr p2, int plen) 10087c478bd9Sstevel@tonic-gate { 10097c478bd9Sstevel@tonic-gate uchar_t mask; 10107c478bd9Sstevel@tonic-gate int j, pbytes, pbits; 10117c478bd9Sstevel@tonic-gate 10127c478bd9Sstevel@tonic-gate if (plen < 0 || plen > IPV6_ABITS) 10137c478bd9Sstevel@tonic-gate return (_B_FALSE); 10147c478bd9Sstevel@tonic-gate 10157c478bd9Sstevel@tonic-gate pbytes = plen >> 3; 10167c478bd9Sstevel@tonic-gate pbits = plen & 7; 10177c478bd9Sstevel@tonic-gate 10187c478bd9Sstevel@tonic-gate for (j = 0; j < pbytes; j++) 10197c478bd9Sstevel@tonic-gate if (p1.s6_addr[j] != p2.s6_addr[j]) 10207c478bd9Sstevel@tonic-gate return (_B_FALSE); 10217c478bd9Sstevel@tonic-gate 10227c478bd9Sstevel@tonic-gate if (pbits == 0) 10237c478bd9Sstevel@tonic-gate return (_B_TRUE); 10247c478bd9Sstevel@tonic-gate 10257c478bd9Sstevel@tonic-gate /* Make the N leftmost bits one */ 10267c478bd9Sstevel@tonic-gate mask = 0xff << (8 - pbits); 10277c478bd9Sstevel@tonic-gate if ((p1.s6_addr[j] & mask) != (p2.s6_addr[j] & mask)) 10287c478bd9Sstevel@tonic-gate return (_B_FALSE); 10297c478bd9Sstevel@tonic-gate 10307c478bd9Sstevel@tonic-gate return (_B_TRUE); 10317c478bd9Sstevel@tonic-gate } 10327c478bd9Sstevel@tonic-gate 10337c478bd9Sstevel@tonic-gate /* 10347c478bd9Sstevel@tonic-gate * Set a prefix from an address and a prefix length. 10357c478bd9Sstevel@tonic-gate * Force all the bits after the prefix length to be zero. 10367c478bd9Sstevel@tonic-gate */ 10377c478bd9Sstevel@tonic-gate void 10387c478bd9Sstevel@tonic-gate prefix_set(struct in6_addr *prefix, struct in6_addr addr, int prefix_len) 10397c478bd9Sstevel@tonic-gate { 10407c478bd9Sstevel@tonic-gate uchar_t mask; 10417c478bd9Sstevel@tonic-gate int j; 10427c478bd9Sstevel@tonic-gate 10437c478bd9Sstevel@tonic-gate if (prefix_len < 0 || prefix_len > IPV6_ABITS) 10447c478bd9Sstevel@tonic-gate return; 10457c478bd9Sstevel@tonic-gate 10467c478bd9Sstevel@tonic-gate bzero((char *)prefix, sizeof (*prefix)); 10477c478bd9Sstevel@tonic-gate 10487c478bd9Sstevel@tonic-gate for (j = 0; prefix_len > 8; prefix_len -= 8, j++) 10497c478bd9Sstevel@tonic-gate prefix->s6_addr[j] = addr.s6_addr[j]; 10507c478bd9Sstevel@tonic-gate 10517c478bd9Sstevel@tonic-gate /* Make the N leftmost bits one */ 10527c478bd9Sstevel@tonic-gate mask = 0xff << (8 - prefix_len); 10537c478bd9Sstevel@tonic-gate prefix->s6_addr[j] = addr.s6_addr[j] & mask; 10547c478bd9Sstevel@tonic-gate } 10557c478bd9Sstevel@tonic-gate 10567c478bd9Sstevel@tonic-gate /* 10577c478bd9Sstevel@tonic-gate * Lookup a prefix based on the kernel's interface name. 10587c478bd9Sstevel@tonic-gate */ 10597c478bd9Sstevel@tonic-gate struct prefix * 10607c478bd9Sstevel@tonic-gate prefix_lookup_name(struct phyint *pi, char *name) 10617c478bd9Sstevel@tonic-gate { 10627c478bd9Sstevel@tonic-gate struct prefix *pr; 10637c478bd9Sstevel@tonic-gate 10647c478bd9Sstevel@tonic-gate if (debug & D_PREFIX) { 10657c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "prefix_lookup_name(%s, %s)\n", 10667c478bd9Sstevel@tonic-gate pi->pi_name, name); 10677c478bd9Sstevel@tonic-gate } 10687c478bd9Sstevel@tonic-gate if (name[0] == '\0') 10697c478bd9Sstevel@tonic-gate return (NULL); 10707c478bd9Sstevel@tonic-gate 10717c478bd9Sstevel@tonic-gate for (pr = pi->pi_prefix_list; pr != NULL; pr = pr->pr_next) { 10727c478bd9Sstevel@tonic-gate if (strcmp(name, pr->pr_name) == 0) 10737c478bd9Sstevel@tonic-gate return (pr); 10747c478bd9Sstevel@tonic-gate } 10757c478bd9Sstevel@tonic-gate return (NULL); 10767c478bd9Sstevel@tonic-gate } 10777c478bd9Sstevel@tonic-gate 10787c478bd9Sstevel@tonic-gate /* 10797c478bd9Sstevel@tonic-gate * Search the phyints list to make sure that this new prefix does 10807c478bd9Sstevel@tonic-gate * not already exist in any other physical interfaces that have 10817c478bd9Sstevel@tonic-gate * the same address as this one 10827c478bd9Sstevel@tonic-gate */ 10837c478bd9Sstevel@tonic-gate struct prefix * 10847c478bd9Sstevel@tonic-gate prefix_lookup_addr_match(struct prefix *pr) 10857c478bd9Sstevel@tonic-gate { 10867c478bd9Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 10877c478bd9Sstevel@tonic-gate struct phyint *pi; 10887c478bd9Sstevel@tonic-gate struct prefix *otherpr = NULL; 10897c478bd9Sstevel@tonic-gate struct in6_addr prefix; 10907c478bd9Sstevel@tonic-gate int prefixlen; 10917c478bd9Sstevel@tonic-gate 10927c478bd9Sstevel@tonic-gate if (debug & D_PREFIX) { 10937c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "prefix_lookup_addr_match(%s/%u)\n", 10947c478bd9Sstevel@tonic-gate inet_ntop(AF_INET6, (void *)&pr->pr_address, 10957c478bd9Sstevel@tonic-gate abuf, sizeof (abuf)), pr->pr_prefix_len); 10967c478bd9Sstevel@tonic-gate } 10977c478bd9Sstevel@tonic-gate prefix = pr->pr_prefix; 10987c478bd9Sstevel@tonic-gate prefixlen = pr->pr_prefix_len; 10997c478bd9Sstevel@tonic-gate for (pi = phyints; pi != NULL; pi = pi->pi_next) { 11007c478bd9Sstevel@tonic-gate otherpr = prefix_lookup(pi, prefix, prefixlen); 11017c478bd9Sstevel@tonic-gate if (otherpr == pr) 11027c478bd9Sstevel@tonic-gate continue; 11037c478bd9Sstevel@tonic-gate if (otherpr != NULL && (otherpr->pr_state & PR_AUTO) && 11047c478bd9Sstevel@tonic-gate IN6_ARE_ADDR_EQUAL(&pr->pr_address, 11057c478bd9Sstevel@tonic-gate &otherpr->pr_address)) 11067c478bd9Sstevel@tonic-gate return (otherpr); 11077c478bd9Sstevel@tonic-gate } 11087c478bd9Sstevel@tonic-gate return (NULL); 11097c478bd9Sstevel@tonic-gate } 11107c478bd9Sstevel@tonic-gate 11117c478bd9Sstevel@tonic-gate /* 11127c478bd9Sstevel@tonic-gate * Initialize a new prefix without setting lifetimes etc. 11137c478bd9Sstevel@tonic-gate */ 11147c478bd9Sstevel@tonic-gate struct prefix * 11157c478bd9Sstevel@tonic-gate prefix_create(struct phyint *pi, struct in6_addr prefix, int prefixlen, 11167c478bd9Sstevel@tonic-gate uint64_t flags) 11177c478bd9Sstevel@tonic-gate { 11187c478bd9Sstevel@tonic-gate struct prefix *pr; 11197c478bd9Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 11207c478bd9Sstevel@tonic-gate 11217c478bd9Sstevel@tonic-gate if (debug & D_PREFIX) { 11227c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "prefix_create(%s, %s/%u, 0x%llx)\n", 11237c478bd9Sstevel@tonic-gate pi->pi_name, inet_ntop(AF_INET6, (void *)&prefix, 11247c478bd9Sstevel@tonic-gate abuf, sizeof (abuf)), prefixlen, flags); 11257c478bd9Sstevel@tonic-gate } 11267c478bd9Sstevel@tonic-gate pr = (struct prefix *)calloc(sizeof (struct prefix), 1); 11277c478bd9Sstevel@tonic-gate if (pr == NULL) { 11287c478bd9Sstevel@tonic-gate logmsg(LOG_ERR, "prefix_create: out of memory\n"); 11297c478bd9Sstevel@tonic-gate return (NULL); 11307c478bd9Sstevel@tonic-gate } 11317c478bd9Sstevel@tonic-gate /* 11327c478bd9Sstevel@tonic-gate * The prefix might have non-zero bits after the prefix len bits. 11337c478bd9Sstevel@tonic-gate * Force them to be zero. 11347c478bd9Sstevel@tonic-gate */ 11357c478bd9Sstevel@tonic-gate prefix_set(&pr->pr_prefix, prefix, prefixlen); 11367c478bd9Sstevel@tonic-gate pr->pr_prefix_len = prefixlen; 11377c478bd9Sstevel@tonic-gate pr->pr_PreferredLifetime = PREFIX_INFINITY; 11387c478bd9Sstevel@tonic-gate pr->pr_ValidLifetime = PREFIX_INFINITY; 11397c478bd9Sstevel@tonic-gate pr->pr_OnLinkLifetime = PREFIX_INFINITY; 11407c478bd9Sstevel@tonic-gate pr->pr_kernel_state = 0; 11417c478bd9Sstevel@tonic-gate pr->pr_flags |= flags; 11427c478bd9Sstevel@tonic-gate prefix_insert(pi, pr); 11437c478bd9Sstevel@tonic-gate return (pr); 11447c478bd9Sstevel@tonic-gate } 11457c478bd9Sstevel@tonic-gate 11467c478bd9Sstevel@tonic-gate /* 11477c478bd9Sstevel@tonic-gate * Create a new named prefix. Caller should use prefix_init_from_k 11487c478bd9Sstevel@tonic-gate * to initialize the content. 11497c478bd9Sstevel@tonic-gate */ 11507c478bd9Sstevel@tonic-gate struct prefix * 11517c478bd9Sstevel@tonic-gate prefix_create_name(struct phyint *pi, char *name) 11527c478bd9Sstevel@tonic-gate { 11537c478bd9Sstevel@tonic-gate struct prefix *pr; 11547c478bd9Sstevel@tonic-gate 11557c478bd9Sstevel@tonic-gate if (debug & D_PREFIX) { 11567c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "prefix_create_name(%s, %s)\n", 11577c478bd9Sstevel@tonic-gate pi->pi_name, name); 11587c478bd9Sstevel@tonic-gate } 11597c478bd9Sstevel@tonic-gate pr = (struct prefix *)calloc(sizeof (struct prefix), 1); 11607c478bd9Sstevel@tonic-gate if (pr == NULL) { 11617c478bd9Sstevel@tonic-gate logmsg(LOG_ERR, "prefix_create_name: out of memory\n"); 11627c478bd9Sstevel@tonic-gate return (NULL); 11637c478bd9Sstevel@tonic-gate } 11647c478bd9Sstevel@tonic-gate (void) strncpy(pr->pr_name, name, sizeof (pr->pr_name)); 11657c478bd9Sstevel@tonic-gate pr->pr_name[sizeof (pr->pr_name) - 1] = '\0'; 11667c478bd9Sstevel@tonic-gate prefix_insert(pi, pr); 11677c478bd9Sstevel@tonic-gate return (pr); 11687c478bd9Sstevel@tonic-gate } 11697c478bd9Sstevel@tonic-gate 11707c478bd9Sstevel@tonic-gate /* Insert in linked list */ 11717c478bd9Sstevel@tonic-gate static void 11727c478bd9Sstevel@tonic-gate prefix_insert(struct phyint *pi, struct prefix *pr) 11737c478bd9Sstevel@tonic-gate { 11747c478bd9Sstevel@tonic-gate pr->pr_next = pi->pi_prefix_list; 11757c478bd9Sstevel@tonic-gate pr->pr_prev = NULL; 11767c478bd9Sstevel@tonic-gate if (pi->pi_prefix_list != NULL) 11777c478bd9Sstevel@tonic-gate pi->pi_prefix_list->pr_prev = pr; 11787c478bd9Sstevel@tonic-gate pi->pi_prefix_list = pr; 11797c478bd9Sstevel@tonic-gate pr->pr_physical = pi; 11807c478bd9Sstevel@tonic-gate } 11817c478bd9Sstevel@tonic-gate 11827c478bd9Sstevel@tonic-gate /* 11837c478bd9Sstevel@tonic-gate * Initialize the prefix from the content of the kernel. 11847c478bd9Sstevel@tonic-gate * If IFF_ADDRCONF is set we treat it as PR_AUTO (i.e. an addrconf 1185d04ccbb3Scarlsonj * prefix). However, we cannot derive the lifetime from 1186d04ccbb3Scarlsonj * the kernel, thus it is set to 1 week. 11877c478bd9Sstevel@tonic-gate * Ignore the prefix if the interface is not IFF_UP. 1188d04ccbb3Scarlsonj * If it's from DHCPv6, then we set the netmask. 11897c478bd9Sstevel@tonic-gate */ 11907c478bd9Sstevel@tonic-gate int 11917c478bd9Sstevel@tonic-gate prefix_init_from_k(struct prefix *pr) 11927c478bd9Sstevel@tonic-gate { 11937c478bd9Sstevel@tonic-gate struct lifreq lifr; 11947c478bd9Sstevel@tonic-gate struct sockaddr_in6 *sin6; 11957c478bd9Sstevel@tonic-gate int sock = pr->pr_physical->pi_sock; 11967c478bd9Sstevel@tonic-gate 11977c478bd9Sstevel@tonic-gate (void) strncpy(lifr.lifr_name, pr->pr_name, sizeof (lifr.lifr_name)); 11987c478bd9Sstevel@tonic-gate lifr.lifr_name[sizeof (lifr.lifr_name) - 1] = '\0'; 11997c478bd9Sstevel@tonic-gate if (ioctl(sock, SIOCGLIFADDR, (char *)&lifr) < 0) { 12007c478bd9Sstevel@tonic-gate logperror_pr(pr, "prefix_init_from_k: ioctl (get addr)"); 12017c478bd9Sstevel@tonic-gate goto error; 12027c478bd9Sstevel@tonic-gate } 12037c478bd9Sstevel@tonic-gate if (lifr.lifr_addr.ss_family != AF_INET6) { 12047c478bd9Sstevel@tonic-gate logmsg(LOG_ERR, "ignoring interface %s: not AF_INET6\n", 12057c478bd9Sstevel@tonic-gate pr->pr_name); 12067c478bd9Sstevel@tonic-gate goto error; 12077c478bd9Sstevel@tonic-gate } 12087c478bd9Sstevel@tonic-gate sin6 = (struct sockaddr_in6 *)&lifr.lifr_addr; 12097c478bd9Sstevel@tonic-gate pr->pr_address = sin6->sin6_addr; 12107c478bd9Sstevel@tonic-gate 12117c478bd9Sstevel@tonic-gate if (ioctl(sock, SIOCGLIFFLAGS, (char *)&lifr) < 0) { 12127c478bd9Sstevel@tonic-gate logperror_pr(pr, "prefix_init_from_k: ioctl (get flags)"); 12137c478bd9Sstevel@tonic-gate goto error; 12147c478bd9Sstevel@tonic-gate } 12157c478bd9Sstevel@tonic-gate pr->pr_flags = lifr.lifr_flags; 12167c478bd9Sstevel@tonic-gate 12177c478bd9Sstevel@tonic-gate /* 1218d04ccbb3Scarlsonj * If this is a DHCPv6 interface, then we control the netmask. 12197c478bd9Sstevel@tonic-gate */ 1220d04ccbb3Scarlsonj if (lifr.lifr_flags & IFF_DHCPRUNNING) { 1221d04ccbb3Scarlsonj struct phyint *pi = pr->pr_physical; 1222d04ccbb3Scarlsonj struct prefix *pr2; 1223d04ccbb3Scarlsonj 1224d04ccbb3Scarlsonj pr->pr_prefix_len = IPV6_ABITS; 1225d04ccbb3Scarlsonj if (!(lifr.lifr_flags & IFF_UP) || 1226d04ccbb3Scarlsonj IN6_IS_ADDR_UNSPECIFIED(&pr->pr_address) || 1227d04ccbb3Scarlsonj IN6_IS_ADDR_LINKLOCAL(&pr->pr_address)) { 1228d04ccbb3Scarlsonj if (debug & D_DHCP) 1229d04ccbb3Scarlsonj logmsg(LOG_DEBUG, "prefix_init_from_k: " 1230d04ccbb3Scarlsonj "ignoring DHCP %s not ready\n", 1231d04ccbb3Scarlsonj pr->pr_name); 1232d04ccbb3Scarlsonj return (0); 1233d04ccbb3Scarlsonj } 12347c478bd9Sstevel@tonic-gate 1235d04ccbb3Scarlsonj for (pr2 = pi->pi_prefix_list; pr2 != NULL; 1236d04ccbb3Scarlsonj pr2 = pr2->pr_next) { 1237d04ccbb3Scarlsonj /* 1238d04ccbb3Scarlsonj * Examine any non-static (autoconfigured) prefixes as 1239d04ccbb3Scarlsonj * well as existing DHCP-controlled prefixes for valid 1240d04ccbb3Scarlsonj * prefix length information. 1241d04ccbb3Scarlsonj */ 1242d04ccbb3Scarlsonj if (pr2->pr_prefix_len != IPV6_ABITS && 1243d04ccbb3Scarlsonj (!(pr2->pr_state & PR_STATIC) || 1244d04ccbb3Scarlsonj (pr2->pr_flags & IFF_DHCPRUNNING)) && 1245d04ccbb3Scarlsonj prefix_equal(pr->pr_prefix, pr2->pr_prefix, 1246d04ccbb3Scarlsonj pr2->pr_prefix_len)) { 1247d04ccbb3Scarlsonj pr->pr_prefix_len = pr2->pr_prefix_len; 1248d04ccbb3Scarlsonj break; 1249d04ccbb3Scarlsonj } 1250d04ccbb3Scarlsonj } 1251d04ccbb3Scarlsonj if (pr2 == NULL) { 1252d04ccbb3Scarlsonj if (debug & D_DHCP) 1253d04ccbb3Scarlsonj logmsg(LOG_DEBUG, "prefix_init_from_k: no " 1254d04ccbb3Scarlsonj "saved mask for DHCP %s; need to " 1255d04ccbb3Scarlsonj "resolicit\n", pr->pr_name); 1256d04ccbb3Scarlsonj (void) check_to_solicit(pi, RESTART_INIT_SOLICIT); 1257d04ccbb3Scarlsonj } else { 1258d04ccbb3Scarlsonj if (debug & D_DHCP) 1259d04ccbb3Scarlsonj logmsg(LOG_DEBUG, "prefix_init_from_k: using " 1260d04ccbb3Scarlsonj "%s mask for DHCP %s\n", 1261d04ccbb3Scarlsonj pr2->pr_name[0] == '\0' ? "saved" : 1262d04ccbb3Scarlsonj pr2->pr_name, pr->pr_name); 1263d04ccbb3Scarlsonj prefix_update_dhcp(pr); 1264d04ccbb3Scarlsonj } 1265d04ccbb3Scarlsonj } else { 1266d04ccbb3Scarlsonj if (ioctl(sock, SIOCGLIFSUBNET, (char *)&lifr) < 0) { 1267d04ccbb3Scarlsonj logperror_pr(pr, 1268d04ccbb3Scarlsonj "prefix_init_from_k: ioctl (get subnet)"); 1269d04ccbb3Scarlsonj goto error; 1270d04ccbb3Scarlsonj } 1271d04ccbb3Scarlsonj if (lifr.lifr_subnet.ss_family != AF_INET6) { 1272d04ccbb3Scarlsonj logmsg(LOG_ERR, 1273d04ccbb3Scarlsonj "ignoring interface %s: not AF_INET6\n", 1274d04ccbb3Scarlsonj pr->pr_name); 1275d04ccbb3Scarlsonj goto error; 1276d04ccbb3Scarlsonj } 1277d04ccbb3Scarlsonj /* 1278d04ccbb3Scarlsonj * Guard against the prefix having non-zero bits after the 1279d04ccbb3Scarlsonj * prefix len bits. 1280d04ccbb3Scarlsonj */ 1281d04ccbb3Scarlsonj sin6 = (struct sockaddr_in6 *)&lifr.lifr_subnet; 1282d04ccbb3Scarlsonj pr->pr_prefix_len = lifr.lifr_addrlen; 1283d04ccbb3Scarlsonj prefix_set(&pr->pr_prefix, sin6->sin6_addr, pr->pr_prefix_len); 1284d04ccbb3Scarlsonj 1285d04ccbb3Scarlsonj if (pr->pr_prefix_len != IPV6_ABITS && 1286d04ccbb3Scarlsonj (pr->pr_flags & IFF_UP) && 1287d04ccbb3Scarlsonj IN6_ARE_ADDR_EQUAL(&pr->pr_address, &pr->pr_prefix)) { 1288d04ccbb3Scarlsonj char abuf[INET6_ADDRSTRLEN]; 1289d04ccbb3Scarlsonj 1290b12d9c4eSmeem logmsg(LOG_ERR, "ignoring interface %s: it appears to " 1291d04ccbb3Scarlsonj "be configured with an invalid interface id " 1292d04ccbb3Scarlsonj "(%s/%u)\n", 1293d04ccbb3Scarlsonj pr->pr_name, 1294d04ccbb3Scarlsonj inet_ntop(AF_INET6, (void *)&pr->pr_address, 1295d04ccbb3Scarlsonj abuf, sizeof (abuf)), pr->pr_prefix_len); 1296d04ccbb3Scarlsonj goto error; 1297d04ccbb3Scarlsonj } 12987c478bd9Sstevel@tonic-gate } 12997c478bd9Sstevel@tonic-gate pr->pr_kernel_state = 0; 13007c478bd9Sstevel@tonic-gate if (pr->pr_prefix_len != IPV6_ABITS) 13017c478bd9Sstevel@tonic-gate pr->pr_kernel_state |= PR_ONLINK; 1302d04ccbb3Scarlsonj if (!(pr->pr_flags & (IFF_NOLOCAL | IFF_DHCPRUNNING))) 13037c478bd9Sstevel@tonic-gate pr->pr_kernel_state |= PR_AUTO; 13047c478bd9Sstevel@tonic-gate if ((pr->pr_flags & IFF_DEPRECATED) && (pr->pr_kernel_state & PR_AUTO)) 13057c478bd9Sstevel@tonic-gate pr->pr_kernel_state |= PR_DEPRECATED; 13067c478bd9Sstevel@tonic-gate if (!(pr->pr_flags & IFF_ADDRCONF)) { 13077c478bd9Sstevel@tonic-gate /* Prevent ndpd from stepping on this prefix */ 13087c478bd9Sstevel@tonic-gate pr->pr_kernel_state |= PR_STATIC; 13097c478bd9Sstevel@tonic-gate } 13107c478bd9Sstevel@tonic-gate pr->pr_state = pr->pr_kernel_state; 13117c478bd9Sstevel@tonic-gate /* Adjust pr_prefix_len based if PR_AUTO is set */ 13127c478bd9Sstevel@tonic-gate if (pr->pr_state & PR_AUTO) { 13137c478bd9Sstevel@tonic-gate pr->pr_prefix_len = 13147c478bd9Sstevel@tonic-gate IPV6_ABITS - pr->pr_physical->pi_token_length; 13157c478bd9Sstevel@tonic-gate prefix_set(&pr->pr_prefix, pr->pr_prefix, pr->pr_prefix_len); 13167c478bd9Sstevel@tonic-gate } 13177c478bd9Sstevel@tonic-gate 13187c478bd9Sstevel@tonic-gate /* Can't extract lifetimes from the kernel - use 1 week */ 13197c478bd9Sstevel@tonic-gate pr->pr_ValidLifetime = NDP_PREFIX_DEFAULT_LIFETIME; 13207c478bd9Sstevel@tonic-gate pr->pr_PreferredLifetime = NDP_PREFIX_DEFAULT_LIFETIME; 13217c478bd9Sstevel@tonic-gate pr->pr_OnLinkLifetime = NDP_PREFIX_DEFAULT_LIFETIME; 13227c478bd9Sstevel@tonic-gate 13237c478bd9Sstevel@tonic-gate /* 13247c478bd9Sstevel@tonic-gate * If this is a temp addr, the creation time needs to be set. 13257c478bd9Sstevel@tonic-gate * Though it won't be entirely accurate, the current time is 13267c478bd9Sstevel@tonic-gate * an okay approximation. 13277c478bd9Sstevel@tonic-gate */ 13287c478bd9Sstevel@tonic-gate if (pr->pr_flags & IFF_TEMPORARY) 13297c478bd9Sstevel@tonic-gate pr->pr_CreateTime = getcurrenttime() / MILLISEC; 13307c478bd9Sstevel@tonic-gate 13317c478bd9Sstevel@tonic-gate if (pr->pr_kernel_state == 0) 13327c478bd9Sstevel@tonic-gate pr->pr_name[0] = '\0'; 13337c478bd9Sstevel@tonic-gate return (0); 13347c478bd9Sstevel@tonic-gate 13357c478bd9Sstevel@tonic-gate error: 13367c478bd9Sstevel@tonic-gate /* Pretend that the prefix does not exist in the kernel */ 13377c478bd9Sstevel@tonic-gate pr->pr_kernel_state = 0; 13387c478bd9Sstevel@tonic-gate pr->pr_name[0] = '\0'; 13397c478bd9Sstevel@tonic-gate return (-1); 13407c478bd9Sstevel@tonic-gate } 13417c478bd9Sstevel@tonic-gate 13427c478bd9Sstevel@tonic-gate /* 13437c478bd9Sstevel@tonic-gate * Delete (unlink and free) and remove from kernel if the prefix 13447c478bd9Sstevel@tonic-gate * was added by in.ndpd (i.e. PR_STATIC is not set). 13457c478bd9Sstevel@tonic-gate * Handles delete of things that have not yet been inserted in the list 13467c478bd9Sstevel@tonic-gate * i.e. pr_physical is NULL. 13477c478bd9Sstevel@tonic-gate */ 13487c478bd9Sstevel@tonic-gate void 13497c478bd9Sstevel@tonic-gate prefix_delete(struct prefix *pr) 13507c478bd9Sstevel@tonic-gate { 13517c478bd9Sstevel@tonic-gate struct phyint *pi; 13527c478bd9Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 13537c478bd9Sstevel@tonic-gate 13547c478bd9Sstevel@tonic-gate if (debug & D_PREFIX) { 13557c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "prefix_delete(%s, %s, %s/%u)\n", 13567c478bd9Sstevel@tonic-gate pr->pr_physical->pi_name, pr->pr_name, 13577c478bd9Sstevel@tonic-gate inet_ntop(AF_INET6, (void *)&pr->pr_prefix, 13587c478bd9Sstevel@tonic-gate abuf, sizeof (abuf)), pr->pr_prefix_len); 13597c478bd9Sstevel@tonic-gate } 13607c478bd9Sstevel@tonic-gate /* Remove non-static prefixes from the kernel. */ 13617c478bd9Sstevel@tonic-gate pr->pr_state &= PR_STATIC; 13627c478bd9Sstevel@tonic-gate pi = pr->pr_physical; 13637c478bd9Sstevel@tonic-gate if (pr->pr_kernel_state != pr->pr_state) 13647c478bd9Sstevel@tonic-gate prefix_update_k(pr); 13657c478bd9Sstevel@tonic-gate 13667c478bd9Sstevel@tonic-gate if (pr->pr_prev == NULL) { 13677c478bd9Sstevel@tonic-gate if (pi != NULL) 13687c478bd9Sstevel@tonic-gate pi->pi_prefix_list = pr->pr_next; 13697c478bd9Sstevel@tonic-gate } else { 13707c478bd9Sstevel@tonic-gate pr->pr_prev->pr_next = pr->pr_next; 13717c478bd9Sstevel@tonic-gate } 13727c478bd9Sstevel@tonic-gate if (pr->pr_next != NULL) 13737c478bd9Sstevel@tonic-gate pr->pr_next->pr_prev = pr->pr_prev; 13747c478bd9Sstevel@tonic-gate pr->pr_next = pr->pr_prev = NULL; 13757c478bd9Sstevel@tonic-gate free(pr); 13767c478bd9Sstevel@tonic-gate } 13777c478bd9Sstevel@tonic-gate 13787c478bd9Sstevel@tonic-gate /* 13797c478bd9Sstevel@tonic-gate * Toggle one or more IFF_ flags for a prefix. Turn on 'onflags' and 13807c478bd9Sstevel@tonic-gate * turn off 'offflags'. 13817c478bd9Sstevel@tonic-gate */ 13827c478bd9Sstevel@tonic-gate static int 13837c478bd9Sstevel@tonic-gate prefix_modify_flags(struct prefix *pr, uint64_t onflags, uint64_t offflags) 13847c478bd9Sstevel@tonic-gate { 13857c478bd9Sstevel@tonic-gate struct lifreq lifr; 13867c478bd9Sstevel@tonic-gate struct phyint *pi = pr->pr_physical; 13877c478bd9Sstevel@tonic-gate uint64_t old_flags; 13887c478bd9Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 13897c478bd9Sstevel@tonic-gate 13907c478bd9Sstevel@tonic-gate if (debug & D_PREFIX) { 13917c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "prefix_modify_flags(%s, %s, %s/%u) " 13927c478bd9Sstevel@tonic-gate "flags %llx on %llx off %llx\n", 13937c478bd9Sstevel@tonic-gate pr->pr_physical->pi_name, 13947c478bd9Sstevel@tonic-gate pr->pr_name, 13957c478bd9Sstevel@tonic-gate inet_ntop(AF_INET6, (void *)&pr->pr_prefix, 13967c478bd9Sstevel@tonic-gate abuf, sizeof (abuf)), pr->pr_prefix_len, 13977c478bd9Sstevel@tonic-gate pr->pr_flags, onflags, offflags); 13987c478bd9Sstevel@tonic-gate } 13997c478bd9Sstevel@tonic-gate /* Assumes that only the PR_STATIC link-local matches the pi_name */ 14007c478bd9Sstevel@tonic-gate if (!(pr->pr_state & PR_STATIC) && 14017c478bd9Sstevel@tonic-gate strcmp(pr->pr_name, pi->pi_name) == 0) { 14027c478bd9Sstevel@tonic-gate logmsg(LOG_ERR, "prefix_modify_flags(%s, on %llx, off %llx): " 14037c478bd9Sstevel@tonic-gate "name matches interface name\n", 14047c478bd9Sstevel@tonic-gate pi->pi_name, onflags, offflags); 14057c478bd9Sstevel@tonic-gate return (-1); 14067c478bd9Sstevel@tonic-gate } 14077c478bd9Sstevel@tonic-gate 14087c478bd9Sstevel@tonic-gate (void) strncpy(lifr.lifr_name, pr->pr_name, sizeof (lifr.lifr_name)); 14097c478bd9Sstevel@tonic-gate lifr.lifr_name[sizeof (lifr.lifr_name) - 1] = '\0'; 14107c478bd9Sstevel@tonic-gate if (ioctl(pi->pi_sock, SIOCGLIFFLAGS, (char *)&lifr) < 0) { 1411*e11c3f44Smeem if (errno != ENXIO) { 1412*e11c3f44Smeem logperror_pr(pr, "prefix_modify_flags: SIOCGLIFFLAGS"); 1413*e11c3f44Smeem logmsg(LOG_ERR, "prefix_modify_flags(%s, %s) old 0x%llx" 1414*e11c3f44Smeem " on 0x%llx off 0x%llx\n", pr->pr_physical->pi_name, 1415*e11c3f44Smeem pr->pr_name, pr->pr_flags, onflags, offflags); 1416*e11c3f44Smeem } 14177c478bd9Sstevel@tonic-gate return (-1); 14187c478bd9Sstevel@tonic-gate } 14197c478bd9Sstevel@tonic-gate old_flags = lifr.lifr_flags; 14207c478bd9Sstevel@tonic-gate lifr.lifr_flags |= onflags; 14217c478bd9Sstevel@tonic-gate lifr.lifr_flags &= ~offflags; 14227c478bd9Sstevel@tonic-gate pr->pr_flags = lifr.lifr_flags; 14237c478bd9Sstevel@tonic-gate if (ioctl(pi->pi_sock, SIOCSLIFFLAGS, (char *)&lifr) < 0) { 1424*e11c3f44Smeem if (errno != ENXIO) { 1425*e11c3f44Smeem logperror_pr(pr, "prefix_modify_flags: SIOCSLIFFLAGS"); 1426*e11c3f44Smeem logmsg(LOG_ERR, "prefix_modify_flags(%s, %s) old 0x%llx" 1427*e11c3f44Smeem " new 0x%llx on 0x%llx off 0x%llx\n", 1428*e11c3f44Smeem pr->pr_physical->pi_name, pr->pr_name, 1429*e11c3f44Smeem old_flags, lifr.lifr_flags, onflags, offflags); 1430*e11c3f44Smeem } 14317c478bd9Sstevel@tonic-gate return (-1); 14327c478bd9Sstevel@tonic-gate } 14337c478bd9Sstevel@tonic-gate return (0); 1434d04ccbb3Scarlsonj } 1435d04ccbb3Scarlsonj 1436d04ccbb3Scarlsonj /* 1437d04ccbb3Scarlsonj * Update the subnet mask for this interface under DHCPv6 control. 1438d04ccbb3Scarlsonj */ 1439d04ccbb3Scarlsonj void 1440d04ccbb3Scarlsonj prefix_update_dhcp(struct prefix *pr) 1441d04ccbb3Scarlsonj { 1442d04ccbb3Scarlsonj struct lifreq lifr; 1443d04ccbb3Scarlsonj 1444d04ccbb3Scarlsonj (void) memset(&lifr, 0, sizeof (lifr)); 1445d04ccbb3Scarlsonj (void) strlcpy(lifr.lifr_name, pr->pr_name, sizeof (lifr.lifr_name)); 1446d04ccbb3Scarlsonj lifr.lifr_addr.ss_family = AF_INET6; 1447d04ccbb3Scarlsonj prefix_set(&((struct sockaddr_in6 *)&lifr.lifr_addr)->sin6_addr, 1448d04ccbb3Scarlsonj pr->pr_address, pr->pr_prefix_len); 1449d04ccbb3Scarlsonj lifr.lifr_addrlen = pr->pr_prefix_len; 1450d04ccbb3Scarlsonj /* 1451d04ccbb3Scarlsonj * Ignore ENXIO, as the dhcpagent process is responsible for plumbing 1452d04ccbb3Scarlsonj * and unplumbing these. 1453d04ccbb3Scarlsonj */ 1454d04ccbb3Scarlsonj if (ioctl(pr->pr_physical->pi_sock, SIOCSLIFSUBNET, (char *)&lifr) == 1455d04ccbb3Scarlsonj -1 && errno != ENXIO) 1456d04ccbb3Scarlsonj logperror_pr(pr, "prefix_update_dhcp: ioctl (set subnet)"); 14577c478bd9Sstevel@tonic-gate } 14587c478bd9Sstevel@tonic-gate 14597c478bd9Sstevel@tonic-gate /* 14607c478bd9Sstevel@tonic-gate * Make the kernel state match what is in the prefix structure. 14617c478bd9Sstevel@tonic-gate * This includes creating the prefix (allocating a new interface name) 14627c478bd9Sstevel@tonic-gate * as well as setting the local address and on-link subnet prefix 14637c478bd9Sstevel@tonic-gate * and controlling the IFF_ADDRCONF and IFF_DEPRECATED flags. 14647c478bd9Sstevel@tonic-gate */ 14657c478bd9Sstevel@tonic-gate void 14667c478bd9Sstevel@tonic-gate prefix_update_k(struct prefix *pr) 14677c478bd9Sstevel@tonic-gate { 14687c478bd9Sstevel@tonic-gate struct lifreq lifr; 14697c478bd9Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 14707c478bd9Sstevel@tonic-gate char buf1[PREFIX_STATESTRLEN], buf2[PREFIX_STATESTRLEN]; 14717c478bd9Sstevel@tonic-gate struct phyint *pi = pr->pr_physical; 14727c478bd9Sstevel@tonic-gate struct sockaddr_in6 *sin6; 14737c478bd9Sstevel@tonic-gate 14747c478bd9Sstevel@tonic-gate if (debug & D_PREFIX) { 14757c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "prefix_update_k(%s, %s, %s/%u) " 14767c478bd9Sstevel@tonic-gate "from %s to %s\n", pr->pr_physical->pi_name, pr->pr_name, 14777c478bd9Sstevel@tonic-gate inet_ntop(AF_INET6, (void *)&pr->pr_prefix, 14787c478bd9Sstevel@tonic-gate abuf, sizeof (abuf)), pr->pr_prefix_len, 14797c478bd9Sstevel@tonic-gate prefix_print_state(pr->pr_kernel_state, buf1, 14807c478bd9Sstevel@tonic-gate sizeof (buf1)), 14817c478bd9Sstevel@tonic-gate prefix_print_state(pr->pr_state, buf2, sizeof (buf2))); 14827c478bd9Sstevel@tonic-gate } 14837c478bd9Sstevel@tonic-gate 14847c478bd9Sstevel@tonic-gate if (pr->pr_kernel_state == pr->pr_state) 14857c478bd9Sstevel@tonic-gate return; /* No changes */ 14867c478bd9Sstevel@tonic-gate 14877c478bd9Sstevel@tonic-gate /* Skip static prefixes */ 14887c478bd9Sstevel@tonic-gate if (pr->pr_state & PR_STATIC) 14897c478bd9Sstevel@tonic-gate return; 14907c478bd9Sstevel@tonic-gate 14917c478bd9Sstevel@tonic-gate if (pr->pr_kernel_state == 0) { 14927c478bd9Sstevel@tonic-gate uint64_t onflags; 14937c478bd9Sstevel@tonic-gate /* 14947c478bd9Sstevel@tonic-gate * Create a new logical interface name and store in pr_name. 14957c478bd9Sstevel@tonic-gate * Set IFF_ADDRCONF. Do not set an address (yet). 14967c478bd9Sstevel@tonic-gate */ 14977c478bd9Sstevel@tonic-gate if (pr->pr_name[0] != '\0') { 14987c478bd9Sstevel@tonic-gate /* Name already set! */ 14997c478bd9Sstevel@tonic-gate logmsg(LOG_ERR, "prefix_update_k(%s, %s, %s/%u) " 15007c478bd9Sstevel@tonic-gate "from %s to %s name is already allocated\n", 15017c478bd9Sstevel@tonic-gate pr->pr_physical->pi_name, pr->pr_name, 15027c478bd9Sstevel@tonic-gate inet_ntop(AF_INET6, (void *)&pr->pr_prefix, 15037c478bd9Sstevel@tonic-gate abuf, sizeof (abuf)), pr->pr_prefix_len, 15047c478bd9Sstevel@tonic-gate prefix_print_state(pr->pr_kernel_state, buf1, 15057c478bd9Sstevel@tonic-gate sizeof (buf1)), 15067c478bd9Sstevel@tonic-gate prefix_print_state(pr->pr_state, buf2, 15077c478bd9Sstevel@tonic-gate sizeof (buf2))); 15087c478bd9Sstevel@tonic-gate return; 15097c478bd9Sstevel@tonic-gate } 15107c478bd9Sstevel@tonic-gate 15117c478bd9Sstevel@tonic-gate (void) strncpy(lifr.lifr_name, pi->pi_name, 15127c478bd9Sstevel@tonic-gate sizeof (lifr.lifr_name)); 15137c478bd9Sstevel@tonic-gate lifr.lifr_name[sizeof (lifr.lifr_name) - 1] = '\0'; 15147c478bd9Sstevel@tonic-gate lifr.lifr_addr.ss_family = AF_UNSPEC; 15157c478bd9Sstevel@tonic-gate if (ioctl(pi->pi_sock, SIOCLIFADDIF, (char *)&lifr) < 0) { 15167c478bd9Sstevel@tonic-gate logperror_pr(pr, "prefix_update_k: SIOCLIFADDIF"); 15177c478bd9Sstevel@tonic-gate return; 15187c478bd9Sstevel@tonic-gate } 15197c478bd9Sstevel@tonic-gate (void) strncpy(pr->pr_name, lifr.lifr_name, 15207c478bd9Sstevel@tonic-gate sizeof (pr->pr_name)); 15217c478bd9Sstevel@tonic-gate pr->pr_name[sizeof (pr->pr_name) - 1] = '\0'; 15227c478bd9Sstevel@tonic-gate if (debug & D_PREFIX) { 15237c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "prefix_update_k: new name %s\n", 15247c478bd9Sstevel@tonic-gate pr->pr_name); 15257c478bd9Sstevel@tonic-gate } 15267c478bd9Sstevel@tonic-gate /* 15277c478bd9Sstevel@tonic-gate * The IFF_TEMPORARY flag might have already been set; if 15287c478bd9Sstevel@tonic-gate * so, it needs to be or'd into the flags we're turning on. 15297c478bd9Sstevel@tonic-gate * But be careful, we might be re-creating a manually 15307c478bd9Sstevel@tonic-gate * removed interface, in which case we don't want to try 15317c478bd9Sstevel@tonic-gate * to set *all* the flags we might have in our copy of the 15327c478bd9Sstevel@tonic-gate * flags yet. 15337c478bd9Sstevel@tonic-gate */ 15347c478bd9Sstevel@tonic-gate onflags = IFF_ADDRCONF; 15357c478bd9Sstevel@tonic-gate if (pr->pr_flags & IFF_TEMPORARY) 15367c478bd9Sstevel@tonic-gate onflags |= IFF_TEMPORARY; 15377c478bd9Sstevel@tonic-gate if (prefix_modify_flags(pr, onflags, 0) == -1) 15387c478bd9Sstevel@tonic-gate return; 15397c478bd9Sstevel@tonic-gate } 15407c478bd9Sstevel@tonic-gate if ((pr->pr_state & (PR_ONLINK|PR_AUTO)) == 0) { 15417c478bd9Sstevel@tonic-gate /* Remove the interface */ 15427c478bd9Sstevel@tonic-gate if (prefix_modify_flags(pr, 0, IFF_UP|IFF_DEPRECATED) == -1) 15437c478bd9Sstevel@tonic-gate return; 15447c478bd9Sstevel@tonic-gate (void) strncpy(lifr.lifr_name, pr->pr_name, 15457c478bd9Sstevel@tonic-gate sizeof (lifr.lifr_name)); 15467c478bd9Sstevel@tonic-gate lifr.lifr_name[sizeof (lifr.lifr_name) - 1] = '\0'; 15477c478bd9Sstevel@tonic-gate 15487c478bd9Sstevel@tonic-gate if (debug & D_PREFIX) { 15497c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "prefix_update_k: remove name %s\n", 15507c478bd9Sstevel@tonic-gate pr->pr_name); 15517c478bd9Sstevel@tonic-gate } 15527c478bd9Sstevel@tonic-gate 15537c478bd9Sstevel@tonic-gate /* 15547c478bd9Sstevel@tonic-gate * Assumes that only the PR_STATIC link-local matches 15557c478bd9Sstevel@tonic-gate * the pi_name 15567c478bd9Sstevel@tonic-gate */ 15577c478bd9Sstevel@tonic-gate if (!(pr->pr_state & PR_STATIC) && 15587c478bd9Sstevel@tonic-gate strcmp(pr->pr_name, pi->pi_name) == 0) { 15597c478bd9Sstevel@tonic-gate logmsg(LOG_ERR, "prefix_update_k(%s): " 15607c478bd9Sstevel@tonic-gate "name matches if\n", pi->pi_name); 15617c478bd9Sstevel@tonic-gate return; 15627c478bd9Sstevel@tonic-gate } 15637c478bd9Sstevel@tonic-gate 15647c478bd9Sstevel@tonic-gate /* Remove logical interface based on pr_name */ 15657c478bd9Sstevel@tonic-gate lifr.lifr_addr.ss_family = AF_UNSPEC; 1566*e11c3f44Smeem if (ioctl(pi->pi_sock, SIOCLIFREMOVEIF, (char *)&lifr) < 0 && 1567*e11c3f44Smeem errno != ENXIO) { 15687c478bd9Sstevel@tonic-gate logperror_pr(pr, "prefix_update_k: SIOCLIFREMOVEIF"); 15697c478bd9Sstevel@tonic-gate } 15707c478bd9Sstevel@tonic-gate pr->pr_kernel_state = 0; 15717c478bd9Sstevel@tonic-gate pr->pr_name[0] = '\0'; 15727c478bd9Sstevel@tonic-gate return; 15737c478bd9Sstevel@tonic-gate } 15747c478bd9Sstevel@tonic-gate if ((pr->pr_state & PR_AUTO) && !(pr->pr_kernel_state & PR_AUTO)) { 15757c478bd9Sstevel@tonic-gate /* 15767c478bd9Sstevel@tonic-gate * Set local address and set the prefix length to 128. 15777c478bd9Sstevel@tonic-gate * Turn off IFF_NOLOCAL in case it was set. 15787c478bd9Sstevel@tonic-gate * Turn on IFF_UP. 15797c478bd9Sstevel@tonic-gate */ 15807c478bd9Sstevel@tonic-gate (void) strncpy(lifr.lifr_name, pr->pr_name, 15817c478bd9Sstevel@tonic-gate sizeof (lifr.lifr_name)); 15827c478bd9Sstevel@tonic-gate lifr.lifr_name[sizeof (lifr.lifr_name) - 1] = '\0'; 15837c478bd9Sstevel@tonic-gate sin6 = (struct sockaddr_in6 *)&lifr.lifr_addr; 15847c478bd9Sstevel@tonic-gate bzero(sin6, sizeof (struct sockaddr_in6)); 15857c478bd9Sstevel@tonic-gate sin6->sin6_family = AF_INET6; 15867c478bd9Sstevel@tonic-gate sin6->sin6_addr = pr->pr_address; 15877c478bd9Sstevel@tonic-gate if (debug & D_PREFIX) { 15887c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "prefix_update_k(%s) set addr %s " 15897c478bd9Sstevel@tonic-gate "for PR_AUTO on\n", 15907c478bd9Sstevel@tonic-gate pr->pr_name, 15917c478bd9Sstevel@tonic-gate inet_ntop(AF_INET6, (void *)&pr->pr_address, 1592b12d9c4eSmeem 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 if (pr->pr_state & PR_ONLINK) { 15997c478bd9Sstevel@tonic-gate sin6->sin6_addr = pr->pr_prefix; 16007c478bd9Sstevel@tonic-gate lifr.lifr_addrlen = pr->pr_prefix_len; 16017c478bd9Sstevel@tonic-gate } else { 16027c478bd9Sstevel@tonic-gate sin6->sin6_addr = pr->pr_address; 16037c478bd9Sstevel@tonic-gate lifr.lifr_addrlen = IPV6_ABITS; 16047c478bd9Sstevel@tonic-gate } 16057c478bd9Sstevel@tonic-gate if (debug & D_PREFIX) { 16067c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "prefix_update_k(%s) set subnet " 16077c478bd9Sstevel@tonic-gate "%s/%u for PR_AUTO on\n", pr->pr_name, 16087c478bd9Sstevel@tonic-gate inet_ntop(AF_INET6, (void *)&sin6->sin6_addr, 1609b12d9c4eSmeem abuf, sizeof (abuf)), lifr.lifr_addrlen); 16107c478bd9Sstevel@tonic-gate } 16117c478bd9Sstevel@tonic-gate if (ioctl(pi->pi_sock, SIOCSLIFSUBNET, (char *)&lifr) < 0) { 16127c478bd9Sstevel@tonic-gate logperror_pr(pr, "prefix_update_k: SIOCSLIFSUBNET"); 16137c478bd9Sstevel@tonic-gate return; 16147c478bd9Sstevel@tonic-gate } 16157c478bd9Sstevel@tonic-gate /* 16167c478bd9Sstevel@tonic-gate * For ptp interfaces, create a destination based on 16177c478bd9Sstevel@tonic-gate * prefix and prefix len together with the remote token 16187c478bd9Sstevel@tonic-gate * extracted from the remote pt-pt address. This is used by 16197c478bd9Sstevel@tonic-gate * ip to choose a proper source for outgoing packets. 16207c478bd9Sstevel@tonic-gate */ 16217c478bd9Sstevel@tonic-gate if (pi->pi_flags & IFF_POINTOPOINT) { 16227c478bd9Sstevel@tonic-gate int i; 16237c478bd9Sstevel@tonic-gate 16247c478bd9Sstevel@tonic-gate sin6 = (struct sockaddr_in6 *)&lifr.lifr_addr; 16257c478bd9Sstevel@tonic-gate bzero(sin6, sizeof (struct sockaddr_in6)); 16267c478bd9Sstevel@tonic-gate sin6->sin6_family = AF_INET6; 16277c478bd9Sstevel@tonic-gate sin6->sin6_addr = pr->pr_prefix; 16287c478bd9Sstevel@tonic-gate for (i = 0; i < 16; i++) { 16297c478bd9Sstevel@tonic-gate sin6->sin6_addr.s6_addr[i] |= 16307c478bd9Sstevel@tonic-gate pi->pi_dst_token.s6_addr[i]; 16317c478bd9Sstevel@tonic-gate } 16327c478bd9Sstevel@tonic-gate if (debug & D_PREFIX) { 16337c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "prefix_update_k(%s) " 16347c478bd9Sstevel@tonic-gate "set dstaddr %s for PR_AUTO on\n", 16357c478bd9Sstevel@tonic-gate pr->pr_name, inet_ntop(AF_INET6, 16367c478bd9Sstevel@tonic-gate (void *)&sin6->sin6_addr, 16377c478bd9Sstevel@tonic-gate abuf, sizeof (abuf))); 16387c478bd9Sstevel@tonic-gate } 16397c478bd9Sstevel@tonic-gate if (ioctl(pi->pi_sock, SIOCSLIFDSTADDR, 16407c478bd9Sstevel@tonic-gate (char *)&lifr) < 0) { 16417c478bd9Sstevel@tonic-gate logperror_pr(pr, 16427c478bd9Sstevel@tonic-gate "prefix_update_k: SIOCSLIFDSTADDR"); 16437c478bd9Sstevel@tonic-gate return; 16447c478bd9Sstevel@tonic-gate } 16457c478bd9Sstevel@tonic-gate } 16467c478bd9Sstevel@tonic-gate if (prefix_modify_flags(pr, IFF_UP, IFF_NOLOCAL) == -1) 16477c478bd9Sstevel@tonic-gate return; 16487c478bd9Sstevel@tonic-gate pr->pr_kernel_state |= PR_AUTO; 16497c478bd9Sstevel@tonic-gate if (pr->pr_state & PR_ONLINK) 16507c478bd9Sstevel@tonic-gate pr->pr_kernel_state |= PR_ONLINK; 16517c478bd9Sstevel@tonic-gate else 16527c478bd9Sstevel@tonic-gate pr->pr_kernel_state &= ~PR_ONLINK; 16537c478bd9Sstevel@tonic-gate } 16547c478bd9Sstevel@tonic-gate if (!(pr->pr_state & PR_AUTO) && (pr->pr_kernel_state & PR_AUTO)) { 16557c478bd9Sstevel@tonic-gate /* Turn on IFF_NOLOCAL and set the local address to all zero */ 16567c478bd9Sstevel@tonic-gate if (prefix_modify_flags(pr, IFF_NOLOCAL, 0) == -1) 16577c478bd9Sstevel@tonic-gate return; 16587c478bd9Sstevel@tonic-gate (void) strncpy(lifr.lifr_name, pr->pr_name, 16597c478bd9Sstevel@tonic-gate sizeof (lifr.lifr_name)); 16607c478bd9Sstevel@tonic-gate lifr.lifr_name[sizeof (lifr.lifr_name) - 1] = '\0'; 16617c478bd9Sstevel@tonic-gate sin6 = (struct sockaddr_in6 *)&lifr.lifr_addr; 16627c478bd9Sstevel@tonic-gate bzero(sin6, sizeof (struct sockaddr_in6)); 16637c478bd9Sstevel@tonic-gate sin6->sin6_family = AF_INET6; 16647c478bd9Sstevel@tonic-gate if (debug & D_PREFIX) { 16657c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "prefix_update_k(%s) set addr %s " 16667c478bd9Sstevel@tonic-gate "for PR_AUTO off\n", pr->pr_name, 16677c478bd9Sstevel@tonic-gate inet_ntop(AF_INET6, (void *)&sin6->sin6_addr, 1668b12d9c4eSmeem abuf, sizeof (abuf))); 16697c478bd9Sstevel@tonic-gate } 16707c478bd9Sstevel@tonic-gate if (ioctl(pi->pi_sock, SIOCSLIFADDR, (char *)&lifr) < 0) { 16717c478bd9Sstevel@tonic-gate logperror_pr(pr, "prefix_update_k: SIOCSLIFADDR"); 16727c478bd9Sstevel@tonic-gate return; 16737c478bd9Sstevel@tonic-gate } 16747c478bd9Sstevel@tonic-gate pr->pr_kernel_state &= ~PR_AUTO; 16757c478bd9Sstevel@tonic-gate } 16767c478bd9Sstevel@tonic-gate if ((pr->pr_state & PR_DEPRECATED) && 16777c478bd9Sstevel@tonic-gate !(pr->pr_kernel_state & PR_DEPRECATED) && 16787c478bd9Sstevel@tonic-gate (pr->pr_kernel_state & PR_AUTO)) { 16797c478bd9Sstevel@tonic-gate /* Only applies if PR_AUTO */ 16807c478bd9Sstevel@tonic-gate if (prefix_modify_flags(pr, IFF_DEPRECATED, 0) == -1) 16817c478bd9Sstevel@tonic-gate return; 16827c478bd9Sstevel@tonic-gate pr->pr_kernel_state |= PR_DEPRECATED; 16837c478bd9Sstevel@tonic-gate } 16847c478bd9Sstevel@tonic-gate if (!(pr->pr_state & PR_DEPRECATED) && 16857c478bd9Sstevel@tonic-gate (pr->pr_kernel_state & PR_DEPRECATED)) { 16867c478bd9Sstevel@tonic-gate if (prefix_modify_flags(pr, 0, IFF_DEPRECATED) == -1) 16877c478bd9Sstevel@tonic-gate return; 16887c478bd9Sstevel@tonic-gate pr->pr_kernel_state &= ~PR_DEPRECATED; 16897c478bd9Sstevel@tonic-gate } 16907c478bd9Sstevel@tonic-gate if ((pr->pr_state & PR_ONLINK) && !(pr->pr_kernel_state & PR_ONLINK)) { 16917c478bd9Sstevel@tonic-gate /* Set the subnet and set IFF_UP */ 16927c478bd9Sstevel@tonic-gate (void) strncpy(lifr.lifr_name, pr->pr_name, 16937c478bd9Sstevel@tonic-gate sizeof (lifr.lifr_name)); 16947c478bd9Sstevel@tonic-gate lifr.lifr_name[sizeof (lifr.lifr_name) - 1] = '\0'; 16957c478bd9Sstevel@tonic-gate sin6 = (struct sockaddr_in6 *)&lifr.lifr_addr; 16967c478bd9Sstevel@tonic-gate bzero(sin6, sizeof (struct sockaddr_in6)); 16977c478bd9Sstevel@tonic-gate sin6->sin6_family = AF_INET6; 16987c478bd9Sstevel@tonic-gate sin6->sin6_addr = pr->pr_prefix; 16997c478bd9Sstevel@tonic-gate lifr.lifr_addrlen = pr->pr_prefix_len; 17007c478bd9Sstevel@tonic-gate if (debug & D_PREFIX) { 17017c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "prefix_update_k(%s) set subnet " 17027c478bd9Sstevel@tonic-gate "%s/%d for PR_ONLINK on\n", pr->pr_name, 17037c478bd9Sstevel@tonic-gate inet_ntop(AF_INET6, (void *)&sin6->sin6_addr, 1704b12d9c4eSmeem abuf, sizeof (abuf)), lifr.lifr_addrlen); 17057c478bd9Sstevel@tonic-gate } 17067c478bd9Sstevel@tonic-gate if (ioctl(pi->pi_sock, SIOCSLIFSUBNET, (char *)&lifr) < 0) { 17077c478bd9Sstevel@tonic-gate logperror_pr(pr, "prefix_update_k: SIOCSLIFSUBNET"); 17087c478bd9Sstevel@tonic-gate return; 17097c478bd9Sstevel@tonic-gate } 1710686c2681Scarlsonj /* 1711686c2681Scarlsonj * If we've previously marked the interface "up" while 1712686c2681Scarlsonj * processing the PR_AUTO flag -- via incoming_prefix_addrconf 1713686c2681Scarlsonj * -- then there's no need to set it "up" again. We're done; 1714686c2681Scarlsonj * just set PR_ONLINK to indicate that we've set the subnet. 1715686c2681Scarlsonj */ 1716686c2681Scarlsonj if (!(pr->pr_state & PR_AUTO) && 1717686c2681Scarlsonj prefix_modify_flags(pr, IFF_UP | IFF_NOLOCAL, 0) == -1) 17187c478bd9Sstevel@tonic-gate return; 17197c478bd9Sstevel@tonic-gate pr->pr_kernel_state |= PR_ONLINK; 17207c478bd9Sstevel@tonic-gate } 17217c478bd9Sstevel@tonic-gate if (!(pr->pr_state & PR_ONLINK) && (pr->pr_kernel_state & PR_ONLINK)) { 17227c478bd9Sstevel@tonic-gate /* Set the prefixlen to 128 */ 17237c478bd9Sstevel@tonic-gate (void) strncpy(lifr.lifr_name, pr->pr_name, 17247c478bd9Sstevel@tonic-gate sizeof (lifr.lifr_name)); 17257c478bd9Sstevel@tonic-gate lifr.lifr_name[sizeof (lifr.lifr_name) - 1] = '\0'; 17267c478bd9Sstevel@tonic-gate sin6 = (struct sockaddr_in6 *)&lifr.lifr_addr; 17277c478bd9Sstevel@tonic-gate bzero(sin6, sizeof (struct sockaddr_in6)); 17287c478bd9Sstevel@tonic-gate sin6->sin6_family = AF_INET6; 17297c478bd9Sstevel@tonic-gate sin6->sin6_addr = pr->pr_address; 17307c478bd9Sstevel@tonic-gate lifr.lifr_addrlen = IPV6_ABITS; 17317c478bd9Sstevel@tonic-gate if (debug & D_PREFIX) { 17327c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "prefix_update_k(%s) set subnet " 17337c478bd9Sstevel@tonic-gate "%s/%d for PR_ONLINK off\n", pr->pr_name, 17347c478bd9Sstevel@tonic-gate inet_ntop(AF_INET6, (void *)&sin6->sin6_addr, 1735b12d9c4eSmeem abuf, sizeof (abuf)), lifr.lifr_addrlen); 17367c478bd9Sstevel@tonic-gate } 17377c478bd9Sstevel@tonic-gate if (ioctl(pi->pi_sock, SIOCSLIFSUBNET, (char *)&lifr) < 0) { 17387c478bd9Sstevel@tonic-gate logperror_pr(pr, "prefix_update_k: SIOCSLIFSUBNET"); 17397c478bd9Sstevel@tonic-gate return; 17407c478bd9Sstevel@tonic-gate } 17417c478bd9Sstevel@tonic-gate pr->pr_kernel_state &= ~PR_ONLINK; 17427c478bd9Sstevel@tonic-gate } 17437c478bd9Sstevel@tonic-gate } 17447c478bd9Sstevel@tonic-gate 17457c478bd9Sstevel@tonic-gate /* 17467c478bd9Sstevel@tonic-gate * Called with the number of millseconds elapsed since the last call. 17477c478bd9Sstevel@tonic-gate * Determines if any timeout event has occurred and 17487c478bd9Sstevel@tonic-gate * returns the number of milliseconds until the next timeout event. 17497c478bd9Sstevel@tonic-gate * Returns TIMER_INFINITY for "never". 17507c478bd9Sstevel@tonic-gate */ 17517c478bd9Sstevel@tonic-gate uint_t 17527c478bd9Sstevel@tonic-gate prefix_timer(struct prefix *pr, uint_t elapsed) 17537c478bd9Sstevel@tonic-gate { 17547c478bd9Sstevel@tonic-gate uint_t next = TIMER_INFINITY; 17557c478bd9Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 17567c478bd9Sstevel@tonic-gate 17577c478bd9Sstevel@tonic-gate if (debug & (D_PREFIX|D_TMP)) { 17587c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "prefix_timer(%s, %s/%u, %d) " 17597c478bd9Sstevel@tonic-gate "valid %d pref %d onlink %d\n", 17607c478bd9Sstevel@tonic-gate pr->pr_name, 17617c478bd9Sstevel@tonic-gate inet_ntop(AF_INET6, (void *)&pr->pr_prefix, 17627c478bd9Sstevel@tonic-gate abuf, sizeof (abuf)), pr->pr_prefix_len, 17637c478bd9Sstevel@tonic-gate elapsed, pr->pr_ValidLifetime, pr->pr_PreferredLifetime, 17647c478bd9Sstevel@tonic-gate pr->pr_OnLinkLifetime); 17657c478bd9Sstevel@tonic-gate } 17667c478bd9Sstevel@tonic-gate 17677c478bd9Sstevel@tonic-gate /* Exclude static prefixes */ 17687c478bd9Sstevel@tonic-gate if (pr->pr_state & PR_STATIC) 17697c478bd9Sstevel@tonic-gate return (next); 17707c478bd9Sstevel@tonic-gate 17717c478bd9Sstevel@tonic-gate if (pr->pr_AutonomousFlag && 17727c478bd9Sstevel@tonic-gate (pr->pr_PreferredLifetime != PREFIX_INFINITY)) { 17737c478bd9Sstevel@tonic-gate if (pr->pr_PreferredLifetime <= elapsed) { 17747c478bd9Sstevel@tonic-gate pr->pr_PreferredLifetime = 0; 17757c478bd9Sstevel@tonic-gate } else { 17767c478bd9Sstevel@tonic-gate pr->pr_PreferredLifetime -= elapsed; 17777c478bd9Sstevel@tonic-gate if (pr->pr_PreferredLifetime < next) 17787c478bd9Sstevel@tonic-gate next = pr->pr_PreferredLifetime; 17797c478bd9Sstevel@tonic-gate } 17807c478bd9Sstevel@tonic-gate } 17817c478bd9Sstevel@tonic-gate if (pr->pr_AutonomousFlag && 17827c478bd9Sstevel@tonic-gate (pr->pr_ValidLifetime != PREFIX_INFINITY)) { 17837c478bd9Sstevel@tonic-gate if (pr->pr_ValidLifetime <= elapsed) { 17847c478bd9Sstevel@tonic-gate pr->pr_ValidLifetime = 0; 17857c478bd9Sstevel@tonic-gate } else { 17867c478bd9Sstevel@tonic-gate pr->pr_ValidLifetime -= elapsed; 17877c478bd9Sstevel@tonic-gate if (pr->pr_ValidLifetime < next) 17887c478bd9Sstevel@tonic-gate next = pr->pr_ValidLifetime; 17897c478bd9Sstevel@tonic-gate } 17907c478bd9Sstevel@tonic-gate } 17917c478bd9Sstevel@tonic-gate if (pr->pr_OnLinkFlag && 17927c478bd9Sstevel@tonic-gate (pr->pr_OnLinkLifetime != PREFIX_INFINITY)) { 17937c478bd9Sstevel@tonic-gate if (pr->pr_OnLinkLifetime <= elapsed) { 17947c478bd9Sstevel@tonic-gate pr->pr_OnLinkLifetime = 0; 17957c478bd9Sstevel@tonic-gate } else { 17967c478bd9Sstevel@tonic-gate pr->pr_OnLinkLifetime -= elapsed; 17977c478bd9Sstevel@tonic-gate if (pr->pr_OnLinkLifetime < next) 17987c478bd9Sstevel@tonic-gate next = pr->pr_OnLinkLifetime; 17997c478bd9Sstevel@tonic-gate } 18007c478bd9Sstevel@tonic-gate } 18017c478bd9Sstevel@tonic-gate if (pr->pr_AutonomousFlag && pr->pr_ValidLifetime == 0) 18027c478bd9Sstevel@tonic-gate pr->pr_state &= ~(PR_AUTO|PR_DEPRECATED); 18037c478bd9Sstevel@tonic-gate if (pr->pr_AutonomousFlag && pr->pr_PreferredLifetime == 0 && 18047c478bd9Sstevel@tonic-gate (pr->pr_state & PR_AUTO)) { 18057c478bd9Sstevel@tonic-gate pr->pr_state |= PR_DEPRECATED; 18067c478bd9Sstevel@tonic-gate if (debug & D_TMP) 18077c478bd9Sstevel@tonic-gate logmsg(LOG_WARNING, "prefix_timer: deprecated " 18087c478bd9Sstevel@tonic-gate "prefix(%s)\n", pr->pr_name); 18097c478bd9Sstevel@tonic-gate } 18107c478bd9Sstevel@tonic-gate if (pr->pr_OnLinkFlag && pr->pr_OnLinkLifetime == 0) 18117c478bd9Sstevel@tonic-gate pr->pr_state &= ~PR_ONLINK; 18127c478bd9Sstevel@tonic-gate 18137c478bd9Sstevel@tonic-gate if (pr->pr_state != pr->pr_kernel_state) { 18147c478bd9Sstevel@tonic-gate /* Might cause prefix to be deleted! */ 18157c478bd9Sstevel@tonic-gate 18167c478bd9Sstevel@tonic-gate /* Log a message when an addrconf prefix goes away */ 18177c478bd9Sstevel@tonic-gate if ((pr->pr_kernel_state & PR_AUTO) && 18187c478bd9Sstevel@tonic-gate !(pr->pr_state & PR_AUTO)) { 18197c478bd9Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 18207c478bd9Sstevel@tonic-gate 18217c478bd9Sstevel@tonic-gate logmsg(LOG_WARNING, 18227c478bd9Sstevel@tonic-gate "Address removed due to timeout %s\n", 18237c478bd9Sstevel@tonic-gate inet_ntop(AF_INET6, (void *)&pr->pr_address, 18247c478bd9Sstevel@tonic-gate abuf, sizeof (abuf))); 18257c478bd9Sstevel@tonic-gate } 18267c478bd9Sstevel@tonic-gate prefix_update_k(pr); 18277c478bd9Sstevel@tonic-gate } 18287c478bd9Sstevel@tonic-gate 18297c478bd9Sstevel@tonic-gate return (next); 18307c478bd9Sstevel@tonic-gate } 18317c478bd9Sstevel@tonic-gate 18327c478bd9Sstevel@tonic-gate static char * 18337c478bd9Sstevel@tonic-gate prefix_print_state(int state, char *buf, int buflen) 18347c478bd9Sstevel@tonic-gate { 18357c478bd9Sstevel@tonic-gate char *cp; 18367c478bd9Sstevel@tonic-gate int cplen = buflen; 18377c478bd9Sstevel@tonic-gate 18387c478bd9Sstevel@tonic-gate cp = buf; 18397c478bd9Sstevel@tonic-gate cp[0] = '\0'; 18407c478bd9Sstevel@tonic-gate 18417c478bd9Sstevel@tonic-gate if (state & PR_ONLINK) { 18427c478bd9Sstevel@tonic-gate if (strlcat(cp, "ONLINK ", cplen) >= cplen) 18437c478bd9Sstevel@tonic-gate return (buf); 18447c478bd9Sstevel@tonic-gate cp += strlen(cp); 18457c478bd9Sstevel@tonic-gate cplen = buflen - (cp - buf); 18467c478bd9Sstevel@tonic-gate } 18477c478bd9Sstevel@tonic-gate if (state & PR_AUTO) { 18487c478bd9Sstevel@tonic-gate if (strlcat(cp, "AUTO ", cplen) >= cplen) 18497c478bd9Sstevel@tonic-gate return (buf); 18507c478bd9Sstevel@tonic-gate cp += strlen(cp); 18517c478bd9Sstevel@tonic-gate cplen = buflen - (cp - buf); 18527c478bd9Sstevel@tonic-gate } 18537c478bd9Sstevel@tonic-gate if (state & PR_DEPRECATED) { 18547c478bd9Sstevel@tonic-gate if (strlcat(cp, "DEPRECATED ", cplen) >= cplen) 18557c478bd9Sstevel@tonic-gate return (buf); 18567c478bd9Sstevel@tonic-gate cp += strlen(cp); 18577c478bd9Sstevel@tonic-gate cplen = buflen - (cp - buf); 18587c478bd9Sstevel@tonic-gate } 18597c478bd9Sstevel@tonic-gate if (state & PR_STATIC) { 18607c478bd9Sstevel@tonic-gate if (strlcat(cp, "STATIC ", cplen) >= cplen) 18617c478bd9Sstevel@tonic-gate return (buf); 18627c478bd9Sstevel@tonic-gate cp += strlen(cp); 18637c478bd9Sstevel@tonic-gate cplen = buflen - (cp - buf); 18647c478bd9Sstevel@tonic-gate } 18657c478bd9Sstevel@tonic-gate return (buf); 18667c478bd9Sstevel@tonic-gate } 18677c478bd9Sstevel@tonic-gate 18687c478bd9Sstevel@tonic-gate static void 18697c478bd9Sstevel@tonic-gate prefix_print(struct prefix *pr) 18707c478bd9Sstevel@tonic-gate { 18717c478bd9Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 18727c478bd9Sstevel@tonic-gate char buf1[PREFIX_STATESTRLEN], buf2[PREFIX_STATESTRLEN]; 18737c478bd9Sstevel@tonic-gate 18747c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "Prefix name: %s prefix %s/%u state %s " 18757c478bd9Sstevel@tonic-gate "kernel_state %s\n", pr->pr_name, 18767c478bd9Sstevel@tonic-gate inet_ntop(AF_INET6, (void *)&pr->pr_prefix, abuf, sizeof (abuf)), 18777c478bd9Sstevel@tonic-gate pr->pr_prefix_len, 18787c478bd9Sstevel@tonic-gate prefix_print_state(pr->pr_state, buf2, sizeof (buf2)), 18797c478bd9Sstevel@tonic-gate prefix_print_state(pr->pr_kernel_state, buf1, sizeof (buf1))); 18807c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "\tAddress: %s flags %llx in_use %d\n", 18817c478bd9Sstevel@tonic-gate inet_ntop(AF_INET6, (void *)&pr->pr_address, abuf, sizeof (abuf)), 18827c478bd9Sstevel@tonic-gate pr->pr_flags, pr->pr_in_use); 18837c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "\tValidLifetime %u PreferredLifetime %u " 18847c478bd9Sstevel@tonic-gate "OnLinkLifetime %u\n", pr->pr_ValidLifetime, 18857c478bd9Sstevel@tonic-gate pr->pr_PreferredLifetime, pr->pr_OnLinkLifetime); 18867c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "\tOnLink %d Auto %d\n", 18877c478bd9Sstevel@tonic-gate pr->pr_OnLinkFlag, pr->pr_AutonomousFlag); 18887c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "\n"); 18897c478bd9Sstevel@tonic-gate } 18907c478bd9Sstevel@tonic-gate 18917c478bd9Sstevel@tonic-gate /* 18927c478bd9Sstevel@tonic-gate * Lookup advertisement prefix structure that matches the prefix and 18937c478bd9Sstevel@tonic-gate * prefix length. 18947c478bd9Sstevel@tonic-gate * Assumes that the bits after prefixlen might not be zero. 18957c478bd9Sstevel@tonic-gate */ 18967c478bd9Sstevel@tonic-gate struct adv_prefix * 18977c478bd9Sstevel@tonic-gate adv_prefix_lookup(struct phyint *pi, struct in6_addr prefix, int prefixlen) 18987c478bd9Sstevel@tonic-gate { 18997c478bd9Sstevel@tonic-gate struct adv_prefix *adv_pr; 19007c478bd9Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 19017c478bd9Sstevel@tonic-gate 19027c478bd9Sstevel@tonic-gate if (debug & D_PREFIX) { 19037c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "adv_prefix_lookup(%s, %s/%u)\n", 19047c478bd9Sstevel@tonic-gate pi->pi_name, inet_ntop(AF_INET6, (void *)&prefix, 19057c478bd9Sstevel@tonic-gate abuf, sizeof (abuf)), prefixlen); 19067c478bd9Sstevel@tonic-gate } 19077c478bd9Sstevel@tonic-gate 19087c478bd9Sstevel@tonic-gate for (adv_pr = pi->pi_adv_prefix_list; adv_pr != NULL; 19097c478bd9Sstevel@tonic-gate adv_pr = adv_pr->adv_pr_next) { 19107c478bd9Sstevel@tonic-gate if (adv_pr->adv_pr_prefix_len == prefixlen && 19117c478bd9Sstevel@tonic-gate prefix_equal(prefix, adv_pr->adv_pr_prefix, prefixlen)) 19127c478bd9Sstevel@tonic-gate return (adv_pr); 19137c478bd9Sstevel@tonic-gate } 19147c478bd9Sstevel@tonic-gate return (NULL); 19157c478bd9Sstevel@tonic-gate } 19167c478bd9Sstevel@tonic-gate 19177c478bd9Sstevel@tonic-gate /* 19187c478bd9Sstevel@tonic-gate * Initialize a new advertisement prefix. 19197c478bd9Sstevel@tonic-gate */ 19207c478bd9Sstevel@tonic-gate struct adv_prefix * 19217c478bd9Sstevel@tonic-gate adv_prefix_create(struct phyint *pi, struct in6_addr prefix, int prefixlen) 19227c478bd9Sstevel@tonic-gate { 19237c478bd9Sstevel@tonic-gate struct adv_prefix *adv_pr; 19247c478bd9Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 19257c478bd9Sstevel@tonic-gate 19267c478bd9Sstevel@tonic-gate if (debug & D_PREFIX) { 19277c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "adv_prefix_create(%s, %s/%u)\n", 19287c478bd9Sstevel@tonic-gate pi->pi_name, inet_ntop(AF_INET6, (void *)&prefix, 19297c478bd9Sstevel@tonic-gate abuf, sizeof (abuf)), prefixlen); 19307c478bd9Sstevel@tonic-gate } 19317c478bd9Sstevel@tonic-gate adv_pr = (struct adv_prefix *)calloc(sizeof (struct adv_prefix), 1); 19327c478bd9Sstevel@tonic-gate if (adv_pr == NULL) { 19337c478bd9Sstevel@tonic-gate logmsg(LOG_ERR, "adv_prefix_create: calloc\n"); 19347c478bd9Sstevel@tonic-gate return (NULL); 19357c478bd9Sstevel@tonic-gate } 19367c478bd9Sstevel@tonic-gate /* 19377c478bd9Sstevel@tonic-gate * The prefix might have non-zero bits after the prefix len bits. 19387c478bd9Sstevel@tonic-gate * Force them to be zero. 19397c478bd9Sstevel@tonic-gate */ 19407c478bd9Sstevel@tonic-gate prefix_set(&adv_pr->adv_pr_prefix, prefix, prefixlen); 19417c478bd9Sstevel@tonic-gate adv_pr->adv_pr_prefix_len = prefixlen; 19427c478bd9Sstevel@tonic-gate adv_prefix_insert(pi, adv_pr); 19437c478bd9Sstevel@tonic-gate return (adv_pr); 19447c478bd9Sstevel@tonic-gate } 19457c478bd9Sstevel@tonic-gate 19467c478bd9Sstevel@tonic-gate /* Insert in linked list */ 19477c478bd9Sstevel@tonic-gate static void 19487c478bd9Sstevel@tonic-gate adv_prefix_insert(struct phyint *pi, struct adv_prefix *adv_pr) 19497c478bd9Sstevel@tonic-gate { 19507c478bd9Sstevel@tonic-gate adv_pr->adv_pr_next = pi->pi_adv_prefix_list; 19517c478bd9Sstevel@tonic-gate adv_pr->adv_pr_prev = NULL; 19527c478bd9Sstevel@tonic-gate if (pi->pi_adv_prefix_list != NULL) 19537c478bd9Sstevel@tonic-gate pi->pi_adv_prefix_list->adv_pr_prev = adv_pr; 19547c478bd9Sstevel@tonic-gate pi->pi_adv_prefix_list = adv_pr; 19557c478bd9Sstevel@tonic-gate adv_pr->adv_pr_physical = pi; 19567c478bd9Sstevel@tonic-gate } 19577c478bd9Sstevel@tonic-gate 19587c478bd9Sstevel@tonic-gate /* 19597c478bd9Sstevel@tonic-gate * Delete (unlink and free) from our tables. There should be 19607c478bd9Sstevel@tonic-gate * a corresponding "struct prefix *" which will clean up the kernel 19617c478bd9Sstevel@tonic-gate * if necessary. adv_prefix is just used for sending out advertisements. 19627c478bd9Sstevel@tonic-gate */ 19637c478bd9Sstevel@tonic-gate static void 19647c478bd9Sstevel@tonic-gate adv_prefix_delete(struct adv_prefix *adv_pr) 19657c478bd9Sstevel@tonic-gate { 19667c478bd9Sstevel@tonic-gate struct phyint *pi; 19677c478bd9Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 19687c478bd9Sstevel@tonic-gate 19697c478bd9Sstevel@tonic-gate if (debug & D_PREFIX) { 19707c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "adv_prefix_delete(%s, %s/%u)\n", 19717c478bd9Sstevel@tonic-gate adv_pr->adv_pr_physical->pi_name, 19727c478bd9Sstevel@tonic-gate inet_ntop(AF_INET6, (void *)&adv_pr->adv_pr_prefix, 19737c478bd9Sstevel@tonic-gate abuf, sizeof (abuf)), adv_pr->adv_pr_prefix_len); 19747c478bd9Sstevel@tonic-gate } 19757c478bd9Sstevel@tonic-gate pi = adv_pr->adv_pr_physical; 19767c478bd9Sstevel@tonic-gate 19777c478bd9Sstevel@tonic-gate if (adv_pr->adv_pr_prev == NULL) { 19787c478bd9Sstevel@tonic-gate if (pi != NULL) 19797c478bd9Sstevel@tonic-gate pi->pi_adv_prefix_list = adv_pr->adv_pr_next; 19807c478bd9Sstevel@tonic-gate } else { 19817c478bd9Sstevel@tonic-gate adv_pr->adv_pr_prev->adv_pr_next = adv_pr->adv_pr_next; 19827c478bd9Sstevel@tonic-gate } 19837c478bd9Sstevel@tonic-gate if (adv_pr->adv_pr_next != NULL) 19847c478bd9Sstevel@tonic-gate adv_pr->adv_pr_next->adv_pr_prev = adv_pr->adv_pr_prev; 19857c478bd9Sstevel@tonic-gate adv_pr->adv_pr_next = adv_pr->adv_pr_prev = NULL; 19867c478bd9Sstevel@tonic-gate free(adv_pr); 19877c478bd9Sstevel@tonic-gate } 19887c478bd9Sstevel@tonic-gate 19897c478bd9Sstevel@tonic-gate /* 19907c478bd9Sstevel@tonic-gate * Called with the number of millseconds elapsed since the last call. 19917c478bd9Sstevel@tonic-gate * Determines if any timeout event has occurred and 19927c478bd9Sstevel@tonic-gate * returns the number of milliseconds until the next timeout event. 19937c478bd9Sstevel@tonic-gate * Returns TIMER_INFINITY for "never". 19947c478bd9Sstevel@tonic-gate */ 19957c478bd9Sstevel@tonic-gate uint_t 19967c478bd9Sstevel@tonic-gate adv_prefix_timer(struct adv_prefix *adv_pr, uint_t elapsed) 19977c478bd9Sstevel@tonic-gate { 19987c478bd9Sstevel@tonic-gate int seconds_elapsed = (elapsed + 500) / 1000; /* Rounded */ 19997c478bd9Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 20007c478bd9Sstevel@tonic-gate 20017c478bd9Sstevel@tonic-gate if (debug & D_PREFIX) { 20027c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "adv_prefix_timer(%s, %s/%u, %d)\n", 20037c478bd9Sstevel@tonic-gate adv_pr->adv_pr_physical->pi_name, 20047c478bd9Sstevel@tonic-gate inet_ntop(AF_INET6, (void *)&adv_pr->adv_pr_prefix, 20057c478bd9Sstevel@tonic-gate abuf, sizeof (abuf)), adv_pr->adv_pr_prefix_len, 20067c478bd9Sstevel@tonic-gate elapsed); 20077c478bd9Sstevel@tonic-gate } 20087c478bd9Sstevel@tonic-gate 20097c478bd9Sstevel@tonic-gate /* Decrement Expire time left for real-time lifetimes */ 20107c478bd9Sstevel@tonic-gate if (adv_pr->adv_pr_AdvValidRealTime) { 20117c478bd9Sstevel@tonic-gate if (adv_pr->adv_pr_AdvValidExpiration > seconds_elapsed) 20127c478bd9Sstevel@tonic-gate adv_pr->adv_pr_AdvValidExpiration -= seconds_elapsed; 20137c478bd9Sstevel@tonic-gate else 20147c478bd9Sstevel@tonic-gate adv_pr->adv_pr_AdvValidExpiration = 0; 20157c478bd9Sstevel@tonic-gate } 20167c478bd9Sstevel@tonic-gate if (adv_pr->adv_pr_AdvPreferredRealTime) { 20177c478bd9Sstevel@tonic-gate if (adv_pr->adv_pr_AdvPreferredExpiration > seconds_elapsed) { 20187c478bd9Sstevel@tonic-gate adv_pr->adv_pr_AdvPreferredExpiration -= 20197c478bd9Sstevel@tonic-gate seconds_elapsed; 20207c478bd9Sstevel@tonic-gate } else { 20217c478bd9Sstevel@tonic-gate adv_pr->adv_pr_AdvPreferredExpiration = 0; 20227c478bd9Sstevel@tonic-gate } 20237c478bd9Sstevel@tonic-gate } 20247c478bd9Sstevel@tonic-gate return (TIMER_INFINITY); 20257c478bd9Sstevel@tonic-gate } 20267c478bd9Sstevel@tonic-gate 20277c478bd9Sstevel@tonic-gate static void 20287c478bd9Sstevel@tonic-gate adv_prefix_print(struct adv_prefix *adv_pr) 20297c478bd9Sstevel@tonic-gate { 20307c478bd9Sstevel@tonic-gate print_prefixlist(adv_pr->adv_pr_config); 20317c478bd9Sstevel@tonic-gate } 20327c478bd9Sstevel@tonic-gate 20337c478bd9Sstevel@tonic-gate /* Lookup router on its link-local IPv6 address */ 20347c478bd9Sstevel@tonic-gate struct router * 20357c478bd9Sstevel@tonic-gate router_lookup(struct phyint *pi, struct in6_addr addr) 20367c478bd9Sstevel@tonic-gate { 20377c478bd9Sstevel@tonic-gate struct router *dr; 20387c478bd9Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 20397c478bd9Sstevel@tonic-gate 20407c478bd9Sstevel@tonic-gate if (debug & D_ROUTER) { 20417c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "router_lookup(%s, %s)\n", pi->pi_name, 20427c478bd9Sstevel@tonic-gate inet_ntop(AF_INET6, (void *)&addr, 20437c478bd9Sstevel@tonic-gate abuf, sizeof (abuf))); 20447c478bd9Sstevel@tonic-gate } 20457c478bd9Sstevel@tonic-gate 20467c478bd9Sstevel@tonic-gate for (dr = pi->pi_router_list; dr != NULL; dr = dr->dr_next) { 20477c478bd9Sstevel@tonic-gate if (bcmp((char *)&addr, (char *)&dr->dr_address, 20487c478bd9Sstevel@tonic-gate sizeof (addr)) == 0) 20497c478bd9Sstevel@tonic-gate return (dr); 20507c478bd9Sstevel@tonic-gate } 20517c478bd9Sstevel@tonic-gate return (NULL); 20527c478bd9Sstevel@tonic-gate } 20537c478bd9Sstevel@tonic-gate 20547c478bd9Sstevel@tonic-gate /* 20557c478bd9Sstevel@tonic-gate * Create a default router entry. 20567c478bd9Sstevel@tonic-gate * The lifetime parameter is in seconds. 20577c478bd9Sstevel@tonic-gate */ 20587c478bd9Sstevel@tonic-gate struct router * 20597c478bd9Sstevel@tonic-gate router_create(struct phyint *pi, struct in6_addr addr, uint_t lifetime) 20607c478bd9Sstevel@tonic-gate { 20617c478bd9Sstevel@tonic-gate struct router *dr; 20627c478bd9Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 20637c478bd9Sstevel@tonic-gate 20647c478bd9Sstevel@tonic-gate if (debug & D_ROUTER) { 20657c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "router_create(%s, %s, %u)\n", pi->pi_name, 20667c478bd9Sstevel@tonic-gate inet_ntop(AF_INET6, (void *)&addr, 20677c478bd9Sstevel@tonic-gate abuf, sizeof (abuf)), lifetime); 20687c478bd9Sstevel@tonic-gate } 20697c478bd9Sstevel@tonic-gate 20707c478bd9Sstevel@tonic-gate dr = (struct router *)calloc(sizeof (struct router), 1); 20717c478bd9Sstevel@tonic-gate if (dr == NULL) { 20727c478bd9Sstevel@tonic-gate logmsg(LOG_ERR, "router_create: out of memory\n"); 20737c478bd9Sstevel@tonic-gate return (NULL); 20747c478bd9Sstevel@tonic-gate } 20757c478bd9Sstevel@tonic-gate dr->dr_address = addr; 20767c478bd9Sstevel@tonic-gate dr->dr_lifetime = lifetime; 20777c478bd9Sstevel@tonic-gate router_insert(pi, dr); 20788121d73fSseb if (dr->dr_lifetime != 0) 20797c478bd9Sstevel@tonic-gate router_add_k(dr); 20807c478bd9Sstevel@tonic-gate return (dr); 20817c478bd9Sstevel@tonic-gate } 20827c478bd9Sstevel@tonic-gate 20837c478bd9Sstevel@tonic-gate /* Insert in linked list */ 20847c478bd9Sstevel@tonic-gate static void 20857c478bd9Sstevel@tonic-gate router_insert(struct phyint *pi, struct router *dr) 20867c478bd9Sstevel@tonic-gate { 20877c478bd9Sstevel@tonic-gate dr->dr_next = pi->pi_router_list; 20887c478bd9Sstevel@tonic-gate dr->dr_prev = NULL; 20897c478bd9Sstevel@tonic-gate if (pi->pi_router_list != NULL) 20907c478bd9Sstevel@tonic-gate pi->pi_router_list->dr_prev = dr; 20917c478bd9Sstevel@tonic-gate pi->pi_router_list = dr; 20927c478bd9Sstevel@tonic-gate dr->dr_physical = pi; 20937c478bd9Sstevel@tonic-gate } 20947c478bd9Sstevel@tonic-gate 20957c478bd9Sstevel@tonic-gate /* 20967c478bd9Sstevel@tonic-gate * Delete (unlink and free). 20977c478bd9Sstevel@tonic-gate * Handles delete of things that have not yet been inserted in the list 20987c478bd9Sstevel@tonic-gate * i.e. dr_physical is NULL. 20997c478bd9Sstevel@tonic-gate */ 21007c478bd9Sstevel@tonic-gate static void 21017c478bd9Sstevel@tonic-gate router_delete(struct router *dr) 21027c478bd9Sstevel@tonic-gate { 21037c478bd9Sstevel@tonic-gate struct phyint *pi; 21047c478bd9Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 21057c478bd9Sstevel@tonic-gate 21067c478bd9Sstevel@tonic-gate if (debug & D_ROUTER) { 21077c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "router_delete(%s, %s, %u)\n", 21087c478bd9Sstevel@tonic-gate dr->dr_physical->pi_name, 21097c478bd9Sstevel@tonic-gate inet_ntop(AF_INET6, (void *)&dr->dr_address, 21107c478bd9Sstevel@tonic-gate abuf, sizeof (abuf)), dr->dr_lifetime); 21117c478bd9Sstevel@tonic-gate } 21127c478bd9Sstevel@tonic-gate pi = dr->dr_physical; 21138121d73fSseb if (dr->dr_inkernel && (pi->pi_kernel_state & PI_PRESENT)) 21148121d73fSseb router_delete_k(dr); 21157c478bd9Sstevel@tonic-gate 21167c478bd9Sstevel@tonic-gate if (dr->dr_prev == NULL) { 21177c478bd9Sstevel@tonic-gate if (pi != NULL) 21187c478bd9Sstevel@tonic-gate pi->pi_router_list = dr->dr_next; 21197c478bd9Sstevel@tonic-gate } else { 21207c478bd9Sstevel@tonic-gate dr->dr_prev->dr_next = dr->dr_next; 21217c478bd9Sstevel@tonic-gate } 21227c478bd9Sstevel@tonic-gate if (dr->dr_next != NULL) 21237c478bd9Sstevel@tonic-gate dr->dr_next->dr_prev = dr->dr_prev; 21247c478bd9Sstevel@tonic-gate dr->dr_next = dr->dr_prev = NULL; 21257c478bd9Sstevel@tonic-gate free(dr); 21267c478bd9Sstevel@tonic-gate } 21277c478bd9Sstevel@tonic-gate 21287c478bd9Sstevel@tonic-gate /* 21297c478bd9Sstevel@tonic-gate * Update the kernel to match dr_lifetime 21307c478bd9Sstevel@tonic-gate */ 21317c478bd9Sstevel@tonic-gate void 21327c478bd9Sstevel@tonic-gate router_update_k(struct router *dr) 21337c478bd9Sstevel@tonic-gate { 21347c478bd9Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 21357c478bd9Sstevel@tonic-gate 21367c478bd9Sstevel@tonic-gate if (debug & D_ROUTER) { 21377c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "router_update_k(%s, %s, %u)\n", 21387c478bd9Sstevel@tonic-gate dr->dr_physical->pi_name, 21397c478bd9Sstevel@tonic-gate inet_ntop(AF_INET6, (void *)&dr->dr_address, 21407c478bd9Sstevel@tonic-gate abuf, sizeof (abuf)), dr->dr_lifetime); 21417c478bd9Sstevel@tonic-gate } 21427c478bd9Sstevel@tonic-gate 21437c478bd9Sstevel@tonic-gate if (dr->dr_lifetime == 0 && dr->dr_inkernel) { 21447c478bd9Sstevel@tonic-gate /* Log a message when last router goes away */ 21457c478bd9Sstevel@tonic-gate if (dr->dr_physical->pi_num_k_routers == 1) { 21467c478bd9Sstevel@tonic-gate logmsg(LOG_WARNING, 21477c478bd9Sstevel@tonic-gate "Last default router (%s) removed on %s\n", 21487c478bd9Sstevel@tonic-gate inet_ntop(AF_INET6, (void *)&dr->dr_address, 21497c478bd9Sstevel@tonic-gate abuf, sizeof (abuf)), dr->dr_physical->pi_name); 21507c478bd9Sstevel@tonic-gate } 21517c478bd9Sstevel@tonic-gate router_delete(dr); 21528121d73fSseb } else if (dr->dr_lifetime != 0 && !dr->dr_inkernel) 21537c478bd9Sstevel@tonic-gate router_add_k(dr); 21547c478bd9Sstevel@tonic-gate } 21557c478bd9Sstevel@tonic-gate 21567c478bd9Sstevel@tonic-gate /* 21577c478bd9Sstevel@tonic-gate * Called with the number of millseconds elapsed since the last call. 21587c478bd9Sstevel@tonic-gate * Determines if any timeout event has occurred and 21597c478bd9Sstevel@tonic-gate * returns the number of milliseconds until the next timeout event. 21607c478bd9Sstevel@tonic-gate * Returns TIMER_INFINITY for "never". 21617c478bd9Sstevel@tonic-gate */ 21627c478bd9Sstevel@tonic-gate uint_t 21637c478bd9Sstevel@tonic-gate router_timer(struct router *dr, uint_t elapsed) 21647c478bd9Sstevel@tonic-gate { 21657c478bd9Sstevel@tonic-gate uint_t next = TIMER_INFINITY; 21667c478bd9Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 21677c478bd9Sstevel@tonic-gate 21687c478bd9Sstevel@tonic-gate if (debug & D_ROUTER) { 21697c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "router_timer(%s, %s, %u, %d)\n", 21707c478bd9Sstevel@tonic-gate dr->dr_physical->pi_name, 21717c478bd9Sstevel@tonic-gate inet_ntop(AF_INET6, (void *)&dr->dr_address, 21727c478bd9Sstevel@tonic-gate abuf, sizeof (abuf)), dr->dr_lifetime, elapsed); 21737c478bd9Sstevel@tonic-gate } 21747c478bd9Sstevel@tonic-gate if (dr->dr_lifetime <= elapsed) { 21757c478bd9Sstevel@tonic-gate dr->dr_lifetime = 0; 21767c478bd9Sstevel@tonic-gate } else { 21777c478bd9Sstevel@tonic-gate dr->dr_lifetime -= elapsed; 21787c478bd9Sstevel@tonic-gate if (dr->dr_lifetime < next) 21797c478bd9Sstevel@tonic-gate next = dr->dr_lifetime; 21807c478bd9Sstevel@tonic-gate } 21817c478bd9Sstevel@tonic-gate 21827c478bd9Sstevel@tonic-gate if (dr->dr_lifetime == 0) { 21837c478bd9Sstevel@tonic-gate /* Log a message when last router goes away */ 21847c478bd9Sstevel@tonic-gate if (dr->dr_physical->pi_num_k_routers == 1) { 21857c478bd9Sstevel@tonic-gate logmsg(LOG_WARNING, 21867c478bd9Sstevel@tonic-gate "Last default router (%s) timed out on %s\n", 21877c478bd9Sstevel@tonic-gate inet_ntop(AF_INET6, (void *)&dr->dr_address, 21887c478bd9Sstevel@tonic-gate abuf, sizeof (abuf)), dr->dr_physical->pi_name); 21897c478bd9Sstevel@tonic-gate } 21907c478bd9Sstevel@tonic-gate router_delete(dr); 21917c478bd9Sstevel@tonic-gate } 21927c478bd9Sstevel@tonic-gate return (next); 21937c478bd9Sstevel@tonic-gate } 21947c478bd9Sstevel@tonic-gate 21957c478bd9Sstevel@tonic-gate /* 21967c478bd9Sstevel@tonic-gate * Add a default route to the kernel (unless the lifetime is zero) 21977c478bd9Sstevel@tonic-gate * Handles onlink default routes. 21987c478bd9Sstevel@tonic-gate */ 21997c478bd9Sstevel@tonic-gate static void 22007c478bd9Sstevel@tonic-gate router_add_k(struct router *dr) 22017c478bd9Sstevel@tonic-gate { 22027c478bd9Sstevel@tonic-gate struct phyint *pi = dr->dr_physical; 22037c478bd9Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 22047c478bd9Sstevel@tonic-gate int rlen; 22057c478bd9Sstevel@tonic-gate 22067c478bd9Sstevel@tonic-gate if (debug & D_ROUTER) { 22077c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "router_add_k(%s, %s, %u)\n", 22087c478bd9Sstevel@tonic-gate dr->dr_physical->pi_name, 22097c478bd9Sstevel@tonic-gate inet_ntop(AF_INET6, (void *)&dr->dr_address, 22107c478bd9Sstevel@tonic-gate abuf, sizeof (abuf)), dr->dr_lifetime); 22117c478bd9Sstevel@tonic-gate } 22127c478bd9Sstevel@tonic-gate 22137c478bd9Sstevel@tonic-gate rta_gateway->sin6_addr = dr->dr_address; 22147c478bd9Sstevel@tonic-gate 22157c478bd9Sstevel@tonic-gate rta_ifp->sdl_index = if_nametoindex(pi->pi_name); 22167c478bd9Sstevel@tonic-gate if (rta_ifp->sdl_index == 0) { 22177c478bd9Sstevel@tonic-gate logperror_pi(pi, "router_add_k: if_nametoindex"); 22187c478bd9Sstevel@tonic-gate return; 22197c478bd9Sstevel@tonic-gate } 22207c478bd9Sstevel@tonic-gate 22218121d73fSseb rt_msg->rtm_flags = RTF_GATEWAY; 22227c478bd9Sstevel@tonic-gate rt_msg->rtm_type = RTM_ADD; 22237c478bd9Sstevel@tonic-gate rt_msg->rtm_seq = ++rtmseq; 22247c478bd9Sstevel@tonic-gate rlen = write(rtsock, rt_msg, rt_msg->rtm_msglen); 22257c478bd9Sstevel@tonic-gate if (rlen < 0) { 22267c478bd9Sstevel@tonic-gate if (errno != EEXIST) { 22277c478bd9Sstevel@tonic-gate logperror_pi(pi, "router_add_k: RTM_ADD"); 22287c478bd9Sstevel@tonic-gate return; 22297c478bd9Sstevel@tonic-gate } 22307c478bd9Sstevel@tonic-gate } else if (rlen < rt_msg->rtm_msglen) { 22317c478bd9Sstevel@tonic-gate logmsg(LOG_ERR, "router_add_k: write to routing socket got " 22327c478bd9Sstevel@tonic-gate "only %d for rlen (interface %s)\n", rlen, pi->pi_name); 22337c478bd9Sstevel@tonic-gate return; 22347c478bd9Sstevel@tonic-gate } 22357c478bd9Sstevel@tonic-gate dr->dr_inkernel = _B_TRUE; 22368121d73fSseb pi->pi_num_k_routers++; 22377c478bd9Sstevel@tonic-gate } 22387c478bd9Sstevel@tonic-gate 22397c478bd9Sstevel@tonic-gate /* 22407c478bd9Sstevel@tonic-gate * Delete a route from the kernel. 22417c478bd9Sstevel@tonic-gate * Handles onlink default routes. 22427c478bd9Sstevel@tonic-gate */ 22437c478bd9Sstevel@tonic-gate static void 22447c478bd9Sstevel@tonic-gate router_delete_k(struct router *dr) 22457c478bd9Sstevel@tonic-gate { 22467c478bd9Sstevel@tonic-gate struct phyint *pi = dr->dr_physical; 22477c478bd9Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 22487c478bd9Sstevel@tonic-gate int rlen; 22497c478bd9Sstevel@tonic-gate 22507c478bd9Sstevel@tonic-gate if (debug & D_ROUTER) { 22517c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "router_delete_k(%s, %s, %u)\n", 22527c478bd9Sstevel@tonic-gate dr->dr_physical->pi_name, 22537c478bd9Sstevel@tonic-gate inet_ntop(AF_INET6, (void *)&dr->dr_address, 22547c478bd9Sstevel@tonic-gate abuf, sizeof (abuf)), dr->dr_lifetime); 22557c478bd9Sstevel@tonic-gate } 22567c478bd9Sstevel@tonic-gate 22577c478bd9Sstevel@tonic-gate rta_gateway->sin6_addr = dr->dr_address; 22587c478bd9Sstevel@tonic-gate 22597c478bd9Sstevel@tonic-gate rta_ifp->sdl_index = if_nametoindex(pi->pi_name); 22607c478bd9Sstevel@tonic-gate if (rta_ifp->sdl_index == 0) { 22617c478bd9Sstevel@tonic-gate logperror_pi(pi, "router_delete_k: if_nametoindex"); 22627c478bd9Sstevel@tonic-gate return; 22637c478bd9Sstevel@tonic-gate } 22647c478bd9Sstevel@tonic-gate 22658121d73fSseb rt_msg->rtm_flags = RTF_GATEWAY; 22667c478bd9Sstevel@tonic-gate rt_msg->rtm_type = RTM_DELETE; 22677c478bd9Sstevel@tonic-gate rt_msg->rtm_seq = ++rtmseq; 22687c478bd9Sstevel@tonic-gate rlen = write(rtsock, rt_msg, rt_msg->rtm_msglen); 22697c478bd9Sstevel@tonic-gate if (rlen < 0) { 22707c478bd9Sstevel@tonic-gate if (errno != ESRCH) { 22717c478bd9Sstevel@tonic-gate logperror_pi(pi, "router_delete_k: RTM_DELETE"); 22727c478bd9Sstevel@tonic-gate } 22737c478bd9Sstevel@tonic-gate } else if (rlen < rt_msg->rtm_msglen) { 22747c478bd9Sstevel@tonic-gate logmsg(LOG_ERR, "router_delete_k: write to routing socket got " 22757c478bd9Sstevel@tonic-gate "only %d for rlen (interface %s)\n", rlen, pi->pi_name); 22767c478bd9Sstevel@tonic-gate } 22777c478bd9Sstevel@tonic-gate dr->dr_inkernel = _B_FALSE; 22788121d73fSseb pi->pi_num_k_routers--; 22797c478bd9Sstevel@tonic-gate } 22807c478bd9Sstevel@tonic-gate 22817c478bd9Sstevel@tonic-gate static void 22827c478bd9Sstevel@tonic-gate router_print(struct router *dr) 22837c478bd9Sstevel@tonic-gate { 22847c478bd9Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 22857c478bd9Sstevel@tonic-gate 22868121d73fSseb logmsg(LOG_DEBUG, "Router %s on %s inkernel %d lifetime %u\n", 22878121d73fSseb inet_ntop(AF_INET6, (void *)&dr->dr_address, abuf, sizeof (abuf)), 22888121d73fSseb dr->dr_physical->pi_name, dr->dr_inkernel, dr->dr_lifetime); 22897c478bd9Sstevel@tonic-gate } 22907c478bd9Sstevel@tonic-gate 22917c478bd9Sstevel@tonic-gate void 22927c478bd9Sstevel@tonic-gate phyint_print_all(void) 22937c478bd9Sstevel@tonic-gate { 22947c478bd9Sstevel@tonic-gate struct phyint *pi; 22957c478bd9Sstevel@tonic-gate 22967c478bd9Sstevel@tonic-gate for (pi = phyints; pi != NULL; pi = pi->pi_next) { 22977c478bd9Sstevel@tonic-gate phyint_print(pi); 22987c478bd9Sstevel@tonic-gate } 22997c478bd9Sstevel@tonic-gate } 23007c478bd9Sstevel@tonic-gate 23017c478bd9Sstevel@tonic-gate void 2302*e11c3f44Smeem phyint_cleanup(struct phyint *pi) 23037c478bd9Sstevel@tonic-gate { 23047c478bd9Sstevel@tonic-gate pi->pi_state = 0; 23057c478bd9Sstevel@tonic-gate pi->pi_kernel_state = 0; 23067c478bd9Sstevel@tonic-gate 23077c478bd9Sstevel@tonic-gate if (pi->pi_AdvSendAdvertisements) { 23087c478bd9Sstevel@tonic-gate check_to_advertise(pi, ADV_OFF); 23097c478bd9Sstevel@tonic-gate } else { 23107c478bd9Sstevel@tonic-gate check_to_solicit(pi, SOLICIT_OFF); 23117c478bd9Sstevel@tonic-gate } 23127c478bd9Sstevel@tonic-gate 23137c478bd9Sstevel@tonic-gate while (pi->pi_router_list) 23147c478bd9Sstevel@tonic-gate router_delete(pi->pi_router_list); 23157c478bd9Sstevel@tonic-gate (void) poll_remove(pi->pi_sock); 23167c478bd9Sstevel@tonic-gate (void) close(pi->pi_sock); 23177c478bd9Sstevel@tonic-gate pi->pi_sock = -1; 23187c478bd9Sstevel@tonic-gate } 2319