16e91bba0SGirish Moodalbail /* 26e91bba0SGirish Moodalbail * CDDL HEADER START 36e91bba0SGirish Moodalbail * 46e91bba0SGirish Moodalbail * The contents of this file are subject to the terms of the 56e91bba0SGirish Moodalbail * Common Development and Distribution License (the "License"). 66e91bba0SGirish Moodalbail * You may not use this file except in compliance with the License. 76e91bba0SGirish Moodalbail * 86e91bba0SGirish Moodalbail * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 96e91bba0SGirish Moodalbail * or http://www.opensolaris.org/os/licensing. 106e91bba0SGirish Moodalbail * See the License for the specific language governing permissions 116e91bba0SGirish Moodalbail * and limitations under the License. 126e91bba0SGirish Moodalbail * 136e91bba0SGirish Moodalbail * When distributing Covered Code, include this CDDL HEADER in each 146e91bba0SGirish Moodalbail * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 156e91bba0SGirish Moodalbail * If applicable, add the following below this CDDL HEADER, with the 166e91bba0SGirish Moodalbail * fields enclosed by brackets "[]" replaced with your own identifying 176e91bba0SGirish Moodalbail * information: Portions Copyright [yyyy] [name of copyright owner] 186e91bba0SGirish Moodalbail * 196e91bba0SGirish Moodalbail * CDDL HEADER END 206e91bba0SGirish Moodalbail */ 216e91bba0SGirish Moodalbail /* 228b88711aSGirish Moodalbail * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. 23*299625c6SSebastien Roy * Copyright (c) 2013 by Delphix. All rights reserved. 246e91bba0SGirish Moodalbail */ 256e91bba0SGirish Moodalbail 266e91bba0SGirish Moodalbail /* 276e91bba0SGirish Moodalbail * This file contains functions for address management such as creating 286e91bba0SGirish Moodalbail * an address, deleting an address, enabling an address, disabling an 296e91bba0SGirish Moodalbail * address, bringing an address down or up, setting/getting properties 306e91bba0SGirish Moodalbail * on an address object and listing address information 316e91bba0SGirish Moodalbail * for all addresses in active as well as persistent configuration. 326e91bba0SGirish Moodalbail */ 336e91bba0SGirish Moodalbail #include <sys/types.h> 346e91bba0SGirish Moodalbail #include <sys/socket.h> 356e91bba0SGirish Moodalbail #include <netdb.h> 366e91bba0SGirish Moodalbail #include <inet/ip.h> 376e91bba0SGirish Moodalbail #include <string.h> 386e91bba0SGirish Moodalbail #include <strings.h> 396e91bba0SGirish Moodalbail #include <assert.h> 406e91bba0SGirish Moodalbail #include <sys/sockio.h> 416e91bba0SGirish Moodalbail #include <errno.h> 426e91bba0SGirish Moodalbail #include <unistd.h> 436e91bba0SGirish Moodalbail #include <stropts.h> 446e91bba0SGirish Moodalbail #include <zone.h> 456e91bba0SGirish Moodalbail #include <netinet/in.h> 466e91bba0SGirish Moodalbail #include <arpa/inet.h> 476e91bba0SGirish Moodalbail #include <fcntl.h> 486e91bba0SGirish Moodalbail #include <ctype.h> 496e91bba0SGirish Moodalbail #include <dhcpagent_util.h> 506e91bba0SGirish Moodalbail #include <dhcpagent_ipc.h> 516e91bba0SGirish Moodalbail #include <ipadm_ndpd.h> 526e91bba0SGirish Moodalbail #include <libdladm.h> 536e91bba0SGirish Moodalbail #include <libdllink.h> 546e91bba0SGirish Moodalbail #include <libdliptun.h> 556e91bba0SGirish Moodalbail #include <ifaddrs.h> 566e91bba0SGirish Moodalbail #include "libipadm_impl.h" 576e91bba0SGirish Moodalbail 586e91bba0SGirish Moodalbail #define SIN6(a) ((struct sockaddr_in6 *)a) 596e91bba0SGirish Moodalbail #define SIN(a) ((struct sockaddr_in *)a) 606e91bba0SGirish Moodalbail 616e91bba0SGirish Moodalbail static ipadm_status_t i_ipadm_create_addr(ipadm_handle_t, ipadm_addrobj_t, 626e91bba0SGirish Moodalbail uint32_t); 636e91bba0SGirish Moodalbail static ipadm_status_t i_ipadm_create_dhcp(ipadm_handle_t, ipadm_addrobj_t, 646e91bba0SGirish Moodalbail uint32_t); 656e91bba0SGirish Moodalbail static ipadm_status_t i_ipadm_delete_dhcp(ipadm_handle_t, ipadm_addrobj_t, 666e91bba0SGirish Moodalbail boolean_t); 676e91bba0SGirish Moodalbail static ipadm_status_t i_ipadm_get_db_addr(ipadm_handle_t, const char *, 686e91bba0SGirish Moodalbail const char *, nvlist_t **); 696e91bba0SGirish Moodalbail static ipadm_status_t i_ipadm_op_dhcp(ipadm_addrobj_t, dhcp_ipc_type_t, 706e91bba0SGirish Moodalbail int *); 716e91bba0SGirish Moodalbail static ipadm_status_t i_ipadm_validate_create_addr(ipadm_handle_t, 726e91bba0SGirish Moodalbail ipadm_addrobj_t, uint32_t); 736e91bba0SGirish Moodalbail static ipadm_status_t i_ipadm_addr_persist_nvl(ipadm_handle_t, nvlist_t *, 746e91bba0SGirish Moodalbail uint32_t); 756e91bba0SGirish Moodalbail static ipadm_status_t i_ipadm_get_default_prefixlen(struct sockaddr_storage *, 766e91bba0SGirish Moodalbail uint32_t *); 776e91bba0SGirish Moodalbail static ipadm_status_t i_ipadm_get_static_addr_db(ipadm_handle_t, 786e91bba0SGirish Moodalbail ipadm_addrobj_t); 796e91bba0SGirish Moodalbail static boolean_t i_ipadm_is_user_aobjname_valid(const char *); 806e91bba0SGirish Moodalbail 816e91bba0SGirish Moodalbail /* 826e91bba0SGirish Moodalbail * Callback functions to retrieve property values from the kernel. These 836e91bba0SGirish Moodalbail * functions, when required, translate the values from the kernel to a format 846e91bba0SGirish Moodalbail * suitable for printing. They also retrieve DEFAULT, PERM and POSSIBLE values 856e91bba0SGirish Moodalbail * for a given property. 866e91bba0SGirish Moodalbail */ 876e91bba0SGirish Moodalbail static ipadm_pd_getf_t i_ipadm_get_prefixlen, i_ipadm_get_addr_flag, 886e91bba0SGirish Moodalbail i_ipadm_get_zone, i_ipadm_get_broadcast; 896e91bba0SGirish Moodalbail 906e91bba0SGirish Moodalbail /* 916e91bba0SGirish Moodalbail * Callback functions to set property values. These functions translate the 926e91bba0SGirish Moodalbail * values to a format suitable for kernel consumption, allocate the necessary 936e91bba0SGirish Moodalbail * ioctl buffers and then invoke ioctl(). 946e91bba0SGirish Moodalbail */ 956e91bba0SGirish Moodalbail static ipadm_pd_setf_t i_ipadm_set_prefixlen, i_ipadm_set_addr_flag, 966e91bba0SGirish Moodalbail i_ipadm_set_zone; 976e91bba0SGirish Moodalbail 986e91bba0SGirish Moodalbail /* address properties description table */ 996e91bba0SGirish Moodalbail ipadm_prop_desc_t ipadm_addrprop_table[] = { 100*299625c6SSebastien Roy { "broadcast", NULL, IPADMPROP_CLASS_ADDR, MOD_PROTO_NONE, 0, 1016e91bba0SGirish Moodalbail NULL, NULL, i_ipadm_get_broadcast }, 1026e91bba0SGirish Moodalbail 103*299625c6SSebastien Roy { "deprecated", NULL, IPADMPROP_CLASS_ADDR, MOD_PROTO_NONE, 0, 1046e91bba0SGirish Moodalbail i_ipadm_set_addr_flag, i_ipadm_get_onoff, 1056e91bba0SGirish Moodalbail i_ipadm_get_addr_flag }, 1066e91bba0SGirish Moodalbail 107*299625c6SSebastien Roy { "prefixlen", NULL, IPADMPROP_CLASS_ADDR, MOD_PROTO_NONE, 0, 1086e91bba0SGirish Moodalbail i_ipadm_set_prefixlen, i_ipadm_get_prefixlen, 1096e91bba0SGirish Moodalbail i_ipadm_get_prefixlen }, 1106e91bba0SGirish Moodalbail 111*299625c6SSebastien Roy { "private", NULL, IPADMPROP_CLASS_ADDR, MOD_PROTO_NONE, 0, 1126e91bba0SGirish Moodalbail i_ipadm_set_addr_flag, i_ipadm_get_onoff, i_ipadm_get_addr_flag }, 1136e91bba0SGirish Moodalbail 114*299625c6SSebastien Roy { "transmit", NULL, IPADMPROP_CLASS_ADDR, MOD_PROTO_NONE, 0, 1156e91bba0SGirish Moodalbail i_ipadm_set_addr_flag, i_ipadm_get_onoff, i_ipadm_get_addr_flag }, 1166e91bba0SGirish Moodalbail 117*299625c6SSebastien Roy { "zone", NULL, IPADMPROP_CLASS_ADDR, MOD_PROTO_NONE, 0, 1186e91bba0SGirish Moodalbail i_ipadm_set_zone, NULL, i_ipadm_get_zone }, 1196e91bba0SGirish Moodalbail 120*299625c6SSebastien Roy { NULL, NULL, 0, 0, 0, NULL, NULL, NULL } 1216e91bba0SGirish Moodalbail }; 1226e91bba0SGirish Moodalbail 123*299625c6SSebastien Roy static ipadm_prop_desc_t up_addrprop = { "up", NULL, IPADMPROP_CLASS_ADDR, 1248b88711aSGirish Moodalbail MOD_PROTO_NONE, 0, NULL, NULL, NULL }; 1256e91bba0SGirish Moodalbail 1266e91bba0SGirish Moodalbail /* 1276e91bba0SGirish Moodalbail * Helper function that initializes the `ipadm_ifname', `ipadm_aobjname', and 1286e91bba0SGirish Moodalbail * `ipadm_atype' fields of the given `ipaddr'. 1296e91bba0SGirish Moodalbail */ 1306e91bba0SGirish Moodalbail void 1316e91bba0SGirish Moodalbail i_ipadm_init_addr(ipadm_addrobj_t ipaddr, const char *ifname, 1326e91bba0SGirish Moodalbail const char *aobjname, ipadm_addr_type_t atype) 1336e91bba0SGirish Moodalbail { 1346e91bba0SGirish Moodalbail bzero(ipaddr, sizeof (struct ipadm_addrobj_s)); 1356e91bba0SGirish Moodalbail (void) strlcpy(ipaddr->ipadm_ifname, ifname, 1366e91bba0SGirish Moodalbail sizeof (ipaddr->ipadm_ifname)); 1376e91bba0SGirish Moodalbail (void) strlcpy(ipaddr->ipadm_aobjname, aobjname, 1386e91bba0SGirish Moodalbail sizeof (ipaddr->ipadm_aobjname)); 1396e91bba0SGirish Moodalbail ipaddr->ipadm_atype = atype; 1406e91bba0SGirish Moodalbail } 1416e91bba0SGirish Moodalbail 1426e91bba0SGirish Moodalbail /* 1436e91bba0SGirish Moodalbail * Determine the permission of the property depending on whether it has a 1446e91bba0SGirish Moodalbail * set() and/or get() callback functions. 1456e91bba0SGirish Moodalbail */ 1466e91bba0SGirish Moodalbail static ipadm_status_t 1476e91bba0SGirish Moodalbail i_ipadm_pd2permstr(ipadm_prop_desc_t *pdp, char *buf, uint_t *bufsize) 1486e91bba0SGirish Moodalbail { 1496e91bba0SGirish Moodalbail uint_t perm; 1506e91bba0SGirish Moodalbail size_t nbytes; 1516e91bba0SGirish Moodalbail 1526e91bba0SGirish Moodalbail perm = 0; 1536e91bba0SGirish Moodalbail if (pdp->ipd_set != NULL) 1546e91bba0SGirish Moodalbail perm |= MOD_PROP_PERM_WRITE; 1556e91bba0SGirish Moodalbail if (pdp->ipd_get != NULL) 1566e91bba0SGirish Moodalbail perm |= MOD_PROP_PERM_READ; 1576e91bba0SGirish Moodalbail 1586e91bba0SGirish Moodalbail nbytes = snprintf(buf, *bufsize, "%c%c", 1596e91bba0SGirish Moodalbail ((perm & MOD_PROP_PERM_READ) != 0) ? 'r' : '-', 1606e91bba0SGirish Moodalbail ((perm & MOD_PROP_PERM_WRITE) != 0) ? 'w' : '-'); 1616e91bba0SGirish Moodalbail 1626e91bba0SGirish Moodalbail if (nbytes >= *bufsize) { 1636e91bba0SGirish Moodalbail /* insufficient buffer space */ 1646e91bba0SGirish Moodalbail *bufsize = nbytes + 1; 1656e91bba0SGirish Moodalbail return (IPADM_NO_BUFS); 1666e91bba0SGirish Moodalbail } 1676e91bba0SGirish Moodalbail return (IPADM_SUCCESS); 1686e91bba0SGirish Moodalbail } 1696e91bba0SGirish Moodalbail 1706e91bba0SGirish Moodalbail /* 1716e91bba0SGirish Moodalbail * Given an addrobj with `ipadm_aobjname' filled in, i_ipadm_get_addrobj() 1726e91bba0SGirish Moodalbail * retrieves the information necessary for any operation on the object, 1736e91bba0SGirish Moodalbail * such as delete-addr, enable-addr, disable-addr, up-addr, down-addr, 1746e91bba0SGirish Moodalbail * refresh-addr, get-addrprop or set-addrprop. The information include 1756e91bba0SGirish Moodalbail * the logical interface number, address type, address family, 1766e91bba0SGirish Moodalbail * the interface id (if the address type is IPADM_ADDR_IPV6_ADDRCONF) and 1776e91bba0SGirish Moodalbail * the ipadm_flags that indicate if the address is present in 1786e91bba0SGirish Moodalbail * active configuration or persistent configuration or both. If the address 1796e91bba0SGirish Moodalbail * is not found, IPADM_NOTSUP is returned. 1806e91bba0SGirish Moodalbail */ 1816e91bba0SGirish Moodalbail ipadm_status_t 1826e91bba0SGirish Moodalbail i_ipadm_get_addrobj(ipadm_handle_t iph, ipadm_addrobj_t ipaddr) 1836e91bba0SGirish Moodalbail { 1846e91bba0SGirish Moodalbail ipmgmt_aobjop_arg_t larg; 1856e91bba0SGirish Moodalbail ipmgmt_aobjop_rval_t rval, *rvalp; 1866e91bba0SGirish Moodalbail int err = 0; 1876e91bba0SGirish Moodalbail 1886e91bba0SGirish Moodalbail /* populate the door_call argument structure */ 1896e91bba0SGirish Moodalbail larg.ia_cmd = IPMGMT_CMD_AOBJNAME2ADDROBJ; 1906e91bba0SGirish Moodalbail (void) strlcpy(larg.ia_aobjname, ipaddr->ipadm_aobjname, 1916e91bba0SGirish Moodalbail sizeof (larg.ia_aobjname)); 1926e91bba0SGirish Moodalbail 1936e91bba0SGirish Moodalbail rvalp = &rval; 1946e91bba0SGirish Moodalbail err = ipadm_door_call(iph, &larg, sizeof (larg), (void **)&rvalp, 1956e91bba0SGirish Moodalbail sizeof (rval), B_FALSE); 1966e91bba0SGirish Moodalbail if (err != 0) 1976e91bba0SGirish Moodalbail return (ipadm_errno2status(err)); 1986e91bba0SGirish Moodalbail (void) strlcpy(ipaddr->ipadm_ifname, rval.ir_ifname, 1996e91bba0SGirish Moodalbail sizeof (ipaddr->ipadm_ifname)); 2006e91bba0SGirish Moodalbail ipaddr->ipadm_lifnum = rval.ir_lnum; 2016e91bba0SGirish Moodalbail ipaddr->ipadm_atype = rval.ir_atype; 2026e91bba0SGirish Moodalbail ipaddr->ipadm_af = rval.ir_family; 2036e91bba0SGirish Moodalbail ipaddr->ipadm_flags = rval.ir_flags; 2046e91bba0SGirish Moodalbail if (rval.ir_atype == IPADM_ADDR_IPV6_ADDRCONF) { 2056e91bba0SGirish Moodalbail (void) memcpy(&ipaddr->ipadm_intfid, &rval.ir_ifid, 2066e91bba0SGirish Moodalbail sizeof (ipaddr->ipadm_intfid)); 2076e91bba0SGirish Moodalbail } 2086e91bba0SGirish Moodalbail 2096e91bba0SGirish Moodalbail return (IPADM_SUCCESS); 2106e91bba0SGirish Moodalbail } 2116e91bba0SGirish Moodalbail 2126e91bba0SGirish Moodalbail /* 2136e91bba0SGirish Moodalbail * Retrieves the static address (IPv4 or IPv6) for the given address object 2146e91bba0SGirish Moodalbail * in `ipaddr' from persistent DB. 2156e91bba0SGirish Moodalbail */ 2166e91bba0SGirish Moodalbail static ipadm_status_t 2176e91bba0SGirish Moodalbail i_ipadm_get_static_addr_db(ipadm_handle_t iph, ipadm_addrobj_t ipaddr) 2186e91bba0SGirish Moodalbail { 2196e91bba0SGirish Moodalbail ipadm_status_t status; 2206e91bba0SGirish Moodalbail nvlist_t *onvl; 2216e91bba0SGirish Moodalbail nvlist_t *anvl = NULL; 2226e91bba0SGirish Moodalbail nvlist_t *nvladdr; 2236e91bba0SGirish Moodalbail nvpair_t *nvp; 2246e91bba0SGirish Moodalbail char *name; 2256e91bba0SGirish Moodalbail char *aobjname = ipaddr->ipadm_aobjname; 2266e91bba0SGirish Moodalbail char *sname; 2276e91bba0SGirish Moodalbail sa_family_t af = AF_UNSPEC; 2286e91bba0SGirish Moodalbail 2296e91bba0SGirish Moodalbail /* 2306e91bba0SGirish Moodalbail * Get the address line in the nvlist `onvl' from ipmgmtd daemon. 2316e91bba0SGirish Moodalbail */ 2326e91bba0SGirish Moodalbail status = i_ipadm_get_db_addr(iph, NULL, aobjname, &onvl); 2336e91bba0SGirish Moodalbail if (status != IPADM_SUCCESS) 2346e91bba0SGirish Moodalbail return (status); 2356e91bba0SGirish Moodalbail /* 2366e91bba0SGirish Moodalbail * Walk through the nvlist `onvl' to extract the IPADM_NVP_IPV4ADDR 2376e91bba0SGirish Moodalbail * or the IPADM_NVP_IPV6ADDR name-value pair. 2386e91bba0SGirish Moodalbail */ 2396e91bba0SGirish Moodalbail for (nvp = nvlist_next_nvpair(onvl, NULL); nvp != NULL; 2406e91bba0SGirish Moodalbail nvp = nvlist_next_nvpair(onvl, NULL)) { 2416e91bba0SGirish Moodalbail if (nvpair_value_nvlist(nvp, &anvl) != 0) 2426e91bba0SGirish Moodalbail continue; 2436e91bba0SGirish Moodalbail if (nvlist_exists(anvl, IPADM_NVP_IPV4ADDR) || 2446e91bba0SGirish Moodalbail nvlist_exists(anvl, IPADM_NVP_IPV6ADDR)) 2456e91bba0SGirish Moodalbail break; 2466e91bba0SGirish Moodalbail } 2476e91bba0SGirish Moodalbail if (nvp == NULL) 2486e91bba0SGirish Moodalbail goto fail; 2496e91bba0SGirish Moodalbail for (nvp = nvlist_next_nvpair(anvl, NULL); 2506e91bba0SGirish Moodalbail nvp != NULL; nvp = nvlist_next_nvpair(anvl, nvp)) { 2516e91bba0SGirish Moodalbail name = nvpair_name(nvp); 2526e91bba0SGirish Moodalbail if (strcmp(name, IPADM_NVP_IPV4ADDR) == 0) { 2536e91bba0SGirish Moodalbail af = AF_INET; 2546e91bba0SGirish Moodalbail break; 2556e91bba0SGirish Moodalbail } else if (strcmp(name, IPADM_NVP_IPV6ADDR) == 0) { 2566e91bba0SGirish Moodalbail af = AF_INET6; 2576e91bba0SGirish Moodalbail break; 2586e91bba0SGirish Moodalbail } 2596e91bba0SGirish Moodalbail } 2606e91bba0SGirish Moodalbail assert(af != AF_UNSPEC); 2616e91bba0SGirish Moodalbail if (nvpair_value_nvlist(nvp, &nvladdr) != 0 || 2626e91bba0SGirish Moodalbail nvlist_lookup_string(nvladdr, IPADM_NVP_IPADDRHNAME, &sname) != 0 || 2636e91bba0SGirish Moodalbail ipadm_set_addr(ipaddr, sname, af) != IPADM_SUCCESS) { 2646e91bba0SGirish Moodalbail goto fail; 2656e91bba0SGirish Moodalbail } 2666e91bba0SGirish Moodalbail nvlist_free(onvl); 2676e91bba0SGirish Moodalbail return (IPADM_SUCCESS); 2686e91bba0SGirish Moodalbail fail: 2696e91bba0SGirish Moodalbail nvlist_free(onvl); 2706e91bba0SGirish Moodalbail return (IPADM_NOTFOUND); 2716e91bba0SGirish Moodalbail } 2726e91bba0SGirish Moodalbail 2736e91bba0SGirish Moodalbail /* 2746e91bba0SGirish Moodalbail * For the given `addrobj->ipadm_lifnum' and `addrobj->ipadm_af', this function 2756e91bba0SGirish Moodalbail * fills in the address objname, the address type and the ipadm_flags. 2766e91bba0SGirish Moodalbail */ 2776e91bba0SGirish Moodalbail ipadm_status_t 2786e91bba0SGirish Moodalbail i_ipadm_get_lif2addrobj(ipadm_handle_t iph, ipadm_addrobj_t addrobj) 2796e91bba0SGirish Moodalbail { 2806e91bba0SGirish Moodalbail ipmgmt_aobjop_arg_t larg; 2816e91bba0SGirish Moodalbail ipmgmt_aobjop_rval_t rval, *rvalp; 2826e91bba0SGirish Moodalbail int err; 2836e91bba0SGirish Moodalbail 2846e91bba0SGirish Moodalbail larg.ia_cmd = IPMGMT_CMD_LIF2ADDROBJ; 2856e91bba0SGirish Moodalbail (void) strlcpy(larg.ia_ifname, addrobj->ipadm_ifname, 2866e91bba0SGirish Moodalbail sizeof (larg.ia_ifname)); 2876e91bba0SGirish Moodalbail larg.ia_lnum = addrobj->ipadm_lifnum; 2886e91bba0SGirish Moodalbail larg.ia_family = addrobj->ipadm_af; 2896e91bba0SGirish Moodalbail 2906e91bba0SGirish Moodalbail rvalp = &rval; 2916e91bba0SGirish Moodalbail err = ipadm_door_call(iph, &larg, sizeof (larg), (void **)&rvalp, 2926e91bba0SGirish Moodalbail sizeof (rval), B_FALSE); 2936e91bba0SGirish Moodalbail if (err != 0) 2946e91bba0SGirish Moodalbail return (ipadm_errno2status(err)); 2956e91bba0SGirish Moodalbail (void) strlcpy(addrobj->ipadm_aobjname, rval.ir_aobjname, 2966e91bba0SGirish Moodalbail sizeof (addrobj->ipadm_aobjname)); 2976e91bba0SGirish Moodalbail addrobj->ipadm_atype = rval.ir_atype; 2986e91bba0SGirish Moodalbail addrobj->ipadm_flags = rval.ir_flags; 2996e91bba0SGirish Moodalbail 3006e91bba0SGirish Moodalbail return (IPADM_SUCCESS); 3016e91bba0SGirish Moodalbail } 3026e91bba0SGirish Moodalbail 3036e91bba0SGirish Moodalbail /* 3046e91bba0SGirish Moodalbail * Adds an addrobj to ipmgmtd daemon's aobjmap (active configuration). 3056e91bba0SGirish Moodalbail * with the given name and logical interface number. 3066e91bba0SGirish Moodalbail * This API is called by in.ndpd to add addrobjs when new prefixes or 3076e91bba0SGirish Moodalbail * dhcpv6 addresses are configured. 3086e91bba0SGirish Moodalbail */ 3096e91bba0SGirish Moodalbail ipadm_status_t 3106e91bba0SGirish Moodalbail ipadm_add_aobjname(ipadm_handle_t iph, const char *ifname, sa_family_t af, 3116e91bba0SGirish Moodalbail const char *aobjname, ipadm_addr_type_t atype, int lnum) 3126e91bba0SGirish Moodalbail { 3136e91bba0SGirish Moodalbail ipmgmt_aobjop_arg_t larg; 3146e91bba0SGirish Moodalbail int err; 3156e91bba0SGirish Moodalbail 3166e91bba0SGirish Moodalbail larg.ia_cmd = IPMGMT_CMD_ADDROBJ_ADD; 3176e91bba0SGirish Moodalbail (void) strlcpy(larg.ia_ifname, ifname, sizeof (larg.ia_ifname)); 3186e91bba0SGirish Moodalbail (void) strlcpy(larg.ia_aobjname, aobjname, sizeof (larg.ia_aobjname)); 3196e91bba0SGirish Moodalbail larg.ia_atype = atype; 3206e91bba0SGirish Moodalbail larg.ia_lnum = lnum; 3216e91bba0SGirish Moodalbail larg.ia_family = af; 3226e91bba0SGirish Moodalbail err = ipadm_door_call(iph, &larg, sizeof (larg), NULL, 0, B_FALSE); 3236e91bba0SGirish Moodalbail return (ipadm_errno2status(err)); 3246e91bba0SGirish Moodalbail } 3256e91bba0SGirish Moodalbail 3266e91bba0SGirish Moodalbail /* 3276e91bba0SGirish Moodalbail * Deletes an address object with given name and logical number from ipmgmtd 3286e91bba0SGirish Moodalbail * daemon's aobjmap (active configuration). This API is called by in.ndpd to 3296e91bba0SGirish Moodalbail * remove addrobjs when auto-configured prefixes or dhcpv6 addresses are 3306e91bba0SGirish Moodalbail * removed. 3316e91bba0SGirish Moodalbail */ 3326e91bba0SGirish Moodalbail ipadm_status_t 3336e91bba0SGirish Moodalbail ipadm_delete_aobjname(ipadm_handle_t iph, const char *ifname, sa_family_t af, 3346e91bba0SGirish Moodalbail const char *aobjname, ipadm_addr_type_t atype, int lnum) 3356e91bba0SGirish Moodalbail { 3366e91bba0SGirish Moodalbail struct ipadm_addrobj_s aobj; 3376e91bba0SGirish Moodalbail 3386e91bba0SGirish Moodalbail i_ipadm_init_addr(&aobj, ifname, aobjname, atype); 3396e91bba0SGirish Moodalbail aobj.ipadm_af = af; 3406e91bba0SGirish Moodalbail aobj.ipadm_lifnum = lnum; 3416e91bba0SGirish Moodalbail return (i_ipadm_delete_addrobj(iph, &aobj, IPADM_OPT_ACTIVE)); 3426e91bba0SGirish Moodalbail } 3436e91bba0SGirish Moodalbail 3446e91bba0SGirish Moodalbail /* 3456e91bba0SGirish Moodalbail * Gets all the addresses from active configuration and populates the 3466e91bba0SGirish Moodalbail * address information in `addrinfo'. 3476e91bba0SGirish Moodalbail */ 3486e91bba0SGirish Moodalbail static ipadm_status_t 3496e91bba0SGirish Moodalbail i_ipadm_active_addr_info(ipadm_handle_t iph, const char *ifname, 3506e91bba0SGirish Moodalbail ipadm_addr_info_t **addrinfo, uint32_t ipadm_flags, int64_t lifc_flags) 3516e91bba0SGirish Moodalbail { 3526e91bba0SGirish Moodalbail ipadm_status_t status; 3536e91bba0SGirish Moodalbail struct ifaddrs *ifap, *ifa; 3546e91bba0SGirish Moodalbail ipadm_addr_info_t *curr, *prev = NULL; 3556e91bba0SGirish Moodalbail struct ifaddrs *cifaddr; 3566e91bba0SGirish Moodalbail struct lifreq lifr; 3576e91bba0SGirish Moodalbail int sock; 3586e91bba0SGirish Moodalbail uint64_t flags; 3596e91bba0SGirish Moodalbail char cifname[LIFNAMSIZ]; 3606e91bba0SGirish Moodalbail struct sockaddr_in6 *sin6; 3616e91bba0SGirish Moodalbail struct ipadm_addrobj_s ipaddr; 3626e91bba0SGirish Moodalbail char *sep; 3636e91bba0SGirish Moodalbail int lnum; 3646e91bba0SGirish Moodalbail 3656e91bba0SGirish Moodalbail retry: 3666e91bba0SGirish Moodalbail *addrinfo = NULL; 3676e91bba0SGirish Moodalbail 3686e91bba0SGirish Moodalbail /* Get all the configured addresses */ 3696e91bba0SGirish Moodalbail if (getallifaddrs(AF_UNSPEC, &ifa, lifc_flags) < 0) 3706e91bba0SGirish Moodalbail return (ipadm_errno2status(errno)); 3716e91bba0SGirish Moodalbail /* Return if there is nothing to process. */ 3726e91bba0SGirish Moodalbail if (ifa == NULL) 3736e91bba0SGirish Moodalbail return (IPADM_SUCCESS); 3746e91bba0SGirish Moodalbail bzero(&lifr, sizeof (lifr)); 3756e91bba0SGirish Moodalbail for (ifap = ifa; ifap != NULL; ifap = ifap->ifa_next) { 37664639aafSDarren Reed struct sockaddr_storage data; 37764639aafSDarren Reed 3786e91bba0SGirish Moodalbail (void) strlcpy(cifname, ifap->ifa_name, sizeof (cifname)); 3796e91bba0SGirish Moodalbail lnum = 0; 3806e91bba0SGirish Moodalbail if ((sep = strrchr(cifname, ':')) != NULL) { 3816e91bba0SGirish Moodalbail *sep++ = '\0'; 3826e91bba0SGirish Moodalbail lnum = atoi(sep); 3836e91bba0SGirish Moodalbail } 3846e91bba0SGirish Moodalbail if (ifname != NULL && strcmp(cifname, ifname) != 0) 3856e91bba0SGirish Moodalbail continue; 386ec3706caSVasumathi Sundaram if (!(ipadm_flags & IPADM_OPT_ZEROADDR) && 387ec3706caSVasumathi Sundaram sockaddrunspec(ifap->ifa_addr) && 388ec3706caSVasumathi Sundaram !(ifap->ifa_flags & IFF_DHCPRUNNING)) 3896e91bba0SGirish Moodalbail continue; 3906e91bba0SGirish Moodalbail 3916e91bba0SGirish Moodalbail /* Allocate and populate the current node in the list. */ 3926e91bba0SGirish Moodalbail if ((curr = calloc(1, sizeof (ipadm_addr_info_t))) == NULL) 3936e91bba0SGirish Moodalbail goto fail; 3946e91bba0SGirish Moodalbail 3956e91bba0SGirish Moodalbail /* Link to the list in `addrinfo'. */ 3966e91bba0SGirish Moodalbail if (prev != NULL) 3976e91bba0SGirish Moodalbail prev->ia_ifa.ifa_next = &curr->ia_ifa; 3986e91bba0SGirish Moodalbail else 3996e91bba0SGirish Moodalbail *addrinfo = curr; 4006e91bba0SGirish Moodalbail prev = curr; 4016e91bba0SGirish Moodalbail 4026e91bba0SGirish Moodalbail cifaddr = &curr->ia_ifa; 4036e91bba0SGirish Moodalbail if ((cifaddr->ifa_name = strdup(ifap->ifa_name)) == NULL) 4046e91bba0SGirish Moodalbail goto fail; 4056e91bba0SGirish Moodalbail cifaddr->ifa_flags = ifap->ifa_flags; 4066e91bba0SGirish Moodalbail cifaddr->ifa_addr = malloc(sizeof (struct sockaddr_storage)); 4076e91bba0SGirish Moodalbail if (cifaddr->ifa_addr == NULL) 4086e91bba0SGirish Moodalbail goto fail; 40964639aafSDarren Reed (void) memcpy(cifaddr->ifa_addr, ifap->ifa_addr, 41064639aafSDarren Reed sizeof (struct sockaddr_storage)); 4116e91bba0SGirish Moodalbail cifaddr->ifa_netmask = malloc(sizeof (struct sockaddr_storage)); 4126e91bba0SGirish Moodalbail if (cifaddr->ifa_netmask == NULL) 4136e91bba0SGirish Moodalbail goto fail; 41464639aafSDarren Reed (void) memcpy(cifaddr->ifa_netmask, ifap->ifa_netmask, 41564639aafSDarren Reed sizeof (struct sockaddr_storage)); 4166e91bba0SGirish Moodalbail if (ifap->ifa_flags & IFF_POINTOPOINT) { 4176e91bba0SGirish Moodalbail cifaddr->ifa_dstaddr = malloc( 4186e91bba0SGirish Moodalbail sizeof (struct sockaddr_storage)); 4196e91bba0SGirish Moodalbail if (cifaddr->ifa_dstaddr == NULL) 4206e91bba0SGirish Moodalbail goto fail; 42164639aafSDarren Reed (void) memcpy(cifaddr->ifa_dstaddr, ifap->ifa_dstaddr, 42264639aafSDarren Reed sizeof (struct sockaddr_storage)); 4236e91bba0SGirish Moodalbail } else if (ifap->ifa_flags & IFF_BROADCAST) { 4246e91bba0SGirish Moodalbail cifaddr->ifa_broadaddr = malloc( 4256e91bba0SGirish Moodalbail sizeof (struct sockaddr_storage)); 4266e91bba0SGirish Moodalbail if (cifaddr->ifa_broadaddr == NULL) 4276e91bba0SGirish Moodalbail goto fail; 42864639aafSDarren Reed (void) memcpy(cifaddr->ifa_broadaddr, 42964639aafSDarren Reed ifap->ifa_broadaddr, 43064639aafSDarren Reed sizeof (struct sockaddr_storage)); 4316e91bba0SGirish Moodalbail } 4326e91bba0SGirish Moodalbail /* Get the addrobj name stored for this logical interface. */ 4336e91bba0SGirish Moodalbail ipaddr.ipadm_aobjname[0] = '\0'; 4346e91bba0SGirish Moodalbail (void) strlcpy(ipaddr.ipadm_ifname, cifname, 4356e91bba0SGirish Moodalbail sizeof (ipaddr.ipadm_ifname)); 4366e91bba0SGirish Moodalbail ipaddr.ipadm_lifnum = lnum; 43764639aafSDarren Reed ipaddr.ipadm_af = ifap->ifa_addr->sa_family; 4386e91bba0SGirish Moodalbail status = i_ipadm_get_lif2addrobj(iph, &ipaddr); 4396e91bba0SGirish Moodalbail 4406e91bba0SGirish Moodalbail /* 4416e91bba0SGirish Moodalbail * Find address type from ifa_flags, if we could not get it 4426e91bba0SGirish Moodalbail * from daemon. 4436e91bba0SGirish Moodalbail */ 44464639aafSDarren Reed (void) memcpy(&data, ifap->ifa_addr, 44564639aafSDarren Reed sizeof (struct sockaddr_in6)); 44664639aafSDarren Reed sin6 = SIN6(&data); 4476e91bba0SGirish Moodalbail flags = ifap->ifa_flags; 4486e91bba0SGirish Moodalbail if (status == IPADM_SUCCESS) { 4496e91bba0SGirish Moodalbail (void) strlcpy(curr->ia_aobjname, ipaddr.ipadm_aobjname, 4506e91bba0SGirish Moodalbail sizeof (curr->ia_aobjname)); 4516e91bba0SGirish Moodalbail curr->ia_atype = ipaddr.ipadm_atype; 4526e91bba0SGirish Moodalbail } else if ((flags & IFF_DHCPRUNNING) && (!(flags & IFF_IPV6) || 4536e91bba0SGirish Moodalbail !IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))) { 4546e91bba0SGirish Moodalbail curr->ia_atype = IPADM_ADDR_DHCP; 4556e91bba0SGirish Moodalbail } else if (flags & IFF_ADDRCONF) { 4566e91bba0SGirish Moodalbail curr->ia_atype = IPADM_ADDR_IPV6_ADDRCONF; 4576e91bba0SGirish Moodalbail } else { 4586e91bba0SGirish Moodalbail curr->ia_atype = IPADM_ADDR_STATIC; 4596e91bba0SGirish Moodalbail } 4606e91bba0SGirish Moodalbail /* 4616e91bba0SGirish Moodalbail * Populate the flags for the active configuration from the 4626e91bba0SGirish Moodalbail * `ifa_flags'. 4636e91bba0SGirish Moodalbail */ 4646e91bba0SGirish Moodalbail if (!(flags & IFF_UP)) { 4656e91bba0SGirish Moodalbail if (flags & IFF_DUPLICATE) 4666e91bba0SGirish Moodalbail curr->ia_state = IFA_DUPLICATE; 4676e91bba0SGirish Moodalbail else 4686e91bba0SGirish Moodalbail curr->ia_state = IFA_DOWN; 4696e91bba0SGirish Moodalbail } else { 4706e91bba0SGirish Moodalbail curr->ia_cflags |= IA_UP; 4716e91bba0SGirish Moodalbail if (flags & IFF_RUNNING) { 4726e91bba0SGirish Moodalbail (void) strlcpy(lifr.lifr_name, ifap->ifa_name, 4736e91bba0SGirish Moodalbail sizeof (lifr.lifr_name)); 47464639aafSDarren Reed sock = (ifap->ifa_addr->sa_family == AF_INET) ? 4756e91bba0SGirish Moodalbail iph->iph_sock : iph->iph_sock6; 4766e91bba0SGirish Moodalbail if (ioctl(sock, SIOCGLIFDADSTATE, 4776e91bba0SGirish Moodalbail (caddr_t)&lifr) < 0) { 4786e91bba0SGirish Moodalbail if (errno == ENXIO) { 4796e91bba0SGirish Moodalbail freeifaddrs(ifa); 4806e91bba0SGirish Moodalbail ipadm_free_addr_info(*addrinfo); 4816e91bba0SGirish Moodalbail goto retry; 4826e91bba0SGirish Moodalbail } 4836e91bba0SGirish Moodalbail goto fail; 4846e91bba0SGirish Moodalbail } 4856e91bba0SGirish Moodalbail if (lifr.lifr_dadstate == DAD_IN_PROGRESS) 4866e91bba0SGirish Moodalbail curr->ia_state = IFA_TENTATIVE; 4876e91bba0SGirish Moodalbail else 4886e91bba0SGirish Moodalbail curr->ia_state = IFA_OK; 4896e91bba0SGirish Moodalbail } else { 4906e91bba0SGirish Moodalbail curr->ia_state = IFA_INACCESSIBLE; 4916e91bba0SGirish Moodalbail } 4926e91bba0SGirish Moodalbail } 4936e91bba0SGirish Moodalbail if (flags & IFF_UNNUMBERED) 4946e91bba0SGirish Moodalbail curr->ia_cflags |= IA_UNNUMBERED; 4956e91bba0SGirish Moodalbail if (flags & IFF_PRIVATE) 4966e91bba0SGirish Moodalbail curr->ia_cflags |= IA_PRIVATE; 4976e91bba0SGirish Moodalbail if (flags & IFF_TEMPORARY) 4986e91bba0SGirish Moodalbail curr->ia_cflags |= IA_TEMPORARY; 4996e91bba0SGirish Moodalbail if (flags & IFF_DEPRECATED) 5006e91bba0SGirish Moodalbail curr->ia_cflags |= IA_DEPRECATED; 5016e91bba0SGirish Moodalbail 5026e91bba0SGirish Moodalbail } 5036e91bba0SGirish Moodalbail 5046e91bba0SGirish Moodalbail freeifaddrs(ifa); 5056e91bba0SGirish Moodalbail return (IPADM_SUCCESS); 5066e91bba0SGirish Moodalbail 5076e91bba0SGirish Moodalbail fail: 5086e91bba0SGirish Moodalbail /* On error, cleanup everything and return. */ 5096e91bba0SGirish Moodalbail ipadm_free_addr_info(*addrinfo); 5106e91bba0SGirish Moodalbail *addrinfo = NULL; 5116e91bba0SGirish Moodalbail freeifaddrs(ifa); 5126e91bba0SGirish Moodalbail return (ipadm_errno2status(errno)); 5136e91bba0SGirish Moodalbail } 5146e91bba0SGirish Moodalbail 5156e91bba0SGirish Moodalbail /* 5166e91bba0SGirish Moodalbail * From the given `name', i_ipadm_name2atype() deduces the address type 5176e91bba0SGirish Moodalbail * and address family. If the `name' implies an address, it returns B_TRUE. 5186e91bba0SGirish Moodalbail * Else, returns B_FALSE and leaves the output parameters unchanged. 5196e91bba0SGirish Moodalbail */ 5206e91bba0SGirish Moodalbail boolean_t 5216e91bba0SGirish Moodalbail i_ipadm_name2atype(const char *name, sa_family_t *af, ipadm_addr_type_t *type) 5226e91bba0SGirish Moodalbail { 5236e91bba0SGirish Moodalbail boolean_t is_addr = B_TRUE; 5246e91bba0SGirish Moodalbail 5256e91bba0SGirish Moodalbail if (strcmp(name, IPADM_NVP_IPV4ADDR) == 0) { 5266e91bba0SGirish Moodalbail *af = AF_INET; 5276e91bba0SGirish Moodalbail *type = IPADM_ADDR_STATIC; 5286e91bba0SGirish Moodalbail } else if (strcmp(name, IPADM_NVP_IPV6ADDR) == 0) { 5296e91bba0SGirish Moodalbail *af = AF_INET6; 5306e91bba0SGirish Moodalbail *type = IPADM_ADDR_STATIC; 5316e91bba0SGirish Moodalbail } else if (strcmp(name, IPADM_NVP_DHCP) == 0) { 5326e91bba0SGirish Moodalbail *af = AF_INET; 5336e91bba0SGirish Moodalbail *type = IPADM_ADDR_DHCP; 5346e91bba0SGirish Moodalbail } else if (strcmp(name, IPADM_NVP_INTFID) == 0) { 5356e91bba0SGirish Moodalbail *af = AF_INET6; 5366e91bba0SGirish Moodalbail *type = IPADM_ADDR_IPV6_ADDRCONF; 5376e91bba0SGirish Moodalbail } else { 5386e91bba0SGirish Moodalbail is_addr = B_FALSE; 5396e91bba0SGirish Moodalbail } 5406e91bba0SGirish Moodalbail 5416e91bba0SGirish Moodalbail return (is_addr); 5426e91bba0SGirish Moodalbail } 5436e91bba0SGirish Moodalbail 5446e91bba0SGirish Moodalbail /* 5456e91bba0SGirish Moodalbail * Parses the given nvlist `nvl' for an address or an address property. 5466e91bba0SGirish Moodalbail * The input nvlist must contain either an address or an address property. 5476e91bba0SGirish Moodalbail * `ainfo' is an input as well as output parameter. When an address or an 5486e91bba0SGirish Moodalbail * address property is found, `ainfo' is updated with the information found. 5496e91bba0SGirish Moodalbail * Some of the fields may be already filled in by the calling function. 5506e91bba0SGirish Moodalbail * 5516e91bba0SGirish Moodalbail * The fields that will be filled/updated by this function are `ia_pflags', 5526e91bba0SGirish Moodalbail * `ia_sname' and `ia_dname'. Values for `ia_pflags' are obtained if the `nvl' 5536e91bba0SGirish Moodalbail * contains an address property. `ia_sname', `ia_dname', and `ia_pflags' are 5546e91bba0SGirish Moodalbail * obtained if `nvl' contains an address. 5556e91bba0SGirish Moodalbail */ 5566e91bba0SGirish Moodalbail static ipadm_status_t 5576e91bba0SGirish Moodalbail i_ipadm_nvl2ainfo_common(nvlist_t *nvl, ipadm_addr_info_t *ainfo) 5586e91bba0SGirish Moodalbail { 5596e91bba0SGirish Moodalbail nvlist_t *nvladdr; 5606e91bba0SGirish Moodalbail char *name; 5616e91bba0SGirish Moodalbail char *propstr = NULL; 5626e91bba0SGirish Moodalbail char *sname, *dname; 5636e91bba0SGirish Moodalbail nvpair_t *nvp; 5646e91bba0SGirish Moodalbail sa_family_t af; 5656e91bba0SGirish Moodalbail ipadm_addr_type_t atype; 5666e91bba0SGirish Moodalbail boolean_t is_addr = B_FALSE; 5676e91bba0SGirish Moodalbail int err; 5686e91bba0SGirish Moodalbail 5696e91bba0SGirish Moodalbail for (nvp = nvlist_next_nvpair(nvl, NULL); nvp != NULL; 5706e91bba0SGirish Moodalbail nvp = nvlist_next_nvpair(nvl, nvp)) { 5716e91bba0SGirish Moodalbail name = nvpair_name(nvp); 5726e91bba0SGirish Moodalbail if (i_ipadm_name2atype(name, &af, &atype)) { 5736e91bba0SGirish Moodalbail err = nvpair_value_nvlist(nvp, &nvladdr); 5746e91bba0SGirish Moodalbail is_addr = B_TRUE; 5756e91bba0SGirish Moodalbail } else if (IPADM_PRIV_NVP(name)) { 5766e91bba0SGirish Moodalbail continue; 5776e91bba0SGirish Moodalbail } else { 5786e91bba0SGirish Moodalbail err = nvpair_value_string(nvp, &propstr); 5796e91bba0SGirish Moodalbail } 5806e91bba0SGirish Moodalbail if (err != 0) 5816e91bba0SGirish Moodalbail return (ipadm_errno2status(err)); 5826e91bba0SGirish Moodalbail } 5836e91bba0SGirish Moodalbail 5846e91bba0SGirish Moodalbail if (is_addr) { 5856e91bba0SGirish Moodalbail /* 5866e91bba0SGirish Moodalbail * We got an address from the nvlist `nvl'. 5876e91bba0SGirish Moodalbail * Parse `nvladdr' and populate relevant information 5886e91bba0SGirish Moodalbail * in `ainfo'. 5896e91bba0SGirish Moodalbail */ 5906e91bba0SGirish Moodalbail switch (atype) { 5916e91bba0SGirish Moodalbail case IPADM_ADDR_STATIC: 5926e91bba0SGirish Moodalbail if (strcmp(name, "up") == 0 && 5936e91bba0SGirish Moodalbail strcmp(propstr, "yes") == 0) { 5946e91bba0SGirish Moodalbail ainfo->ia_pflags |= IA_UP; 5956e91bba0SGirish Moodalbail } 5966e91bba0SGirish Moodalbail /* 5976e91bba0SGirish Moodalbail * For static addresses, we need to get the hostnames. 5986e91bba0SGirish Moodalbail */ 5996e91bba0SGirish Moodalbail err = nvlist_lookup_string(nvladdr, 6006e91bba0SGirish Moodalbail IPADM_NVP_IPADDRHNAME, &sname); 6016e91bba0SGirish Moodalbail if (err != 0) 6026e91bba0SGirish Moodalbail return (ipadm_errno2status(err)); 6036e91bba0SGirish Moodalbail (void) strlcpy(ainfo->ia_sname, sname, 6046e91bba0SGirish Moodalbail sizeof (ainfo->ia_sname)); 6056e91bba0SGirish Moodalbail err = nvlist_lookup_string(nvladdr, 6066e91bba0SGirish Moodalbail IPADM_NVP_IPDADDRHNAME, &dname); 6076e91bba0SGirish Moodalbail if (err == 0) { 6086e91bba0SGirish Moodalbail (void) strlcpy(ainfo->ia_dname, dname, 6096e91bba0SGirish Moodalbail sizeof (ainfo->ia_dname)); 6106e91bba0SGirish Moodalbail } 6116e91bba0SGirish Moodalbail break; 6126e91bba0SGirish Moodalbail case IPADM_ADDR_DHCP: 6136e91bba0SGirish Moodalbail case IPADM_ADDR_IPV6_ADDRCONF: 6146e91bba0SGirish Moodalbail /* 6156e91bba0SGirish Moodalbail * dhcp and addrconf address objects are always 6166e91bba0SGirish Moodalbail * marked up when re-enabled. 6176e91bba0SGirish Moodalbail */ 6186e91bba0SGirish Moodalbail ainfo->ia_pflags |= IA_UP; 6196e91bba0SGirish Moodalbail break; 6206e91bba0SGirish Moodalbail default: 6216e91bba0SGirish Moodalbail return (IPADM_FAILURE); 6226e91bba0SGirish Moodalbail } 6236e91bba0SGirish Moodalbail } else { 6246e91bba0SGirish Moodalbail /* 6256e91bba0SGirish Moodalbail * We got an address property from `nvl'. Parse the 6266e91bba0SGirish Moodalbail * name and the property value. Update the `ainfo->ia_pflags' 6276e91bba0SGirish Moodalbail * for the flags. 6286e91bba0SGirish Moodalbail */ 6296e91bba0SGirish Moodalbail if (strcmp(name, "deprecated") == 0) { 6306e91bba0SGirish Moodalbail if (strcmp(propstr, IPADM_ONSTR) == 0) 6316e91bba0SGirish Moodalbail ainfo->ia_pflags |= IA_DEPRECATED; 6326e91bba0SGirish Moodalbail } else if (strcmp(name, "private") == 0) { 6336e91bba0SGirish Moodalbail if (strcmp(propstr, IPADM_ONSTR) == 0) 6346e91bba0SGirish Moodalbail ainfo->ia_pflags |= IA_PRIVATE; 6356e91bba0SGirish Moodalbail } 6366e91bba0SGirish Moodalbail } 6376e91bba0SGirish Moodalbail 6386e91bba0SGirish Moodalbail return (IPADM_SUCCESS); 6396e91bba0SGirish Moodalbail } 6406e91bba0SGirish Moodalbail 6416e91bba0SGirish Moodalbail /* 6426e91bba0SGirish Moodalbail * Parses the given nvlist `nvl' for an address or an address property. 6436e91bba0SGirish Moodalbail * The input nvlist must contain either an address or an address property. 6446e91bba0SGirish Moodalbail * `ainfo' is an input as well as output parameter. When an address or an 6456e91bba0SGirish Moodalbail * address property is found, `ainfo' is updated with the information found. 6466e91bba0SGirish Moodalbail * Some of the fields may be already filled in by the calling function, 6476e91bba0SGirish Moodalbail * because of previous calls to i_ipadm_nvl2ainfo_active(). 6486e91bba0SGirish Moodalbail * 6496e91bba0SGirish Moodalbail * Since the address object in `nvl' is also in the active configuration, the 6506e91bba0SGirish Moodalbail * fields that will be filled/updated by this function are `ia_pflags', 6516e91bba0SGirish Moodalbail * `ia_sname' and `ia_dname'. 6526e91bba0SGirish Moodalbail * 6536e91bba0SGirish Moodalbail * If this function returns an error, the calling function will take 6546e91bba0SGirish Moodalbail * care of freeing the fields in `ainfo'. 6556e91bba0SGirish Moodalbail */ 6566e91bba0SGirish Moodalbail static ipadm_status_t 6576e91bba0SGirish Moodalbail i_ipadm_nvl2ainfo_active(nvlist_t *nvl, ipadm_addr_info_t *ainfo) 6586e91bba0SGirish Moodalbail { 6596e91bba0SGirish Moodalbail return (i_ipadm_nvl2ainfo_common(nvl, ainfo)); 6606e91bba0SGirish Moodalbail } 6616e91bba0SGirish Moodalbail 6626e91bba0SGirish Moodalbail /* 6636e91bba0SGirish Moodalbail * Parses the given nvlist `nvl' for an address or an address property. 6646e91bba0SGirish Moodalbail * The input nvlist must contain either an address or an address property. 6656e91bba0SGirish Moodalbail * `ainfo' is an input as well as output parameter. When an address or an 6666e91bba0SGirish Moodalbail * address property is found, `ainfo' is updated with the information found. 6676e91bba0SGirish Moodalbail * Some of the fields may be already filled in by the calling function, 6686e91bba0SGirish Moodalbail * because of previous calls to i_ipadm_nvl2ainfo_persist(). 6696e91bba0SGirish Moodalbail * 6706e91bba0SGirish Moodalbail * All the relevant fields in `ainfo' will be filled by this function based 6716e91bba0SGirish Moodalbail * on what we find in `nvl'. 6726e91bba0SGirish Moodalbail * 6736e91bba0SGirish Moodalbail * If this function returns an error, the calling function will take 6746e91bba0SGirish Moodalbail * care of freeing the fields in `ainfo'. 6756e91bba0SGirish Moodalbail */ 6766e91bba0SGirish Moodalbail static ipadm_status_t 6776e91bba0SGirish Moodalbail i_ipadm_nvl2ainfo_persist(nvlist_t *nvl, ipadm_addr_info_t *ainfo) 6786e91bba0SGirish Moodalbail { 6796e91bba0SGirish Moodalbail nvlist_t *nvladdr; 6806e91bba0SGirish Moodalbail struct ifaddrs *ifa; 6816e91bba0SGirish Moodalbail char *name; 6826e91bba0SGirish Moodalbail char *ifname = NULL; 6836e91bba0SGirish Moodalbail char *aobjname = NULL; 6846e91bba0SGirish Moodalbail char *propstr = NULL; 6856e91bba0SGirish Moodalbail nvpair_t *nvp; 6866e91bba0SGirish Moodalbail sa_family_t af; 6876e91bba0SGirish Moodalbail ipadm_addr_type_t atype; 6886e91bba0SGirish Moodalbail boolean_t is_addr = B_FALSE; 6896e91bba0SGirish Moodalbail size_t size = sizeof (struct sockaddr_storage); 6906e91bba0SGirish Moodalbail uint32_t plen = 0; 6916e91bba0SGirish Moodalbail int err; 6926e91bba0SGirish Moodalbail ipadm_status_t status; 6936e91bba0SGirish Moodalbail 6946e91bba0SGirish Moodalbail status = i_ipadm_nvl2ainfo_common(nvl, ainfo); 6956e91bba0SGirish Moodalbail if (status != IPADM_SUCCESS) 6966e91bba0SGirish Moodalbail return (status); 6976e91bba0SGirish Moodalbail 6986e91bba0SGirish Moodalbail for (nvp = nvlist_next_nvpair(nvl, NULL); nvp != NULL; 6996e91bba0SGirish Moodalbail nvp = nvlist_next_nvpair(nvl, nvp)) { 7006e91bba0SGirish Moodalbail name = nvpair_name(nvp); 7016e91bba0SGirish Moodalbail if (strcmp(name, IPADM_NVP_IFNAME) == 0) { 7026e91bba0SGirish Moodalbail err = nvpair_value_string(nvp, &ifname); 7036e91bba0SGirish Moodalbail } else if (strcmp(name, IPADM_NVP_AOBJNAME) == 0) { 7046e91bba0SGirish Moodalbail err = nvpair_value_string(nvp, &aobjname); 7056e91bba0SGirish Moodalbail } else if (i_ipadm_name2atype(name, &af, &atype)) { 7066e91bba0SGirish Moodalbail err = nvpair_value_nvlist(nvp, &nvladdr); 7076e91bba0SGirish Moodalbail is_addr = B_TRUE; 7086e91bba0SGirish Moodalbail } else { 7096e91bba0SGirish Moodalbail err = nvpair_value_string(nvp, &propstr); 7106e91bba0SGirish Moodalbail } 7116e91bba0SGirish Moodalbail if (err != 0) 7126e91bba0SGirish Moodalbail return (ipadm_errno2status(err)); 7136e91bba0SGirish Moodalbail } 7146e91bba0SGirish Moodalbail 7156e91bba0SGirish Moodalbail ifa = &ainfo->ia_ifa; 7166e91bba0SGirish Moodalbail (void) strlcpy(ainfo->ia_aobjname, aobjname, 7176e91bba0SGirish Moodalbail sizeof (ainfo->ia_aobjname)); 7186e91bba0SGirish Moodalbail if (ifa->ifa_name == NULL && (ifa->ifa_name = strdup(ifname)) == NULL) 7196e91bba0SGirish Moodalbail return (IPADM_NO_MEMORY); 7206e91bba0SGirish Moodalbail if (is_addr) { 72164639aafSDarren Reed struct sockaddr_in6 data; 72264639aafSDarren Reed 7236e91bba0SGirish Moodalbail /* 7246e91bba0SGirish Moodalbail * We got an address from the nvlist `nvl'. 7256e91bba0SGirish Moodalbail * Parse `nvladdr' and populate `ifa->ifa_addr'. 7266e91bba0SGirish Moodalbail */ 7276e91bba0SGirish Moodalbail ainfo->ia_atype = atype; 7286e91bba0SGirish Moodalbail if ((ifa->ifa_addr = calloc(1, size)) == NULL) 7296e91bba0SGirish Moodalbail return (IPADM_NO_MEMORY); 7306e91bba0SGirish Moodalbail switch (atype) { 7316e91bba0SGirish Moodalbail case IPADM_ADDR_STATIC: 73264639aafSDarren Reed ifa->ifa_addr->sa_family = af; 7336e91bba0SGirish Moodalbail break; 7346e91bba0SGirish Moodalbail case IPADM_ADDR_DHCP: 73564639aafSDarren Reed ifa->ifa_addr->sa_family = AF_INET; 7366e91bba0SGirish Moodalbail break; 7376e91bba0SGirish Moodalbail case IPADM_ADDR_IPV6_ADDRCONF: 73864639aafSDarren Reed data.sin6_family = AF_INET6; 7396e91bba0SGirish Moodalbail if (i_ipadm_nvl2in6_addr(nvladdr, IPADM_NVP_IPNUMADDR, 74064639aafSDarren Reed &data.sin6_addr) != IPADM_SUCCESS) 7416e91bba0SGirish Moodalbail return (IPADM_NO_MEMORY); 7426e91bba0SGirish Moodalbail err = nvlist_lookup_uint32(nvladdr, IPADM_NVP_PREFIXLEN, 7436e91bba0SGirish Moodalbail &plen); 7446e91bba0SGirish Moodalbail if (err != 0) 7456e91bba0SGirish Moodalbail return (ipadm_errno2status(err)); 7466e91bba0SGirish Moodalbail if ((ifa->ifa_netmask = malloc(size)) == NULL) 7476e91bba0SGirish Moodalbail return (IPADM_NO_MEMORY); 7486e91bba0SGirish Moodalbail if ((err = plen2mask(plen, af, ifa->ifa_netmask)) != 0) 7496e91bba0SGirish Moodalbail return (ipadm_errno2status(err)); 75064639aafSDarren Reed (void) memcpy(ifa->ifa_addr, &data, sizeof (data)); 7516e91bba0SGirish Moodalbail break; 7526e91bba0SGirish Moodalbail default: 7536e91bba0SGirish Moodalbail return (IPADM_FAILURE); 7546e91bba0SGirish Moodalbail } 7556e91bba0SGirish Moodalbail } else { 7566e91bba0SGirish Moodalbail if (strcmp(name, "prefixlen") == 0) { 7576e91bba0SGirish Moodalbail /* 7586e91bba0SGirish Moodalbail * If a prefixlen was found, update the 7596e91bba0SGirish Moodalbail * `ainfo->ia_ifa.ifa_netmask'. 7606e91bba0SGirish Moodalbail */ 7616e91bba0SGirish Moodalbail 7626e91bba0SGirish Moodalbail if ((ifa->ifa_netmask = malloc(size)) == NULL) 7636e91bba0SGirish Moodalbail return (IPADM_NO_MEMORY); 7646e91bba0SGirish Moodalbail /* 7656e91bba0SGirish Moodalbail * Address property lines always follow the address 7666e91bba0SGirish Moodalbail * line itself in the persistent db. We must have 7676e91bba0SGirish Moodalbail * found a valid `ainfo->ia_ifa.ifa_addr' by now. 7686e91bba0SGirish Moodalbail */ 7696e91bba0SGirish Moodalbail assert(ifa->ifa_addr != NULL); 77064639aafSDarren Reed err = plen2mask(atoi(propstr), ifa->ifa_addr->sa_family, 7716e91bba0SGirish Moodalbail ifa->ifa_netmask); 7726e91bba0SGirish Moodalbail if (err != 0) 7736e91bba0SGirish Moodalbail return (ipadm_errno2status(err)); 7746e91bba0SGirish Moodalbail } 7756e91bba0SGirish Moodalbail } 7766e91bba0SGirish Moodalbail 7776e91bba0SGirish Moodalbail return (IPADM_SUCCESS); 7786e91bba0SGirish Moodalbail } 7796e91bba0SGirish Moodalbail 7806e91bba0SGirish Moodalbail /* 7816e91bba0SGirish Moodalbail * Retrieves all addresses from active config and appends to it the 7826e91bba0SGirish Moodalbail * addresses that are found only in persistent config. In addition, 7836e91bba0SGirish Moodalbail * it updates the persistent fields for each address from information 7846e91bba0SGirish Moodalbail * found in persistent config. The output parameter `addrinfo' contains 7856e91bba0SGirish Moodalbail * complete information regarding all addresses in active as well as 7866e91bba0SGirish Moodalbail * persistent config. 7876e91bba0SGirish Moodalbail */ 7886e91bba0SGirish Moodalbail static ipadm_status_t 7896e91bba0SGirish Moodalbail i_ipadm_get_all_addr_info(ipadm_handle_t iph, const char *ifname, 7906e91bba0SGirish Moodalbail ipadm_addr_info_t **addrinfo, uint32_t ipadm_flags, int64_t lifc_flags) 7916e91bba0SGirish Moodalbail { 7926e91bba0SGirish Moodalbail nvlist_t *nvladdr = NULL; 7936e91bba0SGirish Moodalbail nvlist_t *onvl = NULL; 7946e91bba0SGirish Moodalbail nvpair_t *nvp; 7956e91bba0SGirish Moodalbail ipadm_status_t status; 7966e91bba0SGirish Moodalbail ipadm_addr_info_t *ainfo = NULL; 7976e91bba0SGirish Moodalbail ipadm_addr_info_t *curr; 7986e91bba0SGirish Moodalbail ipadm_addr_info_t *last = NULL; 7996e91bba0SGirish Moodalbail char *aobjname; 8006e91bba0SGirish Moodalbail 8016e91bba0SGirish Moodalbail /* Get all addresses from active config. */ 8026e91bba0SGirish Moodalbail status = i_ipadm_active_addr_info(iph, ifname, &ainfo, ipadm_flags, 8036e91bba0SGirish Moodalbail lifc_flags); 8046e91bba0SGirish Moodalbail if (status != IPADM_SUCCESS) 8056e91bba0SGirish Moodalbail goto fail; 8066e91bba0SGirish Moodalbail 8076e91bba0SGirish Moodalbail /* Get all addresses from persistent config. */ 8086e91bba0SGirish Moodalbail status = i_ipadm_get_db_addr(iph, ifname, NULL, &onvl); 8096e91bba0SGirish Moodalbail /* 8106e91bba0SGirish Moodalbail * If no address was found in persistent config, just 8116e91bba0SGirish Moodalbail * return what we found in active config. 8126e91bba0SGirish Moodalbail */ 8136e91bba0SGirish Moodalbail if (status == IPADM_NOTFOUND) { 8146e91bba0SGirish Moodalbail /* 8156e91bba0SGirish Moodalbail * If nothing was found neither active nor persistent 8166e91bba0SGirish Moodalbail * config, this means that the interface does not exist, 8176e91bba0SGirish Moodalbail * if one was provided in `ifname'. 8186e91bba0SGirish Moodalbail */ 8196e91bba0SGirish Moodalbail if (ainfo == NULL && ifname != NULL) 8206e91bba0SGirish Moodalbail return (IPADM_ENXIO); 8216e91bba0SGirish Moodalbail *addrinfo = ainfo; 8226e91bba0SGirish Moodalbail return (IPADM_SUCCESS); 8236e91bba0SGirish Moodalbail } 8246e91bba0SGirish Moodalbail /* In case of any other error, cleanup and return. */ 8256e91bba0SGirish Moodalbail if (status != IPADM_SUCCESS) 8266e91bba0SGirish Moodalbail goto fail; 8276e91bba0SGirish Moodalbail /* we append to make sure, loopback addresses are first */ 8286e91bba0SGirish Moodalbail if (ainfo != NULL) { 8296e91bba0SGirish Moodalbail for (curr = ainfo; IA_NEXT(curr) != NULL; curr = IA_NEXT(curr)) 8306e91bba0SGirish Moodalbail ; 8316e91bba0SGirish Moodalbail last = curr; 8326e91bba0SGirish Moodalbail } 8336e91bba0SGirish Moodalbail 8346e91bba0SGirish Moodalbail /* 8356e91bba0SGirish Moodalbail * `onvl' will contain all the address lines from the db. Each line 8366e91bba0SGirish Moodalbail * could contain the address itself or an address property. Addresses 8376e91bba0SGirish Moodalbail * and address properties are found in separate lines. 8386e91bba0SGirish Moodalbail * 8396e91bba0SGirish Moodalbail * If an address A was found in active, we will already have `ainfo', 8406e91bba0SGirish Moodalbail * and it is present in persistent configuration as well, we need to 8416e91bba0SGirish Moodalbail * update `ainfo' with persistent information (`ia_pflags). 8426e91bba0SGirish Moodalbail * For each address B found only in persistent configuration, 8436e91bba0SGirish Moodalbail * append the address to the list with the address info for B from 8446e91bba0SGirish Moodalbail * `onvl'. 8456e91bba0SGirish Moodalbail */ 8466e91bba0SGirish Moodalbail for (nvp = nvlist_next_nvpair(onvl, NULL); nvp != NULL; 8476e91bba0SGirish Moodalbail nvp = nvlist_next_nvpair(onvl, nvp)) { 8486e91bba0SGirish Moodalbail if (nvpair_value_nvlist(nvp, &nvladdr) != 0) 8496e91bba0SGirish Moodalbail continue; 8506e91bba0SGirish Moodalbail if (nvlist_lookup_string(nvladdr, IPADM_NVP_AOBJNAME, 8516e91bba0SGirish Moodalbail &aobjname) != 0) 8526e91bba0SGirish Moodalbail continue; 8536e91bba0SGirish Moodalbail for (curr = ainfo; curr != NULL; curr = IA_NEXT(curr)) { 8546e91bba0SGirish Moodalbail if (strcmp(curr->ia_aobjname, aobjname) == 0) 8556e91bba0SGirish Moodalbail break; 8566e91bba0SGirish Moodalbail } 8576e91bba0SGirish Moodalbail if (curr == NULL) { 8586e91bba0SGirish Moodalbail /* 8596e91bba0SGirish Moodalbail * We did not find this address object in `ainfo'. 8606e91bba0SGirish Moodalbail * This means that the address object exists only 8616e91bba0SGirish Moodalbail * in the persistent configuration. Get its 8626e91bba0SGirish Moodalbail * details and append to `ainfo'. 8636e91bba0SGirish Moodalbail */ 8646e91bba0SGirish Moodalbail curr = calloc(1, sizeof (ipadm_addr_info_t)); 8656e91bba0SGirish Moodalbail if (curr == NULL) 8666e91bba0SGirish Moodalbail goto fail; 8676e91bba0SGirish Moodalbail curr->ia_state = IFA_DISABLED; 8686e91bba0SGirish Moodalbail if (last != NULL) 8696e91bba0SGirish Moodalbail last->ia_ifa.ifa_next = &curr->ia_ifa; 8706e91bba0SGirish Moodalbail else 8716e91bba0SGirish Moodalbail ainfo = curr; 8726e91bba0SGirish Moodalbail last = curr; 8736e91bba0SGirish Moodalbail } 8746e91bba0SGirish Moodalbail /* 8756e91bba0SGirish Moodalbail * Fill relevant fields of `curr' from the persistent info 8766e91bba0SGirish Moodalbail * in `nvladdr'. Call the appropriate function based on the 8776e91bba0SGirish Moodalbail * `ia_state' value. 8786e91bba0SGirish Moodalbail */ 8796e91bba0SGirish Moodalbail if (curr->ia_state == IFA_DISABLED) 8806e91bba0SGirish Moodalbail status = i_ipadm_nvl2ainfo_persist(nvladdr, curr); 8816e91bba0SGirish Moodalbail else 8826e91bba0SGirish Moodalbail status = i_ipadm_nvl2ainfo_active(nvladdr, curr); 8836e91bba0SGirish Moodalbail if (status != IPADM_SUCCESS) 8846e91bba0SGirish Moodalbail goto fail; 8856e91bba0SGirish Moodalbail } 8866e91bba0SGirish Moodalbail *addrinfo = ainfo; 8876e91bba0SGirish Moodalbail nvlist_free(onvl); 8886e91bba0SGirish Moodalbail return (status); 8896e91bba0SGirish Moodalbail fail: 8906e91bba0SGirish Moodalbail /* On error, cleanup and return. */ 8916e91bba0SGirish Moodalbail nvlist_free(onvl); 8926e91bba0SGirish Moodalbail ipadm_free_addr_info(ainfo); 8936e91bba0SGirish Moodalbail *addrinfo = NULL; 8946e91bba0SGirish Moodalbail return (status); 8956e91bba0SGirish Moodalbail } 8966e91bba0SGirish Moodalbail 8976e91bba0SGirish Moodalbail /* 8986e91bba0SGirish Moodalbail * Callback function that sets the property `prefixlen' on the address 8996e91bba0SGirish Moodalbail * object in `arg' to the value in `pval'. 9006e91bba0SGirish Moodalbail */ 9016e91bba0SGirish Moodalbail /* ARGSUSED */ 9026e91bba0SGirish Moodalbail static ipadm_status_t 9036e91bba0SGirish Moodalbail i_ipadm_set_prefixlen(ipadm_handle_t iph, const void *arg, 9046e91bba0SGirish Moodalbail ipadm_prop_desc_t *pdp, const void *pval, uint_t af, uint_t flags) 9056e91bba0SGirish Moodalbail { 9066e91bba0SGirish Moodalbail struct sockaddr_storage netmask; 9076e91bba0SGirish Moodalbail struct lifreq lifr; 9086e91bba0SGirish Moodalbail int err, s; 9096e91bba0SGirish Moodalbail unsigned long prefixlen, abits; 9106e91bba0SGirish Moodalbail char *end; 9116e91bba0SGirish Moodalbail ipadm_addrobj_t ipaddr = (ipadm_addrobj_t)arg; 9126e91bba0SGirish Moodalbail 9136e91bba0SGirish Moodalbail if (ipaddr->ipadm_atype == IPADM_ADDR_DHCP) 9146e91bba0SGirish Moodalbail return (IPADM_NOTSUP); 9156e91bba0SGirish Moodalbail 9166e91bba0SGirish Moodalbail errno = 0; 9176e91bba0SGirish Moodalbail prefixlen = strtoul(pval, &end, 10); 9186e91bba0SGirish Moodalbail if (errno != 0 || *end != '\0') 9196e91bba0SGirish Moodalbail return (IPADM_INVALID_ARG); 9206e91bba0SGirish Moodalbail 9216e91bba0SGirish Moodalbail abits = (af == AF_INET ? IP_ABITS : IPV6_ABITS); 9226e91bba0SGirish Moodalbail if (prefixlen == 0 || prefixlen == (abits - 1)) 9236e91bba0SGirish Moodalbail return (IPADM_INVALID_ARG); 9246e91bba0SGirish Moodalbail 92564639aafSDarren Reed if ((err = plen2mask(prefixlen, af, (struct sockaddr *)&netmask)) != 0) 9266e91bba0SGirish Moodalbail return (ipadm_errno2status(err)); 9276e91bba0SGirish Moodalbail 9286e91bba0SGirish Moodalbail s = (af == AF_INET ? iph->iph_sock : iph->iph_sock6); 9296e91bba0SGirish Moodalbail 9306e91bba0SGirish Moodalbail bzero(&lifr, sizeof (lifr)); 9316e91bba0SGirish Moodalbail i_ipadm_addrobj2lifname(ipaddr, lifr.lifr_name, 9326e91bba0SGirish Moodalbail sizeof (lifr.lifr_name)); 9336e91bba0SGirish Moodalbail (void) memcpy(&lifr.lifr_addr, &netmask, sizeof (netmask)); 9346e91bba0SGirish Moodalbail if (ioctl(s, SIOCSLIFNETMASK, (caddr_t)&lifr) < 0) 9356e91bba0SGirish Moodalbail return (ipadm_errno2status(errno)); 9366e91bba0SGirish Moodalbail 9376e91bba0SGirish Moodalbail /* now, change the broadcast address to reflect the prefixlen */ 9386e91bba0SGirish Moodalbail if (af == AF_INET) { 9396e91bba0SGirish Moodalbail /* 9406e91bba0SGirish Moodalbail * get the interface address and set it, this should reset 9416e91bba0SGirish Moodalbail * the broadcast address. 9426e91bba0SGirish Moodalbail */ 9436e91bba0SGirish Moodalbail (void) ioctl(s, SIOCGLIFADDR, (caddr_t)&lifr); 9446e91bba0SGirish Moodalbail (void) ioctl(s, SIOCSLIFADDR, (caddr_t)&lifr); 9456e91bba0SGirish Moodalbail } 9466e91bba0SGirish Moodalbail 9476e91bba0SGirish Moodalbail return (IPADM_SUCCESS); 9486e91bba0SGirish Moodalbail } 9496e91bba0SGirish Moodalbail 9506e91bba0SGirish Moodalbail 9516e91bba0SGirish Moodalbail /* 9526e91bba0SGirish Moodalbail * Callback function that sets the given value `pval' to one of the 9536e91bba0SGirish Moodalbail * properties among `deprecated', `private', and `transmit' as defined in 9546e91bba0SGirish Moodalbail * `pdp', on the address object in `arg'. 9556e91bba0SGirish Moodalbail */ 9566e91bba0SGirish Moodalbail /* ARGSUSED */ 9576e91bba0SGirish Moodalbail static ipadm_status_t 9586e91bba0SGirish Moodalbail i_ipadm_set_addr_flag(ipadm_handle_t iph, const void *arg, 9596e91bba0SGirish Moodalbail ipadm_prop_desc_t *pdp, const void *pval, uint_t af, uint_t flags) 9606e91bba0SGirish Moodalbail { 9616e91bba0SGirish Moodalbail char lifname[LIFNAMSIZ]; 9626e91bba0SGirish Moodalbail uint64_t on_flags = 0, off_flags = 0; 9636e91bba0SGirish Moodalbail boolean_t on; 9646e91bba0SGirish Moodalbail ipadm_addrobj_t ipaddr = (ipadm_addrobj_t)arg; 9656e91bba0SGirish Moodalbail 9666e91bba0SGirish Moodalbail if (ipaddr->ipadm_atype == IPADM_ADDR_DHCP && 9676e91bba0SGirish Moodalbail strcmp(pdp->ipd_name, "deprecated") == 0) 9686e91bba0SGirish Moodalbail return (IPADM_NOTSUP); 9696e91bba0SGirish Moodalbail 9706e91bba0SGirish Moodalbail if (strcmp(pval, IPADM_ONSTR) == 0) 9716e91bba0SGirish Moodalbail on = B_TRUE; 9726e91bba0SGirish Moodalbail else if (strcmp(pval, IPADM_OFFSTR) == 0) 9736e91bba0SGirish Moodalbail on = B_FALSE; 9746e91bba0SGirish Moodalbail else 9756e91bba0SGirish Moodalbail return (IPADM_INVALID_ARG); 9766e91bba0SGirish Moodalbail 9776e91bba0SGirish Moodalbail if (strcmp(pdp->ipd_name, "private") == 0) { 9786e91bba0SGirish Moodalbail if (on) 9796e91bba0SGirish Moodalbail on_flags = IFF_PRIVATE; 9806e91bba0SGirish Moodalbail else 9816e91bba0SGirish Moodalbail off_flags = IFF_PRIVATE; 9826e91bba0SGirish Moodalbail } else if (strcmp(pdp->ipd_name, "transmit") == 0) { 9836e91bba0SGirish Moodalbail if (on) 9846e91bba0SGirish Moodalbail off_flags = IFF_NOXMIT; 9856e91bba0SGirish Moodalbail else 9866e91bba0SGirish Moodalbail on_flags = IFF_NOXMIT; 9876e91bba0SGirish Moodalbail } else if (strcmp(pdp->ipd_name, "deprecated") == 0) { 9886e91bba0SGirish Moodalbail if (on) 9896e91bba0SGirish Moodalbail on_flags = IFF_DEPRECATED; 9906e91bba0SGirish Moodalbail else 9916e91bba0SGirish Moodalbail off_flags = IFF_DEPRECATED; 9926e91bba0SGirish Moodalbail } else { 9936e91bba0SGirish Moodalbail return (IPADM_PROP_UNKNOWN); 9946e91bba0SGirish Moodalbail } 9956e91bba0SGirish Moodalbail 9966e91bba0SGirish Moodalbail i_ipadm_addrobj2lifname(ipaddr, lifname, sizeof (lifname)); 9976e91bba0SGirish Moodalbail return (i_ipadm_set_flags(iph, lifname, af, on_flags, off_flags)); 9986e91bba0SGirish Moodalbail } 9996e91bba0SGirish Moodalbail 10006e91bba0SGirish Moodalbail /* 10016e91bba0SGirish Moodalbail * Callback function that sets the property `zone' on the address 10026e91bba0SGirish Moodalbail * object in `arg' to the value in `pval'. 10036e91bba0SGirish Moodalbail */ 10046e91bba0SGirish Moodalbail /* ARGSUSED */ 10056e91bba0SGirish Moodalbail static ipadm_status_t 10066e91bba0SGirish Moodalbail i_ipadm_set_zone(ipadm_handle_t iph, const void *arg, 10076e91bba0SGirish Moodalbail ipadm_prop_desc_t *pdp, const void *pval, uint_t af, uint_t flags) 10086e91bba0SGirish Moodalbail { 10096e91bba0SGirish Moodalbail struct lifreq lifr; 10106e91bba0SGirish Moodalbail zoneid_t zoneid; 10116e91bba0SGirish Moodalbail int s; 10126e91bba0SGirish Moodalbail 10136e91bba0SGirish Moodalbail /* 10146e91bba0SGirish Moodalbail * To modify the zone assignment such that it persists across 10156e91bba0SGirish Moodalbail * reboots, zonecfg(1M) must be used. 10166e91bba0SGirish Moodalbail */ 10176e91bba0SGirish Moodalbail if (flags & IPADM_OPT_PERSIST) { 10186e91bba0SGirish Moodalbail return (IPADM_NOTSUP); 10196e91bba0SGirish Moodalbail } else if (flags & IPADM_OPT_ACTIVE) { 10206e91bba0SGirish Moodalbail /* put logical interface into all zones */ 10216e91bba0SGirish Moodalbail if (strcmp(pval, "all-zones") == 0) { 10226e91bba0SGirish Moodalbail zoneid = ALL_ZONES; 10236e91bba0SGirish Moodalbail } else { 10246e91bba0SGirish Moodalbail /* zone must be ready or running */ 10256e91bba0SGirish Moodalbail if ((zoneid = getzoneidbyname(pval)) == -1) 10266e91bba0SGirish Moodalbail return (ipadm_errno2status(errno)); 10276e91bba0SGirish Moodalbail } 10286e91bba0SGirish Moodalbail } else { 10296e91bba0SGirish Moodalbail return (IPADM_INVALID_ARG); 10306e91bba0SGirish Moodalbail } 10316e91bba0SGirish Moodalbail 10326e91bba0SGirish Moodalbail s = (af == AF_INET ? iph->iph_sock : iph->iph_sock6); 10336e91bba0SGirish Moodalbail bzero(&lifr, sizeof (lifr)); 10346e91bba0SGirish Moodalbail i_ipadm_addrobj2lifname((ipadm_addrobj_t)arg, lifr.lifr_name, 10356e91bba0SGirish Moodalbail sizeof (lifr.lifr_name)); 10366e91bba0SGirish Moodalbail lifr.lifr_zoneid = zoneid; 10376e91bba0SGirish Moodalbail if (ioctl(s, SIOCSLIFZONE, (caddr_t)&lifr) < 0) 10386e91bba0SGirish Moodalbail return (ipadm_errno2status(errno)); 10396e91bba0SGirish Moodalbail 10406e91bba0SGirish Moodalbail return (IPADM_SUCCESS); 10416e91bba0SGirish Moodalbail } 10426e91bba0SGirish Moodalbail 10436e91bba0SGirish Moodalbail /* 10446e91bba0SGirish Moodalbail * Callback function that gets the property `broadcast' for the address 10456e91bba0SGirish Moodalbail * object in `arg'. 10466e91bba0SGirish Moodalbail */ 10476e91bba0SGirish Moodalbail /* ARGSUSED */ 10486e91bba0SGirish Moodalbail static ipadm_status_t 10496e91bba0SGirish Moodalbail i_ipadm_get_broadcast(ipadm_handle_t iph, const void *arg, 10506e91bba0SGirish Moodalbail ipadm_prop_desc_t *pdp, char *buf, uint_t *bufsize, uint_t af, 10516e91bba0SGirish Moodalbail uint_t valtype) 10526e91bba0SGirish Moodalbail { 10536e91bba0SGirish Moodalbail struct sockaddr_in *sin; 10546e91bba0SGirish Moodalbail struct lifreq lifr; 10556e91bba0SGirish Moodalbail char lifname[LIFNAMSIZ]; 10566e91bba0SGirish Moodalbail ipadm_addrobj_t ipaddr = (ipadm_addrobj_t)arg; 10576e91bba0SGirish Moodalbail ipadm_status_t status; 10586e91bba0SGirish Moodalbail size_t nbytes = 0; 10596e91bba0SGirish Moodalbail uint64_t ifflags = 0; 10606e91bba0SGirish Moodalbail 10616e91bba0SGirish Moodalbail i_ipadm_addrobj2lifname(ipaddr, lifname, sizeof (lifname)); 10626e91bba0SGirish Moodalbail if (ipaddr->ipadm_flags & IPMGMT_ACTIVE) { 10636e91bba0SGirish Moodalbail status = i_ipadm_get_flags(iph, lifname, af, &ifflags); 10646e91bba0SGirish Moodalbail if (status != IPADM_SUCCESS) 10656e91bba0SGirish Moodalbail return (status); 10666e91bba0SGirish Moodalbail if (!(ifflags & IFF_BROADCAST)) { 10676e91bba0SGirish Moodalbail buf[0] = '\0'; 10686e91bba0SGirish Moodalbail return (IPADM_SUCCESS); 10696e91bba0SGirish Moodalbail } 10706e91bba0SGirish Moodalbail } 10716e91bba0SGirish Moodalbail 10726e91bba0SGirish Moodalbail switch (valtype) { 10736e91bba0SGirish Moodalbail case MOD_PROP_DEFAULT: { 10746e91bba0SGirish Moodalbail struct sockaddr_storage mask; 10756e91bba0SGirish Moodalbail struct in_addr broadaddr; 10766e91bba0SGirish Moodalbail uint_t plen; 10776e91bba0SGirish Moodalbail in_addr_t addr, maddr; 10786e91bba0SGirish Moodalbail char val[MAXPROPVALLEN]; 10796e91bba0SGirish Moodalbail uint_t valsz = MAXPROPVALLEN; 10806e91bba0SGirish Moodalbail ipadm_status_t status; 10816e91bba0SGirish Moodalbail int err; 10826e91bba0SGirish Moodalbail struct sockaddr_in *sin; 10836e91bba0SGirish Moodalbail 10846e91bba0SGirish Moodalbail if (!(ipaddr->ipadm_flags & IPMGMT_ACTIVE)) { 10856e91bba0SGirish Moodalbail /* 10866e91bba0SGirish Moodalbail * Since the address is unknown we cannot 10876e91bba0SGirish Moodalbail * obtain default prefixlen 10886e91bba0SGirish Moodalbail */ 10896e91bba0SGirish Moodalbail if (ipaddr->ipadm_atype == IPADM_ADDR_DHCP || 10906e91bba0SGirish Moodalbail ipaddr->ipadm_af == AF_INET6) { 10916e91bba0SGirish Moodalbail buf[0] = '\0'; 10926e91bba0SGirish Moodalbail return (IPADM_SUCCESS); 10936e91bba0SGirish Moodalbail } 10946e91bba0SGirish Moodalbail /* 10956e91bba0SGirish Moodalbail * For the static address, we get the address from the 10966e91bba0SGirish Moodalbail * persistent db. 10976e91bba0SGirish Moodalbail */ 10986e91bba0SGirish Moodalbail status = i_ipadm_get_static_addr_db(iph, ipaddr); 10996e91bba0SGirish Moodalbail if (status != IPADM_SUCCESS) 11006e91bba0SGirish Moodalbail return (status); 11016e91bba0SGirish Moodalbail sin = SIN(&ipaddr->ipadm_static_addr); 11026e91bba0SGirish Moodalbail addr = sin->sin_addr.s_addr; 11036e91bba0SGirish Moodalbail } else { 11046e91bba0SGirish Moodalbail /* 11056e91bba0SGirish Moodalbail * If the address object is active, we retrieve the 11066e91bba0SGirish Moodalbail * address from kernel. 11076e91bba0SGirish Moodalbail */ 11086e91bba0SGirish Moodalbail bzero(&lifr, sizeof (lifr)); 11096e91bba0SGirish Moodalbail (void) strlcpy(lifr.lifr_name, lifname, 11106e91bba0SGirish Moodalbail sizeof (lifr.lifr_name)); 11116e91bba0SGirish Moodalbail if (ioctl(iph->iph_sock, SIOCGLIFADDR, 11126e91bba0SGirish Moodalbail (caddr_t)&lifr) < 0) 11136e91bba0SGirish Moodalbail return (ipadm_errno2status(errno)); 11146e91bba0SGirish Moodalbail 11156e91bba0SGirish Moodalbail addr = (SIN(&lifr.lifr_addr))->sin_addr.s_addr; 11166e91bba0SGirish Moodalbail } 11176e91bba0SGirish Moodalbail /* 11186e91bba0SGirish Moodalbail * For default broadcast address, get the address and the 11196e91bba0SGirish Moodalbail * default prefixlen for that address and then compute the 11206e91bba0SGirish Moodalbail * broadcast address. 11216e91bba0SGirish Moodalbail */ 11226e91bba0SGirish Moodalbail status = i_ipadm_get_prefixlen(iph, arg, NULL, val, &valsz, af, 11236e91bba0SGirish Moodalbail MOD_PROP_DEFAULT); 11246e91bba0SGirish Moodalbail if (status != IPADM_SUCCESS) 11256e91bba0SGirish Moodalbail return (status); 11266e91bba0SGirish Moodalbail 11276e91bba0SGirish Moodalbail plen = atoi(val); 112864639aafSDarren Reed if ((err = plen2mask(plen, AF_INET, 112964639aafSDarren Reed (struct sockaddr *)&mask)) != 0) 11306e91bba0SGirish Moodalbail return (ipadm_errno2status(err)); 11316e91bba0SGirish Moodalbail maddr = (SIN(&mask))->sin_addr.s_addr; 11326e91bba0SGirish Moodalbail broadaddr.s_addr = (addr & maddr) | ~maddr; 11336e91bba0SGirish Moodalbail nbytes = snprintf(buf, *bufsize, "%s", inet_ntoa(broadaddr)); 11346e91bba0SGirish Moodalbail break; 11356e91bba0SGirish Moodalbail } 11366e91bba0SGirish Moodalbail case MOD_PROP_ACTIVE: 11376e91bba0SGirish Moodalbail bzero(&lifr, sizeof (lifr)); 11386e91bba0SGirish Moodalbail (void) strlcpy(lifr.lifr_name, lifname, 11396e91bba0SGirish Moodalbail sizeof (lifr.lifr_name)); 11406e91bba0SGirish Moodalbail if (ioctl(iph->iph_sock, SIOCGLIFBRDADDR, 11416e91bba0SGirish Moodalbail (caddr_t)&lifr) < 0) { 11426e91bba0SGirish Moodalbail return (ipadm_errno2status(errno)); 11436e91bba0SGirish Moodalbail } else { 11446e91bba0SGirish Moodalbail sin = SIN(&lifr.lifr_addr); 11456e91bba0SGirish Moodalbail nbytes = snprintf(buf, *bufsize, "%s", 11466e91bba0SGirish Moodalbail inet_ntoa(sin->sin_addr)); 11476e91bba0SGirish Moodalbail } 11486e91bba0SGirish Moodalbail break; 11496e91bba0SGirish Moodalbail default: 11506e91bba0SGirish Moodalbail return (IPADM_INVALID_ARG); 11516e91bba0SGirish Moodalbail } 11526e91bba0SGirish Moodalbail if (nbytes >= *bufsize) { 11536e91bba0SGirish Moodalbail /* insufficient buffer space */ 11546e91bba0SGirish Moodalbail *bufsize = nbytes + 1; 11556e91bba0SGirish Moodalbail return (IPADM_NO_BUFS); 11566e91bba0SGirish Moodalbail } 11576e91bba0SGirish Moodalbail return (IPADM_SUCCESS); 11586e91bba0SGirish Moodalbail } 11596e91bba0SGirish Moodalbail 11606e91bba0SGirish Moodalbail /* 11616e91bba0SGirish Moodalbail * Callback function that retrieves the value of the property `prefixlen' 11626e91bba0SGirish Moodalbail * for the address object in `arg'. 11636e91bba0SGirish Moodalbail */ 11646e91bba0SGirish Moodalbail /* ARGSUSED */ 11656e91bba0SGirish Moodalbail static ipadm_status_t 11666e91bba0SGirish Moodalbail i_ipadm_get_prefixlen(ipadm_handle_t iph, const void *arg, 11676e91bba0SGirish Moodalbail ipadm_prop_desc_t *pdp, char *buf, uint_t *bufsize, uint_t af, 11686e91bba0SGirish Moodalbail uint_t valtype) 11696e91bba0SGirish Moodalbail { 11706e91bba0SGirish Moodalbail struct lifreq lifr; 11716e91bba0SGirish Moodalbail ipadm_addrobj_t ipaddr = (ipadm_addrobj_t)arg; 11726e91bba0SGirish Moodalbail char lifname[LIFNAMSIZ]; 11736e91bba0SGirish Moodalbail int s; 11746e91bba0SGirish Moodalbail uint32_t prefixlen; 11756e91bba0SGirish Moodalbail size_t nbytes; 11766e91bba0SGirish Moodalbail ipadm_status_t status; 11776e91bba0SGirish Moodalbail uint64_t lifflags; 11786e91bba0SGirish Moodalbail 11796e91bba0SGirish Moodalbail i_ipadm_addrobj2lifname(ipaddr, lifname, sizeof (lifname)); 11806e91bba0SGirish Moodalbail if (ipaddr->ipadm_flags & IPMGMT_ACTIVE) { 11816e91bba0SGirish Moodalbail status = i_ipadm_get_flags(iph, lifname, af, &lifflags); 11826e91bba0SGirish Moodalbail if (status != IPADM_SUCCESS) { 11836e91bba0SGirish Moodalbail return (status); 11846e91bba0SGirish Moodalbail } else if (lifflags & IFF_POINTOPOINT) { 11856e91bba0SGirish Moodalbail buf[0] = '\0'; 11866e91bba0SGirish Moodalbail return (status); 11876e91bba0SGirish Moodalbail } 11886e91bba0SGirish Moodalbail } 11896e91bba0SGirish Moodalbail 11906e91bba0SGirish Moodalbail s = (af == AF_INET ? iph->iph_sock : iph->iph_sock6); 11916e91bba0SGirish Moodalbail bzero(&lifr, sizeof (lifr)); 11926e91bba0SGirish Moodalbail (void) strlcpy(lifr.lifr_name, lifname, sizeof (lifr.lifr_name)); 11936e91bba0SGirish Moodalbail switch (valtype) { 11946e91bba0SGirish Moodalbail case MOD_PROP_POSSIBLE: 11956e91bba0SGirish Moodalbail if (af == AF_INET) 11966e91bba0SGirish Moodalbail nbytes = snprintf(buf, *bufsize, "1-30,32"); 11976e91bba0SGirish Moodalbail else 11986e91bba0SGirish Moodalbail nbytes = snprintf(buf, *bufsize, "1-126,128"); 11996e91bba0SGirish Moodalbail break; 12006e91bba0SGirish Moodalbail case MOD_PROP_DEFAULT: 12016e91bba0SGirish Moodalbail if (ipaddr->ipadm_flags & IPMGMT_ACTIVE) { 12026e91bba0SGirish Moodalbail /* 12036e91bba0SGirish Moodalbail * For static addresses, we retrieve the address 12046e91bba0SGirish Moodalbail * from kernel if it is active. 12056e91bba0SGirish Moodalbail */ 12066e91bba0SGirish Moodalbail if (ioctl(s, SIOCGLIFADDR, (caddr_t)&lifr) < 0) 12076e91bba0SGirish Moodalbail return (ipadm_errno2status(errno)); 12086e91bba0SGirish Moodalbail status = i_ipadm_get_default_prefixlen( 12096e91bba0SGirish Moodalbail &lifr.lifr_addr, &prefixlen); 12106e91bba0SGirish Moodalbail if (status != IPADM_SUCCESS) 12116e91bba0SGirish Moodalbail return (status); 12126e91bba0SGirish Moodalbail } else if ((ipaddr->ipadm_flags & IPMGMT_PERSIST) && 12136e91bba0SGirish Moodalbail ipaddr->ipadm_atype == IPADM_ADDR_DHCP) { 12146e91bba0SGirish Moodalbail /* 12156e91bba0SGirish Moodalbail * Since the address is unknown we cannot 12166e91bba0SGirish Moodalbail * obtain default prefixlen 12176e91bba0SGirish Moodalbail */ 12186e91bba0SGirish Moodalbail buf[0] = '\0'; 12196e91bba0SGirish Moodalbail return (IPADM_SUCCESS); 12206e91bba0SGirish Moodalbail } else { 12216e91bba0SGirish Moodalbail /* 12226e91bba0SGirish Moodalbail * If not in active config, we use the address 12236e91bba0SGirish Moodalbail * from persistent store. 12246e91bba0SGirish Moodalbail */ 12256e91bba0SGirish Moodalbail status = i_ipadm_get_static_addr_db(iph, ipaddr); 12266e91bba0SGirish Moodalbail if (status != IPADM_SUCCESS) 12276e91bba0SGirish Moodalbail return (status); 12286e91bba0SGirish Moodalbail status = i_ipadm_get_default_prefixlen( 12296e91bba0SGirish Moodalbail &ipaddr->ipadm_static_addr, &prefixlen); 12306e91bba0SGirish Moodalbail if (status != IPADM_SUCCESS) 12316e91bba0SGirish Moodalbail return (status); 12326e91bba0SGirish Moodalbail } 12336e91bba0SGirish Moodalbail nbytes = snprintf(buf, *bufsize, "%u", prefixlen); 12346e91bba0SGirish Moodalbail break; 12356e91bba0SGirish Moodalbail case MOD_PROP_ACTIVE: 12366e91bba0SGirish Moodalbail if (ioctl(s, SIOCGLIFNETMASK, (caddr_t)&lifr) < 0) 12376e91bba0SGirish Moodalbail return (ipadm_errno2status(errno)); 12386e91bba0SGirish Moodalbail prefixlen = lifr.lifr_addrlen; 12396e91bba0SGirish Moodalbail nbytes = snprintf(buf, *bufsize, "%u", prefixlen); 12406e91bba0SGirish Moodalbail break; 12416e91bba0SGirish Moodalbail default: 12426e91bba0SGirish Moodalbail return (IPADM_INVALID_ARG); 12436e91bba0SGirish Moodalbail } 12446e91bba0SGirish Moodalbail if (nbytes >= *bufsize) { 12456e91bba0SGirish Moodalbail /* insufficient buffer space */ 12466e91bba0SGirish Moodalbail *bufsize = nbytes + 1; 12476e91bba0SGirish Moodalbail return (IPADM_NO_BUFS); 12486e91bba0SGirish Moodalbail } 12496e91bba0SGirish Moodalbail return (IPADM_SUCCESS); 12506e91bba0SGirish Moodalbail } 12516e91bba0SGirish Moodalbail 12526e91bba0SGirish Moodalbail /* 12536e91bba0SGirish Moodalbail * Callback function that retrieves the value of one of the properties 12546e91bba0SGirish Moodalbail * among `deprecated', `private', and `transmit' for the address object 12556e91bba0SGirish Moodalbail * in `arg'. 12566e91bba0SGirish Moodalbail */ 12576e91bba0SGirish Moodalbail /* ARGSUSED */ 12586e91bba0SGirish Moodalbail static ipadm_status_t 12596e91bba0SGirish Moodalbail i_ipadm_get_addr_flag(ipadm_handle_t iph, const void *arg, 12606e91bba0SGirish Moodalbail ipadm_prop_desc_t *pdp, char *buf, uint_t *bufsize, uint_t af, 12616e91bba0SGirish Moodalbail uint_t valtype) 12626e91bba0SGirish Moodalbail { 12636e91bba0SGirish Moodalbail boolean_t on = B_FALSE; 12646e91bba0SGirish Moodalbail char lifname[LIFNAMSIZ]; 12656e91bba0SGirish Moodalbail ipadm_status_t status = IPADM_SUCCESS; 12666e91bba0SGirish Moodalbail uint64_t ifflags; 12676e91bba0SGirish Moodalbail size_t nbytes; 12686e91bba0SGirish Moodalbail ipadm_addrobj_t ipaddr = (ipadm_addrobj_t)arg; 12696e91bba0SGirish Moodalbail 12706e91bba0SGirish Moodalbail switch (valtype) { 12716e91bba0SGirish Moodalbail case MOD_PROP_DEFAULT: 12726e91bba0SGirish Moodalbail if (strcmp(pdp->ipd_name, "private") == 0 || 12736e91bba0SGirish Moodalbail strcmp(pdp->ipd_name, "deprecated") == 0) { 12746e91bba0SGirish Moodalbail on = B_FALSE; 12756e91bba0SGirish Moodalbail } else if (strcmp(pdp->ipd_name, "transmit") == 0) { 12766e91bba0SGirish Moodalbail on = B_TRUE; 12776e91bba0SGirish Moodalbail } else { 12786e91bba0SGirish Moodalbail return (IPADM_PROP_UNKNOWN); 12796e91bba0SGirish Moodalbail } 12806e91bba0SGirish Moodalbail break; 12816e91bba0SGirish Moodalbail case MOD_PROP_ACTIVE: 12826e91bba0SGirish Moodalbail /* 12836e91bba0SGirish Moodalbail * If the address is present in active configuration, we 12846e91bba0SGirish Moodalbail * retrieve it from kernel to get the property value. 12856e91bba0SGirish Moodalbail * Else, there is no value to return. 12866e91bba0SGirish Moodalbail */ 12876e91bba0SGirish Moodalbail i_ipadm_addrobj2lifname(ipaddr, lifname, sizeof (lifname)); 12886e91bba0SGirish Moodalbail status = i_ipadm_get_flags(iph, lifname, af, &ifflags); 12896e91bba0SGirish Moodalbail if (status != IPADM_SUCCESS) 12906e91bba0SGirish Moodalbail return (status); 12916e91bba0SGirish Moodalbail if (strcmp(pdp->ipd_name, "private") == 0) 12926e91bba0SGirish Moodalbail on = (ifflags & IFF_PRIVATE); 12936e91bba0SGirish Moodalbail else if (strcmp(pdp->ipd_name, "transmit") == 0) 12946e91bba0SGirish Moodalbail on = !(ifflags & IFF_NOXMIT); 12956e91bba0SGirish Moodalbail else if (strcmp(pdp->ipd_name, "deprecated") == 0) 12966e91bba0SGirish Moodalbail on = (ifflags & IFF_DEPRECATED); 12976e91bba0SGirish Moodalbail break; 12986e91bba0SGirish Moodalbail default: 12996e91bba0SGirish Moodalbail return (IPADM_INVALID_ARG); 13006e91bba0SGirish Moodalbail } 13016e91bba0SGirish Moodalbail nbytes = snprintf(buf, *bufsize, "%s", 13026e91bba0SGirish Moodalbail (on ? IPADM_ONSTR : IPADM_OFFSTR)); 13036e91bba0SGirish Moodalbail if (nbytes >= *bufsize) { 13046e91bba0SGirish Moodalbail /* insufficient buffer space */ 13056e91bba0SGirish Moodalbail *bufsize = nbytes + 1; 13066e91bba0SGirish Moodalbail status = IPADM_NO_BUFS; 13076e91bba0SGirish Moodalbail } 13086e91bba0SGirish Moodalbail 13096e91bba0SGirish Moodalbail return (status); 13106e91bba0SGirish Moodalbail } 13116e91bba0SGirish Moodalbail 13126e91bba0SGirish Moodalbail /* 13136e91bba0SGirish Moodalbail * Callback function that retrieves the value of the property `zone' 13146e91bba0SGirish Moodalbail * for the address object in `arg'. 13156e91bba0SGirish Moodalbail */ 13166e91bba0SGirish Moodalbail /* ARGSUSED */ 13176e91bba0SGirish Moodalbail static ipadm_status_t 13186e91bba0SGirish Moodalbail i_ipadm_get_zone(ipadm_handle_t iph, const void *arg, 13196e91bba0SGirish Moodalbail ipadm_prop_desc_t *pdp, char *buf, uint_t *bufsize, uint_t af, 13206e91bba0SGirish Moodalbail uint_t valtype) 13216e91bba0SGirish Moodalbail { 13226e91bba0SGirish Moodalbail struct lifreq lifr; 13236e91bba0SGirish Moodalbail char zone_name[ZONENAME_MAX]; 13246e91bba0SGirish Moodalbail int s; 13256e91bba0SGirish Moodalbail size_t nbytes = 0; 13266e91bba0SGirish Moodalbail 1327550b6e40SSowmini Varadhan if (iph->iph_zoneid != GLOBAL_ZONEID) { 13286e91bba0SGirish Moodalbail buf[0] = '\0'; 13296e91bba0SGirish Moodalbail return (IPADM_SUCCESS); 13306e91bba0SGirish Moodalbail } 13316e91bba0SGirish Moodalbail 13326e91bba0SGirish Moodalbail /* 13336e91bba0SGirish Moodalbail * we are in global zone. See if the lifname is assigned to shared-ip 13346e91bba0SGirish Moodalbail * zone or global zone. 13356e91bba0SGirish Moodalbail */ 13366e91bba0SGirish Moodalbail switch (valtype) { 13376e91bba0SGirish Moodalbail case MOD_PROP_DEFAULT: 13386e91bba0SGirish Moodalbail if (getzonenamebyid(GLOBAL_ZONEID, zone_name, 13396e91bba0SGirish Moodalbail sizeof (zone_name)) > 0) 13406e91bba0SGirish Moodalbail nbytes = snprintf(buf, *bufsize, "%s", zone_name); 13416e91bba0SGirish Moodalbail else 13426e91bba0SGirish Moodalbail return (ipadm_errno2status(errno)); 13436e91bba0SGirish Moodalbail break; 13446e91bba0SGirish Moodalbail case MOD_PROP_ACTIVE: 13456e91bba0SGirish Moodalbail bzero(&lifr, sizeof (lifr)); 13466e91bba0SGirish Moodalbail i_ipadm_addrobj2lifname((ipadm_addrobj_t)arg, lifr.lifr_name, 13476e91bba0SGirish Moodalbail sizeof (lifr.lifr_name)); 13486e91bba0SGirish Moodalbail s = (af == AF_INET ? iph->iph_sock : iph->iph_sock6); 13496e91bba0SGirish Moodalbail 13506e91bba0SGirish Moodalbail if (ioctl(s, SIOCGLIFZONE, (caddr_t)&lifr) == -1) 13516e91bba0SGirish Moodalbail return (ipadm_errno2status(errno)); 13526e91bba0SGirish Moodalbail 13536e91bba0SGirish Moodalbail if (lifr.lifr_zoneid == ALL_ZONES) { 13546e91bba0SGirish Moodalbail nbytes = snprintf(buf, *bufsize, "%s", "all-zones"); 13556e91bba0SGirish Moodalbail } else if (getzonenamebyid(lifr.lifr_zoneid, zone_name, 13566e91bba0SGirish Moodalbail sizeof (zone_name)) < 0) { 13576e91bba0SGirish Moodalbail return (ipadm_errno2status(errno)); 13586e91bba0SGirish Moodalbail } else { 13596e91bba0SGirish Moodalbail nbytes = snprintf(buf, *bufsize, "%s", zone_name); 13606e91bba0SGirish Moodalbail } 13616e91bba0SGirish Moodalbail break; 13626e91bba0SGirish Moodalbail default: 13636e91bba0SGirish Moodalbail return (IPADM_INVALID_ARG); 13646e91bba0SGirish Moodalbail } 13656e91bba0SGirish Moodalbail if (nbytes >= *bufsize) { 13666e91bba0SGirish Moodalbail /* insufficient buffer space */ 13676e91bba0SGirish Moodalbail *bufsize = nbytes + 1; 13686e91bba0SGirish Moodalbail return (IPADM_NO_BUFS); 13696e91bba0SGirish Moodalbail } 13706e91bba0SGirish Moodalbail 13716e91bba0SGirish Moodalbail return (IPADM_SUCCESS); 13726e91bba0SGirish Moodalbail } 13736e91bba0SGirish Moodalbail 13746e91bba0SGirish Moodalbail static ipadm_prop_desc_t * 13758887b57dSGirish Moodalbail i_ipadm_get_addrprop_desc(const char *pname) 13766e91bba0SGirish Moodalbail { 13776e91bba0SGirish Moodalbail int i; 13786e91bba0SGirish Moodalbail 13796e91bba0SGirish Moodalbail for (i = 0; ipadm_addrprop_table[i].ipd_name != NULL; i++) { 1380*299625c6SSebastien Roy if (strcmp(pname, ipadm_addrprop_table[i].ipd_name) == 0 || 1381*299625c6SSebastien Roy (ipadm_addrprop_table[i].ipd_old_name != NULL && 1382*299625c6SSebastien Roy strcmp(pname, ipadm_addrprop_table[i].ipd_old_name) == 0)) 13836e91bba0SGirish Moodalbail return (&ipadm_addrprop_table[i]); 13846e91bba0SGirish Moodalbail } 13856e91bba0SGirish Moodalbail return (NULL); 13866e91bba0SGirish Moodalbail } 13876e91bba0SGirish Moodalbail 13886e91bba0SGirish Moodalbail /* 13896e91bba0SGirish Moodalbail * Gets the value of the given address property `pname' for the address 13906e91bba0SGirish Moodalbail * object with name `aobjname'. 13916e91bba0SGirish Moodalbail */ 13926e91bba0SGirish Moodalbail ipadm_status_t 13936e91bba0SGirish Moodalbail ipadm_get_addrprop(ipadm_handle_t iph, const char *pname, char *buf, 13946e91bba0SGirish Moodalbail uint_t *bufsize, const char *aobjname, uint_t valtype) 13956e91bba0SGirish Moodalbail { 13966e91bba0SGirish Moodalbail struct ipadm_addrobj_s ipaddr; 13976e91bba0SGirish Moodalbail ipadm_status_t status = IPADM_SUCCESS; 13986e91bba0SGirish Moodalbail sa_family_t af; 13996e91bba0SGirish Moodalbail ipadm_prop_desc_t *pdp = NULL; 14006e91bba0SGirish Moodalbail 14016e91bba0SGirish Moodalbail if (iph == NULL || pname == NULL || buf == NULL || 14026e91bba0SGirish Moodalbail bufsize == NULL || *bufsize == 0 || aobjname == NULL) { 14036e91bba0SGirish Moodalbail return (IPADM_INVALID_ARG); 14046e91bba0SGirish Moodalbail } 14056e91bba0SGirish Moodalbail 14066e91bba0SGirish Moodalbail /* find the property in the property description table */ 14078887b57dSGirish Moodalbail if ((pdp = i_ipadm_get_addrprop_desc(pname)) == NULL) 14086e91bba0SGirish Moodalbail return (IPADM_PROP_UNKNOWN); 14096e91bba0SGirish Moodalbail 14106e91bba0SGirish Moodalbail /* 14116e91bba0SGirish Moodalbail * For the given aobjname, get the addrobj it represents and 14126e91bba0SGirish Moodalbail * retrieve the property value for that object. 14136e91bba0SGirish Moodalbail */ 14146e91bba0SGirish Moodalbail i_ipadm_init_addr(&ipaddr, "", aobjname, IPADM_ADDR_NONE); 14156e91bba0SGirish Moodalbail if ((status = i_ipadm_get_addrobj(iph, &ipaddr)) != IPADM_SUCCESS) 14166e91bba0SGirish Moodalbail return (status); 14176e91bba0SGirish Moodalbail 14186e91bba0SGirish Moodalbail if (ipaddr.ipadm_atype == IPADM_ADDR_IPV6_ADDRCONF) 14196e91bba0SGirish Moodalbail return (IPADM_NOTSUP); 14206e91bba0SGirish Moodalbail af = ipaddr.ipadm_af; 14216e91bba0SGirish Moodalbail 14226e91bba0SGirish Moodalbail /* 14236e91bba0SGirish Moodalbail * Call the appropriate callback function to based on the field 14246e91bba0SGirish Moodalbail * that was asked for. 14256e91bba0SGirish Moodalbail */ 14266e91bba0SGirish Moodalbail switch (valtype) { 14276e91bba0SGirish Moodalbail case IPADM_OPT_PERM: 14286e91bba0SGirish Moodalbail status = i_ipadm_pd2permstr(pdp, buf, bufsize); 14296e91bba0SGirish Moodalbail break; 14306e91bba0SGirish Moodalbail case IPADM_OPT_ACTIVE: 14316e91bba0SGirish Moodalbail if (!(ipaddr.ipadm_flags & IPMGMT_ACTIVE)) { 14326e91bba0SGirish Moodalbail buf[0] = '\0'; 14336e91bba0SGirish Moodalbail } else { 14346e91bba0SGirish Moodalbail status = pdp->ipd_get(iph, &ipaddr, pdp, buf, bufsize, 14356e91bba0SGirish Moodalbail af, MOD_PROP_ACTIVE); 14366e91bba0SGirish Moodalbail } 14376e91bba0SGirish Moodalbail break; 14386e91bba0SGirish Moodalbail case IPADM_OPT_DEFAULT: 14396e91bba0SGirish Moodalbail status = pdp->ipd_get(iph, &ipaddr, pdp, buf, bufsize, 14406e91bba0SGirish Moodalbail af, MOD_PROP_DEFAULT); 14416e91bba0SGirish Moodalbail break; 14426e91bba0SGirish Moodalbail case IPADM_OPT_POSSIBLE: 14436e91bba0SGirish Moodalbail if (pdp->ipd_get_range != NULL) { 14446e91bba0SGirish Moodalbail status = pdp->ipd_get_range(iph, &ipaddr, pdp, buf, 14456e91bba0SGirish Moodalbail bufsize, af, MOD_PROP_POSSIBLE); 14466e91bba0SGirish Moodalbail break; 14476e91bba0SGirish Moodalbail } 14486e91bba0SGirish Moodalbail buf[0] = '\0'; 14496e91bba0SGirish Moodalbail break; 14506e91bba0SGirish Moodalbail case IPADM_OPT_PERSIST: 14516e91bba0SGirish Moodalbail status = i_ipadm_get_persist_propval(iph, pdp, buf, bufsize, 14526e91bba0SGirish Moodalbail &ipaddr); 14536e91bba0SGirish Moodalbail break; 14546e91bba0SGirish Moodalbail default: 14556e91bba0SGirish Moodalbail status = IPADM_INVALID_ARG; 14566e91bba0SGirish Moodalbail break; 14576e91bba0SGirish Moodalbail } 14586e91bba0SGirish Moodalbail 14596e91bba0SGirish Moodalbail return (status); 14606e91bba0SGirish Moodalbail } 14616e91bba0SGirish Moodalbail 14626e91bba0SGirish Moodalbail /* 14636e91bba0SGirish Moodalbail * Sets the value of the given address property `pname' to `pval' for the 14646e91bba0SGirish Moodalbail * address object with name `aobjname'. 14656e91bba0SGirish Moodalbail */ 14666e91bba0SGirish Moodalbail ipadm_status_t 14676e91bba0SGirish Moodalbail ipadm_set_addrprop(ipadm_handle_t iph, const char *pname, 14686e91bba0SGirish Moodalbail const char *pval, const char *aobjname, uint_t pflags) 14696e91bba0SGirish Moodalbail { 14706e91bba0SGirish Moodalbail struct ipadm_addrobj_s ipaddr; 14716e91bba0SGirish Moodalbail sa_family_t af; 14726e91bba0SGirish Moodalbail ipadm_prop_desc_t *pdp = NULL; 14736e91bba0SGirish Moodalbail char defbuf[MAXPROPVALLEN]; 14746e91bba0SGirish Moodalbail uint_t defbufsize = MAXPROPVALLEN; 14756e91bba0SGirish Moodalbail boolean_t reset = (pflags & IPADM_OPT_DEFAULT); 14766e91bba0SGirish Moodalbail ipadm_status_t status = IPADM_SUCCESS; 14776e91bba0SGirish Moodalbail 14786e91bba0SGirish Moodalbail /* Check for solaris.network.interface.config authorization */ 14796e91bba0SGirish Moodalbail if (!ipadm_check_auth()) 14806e91bba0SGirish Moodalbail return (IPADM_EAUTH); 14816e91bba0SGirish Moodalbail 14826e91bba0SGirish Moodalbail if (iph == NULL || pname == NULL || aobjname == NULL || pflags == 0 || 14836e91bba0SGirish Moodalbail pflags == IPADM_OPT_PERSIST || 14846e91bba0SGirish Moodalbail (pflags & ~(IPADM_COMMON_OPT_MASK|IPADM_OPT_DEFAULT)) || 14856e91bba0SGirish Moodalbail (!reset && pval == NULL)) { 14866e91bba0SGirish Moodalbail return (IPADM_INVALID_ARG); 14876e91bba0SGirish Moodalbail } 14886e91bba0SGirish Moodalbail 14896e91bba0SGirish Moodalbail /* find the property in the property description table */ 14908887b57dSGirish Moodalbail if ((pdp = i_ipadm_get_addrprop_desc(pname)) == NULL) 14916e91bba0SGirish Moodalbail return (IPADM_PROP_UNKNOWN); 14926e91bba0SGirish Moodalbail 14936e91bba0SGirish Moodalbail if (pdp->ipd_set == NULL || (reset && pdp->ipd_get == NULL)) 14946e91bba0SGirish Moodalbail return (IPADM_NOTSUP); 14956e91bba0SGirish Moodalbail 14968b88711aSGirish Moodalbail if (!(pdp->ipd_flags & IPADMPROP_MULVAL) && 14978b88711aSGirish Moodalbail (pflags & (IPADM_OPT_APPEND|IPADM_OPT_REMOVE))) { 14988b88711aSGirish Moodalbail return (IPADM_INVALID_ARG); 14998b88711aSGirish Moodalbail } 15008b88711aSGirish Moodalbail 15016e91bba0SGirish Moodalbail /* 15026e91bba0SGirish Moodalbail * For the given aobjname, get the addrobj it represents and 15036e91bba0SGirish Moodalbail * set the property value for that object. 15046e91bba0SGirish Moodalbail */ 15056e91bba0SGirish Moodalbail i_ipadm_init_addr(&ipaddr, "", aobjname, IPADM_ADDR_NONE); 15066e91bba0SGirish Moodalbail if ((status = i_ipadm_get_addrobj(iph, &ipaddr)) != IPADM_SUCCESS) 15076e91bba0SGirish Moodalbail return (status); 15086e91bba0SGirish Moodalbail 15096e91bba0SGirish Moodalbail if (!(ipaddr.ipadm_flags & IPMGMT_ACTIVE)) 15106e91bba0SGirish Moodalbail return (IPADM_OP_DISABLE_OBJ); 15116e91bba0SGirish Moodalbail 15126e91bba0SGirish Moodalbail /* Persistent operation not allowed on a temporary object. */ 15136e91bba0SGirish Moodalbail if ((pflags & IPADM_OPT_PERSIST) && 15146e91bba0SGirish Moodalbail !(ipaddr.ipadm_flags & IPMGMT_PERSIST)) 15156e91bba0SGirish Moodalbail return (IPADM_TEMPORARY_OBJ); 15166e91bba0SGirish Moodalbail 15176e91bba0SGirish Moodalbail /* 15186e91bba0SGirish Moodalbail * Currently, setting an address property on an address object of type 15196e91bba0SGirish Moodalbail * IPADM_ADDR_IPV6_ADDRCONF is not supported. Supporting it involves 15206e91bba0SGirish Moodalbail * in.ndpd retrieving the address properties from ipmgmtd for given 15216e91bba0SGirish Moodalbail * address object and then setting them on auto-configured addresses, 15226e91bba0SGirish Moodalbail * whenever in.ndpd gets a new prefix. This will be supported in 15236e91bba0SGirish Moodalbail * future releases. 15246e91bba0SGirish Moodalbail */ 15256e91bba0SGirish Moodalbail if (ipaddr.ipadm_atype == IPADM_ADDR_IPV6_ADDRCONF) 15266e91bba0SGirish Moodalbail return (IPADM_NOTSUP); 15276e91bba0SGirish Moodalbail 15286e91bba0SGirish Moodalbail /* 15296e91bba0SGirish Moodalbail * Setting an address property on an address object that is 15306e91bba0SGirish Moodalbail * not present in active configuration is not supported. 15316e91bba0SGirish Moodalbail */ 15326e91bba0SGirish Moodalbail if (!(ipaddr.ipadm_flags & IPMGMT_ACTIVE)) 15336e91bba0SGirish Moodalbail return (IPADM_NOTSUP); 15346e91bba0SGirish Moodalbail 15356e91bba0SGirish Moodalbail af = ipaddr.ipadm_af; 15366e91bba0SGirish Moodalbail if (reset) { 15376e91bba0SGirish Moodalbail /* 15386e91bba0SGirish Moodalbail * If we were asked to reset the value, we need to fetch 15396e91bba0SGirish Moodalbail * the default value and set the default value. 15406e91bba0SGirish Moodalbail */ 15416e91bba0SGirish Moodalbail status = pdp->ipd_get(iph, &ipaddr, pdp, defbuf, &defbufsize, 15426e91bba0SGirish Moodalbail af, MOD_PROP_DEFAULT); 15436e91bba0SGirish Moodalbail if (status != IPADM_SUCCESS) 15446e91bba0SGirish Moodalbail return (status); 15456e91bba0SGirish Moodalbail pval = defbuf; 15466e91bba0SGirish Moodalbail } 15476e91bba0SGirish Moodalbail /* set the user provided or default property value */ 15486e91bba0SGirish Moodalbail status = pdp->ipd_set(iph, &ipaddr, pdp, pval, af, pflags); 15496e91bba0SGirish Moodalbail if (status != IPADM_SUCCESS) 15506e91bba0SGirish Moodalbail return (status); 15516e91bba0SGirish Moodalbail 15526e91bba0SGirish Moodalbail /* 15536e91bba0SGirish Moodalbail * If IPADM_OPT_PERSIST was set in `flags', we need to store 15546e91bba0SGirish Moodalbail * property and its value in persistent DB. 15556e91bba0SGirish Moodalbail */ 15566e91bba0SGirish Moodalbail if (pflags & IPADM_OPT_PERSIST) { 15576e91bba0SGirish Moodalbail status = i_ipadm_persist_propval(iph, pdp, pval, &ipaddr, 15586e91bba0SGirish Moodalbail pflags); 15596e91bba0SGirish Moodalbail } 15606e91bba0SGirish Moodalbail 15616e91bba0SGirish Moodalbail return (status); 15626e91bba0SGirish Moodalbail } 15636e91bba0SGirish Moodalbail 15646e91bba0SGirish Moodalbail /* 15656e91bba0SGirish Moodalbail * Remove the address specified by the address object in `addr' 15666e91bba0SGirish Moodalbail * from kernel. If the address is on a non-zero logical interface, we do a 15676e91bba0SGirish Moodalbail * SIOCLIFREMOVEIF, otherwise we set the address to INADDR_ANY for IPv4 or 15686e91bba0SGirish Moodalbail * :: for IPv6. 15696e91bba0SGirish Moodalbail */ 15706e91bba0SGirish Moodalbail ipadm_status_t 15716e91bba0SGirish Moodalbail i_ipadm_delete_addr(ipadm_handle_t iph, ipadm_addrobj_t addr) 15726e91bba0SGirish Moodalbail { 15736e91bba0SGirish Moodalbail struct lifreq lifr; 15746e91bba0SGirish Moodalbail int sock; 15756e91bba0SGirish Moodalbail ipadm_status_t status; 15766e91bba0SGirish Moodalbail 15776e91bba0SGirish Moodalbail bzero(&lifr, sizeof (lifr)); 15786e91bba0SGirish Moodalbail i_ipadm_addrobj2lifname(addr, lifr.lifr_name, sizeof (lifr.lifr_name)); 15796e91bba0SGirish Moodalbail sock = (addr->ipadm_af == AF_INET ? iph->iph_sock : iph->iph_sock6); 15806e91bba0SGirish Moodalbail if (addr->ipadm_lifnum == 0) { 15816e91bba0SGirish Moodalbail /* 15826e91bba0SGirish Moodalbail * Fake the deletion of the 0'th address by 15836e91bba0SGirish Moodalbail * clearing IFF_UP and setting it to as 0.0.0.0 or ::. 15846e91bba0SGirish Moodalbail */ 15856e91bba0SGirish Moodalbail status = i_ipadm_set_flags(iph, addr->ipadm_ifname, 15866e91bba0SGirish Moodalbail addr->ipadm_af, 0, IFF_UP); 15876e91bba0SGirish Moodalbail if (status != IPADM_SUCCESS) 15886e91bba0SGirish Moodalbail return (status); 15896e91bba0SGirish Moodalbail bzero(&lifr.lifr_addr, sizeof (lifr.lifr_addr)); 15906e91bba0SGirish Moodalbail lifr.lifr_addr.ss_family = addr->ipadm_af; 15916e91bba0SGirish Moodalbail if (ioctl(sock, SIOCSLIFADDR, (caddr_t)&lifr) < 0) 15926e91bba0SGirish Moodalbail return (ipadm_errno2status(errno)); 15936e91bba0SGirish Moodalbail if (ioctl(sock, SIOCSLIFDSTADDR, (caddr_t)&lifr) < 0) 15946e91bba0SGirish Moodalbail return (ipadm_errno2status(errno)); 15956e91bba0SGirish Moodalbail } else if (ioctl(sock, SIOCLIFREMOVEIF, (caddr_t)&lifr) < 0) { 15966e91bba0SGirish Moodalbail return (ipadm_errno2status(errno)); 15976e91bba0SGirish Moodalbail } 15986e91bba0SGirish Moodalbail 15996e91bba0SGirish Moodalbail return (IPADM_SUCCESS); 16006e91bba0SGirish Moodalbail } 16016e91bba0SGirish Moodalbail 16026e91bba0SGirish Moodalbail /* 16036e91bba0SGirish Moodalbail * Extracts the IPv6 address from the nvlist in `nvl'. 16046e91bba0SGirish Moodalbail */ 16056e91bba0SGirish Moodalbail ipadm_status_t 16066e91bba0SGirish Moodalbail i_ipadm_nvl2in6_addr(nvlist_t *nvl, char *addr_type, in6_addr_t *in6_addr) 16076e91bba0SGirish Moodalbail { 16086e91bba0SGirish Moodalbail uint8_t *addr6; 16096e91bba0SGirish Moodalbail uint_t n; 16106e91bba0SGirish Moodalbail 16116e91bba0SGirish Moodalbail if (nvlist_lookup_uint8_array(nvl, addr_type, &addr6, &n) != 0) 16126e91bba0SGirish Moodalbail return (IPADM_NOTFOUND); 16136e91bba0SGirish Moodalbail assert(n == 16); 16146e91bba0SGirish Moodalbail bcopy(addr6, in6_addr->s6_addr, n); 16156e91bba0SGirish Moodalbail return (IPADM_SUCCESS); 16166e91bba0SGirish Moodalbail } 16176e91bba0SGirish Moodalbail 16186e91bba0SGirish Moodalbail /* 16196e91bba0SGirish Moodalbail * Used to validate the given addrobj name string. Length of `aobjname' 16206e91bba0SGirish Moodalbail * cannot exceed IPADM_AOBJ_USTRSIZ. `aobjname' should start with an 16216e91bba0SGirish Moodalbail * alphabetic character and it can only contain alphanumeric characters. 16226e91bba0SGirish Moodalbail */ 16236e91bba0SGirish Moodalbail static boolean_t 16246e91bba0SGirish Moodalbail i_ipadm_is_user_aobjname_valid(const char *aobjname) 16256e91bba0SGirish Moodalbail { 16266e91bba0SGirish Moodalbail const char *cp; 16276e91bba0SGirish Moodalbail 16286e91bba0SGirish Moodalbail if (aobjname == NULL || strlen(aobjname) >= IPADM_AOBJ_USTRSIZ || 16296e91bba0SGirish Moodalbail !isalpha(*aobjname)) { 16306e91bba0SGirish Moodalbail return (B_FALSE); 16316e91bba0SGirish Moodalbail } 16326e91bba0SGirish Moodalbail for (cp = aobjname + 1; *cp && isalnum(*cp); cp++) 16336e91bba0SGirish Moodalbail ; 16346e91bba0SGirish Moodalbail return (*cp == '\0'); 16356e91bba0SGirish Moodalbail } 16366e91bba0SGirish Moodalbail 16376e91bba0SGirish Moodalbail /* 16386e91bba0SGirish Moodalbail * Computes the prefixlen for the given `addr' based on the netmask found using 16396e91bba0SGirish Moodalbail * the order specified in /etc/nsswitch.conf. If not found, then the 16406e91bba0SGirish Moodalbail * prefixlen is computed using the Classful subnetting semantics defined 16416e91bba0SGirish Moodalbail * in RFC 791 for IPv4 and RFC 4291 for IPv6. 16426e91bba0SGirish Moodalbail */ 16436e91bba0SGirish Moodalbail static ipadm_status_t 16446e91bba0SGirish Moodalbail i_ipadm_get_default_prefixlen(struct sockaddr_storage *addr, uint32_t *plen) 16456e91bba0SGirish Moodalbail { 16466e91bba0SGirish Moodalbail sa_family_t af = addr->ss_family; 16476e91bba0SGirish Moodalbail struct sockaddr_storage mask; 16486e91bba0SGirish Moodalbail struct sockaddr_in *m = (struct sockaddr_in *)&mask; 16496e91bba0SGirish Moodalbail struct sockaddr_in6 *sin6; 16506e91bba0SGirish Moodalbail struct sockaddr_in *sin; 16516e91bba0SGirish Moodalbail struct in_addr ia; 16526e91bba0SGirish Moodalbail uint32_t prefixlen = 0; 16536e91bba0SGirish Moodalbail 16546e91bba0SGirish Moodalbail switch (af) { 16556e91bba0SGirish Moodalbail case AF_INET: 16566e91bba0SGirish Moodalbail sin = SIN(addr); 16576e91bba0SGirish Moodalbail ia.s_addr = ntohl(sin->sin_addr.s_addr); 16586e91bba0SGirish Moodalbail get_netmask4(&ia, &m->sin_addr); 16596e91bba0SGirish Moodalbail m->sin_addr.s_addr = htonl(m->sin_addr.s_addr); 16606e91bba0SGirish Moodalbail m->sin_family = AF_INET; 166164639aafSDarren Reed prefixlen = mask2plen((struct sockaddr *)&mask); 16626e91bba0SGirish Moodalbail break; 16636e91bba0SGirish Moodalbail case AF_INET6: 16646e91bba0SGirish Moodalbail sin6 = SIN6(addr); 16656e91bba0SGirish Moodalbail if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) 16666e91bba0SGirish Moodalbail prefixlen = 10; 16676e91bba0SGirish Moodalbail else 16686e91bba0SGirish Moodalbail prefixlen = 64; 16696e91bba0SGirish Moodalbail break; 16706e91bba0SGirish Moodalbail default: 16716e91bba0SGirish Moodalbail return (IPADM_INVALID_ARG); 16726e91bba0SGirish Moodalbail } 16736e91bba0SGirish Moodalbail *plen = prefixlen; 16746e91bba0SGirish Moodalbail return (IPADM_SUCCESS); 16756e91bba0SGirish Moodalbail } 16766e91bba0SGirish Moodalbail 1677550b6e40SSowmini Varadhan ipadm_status_t 16786e91bba0SGirish Moodalbail i_ipadm_resolve_addr(const char *name, sa_family_t af, 16796e91bba0SGirish Moodalbail struct sockaddr_storage *ss) 16806e91bba0SGirish Moodalbail { 16816e91bba0SGirish Moodalbail struct addrinfo hints, *ai; 16826e91bba0SGirish Moodalbail int rc; 16836e91bba0SGirish Moodalbail struct sockaddr_in6 *sin6; 16846e91bba0SGirish Moodalbail struct sockaddr_in *sin; 16856e91bba0SGirish Moodalbail boolean_t is_mapped; 16866e91bba0SGirish Moodalbail 16876e91bba0SGirish Moodalbail (void) memset(&hints, 0, sizeof (hints)); 16886e91bba0SGirish Moodalbail hints.ai_family = af; 16896e91bba0SGirish Moodalbail hints.ai_flags = (AI_ALL | AI_V4MAPPED); 16906e91bba0SGirish Moodalbail rc = getaddrinfo(name, NULL, &hints, &ai); 16916e91bba0SGirish Moodalbail if (rc != 0) { 16926e91bba0SGirish Moodalbail if (rc == EAI_NONAME) 16936e91bba0SGirish Moodalbail return (IPADM_BAD_ADDR); 16946e91bba0SGirish Moodalbail else 16956e91bba0SGirish Moodalbail return (IPADM_FAILURE); 16966e91bba0SGirish Moodalbail } 16976e91bba0SGirish Moodalbail if (ai->ai_next != NULL) { 16986e91bba0SGirish Moodalbail /* maps to more than one hostname */ 16996e91bba0SGirish Moodalbail freeaddrinfo(ai); 17006e91bba0SGirish Moodalbail return (IPADM_BAD_HOSTNAME); 17016e91bba0SGirish Moodalbail } 17026e91bba0SGirish Moodalbail /* LINTED E_BAD_PTR_CAST_ALIGN */ 17036e91bba0SGirish Moodalbail is_mapped = IN6_IS_ADDR_V4MAPPED(&(SIN6(ai->ai_addr))->sin6_addr); 17046e91bba0SGirish Moodalbail if (is_mapped) { 17056e91bba0SGirish Moodalbail sin = SIN(ss); 17066e91bba0SGirish Moodalbail sin->sin_family = AF_INET; 17076e91bba0SGirish Moodalbail /* LINTED E_BAD_PTR_CAST_ALIGN */ 17086e91bba0SGirish Moodalbail IN6_V4MAPPED_TO_INADDR(&(SIN6(ai->ai_addr))->sin6_addr, 17096e91bba0SGirish Moodalbail &sin->sin_addr); 17106e91bba0SGirish Moodalbail } else { 17116e91bba0SGirish Moodalbail sin6 = SIN6(ss); 17126e91bba0SGirish Moodalbail sin6->sin6_family = AF_INET6; 17136e91bba0SGirish Moodalbail bcopy(ai->ai_addr, sin6, sizeof (*sin6)); 17146e91bba0SGirish Moodalbail } 17156e91bba0SGirish Moodalbail freeaddrinfo(ai); 17166e91bba0SGirish Moodalbail return (IPADM_SUCCESS); 17176e91bba0SGirish Moodalbail } 17186e91bba0SGirish Moodalbail 17196e91bba0SGirish Moodalbail /* 17206e91bba0SGirish Moodalbail * This takes a static address string <addr>[/<mask>] or a hostname 17216e91bba0SGirish Moodalbail * and maps it to a single numeric IP address, consulting DNS if 17226e91bba0SGirish Moodalbail * hostname was provided. If a specific address family was requested, 17236e91bba0SGirish Moodalbail * an error is returned if the given hostname does not map to an address 17246e91bba0SGirish Moodalbail * of the given family. Note that this function returns failure 17256e91bba0SGirish Moodalbail * if the name maps to more than one IP address. 17266e91bba0SGirish Moodalbail */ 17276e91bba0SGirish Moodalbail ipadm_status_t 17286e91bba0SGirish Moodalbail ipadm_set_addr(ipadm_addrobj_t ipaddr, const char *astr, sa_family_t af) 17296e91bba0SGirish Moodalbail { 17306e91bba0SGirish Moodalbail char *prefixlenstr; 17316e91bba0SGirish Moodalbail uint32_t prefixlen = 0; 17326e91bba0SGirish Moodalbail char *endp; 17336e91bba0SGirish Moodalbail /* 17346e91bba0SGirish Moodalbail * We use (NI_MAXHOST + 5) because the longest possible 17356e91bba0SGirish Moodalbail * astr will have (NI_MAXHOST + '/' + {a maximum of 32 for IPv4 17366e91bba0SGirish Moodalbail * or a maximum of 128 for IPv6 + '\0') chars 17376e91bba0SGirish Moodalbail */ 17386e91bba0SGirish Moodalbail char addrstr[NI_MAXHOST + 5]; 17396e91bba0SGirish Moodalbail ipadm_status_t status; 17406e91bba0SGirish Moodalbail 17416e91bba0SGirish Moodalbail (void) snprintf(addrstr, sizeof (addrstr), "%s", astr); 17426e91bba0SGirish Moodalbail if ((prefixlenstr = strchr(addrstr, '/')) != NULL) { 17436e91bba0SGirish Moodalbail *prefixlenstr++ = '\0'; 17446e91bba0SGirish Moodalbail errno = 0; 17456e91bba0SGirish Moodalbail prefixlen = strtoul(prefixlenstr, &endp, 10); 17466e91bba0SGirish Moodalbail if (errno != 0 || *endp != '\0') 17476e91bba0SGirish Moodalbail return (IPADM_INVALID_ARG); 17486e91bba0SGirish Moodalbail if ((af == AF_INET && prefixlen > IP_ABITS) || 17496e91bba0SGirish Moodalbail (af == AF_INET6 && prefixlen > IPV6_ABITS)) 17506e91bba0SGirish Moodalbail return (IPADM_INVALID_ARG); 17516e91bba0SGirish Moodalbail } 17526e91bba0SGirish Moodalbail 17536e91bba0SGirish Moodalbail status = i_ipadm_resolve_addr(addrstr, af, &ipaddr->ipadm_static_addr); 17546e91bba0SGirish Moodalbail if (status == IPADM_SUCCESS) { 17556e91bba0SGirish Moodalbail (void) strlcpy(ipaddr->ipadm_static_aname, addrstr, 17566e91bba0SGirish Moodalbail sizeof (ipaddr->ipadm_static_aname)); 17576e91bba0SGirish Moodalbail ipaddr->ipadm_af = ipaddr->ipadm_static_addr.ss_family; 17586e91bba0SGirish Moodalbail ipaddr->ipadm_static_prefixlen = prefixlen; 17596e91bba0SGirish Moodalbail } 17606e91bba0SGirish Moodalbail return (status); 17616e91bba0SGirish Moodalbail } 17626e91bba0SGirish Moodalbail 17636e91bba0SGirish Moodalbail /* 1764f6da83d4SAnurag S. Maskey * Gets the static source address from the address object in `ipaddr'. 1765f6da83d4SAnurag S. Maskey * Memory for `addr' should be already allocated by the caller. 1766f6da83d4SAnurag S. Maskey */ 1767f6da83d4SAnurag S. Maskey ipadm_status_t 1768f6da83d4SAnurag S. Maskey ipadm_get_addr(const ipadm_addrobj_t ipaddr, struct sockaddr_storage *addr) 1769f6da83d4SAnurag S. Maskey { 1770f6da83d4SAnurag S. Maskey if (ipaddr == NULL || ipaddr->ipadm_atype != IPADM_ADDR_STATIC || 1771f6da83d4SAnurag S. Maskey addr == NULL) { 1772f6da83d4SAnurag S. Maskey return (IPADM_INVALID_ARG); 1773f6da83d4SAnurag S. Maskey } 1774f6da83d4SAnurag S. Maskey *addr = ipaddr->ipadm_static_addr; 1775f6da83d4SAnurag S. Maskey 1776f6da83d4SAnurag S. Maskey return (IPADM_SUCCESS); 1777f6da83d4SAnurag S. Maskey } 1778f6da83d4SAnurag S. Maskey /* 17796e91bba0SGirish Moodalbail * Set up tunnel destination address in ipaddr by contacting DNS. 17806e91bba0SGirish Moodalbail * The function works similar to ipadm_set_addr(). 17816e91bba0SGirish Moodalbail * The dst_addr must resolve to exactly one address. IPADM_BAD_ADDR is returned 17826e91bba0SGirish Moodalbail * if dst_addr resolves to more than one address. The caller has to verify 17836e91bba0SGirish Moodalbail * that ipadm_static_addr and ipadm_static_dst_addr have the same ss_family 17846e91bba0SGirish Moodalbail */ 17856e91bba0SGirish Moodalbail ipadm_status_t 17866e91bba0SGirish Moodalbail ipadm_set_dst_addr(ipadm_addrobj_t ipaddr, const char *daddrstr, sa_family_t af) 17876e91bba0SGirish Moodalbail { 17886e91bba0SGirish Moodalbail ipadm_status_t status; 17896e91bba0SGirish Moodalbail 17906e91bba0SGirish Moodalbail /* mask lengths are not meaningful for point-to-point interfaces. */ 17916e91bba0SGirish Moodalbail if (strchr(daddrstr, '/') != NULL) 17926e91bba0SGirish Moodalbail return (IPADM_BAD_ADDR); 17936e91bba0SGirish Moodalbail 17946e91bba0SGirish Moodalbail status = i_ipadm_resolve_addr(daddrstr, af, 17956e91bba0SGirish Moodalbail &ipaddr->ipadm_static_dst_addr); 17966e91bba0SGirish Moodalbail if (status == IPADM_SUCCESS) { 17976e91bba0SGirish Moodalbail (void) strlcpy(ipaddr->ipadm_static_dname, daddrstr, 17986e91bba0SGirish Moodalbail sizeof (ipaddr->ipadm_static_dname)); 17996e91bba0SGirish Moodalbail } 18006e91bba0SGirish Moodalbail return (status); 18016e91bba0SGirish Moodalbail } 18026e91bba0SGirish Moodalbail 18036e91bba0SGirish Moodalbail /* 18046e91bba0SGirish Moodalbail * Sets the interface ID in the address object `ipaddr' with the address 18056e91bba0SGirish Moodalbail * in the string `interface_id'. This interface ID will be used when 18066e91bba0SGirish Moodalbail * ipadm_create_addr() is called with `ipaddr' with address type 18076e91bba0SGirish Moodalbail * set to IPADM_ADDR_IPV6_ADDRCONF. 18086e91bba0SGirish Moodalbail */ 18096e91bba0SGirish Moodalbail ipadm_status_t 18106e91bba0SGirish Moodalbail ipadm_set_interface_id(ipadm_addrobj_t ipaddr, const char *interface_id) 18116e91bba0SGirish Moodalbail { 18126e91bba0SGirish Moodalbail struct sockaddr_in6 *sin6; 18136e91bba0SGirish Moodalbail char *end; 18146e91bba0SGirish Moodalbail char *cp; 18156e91bba0SGirish Moodalbail uint32_t prefixlen; 18166e91bba0SGirish Moodalbail char addrstr[INET6_ADDRSTRLEN + 1]; 18176e91bba0SGirish Moodalbail 18186e91bba0SGirish Moodalbail if (ipaddr == NULL || interface_id == NULL || 18196e91bba0SGirish Moodalbail ipaddr->ipadm_atype != IPADM_ADDR_IPV6_ADDRCONF) 18206e91bba0SGirish Moodalbail return (IPADM_INVALID_ARG); 18216e91bba0SGirish Moodalbail 18226e91bba0SGirish Moodalbail (void) strlcpy(addrstr, interface_id, sizeof (addrstr)); 18236e91bba0SGirish Moodalbail if ((cp = strchr(addrstr, '/')) == NULL) 18246e91bba0SGirish Moodalbail return (IPADM_INVALID_ARG); 18256e91bba0SGirish Moodalbail *cp++ = '\0'; 18266e91bba0SGirish Moodalbail sin6 = &ipaddr->ipadm_intfid; 18276e91bba0SGirish Moodalbail if (inet_pton(AF_INET6, addrstr, &sin6->sin6_addr) == 1) { 18286e91bba0SGirish Moodalbail errno = 0; 18296e91bba0SGirish Moodalbail prefixlen = strtoul(cp, &end, 10); 18306e91bba0SGirish Moodalbail if (errno != 0 || *end != '\0' || prefixlen > IPV6_ABITS) 18316e91bba0SGirish Moodalbail return (IPADM_INVALID_ARG); 18326e91bba0SGirish Moodalbail sin6->sin6_family = AF_INET6; 18336e91bba0SGirish Moodalbail ipaddr->ipadm_intfidlen = prefixlen; 18346e91bba0SGirish Moodalbail return (IPADM_SUCCESS); 18356e91bba0SGirish Moodalbail } 18366e91bba0SGirish Moodalbail return (IPADM_INVALID_ARG); 18376e91bba0SGirish Moodalbail } 18386e91bba0SGirish Moodalbail 18396e91bba0SGirish Moodalbail /* 18406e91bba0SGirish Moodalbail * Sets the value for the field `ipadm_stateless' in address object `ipaddr'. 18416e91bba0SGirish Moodalbail */ 18426e91bba0SGirish Moodalbail ipadm_status_t 18436e91bba0SGirish Moodalbail ipadm_set_stateless(ipadm_addrobj_t ipaddr, boolean_t stateless) 18446e91bba0SGirish Moodalbail { 18456e91bba0SGirish Moodalbail if (ipaddr == NULL || 18466e91bba0SGirish Moodalbail ipaddr->ipadm_atype != IPADM_ADDR_IPV6_ADDRCONF) 18476e91bba0SGirish Moodalbail return (IPADM_INVALID_ARG); 18486e91bba0SGirish Moodalbail ipaddr->ipadm_stateless = stateless; 18496e91bba0SGirish Moodalbail 18506e91bba0SGirish Moodalbail return (IPADM_SUCCESS); 18516e91bba0SGirish Moodalbail } 18526e91bba0SGirish Moodalbail 18536e91bba0SGirish Moodalbail /* 18546e91bba0SGirish Moodalbail * Sets the value for the field `ipadm_stateful' in address object `ipaddr'. 18556e91bba0SGirish Moodalbail */ 18566e91bba0SGirish Moodalbail ipadm_status_t 18576e91bba0SGirish Moodalbail ipadm_set_stateful(ipadm_addrobj_t ipaddr, boolean_t stateful) 18586e91bba0SGirish Moodalbail { 18596e91bba0SGirish Moodalbail if (ipaddr == NULL || 18606e91bba0SGirish Moodalbail ipaddr->ipadm_atype != IPADM_ADDR_IPV6_ADDRCONF) 18616e91bba0SGirish Moodalbail return (IPADM_INVALID_ARG); 18626e91bba0SGirish Moodalbail ipaddr->ipadm_stateful = stateful; 18636e91bba0SGirish Moodalbail 18646e91bba0SGirish Moodalbail return (IPADM_SUCCESS); 18656e91bba0SGirish Moodalbail } 18666e91bba0SGirish Moodalbail 18676e91bba0SGirish Moodalbail /* 18686e91bba0SGirish Moodalbail * Sets the dhcp parameter `ipadm_primary' in the address object `ipaddr'. 18696e91bba0SGirish Moodalbail * The field is used during the address creation with address 18706e91bba0SGirish Moodalbail * type IPADM_ADDR_DHCP. It specifies if the interface should be set 18716e91bba0SGirish Moodalbail * as a primary interface for getting dhcp global options from the DHCP server. 18726e91bba0SGirish Moodalbail */ 18736e91bba0SGirish Moodalbail ipadm_status_t 18746e91bba0SGirish Moodalbail ipadm_set_primary(ipadm_addrobj_t ipaddr, boolean_t primary) 18756e91bba0SGirish Moodalbail { 18766e91bba0SGirish Moodalbail if (ipaddr == NULL || ipaddr->ipadm_atype != IPADM_ADDR_DHCP) 18776e91bba0SGirish Moodalbail return (IPADM_INVALID_ARG); 18786e91bba0SGirish Moodalbail ipaddr->ipadm_primary = primary; 18796e91bba0SGirish Moodalbail 18806e91bba0SGirish Moodalbail return (IPADM_SUCCESS); 18816e91bba0SGirish Moodalbail } 18826e91bba0SGirish Moodalbail 18836e91bba0SGirish Moodalbail /* 18846e91bba0SGirish Moodalbail * Sets the dhcp parameter `ipadm_wait' in the address object `ipaddr'. 18856e91bba0SGirish Moodalbail * This field is used during the address creation with address type 18866e91bba0SGirish Moodalbail * IPADM_ADDR_DHCP. It specifies how long the API ipadm_create_addr() 18876e91bba0SGirish Moodalbail * should wait before returning while the dhcp address is being acquired 18886e91bba0SGirish Moodalbail * by the dhcpagent. 18896e91bba0SGirish Moodalbail * Possible values: 18906e91bba0SGirish Moodalbail * - IPADM_DHCP_WAIT_FOREVER : Do not return until dhcpagent returns. 18916e91bba0SGirish Moodalbail * - IPADM_DHCP_WAIT_DEFAULT : Wait a default amount of time before returning. 18926e91bba0SGirish Moodalbail * - <integer> : Wait the specified number of seconds before returning. 18936e91bba0SGirish Moodalbail */ 18946e91bba0SGirish Moodalbail ipadm_status_t 18956e91bba0SGirish Moodalbail ipadm_set_wait_time(ipadm_addrobj_t ipaddr, int32_t wait) 18966e91bba0SGirish Moodalbail { 18976e91bba0SGirish Moodalbail if (ipaddr == NULL || ipaddr->ipadm_atype != IPADM_ADDR_DHCP) 18986e91bba0SGirish Moodalbail return (IPADM_INVALID_ARG); 18996e91bba0SGirish Moodalbail ipaddr->ipadm_wait = wait; 19006e91bba0SGirish Moodalbail return (IPADM_SUCCESS); 19016e91bba0SGirish Moodalbail } 19026e91bba0SGirish Moodalbail 19036e91bba0SGirish Moodalbail /* 19046e91bba0SGirish Moodalbail * Creates a placeholder for the `ipadm_aobjname' in the ipmgmtd `aobjmap'. 19056e91bba0SGirish Moodalbail * If the `aobjname' already exists in the daemon's `aobjmap' then 19066e91bba0SGirish Moodalbail * IPADM_ADDROBJ_EXISTS will be returned. 19076e91bba0SGirish Moodalbail * 19086e91bba0SGirish Moodalbail * If the libipadm consumer set `ipaddr.ipadm_aobjname[0]' to `\0', then the 19096e91bba0SGirish Moodalbail * daemon will generate an `aobjname' for the given `ipaddr'. 19106e91bba0SGirish Moodalbail */ 19116e91bba0SGirish Moodalbail ipadm_status_t 19126e91bba0SGirish Moodalbail i_ipadm_lookupadd_addrobj(ipadm_handle_t iph, ipadm_addrobj_t ipaddr) 19136e91bba0SGirish Moodalbail { 19146e91bba0SGirish Moodalbail ipmgmt_aobjop_arg_t larg; 19156e91bba0SGirish Moodalbail ipmgmt_aobjop_rval_t rval, *rvalp; 19166e91bba0SGirish Moodalbail int err; 19176e91bba0SGirish Moodalbail 19186e91bba0SGirish Moodalbail bzero(&larg, sizeof (larg)); 19196e91bba0SGirish Moodalbail larg.ia_cmd = IPMGMT_CMD_ADDROBJ_LOOKUPADD; 19206e91bba0SGirish Moodalbail (void) strlcpy(larg.ia_aobjname, ipaddr->ipadm_aobjname, 19216e91bba0SGirish Moodalbail sizeof (larg.ia_aobjname)); 19226e91bba0SGirish Moodalbail (void) strlcpy(larg.ia_ifname, ipaddr->ipadm_ifname, 19236e91bba0SGirish Moodalbail sizeof (larg.ia_ifname)); 19246e91bba0SGirish Moodalbail larg.ia_family = ipaddr->ipadm_af; 1925ec3706caSVasumathi Sundaram larg.ia_atype = ipaddr->ipadm_atype; 19266e91bba0SGirish Moodalbail 19276e91bba0SGirish Moodalbail rvalp = &rval; 19286e91bba0SGirish Moodalbail err = ipadm_door_call(iph, &larg, sizeof (larg), (void **)&rvalp, 19296e91bba0SGirish Moodalbail sizeof (rval), B_FALSE); 19306e91bba0SGirish Moodalbail if (err == 0 && ipaddr->ipadm_aobjname[0] == '\0') { 19316e91bba0SGirish Moodalbail /* copy the daemon generated `aobjname' into `ipadddr' */ 19326e91bba0SGirish Moodalbail (void) strlcpy(ipaddr->ipadm_aobjname, rval.ir_aobjname, 19336e91bba0SGirish Moodalbail sizeof (ipaddr->ipadm_aobjname)); 19346e91bba0SGirish Moodalbail } 19356e91bba0SGirish Moodalbail if (err == EEXIST) 19366e91bba0SGirish Moodalbail return (IPADM_ADDROBJ_EXISTS); 19376e91bba0SGirish Moodalbail return (ipadm_errno2status(err)); 19386e91bba0SGirish Moodalbail } 19396e91bba0SGirish Moodalbail 19406e91bba0SGirish Moodalbail /* 1941ec3706caSVasumathi Sundaram * Sets the logical interface number in the ipmgmtd's memory map for the 1942ec3706caSVasumathi Sundaram * address object `ipaddr'. If another address object has the same 1943ec3706caSVasumathi Sundaram * logical interface number, IPADM_ADDROBJ_EXISTS is returned. 1944ec3706caSVasumathi Sundaram */ 1945ec3706caSVasumathi Sundaram ipadm_status_t 1946ec3706caSVasumathi Sundaram i_ipadm_setlifnum_addrobj(ipadm_handle_t iph, ipadm_addrobj_t ipaddr) 1947ec3706caSVasumathi Sundaram { 1948ec3706caSVasumathi Sundaram ipmgmt_aobjop_arg_t larg; 1949ec3706caSVasumathi Sundaram ipmgmt_retval_t rval, *rvalp; 1950ec3706caSVasumathi Sundaram int err; 1951ec3706caSVasumathi Sundaram 1952550b6e40SSowmini Varadhan if (iph->iph_flags & IPH_IPMGMTD) 1953550b6e40SSowmini Varadhan return (IPADM_SUCCESS); 1954550b6e40SSowmini Varadhan 1955ec3706caSVasumathi Sundaram bzero(&larg, sizeof (larg)); 1956ec3706caSVasumathi Sundaram larg.ia_cmd = IPMGMT_CMD_ADDROBJ_SETLIFNUM; 1957ec3706caSVasumathi Sundaram (void) strlcpy(larg.ia_aobjname, ipaddr->ipadm_aobjname, 1958ec3706caSVasumathi Sundaram sizeof (larg.ia_aobjname)); 1959ec3706caSVasumathi Sundaram larg.ia_lnum = ipaddr->ipadm_lifnum; 1960ec3706caSVasumathi Sundaram (void) strlcpy(larg.ia_ifname, ipaddr->ipadm_ifname, 1961ec3706caSVasumathi Sundaram sizeof (larg.ia_ifname)); 1962ec3706caSVasumathi Sundaram larg.ia_family = ipaddr->ipadm_af; 1963ec3706caSVasumathi Sundaram 1964ec3706caSVasumathi Sundaram rvalp = &rval; 1965ec3706caSVasumathi Sundaram err = ipadm_door_call(iph, &larg, sizeof (larg), (void **)&rvalp, 1966ec3706caSVasumathi Sundaram sizeof (rval), B_FALSE); 1967ec3706caSVasumathi Sundaram if (err == EEXIST) 1968ec3706caSVasumathi Sundaram return (IPADM_ADDROBJ_EXISTS); 1969ec3706caSVasumathi Sundaram return (ipadm_errno2status(err)); 1970ec3706caSVasumathi Sundaram } 1971ec3706caSVasumathi Sundaram 1972ec3706caSVasumathi Sundaram /* 19736e91bba0SGirish Moodalbail * Creates the IPv4 or IPv6 address in the nvlist `nvl' on the interface 19746e91bba0SGirish Moodalbail * `ifname'. If a hostname is present, it is resolved before the address 19756e91bba0SGirish Moodalbail * is created. 19766e91bba0SGirish Moodalbail */ 19776e91bba0SGirish Moodalbail ipadm_status_t 19786e91bba0SGirish Moodalbail i_ipadm_enable_static(ipadm_handle_t iph, const char *ifname, nvlist_t *nvl, 19796e91bba0SGirish Moodalbail sa_family_t af) 19806e91bba0SGirish Moodalbail { 19816e91bba0SGirish Moodalbail char *prefixlenstr = NULL; 19826e91bba0SGirish Moodalbail char *upstr = NULL; 19836e91bba0SGirish Moodalbail char *sname = NULL, *dname = NULL; 19846e91bba0SGirish Moodalbail struct ipadm_addrobj_s ipaddr; 19856e91bba0SGirish Moodalbail char *aobjname = NULL; 19866e91bba0SGirish Moodalbail nvlist_t *nvaddr = NULL; 19876e91bba0SGirish Moodalbail nvpair_t *nvp; 19886e91bba0SGirish Moodalbail char *cidraddr; 19896e91bba0SGirish Moodalbail char *name; 19906e91bba0SGirish Moodalbail ipadm_status_t status; 19916e91bba0SGirish Moodalbail int err = 0; 19926e91bba0SGirish Moodalbail uint32_t flags = IPADM_OPT_ACTIVE; 19936e91bba0SGirish Moodalbail 19946e91bba0SGirish Moodalbail /* retrieve the address information */ 19956e91bba0SGirish Moodalbail for (nvp = nvlist_next_nvpair(nvl, NULL); nvp != NULL; 19966e91bba0SGirish Moodalbail nvp = nvlist_next_nvpair(nvl, nvp)) { 19976e91bba0SGirish Moodalbail name = nvpair_name(nvp); 19986e91bba0SGirish Moodalbail if (strcmp(name, IPADM_NVP_IPV4ADDR) == 0 || 19996e91bba0SGirish Moodalbail strcmp(name, IPADM_NVP_IPV6ADDR) == 0) { 20006e91bba0SGirish Moodalbail err = nvpair_value_nvlist(nvp, &nvaddr); 20016e91bba0SGirish Moodalbail } else if (strcmp(name, IPADM_NVP_AOBJNAME) == 0) { 20026e91bba0SGirish Moodalbail err = nvpair_value_string(nvp, &aobjname); 20036e91bba0SGirish Moodalbail } else if (strcmp(name, IPADM_NVP_PREFIXLEN) == 0) { 20046e91bba0SGirish Moodalbail err = nvpair_value_string(nvp, &prefixlenstr); 20056e91bba0SGirish Moodalbail } else if (strcmp(name, "up") == 0) { 20066e91bba0SGirish Moodalbail err = nvpair_value_string(nvp, &upstr); 20076e91bba0SGirish Moodalbail } 20086e91bba0SGirish Moodalbail if (err != 0) 20096e91bba0SGirish Moodalbail return (ipadm_errno2status(err)); 20106e91bba0SGirish Moodalbail } 20116e91bba0SGirish Moodalbail for (nvp = nvlist_next_nvpair(nvaddr, NULL); nvp != NULL; 20126e91bba0SGirish Moodalbail nvp = nvlist_next_nvpair(nvaddr, nvp)) { 20136e91bba0SGirish Moodalbail name = nvpair_name(nvp); 20146e91bba0SGirish Moodalbail if (strcmp(name, IPADM_NVP_IPADDRHNAME) == 0) 20156e91bba0SGirish Moodalbail err = nvpair_value_string(nvp, &sname); 20166e91bba0SGirish Moodalbail else if (strcmp(name, IPADM_NVP_IPDADDRHNAME) == 0) 20176e91bba0SGirish Moodalbail err = nvpair_value_string(nvp, &dname); 20186e91bba0SGirish Moodalbail if (err != 0) 20196e91bba0SGirish Moodalbail return (ipadm_errno2status(err)); 20206e91bba0SGirish Moodalbail } 20216e91bba0SGirish Moodalbail 20226e91bba0SGirish Moodalbail if (strcmp(upstr, "yes") == 0) 20236e91bba0SGirish Moodalbail flags |= IPADM_OPT_UP; 20246e91bba0SGirish Moodalbail 20256e91bba0SGirish Moodalbail /* build the address object from the above information */ 20266e91bba0SGirish Moodalbail i_ipadm_init_addr(&ipaddr, ifname, aobjname, IPADM_ADDR_STATIC); 20276e91bba0SGirish Moodalbail if (prefixlenstr != NULL && atoi(prefixlenstr) > 0) { 20286e91bba0SGirish Moodalbail if (asprintf(&cidraddr, "%s/%s", sname, prefixlenstr) == -1) 20296e91bba0SGirish Moodalbail return (IPADM_NO_MEMORY); 20306e91bba0SGirish Moodalbail status = ipadm_set_addr(&ipaddr, cidraddr, af); 20316e91bba0SGirish Moodalbail free(cidraddr); 20326e91bba0SGirish Moodalbail } else { 20336e91bba0SGirish Moodalbail status = ipadm_set_addr(&ipaddr, sname, af); 20346e91bba0SGirish Moodalbail } 20356e91bba0SGirish Moodalbail if (status != IPADM_SUCCESS) 20366e91bba0SGirish Moodalbail return (status); 20376e91bba0SGirish Moodalbail 20386e91bba0SGirish Moodalbail if (dname != NULL) { 20396e91bba0SGirish Moodalbail status = ipadm_set_dst_addr(&ipaddr, dname, af); 20406e91bba0SGirish Moodalbail if (status != IPADM_SUCCESS) 20416e91bba0SGirish Moodalbail return (status); 20426e91bba0SGirish Moodalbail } 20436e91bba0SGirish Moodalbail return (i_ipadm_create_addr(iph, &ipaddr, flags)); 20446e91bba0SGirish Moodalbail } 20456e91bba0SGirish Moodalbail 20466e91bba0SGirish Moodalbail /* 20476e91bba0SGirish Moodalbail * Creates a dhcp address on the interface `ifname' based on the 20486e91bba0SGirish Moodalbail * IPADM_ADDR_DHCP address object parameters from the nvlist `nvl'. 20496e91bba0SGirish Moodalbail */ 20506e91bba0SGirish Moodalbail ipadm_status_t 20516e91bba0SGirish Moodalbail i_ipadm_enable_dhcp(ipadm_handle_t iph, const char *ifname, nvlist_t *nvl) 20526e91bba0SGirish Moodalbail { 20536e91bba0SGirish Moodalbail int32_t wait; 20546e91bba0SGirish Moodalbail boolean_t primary; 20556e91bba0SGirish Moodalbail nvlist_t *nvdhcp; 20566e91bba0SGirish Moodalbail nvpair_t *nvp; 20576e91bba0SGirish Moodalbail char *name; 20586e91bba0SGirish Moodalbail struct ipadm_addrobj_s ipaddr; 20596e91bba0SGirish Moodalbail char *aobjname; 20606e91bba0SGirish Moodalbail int err = 0; 20616e91bba0SGirish Moodalbail 20626e91bba0SGirish Moodalbail /* Extract the dhcp parameters */ 20636e91bba0SGirish Moodalbail for (nvp = nvlist_next_nvpair(nvl, NULL); nvp != NULL; 20646e91bba0SGirish Moodalbail nvp = nvlist_next_nvpair(nvl, nvp)) { 20656e91bba0SGirish Moodalbail name = nvpair_name(nvp); 20666e91bba0SGirish Moodalbail if (strcmp(name, IPADM_NVP_DHCP) == 0) 20676e91bba0SGirish Moodalbail err = nvpair_value_nvlist(nvp, &nvdhcp); 20686e91bba0SGirish Moodalbail else if (strcmp(name, IPADM_NVP_AOBJNAME) == 0) 20696e91bba0SGirish Moodalbail err = nvpair_value_string(nvp, &aobjname); 20706e91bba0SGirish Moodalbail if (err != 0) 20716e91bba0SGirish Moodalbail return (ipadm_errno2status(err)); 20726e91bba0SGirish Moodalbail } 20736e91bba0SGirish Moodalbail for (nvp = nvlist_next_nvpair(nvdhcp, NULL); nvp != NULL; 20746e91bba0SGirish Moodalbail nvp = nvlist_next_nvpair(nvdhcp, nvp)) { 20756e91bba0SGirish Moodalbail name = nvpair_name(nvp); 20766e91bba0SGirish Moodalbail if (strcmp(name, IPADM_NVP_WAIT) == 0) 20776e91bba0SGirish Moodalbail err = nvpair_value_int32(nvp, &wait); 20786e91bba0SGirish Moodalbail else if (strcmp(name, IPADM_NVP_PRIMARY) == 0) 20796e91bba0SGirish Moodalbail err = nvpair_value_boolean_value(nvp, &primary); 20806e91bba0SGirish Moodalbail if (err != 0) 20816e91bba0SGirish Moodalbail return (ipadm_errno2status(err)); 20826e91bba0SGirish Moodalbail } 20836e91bba0SGirish Moodalbail 20846e91bba0SGirish Moodalbail /* Build the address object */ 20856e91bba0SGirish Moodalbail i_ipadm_init_addr(&ipaddr, ifname, aobjname, IPADM_ADDR_DHCP); 20866e91bba0SGirish Moodalbail ipaddr.ipadm_primary = primary; 20876e91bba0SGirish Moodalbail if (iph->iph_flags & IPH_INIT) 20886e91bba0SGirish Moodalbail ipaddr.ipadm_wait = 0; 20896e91bba0SGirish Moodalbail else 20906e91bba0SGirish Moodalbail ipaddr.ipadm_wait = wait; 2091ec3706caSVasumathi Sundaram ipaddr.ipadm_af = AF_INET; 20926e91bba0SGirish Moodalbail return (i_ipadm_create_dhcp(iph, &ipaddr, IPADM_OPT_ACTIVE)); 20936e91bba0SGirish Moodalbail } 20946e91bba0SGirish Moodalbail 20956e91bba0SGirish Moodalbail /* 20966e91bba0SGirish Moodalbail * Creates auto-configured addresses on the interface `ifname' based on 20976e91bba0SGirish Moodalbail * the IPADM_ADDR_IPV6_ADDRCONF address object parameters from the nvlist `nvl'. 20986e91bba0SGirish Moodalbail */ 20996e91bba0SGirish Moodalbail ipadm_status_t 21006e91bba0SGirish Moodalbail i_ipadm_enable_addrconf(ipadm_handle_t iph, const char *ifname, nvlist_t *nvl) 21016e91bba0SGirish Moodalbail { 21026e91bba0SGirish Moodalbail struct ipadm_addrobj_s ipaddr; 21036e91bba0SGirish Moodalbail char *stateful = NULL, *stateless = NULL; 21046e91bba0SGirish Moodalbail uint_t n; 21056e91bba0SGirish Moodalbail uint8_t *addr6 = NULL; 21066e91bba0SGirish Moodalbail uint32_t intfidlen = 0; 21076e91bba0SGirish Moodalbail char *aobjname; 21086e91bba0SGirish Moodalbail nvlist_t *nvaddr; 21096e91bba0SGirish Moodalbail nvpair_t *nvp; 21106e91bba0SGirish Moodalbail char *name; 21116e91bba0SGirish Moodalbail int err = 0; 21126e91bba0SGirish Moodalbail 21136e91bba0SGirish Moodalbail /* Extract the parameters */ 21146e91bba0SGirish Moodalbail for (nvp = nvlist_next_nvpair(nvl, NULL); nvp != NULL; 21156e91bba0SGirish Moodalbail nvp = nvlist_next_nvpair(nvl, nvp)) { 21166e91bba0SGirish Moodalbail name = nvpair_name(nvp); 21176e91bba0SGirish Moodalbail if (strcmp(name, IPADM_NVP_INTFID) == 0) 21186e91bba0SGirish Moodalbail err = nvpair_value_nvlist(nvp, &nvaddr); 21196e91bba0SGirish Moodalbail else if (strcmp(name, IPADM_NVP_AOBJNAME) == 0) 21206e91bba0SGirish Moodalbail err = nvpair_value_string(nvp, &aobjname); 21216e91bba0SGirish Moodalbail if (err != 0) 21226e91bba0SGirish Moodalbail return (ipadm_errno2status(err)); 21236e91bba0SGirish Moodalbail } 21246e91bba0SGirish Moodalbail for (nvp = nvlist_next_nvpair(nvaddr, NULL); nvp != NULL; 21256e91bba0SGirish Moodalbail nvp = nvlist_next_nvpair(nvaddr, nvp)) { 21266e91bba0SGirish Moodalbail name = nvpair_name(nvp); 21276e91bba0SGirish Moodalbail if (strcmp(name, IPADM_NVP_IPNUMADDR) == 0) 21286e91bba0SGirish Moodalbail err = nvpair_value_uint8_array(nvp, &addr6, &n); 21296e91bba0SGirish Moodalbail if (strcmp(name, IPADM_NVP_PREFIXLEN) == 0) 21306e91bba0SGirish Moodalbail err = nvpair_value_uint32(nvp, &intfidlen); 21316e91bba0SGirish Moodalbail else if (strcmp(name, IPADM_NVP_STATELESS) == 0) 21326e91bba0SGirish Moodalbail err = nvpair_value_string(nvp, &stateless); 21336e91bba0SGirish Moodalbail else if (strcmp(name, IPADM_NVP_STATEFUL) == 0) 21346e91bba0SGirish Moodalbail err = nvpair_value_string(nvp, &stateful); 21356e91bba0SGirish Moodalbail if (err != 0) 21366e91bba0SGirish Moodalbail return (ipadm_errno2status(err)); 21376e91bba0SGirish Moodalbail } 21386e91bba0SGirish Moodalbail /* Build the address object. */ 21396e91bba0SGirish Moodalbail i_ipadm_init_addr(&ipaddr, ifname, aobjname, IPADM_ADDR_IPV6_ADDRCONF); 21406e91bba0SGirish Moodalbail if (intfidlen > 0) { 21416e91bba0SGirish Moodalbail ipaddr.ipadm_intfidlen = intfidlen; 21426e91bba0SGirish Moodalbail bcopy(addr6, &ipaddr.ipadm_intfid.sin6_addr.s6_addr, n); 21436e91bba0SGirish Moodalbail } 21446e91bba0SGirish Moodalbail ipaddr.ipadm_stateless = (strcmp(stateless, "yes") == 0); 21456e91bba0SGirish Moodalbail ipaddr.ipadm_stateful = (strcmp(stateful, "yes") == 0); 21466e91bba0SGirish Moodalbail return (i_ipadm_create_ipv6addrs(iph, &ipaddr, IPADM_OPT_ACTIVE)); 21476e91bba0SGirish Moodalbail } 21486e91bba0SGirish Moodalbail 21496e91bba0SGirish Moodalbail /* 21506e91bba0SGirish Moodalbail * Allocates `ipadm_addrobj_t' and populates the relevant member fields based on 21516e91bba0SGirish Moodalbail * the provided `type'. `aobjname' represents the address object name, which 21526e91bba0SGirish Moodalbail * is of the form `<ifname>/<addressname>'. 21536e91bba0SGirish Moodalbail * 21546e91bba0SGirish Moodalbail * The caller has to minimally provide <ifname>. If <addressname> is not 21556e91bba0SGirish Moodalbail * provided, then a default one will be generated by the API. 21566e91bba0SGirish Moodalbail */ 21576e91bba0SGirish Moodalbail ipadm_status_t 21586e91bba0SGirish Moodalbail ipadm_create_addrobj(ipadm_addr_type_t type, const char *aobjname, 21596e91bba0SGirish Moodalbail ipadm_addrobj_t *ipaddr) 21606e91bba0SGirish Moodalbail { 21616e91bba0SGirish Moodalbail ipadm_addrobj_t newaddr; 21626e91bba0SGirish Moodalbail ipadm_status_t status; 21636e91bba0SGirish Moodalbail char *aname, *cp; 21646e91bba0SGirish Moodalbail char ifname[IPADM_AOBJSIZ]; 21656e91bba0SGirish Moodalbail ifspec_t ifsp; 21666e91bba0SGirish Moodalbail 21676e91bba0SGirish Moodalbail if (ipaddr == NULL) 21686e91bba0SGirish Moodalbail return (IPADM_INVALID_ARG); 21696e91bba0SGirish Moodalbail *ipaddr = NULL; 21706e91bba0SGirish Moodalbail 21716e91bba0SGirish Moodalbail if (aobjname == NULL || aobjname[0] == '\0') 21726e91bba0SGirish Moodalbail return (IPADM_INVALID_ARG); 21736e91bba0SGirish Moodalbail 21746e91bba0SGirish Moodalbail if (strlcpy(ifname, aobjname, IPADM_AOBJSIZ) >= IPADM_AOBJSIZ) 21756e91bba0SGirish Moodalbail return (IPADM_INVALID_ARG); 21766e91bba0SGirish Moodalbail 21776e91bba0SGirish Moodalbail if ((aname = strchr(ifname, '/')) != NULL) 21786e91bba0SGirish Moodalbail *aname++ = '\0'; 21796e91bba0SGirish Moodalbail 21806e91bba0SGirish Moodalbail /* Check if the interface name is valid. */ 21816e91bba0SGirish Moodalbail if (!ifparse_ifspec(ifname, &ifsp)) 21826e91bba0SGirish Moodalbail return (IPADM_INVALID_ARG); 21836e91bba0SGirish Moodalbail 21846e91bba0SGirish Moodalbail /* Check if the given addrobj name is valid. */ 21856e91bba0SGirish Moodalbail if (aname != NULL && !i_ipadm_is_user_aobjname_valid(aname)) 21866e91bba0SGirish Moodalbail return (IPADM_INVALID_ARG); 21876e91bba0SGirish Moodalbail 21886e91bba0SGirish Moodalbail if ((newaddr = calloc(1, sizeof (struct ipadm_addrobj_s))) == NULL) 21896e91bba0SGirish Moodalbail return (IPADM_NO_MEMORY); 21906e91bba0SGirish Moodalbail 21916e91bba0SGirish Moodalbail /* 21926e91bba0SGirish Moodalbail * If the ifname has logical interface number, extract it and assign 21936e91bba0SGirish Moodalbail * it to `ipadm_lifnum'. Only applications with IPH_LEGACY set will do 21946e91bba0SGirish Moodalbail * this today. We will check for the validity later in 21956e91bba0SGirish Moodalbail * i_ipadm_validate_create_addr(). 21966e91bba0SGirish Moodalbail */ 21976e91bba0SGirish Moodalbail if (ifsp.ifsp_lunvalid) { 21986e91bba0SGirish Moodalbail newaddr->ipadm_lifnum = ifsp.ifsp_lun; 21996e91bba0SGirish Moodalbail cp = strchr(ifname, IPADM_LOGICAL_SEP); 22006e91bba0SGirish Moodalbail *cp = '\0'; 22016e91bba0SGirish Moodalbail } 22026e91bba0SGirish Moodalbail (void) strlcpy(newaddr->ipadm_ifname, ifname, 22036e91bba0SGirish Moodalbail sizeof (newaddr->ipadm_ifname)); 22046e91bba0SGirish Moodalbail 22056e91bba0SGirish Moodalbail if (aname != NULL) { 22066e91bba0SGirish Moodalbail (void) snprintf(newaddr->ipadm_aobjname, 22076e91bba0SGirish Moodalbail sizeof (newaddr->ipadm_aobjname), "%s/%s", ifname, aname); 22086e91bba0SGirish Moodalbail } 22096e91bba0SGirish Moodalbail 22106e91bba0SGirish Moodalbail switch (type) { 22116e91bba0SGirish Moodalbail case IPADM_ADDR_IPV6_ADDRCONF: 22126e91bba0SGirish Moodalbail newaddr->ipadm_intfidlen = 0; 22136e91bba0SGirish Moodalbail newaddr->ipadm_stateful = B_TRUE; 22146e91bba0SGirish Moodalbail newaddr->ipadm_stateless = B_TRUE; 22156e91bba0SGirish Moodalbail newaddr->ipadm_af = AF_INET6; 22166e91bba0SGirish Moodalbail break; 22176e91bba0SGirish Moodalbail 22186e91bba0SGirish Moodalbail case IPADM_ADDR_DHCP: 22196e91bba0SGirish Moodalbail newaddr->ipadm_primary = B_FALSE; 22206e91bba0SGirish Moodalbail newaddr->ipadm_wait = IPADM_DHCP_WAIT_DEFAULT; 22216e91bba0SGirish Moodalbail newaddr->ipadm_af = AF_INET; 22226e91bba0SGirish Moodalbail break; 22236e91bba0SGirish Moodalbail 22246e91bba0SGirish Moodalbail case IPADM_ADDR_STATIC: 22256e91bba0SGirish Moodalbail newaddr->ipadm_af = AF_UNSPEC; 22266e91bba0SGirish Moodalbail newaddr->ipadm_static_prefixlen = 0; 22276e91bba0SGirish Moodalbail break; 22288b88711aSGirish Moodalbail 22296e91bba0SGirish Moodalbail default: 22306e91bba0SGirish Moodalbail status = IPADM_INVALID_ARG; 22316e91bba0SGirish Moodalbail goto fail; 22326e91bba0SGirish Moodalbail } 22336e91bba0SGirish Moodalbail newaddr->ipadm_atype = type; 22346e91bba0SGirish Moodalbail *ipaddr = newaddr; 22356e91bba0SGirish Moodalbail return (IPADM_SUCCESS); 22366e91bba0SGirish Moodalbail fail: 22376e91bba0SGirish Moodalbail free(newaddr); 22386e91bba0SGirish Moodalbail return (status); 22396e91bba0SGirish Moodalbail } 22406e91bba0SGirish Moodalbail 22416e91bba0SGirish Moodalbail /* 2242f6da83d4SAnurag S. Maskey * Returns `aobjname' from the address object in `ipaddr'. 2243f6da83d4SAnurag S. Maskey */ 2244f6da83d4SAnurag S. Maskey ipadm_status_t 2245f6da83d4SAnurag S. Maskey ipadm_get_aobjname(const ipadm_addrobj_t ipaddr, char *aobjname, size_t len) 2246f6da83d4SAnurag S. Maskey { 2247f6da83d4SAnurag S. Maskey if (ipaddr == NULL || aobjname == NULL) 2248f6da83d4SAnurag S. Maskey return (IPADM_INVALID_ARG); 2249f6da83d4SAnurag S. Maskey if (strlcpy(aobjname, ipaddr->ipadm_aobjname, len) >= len) 2250f6da83d4SAnurag S. Maskey return (IPADM_INVALID_ARG); 2251f6da83d4SAnurag S. Maskey 2252f6da83d4SAnurag S. Maskey return (IPADM_SUCCESS); 2253f6da83d4SAnurag S. Maskey } 2254f6da83d4SAnurag S. Maskey 2255f6da83d4SAnurag S. Maskey /* 22566e91bba0SGirish Moodalbail * Frees the address object in `ipaddr'. 22576e91bba0SGirish Moodalbail */ 22586e91bba0SGirish Moodalbail void 22596e91bba0SGirish Moodalbail ipadm_destroy_addrobj(ipadm_addrobj_t ipaddr) 22606e91bba0SGirish Moodalbail { 22616e91bba0SGirish Moodalbail free(ipaddr); 22626e91bba0SGirish Moodalbail } 22636e91bba0SGirish Moodalbail 22646e91bba0SGirish Moodalbail /* 22656e91bba0SGirish Moodalbail * Retrieves the logical interface name from `ipaddr' and stores the 22666e91bba0SGirish Moodalbail * string in `lifname'. 22676e91bba0SGirish Moodalbail */ 22686e91bba0SGirish Moodalbail void 22696e91bba0SGirish Moodalbail i_ipadm_addrobj2lifname(ipadm_addrobj_t ipaddr, char *lifname, int lifnamesize) 22706e91bba0SGirish Moodalbail { 22716e91bba0SGirish Moodalbail if (ipaddr->ipadm_lifnum != 0) { 22726e91bba0SGirish Moodalbail (void) snprintf(lifname, lifnamesize, "%s:%d", 22736e91bba0SGirish Moodalbail ipaddr->ipadm_ifname, ipaddr->ipadm_lifnum); 22746e91bba0SGirish Moodalbail } else { 22756e91bba0SGirish Moodalbail (void) snprintf(lifname, lifnamesize, "%s", 22766e91bba0SGirish Moodalbail ipaddr->ipadm_ifname); 22776e91bba0SGirish Moodalbail } 22786e91bba0SGirish Moodalbail } 22796e91bba0SGirish Moodalbail 22806e91bba0SGirish Moodalbail /* 22816e91bba0SGirish Moodalbail * Checks if a non-zero static address is present on the 0th logical interface 22826e91bba0SGirish Moodalbail * of the given IPv4 or IPv6 physical interface. For an IPv4 interface, it 22836e91bba0SGirish Moodalbail * also checks if the interface is under DHCP control. If the condition is true, 22846e91bba0SGirish Moodalbail * the output argument `exists' will be set to B_TRUE. Otherwise, `exists' 22856e91bba0SGirish Moodalbail * is set to B_FALSE. 2286550b6e40SSowmini Varadhan * 2287550b6e40SSowmini Varadhan * Note that *exists will not be initialized if an error is encountered. 22886e91bba0SGirish Moodalbail */ 22896e91bba0SGirish Moodalbail static ipadm_status_t 22906e91bba0SGirish Moodalbail i_ipadm_addr_exists_on_if(ipadm_handle_t iph, const char *ifname, 22916e91bba0SGirish Moodalbail sa_family_t af, boolean_t *exists) 22926e91bba0SGirish Moodalbail { 22936e91bba0SGirish Moodalbail struct lifreq lifr; 22946e91bba0SGirish Moodalbail int sock; 22956e91bba0SGirish Moodalbail 22966e91bba0SGirish Moodalbail /* For IPH_LEGACY, a new logical interface will never be added. */ 22976e91bba0SGirish Moodalbail if (iph->iph_flags & IPH_LEGACY) { 22986e91bba0SGirish Moodalbail *exists = B_FALSE; 22996e91bba0SGirish Moodalbail return (IPADM_SUCCESS); 23006e91bba0SGirish Moodalbail } 23016e91bba0SGirish Moodalbail bzero(&lifr, sizeof (lifr)); 23026e91bba0SGirish Moodalbail (void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name)); 23036e91bba0SGirish Moodalbail if (af == AF_INET) { 23046e91bba0SGirish Moodalbail sock = iph->iph_sock; 23056e91bba0SGirish Moodalbail if (ioctl(sock, SIOCGLIFFLAGS, (caddr_t)&lifr) < 0) 23066e91bba0SGirish Moodalbail return (ipadm_errno2status(errno)); 23076e91bba0SGirish Moodalbail if (lifr.lifr_flags & IFF_DHCPRUNNING) { 23086e91bba0SGirish Moodalbail *exists = B_TRUE; 23096e91bba0SGirish Moodalbail return (IPADM_SUCCESS); 23106e91bba0SGirish Moodalbail } 23116e91bba0SGirish Moodalbail } else { 23126e91bba0SGirish Moodalbail sock = iph->iph_sock6; 23136e91bba0SGirish Moodalbail } 23146e91bba0SGirish Moodalbail if (ioctl(sock, SIOCGLIFADDR, (caddr_t)&lifr) < 0) 23156e91bba0SGirish Moodalbail return (ipadm_errno2status(errno)); 231664639aafSDarren Reed *exists = !sockaddrunspec((struct sockaddr *)&lifr.lifr_addr); 23176e91bba0SGirish Moodalbail 23186e91bba0SGirish Moodalbail return (IPADM_SUCCESS); 23196e91bba0SGirish Moodalbail } 23206e91bba0SGirish Moodalbail 23216e91bba0SGirish Moodalbail /* 2322ec3706caSVasumathi Sundaram * Adds a new logical interface in the kernel for interface 2323ec3706caSVasumathi Sundaram * `addr->ipadm_ifname', if there is a non-zero address on the 0th 2324ec3706caSVasumathi Sundaram * logical interface or if the 0th logical interface is under DHCP 2325ec3706caSVasumathi Sundaram * control. On success, it sets the lifnum in the address object `addr'. 2326ec3706caSVasumathi Sundaram */ 2327ec3706caSVasumathi Sundaram ipadm_status_t 2328ec3706caSVasumathi Sundaram i_ipadm_do_addif(ipadm_handle_t iph, ipadm_addrobj_t addr) 2329ec3706caSVasumathi Sundaram { 2330ec3706caSVasumathi Sundaram ipadm_status_t status; 2331ec3706caSVasumathi Sundaram boolean_t addif; 2332ec3706caSVasumathi Sundaram struct lifreq lifr; 2333ec3706caSVasumathi Sundaram int sock; 2334ec3706caSVasumathi Sundaram 2335ec3706caSVasumathi Sundaram addr->ipadm_lifnum = 0; 2336ec3706caSVasumathi Sundaram status = i_ipadm_addr_exists_on_if(iph, addr->ipadm_ifname, 2337ec3706caSVasumathi Sundaram addr->ipadm_af, &addif); 2338ec3706caSVasumathi Sundaram if (status != IPADM_SUCCESS) 2339ec3706caSVasumathi Sundaram return (status); 2340ec3706caSVasumathi Sundaram if (addif) { 2341ec3706caSVasumathi Sundaram /* 2342ec3706caSVasumathi Sundaram * If there is an address on 0th logical interface, 2343ec3706caSVasumathi Sundaram * add a new logical interface. 2344ec3706caSVasumathi Sundaram */ 2345ec3706caSVasumathi Sundaram bzero(&lifr, sizeof (lifr)); 2346ec3706caSVasumathi Sundaram (void) strlcpy(lifr.lifr_name, addr->ipadm_ifname, 2347ec3706caSVasumathi Sundaram sizeof (lifr.lifr_name)); 2348ec3706caSVasumathi Sundaram sock = (addr->ipadm_af == AF_INET ? iph->iph_sock : 2349ec3706caSVasumathi Sundaram iph->iph_sock6); 2350ec3706caSVasumathi Sundaram if (ioctl(sock, SIOCLIFADDIF, (caddr_t)&lifr) < 0) 2351ec3706caSVasumathi Sundaram return (ipadm_errno2status(errno)); 2352ec3706caSVasumathi Sundaram addr->ipadm_lifnum = i_ipadm_get_lnum(lifr.lifr_name); 2353ec3706caSVasumathi Sundaram } 2354ec3706caSVasumathi Sundaram return (IPADM_SUCCESS); 2355ec3706caSVasumathi Sundaram } 2356ec3706caSVasumathi Sundaram 2357ec3706caSVasumathi Sundaram /* 23586e91bba0SGirish Moodalbail * Reads all the address lines from the persistent DB into the nvlist `onvl', 23596e91bba0SGirish Moodalbail * when both `ifname' and `aobjname' are NULL. If an `ifname' is provided, 23606e91bba0SGirish Moodalbail * it returns all the addresses for the given interface `ifname'. 23616e91bba0SGirish Moodalbail * If an `aobjname' is specified, then the address line corresponding to 23626e91bba0SGirish Moodalbail * that name will be returned. 23636e91bba0SGirish Moodalbail */ 23646e91bba0SGirish Moodalbail static ipadm_status_t 23656e91bba0SGirish Moodalbail i_ipadm_get_db_addr(ipadm_handle_t iph, const char *ifname, 23666e91bba0SGirish Moodalbail const char *aobjname, nvlist_t **onvl) 23676e91bba0SGirish Moodalbail { 23686e91bba0SGirish Moodalbail ipmgmt_getaddr_arg_t garg; 23696e91bba0SGirish Moodalbail ipmgmt_get_rval_t *rvalp; 23706e91bba0SGirish Moodalbail int err; 23716e91bba0SGirish Moodalbail size_t nvlsize; 23726e91bba0SGirish Moodalbail char *nvlbuf; 23736e91bba0SGirish Moodalbail 23746e91bba0SGirish Moodalbail /* Populate the door_call argument structure */ 23756e91bba0SGirish Moodalbail bzero(&garg, sizeof (garg)); 23766e91bba0SGirish Moodalbail garg.ia_cmd = IPMGMT_CMD_GETADDR; 23776e91bba0SGirish Moodalbail if (aobjname != NULL) 23786e91bba0SGirish Moodalbail (void) strlcpy(garg.ia_aobjname, aobjname, 23796e91bba0SGirish Moodalbail sizeof (garg.ia_aobjname)); 23806e91bba0SGirish Moodalbail if (ifname != NULL) 23816e91bba0SGirish Moodalbail (void) strlcpy(garg.ia_ifname, ifname, sizeof (garg.ia_ifname)); 23826e91bba0SGirish Moodalbail 23836e91bba0SGirish Moodalbail rvalp = malloc(sizeof (ipmgmt_get_rval_t)); 23846e91bba0SGirish Moodalbail err = ipadm_door_call(iph, &garg, sizeof (garg), (void **)&rvalp, 23856e91bba0SGirish Moodalbail sizeof (*rvalp), B_TRUE); 23866e91bba0SGirish Moodalbail if (err == 0) { 23876e91bba0SGirish Moodalbail nvlsize = rvalp->ir_nvlsize; 23886e91bba0SGirish Moodalbail nvlbuf = (char *)rvalp + sizeof (ipmgmt_get_rval_t); 23896e91bba0SGirish Moodalbail err = nvlist_unpack(nvlbuf, nvlsize, onvl, NV_ENCODE_NATIVE); 23906e91bba0SGirish Moodalbail } 23916e91bba0SGirish Moodalbail free(rvalp); 23926e91bba0SGirish Moodalbail return (ipadm_errno2status(err)); 23936e91bba0SGirish Moodalbail } 23946e91bba0SGirish Moodalbail 23956e91bba0SGirish Moodalbail /* 23966e91bba0SGirish Moodalbail * Adds the IP address contained in the 'ipaddr' argument to the physical 23976e91bba0SGirish Moodalbail * interface represented by 'ifname' after doing the required validation. 23986e91bba0SGirish Moodalbail * If the interface does not exist, it is created before the address is 23996e91bba0SGirish Moodalbail * added. 24006e91bba0SGirish Moodalbail * 24016e91bba0SGirish Moodalbail * If IPH_LEGACY is set in iph_flags, flags has to be IPADM_OPT_ACTIVE 24026e91bba0SGirish Moodalbail * and a default addrobj name will be generated. Input `addr->ipadm_aobjname', 24036e91bba0SGirish Moodalbail * if provided, will be ignored and replaced with the newly generated name. 24046e91bba0SGirish Moodalbail * The interface name provided has to be a logical interface name that 24056e91bba0SGirish Moodalbail * already exists. No new logical interface will be added in this function. 2406f6da83d4SAnurag S. Maskey * 2407f6da83d4SAnurag S. Maskey * If IPADM_OPT_V46 is passed in the flags, then both IPv4 and IPv6 interfaces 2408f6da83d4SAnurag S. Maskey * are plumbed (if they haven't been already). Otherwise, just the interface 2409f6da83d4SAnurag S. Maskey * specified in `addr' is plumbed. 24106e91bba0SGirish Moodalbail */ 24116e91bba0SGirish Moodalbail ipadm_status_t 24126e91bba0SGirish Moodalbail ipadm_create_addr(ipadm_handle_t iph, ipadm_addrobj_t addr, uint32_t flags) 24136e91bba0SGirish Moodalbail { 24146e91bba0SGirish Moodalbail ipadm_status_t status; 24156e91bba0SGirish Moodalbail sa_family_t af; 24166e91bba0SGirish Moodalbail sa_family_t daf; 24176e91bba0SGirish Moodalbail sa_family_t other_af; 24186e91bba0SGirish Moodalbail boolean_t created_af = B_FALSE; 24196e91bba0SGirish Moodalbail boolean_t created_other_af = B_FALSE; 24206e91bba0SGirish Moodalbail ipadm_addr_type_t type; 24216e91bba0SGirish Moodalbail char *ifname = addr->ipadm_ifname; 24226e91bba0SGirish Moodalbail boolean_t legacy = (iph->iph_flags & IPH_LEGACY); 24236e91bba0SGirish Moodalbail boolean_t aobjfound; 24246e91bba0SGirish Moodalbail boolean_t is_6to4; 24256e91bba0SGirish Moodalbail struct lifreq lifr; 24266e91bba0SGirish Moodalbail uint64_t ifflags; 2427550b6e40SSowmini Varadhan boolean_t is_boot = (iph->iph_flags & IPH_IPMGMTD); 24286e91bba0SGirish Moodalbail 24296e91bba0SGirish Moodalbail /* check for solaris.network.interface.config authorization */ 24306e91bba0SGirish Moodalbail if (!ipadm_check_auth()) 24316e91bba0SGirish Moodalbail return (IPADM_EAUTH); 24326e91bba0SGirish Moodalbail 24336e91bba0SGirish Moodalbail /* Validate the addrobj. This also fills in addr->ipadm_ifname. */ 24346e91bba0SGirish Moodalbail status = i_ipadm_validate_create_addr(iph, addr, flags); 24356e91bba0SGirish Moodalbail if (status != IPADM_SUCCESS) 24366e91bba0SGirish Moodalbail return (status); 24376e91bba0SGirish Moodalbail 24386e91bba0SGirish Moodalbail /* 24396e91bba0SGirish Moodalbail * For Legacy case, check if an addrobj already exists for the 24406e91bba0SGirish Moodalbail * given logical interface name. If one does not exist, 24416e91bba0SGirish Moodalbail * a default name will be generated and added to the daemon's 24426e91bba0SGirish Moodalbail * aobjmap. 24436e91bba0SGirish Moodalbail */ 24446e91bba0SGirish Moodalbail if (legacy) { 24456e91bba0SGirish Moodalbail struct ipadm_addrobj_s ipaddr; 24466e91bba0SGirish Moodalbail 24476e91bba0SGirish Moodalbail ipaddr = *addr; 24486e91bba0SGirish Moodalbail status = i_ipadm_get_lif2addrobj(iph, &ipaddr); 24496e91bba0SGirish Moodalbail if (status == IPADM_SUCCESS) { 24506e91bba0SGirish Moodalbail aobjfound = B_TRUE; 24516e91bba0SGirish Moodalbail /* 24526e91bba0SGirish Moodalbail * With IPH_LEGACY, modifying an address that is not 24536e91bba0SGirish Moodalbail * a static address will return with an error. 24546e91bba0SGirish Moodalbail */ 24556e91bba0SGirish Moodalbail if (ipaddr.ipadm_atype != IPADM_ADDR_STATIC) 24566e91bba0SGirish Moodalbail return (IPADM_NOTSUP); 24576e91bba0SGirish Moodalbail /* 24586e91bba0SGirish Moodalbail * we found the addrobj in daemon, copy over the 24596e91bba0SGirish Moodalbail * aobjname to `addr'. 24606e91bba0SGirish Moodalbail */ 24616e91bba0SGirish Moodalbail (void) strlcpy(addr->ipadm_aobjname, 24626e91bba0SGirish Moodalbail ipaddr.ipadm_aobjname, IPADM_AOBJSIZ); 24636e91bba0SGirish Moodalbail } else if (status == IPADM_NOTFOUND) { 24646e91bba0SGirish Moodalbail aobjfound = B_FALSE; 24656e91bba0SGirish Moodalbail } else { 24666e91bba0SGirish Moodalbail return (status); 24676e91bba0SGirish Moodalbail } 24686e91bba0SGirish Moodalbail } 24696e91bba0SGirish Moodalbail 24706e91bba0SGirish Moodalbail af = addr->ipadm_af; 24716e91bba0SGirish Moodalbail /* 24726e91bba0SGirish Moodalbail * Create a placeholder for this address object in the daemon. 2473550b6e40SSowmini Varadhan * Skip this step if we are booting a zone (and therefore being called 2474550b6e40SSowmini Varadhan * from ipmgmtd itself), and, for IPH_LEGACY case if the 2475550b6e40SSowmini Varadhan * addrobj already exists. 2476550b6e40SSowmini Varadhan * 2477550b6e40SSowmini Varadhan * Note that the placeholder is not needed in the NGZ boot case, 2478550b6e40SSowmini Varadhan * when zoneadmd has itself applied the "allowed-ips" property to clamp 2479550b6e40SSowmini Varadhan * down any interface configuration, so the namespace for the interface 2480550b6e40SSowmini Varadhan * is fully controlled by the GZ. 24816e91bba0SGirish Moodalbail */ 2482550b6e40SSowmini Varadhan if (!is_boot && (!legacy || !aobjfound)) { 24836e91bba0SGirish Moodalbail status = i_ipadm_lookupadd_addrobj(iph, addr); 24846e91bba0SGirish Moodalbail if (status != IPADM_SUCCESS) 24856e91bba0SGirish Moodalbail return (status); 24866e91bba0SGirish Moodalbail } 24876e91bba0SGirish Moodalbail 24886e91bba0SGirish Moodalbail is_6to4 = i_ipadm_is_6to4(iph, ifname); 24896e91bba0SGirish Moodalbail /* Plumb the IP interfaces if necessary */ 24906e91bba0SGirish Moodalbail status = i_ipadm_create_if(iph, ifname, af, flags); 24916e91bba0SGirish Moodalbail if (status != IPADM_SUCCESS && status != IPADM_IF_EXISTS) { 24926e91bba0SGirish Moodalbail (void) i_ipadm_delete_addrobj(iph, addr, IPADM_OPT_ACTIVE); 24936e91bba0SGirish Moodalbail return (status); 24946e91bba0SGirish Moodalbail } 24956e91bba0SGirish Moodalbail if (status == IPADM_SUCCESS) 24966e91bba0SGirish Moodalbail created_af = B_TRUE; 2497f6da83d4SAnurag S. Maskey if (!is_6to4 && !legacy && (flags & IPADM_OPT_V46)) { 24986e91bba0SGirish Moodalbail other_af = (af == AF_INET ? AF_INET6 : AF_INET); 24996e91bba0SGirish Moodalbail status = i_ipadm_create_if(iph, ifname, other_af, flags); 25006e91bba0SGirish Moodalbail if (status != IPADM_SUCCESS && status != IPADM_IF_EXISTS) { 25016e91bba0SGirish Moodalbail (void) i_ipadm_delete_if(iph, ifname, af, flags); 25026e91bba0SGirish Moodalbail return (status); 25036e91bba0SGirish Moodalbail } 25046e91bba0SGirish Moodalbail if (status == IPADM_SUCCESS) 25056e91bba0SGirish Moodalbail created_other_af = B_TRUE; 25066e91bba0SGirish Moodalbail } 25076e91bba0SGirish Moodalbail 2508550b6e40SSowmini Varadhan /* 2509550b6e40SSowmini Varadhan * Some input validation based on the interface flags: 2510550b6e40SSowmini Varadhan * 1. in non-global zones, make sure that we are not persistently 2511550b6e40SSowmini Varadhan * creating addresses on interfaces that are acquiring 2512550b6e40SSowmini Varadhan * address from the global zone. 2513550b6e40SSowmini Varadhan * 2. Validate static addresses for IFF_POINTOPOINT interfaces. 2514550b6e40SSowmini Varadhan */ 25156e91bba0SGirish Moodalbail if (addr->ipadm_atype == IPADM_ADDR_STATIC) { 25166e91bba0SGirish Moodalbail status = i_ipadm_get_flags(iph, ifname, af, &ifflags); 25176e91bba0SGirish Moodalbail if (status != IPADM_SUCCESS) 25186e91bba0SGirish Moodalbail goto fail; 2519550b6e40SSowmini Varadhan 2520550b6e40SSowmini Varadhan if (iph->iph_zoneid != GLOBAL_ZONEID && 2521550b6e40SSowmini Varadhan (ifflags & IFF_L3PROTECT) && (flags & IPADM_OPT_PERSIST)) { 2522550b6e40SSowmini Varadhan status = IPADM_GZ_PERM; 2523550b6e40SSowmini Varadhan goto fail; 2524550b6e40SSowmini Varadhan } 25256e91bba0SGirish Moodalbail daf = addr->ipadm_static_dst_addr.ss_family; 25266e91bba0SGirish Moodalbail if (ifflags & IFF_POINTOPOINT) { 25276e91bba0SGirish Moodalbail if (is_6to4) { 25286e91bba0SGirish Moodalbail if (af != AF_INET6 || daf != AF_UNSPEC) { 25296e91bba0SGirish Moodalbail status = IPADM_INVALID_ARG; 25306e91bba0SGirish Moodalbail goto fail; 25316e91bba0SGirish Moodalbail } 25326e91bba0SGirish Moodalbail } else { 25336e91bba0SGirish Moodalbail if (daf != af) { 25346e91bba0SGirish Moodalbail status = IPADM_INVALID_ARG; 25356e91bba0SGirish Moodalbail goto fail; 25366e91bba0SGirish Moodalbail } 25376e91bba0SGirish Moodalbail /* Check for a valid dst address. */ 25386e91bba0SGirish Moodalbail if (!legacy && sockaddrunspec( 253964639aafSDarren Reed (struct sockaddr *) 25406e91bba0SGirish Moodalbail &addr->ipadm_static_dst_addr)) { 25416e91bba0SGirish Moodalbail status = IPADM_BAD_ADDR; 25426e91bba0SGirish Moodalbail goto fail; 25436e91bba0SGirish Moodalbail } 25446e91bba0SGirish Moodalbail } 25456e91bba0SGirish Moodalbail } else { 25466e91bba0SGirish Moodalbail /* 25476e91bba0SGirish Moodalbail * Disallow setting of dstaddr when the link is not 25486e91bba0SGirish Moodalbail * a point-to-point link. 25496e91bba0SGirish Moodalbail */ 25506e91bba0SGirish Moodalbail if (daf != AF_UNSPEC) 25516e91bba0SGirish Moodalbail return (IPADM_INVALID_ARG); 25526e91bba0SGirish Moodalbail } 25536e91bba0SGirish Moodalbail } 25546e91bba0SGirish Moodalbail 25556e91bba0SGirish Moodalbail /* 25566e91bba0SGirish Moodalbail * For 6to4 interfaces, kernel configures a default link-local 25576e91bba0SGirish Moodalbail * address. We need to replace it, if the caller has provided 25586e91bba0SGirish Moodalbail * an address that is different from the default link-local. 25596e91bba0SGirish Moodalbail */ 25606e91bba0SGirish Moodalbail if (status == IPADM_SUCCESS && is_6to4) { 25616e91bba0SGirish Moodalbail bzero(&lifr, sizeof (lifr)); 25626e91bba0SGirish Moodalbail (void) strlcpy(lifr.lifr_name, addr->ipadm_ifname, 25636e91bba0SGirish Moodalbail sizeof (lifr.lifr_name)); 25646e91bba0SGirish Moodalbail if (ioctl(iph->iph_sock6, SIOCGLIFADDR, &lifr) < 0) { 25656e91bba0SGirish Moodalbail status = ipadm_errno2status(errno); 25666e91bba0SGirish Moodalbail goto fail; 25676e91bba0SGirish Moodalbail } 25686e91bba0SGirish Moodalbail if (sockaddrcmp(&lifr.lifr_addr, &addr->ipadm_static_addr)) 25696e91bba0SGirish Moodalbail return (IPADM_SUCCESS); 25706e91bba0SGirish Moodalbail } 25716e91bba0SGirish Moodalbail 25726e91bba0SGirish Moodalbail /* Create the address. */ 25736e91bba0SGirish Moodalbail type = addr->ipadm_atype; 25746e91bba0SGirish Moodalbail switch (type) { 25756e91bba0SGirish Moodalbail case IPADM_ADDR_STATIC: 25766e91bba0SGirish Moodalbail status = i_ipadm_create_addr(iph, addr, flags); 25776e91bba0SGirish Moodalbail break; 25786e91bba0SGirish Moodalbail case IPADM_ADDR_DHCP: 25796e91bba0SGirish Moodalbail status = i_ipadm_create_dhcp(iph, addr, flags); 25806e91bba0SGirish Moodalbail break; 25816e91bba0SGirish Moodalbail case IPADM_ADDR_IPV6_ADDRCONF: 25826e91bba0SGirish Moodalbail status = i_ipadm_create_ipv6addrs(iph, addr, flags); 25836e91bba0SGirish Moodalbail break; 25846e91bba0SGirish Moodalbail default: 25856e91bba0SGirish Moodalbail status = IPADM_INVALID_ARG; 25866e91bba0SGirish Moodalbail break; 25876e91bba0SGirish Moodalbail } 25886e91bba0SGirish Moodalbail 25896e91bba0SGirish Moodalbail /* 25906e91bba0SGirish Moodalbail * If address was not created successfully, unplumb the interface 25916e91bba0SGirish Moodalbail * if it was plumbed implicitly in this function and remove the 25926e91bba0SGirish Moodalbail * addrobj created by the ipmgmtd daemon as a placeholder. 25936e91bba0SGirish Moodalbail * If IPH_LEGACY is set, then remove the addrobj only if it was 25946e91bba0SGirish Moodalbail * created in this function. 25956e91bba0SGirish Moodalbail */ 25966e91bba0SGirish Moodalbail fail: 25976e91bba0SGirish Moodalbail if (status != IPADM_DHCP_IPC_TIMEOUT && 25986e91bba0SGirish Moodalbail status != IPADM_SUCCESS) { 25996e91bba0SGirish Moodalbail if (!legacy) { 26006e91bba0SGirish Moodalbail if (created_af || created_other_af) { 26016e91bba0SGirish Moodalbail if (created_af) { 26026e91bba0SGirish Moodalbail (void) i_ipadm_delete_if(iph, ifname, 26036e91bba0SGirish Moodalbail af, flags); 26046e91bba0SGirish Moodalbail } 26056e91bba0SGirish Moodalbail if (created_other_af) { 26066e91bba0SGirish Moodalbail (void) i_ipadm_delete_if(iph, ifname, 26076e91bba0SGirish Moodalbail other_af, flags); 26086e91bba0SGirish Moodalbail } 26096e91bba0SGirish Moodalbail } else { 26106e91bba0SGirish Moodalbail (void) i_ipadm_delete_addrobj(iph, addr, flags); 26116e91bba0SGirish Moodalbail } 26126e91bba0SGirish Moodalbail } else if (!aobjfound) { 26136e91bba0SGirish Moodalbail (void) i_ipadm_delete_addrobj(iph, addr, flags); 26146e91bba0SGirish Moodalbail } 26156e91bba0SGirish Moodalbail } 26166e91bba0SGirish Moodalbail 26176e91bba0SGirish Moodalbail return (status); 26186e91bba0SGirish Moodalbail } 26196e91bba0SGirish Moodalbail 26206e91bba0SGirish Moodalbail /* 26216e91bba0SGirish Moodalbail * Creates the static address in `ipaddr' in kernel. After successfully 26226e91bba0SGirish Moodalbail * creating it, it updates the ipmgmtd daemon's aobjmap with the logical 26236e91bba0SGirish Moodalbail * interface information. 26246e91bba0SGirish Moodalbail */ 26256e91bba0SGirish Moodalbail static ipadm_status_t 26266e91bba0SGirish Moodalbail i_ipadm_create_addr(ipadm_handle_t iph, ipadm_addrobj_t ipaddr, uint32_t flags) 26276e91bba0SGirish Moodalbail { 26286e91bba0SGirish Moodalbail struct lifreq lifr; 26296e91bba0SGirish Moodalbail ipadm_status_t status = IPADM_SUCCESS; 26306e91bba0SGirish Moodalbail int sock; 26316e91bba0SGirish Moodalbail struct sockaddr_storage m, *mask = &m; 26326e91bba0SGirish Moodalbail const struct sockaddr_storage *addr = &ipaddr->ipadm_static_addr; 26336e91bba0SGirish Moodalbail const struct sockaddr_storage *daddr = &ipaddr->ipadm_static_dst_addr; 26346e91bba0SGirish Moodalbail sa_family_t af; 26356e91bba0SGirish Moodalbail boolean_t legacy = (iph->iph_flags & IPH_LEGACY); 26366e91bba0SGirish Moodalbail struct ipadm_addrobj_s legacy_addr; 26376e91bba0SGirish Moodalbail boolean_t default_prefixlen = B_FALSE; 2638550b6e40SSowmini Varadhan boolean_t is_boot; 26396e91bba0SGirish Moodalbail 2640550b6e40SSowmini Varadhan is_boot = ((iph->iph_flags & IPH_IPMGMTD) != 0); 26416e91bba0SGirish Moodalbail af = ipaddr->ipadm_af; 26426e91bba0SGirish Moodalbail sock = (af == AF_INET ? iph->iph_sock : iph->iph_sock6); 26436e91bba0SGirish Moodalbail 26446e91bba0SGirish Moodalbail /* If prefixlen was not provided, get default prefixlen */ 26456e91bba0SGirish Moodalbail if (ipaddr->ipadm_static_prefixlen == 0) { 26466e91bba0SGirish Moodalbail /* prefixlen was not provided, get default prefixlen */ 26476e91bba0SGirish Moodalbail status = i_ipadm_get_default_prefixlen( 26486e91bba0SGirish Moodalbail &ipaddr->ipadm_static_addr, 26496e91bba0SGirish Moodalbail &ipaddr->ipadm_static_prefixlen); 26506e91bba0SGirish Moodalbail if (status != IPADM_SUCCESS) 26516e91bba0SGirish Moodalbail return (status); 26526e91bba0SGirish Moodalbail default_prefixlen = B_TRUE; 26536e91bba0SGirish Moodalbail } 265464639aafSDarren Reed (void) plen2mask(ipaddr->ipadm_static_prefixlen, af, 265564639aafSDarren Reed (struct sockaddr *)mask); 26566e91bba0SGirish Moodalbail 26576e91bba0SGirish Moodalbail /* 2658ec3706caSVasumathi Sundaram * Create a new logical interface if needed; otherwise, just 2659ec3706caSVasumathi Sundaram * use the 0th logical interface. 26606e91bba0SGirish Moodalbail */ 2661ec3706caSVasumathi Sundaram retry: 2662ec3706caSVasumathi Sundaram if (!(iph->iph_flags & IPH_LEGACY)) { 2663ec3706caSVasumathi Sundaram status = i_ipadm_do_addif(iph, ipaddr); 26646e91bba0SGirish Moodalbail if (status != IPADM_SUCCESS) 26656e91bba0SGirish Moodalbail return (status); 26666e91bba0SGirish Moodalbail /* 2667ec3706caSVasumathi Sundaram * We don't have to set the lifnum for IPH_INIT case, because 2668ec3706caSVasumathi Sundaram * there is no placeholder created for the address object in 2669ec3706caSVasumathi Sundaram * this case. For IPH_LEGACY, we don't do this because the 2670ec3706caSVasumathi Sundaram * lifnum is given by the caller and it will be set in the 2671ec3706caSVasumathi Sundaram * end while we call the i_ipadm_addr_persist(). 26726e91bba0SGirish Moodalbail */ 2673ec3706caSVasumathi Sundaram if (!(iph->iph_flags & IPH_INIT)) { 2674ec3706caSVasumathi Sundaram status = i_ipadm_setlifnum_addrobj(iph, ipaddr); 2675ec3706caSVasumathi Sundaram if (status == IPADM_ADDROBJ_EXISTS) 2676ec3706caSVasumathi Sundaram goto retry; 2677ec3706caSVasumathi Sundaram if (status != IPADM_SUCCESS) 2678ec3706caSVasumathi Sundaram return (status); 2679ec3706caSVasumathi Sundaram } 26806e91bba0SGirish Moodalbail } 26816e91bba0SGirish Moodalbail i_ipadm_addrobj2lifname(ipaddr, lifr.lifr_name, 26826e91bba0SGirish Moodalbail sizeof (lifr.lifr_name)); 26836e91bba0SGirish Moodalbail lifr.lifr_addr = *mask; 26846e91bba0SGirish Moodalbail if (ioctl(sock, SIOCSLIFNETMASK, (caddr_t)&lifr) < 0) { 26856e91bba0SGirish Moodalbail status = ipadm_errno2status(errno); 26866e91bba0SGirish Moodalbail goto ret; 26876e91bba0SGirish Moodalbail } 26886e91bba0SGirish Moodalbail lifr.lifr_addr = *addr; 26896e91bba0SGirish Moodalbail if (ioctl(sock, SIOCSLIFADDR, (caddr_t)&lifr) < 0) { 26906e91bba0SGirish Moodalbail status = ipadm_errno2status(errno); 26916e91bba0SGirish Moodalbail goto ret; 26926e91bba0SGirish Moodalbail } 26936e91bba0SGirish Moodalbail /* Set the destination address, if one is given. */ 26946e91bba0SGirish Moodalbail if (daddr->ss_family != AF_UNSPEC) { 26956e91bba0SGirish Moodalbail lifr.lifr_addr = *daddr; 26966e91bba0SGirish Moodalbail if (ioctl(sock, SIOCSLIFDSTADDR, (caddr_t)&lifr) < 0) { 26976e91bba0SGirish Moodalbail status = ipadm_errno2status(errno); 26986e91bba0SGirish Moodalbail goto ret; 26996e91bba0SGirish Moodalbail } 27006e91bba0SGirish Moodalbail } 27016e91bba0SGirish Moodalbail 27026e91bba0SGirish Moodalbail if (flags & IPADM_OPT_UP) { 27036e91bba0SGirish Moodalbail status = i_ipadm_set_flags(iph, lifr.lifr_name, af, IFF_UP, 0); 27046e91bba0SGirish Moodalbail 27056e91bba0SGirish Moodalbail /* 27066e91bba0SGirish Moodalbail * IPADM_DAD_FOUND is a soft-error for create-addr. 27076e91bba0SGirish Moodalbail * No need to tear down the address. 27086e91bba0SGirish Moodalbail */ 27096e91bba0SGirish Moodalbail if (status == IPADM_DAD_FOUND) 27106e91bba0SGirish Moodalbail status = IPADM_SUCCESS; 27116e91bba0SGirish Moodalbail } 27126e91bba0SGirish Moodalbail 2713550b6e40SSowmini Varadhan if (status == IPADM_SUCCESS && !is_boot) { 27146e91bba0SGirish Moodalbail /* 27156e91bba0SGirish Moodalbail * For IPH_LEGACY, we might be modifying the address on 27166e91bba0SGirish Moodalbail * an address object that already exists e.g. by doing 27176e91bba0SGirish Moodalbail * "ifconfig bge0:1 <addr>; ifconfig bge0:1 <newaddr>" 27186e91bba0SGirish Moodalbail * So, we need to store the object only if it does not 27196e91bba0SGirish Moodalbail * already exist in ipmgmtd. 27206e91bba0SGirish Moodalbail */ 27216e91bba0SGirish Moodalbail if (legacy) { 27226e91bba0SGirish Moodalbail bzero(&legacy_addr, sizeof (legacy_addr)); 27236e91bba0SGirish Moodalbail (void) strlcpy(legacy_addr.ipadm_aobjname, 27246e91bba0SGirish Moodalbail ipaddr->ipadm_aobjname, 27256e91bba0SGirish Moodalbail sizeof (legacy_addr.ipadm_aobjname)); 27266e91bba0SGirish Moodalbail status = i_ipadm_get_addrobj(iph, &legacy_addr); 27276e91bba0SGirish Moodalbail if (status == IPADM_SUCCESS && 27286e91bba0SGirish Moodalbail legacy_addr.ipadm_lifnum >= 0) { 27296e91bba0SGirish Moodalbail return (status); 27306e91bba0SGirish Moodalbail } 27316e91bba0SGirish Moodalbail } 27326e91bba0SGirish Moodalbail status = i_ipadm_addr_persist(iph, ipaddr, default_prefixlen, 27336e91bba0SGirish Moodalbail flags); 27346e91bba0SGirish Moodalbail } 27356e91bba0SGirish Moodalbail ret: 27366e91bba0SGirish Moodalbail if (status != IPADM_SUCCESS && !legacy) 27376e91bba0SGirish Moodalbail (void) i_ipadm_delete_addr(iph, ipaddr); 27386e91bba0SGirish Moodalbail return (status); 27396e91bba0SGirish Moodalbail } 27406e91bba0SGirish Moodalbail 27416e91bba0SGirish Moodalbail /* 27426e91bba0SGirish Moodalbail * Removes the address object identified by `aobjname' from both active and 27436e91bba0SGirish Moodalbail * persistent configuration. The address object will be removed from only 27446e91bba0SGirish Moodalbail * active configuration if IPH_LEGACY is set in `iph->iph_flags'. 27456e91bba0SGirish Moodalbail * 27466e91bba0SGirish Moodalbail * If the address type is IPADM_ADDR_STATIC or IPADM_ADDR_DHCP, the address 27476e91bba0SGirish Moodalbail * in the address object will be removed from the physical interface. 27486e91bba0SGirish Moodalbail * If the address type is IPADM_ADDR_DHCP, the flag IPADM_OPT_RELEASE specifies 27496e91bba0SGirish Moodalbail * whether the lease should be released. If IPADM_OPT_RELEASE is not 2750f6da83d4SAnurag S. Maskey * specified, the lease will be dropped. This option is not supported 27516e91bba0SGirish Moodalbail * for other address types. 27526e91bba0SGirish Moodalbail * 27536e91bba0SGirish Moodalbail * If the address type is IPADM_ADDR_IPV6_ADDRCONF, the link-local address and 27546e91bba0SGirish Moodalbail * all the autoconfigured addresses will be removed. 27556e91bba0SGirish Moodalbail * Finally, the address object is also removed from ipmgmtd's aobjmap and from 27566e91bba0SGirish Moodalbail * the persistent DB. 27576e91bba0SGirish Moodalbail */ 27586e91bba0SGirish Moodalbail ipadm_status_t 27596e91bba0SGirish Moodalbail ipadm_delete_addr(ipadm_handle_t iph, const char *aobjname, uint32_t flags) 27606e91bba0SGirish Moodalbail { 27616e91bba0SGirish Moodalbail ipadm_status_t status; 27626e91bba0SGirish Moodalbail struct ipadm_addrobj_s ipaddr; 27636e91bba0SGirish Moodalbail boolean_t release = ((flags & IPADM_OPT_RELEASE) != 0); 27646e91bba0SGirish Moodalbail 27656e91bba0SGirish Moodalbail /* check for solaris.network.interface.config authorization */ 27666e91bba0SGirish Moodalbail if (!ipadm_check_auth()) 27676e91bba0SGirish Moodalbail return (IPADM_EAUTH); 27686e91bba0SGirish Moodalbail 27696e91bba0SGirish Moodalbail /* validate input */ 27706e91bba0SGirish Moodalbail if (flags == 0 || ((flags & IPADM_OPT_PERSIST) && 27716e91bba0SGirish Moodalbail !(flags & IPADM_OPT_ACTIVE)) || 27726e91bba0SGirish Moodalbail (flags & ~(IPADM_COMMON_OPT_MASK|IPADM_OPT_RELEASE))) { 27736e91bba0SGirish Moodalbail return (IPADM_INVALID_ARG); 27746e91bba0SGirish Moodalbail } 27756e91bba0SGirish Moodalbail bzero(&ipaddr, sizeof (ipaddr)); 27766e91bba0SGirish Moodalbail if (aobjname == NULL || strlcpy(ipaddr.ipadm_aobjname, aobjname, 27776e91bba0SGirish Moodalbail IPADM_AOBJSIZ) >= IPADM_AOBJSIZ) { 27786e91bba0SGirish Moodalbail return (IPADM_INVALID_ARG); 27796e91bba0SGirish Moodalbail } 27806e91bba0SGirish Moodalbail 27816e91bba0SGirish Moodalbail /* Retrieve the address object information from ipmgmtd. */ 27826e91bba0SGirish Moodalbail status = i_ipadm_get_addrobj(iph, &ipaddr); 27836e91bba0SGirish Moodalbail if (status != IPADM_SUCCESS) 27846e91bba0SGirish Moodalbail return (status); 27856e91bba0SGirish Moodalbail 27866e91bba0SGirish Moodalbail if (release && ipaddr.ipadm_atype != IPADM_ADDR_DHCP) 27876e91bba0SGirish Moodalbail return (IPADM_NOTSUP); 27886e91bba0SGirish Moodalbail /* 27896e91bba0SGirish Moodalbail * If requested to delete just from active config but the address 27906e91bba0SGirish Moodalbail * is not in active config, return error. 27916e91bba0SGirish Moodalbail */ 27926e91bba0SGirish Moodalbail if (!(ipaddr.ipadm_flags & IPMGMT_ACTIVE) && 27936e91bba0SGirish Moodalbail (flags & IPADM_OPT_ACTIVE) && !(flags & IPADM_OPT_PERSIST)) { 27946e91bba0SGirish Moodalbail return (IPADM_NOTFOUND); 27956e91bba0SGirish Moodalbail } 27966e91bba0SGirish Moodalbail 27976e91bba0SGirish Moodalbail /* 27986e91bba0SGirish Moodalbail * If address is present in active config, remove it from 27996e91bba0SGirish Moodalbail * kernel. 28006e91bba0SGirish Moodalbail */ 28016e91bba0SGirish Moodalbail if (ipaddr.ipadm_flags & IPMGMT_ACTIVE) { 28026e91bba0SGirish Moodalbail switch (ipaddr.ipadm_atype) { 28036e91bba0SGirish Moodalbail case IPADM_ADDR_STATIC: 28046e91bba0SGirish Moodalbail status = i_ipadm_delete_addr(iph, &ipaddr); 28056e91bba0SGirish Moodalbail break; 28066e91bba0SGirish Moodalbail case IPADM_ADDR_DHCP: 28076e91bba0SGirish Moodalbail status = i_ipadm_delete_dhcp(iph, &ipaddr, release); 28086e91bba0SGirish Moodalbail break; 28096e91bba0SGirish Moodalbail case IPADM_ADDR_IPV6_ADDRCONF: 28106e91bba0SGirish Moodalbail status = i_ipadm_delete_ipv6addrs(iph, &ipaddr); 28116e91bba0SGirish Moodalbail break; 28126e91bba0SGirish Moodalbail default: 28136e91bba0SGirish Moodalbail /* 28146e91bba0SGirish Moodalbail * This is the case of address object name residing in 28156e91bba0SGirish Moodalbail * daemon's aobjmap (added by ADDROBJ_LOOKUPADD). Fall 28166e91bba0SGirish Moodalbail * through and delete that address object. 28176e91bba0SGirish Moodalbail */ 28186e91bba0SGirish Moodalbail break; 28196e91bba0SGirish Moodalbail } 28206e91bba0SGirish Moodalbail 28216e91bba0SGirish Moodalbail /* 28226e91bba0SGirish Moodalbail * If the address was previously deleted from the active 28236e91bba0SGirish Moodalbail * config, we will get a IPADM_ENXIO from kernel. 28246e91bba0SGirish Moodalbail * We will still proceed and purge the address information 28256e91bba0SGirish Moodalbail * in the DB. 28266e91bba0SGirish Moodalbail */ 28276e91bba0SGirish Moodalbail if (status == IPADM_ENXIO) 28286e91bba0SGirish Moodalbail status = IPADM_SUCCESS; 28296e91bba0SGirish Moodalbail else if (status != IPADM_SUCCESS) 28306e91bba0SGirish Moodalbail return (status); 28316e91bba0SGirish Moodalbail } 28326e91bba0SGirish Moodalbail 28336e91bba0SGirish Moodalbail if (!(ipaddr.ipadm_flags & IPMGMT_PERSIST) && 28346e91bba0SGirish Moodalbail (flags & IPADM_OPT_PERSIST)) { 28356e91bba0SGirish Moodalbail flags &= ~IPADM_OPT_PERSIST; 28366e91bba0SGirish Moodalbail } 28376e91bba0SGirish Moodalbail status = i_ipadm_delete_addrobj(iph, &ipaddr, flags); 28386e91bba0SGirish Moodalbail if (status == IPADM_NOTFOUND) 28396e91bba0SGirish Moodalbail return (status); 28406e91bba0SGirish Moodalbail return (IPADM_SUCCESS); 28416e91bba0SGirish Moodalbail } 28426e91bba0SGirish Moodalbail 28436e91bba0SGirish Moodalbail /* 28446e91bba0SGirish Moodalbail * Starts the dhcpagent and sends it the message DHCP_START to start 28456e91bba0SGirish Moodalbail * configuring a dhcp address on the given interface in `addr'. 28466e91bba0SGirish Moodalbail * After making the dhcpagent request, it also updates the 28476e91bba0SGirish Moodalbail * address object information in ipmgmtd's aobjmap and creates an 28486e91bba0SGirish Moodalbail * entry in persistent DB if IPADM_OPT_PERSIST is set in `flags'. 28496e91bba0SGirish Moodalbail */ 28506e91bba0SGirish Moodalbail static ipadm_status_t 28516e91bba0SGirish Moodalbail i_ipadm_create_dhcp(ipadm_handle_t iph, ipadm_addrobj_t addr, uint32_t flags) 28526e91bba0SGirish Moodalbail { 28536e91bba0SGirish Moodalbail ipadm_status_t status; 28546e91bba0SGirish Moodalbail ipadm_status_t dh_status; 28556e91bba0SGirish Moodalbail 28566e91bba0SGirish Moodalbail if (dhcp_start_agent(DHCP_IPC_MAX_WAIT) == -1) 28576e91bba0SGirish Moodalbail return (IPADM_DHCP_START_ERROR); 28586e91bba0SGirish Moodalbail /* 2859ec3706caSVasumathi Sundaram * Create a new logical interface if needed; otherwise, just 2860ec3706caSVasumathi Sundaram * use the 0th logical interface. 28616e91bba0SGirish Moodalbail */ 2862ec3706caSVasumathi Sundaram retry: 2863ec3706caSVasumathi Sundaram status = i_ipadm_do_addif(iph, addr); 28646e91bba0SGirish Moodalbail if (status != IPADM_SUCCESS) 28656e91bba0SGirish Moodalbail return (status); 28666e91bba0SGirish Moodalbail /* 2867ec3706caSVasumathi Sundaram * We don't have to set the lifnum for IPH_INIT case, because 2868ec3706caSVasumathi Sundaram * there is no placeholder created for the address object in this 2869ec3706caSVasumathi Sundaram * case. 28706e91bba0SGirish Moodalbail */ 2871ec3706caSVasumathi Sundaram if (!(iph->iph_flags & IPH_INIT)) { 2872ec3706caSVasumathi Sundaram status = i_ipadm_setlifnum_addrobj(iph, addr); 2873ec3706caSVasumathi Sundaram if (status == IPADM_ADDROBJ_EXISTS) 2874ec3706caSVasumathi Sundaram goto retry; 2875ec3706caSVasumathi Sundaram if (status != IPADM_SUCCESS) 2876ec3706caSVasumathi Sundaram return (status); 28776e91bba0SGirish Moodalbail } 28786e91bba0SGirish Moodalbail /* Send DHCP_START to the dhcpagent. */ 28796e91bba0SGirish Moodalbail status = i_ipadm_op_dhcp(addr, DHCP_START, NULL); 28806e91bba0SGirish Moodalbail /* 28816e91bba0SGirish Moodalbail * We do not undo the create-addr operation for IPADM_DHCP_IPC_TIMEOUT 28826e91bba0SGirish Moodalbail * since it is only a soft error to indicate the caller that the lease 28836e91bba0SGirish Moodalbail * might be required after the function returns. 28846e91bba0SGirish Moodalbail */ 28856e91bba0SGirish Moodalbail if (status != IPADM_SUCCESS && status != IPADM_DHCP_IPC_TIMEOUT) 28866e91bba0SGirish Moodalbail goto fail; 28876e91bba0SGirish Moodalbail dh_status = status; 28886e91bba0SGirish Moodalbail 28896e91bba0SGirish Moodalbail /* Persist the address object information in ipmgmtd. */ 28906e91bba0SGirish Moodalbail status = i_ipadm_addr_persist(iph, addr, B_FALSE, flags); 28916e91bba0SGirish Moodalbail if (status != IPADM_SUCCESS) 28926e91bba0SGirish Moodalbail goto fail; 28936e91bba0SGirish Moodalbail 28946e91bba0SGirish Moodalbail return (dh_status); 28956e91bba0SGirish Moodalbail fail: 28966e91bba0SGirish Moodalbail /* In case of error, delete the dhcp address */ 28976e91bba0SGirish Moodalbail (void) i_ipadm_delete_dhcp(iph, addr, B_TRUE); 28986e91bba0SGirish Moodalbail return (status); 28996e91bba0SGirish Moodalbail } 29006e91bba0SGirish Moodalbail 29016e91bba0SGirish Moodalbail /* 29026e91bba0SGirish Moodalbail * Releases/drops the dhcp lease on the logical interface in the address 29036e91bba0SGirish Moodalbail * object `addr'. If `release' is set to B_FALSE, the lease will be dropped. 29046e91bba0SGirish Moodalbail */ 29056e91bba0SGirish Moodalbail static ipadm_status_t 29066e91bba0SGirish Moodalbail i_ipadm_delete_dhcp(ipadm_handle_t iph, ipadm_addrobj_t addr, boolean_t release) 29076e91bba0SGirish Moodalbail { 29086e91bba0SGirish Moodalbail ipadm_status_t status; 29096e91bba0SGirish Moodalbail int dherr; 29106e91bba0SGirish Moodalbail 29116e91bba0SGirish Moodalbail /* Send DHCP_RELEASE or DHCP_DROP to the dhcpagent */ 29126e91bba0SGirish Moodalbail if (release) { 29136e91bba0SGirish Moodalbail status = i_ipadm_op_dhcp(addr, DHCP_RELEASE, &dherr); 29146e91bba0SGirish Moodalbail /* 29156e91bba0SGirish Moodalbail * If no lease was obtained on the object, we should 29166e91bba0SGirish Moodalbail * drop the dhcp control on the interface. 29176e91bba0SGirish Moodalbail */ 29186e91bba0SGirish Moodalbail if (status != IPADM_SUCCESS && dherr == DHCP_IPC_E_OUTSTATE) 29196e91bba0SGirish Moodalbail status = i_ipadm_op_dhcp(addr, DHCP_DROP, NULL); 29206e91bba0SGirish Moodalbail } else { 29216e91bba0SGirish Moodalbail status = i_ipadm_op_dhcp(addr, DHCP_DROP, NULL); 29226e91bba0SGirish Moodalbail } 29236e91bba0SGirish Moodalbail if (status != IPADM_SUCCESS) 29246e91bba0SGirish Moodalbail return (status); 29256e91bba0SGirish Moodalbail 29266e91bba0SGirish Moodalbail /* Delete the logical interface */ 29276e91bba0SGirish Moodalbail if (addr->ipadm_lifnum != 0) { 29286e91bba0SGirish Moodalbail struct lifreq lifr; 29296e91bba0SGirish Moodalbail 29306e91bba0SGirish Moodalbail bzero(&lifr, sizeof (lifr)); 29316e91bba0SGirish Moodalbail i_ipadm_addrobj2lifname(addr, lifr.lifr_name, 29326e91bba0SGirish Moodalbail sizeof (lifr.lifr_name)); 29336e91bba0SGirish Moodalbail if (ioctl(iph->iph_sock, SIOCLIFREMOVEIF, (caddr_t)&lifr) < 0) 29346e91bba0SGirish Moodalbail return (ipadm_errno2status(errno)); 29356e91bba0SGirish Moodalbail } 29366e91bba0SGirish Moodalbail 29376e91bba0SGirish Moodalbail return (IPADM_SUCCESS); 29386e91bba0SGirish Moodalbail } 29396e91bba0SGirish Moodalbail 29406e91bba0SGirish Moodalbail /* 29416e91bba0SGirish Moodalbail * Communicates with the dhcpagent to send a dhcp message of type `type'. 29426e91bba0SGirish Moodalbail * It returns the dhcp error in `dhcperror' if a non-null pointer is provided 29436e91bba0SGirish Moodalbail * in `dhcperror'. 29446e91bba0SGirish Moodalbail */ 29456e91bba0SGirish Moodalbail static ipadm_status_t 29466e91bba0SGirish Moodalbail i_ipadm_op_dhcp(ipadm_addrobj_t addr, dhcp_ipc_type_t type, int *dhcperror) 29476e91bba0SGirish Moodalbail { 29486e91bba0SGirish Moodalbail dhcp_ipc_request_t *request; 29496e91bba0SGirish Moodalbail dhcp_ipc_reply_t *reply = NULL; 29506e91bba0SGirish Moodalbail char ifname[LIFNAMSIZ]; 29516e91bba0SGirish Moodalbail int error; 29526e91bba0SGirish Moodalbail int dhcp_timeout; 29536e91bba0SGirish Moodalbail 29546e91bba0SGirish Moodalbail /* Construct a message to the dhcpagent. */ 29556e91bba0SGirish Moodalbail bzero(&ifname, sizeof (ifname)); 29566e91bba0SGirish Moodalbail i_ipadm_addrobj2lifname(addr, ifname, sizeof (ifname)); 29576e91bba0SGirish Moodalbail if (addr->ipadm_primary) 29586e91bba0SGirish Moodalbail type |= DHCP_PRIMARY; 29596e91bba0SGirish Moodalbail request = dhcp_ipc_alloc_request(type, ifname, NULL, 0, DHCP_TYPE_NONE); 29606e91bba0SGirish Moodalbail if (request == NULL) 29616e91bba0SGirish Moodalbail return (IPADM_NO_MEMORY); 29626e91bba0SGirish Moodalbail 29636e91bba0SGirish Moodalbail if (addr->ipadm_wait == IPADM_DHCP_WAIT_FOREVER) 29646e91bba0SGirish Moodalbail dhcp_timeout = DHCP_IPC_WAIT_FOREVER; 29656e91bba0SGirish Moodalbail else if (addr->ipadm_wait == IPADM_DHCP_WAIT_DEFAULT) 29666e91bba0SGirish Moodalbail dhcp_timeout = DHCP_IPC_WAIT_DEFAULT; 29676e91bba0SGirish Moodalbail else 29686e91bba0SGirish Moodalbail dhcp_timeout = addr->ipadm_wait; 29696e91bba0SGirish Moodalbail /* Send the message to dhcpagent. */ 29706e91bba0SGirish Moodalbail error = dhcp_ipc_make_request(request, &reply, dhcp_timeout); 29716e91bba0SGirish Moodalbail free(request); 29726e91bba0SGirish Moodalbail if (error == 0) { 29736e91bba0SGirish Moodalbail error = reply->return_code; 29746e91bba0SGirish Moodalbail free(reply); 29756e91bba0SGirish Moodalbail } 29766e91bba0SGirish Moodalbail if (error != 0) { 29776e91bba0SGirish Moodalbail if (dhcperror != NULL) 29786e91bba0SGirish Moodalbail *dhcperror = error; 29796e91bba0SGirish Moodalbail if (error != DHCP_IPC_E_TIMEOUT) 29806e91bba0SGirish Moodalbail return (IPADM_DHCP_IPC_ERROR); 29816e91bba0SGirish Moodalbail else if (dhcp_timeout != 0) 29826e91bba0SGirish Moodalbail return (IPADM_DHCP_IPC_TIMEOUT); 29836e91bba0SGirish Moodalbail } 29846e91bba0SGirish Moodalbail 29856e91bba0SGirish Moodalbail return (IPADM_SUCCESS); 29866e91bba0SGirish Moodalbail } 29876e91bba0SGirish Moodalbail 29886e91bba0SGirish Moodalbail /* 29896e91bba0SGirish Moodalbail * Returns the IP addresses of the specified interface in both the 29906e91bba0SGirish Moodalbail * active and the persistent configuration. If no 29916e91bba0SGirish Moodalbail * interface is specified, it returns all non-zero IP addresses 29926e91bba0SGirish Moodalbail * configured on all interfaces in active and persistent 29936e91bba0SGirish Moodalbail * configurations. 29946e91bba0SGirish Moodalbail * `addrinfo' will contain addresses that are 29956e91bba0SGirish Moodalbail * (1) in both active and persistent configuration (created persistently) 29966e91bba0SGirish Moodalbail * (2) only in active configuration (created temporarily) 29976e91bba0SGirish Moodalbail * (3) only in persistent configuration (disabled addresses) 29986e91bba0SGirish Moodalbail * 29996e91bba0SGirish Moodalbail * Address list that is returned by this function must be freed 30006e91bba0SGirish Moodalbail * using the ipadm_freeaddr_info() function. 30016e91bba0SGirish Moodalbail */ 30026e91bba0SGirish Moodalbail ipadm_status_t 30036e91bba0SGirish Moodalbail ipadm_addr_info(ipadm_handle_t iph, const char *ifname, 30046e91bba0SGirish Moodalbail ipadm_addr_info_t **addrinfo, uint32_t flags, int64_t lifc_flags) 30056e91bba0SGirish Moodalbail { 30066e91bba0SGirish Moodalbail ifspec_t ifsp; 30076e91bba0SGirish Moodalbail 30086e91bba0SGirish Moodalbail if (addrinfo == NULL || iph == NULL) 30096e91bba0SGirish Moodalbail return (IPADM_INVALID_ARG); 30106e91bba0SGirish Moodalbail if (ifname != NULL && 30116e91bba0SGirish Moodalbail (!ifparse_ifspec(ifname, &ifsp) || ifsp.ifsp_lunvalid)) { 30126e91bba0SGirish Moodalbail return (IPADM_INVALID_ARG); 30136e91bba0SGirish Moodalbail } 30146e91bba0SGirish Moodalbail return (i_ipadm_get_all_addr_info(iph, ifname, addrinfo, 30156e91bba0SGirish Moodalbail flags, lifc_flags)); 30166e91bba0SGirish Moodalbail } 30176e91bba0SGirish Moodalbail 30186e91bba0SGirish Moodalbail /* 30196e91bba0SGirish Moodalbail * Frees the structure allocated by ipadm_addr_info(). 30206e91bba0SGirish Moodalbail */ 30216e91bba0SGirish Moodalbail void 30226e91bba0SGirish Moodalbail ipadm_free_addr_info(ipadm_addr_info_t *ainfo) 30236e91bba0SGirish Moodalbail { 30246e91bba0SGirish Moodalbail freeifaddrs((struct ifaddrs *)ainfo); 30256e91bba0SGirish Moodalbail } 30266e91bba0SGirish Moodalbail 30276e91bba0SGirish Moodalbail /* 30286e91bba0SGirish Moodalbail * Makes a door call to ipmgmtd to update its `aobjmap' with the address 30296e91bba0SGirish Moodalbail * object in `ipaddr'. This door call also updates the persistent DB to 30306e91bba0SGirish Moodalbail * remember address object to be recreated on next reboot or on an 30316e91bba0SGirish Moodalbail * ipadm_enable_addr()/ipadm_enable_if() call. 30326e91bba0SGirish Moodalbail */ 30336e91bba0SGirish Moodalbail ipadm_status_t 30346e91bba0SGirish Moodalbail i_ipadm_addr_persist(ipadm_handle_t iph, const ipadm_addrobj_t ipaddr, 30356e91bba0SGirish Moodalbail boolean_t default_prefixlen, uint32_t flags) 30366e91bba0SGirish Moodalbail { 30376e91bba0SGirish Moodalbail char *aname = ipaddr->ipadm_aobjname; 30386e91bba0SGirish Moodalbail nvlist_t *nvl; 30396e91bba0SGirish Moodalbail int err = 0; 30406e91bba0SGirish Moodalbail ipadm_status_t status; 30416e91bba0SGirish Moodalbail char pval[MAXPROPVALLEN]; 30426e91bba0SGirish Moodalbail uint_t pflags = 0; 30436e91bba0SGirish Moodalbail ipadm_prop_desc_t *pdp = NULL; 30446e91bba0SGirish Moodalbail 30456e91bba0SGirish Moodalbail /* 30466e91bba0SGirish Moodalbail * Construct the nvl to send to the door. 30476e91bba0SGirish Moodalbail */ 30486e91bba0SGirish Moodalbail if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) 30496e91bba0SGirish Moodalbail return (IPADM_NO_MEMORY); 30506e91bba0SGirish Moodalbail if ((err = nvlist_add_string(nvl, IPADM_NVP_IFNAME, 30516e91bba0SGirish Moodalbail ipaddr->ipadm_ifname)) != 0 || 30526e91bba0SGirish Moodalbail (err = nvlist_add_string(nvl, IPADM_NVP_AOBJNAME, aname)) != 0 || 30536e91bba0SGirish Moodalbail (err = nvlist_add_int32(nvl, IPADM_NVP_LIFNUM, 30546e91bba0SGirish Moodalbail ipaddr->ipadm_lifnum)) != 0) { 30556e91bba0SGirish Moodalbail status = ipadm_errno2status(err); 30566e91bba0SGirish Moodalbail goto ret; 30576e91bba0SGirish Moodalbail } 30586e91bba0SGirish Moodalbail switch (ipaddr->ipadm_atype) { 30596e91bba0SGirish Moodalbail case IPADM_ADDR_STATIC: 30606e91bba0SGirish Moodalbail status = i_ipadm_add_ipaddr2nvl(nvl, ipaddr); 30616e91bba0SGirish Moodalbail if (status != IPADM_SUCCESS) 30626e91bba0SGirish Moodalbail goto ret; 30636e91bba0SGirish Moodalbail (void) snprintf(pval, sizeof (pval), "%d", 30646e91bba0SGirish Moodalbail ipaddr->ipadm_static_prefixlen); 30656e91bba0SGirish Moodalbail if (flags & IPADM_OPT_UP) 30666e91bba0SGirish Moodalbail err = nvlist_add_string(nvl, "up", "yes"); 30676e91bba0SGirish Moodalbail else 30686e91bba0SGirish Moodalbail err = nvlist_add_string(nvl, "up", "no"); 30696e91bba0SGirish Moodalbail status = ipadm_errno2status(err); 30706e91bba0SGirish Moodalbail break; 30716e91bba0SGirish Moodalbail case IPADM_ADDR_DHCP: 30726e91bba0SGirish Moodalbail status = i_ipadm_add_dhcp2nvl(nvl, ipaddr->ipadm_primary, 30736e91bba0SGirish Moodalbail ipaddr->ipadm_wait); 30746e91bba0SGirish Moodalbail break; 30756e91bba0SGirish Moodalbail case IPADM_ADDR_IPV6_ADDRCONF: 30766e91bba0SGirish Moodalbail status = i_ipadm_add_intfid2nvl(nvl, ipaddr); 30776e91bba0SGirish Moodalbail break; 30786e91bba0SGirish Moodalbail } 30796e91bba0SGirish Moodalbail if (status != IPADM_SUCCESS) 30806e91bba0SGirish Moodalbail goto ret; 30816e91bba0SGirish Moodalbail 30826e91bba0SGirish Moodalbail if (iph->iph_flags & IPH_INIT) { 30836e91bba0SGirish Moodalbail /* 30846e91bba0SGirish Moodalbail * IPMGMT_INIT tells the ipmgmtd to set both IPMGMT_ACTIVE and 30856e91bba0SGirish Moodalbail * IPMGMT_PERSIST on the address object in its `aobjmap'. 30866e91bba0SGirish Moodalbail * For the callers ipadm_enable_if() and ipadm_enable_addr(), 30876e91bba0SGirish Moodalbail * IPADM_OPT_PERSIST is not set in their flags. They send 30886e91bba0SGirish Moodalbail * IPH_INIT in iph_flags, so that the address object will be 30896e91bba0SGirish Moodalbail * set as both IPMGMT_ACTIVE and IPMGMT_PERSIST. 30906e91bba0SGirish Moodalbail */ 30916e91bba0SGirish Moodalbail pflags |= IPMGMT_INIT; 30926e91bba0SGirish Moodalbail } else { 30936e91bba0SGirish Moodalbail if (flags & IPADM_OPT_ACTIVE) 30946e91bba0SGirish Moodalbail pflags |= IPMGMT_ACTIVE; 30956e91bba0SGirish Moodalbail if (flags & IPADM_OPT_PERSIST) 30966e91bba0SGirish Moodalbail pflags |= IPMGMT_PERSIST; 30976e91bba0SGirish Moodalbail } 30986e91bba0SGirish Moodalbail status = i_ipadm_addr_persist_nvl(iph, nvl, pflags); 30996e91bba0SGirish Moodalbail /* 31006e91bba0SGirish Moodalbail * prefixlen is stored in a separate line in the DB and not along 31016e91bba0SGirish Moodalbail * with the address itself, since it is also an address property and 31026e91bba0SGirish Moodalbail * all address properties are stored in separate lines. We need to 31036e91bba0SGirish Moodalbail * persist the prefixlen by calling the function that persists 31046e91bba0SGirish Moodalbail * address properties. 31056e91bba0SGirish Moodalbail */ 31066e91bba0SGirish Moodalbail if (status == IPADM_SUCCESS && !default_prefixlen && 31076e91bba0SGirish Moodalbail ipaddr->ipadm_atype == IPADM_ADDR_STATIC && 31086e91bba0SGirish Moodalbail (flags & IPADM_OPT_PERSIST)) { 31096e91bba0SGirish Moodalbail for (pdp = ipadm_addrprop_table; pdp->ipd_name != NULL; pdp++) { 31106e91bba0SGirish Moodalbail if (strcmp("prefixlen", pdp->ipd_name) == 0) 31116e91bba0SGirish Moodalbail break; 31126e91bba0SGirish Moodalbail } 31136e91bba0SGirish Moodalbail assert(pdp != NULL); 31146e91bba0SGirish Moodalbail status = i_ipadm_persist_propval(iph, pdp, pval, ipaddr, flags); 31156e91bba0SGirish Moodalbail } 31166e91bba0SGirish Moodalbail ret: 31176e91bba0SGirish Moodalbail nvlist_free(nvl); 31186e91bba0SGirish Moodalbail return (status); 31196e91bba0SGirish Moodalbail } 31206e91bba0SGirish Moodalbail 31216e91bba0SGirish Moodalbail /* 31226e91bba0SGirish Moodalbail * Makes the door call to ipmgmtd to store the address object in the 31236e91bba0SGirish Moodalbail * nvlist `nvl'. 31246e91bba0SGirish Moodalbail */ 31256e91bba0SGirish Moodalbail static ipadm_status_t 31266e91bba0SGirish Moodalbail i_ipadm_addr_persist_nvl(ipadm_handle_t iph, nvlist_t *nvl, uint32_t flags) 31276e91bba0SGirish Moodalbail { 31286e91bba0SGirish Moodalbail char *buf = NULL, *nvlbuf = NULL; 31296e91bba0SGirish Moodalbail size_t nvlsize, bufsize; 31306e91bba0SGirish Moodalbail ipmgmt_setaddr_arg_t *sargp; 31316e91bba0SGirish Moodalbail int err; 31326e91bba0SGirish Moodalbail 31336e91bba0SGirish Moodalbail err = nvlist_pack(nvl, &nvlbuf, &nvlsize, NV_ENCODE_NATIVE, 0); 31346e91bba0SGirish Moodalbail if (err != 0) 31356e91bba0SGirish Moodalbail return (ipadm_errno2status(err)); 31366e91bba0SGirish Moodalbail bufsize = sizeof (*sargp) + nvlsize; 31376e91bba0SGirish Moodalbail buf = calloc(1, bufsize); 31386e91bba0SGirish Moodalbail sargp = (void *)buf; 31396e91bba0SGirish Moodalbail sargp->ia_cmd = IPMGMT_CMD_SETADDR; 31406e91bba0SGirish Moodalbail sargp->ia_flags = flags; 31416e91bba0SGirish Moodalbail sargp->ia_nvlsize = nvlsize; 31426e91bba0SGirish Moodalbail (void) bcopy(nvlbuf, buf + sizeof (*sargp), nvlsize); 31436e91bba0SGirish Moodalbail err = ipadm_door_call(iph, buf, bufsize, NULL, 0, B_FALSE); 31446e91bba0SGirish Moodalbail free(buf); 31456e91bba0SGirish Moodalbail free(nvlbuf); 31466e91bba0SGirish Moodalbail return (ipadm_errno2status(err)); 31476e91bba0SGirish Moodalbail } 31486e91bba0SGirish Moodalbail 31496e91bba0SGirish Moodalbail /* 31506e91bba0SGirish Moodalbail * Makes a door call to ipmgmtd to remove the address object in `ipaddr' 31516e91bba0SGirish Moodalbail * from its `aobjmap'. This door call also removes the address object and all 31526e91bba0SGirish Moodalbail * its properties from the persistent DB if IPADM_OPT_PERSIST is set in 31536e91bba0SGirish Moodalbail * `flags', so that the object will not be recreated on next reboot or on an 31546e91bba0SGirish Moodalbail * ipadm_enable_addr()/ipadm_enable_if() call. 31556e91bba0SGirish Moodalbail */ 31566e91bba0SGirish Moodalbail ipadm_status_t 31576e91bba0SGirish Moodalbail i_ipadm_delete_addrobj(ipadm_handle_t iph, const ipadm_addrobj_t ipaddr, 31586e91bba0SGirish Moodalbail uint32_t flags) 31596e91bba0SGirish Moodalbail { 31606e91bba0SGirish Moodalbail ipmgmt_addr_arg_t arg; 31616e91bba0SGirish Moodalbail int err; 31626e91bba0SGirish Moodalbail 31636e91bba0SGirish Moodalbail arg.ia_cmd = IPMGMT_CMD_RESETADDR; 31646e91bba0SGirish Moodalbail arg.ia_flags = 0; 31656e91bba0SGirish Moodalbail if (flags & IPADM_OPT_ACTIVE) 31666e91bba0SGirish Moodalbail arg.ia_flags |= IPMGMT_ACTIVE; 31676e91bba0SGirish Moodalbail if (flags & IPADM_OPT_PERSIST) 31686e91bba0SGirish Moodalbail arg.ia_flags |= IPMGMT_PERSIST; 31696e91bba0SGirish Moodalbail (void) strlcpy(arg.ia_aobjname, ipaddr->ipadm_aobjname, 31706e91bba0SGirish Moodalbail sizeof (arg.ia_aobjname)); 31716e91bba0SGirish Moodalbail arg.ia_lnum = ipaddr->ipadm_lifnum; 31726e91bba0SGirish Moodalbail err = ipadm_door_call(iph, &arg, sizeof (arg), NULL, 0, B_FALSE); 31736e91bba0SGirish Moodalbail return (ipadm_errno2status(err)); 31746e91bba0SGirish Moodalbail } 31756e91bba0SGirish Moodalbail 31766e91bba0SGirish Moodalbail /* 31776e91bba0SGirish Moodalbail * Checks if the caller is authorized for the up/down operation. 31786e91bba0SGirish Moodalbail * Retrieves the address object corresponding to `aobjname' from ipmgmtd 31796e91bba0SGirish Moodalbail * and retrieves the address flags for that object from kernel. 31806e91bba0SGirish Moodalbail * The arguments `ipaddr' and `ifflags' must be allocated by the caller. 31816e91bba0SGirish Moodalbail */ 31826e91bba0SGirish Moodalbail static ipadm_status_t 31836e91bba0SGirish Moodalbail i_ipadm_updown_common(ipadm_handle_t iph, const char *aobjname, 31846e91bba0SGirish Moodalbail ipadm_addrobj_t ipaddr, uint32_t ipadm_flags, uint64_t *ifflags) 31856e91bba0SGirish Moodalbail { 31866e91bba0SGirish Moodalbail ipadm_status_t status; 31876e91bba0SGirish Moodalbail char lifname[LIFNAMSIZ]; 31886e91bba0SGirish Moodalbail 31896e91bba0SGirish Moodalbail /* check for solaris.network.interface.config authorization */ 31906e91bba0SGirish Moodalbail if (!ipadm_check_auth()) 31916e91bba0SGirish Moodalbail return (IPADM_EAUTH); 31926e91bba0SGirish Moodalbail 31936e91bba0SGirish Moodalbail /* validate input */ 31946e91bba0SGirish Moodalbail if (aobjname == NULL || strlcpy(ipaddr->ipadm_aobjname, aobjname, 31956e91bba0SGirish Moodalbail IPADM_AOBJSIZ) >= IPADM_AOBJSIZ) { 31966e91bba0SGirish Moodalbail return (IPADM_INVALID_ARG); 31976e91bba0SGirish Moodalbail } 31986e91bba0SGirish Moodalbail 31996e91bba0SGirish Moodalbail /* Retrieve the address object information. */ 32006e91bba0SGirish Moodalbail status = i_ipadm_get_addrobj(iph, ipaddr); 32016e91bba0SGirish Moodalbail if (status != IPADM_SUCCESS) 32026e91bba0SGirish Moodalbail return (status); 32036e91bba0SGirish Moodalbail 32046e91bba0SGirish Moodalbail if (!(ipaddr->ipadm_flags & IPMGMT_ACTIVE)) 32056e91bba0SGirish Moodalbail return (IPADM_OP_DISABLE_OBJ); 32066e91bba0SGirish Moodalbail if ((ipadm_flags & IPADM_OPT_PERSIST) && 32076e91bba0SGirish Moodalbail !(ipaddr->ipadm_flags & IPMGMT_PERSIST)) 32086e91bba0SGirish Moodalbail return (IPADM_TEMPORARY_OBJ); 32096e91bba0SGirish Moodalbail if (ipaddr->ipadm_atype == IPADM_ADDR_IPV6_ADDRCONF || 32106e91bba0SGirish Moodalbail (ipaddr->ipadm_atype == IPADM_ADDR_DHCP && 32116e91bba0SGirish Moodalbail (ipadm_flags & IPADM_OPT_PERSIST))) 32126e91bba0SGirish Moodalbail return (IPADM_NOTSUP); 32136e91bba0SGirish Moodalbail 32146e91bba0SGirish Moodalbail i_ipadm_addrobj2lifname(ipaddr, lifname, sizeof (lifname)); 32156e91bba0SGirish Moodalbail return (i_ipadm_get_flags(iph, lifname, ipaddr->ipadm_af, ifflags)); 32166e91bba0SGirish Moodalbail } 32176e91bba0SGirish Moodalbail 32186e91bba0SGirish Moodalbail /* 32196e91bba0SGirish Moodalbail * Marks the address in the address object `aobjname' up. This operation is 32206e91bba0SGirish Moodalbail * not supported for an address object of type IPADM_ADDR_IPV6_ADDRCONF. 32216e91bba0SGirish Moodalbail * For an address object of type IPADM_ADDR_DHCP, this operation can 32226e91bba0SGirish Moodalbail * only be temporary and no updates will be made to the persistent DB. 32236e91bba0SGirish Moodalbail */ 32246e91bba0SGirish Moodalbail ipadm_status_t 32256e91bba0SGirish Moodalbail ipadm_up_addr(ipadm_handle_t iph, const char *aobjname, uint32_t ipadm_flags) 32266e91bba0SGirish Moodalbail { 32276e91bba0SGirish Moodalbail struct ipadm_addrobj_s ipaddr; 32286e91bba0SGirish Moodalbail ipadm_status_t status; 32296e91bba0SGirish Moodalbail uint64_t flags; 32306e91bba0SGirish Moodalbail char lifname[LIFNAMSIZ]; 32316e91bba0SGirish Moodalbail 32326e91bba0SGirish Moodalbail status = i_ipadm_updown_common(iph, aobjname, &ipaddr, ipadm_flags, 32336e91bba0SGirish Moodalbail &flags); 32346e91bba0SGirish Moodalbail if (status != IPADM_SUCCESS) 32356e91bba0SGirish Moodalbail return (status); 32366e91bba0SGirish Moodalbail if (flags & IFF_UP) 32376e91bba0SGirish Moodalbail goto persist; 32386e91bba0SGirish Moodalbail /* 32396e91bba0SGirish Moodalbail * If the address is already a duplicate, then refresh-addr 32406e91bba0SGirish Moodalbail * should be used to mark it up. 32416e91bba0SGirish Moodalbail */ 32426e91bba0SGirish Moodalbail if (flags & IFF_DUPLICATE) 32436e91bba0SGirish Moodalbail return (IPADM_DAD_FOUND); 32446e91bba0SGirish Moodalbail 32456e91bba0SGirish Moodalbail i_ipadm_addrobj2lifname(&ipaddr, lifname, sizeof (lifname)); 32466e91bba0SGirish Moodalbail status = i_ipadm_set_flags(iph, lifname, ipaddr.ipadm_af, IFF_UP, 0); 32476e91bba0SGirish Moodalbail if (status != IPADM_SUCCESS) 32486e91bba0SGirish Moodalbail return (status); 32496e91bba0SGirish Moodalbail 32506e91bba0SGirish Moodalbail persist: 32516e91bba0SGirish Moodalbail /* Update persistent DB. */ 32526e91bba0SGirish Moodalbail if (ipadm_flags & IPADM_OPT_PERSIST) { 32536e91bba0SGirish Moodalbail status = i_ipadm_persist_propval(iph, &up_addrprop, 32546e91bba0SGirish Moodalbail "yes", &ipaddr, 0); 32556e91bba0SGirish Moodalbail } 32566e91bba0SGirish Moodalbail 32576e91bba0SGirish Moodalbail return (status); 32586e91bba0SGirish Moodalbail } 32596e91bba0SGirish Moodalbail 32606e91bba0SGirish Moodalbail /* 32616e91bba0SGirish Moodalbail * Marks the address in the address object `aobjname' down. This operation is 32626e91bba0SGirish Moodalbail * not supported for an address object of type IPADM_ADDR_IPV6_ADDRCONF. 32636e91bba0SGirish Moodalbail * For an address object of type IPADM_ADDR_DHCP, this operation can 32646e91bba0SGirish Moodalbail * only be temporary and no updates will be made to the persistent DB. 32656e91bba0SGirish Moodalbail */ 32666e91bba0SGirish Moodalbail ipadm_status_t 32676e91bba0SGirish Moodalbail ipadm_down_addr(ipadm_handle_t iph, const char *aobjname, uint32_t ipadm_flags) 32686e91bba0SGirish Moodalbail { 32696e91bba0SGirish Moodalbail struct ipadm_addrobj_s ipaddr; 32706e91bba0SGirish Moodalbail ipadm_status_t status; 32716e91bba0SGirish Moodalbail struct lifreq lifr; 32726e91bba0SGirish Moodalbail uint64_t flags; 32736e91bba0SGirish Moodalbail 32746e91bba0SGirish Moodalbail status = i_ipadm_updown_common(iph, aobjname, &ipaddr, ipadm_flags, 32756e91bba0SGirish Moodalbail &flags); 32766e91bba0SGirish Moodalbail if (status != IPADM_SUCCESS) 32776e91bba0SGirish Moodalbail return (status); 32786e91bba0SGirish Moodalbail i_ipadm_addrobj2lifname(&ipaddr, lifr.lifr_name, 32796e91bba0SGirish Moodalbail sizeof (lifr.lifr_name)); 32806e91bba0SGirish Moodalbail if (flags & IFF_UP) { 32816e91bba0SGirish Moodalbail status = i_ipadm_set_flags(iph, lifr.lifr_name, 32826e91bba0SGirish Moodalbail ipaddr.ipadm_af, 0, IFF_UP); 32836e91bba0SGirish Moodalbail if (status != IPADM_SUCCESS) 32846e91bba0SGirish Moodalbail return (status); 32856e91bba0SGirish Moodalbail } else if (flags & IFF_DUPLICATE) { 32866e91bba0SGirish Moodalbail /* 32876e91bba0SGirish Moodalbail * Clear the IFF_DUPLICATE flag. 32886e91bba0SGirish Moodalbail */ 32896e91bba0SGirish Moodalbail if (ioctl(iph->iph_sock, SIOCGLIFADDR, &lifr) < 0) 32906e91bba0SGirish Moodalbail return (ipadm_errno2status(errno)); 32916e91bba0SGirish Moodalbail if (ioctl(iph->iph_sock, SIOCSLIFADDR, &lifr) < 0) 32926e91bba0SGirish Moodalbail return (ipadm_errno2status(errno)); 32936e91bba0SGirish Moodalbail } 32946e91bba0SGirish Moodalbail 32956e91bba0SGirish Moodalbail /* Update persistent DB */ 32966e91bba0SGirish Moodalbail if (ipadm_flags & IPADM_OPT_PERSIST) { 32976e91bba0SGirish Moodalbail status = i_ipadm_persist_propval(iph, &up_addrprop, 32986e91bba0SGirish Moodalbail "no", &ipaddr, 0); 32996e91bba0SGirish Moodalbail } 33006e91bba0SGirish Moodalbail 33016e91bba0SGirish Moodalbail return (status); 33026e91bba0SGirish Moodalbail } 33036e91bba0SGirish Moodalbail 33046e91bba0SGirish Moodalbail /* 33056e91bba0SGirish Moodalbail * Refreshes the address in the address object `aobjname'. If the address object 33066e91bba0SGirish Moodalbail * is of type IPADM_ADDR_STATIC, DAD is re-initiated on the address. If 33076e91bba0SGirish Moodalbail * `ipadm_flags' has IPADM_OPT_INFORM set, a DHCP_INFORM message is sent to the 33086e91bba0SGirish Moodalbail * dhcpagent for this static address. If the address object is of type 33096e91bba0SGirish Moodalbail * IPADM_ADDR_DHCP, a DHCP_EXTEND message is sent to the dhcpagent. 33106e91bba0SGirish Moodalbail * If a dhcp address has not yet been acquired, a DHCP_START is sent to the 33116e91bba0SGirish Moodalbail * dhcpagent. This operation is not supported for an address object of 33126e91bba0SGirish Moodalbail * type IPADM_ADDR_IPV6_ADDRCONF. 33136e91bba0SGirish Moodalbail */ 33146e91bba0SGirish Moodalbail ipadm_status_t 33156e91bba0SGirish Moodalbail ipadm_refresh_addr(ipadm_handle_t iph, const char *aobjname, 33166e91bba0SGirish Moodalbail uint32_t ipadm_flags) 33176e91bba0SGirish Moodalbail { 33186e91bba0SGirish Moodalbail ipadm_status_t status = IPADM_SUCCESS; 33196e91bba0SGirish Moodalbail uint64_t flags; 33206e91bba0SGirish Moodalbail struct ipadm_addrobj_s ipaddr; 33216e91bba0SGirish Moodalbail sa_family_t af; 33226e91bba0SGirish Moodalbail char lifname[LIFNAMSIZ]; 33236e91bba0SGirish Moodalbail boolean_t inform = 33246e91bba0SGirish Moodalbail ((ipadm_flags & IPADM_OPT_INFORM) != 0); 33256e91bba0SGirish Moodalbail int dherr; 33266e91bba0SGirish Moodalbail 33276e91bba0SGirish Moodalbail /* check for solaris.network.interface.config authorization */ 33286e91bba0SGirish Moodalbail if (!ipadm_check_auth()) 33296e91bba0SGirish Moodalbail return (IPADM_EAUTH); 33306e91bba0SGirish Moodalbail 33314630c8beSGirish Moodalbail bzero(&ipaddr, sizeof (ipaddr)); 33326e91bba0SGirish Moodalbail /* validate input */ 33336e91bba0SGirish Moodalbail if (aobjname == NULL || strlcpy(ipaddr.ipadm_aobjname, aobjname, 33346e91bba0SGirish Moodalbail IPADM_AOBJSIZ) >= IPADM_AOBJSIZ) { 33356e91bba0SGirish Moodalbail return (IPADM_INVALID_ARG); 33366e91bba0SGirish Moodalbail } 33376e91bba0SGirish Moodalbail 33386e91bba0SGirish Moodalbail /* Retrieve the address object information. */ 33396e91bba0SGirish Moodalbail status = i_ipadm_get_addrobj(iph, &ipaddr); 33406e91bba0SGirish Moodalbail if (status != IPADM_SUCCESS) 33416e91bba0SGirish Moodalbail return (status); 33426e91bba0SGirish Moodalbail 33436e91bba0SGirish Moodalbail if (!(ipaddr.ipadm_flags & IPMGMT_ACTIVE)) 33446e91bba0SGirish Moodalbail return (IPADM_OP_DISABLE_OBJ); 33456e91bba0SGirish Moodalbail 33466e91bba0SGirish Moodalbail if (i_ipadm_is_vni(ipaddr.ipadm_ifname)) 33476e91bba0SGirish Moodalbail return (IPADM_NOTSUP); 33486e91bba0SGirish Moodalbail if (inform && ipaddr.ipadm_atype != IPADM_ADDR_STATIC) 33496e91bba0SGirish Moodalbail return (IPADM_INVALID_ARG); 33506e91bba0SGirish Moodalbail af = ipaddr.ipadm_af; 33516e91bba0SGirish Moodalbail if (ipaddr.ipadm_atype == IPADM_ADDR_STATIC) { 33526e91bba0SGirish Moodalbail i_ipadm_addrobj2lifname(&ipaddr, lifname, sizeof (lifname)); 33536e91bba0SGirish Moodalbail status = i_ipadm_get_flags(iph, lifname, af, &flags); 33546e91bba0SGirish Moodalbail if (status != IPADM_SUCCESS) 33556e91bba0SGirish Moodalbail return (status); 33566e91bba0SGirish Moodalbail if (inform) { 33574630c8beSGirish Moodalbail if (dhcp_start_agent(DHCP_IPC_MAX_WAIT) == -1) 33584630c8beSGirish Moodalbail return (IPADM_DHCP_START_ERROR); 33594630c8beSGirish Moodalbail 33606e91bba0SGirish Moodalbail ipaddr.ipadm_wait = IPADM_DHCP_WAIT_DEFAULT; 33616e91bba0SGirish Moodalbail return (i_ipadm_op_dhcp(&ipaddr, DHCP_INFORM, NULL)); 33626e91bba0SGirish Moodalbail } 33636e91bba0SGirish Moodalbail if (!(flags & IFF_DUPLICATE)) 33646e91bba0SGirish Moodalbail return (IPADM_SUCCESS); 33656e91bba0SGirish Moodalbail status = i_ipadm_set_flags(iph, lifname, af, IFF_UP, 0); 33666e91bba0SGirish Moodalbail } else if (ipaddr.ipadm_atype == IPADM_ADDR_DHCP) { 33676e91bba0SGirish Moodalbail status = i_ipadm_op_dhcp(&ipaddr, DHCP_EXTEND, &dherr); 33686e91bba0SGirish Moodalbail /* 33696e91bba0SGirish Moodalbail * Restart the dhcp address negotiation with server if no 33706e91bba0SGirish Moodalbail * address has been acquired yet. 33716e91bba0SGirish Moodalbail */ 33726e91bba0SGirish Moodalbail if (status != IPADM_SUCCESS && dherr == DHCP_IPC_E_OUTSTATE) { 33736e91bba0SGirish Moodalbail ipaddr.ipadm_wait = IPADM_DHCP_WAIT_DEFAULT; 33746e91bba0SGirish Moodalbail status = i_ipadm_op_dhcp(&ipaddr, DHCP_START, NULL); 33756e91bba0SGirish Moodalbail } 33766e91bba0SGirish Moodalbail } else { 33776e91bba0SGirish Moodalbail status = IPADM_NOTSUP; 33786e91bba0SGirish Moodalbail } 33796e91bba0SGirish Moodalbail return (status); 33806e91bba0SGirish Moodalbail } 33816e91bba0SGirish Moodalbail 33826e91bba0SGirish Moodalbail /* 33836e91bba0SGirish Moodalbail * This is called from ipadm_create_addr() to validate the address parameters. 33846e91bba0SGirish Moodalbail * It does the following steps: 33856e91bba0SGirish Moodalbail * 1. Validates the interface name. 33866e91bba0SGirish Moodalbail * 2. Verifies that the interface is not an IPMP meta-interface or an 33876e91bba0SGirish Moodalbail * underlying interface. 33886e91bba0SGirish Moodalbail * 3. In case of a persistent operation, verifies that the interface 33896e91bba0SGirish Moodalbail * is persistent. Returns error if interface is not enabled but 33906e91bba0SGirish Moodalbail * is in persistent config. 33916e91bba0SGirish Moodalbail * 4. Verifies that the destination address is not set or the address type is 33926e91bba0SGirish Moodalbail * not DHCP or ADDRCONF when the interface is a loopback interface. 33936e91bba0SGirish Moodalbail * 5. Verifies that the address type is not DHCP or ADDRCONF when the interface 33946e91bba0SGirish Moodalbail * has IFF_VRRP interface flag set. 33956e91bba0SGirish Moodalbail */ 33966e91bba0SGirish Moodalbail static ipadm_status_t 33976e91bba0SGirish Moodalbail i_ipadm_validate_create_addr(ipadm_handle_t iph, ipadm_addrobj_t ipaddr, 33986e91bba0SGirish Moodalbail uint32_t flags) 33996e91bba0SGirish Moodalbail { 34006e91bba0SGirish Moodalbail sa_family_t af; 34016e91bba0SGirish Moodalbail sa_family_t other_af; 34026e91bba0SGirish Moodalbail char *ifname; 34036e91bba0SGirish Moodalbail ipadm_status_t status; 34046e91bba0SGirish Moodalbail boolean_t legacy = (iph->iph_flags & IPH_LEGACY); 34056e91bba0SGirish Moodalbail boolean_t islo, isvni; 34066e91bba0SGirish Moodalbail uint64_t ifflags = 0; 34076e91bba0SGirish Moodalbail boolean_t p_exists; 34086e91bba0SGirish Moodalbail boolean_t af_exists, other_af_exists, a_exists; 34096e91bba0SGirish Moodalbail 34106e91bba0SGirish Moodalbail if (ipaddr == NULL || flags == 0 || flags == IPADM_OPT_PERSIST || 3411f6da83d4SAnurag S. Maskey (flags & ~(IPADM_COMMON_OPT_MASK|IPADM_OPT_UP|IPADM_OPT_V46))) { 34126e91bba0SGirish Moodalbail return (IPADM_INVALID_ARG); 34136e91bba0SGirish Moodalbail } 34146e91bba0SGirish Moodalbail 34156e91bba0SGirish Moodalbail if (ipaddr->ipadm_af == AF_UNSPEC) 34166e91bba0SGirish Moodalbail return (IPADM_BAD_ADDR); 34176e91bba0SGirish Moodalbail 34186e91bba0SGirish Moodalbail if (!legacy && ipaddr->ipadm_lifnum != 0) 34196e91bba0SGirish Moodalbail return (IPADM_INVALID_ARG); 34206e91bba0SGirish Moodalbail 34216e91bba0SGirish Moodalbail if (legacy && ipaddr->ipadm_atype != IPADM_ADDR_STATIC) 34226e91bba0SGirish Moodalbail return (IPADM_NOTSUP); 34236e91bba0SGirish Moodalbail 34246e91bba0SGirish Moodalbail ifname = ipaddr->ipadm_ifname; 34256e91bba0SGirish Moodalbail 34266e91bba0SGirish Moodalbail if (i_ipadm_is_ipmp(iph, ifname) || i_ipadm_is_under_ipmp(iph, ifname)) 34276e91bba0SGirish Moodalbail return (IPADM_NOTSUP); 34286e91bba0SGirish Moodalbail 34296e91bba0SGirish Moodalbail af = ipaddr->ipadm_af; 34306e91bba0SGirish Moodalbail af_exists = ipadm_if_enabled(iph, ifname, af); 34316e91bba0SGirish Moodalbail /* 34326e91bba0SGirish Moodalbail * For legacy case, interfaces are not implicitly plumbed. We need to 34336e91bba0SGirish Moodalbail * check if the interface exists in the active configuration. 34346e91bba0SGirish Moodalbail */ 34356e91bba0SGirish Moodalbail if (legacy && !af_exists) 34366e91bba0SGirish Moodalbail return (IPADM_ENXIO); 34376e91bba0SGirish Moodalbail 34386e91bba0SGirish Moodalbail other_af = (af == AF_INET ? AF_INET6 : AF_INET); 34396e91bba0SGirish Moodalbail other_af_exists = ipadm_if_enabled(iph, ifname, other_af); 34406e91bba0SGirish Moodalbail /* 34416e91bba0SGirish Moodalbail * Check if one of the v4 or the v6 interfaces exists in the 34426e91bba0SGirish Moodalbail * active configuration. An interface is considered disabled only 34436e91bba0SGirish Moodalbail * if both v4 and v6 are not active. 34446e91bba0SGirish Moodalbail */ 34456e91bba0SGirish Moodalbail a_exists = (af_exists || other_af_exists); 34466e91bba0SGirish Moodalbail 34476e91bba0SGirish Moodalbail /* Check if interface exists in the persistent configuration. */ 34486e91bba0SGirish Moodalbail status = i_ipadm_if_pexists(iph, ifname, af, &p_exists); 34496e91bba0SGirish Moodalbail if (status != IPADM_SUCCESS) 34506e91bba0SGirish Moodalbail return (status); 34516e91bba0SGirish Moodalbail if (!a_exists && p_exists) 34526e91bba0SGirish Moodalbail return (IPADM_OP_DISABLE_OBJ); 34536e91bba0SGirish Moodalbail if ((flags & IPADM_OPT_PERSIST) && a_exists && !p_exists) { 34546e91bba0SGirish Moodalbail /* 34556e91bba0SGirish Moodalbail * If address has to be created persistently, 34566e91bba0SGirish Moodalbail * and the interface does not exist in the persistent 34576e91bba0SGirish Moodalbail * store but in active config, fail. 34586e91bba0SGirish Moodalbail */ 34596e91bba0SGirish Moodalbail return (IPADM_TEMPORARY_OBJ); 34606e91bba0SGirish Moodalbail } 34616e91bba0SGirish Moodalbail if (af_exists) { 34626e91bba0SGirish Moodalbail status = i_ipadm_get_flags(iph, ifname, af, &ifflags); 34636e91bba0SGirish Moodalbail if (status != IPADM_SUCCESS) 34646e91bba0SGirish Moodalbail return (status); 34656e91bba0SGirish Moodalbail } 34666e91bba0SGirish Moodalbail 34676e91bba0SGirish Moodalbail /* Perform validation steps (4) and (5) */ 34686e91bba0SGirish Moodalbail islo = i_ipadm_is_loopback(ifname); 34696e91bba0SGirish Moodalbail isvni = i_ipadm_is_vni(ifname); 34706e91bba0SGirish Moodalbail switch (ipaddr->ipadm_atype) { 34716e91bba0SGirish Moodalbail case IPADM_ADDR_STATIC: 34726e91bba0SGirish Moodalbail if ((islo || isvni) && ipaddr->ipadm_static_dname[0] != '\0') 34736e91bba0SGirish Moodalbail return (IPADM_INVALID_ARG); 34746e91bba0SGirish Moodalbail /* Check for a valid src address */ 347564639aafSDarren Reed if (!legacy && sockaddrunspec( 347664639aafSDarren Reed (struct sockaddr *)&ipaddr->ipadm_static_addr)) 34776e91bba0SGirish Moodalbail return (IPADM_BAD_ADDR); 34786e91bba0SGirish Moodalbail break; 34796e91bba0SGirish Moodalbail case IPADM_ADDR_DHCP: 34806e91bba0SGirish Moodalbail if (islo || (ifflags & IFF_VRRP)) 34816e91bba0SGirish Moodalbail return (IPADM_NOTSUP); 34826e91bba0SGirish Moodalbail break; 34836e91bba0SGirish Moodalbail case IPADM_ADDR_IPV6_ADDRCONF: 34846e91bba0SGirish Moodalbail if (islo || (ifflags & IFF_VRRP) || 34856e91bba0SGirish Moodalbail i_ipadm_is_6to4(iph, ifname)) { 34866e91bba0SGirish Moodalbail return (IPADM_NOTSUP); 34876e91bba0SGirish Moodalbail } 34886e91bba0SGirish Moodalbail break; 34896e91bba0SGirish Moodalbail default: 34906e91bba0SGirish Moodalbail return (IPADM_INVALID_ARG); 34916e91bba0SGirish Moodalbail } 34926e91bba0SGirish Moodalbail 34936e91bba0SGirish Moodalbail return (IPADM_SUCCESS); 34946e91bba0SGirish Moodalbail } 34956e91bba0SGirish Moodalbail 34966e91bba0SGirish Moodalbail ipadm_status_t 34976e91bba0SGirish Moodalbail i_ipadm_merge_prefixlen_from_nvl(nvlist_t *invl, nvlist_t *onvl, 34986e91bba0SGirish Moodalbail const char *aobjname) 34996e91bba0SGirish Moodalbail { 35006e91bba0SGirish Moodalbail nvpair_t *nvp, *prefixnvp; 35016e91bba0SGirish Moodalbail nvlist_t *tnvl; 35026e91bba0SGirish Moodalbail char *aname; 35036e91bba0SGirish Moodalbail int err; 35046e91bba0SGirish Moodalbail 35056e91bba0SGirish Moodalbail for (nvp = nvlist_next_nvpair(invl, NULL); nvp != NULL; 35066e91bba0SGirish Moodalbail nvp = nvlist_next_nvpair(invl, nvp)) { 35076e91bba0SGirish Moodalbail if (nvpair_value_nvlist(nvp, &tnvl) == 0 && 35086e91bba0SGirish Moodalbail nvlist_exists(tnvl, IPADM_NVP_PREFIXLEN) && 35096e91bba0SGirish Moodalbail nvlist_lookup_string(tnvl, IPADM_NVP_AOBJNAME, 35106e91bba0SGirish Moodalbail &aname) == 0 && strcmp(aname, aobjname) == 0) { 35116e91bba0SGirish Moodalbail /* prefixlen exists for given address object */ 35126e91bba0SGirish Moodalbail (void) nvlist_lookup_nvpair(tnvl, IPADM_NVP_PREFIXLEN, 35136e91bba0SGirish Moodalbail &prefixnvp); 35146e91bba0SGirish Moodalbail err = nvlist_add_nvpair(onvl, prefixnvp); 35156e91bba0SGirish Moodalbail if (err == 0) { 35166e91bba0SGirish Moodalbail err = nvlist_remove(invl, nvpair_name(nvp), 35176e91bba0SGirish Moodalbail nvpair_type(nvp)); 35186e91bba0SGirish Moodalbail } 35196e91bba0SGirish Moodalbail return (ipadm_errno2status(err)); 35206e91bba0SGirish Moodalbail } 35216e91bba0SGirish Moodalbail } 35226e91bba0SGirish Moodalbail return (IPADM_SUCCESS); 35236e91bba0SGirish Moodalbail } 35246e91bba0SGirish Moodalbail 35256e91bba0SGirish Moodalbail /* 35266e91bba0SGirish Moodalbail * Re-enables the address object `aobjname' based on the saved 35276e91bba0SGirish Moodalbail * configuration for `aobjname'. 35286e91bba0SGirish Moodalbail */ 35296e91bba0SGirish Moodalbail ipadm_status_t 35306e91bba0SGirish Moodalbail ipadm_enable_addr(ipadm_handle_t iph, const char *aobjname, uint32_t flags) 35316e91bba0SGirish Moodalbail { 35326e91bba0SGirish Moodalbail nvlist_t *addrnvl, *nvl; 35336e91bba0SGirish Moodalbail nvpair_t *nvp; 35346e91bba0SGirish Moodalbail ipadm_status_t status; 35356e91bba0SGirish Moodalbail struct ipadm_addrobj_s ipaddr; 35366e91bba0SGirish Moodalbail 35376e91bba0SGirish Moodalbail /* check for solaris.network.interface.config authorization */ 35386e91bba0SGirish Moodalbail if (!ipadm_check_auth()) 35396e91bba0SGirish Moodalbail return (IPADM_EAUTH); 35406e91bba0SGirish Moodalbail 35416e91bba0SGirish Moodalbail /* validate input */ 35426e91bba0SGirish Moodalbail if (flags & IPADM_OPT_PERSIST) 35436e91bba0SGirish Moodalbail return (IPADM_NOTSUP); 35446e91bba0SGirish Moodalbail if (aobjname == NULL || strlcpy(ipaddr.ipadm_aobjname, aobjname, 35456e91bba0SGirish Moodalbail IPADM_AOBJSIZ) >= IPADM_AOBJSIZ) { 35466e91bba0SGirish Moodalbail return (IPADM_INVALID_ARG); 35476e91bba0SGirish Moodalbail } 35486e91bba0SGirish Moodalbail 35496e91bba0SGirish Moodalbail /* Retrieve the address object information. */ 35506e91bba0SGirish Moodalbail status = i_ipadm_get_addrobj(iph, &ipaddr); 35516e91bba0SGirish Moodalbail if (status != IPADM_SUCCESS) 35526e91bba0SGirish Moodalbail return (status); 35536e91bba0SGirish Moodalbail if (ipaddr.ipadm_flags & IPMGMT_ACTIVE) 35546e91bba0SGirish Moodalbail return (IPADM_ADDROBJ_EXISTS); 35556e91bba0SGirish Moodalbail 35566e91bba0SGirish Moodalbail status = i_ipadm_get_db_addr(iph, NULL, aobjname, &addrnvl); 35576e91bba0SGirish Moodalbail if (status != IPADM_SUCCESS) 35586e91bba0SGirish Moodalbail return (status); 35596e91bba0SGirish Moodalbail 35606e91bba0SGirish Moodalbail assert(addrnvl != NULL); 35616e91bba0SGirish Moodalbail 35626e91bba0SGirish Moodalbail for (nvp = nvlist_next_nvpair(addrnvl, NULL); nvp != NULL; 35636e91bba0SGirish Moodalbail nvp = nvlist_next_nvpair(addrnvl, nvp)) { 35646e91bba0SGirish Moodalbail if (nvpair_value_nvlist(nvp, &nvl) != 0) 35656e91bba0SGirish Moodalbail continue; 35666e91bba0SGirish Moodalbail 35676e91bba0SGirish Moodalbail if (nvlist_exists(nvl, IPADM_NVP_IPV4ADDR) || 35686e91bba0SGirish Moodalbail nvlist_exists(nvl, IPADM_NVP_IPV6ADDR)) { 35696e91bba0SGirish Moodalbail status = i_ipadm_merge_prefixlen_from_nvl(addrnvl, nvl, 35706e91bba0SGirish Moodalbail aobjname); 35716e91bba0SGirish Moodalbail if (status != IPADM_SUCCESS) 35726e91bba0SGirish Moodalbail continue; 35736e91bba0SGirish Moodalbail } 35746e91bba0SGirish Moodalbail iph->iph_flags |= IPH_INIT; 35756e91bba0SGirish Moodalbail status = i_ipadm_init_addrobj(iph, nvl); 35766e91bba0SGirish Moodalbail iph->iph_flags &= ~IPH_INIT; 35776e91bba0SGirish Moodalbail if (status != IPADM_SUCCESS) 35786e91bba0SGirish Moodalbail break; 35796e91bba0SGirish Moodalbail } 35806e91bba0SGirish Moodalbail 35816e91bba0SGirish Moodalbail return (status); 35826e91bba0SGirish Moodalbail } 35836e91bba0SGirish Moodalbail 35846e91bba0SGirish Moodalbail /* 35856e91bba0SGirish Moodalbail * Disables the address object in `aobjname' from the active configuration. 35866e91bba0SGirish Moodalbail * Error code return values follow the model in ipadm_delete_addr(). 35876e91bba0SGirish Moodalbail */ 35886e91bba0SGirish Moodalbail ipadm_status_t 35896e91bba0SGirish Moodalbail ipadm_disable_addr(ipadm_handle_t iph, const char *aobjname, uint32_t flags) 35906e91bba0SGirish Moodalbail { 35916e91bba0SGirish Moodalbail /* validate input */ 35926e91bba0SGirish Moodalbail if (flags & IPADM_OPT_PERSIST) 35936e91bba0SGirish Moodalbail return (IPADM_NOTSUP); 35946e91bba0SGirish Moodalbail 35956e91bba0SGirish Moodalbail return (ipadm_delete_addr(iph, aobjname, IPADM_OPT_ACTIVE)); 35966e91bba0SGirish Moodalbail } 3597