1*6e91bba0SGirish Moodalbail /* 2*6e91bba0SGirish Moodalbail * CDDL HEADER START 3*6e91bba0SGirish Moodalbail * 4*6e91bba0SGirish Moodalbail * The contents of this file are subject to the terms of the 5*6e91bba0SGirish Moodalbail * Common Development and Distribution License (the "License"). 6*6e91bba0SGirish Moodalbail * You may not use this file except in compliance with the License. 7*6e91bba0SGirish Moodalbail * 8*6e91bba0SGirish Moodalbail * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*6e91bba0SGirish Moodalbail * or http://www.opensolaris.org/os/licensing. 10*6e91bba0SGirish Moodalbail * See the License for the specific language governing permissions 11*6e91bba0SGirish Moodalbail * and limitations under the License. 12*6e91bba0SGirish Moodalbail * 13*6e91bba0SGirish Moodalbail * When distributing Covered Code, include this CDDL HEADER in each 14*6e91bba0SGirish Moodalbail * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*6e91bba0SGirish Moodalbail * If applicable, add the following below this CDDL HEADER, with the 16*6e91bba0SGirish Moodalbail * fields enclosed by brackets "[]" replaced with your own identifying 17*6e91bba0SGirish Moodalbail * information: Portions Copyright [yyyy] [name of copyright owner] 18*6e91bba0SGirish Moodalbail * 19*6e91bba0SGirish Moodalbail * CDDL HEADER END 20*6e91bba0SGirish Moodalbail */ 21*6e91bba0SGirish Moodalbail /* 22*6e91bba0SGirish Moodalbail * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 23*6e91bba0SGirish Moodalbail * Use is subject to license terms. 24*6e91bba0SGirish Moodalbail */ 25*6e91bba0SGirish Moodalbail 26*6e91bba0SGirish Moodalbail #include <stdio.h> 27*6e91bba0SGirish Moodalbail #include <stdlib.h> 28*6e91bba0SGirish Moodalbail #include <string.h> 29*6e91bba0SGirish Moodalbail #include <errno.h> 30*6e91bba0SGirish Moodalbail #include <fcntl.h> 31*6e91bba0SGirish Moodalbail #include <unistd.h> 32*6e91bba0SGirish Moodalbail #include <stropts.h> 33*6e91bba0SGirish Moodalbail #include <sys/sockio.h> 34*6e91bba0SGirish Moodalbail #include <sys/types.h> 35*6e91bba0SGirish Moodalbail #include <sys/stat.h> 36*6e91bba0SGirish Moodalbail #include <sys/socket.h> 37*6e91bba0SGirish Moodalbail #include <net/route.h> 38*6e91bba0SGirish Moodalbail #include <netinet/in.h> 39*6e91bba0SGirish Moodalbail #include <inet/ip.h> 40*6e91bba0SGirish Moodalbail #include <arpa/inet.h> 41*6e91bba0SGirish Moodalbail #include <libintl.h> 42*6e91bba0SGirish Moodalbail #include <libdlpi.h> 43*6e91bba0SGirish Moodalbail #include <libinetutil.h> 44*6e91bba0SGirish Moodalbail #include <libdladm.h> 45*6e91bba0SGirish Moodalbail #include <libdllink.h> 46*6e91bba0SGirish Moodalbail #include <libdliptun.h> 47*6e91bba0SGirish Moodalbail #include <strings.h> 48*6e91bba0SGirish Moodalbail #include <zone.h> 49*6e91bba0SGirish Moodalbail #include <ctype.h> 50*6e91bba0SGirish Moodalbail #include <limits.h> 51*6e91bba0SGirish Moodalbail #include <assert.h> 52*6e91bba0SGirish Moodalbail #include <netdb.h> 53*6e91bba0SGirish Moodalbail #include <pwd.h> 54*6e91bba0SGirish Moodalbail #include <auth_attr.h> 55*6e91bba0SGirish Moodalbail #include <secdb.h> 56*6e91bba0SGirish Moodalbail #include <nss_dbdefs.h> 57*6e91bba0SGirish Moodalbail #include "libipadm_impl.h" 58*6e91bba0SGirish Moodalbail 59*6e91bba0SGirish Moodalbail /* error codes and text description */ 60*6e91bba0SGirish Moodalbail static struct ipadm_error_info { 61*6e91bba0SGirish Moodalbail ipadm_status_t error_code; 62*6e91bba0SGirish Moodalbail const char *error_desc; 63*6e91bba0SGirish Moodalbail } ipadm_errors[] = { 64*6e91bba0SGirish Moodalbail { IPADM_SUCCESS, "Operation succeeded" }, 65*6e91bba0SGirish Moodalbail { IPADM_FAILURE, "Operation failed" }, 66*6e91bba0SGirish Moodalbail { IPADM_EAUTH, "Insufficient user authorizations" }, 67*6e91bba0SGirish Moodalbail { IPADM_EPERM, "Permission denied" }, 68*6e91bba0SGirish Moodalbail { IPADM_NO_BUFS, "No buffer space available" }, 69*6e91bba0SGirish Moodalbail { IPADM_NO_MEMORY, "Insufficient memory" }, 70*6e91bba0SGirish Moodalbail { IPADM_BAD_ADDR, "Invalid address" }, 71*6e91bba0SGirish Moodalbail { IPADM_BAD_PROTOCOL, "Incorrect protocol family for operation" }, 72*6e91bba0SGirish Moodalbail { IPADM_DAD_FOUND, "Duplicate address detected" }, 73*6e91bba0SGirish Moodalbail { IPADM_EXISTS, "Already exists" }, 74*6e91bba0SGirish Moodalbail { IPADM_IF_EXISTS, "Interface already exists" }, 75*6e91bba0SGirish Moodalbail { IPADM_ADDROBJ_EXISTS, "Address object already exists" }, 76*6e91bba0SGirish Moodalbail { IPADM_ADDRCONF_EXISTS, "Addrconf already in progress" }, 77*6e91bba0SGirish Moodalbail { IPADM_ENXIO, "Interface does not exist" }, 78*6e91bba0SGirish Moodalbail { IPADM_GRP_NOTEMPTY, "IPMP group is not empty" }, 79*6e91bba0SGirish Moodalbail { IPADM_INVALID_ARG, "Invalid argument provided" }, 80*6e91bba0SGirish Moodalbail { IPADM_INVALID_NAME, "Invalid name" }, 81*6e91bba0SGirish Moodalbail { IPADM_DLPI_FAILURE, "Could not open DLPI link" }, 82*6e91bba0SGirish Moodalbail { IPADM_DLADM_FAILURE, "Datalink does not exist" }, 83*6e91bba0SGirish Moodalbail { IPADM_PROP_UNKNOWN, "Unknown property" }, 84*6e91bba0SGirish Moodalbail { IPADM_ERANGE, "Value is outside the allowed range" }, 85*6e91bba0SGirish Moodalbail { IPADM_ESRCH, "Value does not exist" }, 86*6e91bba0SGirish Moodalbail { IPADM_EOVERFLOW, "Number of values exceeds the allowed limit" }, 87*6e91bba0SGirish Moodalbail { IPADM_NOTFOUND, "Object not found" }, 88*6e91bba0SGirish Moodalbail { IPADM_IF_INUSE, "Interface already in use" }, 89*6e91bba0SGirish Moodalbail { IPADM_ADDR_INUSE, "Address already in use" }, 90*6e91bba0SGirish Moodalbail { IPADM_BAD_HOSTNAME, "Hostname maps to multiple IP addresses" }, 91*6e91bba0SGirish Moodalbail { IPADM_ADDR_NOTAVAIL, "Can't assign requested address" }, 92*6e91bba0SGirish Moodalbail { IPADM_ALL_ADDRS_NOT_ENABLED, "All addresses could not be enabled" }, 93*6e91bba0SGirish Moodalbail { IPADM_NDPD_NOT_RUNNING, "IPv6 autoconf daemon in.ndpd not running" }, 94*6e91bba0SGirish Moodalbail { IPADM_DHCP_START_ERROR, "Could not start dhcpagent" }, 95*6e91bba0SGirish Moodalbail { IPADM_DHCP_IPC_ERROR, "Could not communicate with dhcpagent" }, 96*6e91bba0SGirish Moodalbail { IPADM_DHCP_IPC_TIMEOUT, "Communication with dhcpagent timed out" }, 97*6e91bba0SGirish Moodalbail { IPADM_TEMPORARY_OBJ, "Persistent operation on temporary object" }, 98*6e91bba0SGirish Moodalbail { IPADM_IPC_ERROR, "Could not communicate with ipmgmtd" }, 99*6e91bba0SGirish Moodalbail { IPADM_NOTSUP, "Operation not supported" }, 100*6e91bba0SGirish Moodalbail { IPADM_OP_DISABLE_OBJ, "Operation not supported on disabled object" }, 101*6e91bba0SGirish Moodalbail { IPADM_EBADE, "Invalid data exchange with daemon" } 102*6e91bba0SGirish Moodalbail }; 103*6e91bba0SGirish Moodalbail 104*6e91bba0SGirish Moodalbail #define IPADM_NUM_ERRORS (sizeof (ipadm_errors) / sizeof (*ipadm_errors)) 105*6e91bba0SGirish Moodalbail 106*6e91bba0SGirish Moodalbail ipadm_status_t 107*6e91bba0SGirish Moodalbail ipadm_errno2status(int error) 108*6e91bba0SGirish Moodalbail { 109*6e91bba0SGirish Moodalbail switch (error) { 110*6e91bba0SGirish Moodalbail case 0: 111*6e91bba0SGirish Moodalbail return (IPADM_SUCCESS); 112*6e91bba0SGirish Moodalbail case ENXIO: 113*6e91bba0SGirish Moodalbail return (IPADM_ENXIO); 114*6e91bba0SGirish Moodalbail case ENOMEM: 115*6e91bba0SGirish Moodalbail return (IPADM_NO_MEMORY); 116*6e91bba0SGirish Moodalbail case ENOBUFS: 117*6e91bba0SGirish Moodalbail return (IPADM_NO_BUFS); 118*6e91bba0SGirish Moodalbail case EINVAL: 119*6e91bba0SGirish Moodalbail return (IPADM_INVALID_ARG); 120*6e91bba0SGirish Moodalbail case EBUSY: 121*6e91bba0SGirish Moodalbail return (IPADM_IF_INUSE); 122*6e91bba0SGirish Moodalbail case EEXIST: 123*6e91bba0SGirish Moodalbail return (IPADM_EXISTS); 124*6e91bba0SGirish Moodalbail case EADDRNOTAVAIL: 125*6e91bba0SGirish Moodalbail return (IPADM_ADDR_NOTAVAIL); 126*6e91bba0SGirish Moodalbail case EADDRINUSE: 127*6e91bba0SGirish Moodalbail return (IPADM_ADDR_INUSE); 128*6e91bba0SGirish Moodalbail case ENOENT: 129*6e91bba0SGirish Moodalbail return (IPADM_NOTFOUND); 130*6e91bba0SGirish Moodalbail case ERANGE: 131*6e91bba0SGirish Moodalbail return (IPADM_ERANGE); 132*6e91bba0SGirish Moodalbail case EPERM: 133*6e91bba0SGirish Moodalbail return (IPADM_EPERM); 134*6e91bba0SGirish Moodalbail case ENOTSUP: 135*6e91bba0SGirish Moodalbail case EOPNOTSUPP: 136*6e91bba0SGirish Moodalbail return (IPADM_NOTSUP); 137*6e91bba0SGirish Moodalbail case EBADF: 138*6e91bba0SGirish Moodalbail return (IPADM_IPC_ERROR); 139*6e91bba0SGirish Moodalbail case EBADE: 140*6e91bba0SGirish Moodalbail return (IPADM_EBADE); 141*6e91bba0SGirish Moodalbail case ESRCH: 142*6e91bba0SGirish Moodalbail return (IPADM_ESRCH); 143*6e91bba0SGirish Moodalbail case EOVERFLOW: 144*6e91bba0SGirish Moodalbail return (IPADM_EOVERFLOW); 145*6e91bba0SGirish Moodalbail default: 146*6e91bba0SGirish Moodalbail return (IPADM_FAILURE); 147*6e91bba0SGirish Moodalbail } 148*6e91bba0SGirish Moodalbail } 149*6e91bba0SGirish Moodalbail 150*6e91bba0SGirish Moodalbail /* 151*6e91bba0SGirish Moodalbail * Returns a message string for the given libipadm error status. 152*6e91bba0SGirish Moodalbail */ 153*6e91bba0SGirish Moodalbail const char * 154*6e91bba0SGirish Moodalbail ipadm_status2str(ipadm_status_t status) 155*6e91bba0SGirish Moodalbail { 156*6e91bba0SGirish Moodalbail int i; 157*6e91bba0SGirish Moodalbail 158*6e91bba0SGirish Moodalbail for (i = 0; i < IPADM_NUM_ERRORS; i++) { 159*6e91bba0SGirish Moodalbail if (status == ipadm_errors[i].error_code) 160*6e91bba0SGirish Moodalbail return (dgettext(TEXT_DOMAIN, 161*6e91bba0SGirish Moodalbail ipadm_errors[i].error_desc)); 162*6e91bba0SGirish Moodalbail } 163*6e91bba0SGirish Moodalbail 164*6e91bba0SGirish Moodalbail return (dgettext(TEXT_DOMAIN, "<unknown error>")); 165*6e91bba0SGirish Moodalbail } 166*6e91bba0SGirish Moodalbail 167*6e91bba0SGirish Moodalbail /* 168*6e91bba0SGirish Moodalbail * Opens a handle to libipadm. 169*6e91bba0SGirish Moodalbail * Possible values for flags: 170*6e91bba0SGirish Moodalbail * IPH_VRRP: Used by VRRP daemon to set the socket option SO_VRRP. 171*6e91bba0SGirish Moodalbail * IPH_LEGACY: This is used whenever an application needs to provide a 172*6e91bba0SGirish Moodalbail * logical interface name while creating or deleting 173*6e91bba0SGirish Moodalbail * interfaces and static addresses. 174*6e91bba0SGirish Moodalbail * IPH_INIT: Used by ipadm_init_prop(), to initialize protocol properties 175*6e91bba0SGirish Moodalbail * on reboot. 176*6e91bba0SGirish Moodalbail */ 177*6e91bba0SGirish Moodalbail ipadm_status_t 178*6e91bba0SGirish Moodalbail ipadm_open(ipadm_handle_t *handle, uint32_t flags) 179*6e91bba0SGirish Moodalbail { 180*6e91bba0SGirish Moodalbail ipadm_handle_t iph; 181*6e91bba0SGirish Moodalbail ipadm_status_t status = IPADM_SUCCESS; 182*6e91bba0SGirish Moodalbail zoneid_t zoneid; 183*6e91bba0SGirish Moodalbail ushort_t zflags; 184*6e91bba0SGirish Moodalbail int on = B_TRUE; 185*6e91bba0SGirish Moodalbail 186*6e91bba0SGirish Moodalbail if (handle == NULL) 187*6e91bba0SGirish Moodalbail return (IPADM_INVALID_ARG); 188*6e91bba0SGirish Moodalbail *handle = NULL; 189*6e91bba0SGirish Moodalbail 190*6e91bba0SGirish Moodalbail if (flags & ~(IPH_VRRP|IPH_LEGACY|IPH_INIT)) 191*6e91bba0SGirish Moodalbail return (IPADM_INVALID_ARG); 192*6e91bba0SGirish Moodalbail 193*6e91bba0SGirish Moodalbail if ((iph = calloc(1, sizeof (struct ipadm_handle))) == NULL) 194*6e91bba0SGirish Moodalbail return (IPADM_NO_MEMORY); 195*6e91bba0SGirish Moodalbail iph->iph_sock = -1; 196*6e91bba0SGirish Moodalbail iph->iph_sock6 = -1; 197*6e91bba0SGirish Moodalbail iph->iph_door_fd = -1; 198*6e91bba0SGirish Moodalbail iph->iph_flags = flags; 199*6e91bba0SGirish Moodalbail (void) pthread_mutex_init(&iph->iph_lock, NULL); 200*6e91bba0SGirish Moodalbail 201*6e91bba0SGirish Moodalbail if ((iph->iph_sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0 || 202*6e91bba0SGirish Moodalbail (iph->iph_sock6 = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 203*6e91bba0SGirish Moodalbail goto errnofail; 204*6e91bba0SGirish Moodalbail } 205*6e91bba0SGirish Moodalbail 206*6e91bba0SGirish Moodalbail /* 207*6e91bba0SGirish Moodalbail * We open a handle to libdladm here, to facilitate some daemons (like 208*6e91bba0SGirish Moodalbail * nwamd) which opens handle to libipadm before devfsadmd installs the 209*6e91bba0SGirish Moodalbail * right device permissions into the kernel and requires "all" 210*6e91bba0SGirish Moodalbail * privileges to open DLD_CONTROL_DEV. 211*6e91bba0SGirish Moodalbail * 212*6e91bba0SGirish Moodalbail * In a non-global shared-ip zone there will be no DLD_CONTROL_DEV node 213*6e91bba0SGirish Moodalbail * and dladm_open() will fail. So, we avoid this by not calling 214*6e91bba0SGirish Moodalbail * dladm_open() for such zones. 215*6e91bba0SGirish Moodalbail */ 216*6e91bba0SGirish Moodalbail zoneid = getzoneid(); 217*6e91bba0SGirish Moodalbail if (zoneid != GLOBAL_ZONEID) { 218*6e91bba0SGirish Moodalbail if (zone_getattr(zoneid, ZONE_ATTR_FLAGS, &zflags, 219*6e91bba0SGirish Moodalbail sizeof (zflags)) < 0) { 220*6e91bba0SGirish Moodalbail goto errnofail; 221*6e91bba0SGirish Moodalbail } 222*6e91bba0SGirish Moodalbail } 223*6e91bba0SGirish Moodalbail if ((zoneid == GLOBAL_ZONEID) || (zflags & ZF_NET_EXCL)) { 224*6e91bba0SGirish Moodalbail if (dladm_open(&iph->iph_dlh) != DLADM_STATUS_OK) { 225*6e91bba0SGirish Moodalbail ipadm_close(iph); 226*6e91bba0SGirish Moodalbail return (IPADM_DLADM_FAILURE); 227*6e91bba0SGirish Moodalbail } 228*6e91bba0SGirish Moodalbail } else { 229*6e91bba0SGirish Moodalbail assert(zoneid != GLOBAL_ZONEID); 230*6e91bba0SGirish Moodalbail iph->iph_dlh = NULL; 231*6e91bba0SGirish Moodalbail } 232*6e91bba0SGirish Moodalbail if (flags & IPH_VRRP) { 233*6e91bba0SGirish Moodalbail if (setsockopt(iph->iph_sock6, SOL_SOCKET, SO_VRRP, &on, 234*6e91bba0SGirish Moodalbail sizeof (on)) < 0 || setsockopt(iph->iph_sock, SOL_SOCKET, 235*6e91bba0SGirish Moodalbail SO_VRRP, &on, sizeof (on)) < 0) { 236*6e91bba0SGirish Moodalbail goto errnofail; 237*6e91bba0SGirish Moodalbail } 238*6e91bba0SGirish Moodalbail } 239*6e91bba0SGirish Moodalbail *handle = iph; 240*6e91bba0SGirish Moodalbail return (status); 241*6e91bba0SGirish Moodalbail 242*6e91bba0SGirish Moodalbail errnofail: 243*6e91bba0SGirish Moodalbail status = ipadm_errno2status(errno); 244*6e91bba0SGirish Moodalbail ipadm_close(iph); 245*6e91bba0SGirish Moodalbail return (status); 246*6e91bba0SGirish Moodalbail } 247*6e91bba0SGirish Moodalbail 248*6e91bba0SGirish Moodalbail /* 249*6e91bba0SGirish Moodalbail * Closes and frees the libipadm handle. 250*6e91bba0SGirish Moodalbail */ 251*6e91bba0SGirish Moodalbail void 252*6e91bba0SGirish Moodalbail ipadm_close(ipadm_handle_t iph) 253*6e91bba0SGirish Moodalbail { 254*6e91bba0SGirish Moodalbail if (iph == NULL) 255*6e91bba0SGirish Moodalbail return; 256*6e91bba0SGirish Moodalbail if (iph->iph_sock != -1) 257*6e91bba0SGirish Moodalbail (void) close(iph->iph_sock); 258*6e91bba0SGirish Moodalbail if (iph->iph_sock6 != -1) 259*6e91bba0SGirish Moodalbail (void) close(iph->iph_sock6); 260*6e91bba0SGirish Moodalbail if (iph->iph_door_fd != -1) 261*6e91bba0SGirish Moodalbail (void) close(iph->iph_door_fd); 262*6e91bba0SGirish Moodalbail dladm_close(iph->iph_dlh); 263*6e91bba0SGirish Moodalbail (void) pthread_mutex_destroy(&iph->iph_lock); 264*6e91bba0SGirish Moodalbail free(iph); 265*6e91bba0SGirish Moodalbail } 266*6e91bba0SGirish Moodalbail 267*6e91bba0SGirish Moodalbail /* 268*6e91bba0SGirish Moodalbail * Checks if the caller has the authorization to configure network 269*6e91bba0SGirish Moodalbail * interfaces. 270*6e91bba0SGirish Moodalbail */ 271*6e91bba0SGirish Moodalbail boolean_t 272*6e91bba0SGirish Moodalbail ipadm_check_auth(void) 273*6e91bba0SGirish Moodalbail { 274*6e91bba0SGirish Moodalbail struct passwd pwd; 275*6e91bba0SGirish Moodalbail char buf[NSS_BUFLEN_PASSWD]; 276*6e91bba0SGirish Moodalbail 277*6e91bba0SGirish Moodalbail /* get the password entry for the given user ID */ 278*6e91bba0SGirish Moodalbail if (getpwuid_r(getuid(), &pwd, buf, sizeof (buf)) == NULL) 279*6e91bba0SGirish Moodalbail return (B_FALSE); 280*6e91bba0SGirish Moodalbail 281*6e91bba0SGirish Moodalbail /* check for presence of given authorization */ 282*6e91bba0SGirish Moodalbail return (chkauthattr(NETWORK_INTERFACE_CONFIG_AUTH, pwd.pw_name) != 0); 283*6e91bba0SGirish Moodalbail } 284*6e91bba0SGirish Moodalbail 285*6e91bba0SGirish Moodalbail /* 286*6e91bba0SGirish Moodalbail * Stores the index value of the interface in `ifname' for the address 287*6e91bba0SGirish Moodalbail * family `af' into the buffer pointed to by `index'. 288*6e91bba0SGirish Moodalbail */ 289*6e91bba0SGirish Moodalbail static ipadm_status_t 290*6e91bba0SGirish Moodalbail i_ipadm_get_index(ipadm_handle_t iph, const char *ifname, sa_family_t af, 291*6e91bba0SGirish Moodalbail int *index) 292*6e91bba0SGirish Moodalbail { 293*6e91bba0SGirish Moodalbail struct lifreq lifr; 294*6e91bba0SGirish Moodalbail int sock; 295*6e91bba0SGirish Moodalbail 296*6e91bba0SGirish Moodalbail bzero(&lifr, sizeof (lifr)); 297*6e91bba0SGirish Moodalbail (void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name)); 298*6e91bba0SGirish Moodalbail if (af == AF_INET) 299*6e91bba0SGirish Moodalbail sock = iph->iph_sock; 300*6e91bba0SGirish Moodalbail else 301*6e91bba0SGirish Moodalbail sock = iph->iph_sock6; 302*6e91bba0SGirish Moodalbail 303*6e91bba0SGirish Moodalbail if (ioctl(sock, SIOCGLIFINDEX, (caddr_t)&lifr) < 0) 304*6e91bba0SGirish Moodalbail return (ipadm_errno2status(errno)); 305*6e91bba0SGirish Moodalbail *index = lifr.lifr_index; 306*6e91bba0SGirish Moodalbail 307*6e91bba0SGirish Moodalbail return (IPADM_SUCCESS); 308*6e91bba0SGirish Moodalbail } 309*6e91bba0SGirish Moodalbail 310*6e91bba0SGirish Moodalbail /* 311*6e91bba0SGirish Moodalbail * Maximum amount of time (in milliseconds) to wait for Duplicate Address 312*6e91bba0SGirish Moodalbail * Detection to complete in the kernel. 313*6e91bba0SGirish Moodalbail */ 314*6e91bba0SGirish Moodalbail #define DAD_WAIT_TIME 1000 315*6e91bba0SGirish Moodalbail 316*6e91bba0SGirish Moodalbail /* 317*6e91bba0SGirish Moodalbail * Any time that flags are changed on an interface where either the new or the 318*6e91bba0SGirish Moodalbail * existing flags have IFF_UP set, we'll get a RTM_NEWADDR message to 319*6e91bba0SGirish Moodalbail * announce the new address added and its flag status. 320*6e91bba0SGirish Moodalbail * We wait here for that message and look for IFF_UP. 321*6e91bba0SGirish Moodalbail * If something's amiss with the kernel, though, we don't wait forever. 322*6e91bba0SGirish Moodalbail * (Note that IFF_DUPLICATE is a high-order bit, and we cannot see 323*6e91bba0SGirish Moodalbail * it in the routing socket messages.) 324*6e91bba0SGirish Moodalbail */ 325*6e91bba0SGirish Moodalbail static ipadm_status_t 326*6e91bba0SGirish Moodalbail i_ipadm_dad_wait(ipadm_handle_t handle, const char *lifname, sa_family_t af, 327*6e91bba0SGirish Moodalbail int rtsock) 328*6e91bba0SGirish Moodalbail { 329*6e91bba0SGirish Moodalbail struct pollfd fds[1]; 330*6e91bba0SGirish Moodalbail union { 331*6e91bba0SGirish Moodalbail struct if_msghdr ifm; 332*6e91bba0SGirish Moodalbail char buf[1024]; 333*6e91bba0SGirish Moodalbail } msg; 334*6e91bba0SGirish Moodalbail int index; 335*6e91bba0SGirish Moodalbail ipadm_status_t retv; 336*6e91bba0SGirish Moodalbail uint64_t flags; 337*6e91bba0SGirish Moodalbail hrtime_t starttime, now; 338*6e91bba0SGirish Moodalbail 339*6e91bba0SGirish Moodalbail fds[0].fd = rtsock; 340*6e91bba0SGirish Moodalbail fds[0].events = POLLIN; 341*6e91bba0SGirish Moodalbail fds[0].revents = 0; 342*6e91bba0SGirish Moodalbail 343*6e91bba0SGirish Moodalbail retv = i_ipadm_get_index(handle, lifname, af, &index); 344*6e91bba0SGirish Moodalbail if (retv != IPADM_SUCCESS) 345*6e91bba0SGirish Moodalbail return (retv); 346*6e91bba0SGirish Moodalbail 347*6e91bba0SGirish Moodalbail starttime = gethrtime(); 348*6e91bba0SGirish Moodalbail for (;;) { 349*6e91bba0SGirish Moodalbail now = gethrtime(); 350*6e91bba0SGirish Moodalbail now = (now - starttime) / 1000000; 351*6e91bba0SGirish Moodalbail if (now >= DAD_WAIT_TIME) 352*6e91bba0SGirish Moodalbail break; 353*6e91bba0SGirish Moodalbail if (poll(fds, 1, DAD_WAIT_TIME - (int)now) <= 0) 354*6e91bba0SGirish Moodalbail break; 355*6e91bba0SGirish Moodalbail if (read(rtsock, &msg, sizeof (msg)) <= 0) 356*6e91bba0SGirish Moodalbail break; 357*6e91bba0SGirish Moodalbail if (msg.ifm.ifm_type != RTM_NEWADDR) 358*6e91bba0SGirish Moodalbail continue; 359*6e91bba0SGirish Moodalbail /* Note that ifm_index is just 16 bits */ 360*6e91bba0SGirish Moodalbail if (index == msg.ifm.ifm_index && (msg.ifm.ifm_flags & IFF_UP)) 361*6e91bba0SGirish Moodalbail return (IPADM_SUCCESS); 362*6e91bba0SGirish Moodalbail } 363*6e91bba0SGirish Moodalbail 364*6e91bba0SGirish Moodalbail retv = i_ipadm_get_flags(handle, lifname, af, &flags); 365*6e91bba0SGirish Moodalbail if (retv != IPADM_SUCCESS) 366*6e91bba0SGirish Moodalbail return (retv); 367*6e91bba0SGirish Moodalbail if (flags & IFF_DUPLICATE) 368*6e91bba0SGirish Moodalbail return (IPADM_DAD_FOUND); 369*6e91bba0SGirish Moodalbail 370*6e91bba0SGirish Moodalbail return (IPADM_SUCCESS); 371*6e91bba0SGirish Moodalbail } 372*6e91bba0SGirish Moodalbail 373*6e91bba0SGirish Moodalbail /* 374*6e91bba0SGirish Moodalbail * Sets the flags `on_flags' and resets the flags `off_flags' for the logical 375*6e91bba0SGirish Moodalbail * interface in `lifname'. 376*6e91bba0SGirish Moodalbail * 377*6e91bba0SGirish Moodalbail * If the new flags value will transition the interface from "down" to "up" 378*6e91bba0SGirish Moodalbail * then duplicate address detection is performed by the kernel. This routine 379*6e91bba0SGirish Moodalbail * waits to get the outcome of that test. 380*6e91bba0SGirish Moodalbail */ 381*6e91bba0SGirish Moodalbail ipadm_status_t 382*6e91bba0SGirish Moodalbail i_ipadm_set_flags(ipadm_handle_t iph, const char *lifname, sa_family_t af, 383*6e91bba0SGirish Moodalbail uint64_t on_flags, uint64_t off_flags) 384*6e91bba0SGirish Moodalbail { 385*6e91bba0SGirish Moodalbail struct lifreq lifr; 386*6e91bba0SGirish Moodalbail uint64_t oflags; 387*6e91bba0SGirish Moodalbail ipadm_status_t ret; 388*6e91bba0SGirish Moodalbail int rtsock = -1; 389*6e91bba0SGirish Moodalbail int sock, err; 390*6e91bba0SGirish Moodalbail 391*6e91bba0SGirish Moodalbail ret = i_ipadm_get_flags(iph, lifname, af, &oflags); 392*6e91bba0SGirish Moodalbail if (ret != IPADM_SUCCESS) 393*6e91bba0SGirish Moodalbail return (ret); 394*6e91bba0SGirish Moodalbail 395*6e91bba0SGirish Moodalbail sock = (af == AF_INET ? iph->iph_sock : iph->iph_sock6); 396*6e91bba0SGirish Moodalbail 397*6e91bba0SGirish Moodalbail /* 398*6e91bba0SGirish Moodalbail * Any time flags are changed on an interface that has IFF_UP set, 399*6e91bba0SGirish Moodalbail * we get a routing socket message. We care about the status, 400*6e91bba0SGirish Moodalbail * though, only when the new flags are marked "up." 401*6e91bba0SGirish Moodalbail */ 402*6e91bba0SGirish Moodalbail if (!(oflags & IFF_UP) && (on_flags & IFF_UP)) 403*6e91bba0SGirish Moodalbail rtsock = socket(PF_ROUTE, SOCK_RAW, af); 404*6e91bba0SGirish Moodalbail 405*6e91bba0SGirish Moodalbail oflags |= on_flags; 406*6e91bba0SGirish Moodalbail oflags &= ~off_flags; 407*6e91bba0SGirish Moodalbail bzero(&lifr, sizeof (lifr)); 408*6e91bba0SGirish Moodalbail (void) strlcpy(lifr.lifr_name, lifname, sizeof (lifr.lifr_name)); 409*6e91bba0SGirish Moodalbail lifr.lifr_flags = oflags; 410*6e91bba0SGirish Moodalbail if (ioctl(sock, SIOCSLIFFLAGS, (caddr_t)&lifr) < 0) { 411*6e91bba0SGirish Moodalbail err = errno; 412*6e91bba0SGirish Moodalbail if (rtsock != -1) 413*6e91bba0SGirish Moodalbail (void) close(rtsock); 414*6e91bba0SGirish Moodalbail return (ipadm_errno2status(err)); 415*6e91bba0SGirish Moodalbail } 416*6e91bba0SGirish Moodalbail if (rtsock == -1) { 417*6e91bba0SGirish Moodalbail return (IPADM_SUCCESS); 418*6e91bba0SGirish Moodalbail } else { 419*6e91bba0SGirish Moodalbail /* Wait for DAD to complete. */ 420*6e91bba0SGirish Moodalbail ret = i_ipadm_dad_wait(iph, lifname, af, rtsock); 421*6e91bba0SGirish Moodalbail (void) close(rtsock); 422*6e91bba0SGirish Moodalbail return (ret); 423*6e91bba0SGirish Moodalbail } 424*6e91bba0SGirish Moodalbail } 425*6e91bba0SGirish Moodalbail 426*6e91bba0SGirish Moodalbail /* 427*6e91bba0SGirish Moodalbail * Returns the flags value for the logical interface in `lifname' 428*6e91bba0SGirish Moodalbail * in the buffer pointed to by `flags'. 429*6e91bba0SGirish Moodalbail */ 430*6e91bba0SGirish Moodalbail ipadm_status_t 431*6e91bba0SGirish Moodalbail i_ipadm_get_flags(ipadm_handle_t iph, const char *lifname, sa_family_t af, 432*6e91bba0SGirish Moodalbail uint64_t *flags) 433*6e91bba0SGirish Moodalbail { 434*6e91bba0SGirish Moodalbail struct lifreq lifr; 435*6e91bba0SGirish Moodalbail int sock; 436*6e91bba0SGirish Moodalbail 437*6e91bba0SGirish Moodalbail bzero(&lifr, sizeof (lifr)); 438*6e91bba0SGirish Moodalbail (void) strlcpy(lifr.lifr_name, lifname, sizeof (lifr.lifr_name)); 439*6e91bba0SGirish Moodalbail if (af == AF_INET) 440*6e91bba0SGirish Moodalbail sock = iph->iph_sock; 441*6e91bba0SGirish Moodalbail else 442*6e91bba0SGirish Moodalbail sock = iph->iph_sock6; 443*6e91bba0SGirish Moodalbail 444*6e91bba0SGirish Moodalbail if (ioctl(sock, SIOCGLIFFLAGS, (caddr_t)&lifr) < 0) { 445*6e91bba0SGirish Moodalbail return (ipadm_errno2status(errno)); 446*6e91bba0SGirish Moodalbail } 447*6e91bba0SGirish Moodalbail *flags = lifr.lifr_flags; 448*6e91bba0SGirish Moodalbail 449*6e91bba0SGirish Moodalbail return (IPADM_SUCCESS); 450*6e91bba0SGirish Moodalbail } 451*6e91bba0SGirish Moodalbail 452*6e91bba0SGirish Moodalbail /* 453*6e91bba0SGirish Moodalbail * Determines whether or not an interface name represents a loopback 454*6e91bba0SGirish Moodalbail * interface, before the interface has been plumbed. 455*6e91bba0SGirish Moodalbail * It is assumed that the interface name in `ifname' is of correct format 456*6e91bba0SGirish Moodalbail * as verified by ifparse_ifspec(). 457*6e91bba0SGirish Moodalbail * 458*6e91bba0SGirish Moodalbail * Returns: B_TRUE if loopback, B_FALSE if not. 459*6e91bba0SGirish Moodalbail */ 460*6e91bba0SGirish Moodalbail boolean_t 461*6e91bba0SGirish Moodalbail i_ipadm_is_loopback(const char *ifname) 462*6e91bba0SGirish Moodalbail { 463*6e91bba0SGirish Moodalbail int len = strlen(LOOPBACK_IF); 464*6e91bba0SGirish Moodalbail 465*6e91bba0SGirish Moodalbail return (strncmp(ifname, LOOPBACK_IF, len) == 0 && 466*6e91bba0SGirish Moodalbail (ifname[len] == '\0' || ifname[len] == IPADM_LOGICAL_SEP)); 467*6e91bba0SGirish Moodalbail } 468*6e91bba0SGirish Moodalbail 469*6e91bba0SGirish Moodalbail /* 470*6e91bba0SGirish Moodalbail * Determines whether or not an interface name represents a vni 471*6e91bba0SGirish Moodalbail * interface, before the interface has been plumbed. 472*6e91bba0SGirish Moodalbail * It is assumed that the interface name in `ifname' is of correct format 473*6e91bba0SGirish Moodalbail * as verified by ifparse_ifspec(). 474*6e91bba0SGirish Moodalbail * 475*6e91bba0SGirish Moodalbail * Returns: B_TRUE if vni, B_FALSE if not. 476*6e91bba0SGirish Moodalbail */ 477*6e91bba0SGirish Moodalbail boolean_t 478*6e91bba0SGirish Moodalbail i_ipadm_is_vni(const char *ifname) 479*6e91bba0SGirish Moodalbail { 480*6e91bba0SGirish Moodalbail ifspec_t ifsp; 481*6e91bba0SGirish Moodalbail 482*6e91bba0SGirish Moodalbail return (ifparse_ifspec(ifname, &ifsp) && 483*6e91bba0SGirish Moodalbail strcmp(ifsp.ifsp_devnm, "vni") == 0); 484*6e91bba0SGirish Moodalbail } 485*6e91bba0SGirish Moodalbail 486*6e91bba0SGirish Moodalbail /* 487*6e91bba0SGirish Moodalbail * Returns B_TRUE if `ifname' is an IP interface on a 6to4 tunnel. 488*6e91bba0SGirish Moodalbail */ 489*6e91bba0SGirish Moodalbail boolean_t 490*6e91bba0SGirish Moodalbail i_ipadm_is_6to4(ipadm_handle_t iph, char *ifname) 491*6e91bba0SGirish Moodalbail { 492*6e91bba0SGirish Moodalbail dladm_status_t dlstatus; 493*6e91bba0SGirish Moodalbail datalink_class_t class; 494*6e91bba0SGirish Moodalbail iptun_params_t params; 495*6e91bba0SGirish Moodalbail datalink_id_t linkid; 496*6e91bba0SGirish Moodalbail 497*6e91bba0SGirish Moodalbail if (iph->iph_dlh == NULL) { 498*6e91bba0SGirish Moodalbail assert(getzoneid() != GLOBAL_ZONEID); 499*6e91bba0SGirish Moodalbail return (B_FALSE); 500*6e91bba0SGirish Moodalbail } 501*6e91bba0SGirish Moodalbail dlstatus = dladm_name2info(iph->iph_dlh, ifname, &linkid, NULL, 502*6e91bba0SGirish Moodalbail &class, NULL); 503*6e91bba0SGirish Moodalbail if (dlstatus == DLADM_STATUS_OK && class == DATALINK_CLASS_IPTUN) { 504*6e91bba0SGirish Moodalbail params.iptun_param_linkid = linkid; 505*6e91bba0SGirish Moodalbail dlstatus = dladm_iptun_getparams(iph->iph_dlh, ¶ms, 506*6e91bba0SGirish Moodalbail DLADM_OPT_ACTIVE); 507*6e91bba0SGirish Moodalbail if (dlstatus == DLADM_STATUS_OK && 508*6e91bba0SGirish Moodalbail params.iptun_param_type == IPTUN_TYPE_6TO4) { 509*6e91bba0SGirish Moodalbail return (B_TRUE); 510*6e91bba0SGirish Moodalbail } 511*6e91bba0SGirish Moodalbail } 512*6e91bba0SGirish Moodalbail return (B_FALSE); 513*6e91bba0SGirish Moodalbail } 514*6e91bba0SGirish Moodalbail 515*6e91bba0SGirish Moodalbail /* 516*6e91bba0SGirish Moodalbail * Returns B_TRUE if `ifname' represents an IPMP underlying interface. 517*6e91bba0SGirish Moodalbail */ 518*6e91bba0SGirish Moodalbail boolean_t 519*6e91bba0SGirish Moodalbail i_ipadm_is_under_ipmp(ipadm_handle_t iph, const char *ifname) 520*6e91bba0SGirish Moodalbail { 521*6e91bba0SGirish Moodalbail struct lifreq lifr; 522*6e91bba0SGirish Moodalbail 523*6e91bba0SGirish Moodalbail (void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name)); 524*6e91bba0SGirish Moodalbail if (ioctl(iph->iph_sock, SIOCGLIFGROUPNAME, (caddr_t)&lifr) < 0) { 525*6e91bba0SGirish Moodalbail if (ioctl(iph->iph_sock6, SIOCGLIFGROUPNAME, 526*6e91bba0SGirish Moodalbail (caddr_t)&lifr) < 0) { 527*6e91bba0SGirish Moodalbail return (B_FALSE); 528*6e91bba0SGirish Moodalbail } 529*6e91bba0SGirish Moodalbail } 530*6e91bba0SGirish Moodalbail return (lifr.lifr_groupname[0] != '\0'); 531*6e91bba0SGirish Moodalbail } 532*6e91bba0SGirish Moodalbail 533*6e91bba0SGirish Moodalbail /* 534*6e91bba0SGirish Moodalbail * Returns B_TRUE if `ifname' represents an IPMP meta-interface. 535*6e91bba0SGirish Moodalbail */ 536*6e91bba0SGirish Moodalbail boolean_t 537*6e91bba0SGirish Moodalbail i_ipadm_is_ipmp(ipadm_handle_t iph, const char *ifname) 538*6e91bba0SGirish Moodalbail { 539*6e91bba0SGirish Moodalbail uint64_t flags; 540*6e91bba0SGirish Moodalbail 541*6e91bba0SGirish Moodalbail if (i_ipadm_get_flags(iph, ifname, AF_INET, &flags) != IPADM_SUCCESS && 542*6e91bba0SGirish Moodalbail i_ipadm_get_flags(iph, ifname, AF_INET6, &flags) != IPADM_SUCCESS) 543*6e91bba0SGirish Moodalbail return (B_FALSE); 544*6e91bba0SGirish Moodalbail 545*6e91bba0SGirish Moodalbail return ((flags & IFF_IPMP) != 0); 546*6e91bba0SGirish Moodalbail } 547*6e91bba0SGirish Moodalbail 548*6e91bba0SGirish Moodalbail /* 549*6e91bba0SGirish Moodalbail * For a given interface name, ipadm_if_enabled() checks if v4 550*6e91bba0SGirish Moodalbail * or v6 or both IP interfaces exist in the active configuration. 551*6e91bba0SGirish Moodalbail */ 552*6e91bba0SGirish Moodalbail boolean_t 553*6e91bba0SGirish Moodalbail ipadm_if_enabled(ipadm_handle_t iph, const char *ifname, sa_family_t af) 554*6e91bba0SGirish Moodalbail { 555*6e91bba0SGirish Moodalbail struct lifreq lifr; 556*6e91bba0SGirish Moodalbail int s4 = iph->iph_sock; 557*6e91bba0SGirish Moodalbail int s6 = iph->iph_sock6; 558*6e91bba0SGirish Moodalbail 559*6e91bba0SGirish Moodalbail bzero(&lifr, sizeof (lifr)); 560*6e91bba0SGirish Moodalbail (void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name)); 561*6e91bba0SGirish Moodalbail switch (af) { 562*6e91bba0SGirish Moodalbail case AF_INET: 563*6e91bba0SGirish Moodalbail if (ioctl(s4, SIOCGLIFFLAGS, (caddr_t)&lifr) == 0) 564*6e91bba0SGirish Moodalbail return (B_TRUE); 565*6e91bba0SGirish Moodalbail break; 566*6e91bba0SGirish Moodalbail case AF_INET6: 567*6e91bba0SGirish Moodalbail if (ioctl(s6, SIOCGLIFFLAGS, (caddr_t)&lifr) == 0) 568*6e91bba0SGirish Moodalbail return (B_TRUE); 569*6e91bba0SGirish Moodalbail break; 570*6e91bba0SGirish Moodalbail case AF_UNSPEC: 571*6e91bba0SGirish Moodalbail if (ioctl(s4, SIOCGLIFFLAGS, (caddr_t)&lifr) == 0 || 572*6e91bba0SGirish Moodalbail ioctl(s6, SIOCGLIFFLAGS, (caddr_t)&lifr) == 0) { 573*6e91bba0SGirish Moodalbail return (B_TRUE); 574*6e91bba0SGirish Moodalbail } 575*6e91bba0SGirish Moodalbail } 576*6e91bba0SGirish Moodalbail return (B_FALSE); 577*6e91bba0SGirish Moodalbail } 578*6e91bba0SGirish Moodalbail 579*6e91bba0SGirish Moodalbail /* 580*6e91bba0SGirish Moodalbail * Apply the interface property by retrieving information from nvl. 581*6e91bba0SGirish Moodalbail */ 582*6e91bba0SGirish Moodalbail static ipadm_status_t 583*6e91bba0SGirish Moodalbail i_ipadm_init_ifprop(ipadm_handle_t iph, nvlist_t *nvl) 584*6e91bba0SGirish Moodalbail { 585*6e91bba0SGirish Moodalbail nvpair_t *nvp; 586*6e91bba0SGirish Moodalbail char *name, *pname = NULL; 587*6e91bba0SGirish Moodalbail char *protostr = NULL, *ifname = NULL, *pval = NULL; 588*6e91bba0SGirish Moodalbail uint_t proto; 589*6e91bba0SGirish Moodalbail int err = 0; 590*6e91bba0SGirish Moodalbail 591*6e91bba0SGirish Moodalbail for (nvp = nvlist_next_nvpair(nvl, NULL); nvp != NULL; 592*6e91bba0SGirish Moodalbail nvp = nvlist_next_nvpair(nvl, nvp)) { 593*6e91bba0SGirish Moodalbail name = nvpair_name(nvp); 594*6e91bba0SGirish Moodalbail if (strcmp(name, IPADM_NVP_IFNAME) == 0) { 595*6e91bba0SGirish Moodalbail if ((err = nvpair_value_string(nvp, &ifname)) != 0) 596*6e91bba0SGirish Moodalbail break; 597*6e91bba0SGirish Moodalbail } else if (strcmp(name, IPADM_NVP_PROTONAME) == 0) { 598*6e91bba0SGirish Moodalbail if ((err = nvpair_value_string(nvp, &protostr)) != 0) 599*6e91bba0SGirish Moodalbail break; 600*6e91bba0SGirish Moodalbail } else { 601*6e91bba0SGirish Moodalbail assert(!IPADM_PRIV_NVP(name)); 602*6e91bba0SGirish Moodalbail pname = name; 603*6e91bba0SGirish Moodalbail if ((err = nvpair_value_string(nvp, &pval)) != 0) 604*6e91bba0SGirish Moodalbail break; 605*6e91bba0SGirish Moodalbail } 606*6e91bba0SGirish Moodalbail } 607*6e91bba0SGirish Moodalbail if (err != 0) 608*6e91bba0SGirish Moodalbail return (ipadm_errno2status(err)); 609*6e91bba0SGirish Moodalbail proto = ipadm_str2proto(protostr); 610*6e91bba0SGirish Moodalbail return (ipadm_set_ifprop(iph, ifname, pname, pval, proto, 611*6e91bba0SGirish Moodalbail IPADM_OPT_ACTIVE)); 612*6e91bba0SGirish Moodalbail } 613*6e91bba0SGirish Moodalbail 614*6e91bba0SGirish Moodalbail /* 615*6e91bba0SGirish Moodalbail * Instantiate the address object or set the address object property by 616*6e91bba0SGirish Moodalbail * retrieving the configuration from the nvlist `nvl'. 617*6e91bba0SGirish Moodalbail */ 618*6e91bba0SGirish Moodalbail ipadm_status_t 619*6e91bba0SGirish Moodalbail i_ipadm_init_addrobj(ipadm_handle_t iph, nvlist_t *nvl) 620*6e91bba0SGirish Moodalbail { 621*6e91bba0SGirish Moodalbail nvpair_t *nvp; 622*6e91bba0SGirish Moodalbail char *name; 623*6e91bba0SGirish Moodalbail char *aobjname = NULL, *pval = NULL, *ifname = NULL; 624*6e91bba0SGirish Moodalbail sa_family_t af = AF_UNSPEC; 625*6e91bba0SGirish Moodalbail ipadm_addr_type_t atype = IPADM_ADDR_NONE; 626*6e91bba0SGirish Moodalbail int err = 0; 627*6e91bba0SGirish Moodalbail ipadm_status_t status = IPADM_SUCCESS; 628*6e91bba0SGirish Moodalbail 629*6e91bba0SGirish Moodalbail for (nvp = nvlist_next_nvpair(nvl, NULL); nvp != NULL; 630*6e91bba0SGirish Moodalbail nvp = nvlist_next_nvpair(nvl, nvp)) { 631*6e91bba0SGirish Moodalbail name = nvpair_name(nvp); 632*6e91bba0SGirish Moodalbail if (strcmp(name, IPADM_NVP_IFNAME) == 0) { 633*6e91bba0SGirish Moodalbail if ((err = nvpair_value_string(nvp, &ifname)) != 0) 634*6e91bba0SGirish Moodalbail break; 635*6e91bba0SGirish Moodalbail } else if (strcmp(name, IPADM_NVP_AOBJNAME) == 0) { 636*6e91bba0SGirish Moodalbail if ((err = nvpair_value_string(nvp, &aobjname)) != 0) 637*6e91bba0SGirish Moodalbail break; 638*6e91bba0SGirish Moodalbail } else if (i_ipadm_name2atype(name, &af, &atype)) { 639*6e91bba0SGirish Moodalbail break; 640*6e91bba0SGirish Moodalbail } else { 641*6e91bba0SGirish Moodalbail assert(!IPADM_PRIV_NVP(name)); 642*6e91bba0SGirish Moodalbail err = nvpair_value_string(nvp, &pval); 643*6e91bba0SGirish Moodalbail break; 644*6e91bba0SGirish Moodalbail } 645*6e91bba0SGirish Moodalbail } 646*6e91bba0SGirish Moodalbail if (err != 0) 647*6e91bba0SGirish Moodalbail return (ipadm_errno2status(err)); 648*6e91bba0SGirish Moodalbail 649*6e91bba0SGirish Moodalbail switch (atype) { 650*6e91bba0SGirish Moodalbail case IPADM_ADDR_STATIC: 651*6e91bba0SGirish Moodalbail status = i_ipadm_enable_static(iph, ifname, nvl, af); 652*6e91bba0SGirish Moodalbail break; 653*6e91bba0SGirish Moodalbail case IPADM_ADDR_DHCP: 654*6e91bba0SGirish Moodalbail status = i_ipadm_enable_dhcp(iph, ifname, nvl); 655*6e91bba0SGirish Moodalbail if (status == IPADM_DHCP_IPC_TIMEOUT) 656*6e91bba0SGirish Moodalbail status = IPADM_SUCCESS; 657*6e91bba0SGirish Moodalbail break; 658*6e91bba0SGirish Moodalbail case IPADM_ADDR_IPV6_ADDRCONF: 659*6e91bba0SGirish Moodalbail status = i_ipadm_enable_addrconf(iph, ifname, nvl); 660*6e91bba0SGirish Moodalbail break; 661*6e91bba0SGirish Moodalbail case IPADM_ADDR_NONE: 662*6e91bba0SGirish Moodalbail status = ipadm_set_addrprop(iph, name, pval, aobjname, 663*6e91bba0SGirish Moodalbail IPADM_OPT_ACTIVE); 664*6e91bba0SGirish Moodalbail break; 665*6e91bba0SGirish Moodalbail } 666*6e91bba0SGirish Moodalbail 667*6e91bba0SGirish Moodalbail return (status); 668*6e91bba0SGirish Moodalbail } 669*6e91bba0SGirish Moodalbail 670*6e91bba0SGirish Moodalbail /* 671*6e91bba0SGirish Moodalbail * Instantiate the interface object by retrieving the configuration from 672*6e91bba0SGirish Moodalbail * `ifnvl'. The nvlist `ifnvl' contains all the persistent configuration 673*6e91bba0SGirish Moodalbail * (interface properties and address objects on that interface) for the 674*6e91bba0SGirish Moodalbail * given `ifname'. 675*6e91bba0SGirish Moodalbail */ 676*6e91bba0SGirish Moodalbail ipadm_status_t 677*6e91bba0SGirish Moodalbail i_ipadm_init_ifobj(ipadm_handle_t iph, const char *ifname, nvlist_t *ifnvl) 678*6e91bba0SGirish Moodalbail { 679*6e91bba0SGirish Moodalbail nvlist_t *nvl = NULL; 680*6e91bba0SGirish Moodalbail nvpair_t *nvp; 681*6e91bba0SGirish Moodalbail char *afstr; 682*6e91bba0SGirish Moodalbail ipadm_status_t status; 683*6e91bba0SGirish Moodalbail ipadm_status_t ret_status = IPADM_SUCCESS; 684*6e91bba0SGirish Moodalbail char newifname[LIFNAMSIZ]; 685*6e91bba0SGirish Moodalbail char *aobjstr; 686*6e91bba0SGirish Moodalbail 687*6e91bba0SGirish Moodalbail (void) strlcpy(newifname, ifname, sizeof (newifname)); 688*6e91bba0SGirish Moodalbail /* 689*6e91bba0SGirish Moodalbail * First plumb the given interface and then apply all the persistent 690*6e91bba0SGirish Moodalbail * interface properties and then instantiate any persistent addresses 691*6e91bba0SGirish Moodalbail * objects on that interface. 692*6e91bba0SGirish Moodalbail */ 693*6e91bba0SGirish Moodalbail for (nvp = nvlist_next_nvpair(ifnvl, NULL); nvp != NULL; 694*6e91bba0SGirish Moodalbail nvp = nvlist_next_nvpair(ifnvl, nvp)) { 695*6e91bba0SGirish Moodalbail if (nvpair_value_nvlist(nvp, &nvl) != 0) 696*6e91bba0SGirish Moodalbail continue; 697*6e91bba0SGirish Moodalbail 698*6e91bba0SGirish Moodalbail if (nvlist_lookup_string(nvl, IPADM_NVP_FAMILY, &afstr) == 0) { 699*6e91bba0SGirish Moodalbail status = i_ipadm_plumb_if(iph, newifname, atoi(afstr), 700*6e91bba0SGirish Moodalbail IPADM_OPT_ACTIVE); 701*6e91bba0SGirish Moodalbail /* 702*6e91bba0SGirish Moodalbail * If the interface is already plumbed, we should 703*6e91bba0SGirish Moodalbail * ignore this error because there might be address 704*6e91bba0SGirish Moodalbail * address objects on that interface that needs to 705*6e91bba0SGirish Moodalbail * be enabled again. 706*6e91bba0SGirish Moodalbail */ 707*6e91bba0SGirish Moodalbail if (status == IPADM_IF_EXISTS) 708*6e91bba0SGirish Moodalbail status = IPADM_SUCCESS; 709*6e91bba0SGirish Moodalbail } else if (nvlist_lookup_string(nvl, IPADM_NVP_AOBJNAME, 710*6e91bba0SGirish Moodalbail &aobjstr) == 0) { 711*6e91bba0SGirish Moodalbail /* 712*6e91bba0SGirish Moodalbail * For a static address, we need to search for 713*6e91bba0SGirish Moodalbail * the prefixlen in the nvlist `ifnvl'. 714*6e91bba0SGirish Moodalbail */ 715*6e91bba0SGirish Moodalbail if (nvlist_exists(nvl, IPADM_NVP_IPV4ADDR) || 716*6e91bba0SGirish Moodalbail nvlist_exists(nvl, IPADM_NVP_IPV6ADDR)) { 717*6e91bba0SGirish Moodalbail status = i_ipadm_merge_prefixlen_from_nvl(ifnvl, 718*6e91bba0SGirish Moodalbail nvl, aobjstr); 719*6e91bba0SGirish Moodalbail if (status != IPADM_SUCCESS) 720*6e91bba0SGirish Moodalbail continue; 721*6e91bba0SGirish Moodalbail } 722*6e91bba0SGirish Moodalbail status = i_ipadm_init_addrobj(iph, nvl); 723*6e91bba0SGirish Moodalbail /* 724*6e91bba0SGirish Moodalbail * If this address is in use on some other interface, 725*6e91bba0SGirish Moodalbail * we want to record an error to be returned as 726*6e91bba0SGirish Moodalbail * a soft error and continue processing the rest of 727*6e91bba0SGirish Moodalbail * the addresses. 728*6e91bba0SGirish Moodalbail */ 729*6e91bba0SGirish Moodalbail if (status == IPADM_ADDR_NOTAVAIL) { 730*6e91bba0SGirish Moodalbail ret_status = IPADM_ALL_ADDRS_NOT_ENABLED; 731*6e91bba0SGirish Moodalbail status = IPADM_SUCCESS; 732*6e91bba0SGirish Moodalbail } 733*6e91bba0SGirish Moodalbail } else { 734*6e91bba0SGirish Moodalbail assert(nvlist_exists(nvl, IPADM_NVP_PROTONAME)); 735*6e91bba0SGirish Moodalbail status = i_ipadm_init_ifprop(iph, nvl); 736*6e91bba0SGirish Moodalbail } 737*6e91bba0SGirish Moodalbail if (status != IPADM_SUCCESS) 738*6e91bba0SGirish Moodalbail return (status); 739*6e91bba0SGirish Moodalbail } 740*6e91bba0SGirish Moodalbail return (ret_status); 741*6e91bba0SGirish Moodalbail } 742*6e91bba0SGirish Moodalbail 743*6e91bba0SGirish Moodalbail /* 744*6e91bba0SGirish Moodalbail * Retrieves the persistent configuration for the given interface(s) in `ifs' 745*6e91bba0SGirish Moodalbail * by contacting the daemon and dumps the information in `allifs'. 746*6e91bba0SGirish Moodalbail */ 747*6e91bba0SGirish Moodalbail ipadm_status_t 748*6e91bba0SGirish Moodalbail i_ipadm_init_ifs(ipadm_handle_t iph, const char *ifs, nvlist_t **allifs) 749*6e91bba0SGirish Moodalbail { 750*6e91bba0SGirish Moodalbail nvlist_t *nvl = NULL; 751*6e91bba0SGirish Moodalbail size_t nvlsize, bufsize; 752*6e91bba0SGirish Moodalbail ipmgmt_initif_arg_t *iargp; 753*6e91bba0SGirish Moodalbail char *buf = NULL, *nvlbuf = NULL; 754*6e91bba0SGirish Moodalbail ipmgmt_get_rval_t *rvalp = NULL; 755*6e91bba0SGirish Moodalbail int err; 756*6e91bba0SGirish Moodalbail ipadm_status_t status = IPADM_SUCCESS; 757*6e91bba0SGirish Moodalbail 758*6e91bba0SGirish Moodalbail if ((err = ipadm_str2nvlist(ifs, &nvl, IPADM_NORVAL)) != 0) 759*6e91bba0SGirish Moodalbail return (ipadm_errno2status(err)); 760*6e91bba0SGirish Moodalbail 761*6e91bba0SGirish Moodalbail err = nvlist_pack(nvl, &nvlbuf, &nvlsize, NV_ENCODE_NATIVE, 0); 762*6e91bba0SGirish Moodalbail if (err != 0) { 763*6e91bba0SGirish Moodalbail status = ipadm_errno2status(err); 764*6e91bba0SGirish Moodalbail goto done; 765*6e91bba0SGirish Moodalbail } 766*6e91bba0SGirish Moodalbail bufsize = sizeof (*iargp) + nvlsize; 767*6e91bba0SGirish Moodalbail if ((buf = malloc(bufsize)) == NULL) { 768*6e91bba0SGirish Moodalbail status = ipadm_errno2status(errno); 769*6e91bba0SGirish Moodalbail goto done; 770*6e91bba0SGirish Moodalbail } 771*6e91bba0SGirish Moodalbail 772*6e91bba0SGirish Moodalbail /* populate the door_call argument structure */ 773*6e91bba0SGirish Moodalbail iargp = (void *)buf; 774*6e91bba0SGirish Moodalbail iargp->ia_cmd = IPMGMT_CMD_INITIF; 775*6e91bba0SGirish Moodalbail iargp->ia_flags = 0; 776*6e91bba0SGirish Moodalbail iargp->ia_family = AF_UNSPEC; 777*6e91bba0SGirish Moodalbail iargp->ia_nvlsize = nvlsize; 778*6e91bba0SGirish Moodalbail (void) bcopy(nvlbuf, buf + sizeof (*iargp), nvlsize); 779*6e91bba0SGirish Moodalbail 780*6e91bba0SGirish Moodalbail if ((rvalp = malloc(sizeof (ipmgmt_get_rval_t))) == NULL) { 781*6e91bba0SGirish Moodalbail status = ipadm_errno2status(errno); 782*6e91bba0SGirish Moodalbail goto done; 783*6e91bba0SGirish Moodalbail } 784*6e91bba0SGirish Moodalbail if ((err = ipadm_door_call(iph, iargp, bufsize, (void **)&rvalp, 785*6e91bba0SGirish Moodalbail sizeof (*rvalp), B_TRUE)) != 0) { 786*6e91bba0SGirish Moodalbail status = ipadm_errno2status(err); 787*6e91bba0SGirish Moodalbail goto done; 788*6e91bba0SGirish Moodalbail } 789*6e91bba0SGirish Moodalbail nvlsize = rvalp->ir_nvlsize; 790*6e91bba0SGirish Moodalbail nvlbuf = (char *)rvalp + sizeof (ipmgmt_get_rval_t); 791*6e91bba0SGirish Moodalbail 792*6e91bba0SGirish Moodalbail /* 793*6e91bba0SGirish Moodalbail * nvlbuf contains a list of nvlists, each of which represents 794*6e91bba0SGirish Moodalbail * configuration information for the given interface(s) 795*6e91bba0SGirish Moodalbail */ 796*6e91bba0SGirish Moodalbail err = nvlist_unpack(nvlbuf, nvlsize, allifs, NV_ENCODE_NATIVE); 797*6e91bba0SGirish Moodalbail if (err != 0) 798*6e91bba0SGirish Moodalbail status = ipadm_errno2status(err); 799*6e91bba0SGirish Moodalbail done: 800*6e91bba0SGirish Moodalbail nvlist_free(nvl); 801*6e91bba0SGirish Moodalbail free(buf); 802*6e91bba0SGirish Moodalbail free(nvlbuf); 803*6e91bba0SGirish Moodalbail free(rvalp); 804*6e91bba0SGirish Moodalbail return (status); 805*6e91bba0SGirish Moodalbail } 806*6e91bba0SGirish Moodalbail 807*6e91bba0SGirish Moodalbail /* 808*6e91bba0SGirish Moodalbail * Returns B_FALSE if 809*6e91bba0SGirish Moodalbail * (1) `ifname' is NULL or has no string or has a string of invalid length 810*6e91bba0SGirish Moodalbail * (2) ifname is a logical interface and IPH_LEGACY is not set, or 811*6e91bba0SGirish Moodalbail */ 812*6e91bba0SGirish Moodalbail boolean_t 813*6e91bba0SGirish Moodalbail i_ipadm_validate_ifname(ipadm_handle_t iph, const char *ifname) 814*6e91bba0SGirish Moodalbail { 815*6e91bba0SGirish Moodalbail ifspec_t ifsp; 816*6e91bba0SGirish Moodalbail 817*6e91bba0SGirish Moodalbail if (ifname == NULL || ifname[0] == '\0' || 818*6e91bba0SGirish Moodalbail !ifparse_ifspec(ifname, &ifsp)) 819*6e91bba0SGirish Moodalbail return (B_FALSE); 820*6e91bba0SGirish Moodalbail if (ifsp.ifsp_lunvalid) 821*6e91bba0SGirish Moodalbail return (ifsp.ifsp_lun > 0 && (iph->iph_flags & IPH_LEGACY)); 822*6e91bba0SGirish Moodalbail return (B_TRUE); 823*6e91bba0SGirish Moodalbail } 824*6e91bba0SGirish Moodalbail 825*6e91bba0SGirish Moodalbail /* 826*6e91bba0SGirish Moodalbail * Wrapper for sending a non-transparent I_STR ioctl(). 827*6e91bba0SGirish Moodalbail * Returns: Result from ioctl(). 828*6e91bba0SGirish Moodalbail */ 829*6e91bba0SGirish Moodalbail int 830*6e91bba0SGirish Moodalbail i_ipadm_strioctl(int s, int cmd, char *buf, int buflen) 831*6e91bba0SGirish Moodalbail { 832*6e91bba0SGirish Moodalbail struct strioctl ioc; 833*6e91bba0SGirish Moodalbail 834*6e91bba0SGirish Moodalbail (void) memset(&ioc, 0, sizeof (ioc)); 835*6e91bba0SGirish Moodalbail ioc.ic_cmd = cmd; 836*6e91bba0SGirish Moodalbail ioc.ic_timout = 0; 837*6e91bba0SGirish Moodalbail ioc.ic_len = buflen; 838*6e91bba0SGirish Moodalbail ioc.ic_dp = buf; 839*6e91bba0SGirish Moodalbail 840*6e91bba0SGirish Moodalbail return (ioctl(s, I_STR, (char *)&ioc)); 841*6e91bba0SGirish Moodalbail } 842*6e91bba0SGirish Moodalbail 843*6e91bba0SGirish Moodalbail /* 844*6e91bba0SGirish Moodalbail * Make a door call to the server and checks if the door call succeeded or not. 845*6e91bba0SGirish Moodalbail * `is_varsize' specifies that the data returned by ipmgmtd daemon is of 846*6e91bba0SGirish Moodalbail * variable size and door will allocate buffer using mmap(). In such cases 847*6e91bba0SGirish Moodalbail * we re-allocate the required memory,n assign it to `rbufp', copy the data to 848*6e91bba0SGirish Moodalbail * `rbufp' and then call munmap() (see below). 849*6e91bba0SGirish Moodalbail * 850*6e91bba0SGirish Moodalbail * It also checks to see if the server side procedure ran successfully by 851*6e91bba0SGirish Moodalbail * checking for ir_err. Therefore, for some callers who just care about the 852*6e91bba0SGirish Moodalbail * return status can set `rbufp' to NULL and set `rsize' to 0. 853*6e91bba0SGirish Moodalbail */ 854*6e91bba0SGirish Moodalbail int 855*6e91bba0SGirish Moodalbail ipadm_door_call(ipadm_handle_t iph, void *arg, size_t asize, void **rbufp, 856*6e91bba0SGirish Moodalbail size_t rsize, boolean_t is_varsize) 857*6e91bba0SGirish Moodalbail { 858*6e91bba0SGirish Moodalbail door_arg_t darg; 859*6e91bba0SGirish Moodalbail int err; 860*6e91bba0SGirish Moodalbail ipmgmt_retval_t rval, *rvalp; 861*6e91bba0SGirish Moodalbail 862*6e91bba0SGirish Moodalbail if (rbufp == NULL) { 863*6e91bba0SGirish Moodalbail rvalp = &rval; 864*6e91bba0SGirish Moodalbail rbufp = (void **)&rvalp; 865*6e91bba0SGirish Moodalbail rsize = sizeof (rval); 866*6e91bba0SGirish Moodalbail } 867*6e91bba0SGirish Moodalbail 868*6e91bba0SGirish Moodalbail darg.data_ptr = arg; 869*6e91bba0SGirish Moodalbail darg.data_size = asize; 870*6e91bba0SGirish Moodalbail darg.desc_ptr = NULL; 871*6e91bba0SGirish Moodalbail darg.desc_num = 0; 872*6e91bba0SGirish Moodalbail darg.rbuf = *rbufp; 873*6e91bba0SGirish Moodalbail darg.rsize = rsize; 874*6e91bba0SGirish Moodalbail 875*6e91bba0SGirish Moodalbail (void) pthread_mutex_lock(&iph->iph_lock); 876*6e91bba0SGirish Moodalbail /* The door descriptor is opened if it isn't already */ 877*6e91bba0SGirish Moodalbail if (iph->iph_door_fd == -1) { 878*6e91bba0SGirish Moodalbail if ((iph->iph_door_fd = open(IPMGMT_DOOR, O_RDONLY)) < 0) { 879*6e91bba0SGirish Moodalbail err = errno; 880*6e91bba0SGirish Moodalbail (void) pthread_mutex_unlock(&iph->iph_lock); 881*6e91bba0SGirish Moodalbail return (err); 882*6e91bba0SGirish Moodalbail } 883*6e91bba0SGirish Moodalbail } 884*6e91bba0SGirish Moodalbail (void) pthread_mutex_unlock(&iph->iph_lock); 885*6e91bba0SGirish Moodalbail 886*6e91bba0SGirish Moodalbail if (door_call(iph->iph_door_fd, &darg) == -1) 887*6e91bba0SGirish Moodalbail return (errno); 888*6e91bba0SGirish Moodalbail err = ((ipmgmt_retval_t *)(void *)(darg.rbuf))->ir_err; 889*6e91bba0SGirish Moodalbail if (darg.rbuf != *rbufp) { 890*6e91bba0SGirish Moodalbail /* 891*6e91bba0SGirish Moodalbail * if the caller is expecting the result to fit in specified 892*6e91bba0SGirish Moodalbail * buffer then return failure. 893*6e91bba0SGirish Moodalbail */ 894*6e91bba0SGirish Moodalbail if (!is_varsize) 895*6e91bba0SGirish Moodalbail err = EBADE; 896*6e91bba0SGirish Moodalbail /* 897*6e91bba0SGirish Moodalbail * The size of the buffer `*rbufp' was not big enough 898*6e91bba0SGirish Moodalbail * and the door itself allocated buffer, for us. We will 899*6e91bba0SGirish Moodalbail * hit this, on several occasion as for some cases 900*6e91bba0SGirish Moodalbail * we cannot predict the size of the return structure. 901*6e91bba0SGirish Moodalbail * Reallocate the buffer `*rbufp' and memcpy() the contents 902*6e91bba0SGirish Moodalbail * to new buffer. 903*6e91bba0SGirish Moodalbail */ 904*6e91bba0SGirish Moodalbail if (err == 0) { 905*6e91bba0SGirish Moodalbail void *newp; 906*6e91bba0SGirish Moodalbail 907*6e91bba0SGirish Moodalbail /* allocated memory will be freed by the caller */ 908*6e91bba0SGirish Moodalbail if ((newp = realloc(*rbufp, darg.rsize)) == NULL) { 909*6e91bba0SGirish Moodalbail err = ENOMEM; 910*6e91bba0SGirish Moodalbail } else { 911*6e91bba0SGirish Moodalbail *rbufp = newp; 912*6e91bba0SGirish Moodalbail (void) memcpy(*rbufp, darg.rbuf, darg.rsize); 913*6e91bba0SGirish Moodalbail } 914*6e91bba0SGirish Moodalbail } 915*6e91bba0SGirish Moodalbail /* munmap() the door buffer */ 916*6e91bba0SGirish Moodalbail (void) munmap(darg.rbuf, darg.rsize); 917*6e91bba0SGirish Moodalbail } else { 918*6e91bba0SGirish Moodalbail if (darg.rsize != rsize) 919*6e91bba0SGirish Moodalbail err = EBADE; 920*6e91bba0SGirish Moodalbail } 921*6e91bba0SGirish Moodalbail return (err); 922*6e91bba0SGirish Moodalbail } 923