xref: /titanic_50/usr/src/lib/libipadm/common/ipadm_addr.c (revision 299625c6492013aa7bd163862f0d181854f69b3c)
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
i_ipadm_init_addr(ipadm_addrobj_t ipaddr,const char * ifname,const char * aobjname,ipadm_addr_type_t atype)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
i_ipadm_pd2permstr(ipadm_prop_desc_t * pdp,char * buf,uint_t * bufsize)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
i_ipadm_get_addrobj(ipadm_handle_t iph,ipadm_addrobj_t ipaddr)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
i_ipadm_get_static_addr_db(ipadm_handle_t iph,ipadm_addrobj_t ipaddr)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
i_ipadm_get_lif2addrobj(ipadm_handle_t iph,ipadm_addrobj_t addrobj)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
ipadm_add_aobjname(ipadm_handle_t iph,const char * ifname,sa_family_t af,const char * aobjname,ipadm_addr_type_t atype,int lnum)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
ipadm_delete_aobjname(ipadm_handle_t iph,const char * ifname,sa_family_t af,const char * aobjname,ipadm_addr_type_t atype,int lnum)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
i_ipadm_active_addr_info(ipadm_handle_t iph,const char * ifname,ipadm_addr_info_t ** addrinfo,uint32_t ipadm_flags,int64_t lifc_flags)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
i_ipadm_name2atype(const char * name,sa_family_t * af,ipadm_addr_type_t * type)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
i_ipadm_nvl2ainfo_common(nvlist_t * nvl,ipadm_addr_info_t * ainfo)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
i_ipadm_nvl2ainfo_active(nvlist_t * nvl,ipadm_addr_info_t * ainfo)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
i_ipadm_nvl2ainfo_persist(nvlist_t * nvl,ipadm_addr_info_t * ainfo)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
i_ipadm_get_all_addr_info(ipadm_handle_t iph,const char * ifname,ipadm_addr_info_t ** addrinfo,uint32_t ipadm_flags,int64_t lifc_flags)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
i_ipadm_set_prefixlen(ipadm_handle_t iph,const void * arg,ipadm_prop_desc_t * pdp,const void * pval,uint_t af,uint_t flags)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
i_ipadm_set_addr_flag(ipadm_handle_t iph,const void * arg,ipadm_prop_desc_t * pdp,const void * pval,uint_t af,uint_t flags)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
i_ipadm_set_zone(ipadm_handle_t iph,const void * arg,ipadm_prop_desc_t * pdp,const void * pval,uint_t af,uint_t flags)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
i_ipadm_get_broadcast(ipadm_handle_t iph,const void * arg,ipadm_prop_desc_t * pdp,char * buf,uint_t * bufsize,uint_t af,uint_t valtype)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
i_ipadm_get_prefixlen(ipadm_handle_t iph,const void * arg,ipadm_prop_desc_t * pdp,char * buf,uint_t * bufsize,uint_t af,uint_t valtype)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
i_ipadm_get_addr_flag(ipadm_handle_t iph,const void * arg,ipadm_prop_desc_t * pdp,char * buf,uint_t * bufsize,uint_t af,uint_t valtype)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
i_ipadm_get_zone(ipadm_handle_t iph,const void * arg,ipadm_prop_desc_t * pdp,char * buf,uint_t * bufsize,uint_t af,uint_t valtype)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 *
i_ipadm_get_addrprop_desc(const char * pname)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
ipadm_get_addrprop(ipadm_handle_t iph,const char * pname,char * buf,uint_t * bufsize,const char * aobjname,uint_t valtype)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
ipadm_set_addrprop(ipadm_handle_t iph,const char * pname,const char * pval,const char * aobjname,uint_t pflags)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
i_ipadm_delete_addr(ipadm_handle_t iph,ipadm_addrobj_t addr)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
i_ipadm_nvl2in6_addr(nvlist_t * nvl,char * addr_type,in6_addr_t * in6_addr)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
i_ipadm_is_user_aobjname_valid(const char * aobjname)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
i_ipadm_get_default_prefixlen(struct sockaddr_storage * addr,uint32_t * plen)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
i_ipadm_resolve_addr(const char * name,sa_family_t af,struct sockaddr_storage * ss)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
ipadm_set_addr(ipadm_addrobj_t ipaddr,const char * astr,sa_family_t af)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
ipadm_get_addr(const ipadm_addrobj_t ipaddr,struct sockaddr_storage * addr)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
ipadm_set_dst_addr(ipadm_addrobj_t ipaddr,const char * daddrstr,sa_family_t af)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
ipadm_set_interface_id(ipadm_addrobj_t ipaddr,const char * interface_id)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
ipadm_set_stateless(ipadm_addrobj_t ipaddr,boolean_t stateless)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
ipadm_set_stateful(ipadm_addrobj_t ipaddr,boolean_t stateful)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
ipadm_set_primary(ipadm_addrobj_t ipaddr,boolean_t primary)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
ipadm_set_wait_time(ipadm_addrobj_t ipaddr,int32_t wait)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
i_ipadm_lookupadd_addrobj(ipadm_handle_t iph,ipadm_addrobj_t ipaddr)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
i_ipadm_setlifnum_addrobj(ipadm_handle_t iph,ipadm_addrobj_t ipaddr)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
i_ipadm_enable_static(ipadm_handle_t iph,const char * ifname,nvlist_t * nvl,sa_family_t af)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
i_ipadm_enable_dhcp(ipadm_handle_t iph,const char * ifname,nvlist_t * nvl)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
i_ipadm_enable_addrconf(ipadm_handle_t iph,const char * ifname,nvlist_t * nvl)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
ipadm_create_addrobj(ipadm_addr_type_t type,const char * aobjname,ipadm_addrobj_t * ipaddr)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
ipadm_get_aobjname(const ipadm_addrobj_t ipaddr,char * aobjname,size_t len)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
ipadm_destroy_addrobj(ipadm_addrobj_t ipaddr)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
i_ipadm_addrobj2lifname(ipadm_addrobj_t ipaddr,char * lifname,int lifnamesize)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
i_ipadm_addr_exists_on_if(ipadm_handle_t iph,const char * ifname,sa_family_t af,boolean_t * exists)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
i_ipadm_do_addif(ipadm_handle_t iph,ipadm_addrobj_t addr)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
i_ipadm_get_db_addr(ipadm_handle_t iph,const char * ifname,const char * aobjname,nvlist_t ** onvl)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
ipadm_create_addr(ipadm_handle_t iph,ipadm_addrobj_t addr,uint32_t flags)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
i_ipadm_create_addr(ipadm_handle_t iph,ipadm_addrobj_t ipaddr,uint32_t flags)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
ipadm_delete_addr(ipadm_handle_t iph,const char * aobjname,uint32_t flags)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
i_ipadm_create_dhcp(ipadm_handle_t iph,ipadm_addrobj_t addr,uint32_t flags)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
i_ipadm_delete_dhcp(ipadm_handle_t iph,ipadm_addrobj_t addr,boolean_t release)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
i_ipadm_op_dhcp(ipadm_addrobj_t addr,dhcp_ipc_type_t type,int * dhcperror)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
ipadm_addr_info(ipadm_handle_t iph,const char * ifname,ipadm_addr_info_t ** addrinfo,uint32_t flags,int64_t lifc_flags)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
ipadm_free_addr_info(ipadm_addr_info_t * ainfo)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
i_ipadm_addr_persist(ipadm_handle_t iph,const ipadm_addrobj_t ipaddr,boolean_t default_prefixlen,uint32_t flags)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
i_ipadm_addr_persist_nvl(ipadm_handle_t iph,nvlist_t * nvl,uint32_t flags)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
i_ipadm_delete_addrobj(ipadm_handle_t iph,const ipadm_addrobj_t ipaddr,uint32_t flags)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
i_ipadm_updown_common(ipadm_handle_t iph,const char * aobjname,ipadm_addrobj_t ipaddr,uint32_t ipadm_flags,uint64_t * ifflags)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
ipadm_up_addr(ipadm_handle_t iph,const char * aobjname,uint32_t ipadm_flags)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
ipadm_down_addr(ipadm_handle_t iph,const char * aobjname,uint32_t ipadm_flags)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
ipadm_refresh_addr(ipadm_handle_t iph,const char * aobjname,uint32_t ipadm_flags)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
i_ipadm_validate_create_addr(ipadm_handle_t iph,ipadm_addrobj_t ipaddr,uint32_t flags)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
i_ipadm_merge_prefixlen_from_nvl(nvlist_t * invl,nvlist_t * onvl,const char * aobjname)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
ipadm_enable_addr(ipadm_handle_t iph,const char * aobjname,uint32_t flags)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
ipadm_disable_addr(ipadm_handle_t iph,const char * aobjname,uint32_t flags)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