1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gate #include "defs.h" 30*0Sstevel@tonic-gate #include "tables.h" 31*0Sstevel@tonic-gate 32*0Sstevel@tonic-gate #include <time.h> 33*0Sstevel@tonic-gate #include <inet/ip6.h> 34*0Sstevel@tonic-gate 35*0Sstevel@tonic-gate struct phyint *phyints = NULL; 36*0Sstevel@tonic-gate 37*0Sstevel@tonic-gate static void phyint_print(struct phyint *pi); 38*0Sstevel@tonic-gate static void phyint_insert(struct phyint *pi); 39*0Sstevel@tonic-gate 40*0Sstevel@tonic-gate static boolean_t tmptoken_isvalid(struct in6_addr *token); 41*0Sstevel@tonic-gate 42*0Sstevel@tonic-gate static void prefix_print(struct prefix *pr); 43*0Sstevel@tonic-gate static void prefix_insert(struct phyint *pi, struct prefix *pr); 44*0Sstevel@tonic-gate static char *prefix_print_state(int state, char *buf, int buflen); 45*0Sstevel@tonic-gate static void prefix_set(struct in6_addr *prefix, struct in6_addr addr, 46*0Sstevel@tonic-gate int bits); 47*0Sstevel@tonic-gate 48*0Sstevel@tonic-gate static void adv_prefix_print(struct adv_prefix *adv_pr); 49*0Sstevel@tonic-gate static void adv_prefix_insert(struct phyint *pi, struct adv_prefix *adv_pr); 50*0Sstevel@tonic-gate static void adv_prefix_delete(struct adv_prefix *adv_pr); 51*0Sstevel@tonic-gate 52*0Sstevel@tonic-gate static void router_print(struct router *dr); 53*0Sstevel@tonic-gate static void router_insert(struct phyint *pi, struct router *dr); 54*0Sstevel@tonic-gate static void router_delete(struct router *dr); 55*0Sstevel@tonic-gate static void router_add_k(struct router *dr); 56*0Sstevel@tonic-gate static void router_delete_k(struct router *dr); 57*0Sstevel@tonic-gate static void router_delete_onlink(struct phyint *pi); 58*0Sstevel@tonic-gate 59*0Sstevel@tonic-gate static int rtmseq; /* rtm_seq sequence number */ 60*0Sstevel@tonic-gate 61*0Sstevel@tonic-gate /* 1 week in ms */ 62*0Sstevel@tonic-gate #define NDP_PREFIX_DEFAULT_LIFETIME (7*24*60*60*1000) 63*0Sstevel@tonic-gate struct phyint * 64*0Sstevel@tonic-gate phyint_lookup(char *name) 65*0Sstevel@tonic-gate { 66*0Sstevel@tonic-gate struct phyint *pi; 67*0Sstevel@tonic-gate 68*0Sstevel@tonic-gate if (debug & D_PHYINT) 69*0Sstevel@tonic-gate logmsg(LOG_DEBUG, "phyint_lookup(%s)\n", name); 70*0Sstevel@tonic-gate 71*0Sstevel@tonic-gate for (pi = phyints; pi != NULL; pi = pi->pi_next) { 72*0Sstevel@tonic-gate if (strcmp(pi->pi_name, name) == 0) 73*0Sstevel@tonic-gate break; 74*0Sstevel@tonic-gate } 75*0Sstevel@tonic-gate return (pi); 76*0Sstevel@tonic-gate } 77*0Sstevel@tonic-gate 78*0Sstevel@tonic-gate struct phyint * 79*0Sstevel@tonic-gate phyint_lookup_on_index(uint_t ifindex) 80*0Sstevel@tonic-gate { 81*0Sstevel@tonic-gate struct phyint *pi; 82*0Sstevel@tonic-gate 83*0Sstevel@tonic-gate if (debug & D_PHYINT) 84*0Sstevel@tonic-gate logmsg(LOG_DEBUG, "phyint_lookup_on_index(%d)\n", ifindex); 85*0Sstevel@tonic-gate 86*0Sstevel@tonic-gate for (pi = phyints; pi != NULL; pi = pi->pi_next) { 87*0Sstevel@tonic-gate if (pi->pi_index == ifindex) 88*0Sstevel@tonic-gate break; 89*0Sstevel@tonic-gate } 90*0Sstevel@tonic-gate return (pi); 91*0Sstevel@tonic-gate } 92*0Sstevel@tonic-gate 93*0Sstevel@tonic-gate struct phyint * 94*0Sstevel@tonic-gate phyint_create(char *name) 95*0Sstevel@tonic-gate { 96*0Sstevel@tonic-gate struct phyint *pi; 97*0Sstevel@tonic-gate int i; 98*0Sstevel@tonic-gate 99*0Sstevel@tonic-gate if (debug & D_PHYINT) 100*0Sstevel@tonic-gate logmsg(LOG_DEBUG, "phyint_create(%s)\n", name); 101*0Sstevel@tonic-gate 102*0Sstevel@tonic-gate pi = (struct phyint *)calloc(sizeof (struct phyint), 1); 103*0Sstevel@tonic-gate if (pi == NULL) { 104*0Sstevel@tonic-gate logmsg(LOG_ERR, "phyint_create: out of memory\n"); 105*0Sstevel@tonic-gate return (NULL); 106*0Sstevel@tonic-gate } 107*0Sstevel@tonic-gate (void) strncpy(pi->pi_name, name, sizeof (pi->pi_name)); 108*0Sstevel@tonic-gate pi->pi_name[sizeof (pi->pi_name) - 1] = '\0'; 109*0Sstevel@tonic-gate 110*0Sstevel@tonic-gate /* 111*0Sstevel@tonic-gate * Copy the defaults from the defaults array. 112*0Sstevel@tonic-gate * Do not copy the cf_notdefault fields since these have not 113*0Sstevel@tonic-gate * been explicitly set for the phyint. 114*0Sstevel@tonic-gate */ 115*0Sstevel@tonic-gate for (i = 0; i < I_IFSIZE; i++) 116*0Sstevel@tonic-gate pi->pi_config[i].cf_value = ifdefaults[i].cf_value; 117*0Sstevel@tonic-gate 118*0Sstevel@tonic-gate /* 119*0Sstevel@tonic-gate * TmpDesyncFactor is used to desynchronize temporary token 120*0Sstevel@tonic-gate * generation among systems; the actual preferred lifetime value 121*0Sstevel@tonic-gate * of a temporary address will be (TmpPreferredLifetime - 122*0Sstevel@tonic-gate * TmpDesyncFactor). It's a random value, with a user-configurable 123*0Sstevel@tonic-gate * maximum value. The value is constant throughout the lifetime 124*0Sstevel@tonic-gate * of the in.ndpd process, but can change if the daemon is restarted, 125*0Sstevel@tonic-gate * per RFC3041. 126*0Sstevel@tonic-gate */ 127*0Sstevel@tonic-gate if (pi->pi_TmpMaxDesyncFactor != 0) { 128*0Sstevel@tonic-gate time_t seed = time(NULL); 129*0Sstevel@tonic-gate srand((uint_t)seed); 130*0Sstevel@tonic-gate pi->pi_TmpDesyncFactor = rand() % pi->pi_TmpMaxDesyncFactor; 131*0Sstevel@tonic-gate /* we actually want [1,max], not [0,(max-1)] */ 132*0Sstevel@tonic-gate pi->pi_TmpDesyncFactor++; 133*0Sstevel@tonic-gate } 134*0Sstevel@tonic-gate pi->pi_TmpRegenCountdown = TIMER_INFINITY; 135*0Sstevel@tonic-gate 136*0Sstevel@tonic-gate pi->pi_sock = -1; 137*0Sstevel@tonic-gate if (phyint_init_from_k(pi) == -1) { 138*0Sstevel@tonic-gate if (pi->pi_group_name != NULL) 139*0Sstevel@tonic-gate free(pi->pi_group_name); 140*0Sstevel@tonic-gate free(pi); 141*0Sstevel@tonic-gate return (NULL); 142*0Sstevel@tonic-gate } 143*0Sstevel@tonic-gate phyint_insert(pi); 144*0Sstevel@tonic-gate if (pi->pi_sock != -1) { 145*0Sstevel@tonic-gate if (poll_add(pi->pi_sock) == -1) { 146*0Sstevel@tonic-gate phyint_delete(pi); 147*0Sstevel@tonic-gate return (NULL); 148*0Sstevel@tonic-gate } 149*0Sstevel@tonic-gate } 150*0Sstevel@tonic-gate return (pi); 151*0Sstevel@tonic-gate } 152*0Sstevel@tonic-gate 153*0Sstevel@tonic-gate /* Insert in linked list */ 154*0Sstevel@tonic-gate static void 155*0Sstevel@tonic-gate phyint_insert(struct phyint *pi) 156*0Sstevel@tonic-gate { 157*0Sstevel@tonic-gate /* Insert in list */ 158*0Sstevel@tonic-gate pi->pi_next = phyints; 159*0Sstevel@tonic-gate pi->pi_prev = NULL; 160*0Sstevel@tonic-gate if (phyints) 161*0Sstevel@tonic-gate phyints->pi_prev = pi; 162*0Sstevel@tonic-gate phyints = pi; 163*0Sstevel@tonic-gate } 164*0Sstevel@tonic-gate 165*0Sstevel@tonic-gate /* 166*0Sstevel@tonic-gate * Initialize both the phyint data structure and the pi_sock for 167*0Sstevel@tonic-gate * sending and receving on the interface. 168*0Sstevel@tonic-gate * Extract information from the kernel (if present) and set pi_kernel_state. 169*0Sstevel@tonic-gate */ 170*0Sstevel@tonic-gate int 171*0Sstevel@tonic-gate phyint_init_from_k(struct phyint *pi) 172*0Sstevel@tonic-gate { 173*0Sstevel@tonic-gate struct ipv6_mreq v6mcastr; 174*0Sstevel@tonic-gate struct lifreq lifr; 175*0Sstevel@tonic-gate int fd; 176*0Sstevel@tonic-gate boolean_t newsock; 177*0Sstevel@tonic-gate uint_t ttl; 178*0Sstevel@tonic-gate struct sockaddr_in6 *sin6; 179*0Sstevel@tonic-gate 180*0Sstevel@tonic-gate if (debug & D_PHYINT) 181*0Sstevel@tonic-gate logmsg(LOG_DEBUG, "phyint_init_from_k(%s)\n", pi->pi_name); 182*0Sstevel@tonic-gate 183*0Sstevel@tonic-gate start_over: 184*0Sstevel@tonic-gate 185*0Sstevel@tonic-gate if (pi->pi_sock < 0) { 186*0Sstevel@tonic-gate pi->pi_sock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6); 187*0Sstevel@tonic-gate if (pi->pi_sock < 0) { 188*0Sstevel@tonic-gate logperror_pi(pi, "phyint_init_from_k: socket"); 189*0Sstevel@tonic-gate return (-1); 190*0Sstevel@tonic-gate } 191*0Sstevel@tonic-gate newsock = _B_TRUE; 192*0Sstevel@tonic-gate } else { 193*0Sstevel@tonic-gate newsock = _B_FALSE; 194*0Sstevel@tonic-gate } 195*0Sstevel@tonic-gate fd = pi->pi_sock; 196*0Sstevel@tonic-gate 197*0Sstevel@tonic-gate (void) strncpy(lifr.lifr_name, pi->pi_name, sizeof (lifr.lifr_name)); 198*0Sstevel@tonic-gate lifr.lifr_name[sizeof (lifr.lifr_name) - 1] = '\0'; 199*0Sstevel@tonic-gate if (ioctl(fd, SIOCGLIFINDEX, (char *)&lifr) < 0) { 200*0Sstevel@tonic-gate if (errno == ENXIO) { 201*0Sstevel@tonic-gate if (newsock) { 202*0Sstevel@tonic-gate (void) close(pi->pi_sock); 203*0Sstevel@tonic-gate pi->pi_sock = -1; 204*0Sstevel@tonic-gate } 205*0Sstevel@tonic-gate if (debug & D_PHYINT) { 206*0Sstevel@tonic-gate logmsg(LOG_DEBUG, "phyint_init_from_k(%s): " 207*0Sstevel@tonic-gate "not exist\n", pi->pi_name); 208*0Sstevel@tonic-gate } 209*0Sstevel@tonic-gate return (0); 210*0Sstevel@tonic-gate } 211*0Sstevel@tonic-gate logperror_pi(pi, "phyint_init_from_k: SIOCGLIFINDEX"); 212*0Sstevel@tonic-gate goto error; 213*0Sstevel@tonic-gate } 214*0Sstevel@tonic-gate 215*0Sstevel@tonic-gate if (!newsock && (pi->pi_index != lifr.lifr_index)) { 216*0Sstevel@tonic-gate /* 217*0Sstevel@tonic-gate * Interface has been re-plumbed, lets open a new socket. 218*0Sstevel@tonic-gate * This situation can occur if plumb/unplumb are happening 219*0Sstevel@tonic-gate * quite frequently. 220*0Sstevel@tonic-gate */ 221*0Sstevel@tonic-gate 222*0Sstevel@tonic-gate phyint_cleanup(pi); 223*0Sstevel@tonic-gate goto start_over; 224*0Sstevel@tonic-gate } 225*0Sstevel@tonic-gate 226*0Sstevel@tonic-gate pi->pi_index = lifr.lifr_index; 227*0Sstevel@tonic-gate 228*0Sstevel@tonic-gate if (ioctl(fd, SIOCGLIFFLAGS, (char *)&lifr) < 0) { 229*0Sstevel@tonic-gate logperror_pi(pi, "phyint_init_from_k: ioctl (get flags)"); 230*0Sstevel@tonic-gate goto error; 231*0Sstevel@tonic-gate } 232*0Sstevel@tonic-gate pi->pi_flags = lifr.lifr_flags; 233*0Sstevel@tonic-gate 234*0Sstevel@tonic-gate /* 235*0Sstevel@tonic-gate * If the link local interface is not up yet or it's IFF_UP 236*0Sstevel@tonic-gate * and the flag is set to IFF_NOLOCAL as Duplicate Address 237*0Sstevel@tonic-gate * Detection is in progress. 238*0Sstevel@tonic-gate * IFF_NOLOCAL is "normal" on other prefixes. 239*0Sstevel@tonic-gate */ 240*0Sstevel@tonic-gate 241*0Sstevel@tonic-gate if (!(pi->pi_flags & IFF_UP) || (pi->pi_flags & IFF_NOLOCAL)) { 242*0Sstevel@tonic-gate if (newsock) { 243*0Sstevel@tonic-gate (void) close(pi->pi_sock); 244*0Sstevel@tonic-gate pi->pi_sock = -1; 245*0Sstevel@tonic-gate } 246*0Sstevel@tonic-gate if (debug & D_PHYINT) { 247*0Sstevel@tonic-gate logmsg(LOG_DEBUG, "phyint_init_from_k(%s): " 248*0Sstevel@tonic-gate "not IFF_UP\n", pi->pi_name); 249*0Sstevel@tonic-gate } 250*0Sstevel@tonic-gate return (0); 251*0Sstevel@tonic-gate } 252*0Sstevel@tonic-gate pi->pi_kernel_state |= PI_PRESENT; 253*0Sstevel@tonic-gate 254*0Sstevel@tonic-gate bzero(lifr.lifr_groupname, sizeof (lifr.lifr_groupname)); 255*0Sstevel@tonic-gate if (ioctl(fd, SIOCGLIFGROUPNAME, (caddr_t)&lifr) < 0) { 256*0Sstevel@tonic-gate logperror_pi(pi, "phyint_init_from_k: ioctl (get group name)"); 257*0Sstevel@tonic-gate goto error; 258*0Sstevel@tonic-gate } 259*0Sstevel@tonic-gate 260*0Sstevel@tonic-gate if (lifr.lifr_groupname != NULL && strlen(lifr.lifr_groupname) != 0) { 261*0Sstevel@tonic-gate if (pi->pi_group_name == NULL) { 262*0Sstevel@tonic-gate pi->pi_group_name = malloc( 263*0Sstevel@tonic-gate sizeof (lifr.lifr_groupname)); 264*0Sstevel@tonic-gate if (pi->pi_group_name == NULL) { 265*0Sstevel@tonic-gate logperror_pi(pi, "phyint_init_from_k:" 266*0Sstevel@tonic-gate " malloc(group name)"); 267*0Sstevel@tonic-gate goto error; 268*0Sstevel@tonic-gate } 269*0Sstevel@tonic-gate } 270*0Sstevel@tonic-gate /* 271*0Sstevel@tonic-gate * Size of the group name can only be LIFNAMESZ -1 characters 272*0Sstevel@tonic-gate * which is ensured by kernel. Thus, we don't need strncpy. 273*0Sstevel@tonic-gate */ 274*0Sstevel@tonic-gate (void) strncpy(pi->pi_group_name, lifr.lifr_groupname, 275*0Sstevel@tonic-gate sizeof (lifr.lifr_name)); 276*0Sstevel@tonic-gate pi->pi_group_name[sizeof (pi->pi_group_name) - 1] = '\0'; 277*0Sstevel@tonic-gate } else if (pi->pi_group_name != NULL) { 278*0Sstevel@tonic-gate free(pi->pi_group_name); 279*0Sstevel@tonic-gate pi->pi_group_name = NULL; 280*0Sstevel@tonic-gate } 281*0Sstevel@tonic-gate 282*0Sstevel@tonic-gate if (ioctl(fd, SIOCGLIFMTU, (caddr_t)&lifr) < 0) { 283*0Sstevel@tonic-gate logperror_pi(pi, "phyint_init_from_k: ioctl (get mtu)"); 284*0Sstevel@tonic-gate goto error; 285*0Sstevel@tonic-gate } 286*0Sstevel@tonic-gate pi->pi_mtu = lifr.lifr_mtu; 287*0Sstevel@tonic-gate 288*0Sstevel@tonic-gate if (ioctl(fd, SIOCGLIFADDR, (char *)&lifr) < 0) { 289*0Sstevel@tonic-gate logperror_pi(pi, "phyint_init_from_k: SIOCGLIFADDR"); 290*0Sstevel@tonic-gate goto error; 291*0Sstevel@tonic-gate } 292*0Sstevel@tonic-gate sin6 = (struct sockaddr_in6 *)&lifr.lifr_addr; 293*0Sstevel@tonic-gate pi->pi_ifaddr = sin6->sin6_addr; 294*0Sstevel@tonic-gate 295*0Sstevel@tonic-gate if (ioctl(fd, SIOCGLIFTOKEN, (char *)&lifr) < 0) { 296*0Sstevel@tonic-gate logperror_pi(pi, "phyint_init_from_k: SIOCGLIFTOKEN"); 297*0Sstevel@tonic-gate goto error; 298*0Sstevel@tonic-gate } 299*0Sstevel@tonic-gate /* Ignore interface if the token is all zeros */ 300*0Sstevel@tonic-gate sin6 = (struct sockaddr_in6 *)&lifr.lifr_token; 301*0Sstevel@tonic-gate if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { 302*0Sstevel@tonic-gate logmsg(LOG_ERR, "ignoring interface %s: zero token\n", 303*0Sstevel@tonic-gate pi->pi_name); 304*0Sstevel@tonic-gate goto error; 305*0Sstevel@tonic-gate } 306*0Sstevel@tonic-gate pi->pi_token = sin6->sin6_addr; 307*0Sstevel@tonic-gate pi->pi_token_length = lifr.lifr_addrlen; 308*0Sstevel@tonic-gate 309*0Sstevel@tonic-gate /* 310*0Sstevel@tonic-gate * Guess a remote token for POINTOPOINT by looking at 311*0Sstevel@tonic-gate * the link-local destination address. 312*0Sstevel@tonic-gate */ 313*0Sstevel@tonic-gate if (pi->pi_flags & IFF_POINTOPOINT) { 314*0Sstevel@tonic-gate if (ioctl(fd, SIOCGLIFDSTADDR, (char *)&lifr) < 0) { 315*0Sstevel@tonic-gate logperror_pi(pi, "phyint_init_from_k: SIOCGLIFDSTADDR"); 316*0Sstevel@tonic-gate goto error; 317*0Sstevel@tonic-gate } 318*0Sstevel@tonic-gate sin6 = (struct sockaddr_in6 *)&lifr.lifr_addr; 319*0Sstevel@tonic-gate if (sin6->sin6_family != AF_INET6 || 320*0Sstevel@tonic-gate IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) || 321*0Sstevel@tonic-gate !IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) { 322*0Sstevel@tonic-gate pi->pi_dst_token = in6addr_any; 323*0Sstevel@tonic-gate } else { 324*0Sstevel@tonic-gate pi->pi_dst_token = sin6->sin6_addr; 325*0Sstevel@tonic-gate /* Clear link-local prefix (first 10 bits) */ 326*0Sstevel@tonic-gate pi->pi_dst_token.s6_addr[0] = 0; 327*0Sstevel@tonic-gate pi->pi_dst_token.s6_addr[1] &= 0x3f; 328*0Sstevel@tonic-gate } 329*0Sstevel@tonic-gate } else { 330*0Sstevel@tonic-gate pi->pi_dst_token = in6addr_any; 331*0Sstevel@tonic-gate } 332*0Sstevel@tonic-gate 333*0Sstevel@tonic-gate /* Get link-layer address */ 334*0Sstevel@tonic-gate if (!(pi->pi_flags & IFF_MULTICAST) || 335*0Sstevel@tonic-gate (pi->pi_flags & IFF_POINTOPOINT)) { 336*0Sstevel@tonic-gate pi->pi_hdw_addr_len = 0; 337*0Sstevel@tonic-gate } else { 338*0Sstevel@tonic-gate sin6 = (struct sockaddr_in6 *)&lifr.lifr_nd.lnr_addr; 339*0Sstevel@tonic-gate bzero(sin6, sizeof (struct sockaddr_in6)); 340*0Sstevel@tonic-gate sin6->sin6_family = AF_INET6; 341*0Sstevel@tonic-gate sin6->sin6_addr = pi->pi_ifaddr; 342*0Sstevel@tonic-gate 343*0Sstevel@tonic-gate if (ioctl(fd, SIOCLIFGETND, (char *)&lifr) < 0) { 344*0Sstevel@tonic-gate logperror_pi(pi, "phyint_init_from_k: SIOCLIFGETND"); 345*0Sstevel@tonic-gate goto error; 346*0Sstevel@tonic-gate } 347*0Sstevel@tonic-gate 348*0Sstevel@tonic-gate pi->pi_hdw_addr_len = lifr.lifr_nd.lnr_hdw_len; 349*0Sstevel@tonic-gate 350*0Sstevel@tonic-gate if (lifr.lifr_nd.lnr_hdw_len != 0) { 351*0Sstevel@tonic-gate bcopy((char *)lifr.lifr_nd.lnr_hdw_addr, 352*0Sstevel@tonic-gate (char *)pi->pi_hdw_addr, 353*0Sstevel@tonic-gate lifr.lifr_nd.lnr_hdw_len); 354*0Sstevel@tonic-gate } 355*0Sstevel@tonic-gate } 356*0Sstevel@tonic-gate 357*0Sstevel@tonic-gate if (newsock) { 358*0Sstevel@tonic-gate icmp6_filter_t filter; 359*0Sstevel@tonic-gate int on = 1; 360*0Sstevel@tonic-gate 361*0Sstevel@tonic-gate /* Set default values */ 362*0Sstevel@tonic-gate pi->pi_LinkMTU = pi->pi_mtu; 363*0Sstevel@tonic-gate pi->pi_CurHopLimit = 0; 364*0Sstevel@tonic-gate pi->pi_BaseReachableTime = ND_REACHABLE_TIME; 365*0Sstevel@tonic-gate phyint_reach_random(pi, _B_FALSE); 366*0Sstevel@tonic-gate pi->pi_RetransTimer = ND_RETRANS_TIMER; 367*0Sstevel@tonic-gate 368*0Sstevel@tonic-gate /* Setup socket for transmission and reception */ 369*0Sstevel@tonic-gate if (setsockopt(fd, IPPROTO_IPV6, 370*0Sstevel@tonic-gate IPV6_BOUND_IF, (char *)&pi->pi_index, 371*0Sstevel@tonic-gate sizeof (pi->pi_index)) < 0) { 372*0Sstevel@tonic-gate logperror_pi(pi, "phyint_init_from_k: setsockopt " 373*0Sstevel@tonic-gate "IPV6_BOUND_IF"); 374*0Sstevel@tonic-gate goto error; 375*0Sstevel@tonic-gate } 376*0Sstevel@tonic-gate 377*0Sstevel@tonic-gate ttl = IPV6_MAX_HOPS; 378*0Sstevel@tonic-gate if (setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, 379*0Sstevel@tonic-gate (char *)&ttl, sizeof (ttl)) < 0) { 380*0Sstevel@tonic-gate logperror_pi(pi, "phyint_init_from_k: setsockopt " 381*0Sstevel@tonic-gate "IPV6_UNICAST_HOPS"); 382*0Sstevel@tonic-gate goto error; 383*0Sstevel@tonic-gate } 384*0Sstevel@tonic-gate 385*0Sstevel@tonic-gate if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, 386*0Sstevel@tonic-gate (char *)&ttl, sizeof (ttl)) < 0) { 387*0Sstevel@tonic-gate logperror_pi(pi, "phyint_init_from_k: setsockopt " 388*0Sstevel@tonic-gate "IPV6_MULTICAST_HOPS"); 389*0Sstevel@tonic-gate goto error; 390*0Sstevel@tonic-gate } 391*0Sstevel@tonic-gate 392*0Sstevel@tonic-gate v6mcastr.ipv6mr_multiaddr = all_nodes_mcast; 393*0Sstevel@tonic-gate v6mcastr.ipv6mr_interface = pi->pi_index; 394*0Sstevel@tonic-gate if (setsockopt(fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, 395*0Sstevel@tonic-gate (char *)&v6mcastr, sizeof (v6mcastr)) < 0) { 396*0Sstevel@tonic-gate logperror_pi(pi, "phyint_init_from_k: " 397*0Sstevel@tonic-gate "setsockopt IPV6_JOIN_GROUP"); 398*0Sstevel@tonic-gate goto error; 399*0Sstevel@tonic-gate } 400*0Sstevel@tonic-gate pi->pi_state |= PI_JOINED_ALLNODES; 401*0Sstevel@tonic-gate pi->pi_kernel_state |= PI_JOINED_ALLNODES; 402*0Sstevel@tonic-gate 403*0Sstevel@tonic-gate /* 404*0Sstevel@tonic-gate * Filter out so that we only receive router advertisements and 405*0Sstevel@tonic-gate * router solicitations. 406*0Sstevel@tonic-gate */ 407*0Sstevel@tonic-gate ICMP6_FILTER_SETBLOCKALL(&filter); 408*0Sstevel@tonic-gate ICMP6_FILTER_SETPASS(ND_ROUTER_SOLICIT, &filter); 409*0Sstevel@tonic-gate ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT, &filter); 410*0Sstevel@tonic-gate 411*0Sstevel@tonic-gate if (setsockopt(fd, IPPROTO_ICMPV6, ICMP6_FILTER, 412*0Sstevel@tonic-gate (char *)&filter, sizeof (filter)) < 0) { 413*0Sstevel@tonic-gate logperror_pi(pi, "phyint_init_from_k: setsockopt " 414*0Sstevel@tonic-gate "ICMP6_FILTER"); 415*0Sstevel@tonic-gate goto error; 416*0Sstevel@tonic-gate } 417*0Sstevel@tonic-gate 418*0Sstevel@tonic-gate /* Enable receipt of ancillary data */ 419*0Sstevel@tonic-gate if (setsockopt(fd, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, 420*0Sstevel@tonic-gate (char *)&on, sizeof (on)) < 0) { 421*0Sstevel@tonic-gate logperror_pi(pi, "phyint_init_from_k: setsockopt " 422*0Sstevel@tonic-gate "IPV6_RECVHOPLIMIT"); 423*0Sstevel@tonic-gate goto error; 424*0Sstevel@tonic-gate } 425*0Sstevel@tonic-gate if (setsockopt(fd, IPPROTO_IPV6, IPV6_RECVRTHDR, 426*0Sstevel@tonic-gate (char *)&on, sizeof (on)) < 0) { 427*0Sstevel@tonic-gate logperror_pi(pi, "phyint_init_from_k: setsockopt " 428*0Sstevel@tonic-gate "IPV6_RECVRTHDR"); 429*0Sstevel@tonic-gate goto error; 430*0Sstevel@tonic-gate } 431*0Sstevel@tonic-gate } 432*0Sstevel@tonic-gate 433*0Sstevel@tonic-gate if (pi->pi_AdvSendAdvertisements && 434*0Sstevel@tonic-gate !(pi->pi_kernel_state & PI_JOINED_ALLROUTERS)) { 435*0Sstevel@tonic-gate v6mcastr.ipv6mr_multiaddr = all_routers_mcast; 436*0Sstevel@tonic-gate v6mcastr.ipv6mr_interface = pi->pi_index; 437*0Sstevel@tonic-gate if (setsockopt(fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, 438*0Sstevel@tonic-gate (char *)&v6mcastr, sizeof (v6mcastr)) < 0) { 439*0Sstevel@tonic-gate logperror_pi(pi, "phyint_init_from_k: setsockopt " 440*0Sstevel@tonic-gate "IPV6_JOIN_GROUP"); 441*0Sstevel@tonic-gate goto error; 442*0Sstevel@tonic-gate } 443*0Sstevel@tonic-gate pi->pi_state |= PI_JOINED_ALLROUTERS; 444*0Sstevel@tonic-gate pi->pi_kernel_state |= PI_JOINED_ALLROUTERS; 445*0Sstevel@tonic-gate } 446*0Sstevel@tonic-gate /* 447*0Sstevel@tonic-gate * If not already set, set the IFF_ROUTER interface flag based on 448*0Sstevel@tonic-gate * AdvSendAdvertisements. Note that this will also enable IPv6 449*0Sstevel@tonic-gate * forwarding on the interface. We don't clear IFF_ROUTER if we're 450*0Sstevel@tonic-gate * not advertising on an interface, because we could still be 451*0Sstevel@tonic-gate * forwarding on those interfaces. 452*0Sstevel@tonic-gate */ 453*0Sstevel@tonic-gate (void) strncpy(lifr.lifr_name, pi->pi_name, sizeof (lifr.lifr_name)); 454*0Sstevel@tonic-gate lifr.lifr_name[sizeof (lifr.lifr_name) - 1] = '\0'; 455*0Sstevel@tonic-gate if (ioctl(fd, SIOCGLIFFLAGS, (char *)&lifr) < 0) { 456*0Sstevel@tonic-gate logperror_pi(pi, "phyint_init_from_k: SIOCGLIFFLAGS"); 457*0Sstevel@tonic-gate goto error; 458*0Sstevel@tonic-gate } 459*0Sstevel@tonic-gate if (!(lifr.lifr_flags & IFF_ROUTER) && pi->pi_AdvSendAdvertisements) { 460*0Sstevel@tonic-gate lifr.lifr_flags |= IFF_ROUTER; 461*0Sstevel@tonic-gate 462*0Sstevel@tonic-gate if (ioctl(fd, SIOCSLIFFLAGS, (char *)&lifr) < 0) { 463*0Sstevel@tonic-gate logperror_pi(pi, "phyint_init_from_k: SIOCSLIFFLAGS"); 464*0Sstevel@tonic-gate goto error; 465*0Sstevel@tonic-gate } 466*0Sstevel@tonic-gate pi->pi_flags = lifr.lifr_flags; 467*0Sstevel@tonic-gate } 468*0Sstevel@tonic-gate 469*0Sstevel@tonic-gate /* Set linkinfo parameters */ 470*0Sstevel@tonic-gate (void) strncpy(lifr.lifr_name, pi->pi_name, sizeof (lifr.lifr_name)); 471*0Sstevel@tonic-gate lifr.lifr_name[sizeof (lifr.lifr_name) - 1] = '\0'; 472*0Sstevel@tonic-gate if (ioctl(fd, SIOCGLIFLNKINFO, (char *)&lifr) < 0) { 473*0Sstevel@tonic-gate logperror_pi(pi, "phyint_init_from_k: SIOCGLIFLNKINFO"); 474*0Sstevel@tonic-gate goto error; 475*0Sstevel@tonic-gate } 476*0Sstevel@tonic-gate lifr.lifr_ifinfo.lir_maxhops = pi->pi_CurHopLimit; 477*0Sstevel@tonic-gate lifr.lifr_ifinfo.lir_reachtime = pi->pi_ReachableTime; 478*0Sstevel@tonic-gate lifr.lifr_ifinfo.lir_reachretrans = pi->pi_RetransTimer; 479*0Sstevel@tonic-gate if (ioctl(fd, SIOCSLIFLNKINFO, (char *)&lifr) < 0) { 480*0Sstevel@tonic-gate logperror_pi(pi, "phyint_init_from_k: SIOCSLIFLNKINFO"); 481*0Sstevel@tonic-gate goto error; 482*0Sstevel@tonic-gate } 483*0Sstevel@tonic-gate if (debug & D_PHYINT) { 484*0Sstevel@tonic-gate logmsg(LOG_DEBUG, "phyint_init_from_k(%s): done\n", 485*0Sstevel@tonic-gate pi->pi_name); 486*0Sstevel@tonic-gate } 487*0Sstevel@tonic-gate return (0); 488*0Sstevel@tonic-gate 489*0Sstevel@tonic-gate error: 490*0Sstevel@tonic-gate /* Pretend the interface does not exist in the kernel */ 491*0Sstevel@tonic-gate pi->pi_kernel_state &= ~PI_PRESENT; 492*0Sstevel@tonic-gate if (newsock) { 493*0Sstevel@tonic-gate (void) close(pi->pi_sock); 494*0Sstevel@tonic-gate pi->pi_sock = -1; 495*0Sstevel@tonic-gate } 496*0Sstevel@tonic-gate return (-1); 497*0Sstevel@tonic-gate } 498*0Sstevel@tonic-gate 499*0Sstevel@tonic-gate /* 500*0Sstevel@tonic-gate * Delete (unlink and free). 501*0Sstevel@tonic-gate * Handles delete of things that have not yet been inserted in the list. 502*0Sstevel@tonic-gate */ 503*0Sstevel@tonic-gate void 504*0Sstevel@tonic-gate phyint_delete(struct phyint *pi) 505*0Sstevel@tonic-gate { 506*0Sstevel@tonic-gate if (debug & D_PHYINT) 507*0Sstevel@tonic-gate logmsg(LOG_DEBUG, "phyint_delete(%s)\n", pi->pi_name); 508*0Sstevel@tonic-gate 509*0Sstevel@tonic-gate while (pi->pi_router_list) 510*0Sstevel@tonic-gate router_delete(pi->pi_router_list); 511*0Sstevel@tonic-gate while (pi->pi_prefix_list) 512*0Sstevel@tonic-gate prefix_delete(pi->pi_prefix_list); 513*0Sstevel@tonic-gate while (pi->pi_adv_prefix_list) 514*0Sstevel@tonic-gate adv_prefix_delete(pi->pi_adv_prefix_list); 515*0Sstevel@tonic-gate 516*0Sstevel@tonic-gate if (pi->pi_sock != -1) { 517*0Sstevel@tonic-gate (void) poll_remove(pi->pi_sock); 518*0Sstevel@tonic-gate if (close(pi->pi_sock) < 0) { 519*0Sstevel@tonic-gate logperror_pi(pi, "phyint_delete: close"); 520*0Sstevel@tonic-gate } 521*0Sstevel@tonic-gate pi->pi_sock = -1; 522*0Sstevel@tonic-gate } 523*0Sstevel@tonic-gate 524*0Sstevel@tonic-gate if (pi->pi_prev == NULL) { 525*0Sstevel@tonic-gate if (phyints == pi) 526*0Sstevel@tonic-gate phyints = pi->pi_next; 527*0Sstevel@tonic-gate } else { 528*0Sstevel@tonic-gate pi->pi_prev->pi_next = pi->pi_next; 529*0Sstevel@tonic-gate } 530*0Sstevel@tonic-gate if (pi->pi_next != NULL) 531*0Sstevel@tonic-gate pi->pi_next->pi_prev = pi->pi_prev; 532*0Sstevel@tonic-gate pi->pi_next = pi->pi_prev = NULL; 533*0Sstevel@tonic-gate if (pi->pi_group_name != NULL) 534*0Sstevel@tonic-gate free(pi->pi_group_name); 535*0Sstevel@tonic-gate free(pi); 536*0Sstevel@tonic-gate } 537*0Sstevel@tonic-gate 538*0Sstevel@tonic-gate /* 539*0Sstevel@tonic-gate * Called with the number of millseconds elapsed since the last call. 540*0Sstevel@tonic-gate * Determines if any timeout event has occurred and 541*0Sstevel@tonic-gate * returns the number of milliseconds until the next timeout event 542*0Sstevel@tonic-gate * for the phyint iself (excluding prefixes and routers). 543*0Sstevel@tonic-gate * Returns TIMER_INFINITY for "never". 544*0Sstevel@tonic-gate */ 545*0Sstevel@tonic-gate uint_t 546*0Sstevel@tonic-gate phyint_timer(struct phyint *pi, uint_t elapsed) 547*0Sstevel@tonic-gate { 548*0Sstevel@tonic-gate uint_t next = TIMER_INFINITY; 549*0Sstevel@tonic-gate 550*0Sstevel@tonic-gate if (pi->pi_AdvSendAdvertisements) { 551*0Sstevel@tonic-gate if (pi->pi_adv_state != NO_ADV) { 552*0Sstevel@tonic-gate int old_state = pi->pi_adv_state; 553*0Sstevel@tonic-gate 554*0Sstevel@tonic-gate if (debug & (D_STATE|D_PHYINT)) { 555*0Sstevel@tonic-gate logmsg(LOG_DEBUG, "phyint_timer ADV(%s) " 556*0Sstevel@tonic-gate "state %d\n", pi->pi_name, (int)old_state); 557*0Sstevel@tonic-gate } 558*0Sstevel@tonic-gate next = advertise_event(pi, ADV_TIMER, elapsed); 559*0Sstevel@tonic-gate if (debug & D_STATE) { 560*0Sstevel@tonic-gate logmsg(LOG_DEBUG, "phyint_timer ADV(%s) " 561*0Sstevel@tonic-gate "state %d -> %d\n", 562*0Sstevel@tonic-gate pi->pi_name, (int)old_state, 563*0Sstevel@tonic-gate (int)pi->pi_adv_state); 564*0Sstevel@tonic-gate } 565*0Sstevel@tonic-gate } 566*0Sstevel@tonic-gate } else { 567*0Sstevel@tonic-gate if (pi->pi_sol_state != NO_SOLICIT) { 568*0Sstevel@tonic-gate int old_state = pi->pi_sol_state; 569*0Sstevel@tonic-gate 570*0Sstevel@tonic-gate if (debug & (D_STATE|D_PHYINT)) { 571*0Sstevel@tonic-gate logmsg(LOG_DEBUG, "phyint_timer SOL(%s) " 572*0Sstevel@tonic-gate "state %d\n", pi->pi_name, (int)old_state); 573*0Sstevel@tonic-gate } 574*0Sstevel@tonic-gate next = solicit_event(pi, SOL_TIMER, elapsed); 575*0Sstevel@tonic-gate if (debug & D_STATE) { 576*0Sstevel@tonic-gate logmsg(LOG_DEBUG, "phyint_timer SOL(%s) " 577*0Sstevel@tonic-gate "state %d -> %d\n", 578*0Sstevel@tonic-gate pi->pi_name, (int)old_state, 579*0Sstevel@tonic-gate (int)pi->pi_sol_state); 580*0Sstevel@tonic-gate } 581*0Sstevel@tonic-gate } 582*0Sstevel@tonic-gate } 583*0Sstevel@tonic-gate 584*0Sstevel@tonic-gate /* 585*0Sstevel@tonic-gate * If the phyint has been unplumbed, we don't want to call 586*0Sstevel@tonic-gate * phyint_reach_random. We will be in the NO_ADV or NO_SOLICIT state. 587*0Sstevel@tonic-gate */ 588*0Sstevel@tonic-gate if ((pi->pi_AdvSendAdvertisements && (pi->pi_adv_state != NO_ADV)) || 589*0Sstevel@tonic-gate (!pi->pi_AdvSendAdvertisements && 590*0Sstevel@tonic-gate (pi->pi_sol_state != NO_SOLICIT))) { 591*0Sstevel@tonic-gate pi->pi_reach_time_since_random += elapsed; 592*0Sstevel@tonic-gate if (pi->pi_reach_time_since_random >= MAX_REACH_RANDOM_INTERVAL) 593*0Sstevel@tonic-gate phyint_reach_random(pi, _B_TRUE); 594*0Sstevel@tonic-gate } 595*0Sstevel@tonic-gate 596*0Sstevel@tonic-gate return (next); 597*0Sstevel@tonic-gate } 598*0Sstevel@tonic-gate 599*0Sstevel@tonic-gate static void 600*0Sstevel@tonic-gate phyint_print(struct phyint *pi) 601*0Sstevel@tonic-gate { 602*0Sstevel@tonic-gate struct prefix *pr; 603*0Sstevel@tonic-gate struct adv_prefix *adv_pr; 604*0Sstevel@tonic-gate struct router *dr; 605*0Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 606*0Sstevel@tonic-gate char llabuf[BUFSIZ]; 607*0Sstevel@tonic-gate 608*0Sstevel@tonic-gate logmsg(LOG_DEBUG, "Phyint %s index %d state %x, kernel %x, " 609*0Sstevel@tonic-gate "onlink_def %d num routers %d\n", 610*0Sstevel@tonic-gate pi->pi_name, pi->pi_index, 611*0Sstevel@tonic-gate pi->pi_state, pi->pi_kernel_state, 612*0Sstevel@tonic-gate pi->pi_onlink_default ? 1 : 0, 613*0Sstevel@tonic-gate pi->pi_num_k_routers); 614*0Sstevel@tonic-gate logmsg(LOG_DEBUG, "\taddress: %s flags %x\n", 615*0Sstevel@tonic-gate inet_ntop(AF_INET6, (void *)&pi->pi_ifaddr, 616*0Sstevel@tonic-gate abuf, sizeof (abuf)), pi->pi_flags); 617*0Sstevel@tonic-gate logmsg(LOG_DEBUG, "\tsock %d mtu %d hdw_addr len %d <%s>\n", 618*0Sstevel@tonic-gate pi->pi_sock, pi->pi_mtu, pi->pi_hdw_addr_len, 619*0Sstevel@tonic-gate ((pi->pi_hdw_addr_len != 0) ? 620*0Sstevel@tonic-gate fmt_lla(llabuf, sizeof (llabuf), pi->pi_hdw_addr, 621*0Sstevel@tonic-gate pi->pi_hdw_addr_len) : "none")); 622*0Sstevel@tonic-gate logmsg(LOG_DEBUG, "\ttoken: len %d %s\n", 623*0Sstevel@tonic-gate pi->pi_token_length, 624*0Sstevel@tonic-gate inet_ntop(AF_INET6, (void *)&pi->pi_token, 625*0Sstevel@tonic-gate abuf, sizeof (abuf))); 626*0Sstevel@tonic-gate if (pi->pi_TmpAddrsEnabled) { 627*0Sstevel@tonic-gate logmsg(LOG_DEBUG, "\ttmp_token: %s\n", 628*0Sstevel@tonic-gate inet_ntop(AF_INET6, (void *)&pi->pi_tmp_token, 629*0Sstevel@tonic-gate abuf, sizeof (abuf))); 630*0Sstevel@tonic-gate logmsg(LOG_DEBUG, "\ttmp config: pref %d valid %d " 631*0Sstevel@tonic-gate "maxdesync %d desync %d regen %d\n", 632*0Sstevel@tonic-gate pi->pi_TmpPreferredLifetime, pi->pi_TmpValidLifetime, 633*0Sstevel@tonic-gate pi->pi_TmpMaxDesyncFactor, pi->pi_TmpDesyncFactor, 634*0Sstevel@tonic-gate pi->pi_TmpRegenAdvance); 635*0Sstevel@tonic-gate } 636*0Sstevel@tonic-gate if (pi->pi_flags & IFF_POINTOPOINT) { 637*0Sstevel@tonic-gate logmsg(LOG_DEBUG, "\tdst_token: %s\n", 638*0Sstevel@tonic-gate inet_ntop(AF_INET6, (void *)&pi->pi_dst_token, 639*0Sstevel@tonic-gate abuf, sizeof (abuf))); 640*0Sstevel@tonic-gate } 641*0Sstevel@tonic-gate logmsg(LOG_DEBUG, "\tLinkMTU %d CurHopLimit %d " 642*0Sstevel@tonic-gate "BaseReachableTime %d\n\tReachableTime %d RetransTimer %d\n", 643*0Sstevel@tonic-gate pi->pi_LinkMTU, pi->pi_CurHopLimit, pi->pi_BaseReachableTime, 644*0Sstevel@tonic-gate pi->pi_ReachableTime, pi->pi_RetransTimer); 645*0Sstevel@tonic-gate if (!pi->pi_AdvSendAdvertisements) { 646*0Sstevel@tonic-gate /* Solicit state */ 647*0Sstevel@tonic-gate logmsg(LOG_DEBUG, "\tSOLICIT: time_left %d state %d count %d\n", 648*0Sstevel@tonic-gate pi->pi_sol_time_left, pi->pi_sol_state, pi->pi_sol_count); 649*0Sstevel@tonic-gate } else { 650*0Sstevel@tonic-gate /* Advertise state */ 651*0Sstevel@tonic-gate logmsg(LOG_DEBUG, "\tADVERT: time_left %d state %d count %d " 652*0Sstevel@tonic-gate "since last %d\n", 653*0Sstevel@tonic-gate pi->pi_adv_time_left, pi->pi_adv_state, pi->pi_adv_count, 654*0Sstevel@tonic-gate pi->pi_adv_time_since_sent); 655*0Sstevel@tonic-gate print_iflist(pi->pi_config); 656*0Sstevel@tonic-gate } 657*0Sstevel@tonic-gate for (pr = pi->pi_prefix_list; pr != NULL; pr = pr->pr_next) 658*0Sstevel@tonic-gate prefix_print(pr); 659*0Sstevel@tonic-gate 660*0Sstevel@tonic-gate for (adv_pr = pi->pi_adv_prefix_list; adv_pr != NULL; 661*0Sstevel@tonic-gate adv_pr = adv_pr->adv_pr_next) { 662*0Sstevel@tonic-gate adv_prefix_print(adv_pr); 663*0Sstevel@tonic-gate } 664*0Sstevel@tonic-gate 665*0Sstevel@tonic-gate for (dr = pi->pi_router_list; dr != NULL; dr = dr->dr_next) 666*0Sstevel@tonic-gate router_print(dr); 667*0Sstevel@tonic-gate 668*0Sstevel@tonic-gate logmsg(LOG_DEBUG, "\n"); 669*0Sstevel@tonic-gate } 670*0Sstevel@tonic-gate 671*0Sstevel@tonic-gate /* 672*0Sstevel@tonic-gate * Randomize pi->pi_ReachableTime. 673*0Sstevel@tonic-gate * Done periodically when there are no RAs and at a maximum frequency when 674*0Sstevel@tonic-gate * RA's arrive. 675*0Sstevel@tonic-gate * Assumes that caller has determined that it is time to generate 676*0Sstevel@tonic-gate * a new random ReachableTime. 677*0Sstevel@tonic-gate */ 678*0Sstevel@tonic-gate void 679*0Sstevel@tonic-gate phyint_reach_random(struct phyint *pi, boolean_t set_needed) 680*0Sstevel@tonic-gate { 681*0Sstevel@tonic-gate pi->pi_ReachableTime = GET_RANDOM( 682*0Sstevel@tonic-gate (int)(ND_MIN_RANDOM_FACTOR * pi->pi_BaseReachableTime), 683*0Sstevel@tonic-gate (int)(ND_MAX_RANDOM_FACTOR * pi->pi_BaseReachableTime)); 684*0Sstevel@tonic-gate if (set_needed) { 685*0Sstevel@tonic-gate struct lifreq lifr; 686*0Sstevel@tonic-gate 687*0Sstevel@tonic-gate (void) strncpy(lifr.lifr_name, pi->pi_name, 688*0Sstevel@tonic-gate sizeof (lifr.lifr_name)); 689*0Sstevel@tonic-gate pi->pi_name[sizeof (pi->pi_name) - 1] = '\0'; 690*0Sstevel@tonic-gate if (ioctl(pi->pi_sock, SIOCGLIFLNKINFO, (char *)&lifr) < 0) { 691*0Sstevel@tonic-gate logperror_pi(pi, 692*0Sstevel@tonic-gate "phyint_reach_random: SIOCGLIFLNKINFO"); 693*0Sstevel@tonic-gate return; 694*0Sstevel@tonic-gate } 695*0Sstevel@tonic-gate lifr.lifr_ifinfo.lir_reachtime = pi->pi_ReachableTime; 696*0Sstevel@tonic-gate if (ioctl(pi->pi_sock, SIOCSLIFLNKINFO, (char *)&lifr) < 0) { 697*0Sstevel@tonic-gate logperror_pi(pi, 698*0Sstevel@tonic-gate "phyint_reach_random: SIOCSLIFLNKINFO"); 699*0Sstevel@tonic-gate return; 700*0Sstevel@tonic-gate } 701*0Sstevel@tonic-gate } 702*0Sstevel@tonic-gate pi->pi_reach_time_since_random = 0; 703*0Sstevel@tonic-gate } 704*0Sstevel@tonic-gate 705*0Sstevel@tonic-gate /* 706*0Sstevel@tonic-gate * Validate a temporary token against a list of known bad values. 707*0Sstevel@tonic-gate * Currently assumes that token is 8 bytes long! Current known 708*0Sstevel@tonic-gate * bad values include 0, reserved anycast tokens (RFC 2526), tokens 709*0Sstevel@tonic-gate * used by ISATAP (draft-ietf-ngtrans-isatap-N), any token already 710*0Sstevel@tonic-gate * assigned to this interface, or any token for which the global 711*0Sstevel@tonic-gate * bit is set. 712*0Sstevel@tonic-gate * 713*0Sstevel@tonic-gate * Called by tmptoken_create(). 714*0Sstevel@tonic-gate * 715*0Sstevel@tonic-gate * Return _B_TRUE if token is valid (no match), _B_FALSE if not. 716*0Sstevel@tonic-gate */ 717*0Sstevel@tonic-gate static boolean_t 718*0Sstevel@tonic-gate tmptoken_isvalid(struct in6_addr *token) 719*0Sstevel@tonic-gate { 720*0Sstevel@tonic-gate struct phyint *pi; 721*0Sstevel@tonic-gate struct in6_addr mask; 722*0Sstevel@tonic-gate struct in6_addr isatap = { 0, 0, 0, 0, 0, 0, 0, 0, \ 723*0Sstevel@tonic-gate 0, 0, 0x5e, 0xfe, 0, 0, 0, 0 }; 724*0Sstevel@tonic-gate struct in6_addr anycast = { 0, 0, 0, 0, \ 725*0Sstevel@tonic-gate 0, 0, 0, 0, \ 726*0Sstevel@tonic-gate 0xfd, 0xff, 0xff, 0xff, \ 727*0Sstevel@tonic-gate 0xff, 0xff, 0xff, 0x80 }; 728*0Sstevel@tonic-gate 729*0Sstevel@tonic-gate if (IN6_IS_ADDR_UNSPECIFIED(token)) 730*0Sstevel@tonic-gate return (_B_FALSE); 731*0Sstevel@tonic-gate 732*0Sstevel@tonic-gate if (token->s6_addr[8] & 0x2) 733*0Sstevel@tonic-gate return (_B_FALSE); 734*0Sstevel@tonic-gate 735*0Sstevel@tonic-gate (void) memcpy(&mask, token, sizeof (mask)); 736*0Sstevel@tonic-gate mask._S6_un._S6_u32[3] = 0; 737*0Sstevel@tonic-gate if (IN6_ARE_ADDR_EQUAL(&isatap, token)) 738*0Sstevel@tonic-gate return (_B_FALSE); 739*0Sstevel@tonic-gate 740*0Sstevel@tonic-gate mask._S6_un._S6_u32[3] = token->_S6_un._S6_u32[3] & 0xffffff80; 741*0Sstevel@tonic-gate if (IN6_ARE_ADDR_EQUAL(&anycast, token)) 742*0Sstevel@tonic-gate return (_B_FALSE); 743*0Sstevel@tonic-gate 744*0Sstevel@tonic-gate for (pi = phyints; pi != NULL; pi = pi->pi_next) { 745*0Sstevel@tonic-gate if (((pi->pi_token_length == TMP_TOKEN_BITS) && 746*0Sstevel@tonic-gate IN6_ARE_ADDR_EQUAL(&pi->pi_token, token)) || 747*0Sstevel@tonic-gate IN6_ARE_ADDR_EQUAL(&pi->pi_tmp_token, token)) 748*0Sstevel@tonic-gate return (_B_FALSE); 749*0Sstevel@tonic-gate } 750*0Sstevel@tonic-gate 751*0Sstevel@tonic-gate /* none of our tests failed, must be a good one! */ 752*0Sstevel@tonic-gate return (_B_TRUE); 753*0Sstevel@tonic-gate } 754*0Sstevel@tonic-gate 755*0Sstevel@tonic-gate /* 756*0Sstevel@tonic-gate * Generate a temporary token and set up its timer 757*0Sstevel@tonic-gate * 758*0Sstevel@tonic-gate * Called from incoming_prefix_addrconf_process() (when token is first 759*0Sstevel@tonic-gate * needed) and from tmptoken_timer() (when current token expires). 760*0Sstevel@tonic-gate * 761*0Sstevel@tonic-gate * Returns _B_TRUE if a token was successfully generated, _B_FALSE if not. 762*0Sstevel@tonic-gate */ 763*0Sstevel@tonic-gate boolean_t 764*0Sstevel@tonic-gate tmptoken_create(struct phyint *pi) 765*0Sstevel@tonic-gate { 766*0Sstevel@tonic-gate int fd, i = 0, max_tries = 15; 767*0Sstevel@tonic-gate struct in6_addr token; 768*0Sstevel@tonic-gate uint32_t *tokenp = &(token._S6_un._S6_u32[2]); 769*0Sstevel@tonic-gate char buf[INET6_ADDRSTRLEN]; 770*0Sstevel@tonic-gate 771*0Sstevel@tonic-gate if ((fd = open("/dev/urandom", O_RDONLY)) == -1) { 772*0Sstevel@tonic-gate perror("open /dev/urandom"); 773*0Sstevel@tonic-gate goto no_token; 774*0Sstevel@tonic-gate } 775*0Sstevel@tonic-gate 776*0Sstevel@tonic-gate bzero((char *)&token, sizeof (token)); 777*0Sstevel@tonic-gate do { 778*0Sstevel@tonic-gate if (read(fd, (void *)tokenp, TMP_TOKEN_BYTES) == -1) { 779*0Sstevel@tonic-gate perror("read /dev/urandom"); 780*0Sstevel@tonic-gate (void) close(fd); 781*0Sstevel@tonic-gate goto no_token; 782*0Sstevel@tonic-gate } 783*0Sstevel@tonic-gate 784*0Sstevel@tonic-gate /* 785*0Sstevel@tonic-gate * Assume EUI-64 formatting, and thus 64-bit 786*0Sstevel@tonic-gate * token len; need to clear global bit. 787*0Sstevel@tonic-gate */ 788*0Sstevel@tonic-gate token.s6_addr[8] &= 0xfd; 789*0Sstevel@tonic-gate 790*0Sstevel@tonic-gate i++; 791*0Sstevel@tonic-gate 792*0Sstevel@tonic-gate } while (!tmptoken_isvalid(&token) && i < max_tries); 793*0Sstevel@tonic-gate 794*0Sstevel@tonic-gate (void) close(fd); 795*0Sstevel@tonic-gate 796*0Sstevel@tonic-gate if (i == max_tries) { 797*0Sstevel@tonic-gate no_token: 798*0Sstevel@tonic-gate logmsg(LOG_WARNING, "tmptoken_create(%s): failed to create " 799*0Sstevel@tonic-gate "token; disabling temporary addresses on %s\n", 800*0Sstevel@tonic-gate pi->pi_name, pi->pi_name); 801*0Sstevel@tonic-gate pi->pi_TmpAddrsEnabled = 0; 802*0Sstevel@tonic-gate return (_B_FALSE); 803*0Sstevel@tonic-gate } 804*0Sstevel@tonic-gate 805*0Sstevel@tonic-gate pi->pi_tmp_token = token; 806*0Sstevel@tonic-gate 807*0Sstevel@tonic-gate if (debug & D_TMP) 808*0Sstevel@tonic-gate logmsg(LOG_DEBUG, "tmptoken_create(%s): created temporary " 809*0Sstevel@tonic-gate "token %s\n", pi->pi_name, 810*0Sstevel@tonic-gate inet_ntop(AF_INET6, &pi->pi_tmp_token, buf, sizeof (buf))); 811*0Sstevel@tonic-gate 812*0Sstevel@tonic-gate pi->pi_TmpRegenCountdown = (pi->pi_TmpPreferredLifetime - 813*0Sstevel@tonic-gate pi->pi_TmpDesyncFactor - pi->pi_TmpRegenAdvance) * MILLISEC; 814*0Sstevel@tonic-gate if (pi->pi_TmpRegenCountdown != 0) 815*0Sstevel@tonic-gate timer_schedule(pi->pi_TmpRegenCountdown); 816*0Sstevel@tonic-gate 817*0Sstevel@tonic-gate return (_B_TRUE); 818*0Sstevel@tonic-gate } 819*0Sstevel@tonic-gate 820*0Sstevel@tonic-gate /* 821*0Sstevel@tonic-gate * Delete a temporary token. This is outside the normal timeout process, 822*0Sstevel@tonic-gate * so mark any existing addresses based on this token DEPRECATED and set 823*0Sstevel@tonic-gate * their preferred lifetime to 0. Don't tamper with valid lifetime, that 824*0Sstevel@tonic-gate * will be used to eventually remove the address. Also reset the current 825*0Sstevel@tonic-gate * pi_tmp_token value to 0. 826*0Sstevel@tonic-gate * 827*0Sstevel@tonic-gate * Called from incoming_prefix_addrconf_process() if DAD fails on a temp 828*0Sstevel@tonic-gate * addr. 829*0Sstevel@tonic-gate */ 830*0Sstevel@tonic-gate void 831*0Sstevel@tonic-gate tmptoken_delete(struct phyint *pi) 832*0Sstevel@tonic-gate { 833*0Sstevel@tonic-gate struct prefix *pr; 834*0Sstevel@tonic-gate 835*0Sstevel@tonic-gate for (pr = pi->pi_prefix_list; pr != NULL; pr = pr->pr_next) { 836*0Sstevel@tonic-gate if (!(pr->pr_flags & IFF_TEMPORARY) || 837*0Sstevel@tonic-gate (pr->pr_flags & IFF_DEPRECATED) || 838*0Sstevel@tonic-gate (!token_equal(pr->pr_address, pi->pi_tmp_token, 839*0Sstevel@tonic-gate TMP_TOKEN_BITS))) { 840*0Sstevel@tonic-gate continue; 841*0Sstevel@tonic-gate } 842*0Sstevel@tonic-gate pr->pr_PreferredLifetime = 0; 843*0Sstevel@tonic-gate pr->pr_state |= PR_DEPRECATED; 844*0Sstevel@tonic-gate prefix_update_k(pr); 845*0Sstevel@tonic-gate } 846*0Sstevel@tonic-gate 847*0Sstevel@tonic-gate (void) memset(&pi->pi_tmp_token, 0, sizeof (pi->pi_tmp_token)); 848*0Sstevel@tonic-gate } 849*0Sstevel@tonic-gate 850*0Sstevel@tonic-gate /* 851*0Sstevel@tonic-gate * Called from run_timeouts() with the number of milliseconds elapsed 852*0Sstevel@tonic-gate * since the last call. Determines if any timeout event has occurred 853*0Sstevel@tonic-gate * and returns the number of milliseconds until the next timeout event 854*0Sstevel@tonic-gate * for the tmp token. Returns TIMER_INFINITY for "never". 855*0Sstevel@tonic-gate */ 856*0Sstevel@tonic-gate uint_t 857*0Sstevel@tonic-gate tmptoken_timer(struct phyint *pi, uint_t elapsed) 858*0Sstevel@tonic-gate { 859*0Sstevel@tonic-gate struct nd_opt_prefix_info opt; 860*0Sstevel@tonic-gate struct sockaddr_in6 sin6; 861*0Sstevel@tonic-gate struct prefix *pr, *newpr; 862*0Sstevel@tonic-gate 863*0Sstevel@tonic-gate if (debug & D_TMP) { 864*0Sstevel@tonic-gate logmsg(LOG_DEBUG, "tmptoken_timer(%s, %d) regencountdown %d\n", 865*0Sstevel@tonic-gate pi->pi_name, (int)elapsed, pi->pi_TmpRegenCountdown); 866*0Sstevel@tonic-gate } 867*0Sstevel@tonic-gate if (!pi->pi_TmpAddrsEnabled || 868*0Sstevel@tonic-gate (pi->pi_TmpRegenCountdown == TIMER_INFINITY)) 869*0Sstevel@tonic-gate return (TIMER_INFINITY); 870*0Sstevel@tonic-gate 871*0Sstevel@tonic-gate if (pi->pi_TmpRegenCountdown > elapsed) { 872*0Sstevel@tonic-gate pi->pi_TmpRegenCountdown -= elapsed; 873*0Sstevel@tonic-gate return (pi->pi_TmpRegenCountdown); 874*0Sstevel@tonic-gate } 875*0Sstevel@tonic-gate 876*0Sstevel@tonic-gate /* 877*0Sstevel@tonic-gate * Tmp token timer has expired. Start by generating a new token. 878*0Sstevel@tonic-gate * If we can't get a new token, tmp addrs are disabled on this 879*0Sstevel@tonic-gate * interface, so there's no need to continue, or to set a timer. 880*0Sstevel@tonic-gate */ 881*0Sstevel@tonic-gate if (!tmptoken_create(pi)) 882*0Sstevel@tonic-gate return (TIMER_INFINITY); 883*0Sstevel@tonic-gate 884*0Sstevel@tonic-gate /* 885*0Sstevel@tonic-gate * Now that we have a new token, walk the list of prefixes to 886*0Sstevel@tonic-gate * find which ones need a corresponding tmp addr generated. 887*0Sstevel@tonic-gate */ 888*0Sstevel@tonic-gate for (pr = pi->pi_prefix_list; pr != NULL; pr = pr->pr_next) { 889*0Sstevel@tonic-gate 890*0Sstevel@tonic-gate if (!(pr->pr_state & PR_AUTO) || pr->pr_state & PR_STATIC || 891*0Sstevel@tonic-gate pr->pr_state & PR_DEPRECATED || 892*0Sstevel@tonic-gate pr->pr_flags & IFF_TEMPORARY) 893*0Sstevel@tonic-gate continue; 894*0Sstevel@tonic-gate 895*0Sstevel@tonic-gate newpr = prefix_create(pi, pr->pr_prefix, pr->pr_prefix_len, 896*0Sstevel@tonic-gate IFF_TEMPORARY); 897*0Sstevel@tonic-gate if (newpr == NULL) { 898*0Sstevel@tonic-gate char pbuf[INET6_ADDRSTRLEN]; 899*0Sstevel@tonic-gate char tbuf[INET6_ADDRSTRLEN]; 900*0Sstevel@tonic-gate (void) inet_ntop(AF_INET6, &pr->pr_prefix, pbuf, 901*0Sstevel@tonic-gate sizeof (pbuf)); 902*0Sstevel@tonic-gate (void) inet_ntop(AF_INET6, &pi->pi_tmp_token, tbuf, 903*0Sstevel@tonic-gate sizeof (tbuf)); 904*0Sstevel@tonic-gate logmsg(LOG_ERR, "can't create new tmp addr " 905*0Sstevel@tonic-gate "(%s, %s, %s)\n", pi->pi_name, pbuf, tbuf); 906*0Sstevel@tonic-gate continue; 907*0Sstevel@tonic-gate } 908*0Sstevel@tonic-gate 909*0Sstevel@tonic-gate /* 910*0Sstevel@tonic-gate * We want to use incoming_prefix_*_process() functions to 911*0Sstevel@tonic-gate * set up the new tmp addr, so cobble together a prefix 912*0Sstevel@tonic-gate * info option struct based on the existing prefix to pass 913*0Sstevel@tonic-gate * in. The lifetimes will be based on the current time 914*0Sstevel@tonic-gate * remaining. 915*0Sstevel@tonic-gate * 916*0Sstevel@tonic-gate * The "from" param is only used for messages; pass in 917*0Sstevel@tonic-gate * ::0 for that. 918*0Sstevel@tonic-gate */ 919*0Sstevel@tonic-gate opt.nd_opt_pi_type = ND_OPT_PREFIX_INFORMATION; 920*0Sstevel@tonic-gate opt.nd_opt_pi_len = sizeof (opt) / 8; 921*0Sstevel@tonic-gate opt.nd_opt_pi_prefix_len = pr->pr_prefix_len; 922*0Sstevel@tonic-gate opt.nd_opt_pi_flags_reserved = ND_OPT_PI_FLAG_AUTO; 923*0Sstevel@tonic-gate opt.nd_opt_pi_valid_time = 924*0Sstevel@tonic-gate htonl(pr->pr_ValidLifetime / 1000); 925*0Sstevel@tonic-gate opt.nd_opt_pi_preferred_time = 926*0Sstevel@tonic-gate htonl(pr->pr_PreferredLifetime / 1000); 927*0Sstevel@tonic-gate if (pr->pr_state & PR_ONLINK) 928*0Sstevel@tonic-gate opt.nd_opt_pi_flags_reserved &= ND_OPT_PI_FLAG_ONLINK; 929*0Sstevel@tonic-gate opt.nd_opt_pi_prefix = pr->pr_prefix; 930*0Sstevel@tonic-gate 931*0Sstevel@tonic-gate (void) memset(&sin6, 0, sizeof (sin6)); 932*0Sstevel@tonic-gate 933*0Sstevel@tonic-gate if (!incoming_prefix_addrconf_process(pi, newpr, 934*0Sstevel@tonic-gate (uchar_t *)&opt, &sin6, _B_FALSE, _B_TRUE)) { 935*0Sstevel@tonic-gate char pbuf[INET6_ADDRSTRLEN]; 936*0Sstevel@tonic-gate char tbuf[INET6_ADDRSTRLEN]; 937*0Sstevel@tonic-gate (void) inet_ntop(AF_INET6, &pr->pr_prefix, pbuf, 938*0Sstevel@tonic-gate sizeof (pbuf)); 939*0Sstevel@tonic-gate (void) inet_ntop(AF_INET6, &pi->pi_tmp_token, tbuf, 940*0Sstevel@tonic-gate sizeof (tbuf)); 941*0Sstevel@tonic-gate logmsg(LOG_ERR, "can't create new tmp addr " 942*0Sstevel@tonic-gate "(%s, %s, %s)\n", pi->pi_name, pbuf, tbuf); 943*0Sstevel@tonic-gate continue; 944*0Sstevel@tonic-gate } 945*0Sstevel@tonic-gate 946*0Sstevel@tonic-gate if (pr->pr_state & PR_ONLINK) { 947*0Sstevel@tonic-gate incoming_prefix_onlink_process(newpr, (uchar_t *)&opt); 948*0Sstevel@tonic-gate } 949*0Sstevel@tonic-gate } 950*0Sstevel@tonic-gate 951*0Sstevel@tonic-gate /* 952*0Sstevel@tonic-gate * appropriate timers were scheduled when 953*0Sstevel@tonic-gate * the token and addresses were created. 954*0Sstevel@tonic-gate */ 955*0Sstevel@tonic-gate return (TIMER_INFINITY); 956*0Sstevel@tonic-gate } 957*0Sstevel@tonic-gate 958*0Sstevel@tonic-gate /* 959*0Sstevel@tonic-gate * tlen specifies the token length in bits. Compares the lower 960*0Sstevel@tonic-gate * tlen bits of the two addresses provided and returns _B_TRUE if 961*0Sstevel@tonic-gate * they match, _B_FALSE if not. Also returns _B_FALSE for invalid 962*0Sstevel@tonic-gate * values of tlen. 963*0Sstevel@tonic-gate */ 964*0Sstevel@tonic-gate boolean_t 965*0Sstevel@tonic-gate token_equal(struct in6_addr t1, struct in6_addr t2, int tlen) 966*0Sstevel@tonic-gate { 967*0Sstevel@tonic-gate uchar_t mask; 968*0Sstevel@tonic-gate int j, abytes, tbytes, tbits; 969*0Sstevel@tonic-gate 970*0Sstevel@tonic-gate if (tlen < 0 || tlen > IPV6_ABITS) 971*0Sstevel@tonic-gate return (_B_FALSE); 972*0Sstevel@tonic-gate 973*0Sstevel@tonic-gate abytes = IPV6_ABITS >> 3; 974*0Sstevel@tonic-gate tbytes = tlen >> 3; 975*0Sstevel@tonic-gate tbits = tlen & 7; 976*0Sstevel@tonic-gate 977*0Sstevel@tonic-gate for (j = abytes - 1; j >= abytes - tbytes; j--) 978*0Sstevel@tonic-gate if (t1.s6_addr[j] != t2.s6_addr[j]) 979*0Sstevel@tonic-gate return (_B_FALSE); 980*0Sstevel@tonic-gate 981*0Sstevel@tonic-gate if (tbits == 0) 982*0Sstevel@tonic-gate return (_B_TRUE); 983*0Sstevel@tonic-gate 984*0Sstevel@tonic-gate /* We only care about the tbits rightmost bits */ 985*0Sstevel@tonic-gate mask = 0xff >> (8 - tbits); 986*0Sstevel@tonic-gate if ((t1.s6_addr[j] & mask) != (t2.s6_addr[j] & mask)) 987*0Sstevel@tonic-gate return (_B_FALSE); 988*0Sstevel@tonic-gate 989*0Sstevel@tonic-gate return (_B_TRUE); 990*0Sstevel@tonic-gate } 991*0Sstevel@tonic-gate 992*0Sstevel@tonic-gate /* 993*0Sstevel@tonic-gate * Lookup prefix structure that matches the prefix and prefix length. 994*0Sstevel@tonic-gate * Assumes that the bits after prefixlen might not be zero. 995*0Sstevel@tonic-gate */ 996*0Sstevel@tonic-gate static struct prefix * 997*0Sstevel@tonic-gate prefix_lookup(struct phyint *pi, struct in6_addr prefix, int prefixlen) 998*0Sstevel@tonic-gate { 999*0Sstevel@tonic-gate struct prefix *pr; 1000*0Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 1001*0Sstevel@tonic-gate 1002*0Sstevel@tonic-gate if (debug & D_PREFIX) { 1003*0Sstevel@tonic-gate logmsg(LOG_DEBUG, "prefix_lookup(%s, %s/%u)\n", pi->pi_name, 1004*0Sstevel@tonic-gate inet_ntop(AF_INET6, (void *)&prefix, 1005*0Sstevel@tonic-gate abuf, sizeof (abuf)), prefixlen); 1006*0Sstevel@tonic-gate } 1007*0Sstevel@tonic-gate 1008*0Sstevel@tonic-gate for (pr = pi->pi_prefix_list; pr != NULL; pr = pr->pr_next) { 1009*0Sstevel@tonic-gate if (pr->pr_prefix_len == prefixlen && 1010*0Sstevel@tonic-gate prefix_equal(prefix, pr->pr_prefix, prefixlen)) 1011*0Sstevel@tonic-gate return (pr); 1012*0Sstevel@tonic-gate } 1013*0Sstevel@tonic-gate return (NULL); 1014*0Sstevel@tonic-gate } 1015*0Sstevel@tonic-gate 1016*0Sstevel@tonic-gate /* 1017*0Sstevel@tonic-gate * Compare two prefixes that have the same prefix length. 1018*0Sstevel@tonic-gate * Fails if the prefix length is unreasonable. 1019*0Sstevel@tonic-gate */ 1020*0Sstevel@tonic-gate boolean_t 1021*0Sstevel@tonic-gate prefix_equal(struct in6_addr p1, struct in6_addr p2, int plen) 1022*0Sstevel@tonic-gate { 1023*0Sstevel@tonic-gate uchar_t mask; 1024*0Sstevel@tonic-gate int j, pbytes, pbits; 1025*0Sstevel@tonic-gate 1026*0Sstevel@tonic-gate if (plen < 0 || plen > IPV6_ABITS) 1027*0Sstevel@tonic-gate return (_B_FALSE); 1028*0Sstevel@tonic-gate 1029*0Sstevel@tonic-gate pbytes = plen >> 3; 1030*0Sstevel@tonic-gate pbits = plen & 7; 1031*0Sstevel@tonic-gate 1032*0Sstevel@tonic-gate for (j = 0; j < pbytes; j++) 1033*0Sstevel@tonic-gate if (p1.s6_addr[j] != p2.s6_addr[j]) 1034*0Sstevel@tonic-gate return (_B_FALSE); 1035*0Sstevel@tonic-gate 1036*0Sstevel@tonic-gate if (pbits == 0) 1037*0Sstevel@tonic-gate return (_B_TRUE); 1038*0Sstevel@tonic-gate 1039*0Sstevel@tonic-gate /* Make the N leftmost bits one */ 1040*0Sstevel@tonic-gate mask = 0xff << (8 - pbits); 1041*0Sstevel@tonic-gate if ((p1.s6_addr[j] & mask) != (p2.s6_addr[j] & mask)) 1042*0Sstevel@tonic-gate return (_B_FALSE); 1043*0Sstevel@tonic-gate 1044*0Sstevel@tonic-gate return (_B_TRUE); 1045*0Sstevel@tonic-gate } 1046*0Sstevel@tonic-gate 1047*0Sstevel@tonic-gate /* 1048*0Sstevel@tonic-gate * Set a prefix from an address and a prefix length. 1049*0Sstevel@tonic-gate * Force all the bits after the prefix length to be zero. 1050*0Sstevel@tonic-gate */ 1051*0Sstevel@tonic-gate void 1052*0Sstevel@tonic-gate prefix_set(struct in6_addr *prefix, struct in6_addr addr, int prefix_len) 1053*0Sstevel@tonic-gate { 1054*0Sstevel@tonic-gate uchar_t mask; 1055*0Sstevel@tonic-gate int j; 1056*0Sstevel@tonic-gate 1057*0Sstevel@tonic-gate if (prefix_len < 0 || prefix_len > IPV6_ABITS) 1058*0Sstevel@tonic-gate return; 1059*0Sstevel@tonic-gate 1060*0Sstevel@tonic-gate bzero((char *)prefix, sizeof (*prefix)); 1061*0Sstevel@tonic-gate 1062*0Sstevel@tonic-gate for (j = 0; prefix_len > 8; prefix_len -= 8, j++) 1063*0Sstevel@tonic-gate prefix->s6_addr[j] = addr.s6_addr[j]; 1064*0Sstevel@tonic-gate 1065*0Sstevel@tonic-gate /* Make the N leftmost bits one */ 1066*0Sstevel@tonic-gate mask = 0xff << (8 - prefix_len); 1067*0Sstevel@tonic-gate prefix->s6_addr[j] = addr.s6_addr[j] & mask; 1068*0Sstevel@tonic-gate } 1069*0Sstevel@tonic-gate 1070*0Sstevel@tonic-gate /* 1071*0Sstevel@tonic-gate * Lookup a prefix based on the kernel's interface name. 1072*0Sstevel@tonic-gate */ 1073*0Sstevel@tonic-gate struct prefix * 1074*0Sstevel@tonic-gate prefix_lookup_name(struct phyint *pi, char *name) 1075*0Sstevel@tonic-gate { 1076*0Sstevel@tonic-gate struct prefix *pr; 1077*0Sstevel@tonic-gate 1078*0Sstevel@tonic-gate if (debug & D_PREFIX) { 1079*0Sstevel@tonic-gate logmsg(LOG_DEBUG, "prefix_lookup_name(%s, %s)\n", 1080*0Sstevel@tonic-gate pi->pi_name, name); 1081*0Sstevel@tonic-gate } 1082*0Sstevel@tonic-gate if (name[0] == '\0') 1083*0Sstevel@tonic-gate return (NULL); 1084*0Sstevel@tonic-gate 1085*0Sstevel@tonic-gate for (pr = pi->pi_prefix_list; pr != NULL; pr = pr->pr_next) { 1086*0Sstevel@tonic-gate if (strcmp(name, pr->pr_name) == 0) 1087*0Sstevel@tonic-gate return (pr); 1088*0Sstevel@tonic-gate } 1089*0Sstevel@tonic-gate return (NULL); 1090*0Sstevel@tonic-gate } 1091*0Sstevel@tonic-gate 1092*0Sstevel@tonic-gate /* 1093*0Sstevel@tonic-gate * Search the phyints list to make sure that this new prefix does 1094*0Sstevel@tonic-gate * not already exist in any other physical interfaces that have 1095*0Sstevel@tonic-gate * the same address as this one 1096*0Sstevel@tonic-gate */ 1097*0Sstevel@tonic-gate struct prefix * 1098*0Sstevel@tonic-gate prefix_lookup_addr_match(struct prefix *pr) 1099*0Sstevel@tonic-gate { 1100*0Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 1101*0Sstevel@tonic-gate struct phyint *pi; 1102*0Sstevel@tonic-gate struct prefix *otherpr = NULL; 1103*0Sstevel@tonic-gate struct in6_addr prefix; 1104*0Sstevel@tonic-gate int prefixlen; 1105*0Sstevel@tonic-gate 1106*0Sstevel@tonic-gate if (debug & D_PREFIX) { 1107*0Sstevel@tonic-gate logmsg(LOG_DEBUG, "prefix_lookup_addr_match(%s/%u)\n", 1108*0Sstevel@tonic-gate inet_ntop(AF_INET6, (void *)&pr->pr_address, 1109*0Sstevel@tonic-gate abuf, sizeof (abuf)), pr->pr_prefix_len); 1110*0Sstevel@tonic-gate } 1111*0Sstevel@tonic-gate prefix = pr->pr_prefix; 1112*0Sstevel@tonic-gate prefixlen = pr->pr_prefix_len; 1113*0Sstevel@tonic-gate for (pi = phyints; pi != NULL; pi = pi->pi_next) { 1114*0Sstevel@tonic-gate otherpr = prefix_lookup(pi, prefix, prefixlen); 1115*0Sstevel@tonic-gate if (otherpr == pr) 1116*0Sstevel@tonic-gate continue; 1117*0Sstevel@tonic-gate if (otherpr != NULL && (otherpr->pr_state & PR_AUTO) && 1118*0Sstevel@tonic-gate IN6_ARE_ADDR_EQUAL(&pr->pr_address, 1119*0Sstevel@tonic-gate &otherpr->pr_address)) 1120*0Sstevel@tonic-gate return (otherpr); 1121*0Sstevel@tonic-gate } 1122*0Sstevel@tonic-gate return (NULL); 1123*0Sstevel@tonic-gate } 1124*0Sstevel@tonic-gate 1125*0Sstevel@tonic-gate /* 1126*0Sstevel@tonic-gate * Initialize a new prefix without setting lifetimes etc. 1127*0Sstevel@tonic-gate */ 1128*0Sstevel@tonic-gate struct prefix * 1129*0Sstevel@tonic-gate prefix_create(struct phyint *pi, struct in6_addr prefix, int prefixlen, 1130*0Sstevel@tonic-gate uint64_t flags) 1131*0Sstevel@tonic-gate { 1132*0Sstevel@tonic-gate struct prefix *pr; 1133*0Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 1134*0Sstevel@tonic-gate 1135*0Sstevel@tonic-gate if (debug & D_PREFIX) { 1136*0Sstevel@tonic-gate logmsg(LOG_DEBUG, "prefix_create(%s, %s/%u, 0x%llx)\n", 1137*0Sstevel@tonic-gate pi->pi_name, inet_ntop(AF_INET6, (void *)&prefix, 1138*0Sstevel@tonic-gate abuf, sizeof (abuf)), prefixlen, flags); 1139*0Sstevel@tonic-gate } 1140*0Sstevel@tonic-gate pr = (struct prefix *)calloc(sizeof (struct prefix), 1); 1141*0Sstevel@tonic-gate if (pr == NULL) { 1142*0Sstevel@tonic-gate logmsg(LOG_ERR, "prefix_create: out of memory\n"); 1143*0Sstevel@tonic-gate return (NULL); 1144*0Sstevel@tonic-gate } 1145*0Sstevel@tonic-gate /* 1146*0Sstevel@tonic-gate * The prefix might have non-zero bits after the prefix len bits. 1147*0Sstevel@tonic-gate * Force them to be zero. 1148*0Sstevel@tonic-gate */ 1149*0Sstevel@tonic-gate prefix_set(&pr->pr_prefix, prefix, prefixlen); 1150*0Sstevel@tonic-gate pr->pr_prefix_len = prefixlen; 1151*0Sstevel@tonic-gate pr->pr_PreferredLifetime = PREFIX_INFINITY; 1152*0Sstevel@tonic-gate pr->pr_ValidLifetime = PREFIX_INFINITY; 1153*0Sstevel@tonic-gate pr->pr_OnLinkLifetime = PREFIX_INFINITY; 1154*0Sstevel@tonic-gate pr->pr_kernel_state = 0; 1155*0Sstevel@tonic-gate pr->pr_flags |= flags; 1156*0Sstevel@tonic-gate prefix_insert(pi, pr); 1157*0Sstevel@tonic-gate return (pr); 1158*0Sstevel@tonic-gate } 1159*0Sstevel@tonic-gate 1160*0Sstevel@tonic-gate /* 1161*0Sstevel@tonic-gate * Create a new named prefix. Caller should use prefix_init_from_k 1162*0Sstevel@tonic-gate * to initialize the content. 1163*0Sstevel@tonic-gate */ 1164*0Sstevel@tonic-gate struct prefix * 1165*0Sstevel@tonic-gate prefix_create_name(struct phyint *pi, char *name) 1166*0Sstevel@tonic-gate { 1167*0Sstevel@tonic-gate struct prefix *pr; 1168*0Sstevel@tonic-gate 1169*0Sstevel@tonic-gate if (debug & D_PREFIX) { 1170*0Sstevel@tonic-gate logmsg(LOG_DEBUG, "prefix_create_name(%s, %s)\n", 1171*0Sstevel@tonic-gate pi->pi_name, name); 1172*0Sstevel@tonic-gate } 1173*0Sstevel@tonic-gate pr = (struct prefix *)calloc(sizeof (struct prefix), 1); 1174*0Sstevel@tonic-gate if (pr == NULL) { 1175*0Sstevel@tonic-gate logmsg(LOG_ERR, "prefix_create_name: out of memory\n"); 1176*0Sstevel@tonic-gate return (NULL); 1177*0Sstevel@tonic-gate } 1178*0Sstevel@tonic-gate (void) strncpy(pr->pr_name, name, sizeof (pr->pr_name)); 1179*0Sstevel@tonic-gate pr->pr_name[sizeof (pr->pr_name) - 1] = '\0'; 1180*0Sstevel@tonic-gate prefix_insert(pi, pr); 1181*0Sstevel@tonic-gate return (pr); 1182*0Sstevel@tonic-gate } 1183*0Sstevel@tonic-gate 1184*0Sstevel@tonic-gate /* Insert in linked list */ 1185*0Sstevel@tonic-gate static void 1186*0Sstevel@tonic-gate prefix_insert(struct phyint *pi, struct prefix *pr) 1187*0Sstevel@tonic-gate { 1188*0Sstevel@tonic-gate pr->pr_next = pi->pi_prefix_list; 1189*0Sstevel@tonic-gate pr->pr_prev = NULL; 1190*0Sstevel@tonic-gate if (pi->pi_prefix_list != NULL) 1191*0Sstevel@tonic-gate pi->pi_prefix_list->pr_prev = pr; 1192*0Sstevel@tonic-gate pi->pi_prefix_list = pr; 1193*0Sstevel@tonic-gate pr->pr_physical = pi; 1194*0Sstevel@tonic-gate } 1195*0Sstevel@tonic-gate 1196*0Sstevel@tonic-gate /* 1197*0Sstevel@tonic-gate * Initialize the prefix from the content of the kernel. 1198*0Sstevel@tonic-gate * If IFF_ADDRCONF is set we treat it as PR_AUTO (i.e. an addrconf 1199*0Sstevel@tonic-gate * prefix). However, we not derive the lifetimes from 1200*0Sstevel@tonic-gate * the kernel thus they are set to 1 week. 1201*0Sstevel@tonic-gate * Ignore the prefix if the interface is not IFF_UP. 1202*0Sstevel@tonic-gate */ 1203*0Sstevel@tonic-gate int 1204*0Sstevel@tonic-gate prefix_init_from_k(struct prefix *pr) 1205*0Sstevel@tonic-gate { 1206*0Sstevel@tonic-gate struct lifreq lifr; 1207*0Sstevel@tonic-gate struct sockaddr_in6 *sin6; 1208*0Sstevel@tonic-gate int sock = pr->pr_physical->pi_sock; 1209*0Sstevel@tonic-gate 1210*0Sstevel@tonic-gate (void) strncpy(lifr.lifr_name, pr->pr_name, sizeof (lifr.lifr_name)); 1211*0Sstevel@tonic-gate lifr.lifr_name[sizeof (lifr.lifr_name) - 1] = '\0'; 1212*0Sstevel@tonic-gate if (ioctl(sock, SIOCGLIFADDR, (char *)&lifr) < 0) { 1213*0Sstevel@tonic-gate logperror_pr(pr, "prefix_init_from_k: ioctl (get addr)"); 1214*0Sstevel@tonic-gate goto error; 1215*0Sstevel@tonic-gate } 1216*0Sstevel@tonic-gate if (lifr.lifr_addr.ss_family != AF_INET6) { 1217*0Sstevel@tonic-gate logmsg(LOG_ERR, "ignoring interface %s: not AF_INET6\n", 1218*0Sstevel@tonic-gate pr->pr_name); 1219*0Sstevel@tonic-gate goto error; 1220*0Sstevel@tonic-gate } 1221*0Sstevel@tonic-gate sin6 = (struct sockaddr_in6 *)&lifr.lifr_addr; 1222*0Sstevel@tonic-gate pr->pr_address = sin6->sin6_addr; 1223*0Sstevel@tonic-gate 1224*0Sstevel@tonic-gate if (ioctl(sock, SIOCGLIFFLAGS, (char *)&lifr) < 0) { 1225*0Sstevel@tonic-gate logperror_pr(pr, "prefix_init_from_k: ioctl (get flags)"); 1226*0Sstevel@tonic-gate goto error; 1227*0Sstevel@tonic-gate } 1228*0Sstevel@tonic-gate pr->pr_flags = lifr.lifr_flags; 1229*0Sstevel@tonic-gate 1230*0Sstevel@tonic-gate if (ioctl(sock, SIOCGLIFSUBNET, (char *)&lifr) < 0) { 1231*0Sstevel@tonic-gate logperror_pr(pr, "prefix_init_from_k: ioctl (get subnet)"); 1232*0Sstevel@tonic-gate goto error; 1233*0Sstevel@tonic-gate } 1234*0Sstevel@tonic-gate if (lifr.lifr_subnet.ss_family != AF_INET6) { 1235*0Sstevel@tonic-gate logmsg(LOG_ERR, "ignoring interface %s: not AF_INET6\n", 1236*0Sstevel@tonic-gate pr->pr_name); 1237*0Sstevel@tonic-gate goto error; 1238*0Sstevel@tonic-gate } 1239*0Sstevel@tonic-gate /* 1240*0Sstevel@tonic-gate * Guard against the prefix having non-zero bits after the prefix 1241*0Sstevel@tonic-gate * len bits. 1242*0Sstevel@tonic-gate */ 1243*0Sstevel@tonic-gate sin6 = (struct sockaddr_in6 *)&lifr.lifr_subnet; 1244*0Sstevel@tonic-gate pr->pr_prefix_len = lifr.lifr_addrlen; 1245*0Sstevel@tonic-gate prefix_set(&pr->pr_prefix, sin6->sin6_addr, pr->pr_prefix_len); 1246*0Sstevel@tonic-gate 1247*0Sstevel@tonic-gate if (pr->pr_prefix_len != IPV6_ABITS && (pr->pr_flags & IFF_UP) && 1248*0Sstevel@tonic-gate IN6_ARE_ADDR_EQUAL(&pr->pr_address, &pr->pr_prefix)) { 1249*0Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 1250*0Sstevel@tonic-gate 1251*0Sstevel@tonic-gate logmsg(LOG_ERR, "ingoring interface %s: it appears to be " 1252*0Sstevel@tonic-gate "configured with an invalid interface id (%s/%u)\n", 1253*0Sstevel@tonic-gate pr->pr_name, 1254*0Sstevel@tonic-gate inet_ntop(AF_INET6, (void *)&pr->pr_address, 1255*0Sstevel@tonic-gate abuf, sizeof (abuf)), pr->pr_prefix_len); 1256*0Sstevel@tonic-gate goto error; 1257*0Sstevel@tonic-gate } 1258*0Sstevel@tonic-gate pr->pr_kernel_state = 0; 1259*0Sstevel@tonic-gate if (pr->pr_prefix_len != IPV6_ABITS) 1260*0Sstevel@tonic-gate pr->pr_kernel_state |= PR_ONLINK; 1261*0Sstevel@tonic-gate if (!(pr->pr_flags & IFF_NOLOCAL)) 1262*0Sstevel@tonic-gate pr->pr_kernel_state |= PR_AUTO; 1263*0Sstevel@tonic-gate if ((pr->pr_flags & IFF_DEPRECATED) && (pr->pr_kernel_state & PR_AUTO)) 1264*0Sstevel@tonic-gate pr->pr_kernel_state |= PR_DEPRECATED; 1265*0Sstevel@tonic-gate if (!(pr->pr_flags & IFF_ADDRCONF)) { 1266*0Sstevel@tonic-gate /* Prevent ndpd from stepping on this prefix */ 1267*0Sstevel@tonic-gate pr->pr_kernel_state |= PR_STATIC; 1268*0Sstevel@tonic-gate } 1269*0Sstevel@tonic-gate pr->pr_state = pr->pr_kernel_state; 1270*0Sstevel@tonic-gate /* Adjust pr_prefix_len based if PR_AUTO is set */ 1271*0Sstevel@tonic-gate if (pr->pr_state & PR_AUTO) { 1272*0Sstevel@tonic-gate pr->pr_prefix_len = 1273*0Sstevel@tonic-gate IPV6_ABITS - pr->pr_physical->pi_token_length; 1274*0Sstevel@tonic-gate prefix_set(&pr->pr_prefix, pr->pr_prefix, pr->pr_prefix_len); 1275*0Sstevel@tonic-gate } 1276*0Sstevel@tonic-gate 1277*0Sstevel@tonic-gate /* Can't extract lifetimes from the kernel - use 1 week */ 1278*0Sstevel@tonic-gate pr->pr_ValidLifetime = NDP_PREFIX_DEFAULT_LIFETIME; 1279*0Sstevel@tonic-gate pr->pr_PreferredLifetime = NDP_PREFIX_DEFAULT_LIFETIME; 1280*0Sstevel@tonic-gate pr->pr_OnLinkLifetime = NDP_PREFIX_DEFAULT_LIFETIME; 1281*0Sstevel@tonic-gate 1282*0Sstevel@tonic-gate /* 1283*0Sstevel@tonic-gate * If this is a temp addr, the creation time needs to be set. 1284*0Sstevel@tonic-gate * Though it won't be entirely accurate, the current time is 1285*0Sstevel@tonic-gate * an okay approximation. 1286*0Sstevel@tonic-gate */ 1287*0Sstevel@tonic-gate if (pr->pr_flags & IFF_TEMPORARY) 1288*0Sstevel@tonic-gate pr->pr_CreateTime = getcurrenttime() / MILLISEC; 1289*0Sstevel@tonic-gate 1290*0Sstevel@tonic-gate if (pr->pr_kernel_state == 0) 1291*0Sstevel@tonic-gate pr->pr_name[0] = '\0'; 1292*0Sstevel@tonic-gate return (0); 1293*0Sstevel@tonic-gate 1294*0Sstevel@tonic-gate error: 1295*0Sstevel@tonic-gate /* Pretend that the prefix does not exist in the kernel */ 1296*0Sstevel@tonic-gate pr->pr_kernel_state = 0; 1297*0Sstevel@tonic-gate pr->pr_name[0] = '\0'; 1298*0Sstevel@tonic-gate return (-1); 1299*0Sstevel@tonic-gate } 1300*0Sstevel@tonic-gate 1301*0Sstevel@tonic-gate /* 1302*0Sstevel@tonic-gate * Delete (unlink and free) and remove from kernel if the prefix 1303*0Sstevel@tonic-gate * was added by in.ndpd (i.e. PR_STATIC is not set). 1304*0Sstevel@tonic-gate * Handles delete of things that have not yet been inserted in the list 1305*0Sstevel@tonic-gate * i.e. pr_physical is NULL. 1306*0Sstevel@tonic-gate */ 1307*0Sstevel@tonic-gate void 1308*0Sstevel@tonic-gate prefix_delete(struct prefix *pr) 1309*0Sstevel@tonic-gate { 1310*0Sstevel@tonic-gate struct phyint *pi; 1311*0Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 1312*0Sstevel@tonic-gate 1313*0Sstevel@tonic-gate if (debug & D_PREFIX) { 1314*0Sstevel@tonic-gate logmsg(LOG_DEBUG, "prefix_delete(%s, %s, %s/%u)\n", 1315*0Sstevel@tonic-gate pr->pr_physical->pi_name, pr->pr_name, 1316*0Sstevel@tonic-gate inet_ntop(AF_INET6, (void *)&pr->pr_prefix, 1317*0Sstevel@tonic-gate abuf, sizeof (abuf)), pr->pr_prefix_len); 1318*0Sstevel@tonic-gate } 1319*0Sstevel@tonic-gate /* Remove non-static prefixes from the kernel. */ 1320*0Sstevel@tonic-gate pr->pr_state &= PR_STATIC; 1321*0Sstevel@tonic-gate pi = pr->pr_physical; 1322*0Sstevel@tonic-gate if (pr->pr_kernel_state != pr->pr_state) 1323*0Sstevel@tonic-gate prefix_update_k(pr); 1324*0Sstevel@tonic-gate 1325*0Sstevel@tonic-gate if (pr->pr_prev == NULL) { 1326*0Sstevel@tonic-gate if (pi != NULL) 1327*0Sstevel@tonic-gate pi->pi_prefix_list = pr->pr_next; 1328*0Sstevel@tonic-gate } else { 1329*0Sstevel@tonic-gate pr->pr_prev->pr_next = pr->pr_next; 1330*0Sstevel@tonic-gate } 1331*0Sstevel@tonic-gate if (pr->pr_next != NULL) 1332*0Sstevel@tonic-gate pr->pr_next->pr_prev = pr->pr_prev; 1333*0Sstevel@tonic-gate pr->pr_next = pr->pr_prev = NULL; 1334*0Sstevel@tonic-gate free(pr); 1335*0Sstevel@tonic-gate } 1336*0Sstevel@tonic-gate 1337*0Sstevel@tonic-gate /* 1338*0Sstevel@tonic-gate * Toggle one or more IFF_ flags for a prefix. Turn on 'onflags' and 1339*0Sstevel@tonic-gate * turn off 'offflags'. 1340*0Sstevel@tonic-gate */ 1341*0Sstevel@tonic-gate static int 1342*0Sstevel@tonic-gate prefix_modify_flags(struct prefix *pr, uint64_t onflags, uint64_t offflags) 1343*0Sstevel@tonic-gate { 1344*0Sstevel@tonic-gate struct lifreq lifr; 1345*0Sstevel@tonic-gate struct phyint *pi = pr->pr_physical; 1346*0Sstevel@tonic-gate uint64_t old_flags; 1347*0Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 1348*0Sstevel@tonic-gate 1349*0Sstevel@tonic-gate if (debug & D_PREFIX) { 1350*0Sstevel@tonic-gate logmsg(LOG_DEBUG, "prefix_modify_flags(%s, %s, %s/%u) " 1351*0Sstevel@tonic-gate "flags %llx on %llx off %llx\n", 1352*0Sstevel@tonic-gate pr->pr_physical->pi_name, 1353*0Sstevel@tonic-gate pr->pr_name, 1354*0Sstevel@tonic-gate inet_ntop(AF_INET6, (void *)&pr->pr_prefix, 1355*0Sstevel@tonic-gate abuf, sizeof (abuf)), pr->pr_prefix_len, 1356*0Sstevel@tonic-gate pr->pr_flags, onflags, offflags); 1357*0Sstevel@tonic-gate } 1358*0Sstevel@tonic-gate /* Assumes that only the PR_STATIC link-local matches the pi_name */ 1359*0Sstevel@tonic-gate if (!(pr->pr_state & PR_STATIC) && 1360*0Sstevel@tonic-gate strcmp(pr->pr_name, pi->pi_name) == 0) { 1361*0Sstevel@tonic-gate logmsg(LOG_ERR, "prefix_modify_flags(%s, on %llx, off %llx): " 1362*0Sstevel@tonic-gate "name matches interface name\n", 1363*0Sstevel@tonic-gate pi->pi_name, onflags, offflags); 1364*0Sstevel@tonic-gate return (-1); 1365*0Sstevel@tonic-gate } 1366*0Sstevel@tonic-gate 1367*0Sstevel@tonic-gate (void) strncpy(lifr.lifr_name, pr->pr_name, sizeof (lifr.lifr_name)); 1368*0Sstevel@tonic-gate lifr.lifr_name[sizeof (lifr.lifr_name) - 1] = '\0'; 1369*0Sstevel@tonic-gate if (ioctl(pi->pi_sock, SIOCGLIFFLAGS, (char *)&lifr) < 0) { 1370*0Sstevel@tonic-gate logperror_pr(pr, "prefix_modify_flags: SIOCGLIFFLAGS"); 1371*0Sstevel@tonic-gate logmsg(LOG_ERR, "prefix_modify_flags(%s, %s) old 0x%llx " 1372*0Sstevel@tonic-gate "on 0x%llx off 0x%llx\n", 1373*0Sstevel@tonic-gate pr->pr_physical->pi_name, 1374*0Sstevel@tonic-gate pr->pr_name, 1375*0Sstevel@tonic-gate pr->pr_flags, onflags, offflags); 1376*0Sstevel@tonic-gate return (-1); 1377*0Sstevel@tonic-gate } 1378*0Sstevel@tonic-gate old_flags = lifr.lifr_flags; 1379*0Sstevel@tonic-gate lifr.lifr_flags |= onflags; 1380*0Sstevel@tonic-gate lifr.lifr_flags &= ~offflags; 1381*0Sstevel@tonic-gate pr->pr_flags = lifr.lifr_flags; 1382*0Sstevel@tonic-gate if (ioctl(pi->pi_sock, SIOCSLIFFLAGS, (char *)&lifr) < 0) { 1383*0Sstevel@tonic-gate logperror_pr(pr, "prefix_modify_flags: SIOCSLIFFLAGS"); 1384*0Sstevel@tonic-gate logmsg(LOG_ERR, "prefix_modify_flags(%s, %s) old 0x%llx " 1385*0Sstevel@tonic-gate "new 0x%llx on 0x%llx off 0x%llx\n", 1386*0Sstevel@tonic-gate pr->pr_physical->pi_name, 1387*0Sstevel@tonic-gate pr->pr_name, 1388*0Sstevel@tonic-gate old_flags, lifr.lifr_flags, onflags, offflags); 1389*0Sstevel@tonic-gate return (-1); 1390*0Sstevel@tonic-gate } 1391*0Sstevel@tonic-gate return (0); 1392*0Sstevel@tonic-gate } 1393*0Sstevel@tonic-gate 1394*0Sstevel@tonic-gate /* 1395*0Sstevel@tonic-gate * Make the kernel state match what is in the prefix structure. 1396*0Sstevel@tonic-gate * This includes creating the prefix (allocating a new interface name) 1397*0Sstevel@tonic-gate * as well as setting the local address and on-link subnet prefix 1398*0Sstevel@tonic-gate * and controlling the IFF_ADDRCONF and IFF_DEPRECATED flags. 1399*0Sstevel@tonic-gate */ 1400*0Sstevel@tonic-gate void 1401*0Sstevel@tonic-gate prefix_update_k(struct prefix *pr) 1402*0Sstevel@tonic-gate { 1403*0Sstevel@tonic-gate struct lifreq lifr; 1404*0Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 1405*0Sstevel@tonic-gate char buf1[PREFIX_STATESTRLEN], buf2[PREFIX_STATESTRLEN]; 1406*0Sstevel@tonic-gate struct phyint *pi = pr->pr_physical; 1407*0Sstevel@tonic-gate struct sockaddr_in6 *sin6; 1408*0Sstevel@tonic-gate 1409*0Sstevel@tonic-gate if (debug & D_PREFIX) { 1410*0Sstevel@tonic-gate logmsg(LOG_DEBUG, "prefix_update_k(%s, %s, %s/%u) " 1411*0Sstevel@tonic-gate "from %s to %s\n", pr->pr_physical->pi_name, pr->pr_name, 1412*0Sstevel@tonic-gate inet_ntop(AF_INET6, (void *)&pr->pr_prefix, 1413*0Sstevel@tonic-gate abuf, sizeof (abuf)), pr->pr_prefix_len, 1414*0Sstevel@tonic-gate prefix_print_state(pr->pr_kernel_state, buf1, 1415*0Sstevel@tonic-gate sizeof (buf1)), 1416*0Sstevel@tonic-gate prefix_print_state(pr->pr_state, buf2, sizeof (buf2))); 1417*0Sstevel@tonic-gate } 1418*0Sstevel@tonic-gate 1419*0Sstevel@tonic-gate if (pr->pr_kernel_state == pr->pr_state) 1420*0Sstevel@tonic-gate return; /* No changes */ 1421*0Sstevel@tonic-gate 1422*0Sstevel@tonic-gate /* Skip static prefixes */ 1423*0Sstevel@tonic-gate if (pr->pr_state & PR_STATIC) 1424*0Sstevel@tonic-gate return; 1425*0Sstevel@tonic-gate 1426*0Sstevel@tonic-gate if (pr->pr_kernel_state == 0) { 1427*0Sstevel@tonic-gate uint64_t onflags; 1428*0Sstevel@tonic-gate /* 1429*0Sstevel@tonic-gate * Create a new logical interface name and store in pr_name. 1430*0Sstevel@tonic-gate * Set IFF_ADDRCONF. Do not set an address (yet). 1431*0Sstevel@tonic-gate */ 1432*0Sstevel@tonic-gate if (pr->pr_name[0] != '\0') { 1433*0Sstevel@tonic-gate /* Name already set! */ 1434*0Sstevel@tonic-gate logmsg(LOG_ERR, "prefix_update_k(%s, %s, %s/%u) " 1435*0Sstevel@tonic-gate "from %s to %s name is already allocated\n", 1436*0Sstevel@tonic-gate pr->pr_physical->pi_name, pr->pr_name, 1437*0Sstevel@tonic-gate inet_ntop(AF_INET6, (void *)&pr->pr_prefix, 1438*0Sstevel@tonic-gate abuf, sizeof (abuf)), pr->pr_prefix_len, 1439*0Sstevel@tonic-gate prefix_print_state(pr->pr_kernel_state, buf1, 1440*0Sstevel@tonic-gate sizeof (buf1)), 1441*0Sstevel@tonic-gate prefix_print_state(pr->pr_state, buf2, 1442*0Sstevel@tonic-gate sizeof (buf2))); 1443*0Sstevel@tonic-gate return; 1444*0Sstevel@tonic-gate } 1445*0Sstevel@tonic-gate 1446*0Sstevel@tonic-gate (void) strncpy(lifr.lifr_name, pi->pi_name, 1447*0Sstevel@tonic-gate sizeof (lifr.lifr_name)); 1448*0Sstevel@tonic-gate lifr.lifr_name[sizeof (lifr.lifr_name) - 1] = '\0'; 1449*0Sstevel@tonic-gate lifr.lifr_addr.ss_family = AF_UNSPEC; 1450*0Sstevel@tonic-gate if (ioctl(pi->pi_sock, SIOCLIFADDIF, (char *)&lifr) < 0) { 1451*0Sstevel@tonic-gate logperror_pr(pr, "prefix_update_k: SIOCLIFADDIF"); 1452*0Sstevel@tonic-gate return; 1453*0Sstevel@tonic-gate } 1454*0Sstevel@tonic-gate (void) strncpy(pr->pr_name, lifr.lifr_name, 1455*0Sstevel@tonic-gate sizeof (pr->pr_name)); 1456*0Sstevel@tonic-gate pr->pr_name[sizeof (pr->pr_name) - 1] = '\0'; 1457*0Sstevel@tonic-gate if (debug & D_PREFIX) { 1458*0Sstevel@tonic-gate logmsg(LOG_DEBUG, "prefix_update_k: new name %s\n", 1459*0Sstevel@tonic-gate pr->pr_name); 1460*0Sstevel@tonic-gate } 1461*0Sstevel@tonic-gate /* 1462*0Sstevel@tonic-gate * The IFF_TEMPORARY flag might have already been set; if 1463*0Sstevel@tonic-gate * so, it needs to be or'd into the flags we're turning on. 1464*0Sstevel@tonic-gate * But be careful, we might be re-creating a manually 1465*0Sstevel@tonic-gate * removed interface, in which case we don't want to try 1466*0Sstevel@tonic-gate * to set *all* the flags we might have in our copy of the 1467*0Sstevel@tonic-gate * flags yet. 1468*0Sstevel@tonic-gate */ 1469*0Sstevel@tonic-gate onflags = IFF_ADDRCONF; 1470*0Sstevel@tonic-gate if (pr->pr_flags & IFF_TEMPORARY) 1471*0Sstevel@tonic-gate onflags |= IFF_TEMPORARY; 1472*0Sstevel@tonic-gate if (prefix_modify_flags(pr, onflags, 0) == -1) 1473*0Sstevel@tonic-gate return; 1474*0Sstevel@tonic-gate } 1475*0Sstevel@tonic-gate if ((pr->pr_state & (PR_ONLINK|PR_AUTO)) == 0) { 1476*0Sstevel@tonic-gate /* Remove the interface */ 1477*0Sstevel@tonic-gate if (prefix_modify_flags(pr, 0, IFF_UP|IFF_DEPRECATED) == -1) 1478*0Sstevel@tonic-gate return; 1479*0Sstevel@tonic-gate (void) strncpy(lifr.lifr_name, pr->pr_name, 1480*0Sstevel@tonic-gate sizeof (lifr.lifr_name)); 1481*0Sstevel@tonic-gate lifr.lifr_name[sizeof (lifr.lifr_name) - 1] = '\0'; 1482*0Sstevel@tonic-gate 1483*0Sstevel@tonic-gate if (debug & D_PREFIX) { 1484*0Sstevel@tonic-gate logmsg(LOG_DEBUG, "prefix_update_k: remove name %s\n", 1485*0Sstevel@tonic-gate pr->pr_name); 1486*0Sstevel@tonic-gate } 1487*0Sstevel@tonic-gate 1488*0Sstevel@tonic-gate /* 1489*0Sstevel@tonic-gate * Assumes that only the PR_STATIC link-local matches 1490*0Sstevel@tonic-gate * the pi_name 1491*0Sstevel@tonic-gate */ 1492*0Sstevel@tonic-gate if (!(pr->pr_state & PR_STATIC) && 1493*0Sstevel@tonic-gate strcmp(pr->pr_name, pi->pi_name) == 0) { 1494*0Sstevel@tonic-gate logmsg(LOG_ERR, "prefix_update_k(%s): " 1495*0Sstevel@tonic-gate "name matches if\n", pi->pi_name); 1496*0Sstevel@tonic-gate return; 1497*0Sstevel@tonic-gate } 1498*0Sstevel@tonic-gate 1499*0Sstevel@tonic-gate /* Remove logical interface based on pr_name */ 1500*0Sstevel@tonic-gate lifr.lifr_addr.ss_family = AF_UNSPEC; 1501*0Sstevel@tonic-gate if (ioctl(pi->pi_sock, SIOCLIFREMOVEIF, (char *)&lifr) < 0) { 1502*0Sstevel@tonic-gate logperror_pr(pr, "prefix_update_k: SIOCLIFREMOVEIF"); 1503*0Sstevel@tonic-gate } 1504*0Sstevel@tonic-gate pr->pr_kernel_state = 0; 1505*0Sstevel@tonic-gate pr->pr_name[0] = '\0'; 1506*0Sstevel@tonic-gate return; 1507*0Sstevel@tonic-gate } 1508*0Sstevel@tonic-gate if ((pr->pr_state & PR_AUTO) && !(pr->pr_kernel_state & PR_AUTO)) { 1509*0Sstevel@tonic-gate /* 1510*0Sstevel@tonic-gate * Set local address and set the prefix length to 128. 1511*0Sstevel@tonic-gate * Turn off IFF_NOLOCAL in case it was set. 1512*0Sstevel@tonic-gate * Turn on IFF_UP. 1513*0Sstevel@tonic-gate */ 1514*0Sstevel@tonic-gate (void) strncpy(lifr.lifr_name, pr->pr_name, 1515*0Sstevel@tonic-gate sizeof (lifr.lifr_name)); 1516*0Sstevel@tonic-gate lifr.lifr_name[sizeof (lifr.lifr_name) - 1] = '\0'; 1517*0Sstevel@tonic-gate sin6 = (struct sockaddr_in6 *)&lifr.lifr_addr; 1518*0Sstevel@tonic-gate bzero(sin6, sizeof (struct sockaddr_in6)); 1519*0Sstevel@tonic-gate sin6->sin6_family = AF_INET6; 1520*0Sstevel@tonic-gate sin6->sin6_addr = pr->pr_address; 1521*0Sstevel@tonic-gate if (debug & D_PREFIX) { 1522*0Sstevel@tonic-gate logmsg(LOG_DEBUG, "prefix_update_k(%s) set addr %s " 1523*0Sstevel@tonic-gate "for PR_AUTO on\n", 1524*0Sstevel@tonic-gate pr->pr_name, 1525*0Sstevel@tonic-gate inet_ntop(AF_INET6, (void *)&pr->pr_address, 1526*0Sstevel@tonic-gate abuf, sizeof (abuf))); 1527*0Sstevel@tonic-gate } 1528*0Sstevel@tonic-gate if (ioctl(pi->pi_sock, SIOCSLIFADDR, (char *)&lifr) < 0) { 1529*0Sstevel@tonic-gate logperror_pr(pr, "prefix_update_k: SIOCSLIFADDR"); 1530*0Sstevel@tonic-gate return; 1531*0Sstevel@tonic-gate } 1532*0Sstevel@tonic-gate if (pr->pr_state & PR_ONLINK) { 1533*0Sstevel@tonic-gate sin6->sin6_addr = pr->pr_prefix; 1534*0Sstevel@tonic-gate lifr.lifr_addrlen = pr->pr_prefix_len; 1535*0Sstevel@tonic-gate } else { 1536*0Sstevel@tonic-gate sin6->sin6_addr = pr->pr_address; 1537*0Sstevel@tonic-gate lifr.lifr_addrlen = IPV6_ABITS; 1538*0Sstevel@tonic-gate } 1539*0Sstevel@tonic-gate if (debug & D_PREFIX) { 1540*0Sstevel@tonic-gate logmsg(LOG_DEBUG, "prefix_update_k(%s) set subnet " 1541*0Sstevel@tonic-gate "%s/%u for PR_AUTO on\n", pr->pr_name, 1542*0Sstevel@tonic-gate inet_ntop(AF_INET6, (void *)&sin6->sin6_addr, 1543*0Sstevel@tonic-gate abuf, sizeof (abuf)), lifr.lifr_addrlen); 1544*0Sstevel@tonic-gate } 1545*0Sstevel@tonic-gate if (ioctl(pi->pi_sock, SIOCSLIFSUBNET, (char *)&lifr) < 0) { 1546*0Sstevel@tonic-gate logperror_pr(pr, "prefix_update_k: SIOCSLIFSUBNET"); 1547*0Sstevel@tonic-gate return; 1548*0Sstevel@tonic-gate } 1549*0Sstevel@tonic-gate /* 1550*0Sstevel@tonic-gate * For ptp interfaces, create a destination based on 1551*0Sstevel@tonic-gate * prefix and prefix len together with the remote token 1552*0Sstevel@tonic-gate * extracted from the remote pt-pt address. This is used by 1553*0Sstevel@tonic-gate * ip to choose a proper source for outgoing packets. 1554*0Sstevel@tonic-gate */ 1555*0Sstevel@tonic-gate if (pi->pi_flags & IFF_POINTOPOINT) { 1556*0Sstevel@tonic-gate int i; 1557*0Sstevel@tonic-gate 1558*0Sstevel@tonic-gate sin6 = (struct sockaddr_in6 *)&lifr.lifr_addr; 1559*0Sstevel@tonic-gate bzero(sin6, sizeof (struct sockaddr_in6)); 1560*0Sstevel@tonic-gate sin6->sin6_family = AF_INET6; 1561*0Sstevel@tonic-gate sin6->sin6_addr = pr->pr_prefix; 1562*0Sstevel@tonic-gate for (i = 0; i < 16; i++) { 1563*0Sstevel@tonic-gate sin6->sin6_addr.s6_addr[i] |= 1564*0Sstevel@tonic-gate pi->pi_dst_token.s6_addr[i]; 1565*0Sstevel@tonic-gate } 1566*0Sstevel@tonic-gate if (debug & D_PREFIX) { 1567*0Sstevel@tonic-gate logmsg(LOG_DEBUG, "prefix_update_k(%s) " 1568*0Sstevel@tonic-gate "set dstaddr %s for PR_AUTO on\n", 1569*0Sstevel@tonic-gate pr->pr_name, inet_ntop(AF_INET6, 1570*0Sstevel@tonic-gate (void *)&sin6->sin6_addr, 1571*0Sstevel@tonic-gate abuf, sizeof (abuf))); 1572*0Sstevel@tonic-gate } 1573*0Sstevel@tonic-gate if (ioctl(pi->pi_sock, SIOCSLIFDSTADDR, 1574*0Sstevel@tonic-gate (char *)&lifr) < 0) { 1575*0Sstevel@tonic-gate logperror_pr(pr, 1576*0Sstevel@tonic-gate "prefix_update_k: SIOCSLIFDSTADDR"); 1577*0Sstevel@tonic-gate return; 1578*0Sstevel@tonic-gate } 1579*0Sstevel@tonic-gate } 1580*0Sstevel@tonic-gate if (prefix_modify_flags(pr, IFF_UP, IFF_NOLOCAL) == -1) 1581*0Sstevel@tonic-gate return; 1582*0Sstevel@tonic-gate pr->pr_kernel_state |= PR_AUTO; 1583*0Sstevel@tonic-gate if (pr->pr_state & PR_ONLINK) 1584*0Sstevel@tonic-gate pr->pr_kernel_state |= PR_ONLINK; 1585*0Sstevel@tonic-gate else 1586*0Sstevel@tonic-gate pr->pr_kernel_state &= ~PR_ONLINK; 1587*0Sstevel@tonic-gate } 1588*0Sstevel@tonic-gate if (!(pr->pr_state & PR_AUTO) && (pr->pr_kernel_state & PR_AUTO)) { 1589*0Sstevel@tonic-gate /* Turn on IFF_NOLOCAL and set the local address to all zero */ 1590*0Sstevel@tonic-gate if (prefix_modify_flags(pr, IFF_NOLOCAL, 0) == -1) 1591*0Sstevel@tonic-gate return; 1592*0Sstevel@tonic-gate (void) strncpy(lifr.lifr_name, pr->pr_name, 1593*0Sstevel@tonic-gate sizeof (lifr.lifr_name)); 1594*0Sstevel@tonic-gate lifr.lifr_name[sizeof (lifr.lifr_name) - 1] = '\0'; 1595*0Sstevel@tonic-gate sin6 = (struct sockaddr_in6 *)&lifr.lifr_addr; 1596*0Sstevel@tonic-gate bzero(sin6, sizeof (struct sockaddr_in6)); 1597*0Sstevel@tonic-gate sin6->sin6_family = AF_INET6; 1598*0Sstevel@tonic-gate if (debug & D_PREFIX) { 1599*0Sstevel@tonic-gate logmsg(LOG_DEBUG, "prefix_update_k(%s) set addr %s " 1600*0Sstevel@tonic-gate "for PR_AUTO off\n", pr->pr_name, 1601*0Sstevel@tonic-gate inet_ntop(AF_INET6, (void *)&sin6->sin6_addr, 1602*0Sstevel@tonic-gate abuf, sizeof (abuf))); 1603*0Sstevel@tonic-gate } 1604*0Sstevel@tonic-gate if (ioctl(pi->pi_sock, SIOCSLIFADDR, (char *)&lifr) < 0) { 1605*0Sstevel@tonic-gate logperror_pr(pr, "prefix_update_k: SIOCSLIFADDR"); 1606*0Sstevel@tonic-gate return; 1607*0Sstevel@tonic-gate } 1608*0Sstevel@tonic-gate pr->pr_kernel_state &= ~PR_AUTO; 1609*0Sstevel@tonic-gate } 1610*0Sstevel@tonic-gate if ((pr->pr_state & PR_DEPRECATED) && 1611*0Sstevel@tonic-gate !(pr->pr_kernel_state & PR_DEPRECATED) && 1612*0Sstevel@tonic-gate (pr->pr_kernel_state & PR_AUTO)) { 1613*0Sstevel@tonic-gate /* Only applies if PR_AUTO */ 1614*0Sstevel@tonic-gate if (prefix_modify_flags(pr, IFF_DEPRECATED, 0) == -1) 1615*0Sstevel@tonic-gate return; 1616*0Sstevel@tonic-gate pr->pr_kernel_state |= PR_DEPRECATED; 1617*0Sstevel@tonic-gate } 1618*0Sstevel@tonic-gate if (!(pr->pr_state & PR_DEPRECATED) && 1619*0Sstevel@tonic-gate (pr->pr_kernel_state & PR_DEPRECATED)) { 1620*0Sstevel@tonic-gate if (prefix_modify_flags(pr, 0, IFF_DEPRECATED) == -1) 1621*0Sstevel@tonic-gate return; 1622*0Sstevel@tonic-gate pr->pr_kernel_state &= ~PR_DEPRECATED; 1623*0Sstevel@tonic-gate } 1624*0Sstevel@tonic-gate if ((pr->pr_state & PR_ONLINK) && !(pr->pr_kernel_state & PR_ONLINK)) { 1625*0Sstevel@tonic-gate /* Set the subnet and set IFF_UP */ 1626*0Sstevel@tonic-gate (void) strncpy(lifr.lifr_name, pr->pr_name, 1627*0Sstevel@tonic-gate sizeof (lifr.lifr_name)); 1628*0Sstevel@tonic-gate lifr.lifr_name[sizeof (lifr.lifr_name) - 1] = '\0'; 1629*0Sstevel@tonic-gate sin6 = (struct sockaddr_in6 *)&lifr.lifr_addr; 1630*0Sstevel@tonic-gate bzero(sin6, sizeof (struct sockaddr_in6)); 1631*0Sstevel@tonic-gate sin6->sin6_family = AF_INET6; 1632*0Sstevel@tonic-gate sin6->sin6_addr = pr->pr_prefix; 1633*0Sstevel@tonic-gate lifr.lifr_addrlen = pr->pr_prefix_len; 1634*0Sstevel@tonic-gate if (debug & D_PREFIX) { 1635*0Sstevel@tonic-gate logmsg(LOG_DEBUG, "prefix_update_k(%s) set subnet " 1636*0Sstevel@tonic-gate "%s/%d for PR_ONLINK on\n", pr->pr_name, 1637*0Sstevel@tonic-gate inet_ntop(AF_INET6, (void *)&sin6->sin6_addr, 1638*0Sstevel@tonic-gate abuf, sizeof (abuf)), lifr.lifr_addrlen); 1639*0Sstevel@tonic-gate } 1640*0Sstevel@tonic-gate if (ioctl(pi->pi_sock, SIOCSLIFSUBNET, (char *)&lifr) < 0) { 1641*0Sstevel@tonic-gate logperror_pr(pr, "prefix_update_k: SIOCSLIFSUBNET"); 1642*0Sstevel@tonic-gate return; 1643*0Sstevel@tonic-gate } 1644*0Sstevel@tonic-gate if (!(pr->pr_state & PR_AUTO)) { 1645*0Sstevel@tonic-gate if (prefix_modify_flags(pr, IFF_NOLOCAL, 0) == -1) 1646*0Sstevel@tonic-gate return; 1647*0Sstevel@tonic-gate } 1648*0Sstevel@tonic-gate if (prefix_modify_flags(pr, IFF_UP, 0) == -1) 1649*0Sstevel@tonic-gate return; 1650*0Sstevel@tonic-gate pr->pr_kernel_state |= PR_ONLINK; 1651*0Sstevel@tonic-gate } 1652*0Sstevel@tonic-gate if (!(pr->pr_state & PR_ONLINK) && (pr->pr_kernel_state & PR_ONLINK)) { 1653*0Sstevel@tonic-gate /* Set the prefixlen to 128 */ 1654*0Sstevel@tonic-gate (void) strncpy(lifr.lifr_name, pr->pr_name, 1655*0Sstevel@tonic-gate sizeof (lifr.lifr_name)); 1656*0Sstevel@tonic-gate lifr.lifr_name[sizeof (lifr.lifr_name) - 1] = '\0'; 1657*0Sstevel@tonic-gate sin6 = (struct sockaddr_in6 *)&lifr.lifr_addr; 1658*0Sstevel@tonic-gate bzero(sin6, sizeof (struct sockaddr_in6)); 1659*0Sstevel@tonic-gate sin6->sin6_family = AF_INET6; 1660*0Sstevel@tonic-gate sin6->sin6_addr = pr->pr_address; 1661*0Sstevel@tonic-gate lifr.lifr_addrlen = IPV6_ABITS; 1662*0Sstevel@tonic-gate if (debug & D_PREFIX) { 1663*0Sstevel@tonic-gate logmsg(LOG_DEBUG, "prefix_update_k(%s) set subnet " 1664*0Sstevel@tonic-gate "%s/%d for PR_ONLINK off\n", pr->pr_name, 1665*0Sstevel@tonic-gate inet_ntop(AF_INET6, (void *)&sin6->sin6_addr, 1666*0Sstevel@tonic-gate abuf, sizeof (abuf)), lifr.lifr_addrlen); 1667*0Sstevel@tonic-gate } 1668*0Sstevel@tonic-gate if (ioctl(pi->pi_sock, SIOCSLIFSUBNET, (char *)&lifr) < 0) { 1669*0Sstevel@tonic-gate logperror_pr(pr, "prefix_update_k: SIOCSLIFSUBNET"); 1670*0Sstevel@tonic-gate return; 1671*0Sstevel@tonic-gate } 1672*0Sstevel@tonic-gate pr->pr_kernel_state &= ~PR_ONLINK; 1673*0Sstevel@tonic-gate } 1674*0Sstevel@tonic-gate } 1675*0Sstevel@tonic-gate 1676*0Sstevel@tonic-gate /* 1677*0Sstevel@tonic-gate * Called with the number of millseconds elapsed since the last call. 1678*0Sstevel@tonic-gate * Determines if any timeout event has occurred and 1679*0Sstevel@tonic-gate * returns the number of milliseconds until the next timeout event. 1680*0Sstevel@tonic-gate * Returns TIMER_INFINITY for "never". 1681*0Sstevel@tonic-gate */ 1682*0Sstevel@tonic-gate uint_t 1683*0Sstevel@tonic-gate prefix_timer(struct prefix *pr, uint_t elapsed) 1684*0Sstevel@tonic-gate { 1685*0Sstevel@tonic-gate uint_t next = TIMER_INFINITY; 1686*0Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 1687*0Sstevel@tonic-gate 1688*0Sstevel@tonic-gate if (debug & (D_PREFIX|D_TMP)) { 1689*0Sstevel@tonic-gate logmsg(LOG_DEBUG, "prefix_timer(%s, %s/%u, %d) " 1690*0Sstevel@tonic-gate "valid %d pref %d onlink %d\n", 1691*0Sstevel@tonic-gate pr->pr_name, 1692*0Sstevel@tonic-gate inet_ntop(AF_INET6, (void *)&pr->pr_prefix, 1693*0Sstevel@tonic-gate abuf, sizeof (abuf)), pr->pr_prefix_len, 1694*0Sstevel@tonic-gate elapsed, pr->pr_ValidLifetime, pr->pr_PreferredLifetime, 1695*0Sstevel@tonic-gate pr->pr_OnLinkLifetime); 1696*0Sstevel@tonic-gate } 1697*0Sstevel@tonic-gate 1698*0Sstevel@tonic-gate /* Exclude static prefixes */ 1699*0Sstevel@tonic-gate if (pr->pr_state & PR_STATIC) 1700*0Sstevel@tonic-gate return (next); 1701*0Sstevel@tonic-gate 1702*0Sstevel@tonic-gate if (pr->pr_AutonomousFlag && 1703*0Sstevel@tonic-gate (pr->pr_PreferredLifetime != PREFIX_INFINITY)) { 1704*0Sstevel@tonic-gate if (pr->pr_PreferredLifetime <= elapsed) { 1705*0Sstevel@tonic-gate pr->pr_PreferredLifetime = 0; 1706*0Sstevel@tonic-gate } else { 1707*0Sstevel@tonic-gate pr->pr_PreferredLifetime -= elapsed; 1708*0Sstevel@tonic-gate if (pr->pr_PreferredLifetime < next) 1709*0Sstevel@tonic-gate next = pr->pr_PreferredLifetime; 1710*0Sstevel@tonic-gate } 1711*0Sstevel@tonic-gate } 1712*0Sstevel@tonic-gate if (pr->pr_AutonomousFlag && 1713*0Sstevel@tonic-gate (pr->pr_ValidLifetime != PREFIX_INFINITY)) { 1714*0Sstevel@tonic-gate if (pr->pr_ValidLifetime <= elapsed) { 1715*0Sstevel@tonic-gate pr->pr_ValidLifetime = 0; 1716*0Sstevel@tonic-gate } else { 1717*0Sstevel@tonic-gate pr->pr_ValidLifetime -= elapsed; 1718*0Sstevel@tonic-gate if (pr->pr_ValidLifetime < next) 1719*0Sstevel@tonic-gate next = pr->pr_ValidLifetime; 1720*0Sstevel@tonic-gate } 1721*0Sstevel@tonic-gate } 1722*0Sstevel@tonic-gate if (pr->pr_OnLinkFlag && 1723*0Sstevel@tonic-gate (pr->pr_OnLinkLifetime != PREFIX_INFINITY)) { 1724*0Sstevel@tonic-gate if (pr->pr_OnLinkLifetime <= elapsed) { 1725*0Sstevel@tonic-gate pr->pr_OnLinkLifetime = 0; 1726*0Sstevel@tonic-gate } else { 1727*0Sstevel@tonic-gate pr->pr_OnLinkLifetime -= elapsed; 1728*0Sstevel@tonic-gate if (pr->pr_OnLinkLifetime < next) 1729*0Sstevel@tonic-gate next = pr->pr_OnLinkLifetime; 1730*0Sstevel@tonic-gate } 1731*0Sstevel@tonic-gate } 1732*0Sstevel@tonic-gate if (pr->pr_AutonomousFlag && pr->pr_ValidLifetime == 0) 1733*0Sstevel@tonic-gate pr->pr_state &= ~(PR_AUTO|PR_DEPRECATED); 1734*0Sstevel@tonic-gate if (pr->pr_AutonomousFlag && pr->pr_PreferredLifetime == 0 && 1735*0Sstevel@tonic-gate (pr->pr_state & PR_AUTO)) { 1736*0Sstevel@tonic-gate pr->pr_state |= PR_DEPRECATED; 1737*0Sstevel@tonic-gate if (debug & D_TMP) 1738*0Sstevel@tonic-gate logmsg(LOG_WARNING, "prefix_timer: deprecated " 1739*0Sstevel@tonic-gate "prefix(%s)\n", pr->pr_name); 1740*0Sstevel@tonic-gate } 1741*0Sstevel@tonic-gate if (pr->pr_OnLinkFlag && pr->pr_OnLinkLifetime == 0) 1742*0Sstevel@tonic-gate pr->pr_state &= ~PR_ONLINK; 1743*0Sstevel@tonic-gate 1744*0Sstevel@tonic-gate if (pr->pr_state != pr->pr_kernel_state) { 1745*0Sstevel@tonic-gate /* Might cause prefix to be deleted! */ 1746*0Sstevel@tonic-gate 1747*0Sstevel@tonic-gate /* Log a message when an addrconf prefix goes away */ 1748*0Sstevel@tonic-gate if ((pr->pr_kernel_state & PR_AUTO) && 1749*0Sstevel@tonic-gate !(pr->pr_state & PR_AUTO)) { 1750*0Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 1751*0Sstevel@tonic-gate 1752*0Sstevel@tonic-gate logmsg(LOG_WARNING, 1753*0Sstevel@tonic-gate "Address removed due to timeout %s\n", 1754*0Sstevel@tonic-gate inet_ntop(AF_INET6, (void *)&pr->pr_address, 1755*0Sstevel@tonic-gate abuf, sizeof (abuf))); 1756*0Sstevel@tonic-gate } 1757*0Sstevel@tonic-gate prefix_update_k(pr); 1758*0Sstevel@tonic-gate } 1759*0Sstevel@tonic-gate 1760*0Sstevel@tonic-gate return (next); 1761*0Sstevel@tonic-gate } 1762*0Sstevel@tonic-gate 1763*0Sstevel@tonic-gate static char * 1764*0Sstevel@tonic-gate prefix_print_state(int state, char *buf, int buflen) 1765*0Sstevel@tonic-gate { 1766*0Sstevel@tonic-gate char *cp; 1767*0Sstevel@tonic-gate int cplen = buflen; 1768*0Sstevel@tonic-gate 1769*0Sstevel@tonic-gate cp = buf; 1770*0Sstevel@tonic-gate cp[0] = '\0'; 1771*0Sstevel@tonic-gate 1772*0Sstevel@tonic-gate if (state & PR_ONLINK) { 1773*0Sstevel@tonic-gate if (strlcat(cp, "ONLINK ", cplen) >= cplen) 1774*0Sstevel@tonic-gate return (buf); 1775*0Sstevel@tonic-gate cp += strlen(cp); 1776*0Sstevel@tonic-gate cplen = buflen - (cp - buf); 1777*0Sstevel@tonic-gate } 1778*0Sstevel@tonic-gate if (state & PR_AUTO) { 1779*0Sstevel@tonic-gate if (strlcat(cp, "AUTO ", cplen) >= cplen) 1780*0Sstevel@tonic-gate return (buf); 1781*0Sstevel@tonic-gate cp += strlen(cp); 1782*0Sstevel@tonic-gate cplen = buflen - (cp - buf); 1783*0Sstevel@tonic-gate } 1784*0Sstevel@tonic-gate if (state & PR_DEPRECATED) { 1785*0Sstevel@tonic-gate if (strlcat(cp, "DEPRECATED ", cplen) >= cplen) 1786*0Sstevel@tonic-gate return (buf); 1787*0Sstevel@tonic-gate cp += strlen(cp); 1788*0Sstevel@tonic-gate cplen = buflen - (cp - buf); 1789*0Sstevel@tonic-gate } 1790*0Sstevel@tonic-gate if (state & PR_STATIC) { 1791*0Sstevel@tonic-gate if (strlcat(cp, "STATIC ", cplen) >= cplen) 1792*0Sstevel@tonic-gate return (buf); 1793*0Sstevel@tonic-gate cp += strlen(cp); 1794*0Sstevel@tonic-gate cplen = buflen - (cp - buf); 1795*0Sstevel@tonic-gate } 1796*0Sstevel@tonic-gate return (buf); 1797*0Sstevel@tonic-gate } 1798*0Sstevel@tonic-gate 1799*0Sstevel@tonic-gate static void 1800*0Sstevel@tonic-gate prefix_print(struct prefix *pr) 1801*0Sstevel@tonic-gate { 1802*0Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 1803*0Sstevel@tonic-gate char buf1[PREFIX_STATESTRLEN], buf2[PREFIX_STATESTRLEN]; 1804*0Sstevel@tonic-gate 1805*0Sstevel@tonic-gate logmsg(LOG_DEBUG, "Prefix name: %s prefix %s/%u state %s " 1806*0Sstevel@tonic-gate "kernel_state %s\n", pr->pr_name, 1807*0Sstevel@tonic-gate inet_ntop(AF_INET6, (void *)&pr->pr_prefix, abuf, sizeof (abuf)), 1808*0Sstevel@tonic-gate pr->pr_prefix_len, 1809*0Sstevel@tonic-gate prefix_print_state(pr->pr_state, buf2, sizeof (buf2)), 1810*0Sstevel@tonic-gate prefix_print_state(pr->pr_kernel_state, buf1, sizeof (buf1))); 1811*0Sstevel@tonic-gate logmsg(LOG_DEBUG, "\tAddress: %s flags %llx in_use %d\n", 1812*0Sstevel@tonic-gate inet_ntop(AF_INET6, (void *)&pr->pr_address, abuf, sizeof (abuf)), 1813*0Sstevel@tonic-gate pr->pr_flags, pr->pr_in_use); 1814*0Sstevel@tonic-gate logmsg(LOG_DEBUG, "\tValidLifetime %u PreferredLifetime %u " 1815*0Sstevel@tonic-gate "OnLinkLifetime %u\n", pr->pr_ValidLifetime, 1816*0Sstevel@tonic-gate pr->pr_PreferredLifetime, pr->pr_OnLinkLifetime); 1817*0Sstevel@tonic-gate logmsg(LOG_DEBUG, "\tOnLink %d Auto %d\n", 1818*0Sstevel@tonic-gate pr->pr_OnLinkFlag, pr->pr_AutonomousFlag); 1819*0Sstevel@tonic-gate logmsg(LOG_DEBUG, "\n"); 1820*0Sstevel@tonic-gate } 1821*0Sstevel@tonic-gate 1822*0Sstevel@tonic-gate /* 1823*0Sstevel@tonic-gate * Does the address formed by pr->pr_prefix and pi->pi_token match 1824*0Sstevel@tonic-gate * pr->pr_address. It does not match if a failover has happened 1825*0Sstevel@tonic-gate * earlier (done by in.mpathd) from a different pi. Should not 1826*0Sstevel@tonic-gate * be called for onlink prefixes. 1827*0Sstevel@tonic-gate */ 1828*0Sstevel@tonic-gate boolean_t 1829*0Sstevel@tonic-gate prefix_token_match(struct phyint *pi, struct prefix *pr, uint64_t flags) 1830*0Sstevel@tonic-gate { 1831*0Sstevel@tonic-gate int i; 1832*0Sstevel@tonic-gate in6_addr_t addr, *token; 1833*0Sstevel@tonic-gate 1834*0Sstevel@tonic-gate if (flags & IFF_TEMPORARY) 1835*0Sstevel@tonic-gate token = &pi->pi_tmp_token; 1836*0Sstevel@tonic-gate else 1837*0Sstevel@tonic-gate token = &pi->pi_token; 1838*0Sstevel@tonic-gate for (i = 0; i < 16; i++) { 1839*0Sstevel@tonic-gate /* 1840*0Sstevel@tonic-gate * prefix_create ensures that pr_prefix has all-zero 1841*0Sstevel@tonic-gate * bits after prefixlen. 1842*0Sstevel@tonic-gate */ 1843*0Sstevel@tonic-gate addr.s6_addr[i] = pr->pr_prefix.s6_addr[i] | token->s6_addr[i]; 1844*0Sstevel@tonic-gate } 1845*0Sstevel@tonic-gate if (IN6_ARE_ADDR_EQUAL(&pr->pr_address, &addr)) { 1846*0Sstevel@tonic-gate return (_B_TRUE); 1847*0Sstevel@tonic-gate } else { 1848*0Sstevel@tonic-gate return (_B_FALSE); 1849*0Sstevel@tonic-gate } 1850*0Sstevel@tonic-gate } 1851*0Sstevel@tonic-gate 1852*0Sstevel@tonic-gate /* 1853*0Sstevel@tonic-gate * Lookup advertisement prefix structure that matches the prefix and 1854*0Sstevel@tonic-gate * prefix length. 1855*0Sstevel@tonic-gate * Assumes that the bits after prefixlen might not be zero. 1856*0Sstevel@tonic-gate */ 1857*0Sstevel@tonic-gate struct adv_prefix * 1858*0Sstevel@tonic-gate adv_prefix_lookup(struct phyint *pi, struct in6_addr prefix, int prefixlen) 1859*0Sstevel@tonic-gate { 1860*0Sstevel@tonic-gate struct adv_prefix *adv_pr; 1861*0Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 1862*0Sstevel@tonic-gate 1863*0Sstevel@tonic-gate if (debug & D_PREFIX) { 1864*0Sstevel@tonic-gate logmsg(LOG_DEBUG, "adv_prefix_lookup(%s, %s/%u)\n", 1865*0Sstevel@tonic-gate pi->pi_name, inet_ntop(AF_INET6, (void *)&prefix, 1866*0Sstevel@tonic-gate abuf, sizeof (abuf)), prefixlen); 1867*0Sstevel@tonic-gate } 1868*0Sstevel@tonic-gate 1869*0Sstevel@tonic-gate for (adv_pr = pi->pi_adv_prefix_list; adv_pr != NULL; 1870*0Sstevel@tonic-gate adv_pr = adv_pr->adv_pr_next) { 1871*0Sstevel@tonic-gate if (adv_pr->adv_pr_prefix_len == prefixlen && 1872*0Sstevel@tonic-gate prefix_equal(prefix, adv_pr->adv_pr_prefix, prefixlen)) 1873*0Sstevel@tonic-gate return (adv_pr); 1874*0Sstevel@tonic-gate } 1875*0Sstevel@tonic-gate return (NULL); 1876*0Sstevel@tonic-gate } 1877*0Sstevel@tonic-gate 1878*0Sstevel@tonic-gate /* 1879*0Sstevel@tonic-gate * Initialize a new advertisement prefix. 1880*0Sstevel@tonic-gate */ 1881*0Sstevel@tonic-gate struct adv_prefix * 1882*0Sstevel@tonic-gate adv_prefix_create(struct phyint *pi, struct in6_addr prefix, int prefixlen) 1883*0Sstevel@tonic-gate { 1884*0Sstevel@tonic-gate struct adv_prefix *adv_pr; 1885*0Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 1886*0Sstevel@tonic-gate 1887*0Sstevel@tonic-gate if (debug & D_PREFIX) { 1888*0Sstevel@tonic-gate logmsg(LOG_DEBUG, "adv_prefix_create(%s, %s/%u)\n", 1889*0Sstevel@tonic-gate pi->pi_name, inet_ntop(AF_INET6, (void *)&prefix, 1890*0Sstevel@tonic-gate abuf, sizeof (abuf)), prefixlen); 1891*0Sstevel@tonic-gate } 1892*0Sstevel@tonic-gate adv_pr = (struct adv_prefix *)calloc(sizeof (struct adv_prefix), 1); 1893*0Sstevel@tonic-gate if (adv_pr == NULL) { 1894*0Sstevel@tonic-gate logmsg(LOG_ERR, "adv_prefix_create: calloc\n"); 1895*0Sstevel@tonic-gate return (NULL); 1896*0Sstevel@tonic-gate } 1897*0Sstevel@tonic-gate /* 1898*0Sstevel@tonic-gate * The prefix might have non-zero bits after the prefix len bits. 1899*0Sstevel@tonic-gate * Force them to be zero. 1900*0Sstevel@tonic-gate */ 1901*0Sstevel@tonic-gate prefix_set(&adv_pr->adv_pr_prefix, prefix, prefixlen); 1902*0Sstevel@tonic-gate adv_pr->adv_pr_prefix_len = prefixlen; 1903*0Sstevel@tonic-gate adv_prefix_insert(pi, adv_pr); 1904*0Sstevel@tonic-gate return (adv_pr); 1905*0Sstevel@tonic-gate } 1906*0Sstevel@tonic-gate 1907*0Sstevel@tonic-gate /* Insert in linked list */ 1908*0Sstevel@tonic-gate static void 1909*0Sstevel@tonic-gate adv_prefix_insert(struct phyint *pi, struct adv_prefix *adv_pr) 1910*0Sstevel@tonic-gate { 1911*0Sstevel@tonic-gate adv_pr->adv_pr_next = pi->pi_adv_prefix_list; 1912*0Sstevel@tonic-gate adv_pr->adv_pr_prev = NULL; 1913*0Sstevel@tonic-gate if (pi->pi_adv_prefix_list != NULL) 1914*0Sstevel@tonic-gate pi->pi_adv_prefix_list->adv_pr_prev = adv_pr; 1915*0Sstevel@tonic-gate pi->pi_adv_prefix_list = adv_pr; 1916*0Sstevel@tonic-gate adv_pr->adv_pr_physical = pi; 1917*0Sstevel@tonic-gate } 1918*0Sstevel@tonic-gate 1919*0Sstevel@tonic-gate /* 1920*0Sstevel@tonic-gate * Delete (unlink and free) from our tables. There should be 1921*0Sstevel@tonic-gate * a corresponding "struct prefix *" which will clean up the kernel 1922*0Sstevel@tonic-gate * if necessary. adv_prefix is just used for sending out advertisements. 1923*0Sstevel@tonic-gate */ 1924*0Sstevel@tonic-gate static void 1925*0Sstevel@tonic-gate adv_prefix_delete(struct adv_prefix *adv_pr) 1926*0Sstevel@tonic-gate { 1927*0Sstevel@tonic-gate struct phyint *pi; 1928*0Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 1929*0Sstevel@tonic-gate 1930*0Sstevel@tonic-gate if (debug & D_PREFIX) { 1931*0Sstevel@tonic-gate logmsg(LOG_DEBUG, "adv_prefix_delete(%s, %s/%u)\n", 1932*0Sstevel@tonic-gate adv_pr->adv_pr_physical->pi_name, 1933*0Sstevel@tonic-gate inet_ntop(AF_INET6, (void *)&adv_pr->adv_pr_prefix, 1934*0Sstevel@tonic-gate abuf, sizeof (abuf)), adv_pr->adv_pr_prefix_len); 1935*0Sstevel@tonic-gate } 1936*0Sstevel@tonic-gate pi = adv_pr->adv_pr_physical; 1937*0Sstevel@tonic-gate 1938*0Sstevel@tonic-gate if (adv_pr->adv_pr_prev == NULL) { 1939*0Sstevel@tonic-gate if (pi != NULL) 1940*0Sstevel@tonic-gate pi->pi_adv_prefix_list = adv_pr->adv_pr_next; 1941*0Sstevel@tonic-gate } else { 1942*0Sstevel@tonic-gate adv_pr->adv_pr_prev->adv_pr_next = adv_pr->adv_pr_next; 1943*0Sstevel@tonic-gate } 1944*0Sstevel@tonic-gate if (adv_pr->adv_pr_next != NULL) 1945*0Sstevel@tonic-gate adv_pr->adv_pr_next->adv_pr_prev = adv_pr->adv_pr_prev; 1946*0Sstevel@tonic-gate adv_pr->adv_pr_next = adv_pr->adv_pr_prev = NULL; 1947*0Sstevel@tonic-gate free(adv_pr); 1948*0Sstevel@tonic-gate } 1949*0Sstevel@tonic-gate 1950*0Sstevel@tonic-gate /* 1951*0Sstevel@tonic-gate * Called with the number of millseconds elapsed since the last call. 1952*0Sstevel@tonic-gate * Determines if any timeout event has occurred and 1953*0Sstevel@tonic-gate * returns the number of milliseconds until the next timeout event. 1954*0Sstevel@tonic-gate * Returns TIMER_INFINITY for "never". 1955*0Sstevel@tonic-gate */ 1956*0Sstevel@tonic-gate uint_t 1957*0Sstevel@tonic-gate adv_prefix_timer(struct adv_prefix *adv_pr, uint_t elapsed) 1958*0Sstevel@tonic-gate { 1959*0Sstevel@tonic-gate int seconds_elapsed = (elapsed + 500) / 1000; /* Rounded */ 1960*0Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 1961*0Sstevel@tonic-gate 1962*0Sstevel@tonic-gate if (debug & D_PREFIX) { 1963*0Sstevel@tonic-gate logmsg(LOG_DEBUG, "adv_prefix_timer(%s, %s/%u, %d)\n", 1964*0Sstevel@tonic-gate adv_pr->adv_pr_physical->pi_name, 1965*0Sstevel@tonic-gate inet_ntop(AF_INET6, (void *)&adv_pr->adv_pr_prefix, 1966*0Sstevel@tonic-gate abuf, sizeof (abuf)), adv_pr->adv_pr_prefix_len, 1967*0Sstevel@tonic-gate elapsed); 1968*0Sstevel@tonic-gate } 1969*0Sstevel@tonic-gate 1970*0Sstevel@tonic-gate /* Decrement Expire time left for real-time lifetimes */ 1971*0Sstevel@tonic-gate if (adv_pr->adv_pr_AdvValidRealTime) { 1972*0Sstevel@tonic-gate if (adv_pr->adv_pr_AdvValidExpiration > seconds_elapsed) 1973*0Sstevel@tonic-gate adv_pr->adv_pr_AdvValidExpiration -= seconds_elapsed; 1974*0Sstevel@tonic-gate else 1975*0Sstevel@tonic-gate adv_pr->adv_pr_AdvValidExpiration = 0; 1976*0Sstevel@tonic-gate } 1977*0Sstevel@tonic-gate if (adv_pr->adv_pr_AdvPreferredRealTime) { 1978*0Sstevel@tonic-gate if (adv_pr->adv_pr_AdvPreferredExpiration > seconds_elapsed) { 1979*0Sstevel@tonic-gate adv_pr->adv_pr_AdvPreferredExpiration -= 1980*0Sstevel@tonic-gate seconds_elapsed; 1981*0Sstevel@tonic-gate } else { 1982*0Sstevel@tonic-gate adv_pr->adv_pr_AdvPreferredExpiration = 0; 1983*0Sstevel@tonic-gate } 1984*0Sstevel@tonic-gate } 1985*0Sstevel@tonic-gate return (TIMER_INFINITY); 1986*0Sstevel@tonic-gate } 1987*0Sstevel@tonic-gate 1988*0Sstevel@tonic-gate static void 1989*0Sstevel@tonic-gate adv_prefix_print(struct adv_prefix *adv_pr) 1990*0Sstevel@tonic-gate { 1991*0Sstevel@tonic-gate print_prefixlist(adv_pr->adv_pr_config); 1992*0Sstevel@tonic-gate } 1993*0Sstevel@tonic-gate 1994*0Sstevel@tonic-gate /* Lookup router on its link-local IPv6 address */ 1995*0Sstevel@tonic-gate struct router * 1996*0Sstevel@tonic-gate router_lookup(struct phyint *pi, struct in6_addr addr) 1997*0Sstevel@tonic-gate { 1998*0Sstevel@tonic-gate struct router *dr; 1999*0Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 2000*0Sstevel@tonic-gate 2001*0Sstevel@tonic-gate if (debug & D_ROUTER) { 2002*0Sstevel@tonic-gate logmsg(LOG_DEBUG, "router_lookup(%s, %s)\n", pi->pi_name, 2003*0Sstevel@tonic-gate inet_ntop(AF_INET6, (void *)&addr, 2004*0Sstevel@tonic-gate abuf, sizeof (abuf))); 2005*0Sstevel@tonic-gate } 2006*0Sstevel@tonic-gate 2007*0Sstevel@tonic-gate for (dr = pi->pi_router_list; dr != NULL; dr = dr->dr_next) { 2008*0Sstevel@tonic-gate if (bcmp((char *)&addr, (char *)&dr->dr_address, 2009*0Sstevel@tonic-gate sizeof (addr)) == 0) 2010*0Sstevel@tonic-gate return (dr); 2011*0Sstevel@tonic-gate } 2012*0Sstevel@tonic-gate return (NULL); 2013*0Sstevel@tonic-gate } 2014*0Sstevel@tonic-gate 2015*0Sstevel@tonic-gate /* 2016*0Sstevel@tonic-gate * Create a default router entry. 2017*0Sstevel@tonic-gate * The lifetime parameter is in seconds. 2018*0Sstevel@tonic-gate */ 2019*0Sstevel@tonic-gate struct router * 2020*0Sstevel@tonic-gate router_create(struct phyint *pi, struct in6_addr addr, uint_t lifetime) 2021*0Sstevel@tonic-gate { 2022*0Sstevel@tonic-gate struct router *dr; 2023*0Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 2024*0Sstevel@tonic-gate 2025*0Sstevel@tonic-gate if (debug & D_ROUTER) { 2026*0Sstevel@tonic-gate logmsg(LOG_DEBUG, "router_create(%s, %s, %u)\n", pi->pi_name, 2027*0Sstevel@tonic-gate inet_ntop(AF_INET6, (void *)&addr, 2028*0Sstevel@tonic-gate abuf, sizeof (abuf)), lifetime); 2029*0Sstevel@tonic-gate } 2030*0Sstevel@tonic-gate 2031*0Sstevel@tonic-gate dr = (struct router *)calloc(sizeof (struct router), 1); 2032*0Sstevel@tonic-gate if (dr == NULL) { 2033*0Sstevel@tonic-gate logmsg(LOG_ERR, "router_create: out of memory\n"); 2034*0Sstevel@tonic-gate return (NULL); 2035*0Sstevel@tonic-gate } 2036*0Sstevel@tonic-gate dr->dr_address = addr; 2037*0Sstevel@tonic-gate dr->dr_lifetime = lifetime; 2038*0Sstevel@tonic-gate router_insert(pi, dr); 2039*0Sstevel@tonic-gate if (dr->dr_lifetime != 0) { 2040*0Sstevel@tonic-gate /* 2041*0Sstevel@tonic-gate * Delete an onlink default if it exists since we now have 2042*0Sstevel@tonic-gate * at least one default router. 2043*0Sstevel@tonic-gate */ 2044*0Sstevel@tonic-gate if (pi->pi_onlink_default) 2045*0Sstevel@tonic-gate router_delete_onlink(dr->dr_physical); 2046*0Sstevel@tonic-gate router_add_k(dr); 2047*0Sstevel@tonic-gate } 2048*0Sstevel@tonic-gate return (dr); 2049*0Sstevel@tonic-gate } 2050*0Sstevel@tonic-gate 2051*0Sstevel@tonic-gate /* Insert in linked list */ 2052*0Sstevel@tonic-gate static void 2053*0Sstevel@tonic-gate router_insert(struct phyint *pi, struct router *dr) 2054*0Sstevel@tonic-gate { 2055*0Sstevel@tonic-gate dr->dr_next = pi->pi_router_list; 2056*0Sstevel@tonic-gate dr->dr_prev = NULL; 2057*0Sstevel@tonic-gate if (pi->pi_router_list != NULL) 2058*0Sstevel@tonic-gate pi->pi_router_list->dr_prev = dr; 2059*0Sstevel@tonic-gate pi->pi_router_list = dr; 2060*0Sstevel@tonic-gate dr->dr_physical = pi; 2061*0Sstevel@tonic-gate } 2062*0Sstevel@tonic-gate 2063*0Sstevel@tonic-gate /* 2064*0Sstevel@tonic-gate * Delete (unlink and free). 2065*0Sstevel@tonic-gate * Handles delete of things that have not yet been inserted in the list 2066*0Sstevel@tonic-gate * i.e. dr_physical is NULL. 2067*0Sstevel@tonic-gate */ 2068*0Sstevel@tonic-gate static void 2069*0Sstevel@tonic-gate router_delete(struct router *dr) 2070*0Sstevel@tonic-gate { 2071*0Sstevel@tonic-gate struct phyint *pi; 2072*0Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 2073*0Sstevel@tonic-gate 2074*0Sstevel@tonic-gate if (debug & D_ROUTER) { 2075*0Sstevel@tonic-gate logmsg(LOG_DEBUG, "router_delete(%s, %s, %u)\n", 2076*0Sstevel@tonic-gate dr->dr_physical->pi_name, 2077*0Sstevel@tonic-gate inet_ntop(AF_INET6, (void *)&dr->dr_address, 2078*0Sstevel@tonic-gate abuf, sizeof (abuf)), dr->dr_lifetime); 2079*0Sstevel@tonic-gate } 2080*0Sstevel@tonic-gate pi = dr->dr_physical; 2081*0Sstevel@tonic-gate if (dr->dr_inkernel) { 2082*0Sstevel@tonic-gate /* 2083*0Sstevel@tonic-gate * Create a on-link default route only if the interface 2084*0Sstevel@tonic-gate * is present in the kernel. This function is called 2085*0Sstevel@tonic-gate * to clean up the routes when the interface is 2086*0Sstevel@tonic-gate * unplumbed. In that case, don't try to create one 2087*0Sstevel@tonic-gate * in the kernel. 2088*0Sstevel@tonic-gate */ 2089*0Sstevel@tonic-gate if (pi->pi_kernel_state & PI_PRESENT) { 2090*0Sstevel@tonic-gate if (!dr->dr_onlink && 2091*0Sstevel@tonic-gate dr->dr_physical->pi_num_k_routers == 1) { 2092*0Sstevel@tonic-gate (void) router_create_onlink(dr->dr_physical); 2093*0Sstevel@tonic-gate } 2094*0Sstevel@tonic-gate router_delete_k(dr); 2095*0Sstevel@tonic-gate } 2096*0Sstevel@tonic-gate } 2097*0Sstevel@tonic-gate if (dr->dr_onlink) 2098*0Sstevel@tonic-gate pi->pi_onlink_default = _B_FALSE; 2099*0Sstevel@tonic-gate 2100*0Sstevel@tonic-gate if (dr->dr_prev == NULL) { 2101*0Sstevel@tonic-gate if (pi != NULL) 2102*0Sstevel@tonic-gate pi->pi_router_list = dr->dr_next; 2103*0Sstevel@tonic-gate } else { 2104*0Sstevel@tonic-gate dr->dr_prev->dr_next = dr->dr_next; 2105*0Sstevel@tonic-gate } 2106*0Sstevel@tonic-gate if (dr->dr_next != NULL) 2107*0Sstevel@tonic-gate dr->dr_next->dr_prev = dr->dr_prev; 2108*0Sstevel@tonic-gate dr->dr_next = dr->dr_prev = NULL; 2109*0Sstevel@tonic-gate free(dr); 2110*0Sstevel@tonic-gate } 2111*0Sstevel@tonic-gate 2112*0Sstevel@tonic-gate 2113*0Sstevel@tonic-gate /* Create an onlink default route */ 2114*0Sstevel@tonic-gate struct router * 2115*0Sstevel@tonic-gate router_create_onlink(struct phyint *pi) 2116*0Sstevel@tonic-gate { 2117*0Sstevel@tonic-gate struct router *dr; 2118*0Sstevel@tonic-gate struct prefix *pr; 2119*0Sstevel@tonic-gate 2120*0Sstevel@tonic-gate if (debug & D_ROUTER) { 2121*0Sstevel@tonic-gate logmsg(LOG_DEBUG, "router_create_onlink(%s)\n", pi->pi_name); 2122*0Sstevel@tonic-gate } 2123*0Sstevel@tonic-gate 2124*0Sstevel@tonic-gate if (pi->pi_onlink_default) { 2125*0Sstevel@tonic-gate logmsg(LOG_ERR, "router_create_onlink: already an onlink " 2126*0Sstevel@tonic-gate "default: %s\n", pi->pi_name); 2127*0Sstevel@tonic-gate return (NULL); 2128*0Sstevel@tonic-gate } 2129*0Sstevel@tonic-gate 2130*0Sstevel@tonic-gate /* 2131*0Sstevel@tonic-gate * Find the interface address to use for the route gateway. 2132*0Sstevel@tonic-gate * We need to use the link-local since the others ones might be 2133*0Sstevel@tonic-gate * deleted when the prefixes get invalidated. 2134*0Sstevel@tonic-gate */ 2135*0Sstevel@tonic-gate for (pr = pi->pi_prefix_list; pr != NULL; pr = pr->pr_next) { 2136*0Sstevel@tonic-gate if ((pr->pr_state & PR_AUTO) && 2137*0Sstevel@tonic-gate IN6_IS_ADDR_LINKLOCAL(&pr->pr_address)) 2138*0Sstevel@tonic-gate break; 2139*0Sstevel@tonic-gate } 2140*0Sstevel@tonic-gate if (pr == NULL) { 2141*0Sstevel@tonic-gate logmsg(LOG_ERR, "router_create_onlink: no source address\n"); 2142*0Sstevel@tonic-gate return (NULL); 2143*0Sstevel@tonic-gate } 2144*0Sstevel@tonic-gate dr = (struct router *)calloc(sizeof (struct router), 1); 2145*0Sstevel@tonic-gate if (dr == NULL) { 2146*0Sstevel@tonic-gate logmsg(LOG_ERR, "router_create_onlink: out of memory\n"); 2147*0Sstevel@tonic-gate return (NULL); 2148*0Sstevel@tonic-gate } 2149*0Sstevel@tonic-gate dr->dr_address = pr->pr_address; 2150*0Sstevel@tonic-gate dr->dr_lifetime = 1; /* Not used */ 2151*0Sstevel@tonic-gate dr->dr_onlink = _B_TRUE; 2152*0Sstevel@tonic-gate router_insert(pi, dr); 2153*0Sstevel@tonic-gate 2154*0Sstevel@tonic-gate router_add_k(dr); 2155*0Sstevel@tonic-gate pi->pi_onlink_default = _B_TRUE; 2156*0Sstevel@tonic-gate return (dr); 2157*0Sstevel@tonic-gate } 2158*0Sstevel@tonic-gate 2159*0Sstevel@tonic-gate /* Remove an onlink default route */ 2160*0Sstevel@tonic-gate static void 2161*0Sstevel@tonic-gate router_delete_onlink(struct phyint *pi) 2162*0Sstevel@tonic-gate { 2163*0Sstevel@tonic-gate struct router *dr, *next_dr; 2164*0Sstevel@tonic-gate 2165*0Sstevel@tonic-gate if (debug & D_ROUTER) { 2166*0Sstevel@tonic-gate logmsg(LOG_DEBUG, "router_delete_onlink(%s)\n", pi->pi_name); 2167*0Sstevel@tonic-gate } 2168*0Sstevel@tonic-gate 2169*0Sstevel@tonic-gate if (!pi->pi_onlink_default) { 2170*0Sstevel@tonic-gate logmsg(LOG_ERR, "router_delete_onlink: no onlink default: " 2171*0Sstevel@tonic-gate "%s\n", pi->pi_name); 2172*0Sstevel@tonic-gate return; 2173*0Sstevel@tonic-gate } 2174*0Sstevel@tonic-gate /* Find all onlink routes */ 2175*0Sstevel@tonic-gate for (dr = pi->pi_router_list; dr != NULL; dr = next_dr) { 2176*0Sstevel@tonic-gate next_dr = dr->dr_next; 2177*0Sstevel@tonic-gate if (dr->dr_onlink) 2178*0Sstevel@tonic-gate router_delete(dr); 2179*0Sstevel@tonic-gate } 2180*0Sstevel@tonic-gate } 2181*0Sstevel@tonic-gate 2182*0Sstevel@tonic-gate /* 2183*0Sstevel@tonic-gate * Update the kernel to match dr_lifetime 2184*0Sstevel@tonic-gate */ 2185*0Sstevel@tonic-gate void 2186*0Sstevel@tonic-gate router_update_k(struct router *dr) 2187*0Sstevel@tonic-gate { 2188*0Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 2189*0Sstevel@tonic-gate 2190*0Sstevel@tonic-gate if (debug & D_ROUTER) { 2191*0Sstevel@tonic-gate logmsg(LOG_DEBUG, "router_update_k(%s, %s, %u)\n", 2192*0Sstevel@tonic-gate dr->dr_physical->pi_name, 2193*0Sstevel@tonic-gate inet_ntop(AF_INET6, (void *)&dr->dr_address, 2194*0Sstevel@tonic-gate abuf, sizeof (abuf)), dr->dr_lifetime); 2195*0Sstevel@tonic-gate } 2196*0Sstevel@tonic-gate 2197*0Sstevel@tonic-gate if (dr->dr_lifetime == 0 && dr->dr_inkernel) { 2198*0Sstevel@tonic-gate /* Log a message when last router goes away */ 2199*0Sstevel@tonic-gate if (dr->dr_physical->pi_num_k_routers == 1) { 2200*0Sstevel@tonic-gate logmsg(LOG_WARNING, 2201*0Sstevel@tonic-gate "Last default router (%s) removed on %s\n", 2202*0Sstevel@tonic-gate inet_ntop(AF_INET6, (void *)&dr->dr_address, 2203*0Sstevel@tonic-gate abuf, sizeof (abuf)), dr->dr_physical->pi_name); 2204*0Sstevel@tonic-gate } 2205*0Sstevel@tonic-gate router_delete(dr); 2206*0Sstevel@tonic-gate } else if (dr->dr_lifetime != 0 && !dr->dr_inkernel) { 2207*0Sstevel@tonic-gate /* 2208*0Sstevel@tonic-gate * Delete an onlink default if it exists since we now have 2209*0Sstevel@tonic-gate * at least one default router. 2210*0Sstevel@tonic-gate */ 2211*0Sstevel@tonic-gate if (dr->dr_physical->pi_onlink_default) 2212*0Sstevel@tonic-gate router_delete_onlink(dr->dr_physical); 2213*0Sstevel@tonic-gate router_add_k(dr); 2214*0Sstevel@tonic-gate } 2215*0Sstevel@tonic-gate } 2216*0Sstevel@tonic-gate 2217*0Sstevel@tonic-gate 2218*0Sstevel@tonic-gate /* 2219*0Sstevel@tonic-gate * Called with the number of millseconds elapsed since the last call. 2220*0Sstevel@tonic-gate * Determines if any timeout event has occurred and 2221*0Sstevel@tonic-gate * returns the number of milliseconds until the next timeout event. 2222*0Sstevel@tonic-gate * Returns TIMER_INFINITY for "never". 2223*0Sstevel@tonic-gate */ 2224*0Sstevel@tonic-gate uint_t 2225*0Sstevel@tonic-gate router_timer(struct router *dr, uint_t elapsed) 2226*0Sstevel@tonic-gate { 2227*0Sstevel@tonic-gate uint_t next = TIMER_INFINITY; 2228*0Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 2229*0Sstevel@tonic-gate 2230*0Sstevel@tonic-gate if (debug & D_ROUTER) { 2231*0Sstevel@tonic-gate logmsg(LOG_DEBUG, "router_timer(%s, %s, %u, %d)\n", 2232*0Sstevel@tonic-gate dr->dr_physical->pi_name, 2233*0Sstevel@tonic-gate inet_ntop(AF_INET6, (void *)&dr->dr_address, 2234*0Sstevel@tonic-gate abuf, sizeof (abuf)), dr->dr_lifetime, elapsed); 2235*0Sstevel@tonic-gate } 2236*0Sstevel@tonic-gate if (dr->dr_onlink) { 2237*0Sstevel@tonic-gate /* No timeout */ 2238*0Sstevel@tonic-gate return (next); 2239*0Sstevel@tonic-gate } 2240*0Sstevel@tonic-gate if (dr->dr_lifetime <= elapsed) { 2241*0Sstevel@tonic-gate dr->dr_lifetime = 0; 2242*0Sstevel@tonic-gate } else { 2243*0Sstevel@tonic-gate dr->dr_lifetime -= elapsed; 2244*0Sstevel@tonic-gate if (dr->dr_lifetime < next) 2245*0Sstevel@tonic-gate next = dr->dr_lifetime; 2246*0Sstevel@tonic-gate } 2247*0Sstevel@tonic-gate 2248*0Sstevel@tonic-gate if (dr->dr_lifetime == 0) { 2249*0Sstevel@tonic-gate /* Log a message when last router goes away */ 2250*0Sstevel@tonic-gate if (dr->dr_physical->pi_num_k_routers == 1) { 2251*0Sstevel@tonic-gate logmsg(LOG_WARNING, 2252*0Sstevel@tonic-gate "Last default router (%s) timed out on %s\n", 2253*0Sstevel@tonic-gate inet_ntop(AF_INET6, (void *)&dr->dr_address, 2254*0Sstevel@tonic-gate abuf, sizeof (abuf)), dr->dr_physical->pi_name); 2255*0Sstevel@tonic-gate } 2256*0Sstevel@tonic-gate router_delete(dr); 2257*0Sstevel@tonic-gate } 2258*0Sstevel@tonic-gate return (next); 2259*0Sstevel@tonic-gate } 2260*0Sstevel@tonic-gate 2261*0Sstevel@tonic-gate /* 2262*0Sstevel@tonic-gate * Add a default route to the kernel (unless the lifetime is zero) 2263*0Sstevel@tonic-gate * Handles onlink default routes. 2264*0Sstevel@tonic-gate */ 2265*0Sstevel@tonic-gate static void 2266*0Sstevel@tonic-gate router_add_k(struct router *dr) 2267*0Sstevel@tonic-gate { 2268*0Sstevel@tonic-gate struct phyint *pi = dr->dr_physical; 2269*0Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 2270*0Sstevel@tonic-gate int rlen; 2271*0Sstevel@tonic-gate 2272*0Sstevel@tonic-gate if (debug & D_ROUTER) { 2273*0Sstevel@tonic-gate logmsg(LOG_DEBUG, "router_add_k(%s, %s, %u)\n", 2274*0Sstevel@tonic-gate dr->dr_physical->pi_name, 2275*0Sstevel@tonic-gate inet_ntop(AF_INET6, (void *)&dr->dr_address, 2276*0Sstevel@tonic-gate abuf, sizeof (abuf)), dr->dr_lifetime); 2277*0Sstevel@tonic-gate } 2278*0Sstevel@tonic-gate 2279*0Sstevel@tonic-gate if (dr->dr_onlink) 2280*0Sstevel@tonic-gate rt_msg->rtm_flags = 0; 2281*0Sstevel@tonic-gate else 2282*0Sstevel@tonic-gate rt_msg->rtm_flags = RTF_GATEWAY; 2283*0Sstevel@tonic-gate 2284*0Sstevel@tonic-gate rta_gateway->sin6_addr = dr->dr_address; 2285*0Sstevel@tonic-gate 2286*0Sstevel@tonic-gate rta_ifp->sdl_index = if_nametoindex(pi->pi_name); 2287*0Sstevel@tonic-gate if (rta_ifp->sdl_index == 0) { 2288*0Sstevel@tonic-gate logperror_pi(pi, "router_add_k: if_nametoindex"); 2289*0Sstevel@tonic-gate return; 2290*0Sstevel@tonic-gate } 2291*0Sstevel@tonic-gate 2292*0Sstevel@tonic-gate rt_msg->rtm_type = RTM_ADD; 2293*0Sstevel@tonic-gate rt_msg->rtm_seq = ++rtmseq; 2294*0Sstevel@tonic-gate rlen = write(rtsock, rt_msg, rt_msg->rtm_msglen); 2295*0Sstevel@tonic-gate if (rlen < 0) { 2296*0Sstevel@tonic-gate if (errno != EEXIST) { 2297*0Sstevel@tonic-gate logperror_pi(pi, "router_add_k: RTM_ADD"); 2298*0Sstevel@tonic-gate return; 2299*0Sstevel@tonic-gate } 2300*0Sstevel@tonic-gate } else if (rlen < rt_msg->rtm_msglen) { 2301*0Sstevel@tonic-gate logmsg(LOG_ERR, "router_add_k: write to routing socket got " 2302*0Sstevel@tonic-gate "only %d for rlen (interface %s)\n", rlen, pi->pi_name); 2303*0Sstevel@tonic-gate return; 2304*0Sstevel@tonic-gate } 2305*0Sstevel@tonic-gate dr->dr_inkernel = _B_TRUE; 2306*0Sstevel@tonic-gate if (!dr->dr_onlink) 2307*0Sstevel@tonic-gate pi->pi_num_k_routers++; 2308*0Sstevel@tonic-gate } 2309*0Sstevel@tonic-gate 2310*0Sstevel@tonic-gate /* 2311*0Sstevel@tonic-gate * Delete a route from the kernel. 2312*0Sstevel@tonic-gate * Handles onlink default routes. 2313*0Sstevel@tonic-gate */ 2314*0Sstevel@tonic-gate static void 2315*0Sstevel@tonic-gate router_delete_k(struct router *dr) 2316*0Sstevel@tonic-gate { 2317*0Sstevel@tonic-gate struct phyint *pi = dr->dr_physical; 2318*0Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 2319*0Sstevel@tonic-gate int rlen; 2320*0Sstevel@tonic-gate 2321*0Sstevel@tonic-gate if (debug & D_ROUTER) { 2322*0Sstevel@tonic-gate logmsg(LOG_DEBUG, "router_delete_k(%s, %s, %u)\n", 2323*0Sstevel@tonic-gate dr->dr_physical->pi_name, 2324*0Sstevel@tonic-gate inet_ntop(AF_INET6, (void *)&dr->dr_address, 2325*0Sstevel@tonic-gate abuf, sizeof (abuf)), dr->dr_lifetime); 2326*0Sstevel@tonic-gate } 2327*0Sstevel@tonic-gate 2328*0Sstevel@tonic-gate if (dr->dr_onlink) 2329*0Sstevel@tonic-gate rt_msg->rtm_flags = 0; 2330*0Sstevel@tonic-gate else 2331*0Sstevel@tonic-gate rt_msg->rtm_flags = RTF_GATEWAY; 2332*0Sstevel@tonic-gate 2333*0Sstevel@tonic-gate rta_gateway->sin6_addr = dr->dr_address; 2334*0Sstevel@tonic-gate 2335*0Sstevel@tonic-gate rta_ifp->sdl_index = if_nametoindex(pi->pi_name); 2336*0Sstevel@tonic-gate if (rta_ifp->sdl_index == 0) { 2337*0Sstevel@tonic-gate logperror_pi(pi, "router_delete_k: if_nametoindex"); 2338*0Sstevel@tonic-gate return; 2339*0Sstevel@tonic-gate } 2340*0Sstevel@tonic-gate 2341*0Sstevel@tonic-gate rt_msg->rtm_type = RTM_DELETE; 2342*0Sstevel@tonic-gate rt_msg->rtm_seq = ++rtmseq; 2343*0Sstevel@tonic-gate rlen = write(rtsock, rt_msg, rt_msg->rtm_msglen); 2344*0Sstevel@tonic-gate if (rlen < 0) { 2345*0Sstevel@tonic-gate if (errno != ESRCH) { 2346*0Sstevel@tonic-gate logperror_pi(pi, "router_delete_k: RTM_DELETE"); 2347*0Sstevel@tonic-gate } 2348*0Sstevel@tonic-gate } else if (rlen < rt_msg->rtm_msglen) { 2349*0Sstevel@tonic-gate logmsg(LOG_ERR, "router_delete_k: write to routing socket got " 2350*0Sstevel@tonic-gate "only %d for rlen (interface %s)\n", rlen, pi->pi_name); 2351*0Sstevel@tonic-gate } 2352*0Sstevel@tonic-gate dr->dr_inkernel = _B_FALSE; 2353*0Sstevel@tonic-gate if (!dr->dr_onlink) 2354*0Sstevel@tonic-gate pi->pi_num_k_routers--; 2355*0Sstevel@tonic-gate } 2356*0Sstevel@tonic-gate 2357*0Sstevel@tonic-gate 2358*0Sstevel@tonic-gate static void 2359*0Sstevel@tonic-gate router_print(struct router *dr) 2360*0Sstevel@tonic-gate { 2361*0Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 2362*0Sstevel@tonic-gate 2363*0Sstevel@tonic-gate logmsg(LOG_DEBUG, "Router %s on %s inkernel %d onlink %d lifetime %u\n", 2364*0Sstevel@tonic-gate inet_ntop(AF_INET6, (void *)&dr->dr_address, 2365*0Sstevel@tonic-gate abuf, sizeof (abuf)), 2366*0Sstevel@tonic-gate dr->dr_physical->pi_name, 2367*0Sstevel@tonic-gate dr->dr_inkernel, dr->dr_onlink, dr->dr_lifetime); 2368*0Sstevel@tonic-gate } 2369*0Sstevel@tonic-gate 2370*0Sstevel@tonic-gate 2371*0Sstevel@tonic-gate void 2372*0Sstevel@tonic-gate phyint_print_all(void) 2373*0Sstevel@tonic-gate { 2374*0Sstevel@tonic-gate struct phyint *pi; 2375*0Sstevel@tonic-gate 2376*0Sstevel@tonic-gate for (pi = phyints; pi != NULL; pi = pi->pi_next) { 2377*0Sstevel@tonic-gate phyint_print(pi); 2378*0Sstevel@tonic-gate } 2379*0Sstevel@tonic-gate } 2380*0Sstevel@tonic-gate 2381*0Sstevel@tonic-gate void 2382*0Sstevel@tonic-gate phyint_cleanup(pi) 2383*0Sstevel@tonic-gate struct phyint *pi; 2384*0Sstevel@tonic-gate { 2385*0Sstevel@tonic-gate pi->pi_state = 0; 2386*0Sstevel@tonic-gate pi->pi_kernel_state = 0; 2387*0Sstevel@tonic-gate 2388*0Sstevel@tonic-gate if (pi->pi_AdvSendAdvertisements) { 2389*0Sstevel@tonic-gate check_to_advertise(pi, ADV_OFF); 2390*0Sstevel@tonic-gate } else { 2391*0Sstevel@tonic-gate check_to_solicit(pi, SOLICIT_OFF); 2392*0Sstevel@tonic-gate } 2393*0Sstevel@tonic-gate 2394*0Sstevel@tonic-gate while (pi->pi_router_list) 2395*0Sstevel@tonic-gate router_delete(pi->pi_router_list); 2396*0Sstevel@tonic-gate (void) poll_remove(pi->pi_sock); 2397*0Sstevel@tonic-gate (void) close(pi->pi_sock); 2398*0Sstevel@tonic-gate pi->pi_sock = -1; 2399*0Sstevel@tonic-gate } 2400