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