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