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  */
21a73be61aSHans Rosenfeld 
226e91bba0SGirish Moodalbail /*
238b88711aSGirish Moodalbail  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
24299625c6SSebastien Roy  * Copyright (c) 2013 by Delphix. All rights reserved.
25b31320a7SChris Fraire  * Copyright (c) 2016-2017, Chris Fraire <cfraire@me.com>.
26a73be61aSHans Rosenfeld  * Copyright 2021 Tintri by DDN, Inc. All rights reserved.
27c8152f8fSAndy Fiddaman  * Copyright 2023 Oxide Computer Company
286e91bba0SGirish Moodalbail  */
296e91bba0SGirish Moodalbail 
306e91bba0SGirish Moodalbail /*
316e91bba0SGirish Moodalbail  * This file contains functions for address management such as creating
326e91bba0SGirish Moodalbail  * an address, deleting an address, enabling an address, disabling an
336e91bba0SGirish Moodalbail  * address, bringing an address down or up, setting/getting properties
346e91bba0SGirish Moodalbail  * on an address object and listing address information
356e91bba0SGirish Moodalbail  * for all addresses in active as well as persistent configuration.
366e91bba0SGirish Moodalbail  */
376e91bba0SGirish Moodalbail #include <sys/types.h>
386e91bba0SGirish Moodalbail #include <sys/socket.h>
39b31320a7SChris Fraire #include <sys/param.h>
406e91bba0SGirish Moodalbail #include <netdb.h>
416e91bba0SGirish Moodalbail #include <inet/ip.h>
426e91bba0SGirish Moodalbail #include <string.h>
436e91bba0SGirish Moodalbail #include <strings.h>
446e91bba0SGirish Moodalbail #include <assert.h>
456e91bba0SGirish Moodalbail #include <sys/sockio.h>
466e91bba0SGirish Moodalbail #include <errno.h>
476e91bba0SGirish Moodalbail #include <unistd.h>
486e91bba0SGirish Moodalbail #include <stropts.h>
496e91bba0SGirish Moodalbail #include <zone.h>
506e91bba0SGirish Moodalbail #include <netinet/in.h>
516e91bba0SGirish Moodalbail #include <arpa/inet.h>
526e91bba0SGirish Moodalbail #include <fcntl.h>
536e91bba0SGirish Moodalbail #include <ctype.h>
546e91bba0SGirish Moodalbail #include <dhcpagent_util.h>
556e91bba0SGirish Moodalbail #include <dhcpagent_ipc.h>
56b31320a7SChris Fraire #include <dhcp_inittab.h>
57b31320a7SChris Fraire #include <dhcp_symbol.h>
586e91bba0SGirish Moodalbail #include <ipadm_ndpd.h>
596e91bba0SGirish Moodalbail #include <libdladm.h>
606e91bba0SGirish Moodalbail #include <libdllink.h>
616e91bba0SGirish Moodalbail #include <libdliptun.h>
626e91bba0SGirish Moodalbail #include <ifaddrs.h>
636e91bba0SGirish Moodalbail #include "libipadm_impl.h"
646e91bba0SGirish Moodalbail 
656e91bba0SGirish Moodalbail #define	SIN6(a)		((struct sockaddr_in6 *)a)
666e91bba0SGirish Moodalbail #define	SIN(a)		((struct sockaddr_in *)a)
676e91bba0SGirish Moodalbail 
686e91bba0SGirish Moodalbail static ipadm_status_t	i_ipadm_create_addr(ipadm_handle_t, ipadm_addrobj_t,
696e91bba0SGirish Moodalbail 			    uint32_t);
706e91bba0SGirish Moodalbail static ipadm_status_t	i_ipadm_create_dhcp(ipadm_handle_t, ipadm_addrobj_t,
716e91bba0SGirish Moodalbail 			    uint32_t);
726e91bba0SGirish Moodalbail static ipadm_status_t	i_ipadm_delete_dhcp(ipadm_handle_t, ipadm_addrobj_t,
736e91bba0SGirish Moodalbail 			    boolean_t);
74b31320a7SChris Fraire static ipadm_status_t	i_ipadm_refresh_dhcp(ipadm_addrobj_t);
756e91bba0SGirish Moodalbail static ipadm_status_t	i_ipadm_get_db_addr(ipadm_handle_t, const char *,
766e91bba0SGirish Moodalbail 			    const char *, nvlist_t **);
776e91bba0SGirish Moodalbail static ipadm_status_t	i_ipadm_op_dhcp(ipadm_addrobj_t, dhcp_ipc_type_t,
786e91bba0SGirish Moodalbail 			    int *);
79b31320a7SChris Fraire static ipadm_status_t	i_ipadm_dhcp_status(ipadm_addrobj_t addr,
80b31320a7SChris Fraire 			    dhcp_status_t *status, int *dhcperror);
816e91bba0SGirish Moodalbail static ipadm_status_t	i_ipadm_validate_create_addr(ipadm_handle_t,
826e91bba0SGirish Moodalbail 			    ipadm_addrobj_t, uint32_t);
836e91bba0SGirish Moodalbail static ipadm_status_t	i_ipadm_addr_persist_nvl(ipadm_handle_t, nvlist_t *,
846e91bba0SGirish Moodalbail 			    uint32_t);
856e91bba0SGirish Moodalbail static ipadm_status_t	i_ipadm_get_default_prefixlen(struct sockaddr_storage *,
866e91bba0SGirish Moodalbail 			    uint32_t *);
876e91bba0SGirish Moodalbail static ipadm_status_t	i_ipadm_get_static_addr_db(ipadm_handle_t,
886e91bba0SGirish Moodalbail 			    ipadm_addrobj_t);
896e91bba0SGirish Moodalbail static boolean_t	i_ipadm_is_user_aobjname_valid(const char *);
90b31320a7SChris Fraire static ipadm_prop_desc_t	*i_ipadm_get_addrprop_desc(const char *pname);
916e91bba0SGirish Moodalbail 
926e91bba0SGirish Moodalbail /*
936e91bba0SGirish Moodalbail  * Callback functions to retrieve property values from the kernel. These
946e91bba0SGirish Moodalbail  * functions, when required, translate the values from the kernel to a format
956e91bba0SGirish Moodalbail  * suitable for printing. They also retrieve DEFAULT, PERM and POSSIBLE values
966e91bba0SGirish Moodalbail  * for a given property.
976e91bba0SGirish Moodalbail  */
986e91bba0SGirish Moodalbail static ipadm_pd_getf_t	i_ipadm_get_prefixlen, i_ipadm_get_addr_flag,
99b31320a7SChris Fraire 			i_ipadm_get_zone, i_ipadm_get_broadcast,
100b31320a7SChris Fraire 			i_ipadm_get_primary, i_ipadm_get_reqhost;
1016e91bba0SGirish Moodalbail 
1026e91bba0SGirish Moodalbail /*
1036e91bba0SGirish Moodalbail  * Callback functions to set property values. These functions translate the
1046e91bba0SGirish Moodalbail  * values to a format suitable for kernel consumption, allocate the necessary
105b31320a7SChris Fraire  * ioctl buffers and then invoke ioctl(); or in the case of reqhost, get the
106b31320a7SChris Fraire  * collaborating agent to set the value.
1076e91bba0SGirish Moodalbail  */
1086e91bba0SGirish Moodalbail static ipadm_pd_setf_t	i_ipadm_set_prefixlen, i_ipadm_set_addr_flag,
109b31320a7SChris Fraire 			i_ipadm_set_zone, i_ipadm_set_reqhost;
110b31320a7SChris Fraire 
111b31320a7SChris Fraire static ipadm_status_t	i_ipadm_set_aobj_addrprop(ipadm_handle_t iph,
112b31320a7SChris Fraire     ipadm_addrobj_t ipaddr, uint_t flags, const char *propname);
1136e91bba0SGirish Moodalbail 
1146e91bba0SGirish Moodalbail /* address properties description table */
1156e91bba0SGirish Moodalbail ipadm_prop_desc_t ipadm_addrprop_table[] = {
116299625c6SSebastien Roy 	{ "broadcast", NULL, IPADMPROP_CLASS_ADDR, MOD_PROTO_NONE, 0,
1176e91bba0SGirish Moodalbail 	    NULL, NULL, i_ipadm_get_broadcast },
1186e91bba0SGirish Moodalbail 
119299625c6SSebastien Roy 	{ "deprecated", NULL, IPADMPROP_CLASS_ADDR, MOD_PROTO_NONE, 0,
1206e91bba0SGirish Moodalbail 	    i_ipadm_set_addr_flag, i_ipadm_get_onoff,
1216e91bba0SGirish Moodalbail 	    i_ipadm_get_addr_flag },
1226e91bba0SGirish Moodalbail 
123b31320a7SChris Fraire 	{ IPADM_NVP_PREFIXLEN, NULL, IPADMPROP_CLASS_ADDR, MOD_PROTO_NONE, 0,
1246e91bba0SGirish Moodalbail 	    i_ipadm_set_prefixlen, i_ipadm_get_prefixlen,
1256e91bba0SGirish Moodalbail 	    i_ipadm_get_prefixlen },
1266e91bba0SGirish Moodalbail 
127b31320a7SChris Fraire 	/*
128b31320a7SChris Fraire 	 * primary is read-only because there is no operation to un-set
129b31320a7SChris Fraire 	 * DHCP_IF_PRIMARY in dhcpagent except to delete-addr and then
130b31320a7SChris Fraire 	 * re-create-addr.
131b31320a7SChris Fraire 	 */
132b31320a7SChris Fraire 	{ "primary", NULL, IPADMPROP_CLASS_ADDR, MOD_PROTO_NONE, 0,
133b31320a7SChris Fraire 		NULL, NULL, i_ipadm_get_primary },
134b31320a7SChris Fraire 
135299625c6SSebastien Roy 	{ "private", NULL, IPADMPROP_CLASS_ADDR, MOD_PROTO_NONE, 0,
1366e91bba0SGirish Moodalbail 	    i_ipadm_set_addr_flag, i_ipadm_get_onoff, i_ipadm_get_addr_flag },
1376e91bba0SGirish Moodalbail 
138b31320a7SChris Fraire 	{ IPADM_NVP_REQHOST, NULL, IPADMPROP_CLASS_ADDR, MOD_PROTO_NONE, 0,
139b31320a7SChris Fraire 	    i_ipadm_set_reqhost, NULL, i_ipadm_get_reqhost },
140b31320a7SChris Fraire 
141299625c6SSebastien Roy 	{ "transmit", NULL, IPADMPROP_CLASS_ADDR, MOD_PROTO_NONE, 0,
1426e91bba0SGirish Moodalbail 	    i_ipadm_set_addr_flag, i_ipadm_get_onoff, i_ipadm_get_addr_flag },
1436e91bba0SGirish Moodalbail 
144299625c6SSebastien Roy 	{ "zone", NULL, IPADMPROP_CLASS_ADDR, MOD_PROTO_NONE, 0,
1456e91bba0SGirish Moodalbail 	    i_ipadm_set_zone, NULL, i_ipadm_get_zone },
1466e91bba0SGirish Moodalbail 
147299625c6SSebastien Roy 	{ NULL, NULL, 0, 0, 0, NULL, NULL, NULL }
1486e91bba0SGirish Moodalbail };
1496e91bba0SGirish Moodalbail 
150299625c6SSebastien Roy static ipadm_prop_desc_t up_addrprop = { "up", NULL, IPADMPROP_CLASS_ADDR,
1518b88711aSGirish Moodalbail 					MOD_PROTO_NONE, 0, NULL, NULL, NULL };
1526e91bba0SGirish Moodalbail 
1536e91bba0SGirish Moodalbail /*
1546e91bba0SGirish Moodalbail  * Helper function that initializes the `ipadm_ifname', `ipadm_aobjname', and
1556e91bba0SGirish Moodalbail  * `ipadm_atype' fields of the given `ipaddr'.
1566e91bba0SGirish Moodalbail  */
1576e91bba0SGirish Moodalbail void
i_ipadm_init_addr(ipadm_addrobj_t ipaddr,const char * ifname,const char * aobjname,ipadm_addr_type_t atype)1586e91bba0SGirish Moodalbail i_ipadm_init_addr(ipadm_addrobj_t ipaddr, const char *ifname,
1596e91bba0SGirish Moodalbail     const char *aobjname, ipadm_addr_type_t atype)
1606e91bba0SGirish Moodalbail {
1616e91bba0SGirish Moodalbail 	bzero(ipaddr, sizeof (struct ipadm_addrobj_s));
1626e91bba0SGirish Moodalbail 	(void) strlcpy(ipaddr->ipadm_ifname, ifname,
1636e91bba0SGirish Moodalbail 	    sizeof (ipaddr->ipadm_ifname));
1646e91bba0SGirish Moodalbail 	(void) strlcpy(ipaddr->ipadm_aobjname, aobjname,
1656e91bba0SGirish Moodalbail 	    sizeof (ipaddr->ipadm_aobjname));
1666e91bba0SGirish Moodalbail 	ipaddr->ipadm_atype = atype;
1676e91bba0SGirish Moodalbail }
1686e91bba0SGirish Moodalbail 
1696e91bba0SGirish Moodalbail /*
1706e91bba0SGirish Moodalbail  * Determine the permission of the property depending on whether it has a
1716e91bba0SGirish Moodalbail  * set() and/or get() callback functions.
1726e91bba0SGirish Moodalbail  */
1736e91bba0SGirish Moodalbail static ipadm_status_t
i_ipadm_pd2permstr(ipadm_prop_desc_t * pdp,char * buf,uint_t * bufsize)1746e91bba0SGirish Moodalbail i_ipadm_pd2permstr(ipadm_prop_desc_t *pdp, char *buf, uint_t *bufsize)
1756e91bba0SGirish Moodalbail {
1766e91bba0SGirish Moodalbail 	uint_t	perm;
1776e91bba0SGirish Moodalbail 	size_t	nbytes;
1786e91bba0SGirish Moodalbail 
1796e91bba0SGirish Moodalbail 	perm = 0;
1806e91bba0SGirish Moodalbail 	if (pdp->ipd_set != NULL)
1816e91bba0SGirish Moodalbail 		perm |= MOD_PROP_PERM_WRITE;
1826e91bba0SGirish Moodalbail 	if (pdp->ipd_get != NULL)
1836e91bba0SGirish Moodalbail 		perm |= MOD_PROP_PERM_READ;
1846e91bba0SGirish Moodalbail 
1856e91bba0SGirish Moodalbail 	nbytes = snprintf(buf, *bufsize, "%c%c",
1866e91bba0SGirish Moodalbail 	    ((perm & MOD_PROP_PERM_READ) != 0) ? 'r' : '-',
1876e91bba0SGirish Moodalbail 	    ((perm & MOD_PROP_PERM_WRITE) != 0) ? 'w' : '-');
1886e91bba0SGirish Moodalbail 
1896e91bba0SGirish Moodalbail 	if (nbytes >= *bufsize) {
1906e91bba0SGirish Moodalbail 		/* insufficient buffer space */
1916e91bba0SGirish Moodalbail 		*bufsize = nbytes + 1;
1926e91bba0SGirish Moodalbail 		return (IPADM_NO_BUFS);
1936e91bba0SGirish Moodalbail 	}
1946e91bba0SGirish Moodalbail 	return (IPADM_SUCCESS);
1956e91bba0SGirish Moodalbail }
1966e91bba0SGirish Moodalbail 
1976e91bba0SGirish Moodalbail /*
1986e91bba0SGirish Moodalbail  * Given an addrobj with `ipadm_aobjname' filled in, i_ipadm_get_addrobj()
1996e91bba0SGirish Moodalbail  * retrieves the information necessary for any operation on the object,
2006e91bba0SGirish Moodalbail  * such as delete-addr, enable-addr, disable-addr, up-addr, down-addr,
2016e91bba0SGirish Moodalbail  * refresh-addr, get-addrprop or set-addrprop. The information include
2026e91bba0SGirish Moodalbail  * the logical interface number, address type, address family,
2036e91bba0SGirish Moodalbail  * the interface id (if the address type is IPADM_ADDR_IPV6_ADDRCONF) and
2046e91bba0SGirish Moodalbail  * the ipadm_flags that indicate if the address is present in
2056e91bba0SGirish Moodalbail  * active configuration or persistent configuration or both. If the address
2066e91bba0SGirish Moodalbail  * is not found, IPADM_NOTSUP is returned.
2076e91bba0SGirish Moodalbail  */
2086e91bba0SGirish Moodalbail ipadm_status_t
i_ipadm_get_addrobj(ipadm_handle_t iph,ipadm_addrobj_t ipaddr)2096e91bba0SGirish Moodalbail i_ipadm_get_addrobj(ipadm_handle_t iph, ipadm_addrobj_t ipaddr)
2106e91bba0SGirish Moodalbail {
2116e91bba0SGirish Moodalbail 	ipmgmt_aobjop_arg_t	larg;
2126e91bba0SGirish Moodalbail 	ipmgmt_aobjop_rval_t	rval, *rvalp;
2136e91bba0SGirish Moodalbail 	int			err = 0;
2146e91bba0SGirish Moodalbail 
2156e91bba0SGirish Moodalbail 	/* populate the door_call argument structure */
2166e91bba0SGirish Moodalbail 	larg.ia_cmd = IPMGMT_CMD_AOBJNAME2ADDROBJ;
2176e91bba0SGirish Moodalbail 	(void) strlcpy(larg.ia_aobjname, ipaddr->ipadm_aobjname,
2186e91bba0SGirish Moodalbail 	    sizeof (larg.ia_aobjname));
2196e91bba0SGirish Moodalbail 
2206e91bba0SGirish Moodalbail 	rvalp = &rval;
2216e91bba0SGirish Moodalbail 	err = ipadm_door_call(iph, &larg, sizeof (larg), (void **)&rvalp,
2226e91bba0SGirish Moodalbail 	    sizeof (rval), B_FALSE);
2236e91bba0SGirish Moodalbail 	if (err != 0)
2246e91bba0SGirish Moodalbail 		return (ipadm_errno2status(err));
2256e91bba0SGirish Moodalbail 	(void) strlcpy(ipaddr->ipadm_ifname, rval.ir_ifname,
2266e91bba0SGirish Moodalbail 	    sizeof (ipaddr->ipadm_ifname));
2276e91bba0SGirish Moodalbail 	ipaddr->ipadm_lifnum = rval.ir_lnum;
2286e91bba0SGirish Moodalbail 	ipaddr->ipadm_atype = rval.ir_atype;
2296e91bba0SGirish Moodalbail 	ipaddr->ipadm_af = rval.ir_family;
2306e91bba0SGirish Moodalbail 	ipaddr->ipadm_flags = rval.ir_flags;
231b31320a7SChris Fraire 	switch (rval.ir_atype) {
232b31320a7SChris Fraire 	case IPADM_ADDR_IPV6_ADDRCONF:
233b31320a7SChris Fraire 		ipaddr->ipadm_intfid = rval.ipmgmt_ir_intfid;
234b31320a7SChris Fraire 		break;
235b31320a7SChris Fraire 	case IPADM_ADDR_DHCP:
236b31320a7SChris Fraire 		if (strlcpy(ipaddr->ipadm_reqhost, rval.ipmgmt_ir_reqhost,
237b31320a7SChris Fraire 		    sizeof (ipaddr->ipadm_reqhost)) >=
238b31320a7SChris Fraire 		    sizeof (ipaddr->ipadm_reqhost)) {
239b31320a7SChris Fraire 			/*
240b31320a7SChris Fraire 			 * shouldn't get here as the buffers are defined
241b31320a7SChris Fraire 			 * with same length, MAX_NAME_LEN
242b31320a7SChris Fraire 			 */
243b31320a7SChris Fraire 			return (IPADM_FAILURE);
244b31320a7SChris Fraire 		}
245b31320a7SChris Fraire 		break;
246b31320a7SChris Fraire 	default:
247b31320a7SChris Fraire 		break;
2486e91bba0SGirish Moodalbail 	}
2496e91bba0SGirish Moodalbail 
2506e91bba0SGirish Moodalbail 	return (IPADM_SUCCESS);
2516e91bba0SGirish Moodalbail }
2526e91bba0SGirish Moodalbail 
2536e91bba0SGirish Moodalbail /*
2546e91bba0SGirish Moodalbail  * Retrieves the static address (IPv4 or IPv6) for the given address object
2556e91bba0SGirish Moodalbail  * in `ipaddr' from persistent DB.
2566e91bba0SGirish Moodalbail  */
2576e91bba0SGirish Moodalbail static ipadm_status_t
i_ipadm_get_static_addr_db(ipadm_handle_t iph,ipadm_addrobj_t ipaddr)2586e91bba0SGirish Moodalbail i_ipadm_get_static_addr_db(ipadm_handle_t iph, ipadm_addrobj_t ipaddr)
2596e91bba0SGirish Moodalbail {
2606e91bba0SGirish Moodalbail 	ipadm_status_t		status;
2616e91bba0SGirish Moodalbail 	nvlist_t		*onvl;
2626e91bba0SGirish Moodalbail 	nvlist_t		*anvl = NULL;
2636e91bba0SGirish Moodalbail 	nvlist_t		*nvladdr;
2646e91bba0SGirish Moodalbail 	nvpair_t		*nvp;
2656e91bba0SGirish Moodalbail 	char			*name;
2666e91bba0SGirish Moodalbail 	char			*aobjname = ipaddr->ipadm_aobjname;
2676e91bba0SGirish Moodalbail 	char			*sname;
2686e91bba0SGirish Moodalbail 	sa_family_t		af = AF_UNSPEC;
2696e91bba0SGirish Moodalbail 
2706e91bba0SGirish Moodalbail 	/*
2716e91bba0SGirish Moodalbail 	 * Get the address line in the nvlist `onvl' from ipmgmtd daemon.
2726e91bba0SGirish Moodalbail 	 */
2736e91bba0SGirish Moodalbail 	status = i_ipadm_get_db_addr(iph, NULL, aobjname, &onvl);
2746e91bba0SGirish Moodalbail 	if (status != IPADM_SUCCESS)
2756e91bba0SGirish Moodalbail 		return (status);
2766e91bba0SGirish Moodalbail 	/*
2776e91bba0SGirish Moodalbail 	 * Walk through the nvlist `onvl' to extract the IPADM_NVP_IPV4ADDR
2786e91bba0SGirish Moodalbail 	 * or the IPADM_NVP_IPV6ADDR name-value pair.
2796e91bba0SGirish Moodalbail 	 */
2806e91bba0SGirish Moodalbail 	for (nvp = nvlist_next_nvpair(onvl, NULL); nvp != NULL;
2816e91bba0SGirish Moodalbail 	    nvp = nvlist_next_nvpair(onvl, NULL)) {
2826e91bba0SGirish Moodalbail 		if (nvpair_value_nvlist(nvp, &anvl) != 0)
2836e91bba0SGirish Moodalbail 			continue;
2846e91bba0SGirish Moodalbail 		if (nvlist_exists(anvl, IPADM_NVP_IPV4ADDR) ||
2856e91bba0SGirish Moodalbail 		    nvlist_exists(anvl, IPADM_NVP_IPV6ADDR))
2866e91bba0SGirish Moodalbail 			break;
2876e91bba0SGirish Moodalbail 	}
288a73be61aSHans Rosenfeld 	nvlist_free(onvl);
289a73be61aSHans Rosenfeld 
2906e91bba0SGirish Moodalbail 	if (nvp == NULL)
291a73be61aSHans Rosenfeld 		return (IPADM_NOTFOUND);
292a73be61aSHans Rosenfeld 
2936e91bba0SGirish Moodalbail 	for (nvp = nvlist_next_nvpair(anvl, NULL);
2946e91bba0SGirish Moodalbail 	    nvp != NULL; nvp = nvlist_next_nvpair(anvl, nvp)) {
2956e91bba0SGirish Moodalbail 		name = nvpair_name(nvp);
2966e91bba0SGirish Moodalbail 		if (strcmp(name, IPADM_NVP_IPV4ADDR) == 0) {
2976e91bba0SGirish Moodalbail 			af = AF_INET;
2986e91bba0SGirish Moodalbail 			break;
2996e91bba0SGirish Moodalbail 		} else if (strcmp(name, IPADM_NVP_IPV6ADDR) == 0) {
3006e91bba0SGirish Moodalbail 			af = AF_INET6;
3016e91bba0SGirish Moodalbail 			break;
3026e91bba0SGirish Moodalbail 		}
3036e91bba0SGirish Moodalbail 	}
3046e91bba0SGirish Moodalbail 	assert(af != AF_UNSPEC);
305a73be61aSHans Rosenfeld 
3066e91bba0SGirish Moodalbail 	if (nvpair_value_nvlist(nvp, &nvladdr) != 0 ||
3076e91bba0SGirish Moodalbail 	    nvlist_lookup_string(nvladdr, IPADM_NVP_IPADDRHNAME, &sname) != 0 ||
308a73be61aSHans Rosenfeld 	    ipadm_set_addr(ipaddr, sname, af) != IPADM_SUCCESS)
309a73be61aSHans Rosenfeld 		return (IPADM_NOTFOUND);
310a73be61aSHans Rosenfeld 
3116e91bba0SGirish Moodalbail 	return (IPADM_SUCCESS);
3126e91bba0SGirish Moodalbail }
3136e91bba0SGirish Moodalbail 
3146e91bba0SGirish Moodalbail /*
3156e91bba0SGirish Moodalbail  * For the given `addrobj->ipadm_lifnum' and `addrobj->ipadm_af', this function
3166e91bba0SGirish Moodalbail  * fills in the address objname, the address type and the ipadm_flags.
3176e91bba0SGirish Moodalbail  */
3186e91bba0SGirish Moodalbail ipadm_status_t
i_ipadm_get_lif2addrobj(ipadm_handle_t iph,ipadm_addrobj_t addrobj)3196e91bba0SGirish Moodalbail i_ipadm_get_lif2addrobj(ipadm_handle_t iph, ipadm_addrobj_t addrobj)
3206e91bba0SGirish Moodalbail {
3216e91bba0SGirish Moodalbail 	ipmgmt_aobjop_arg_t	larg;
3226e91bba0SGirish Moodalbail 	ipmgmt_aobjop_rval_t	rval, *rvalp;
3236e91bba0SGirish Moodalbail 	int			err;
3246e91bba0SGirish Moodalbail 
3256e91bba0SGirish Moodalbail 	larg.ia_cmd = IPMGMT_CMD_LIF2ADDROBJ;
3266e91bba0SGirish Moodalbail 	(void) strlcpy(larg.ia_ifname, addrobj->ipadm_ifname,
3276e91bba0SGirish Moodalbail 	    sizeof (larg.ia_ifname));
3286e91bba0SGirish Moodalbail 	larg.ia_lnum = addrobj->ipadm_lifnum;
3296e91bba0SGirish Moodalbail 	larg.ia_family = addrobj->ipadm_af;
3306e91bba0SGirish Moodalbail 
3316e91bba0SGirish Moodalbail 	rvalp = &rval;
3326e91bba0SGirish Moodalbail 	err = ipadm_door_call(iph, &larg, sizeof (larg), (void **)&rvalp,
3336e91bba0SGirish Moodalbail 	    sizeof (rval), B_FALSE);
3346e91bba0SGirish Moodalbail 	if (err != 0)
3356e91bba0SGirish Moodalbail 		return (ipadm_errno2status(err));
3366e91bba0SGirish Moodalbail 	(void) strlcpy(addrobj->ipadm_aobjname, rval.ir_aobjname,
3376e91bba0SGirish Moodalbail 	    sizeof (addrobj->ipadm_aobjname));
3386e91bba0SGirish Moodalbail 	addrobj->ipadm_atype = rval.ir_atype;
3396e91bba0SGirish Moodalbail 	addrobj->ipadm_flags = rval.ir_flags;
3406e91bba0SGirish Moodalbail 
3416e91bba0SGirish Moodalbail 	return (IPADM_SUCCESS);
3426e91bba0SGirish Moodalbail }
3436e91bba0SGirish Moodalbail 
3446e91bba0SGirish Moodalbail /*
3456e91bba0SGirish Moodalbail  * Adds an addrobj to ipmgmtd daemon's aobjmap (active configuration).
3466e91bba0SGirish Moodalbail  * with the given name and logical interface number.
3476e91bba0SGirish Moodalbail  * This API is called by in.ndpd to add addrobjs when new prefixes or
3486e91bba0SGirish Moodalbail  * dhcpv6 addresses are configured.
3496e91bba0SGirish Moodalbail  */
3506e91bba0SGirish 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)3516e91bba0SGirish Moodalbail ipadm_add_aobjname(ipadm_handle_t iph, const char *ifname, sa_family_t af,
3526e91bba0SGirish Moodalbail     const char *aobjname, ipadm_addr_type_t atype, int lnum)
3536e91bba0SGirish Moodalbail {
3546e91bba0SGirish Moodalbail 	ipmgmt_aobjop_arg_t	larg;
3556e91bba0SGirish Moodalbail 	int			err;
3566e91bba0SGirish Moodalbail 
3576e91bba0SGirish Moodalbail 	larg.ia_cmd = IPMGMT_CMD_ADDROBJ_ADD;
3586e91bba0SGirish Moodalbail 	(void) strlcpy(larg.ia_ifname, ifname, sizeof (larg.ia_ifname));
3596e91bba0SGirish Moodalbail 	(void) strlcpy(larg.ia_aobjname, aobjname, sizeof (larg.ia_aobjname));
3606e91bba0SGirish Moodalbail 	larg.ia_atype = atype;
3616e91bba0SGirish Moodalbail 	larg.ia_lnum = lnum;
3626e91bba0SGirish Moodalbail 	larg.ia_family = af;
3636e91bba0SGirish Moodalbail 	err = ipadm_door_call(iph, &larg, sizeof (larg), NULL, 0, B_FALSE);
3646e91bba0SGirish Moodalbail 	return (ipadm_errno2status(err));
3656e91bba0SGirish Moodalbail }
3666e91bba0SGirish Moodalbail 
3676e91bba0SGirish Moodalbail /*
3686e91bba0SGirish Moodalbail  * Deletes an address object with given name and logical number from ipmgmtd
3696e91bba0SGirish Moodalbail  * daemon's aobjmap (active configuration). This API is called by in.ndpd to
3706e91bba0SGirish Moodalbail  * remove addrobjs when auto-configured prefixes or dhcpv6 addresses are
3716e91bba0SGirish Moodalbail  * removed.
3726e91bba0SGirish Moodalbail  */
3736e91bba0SGirish 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)3746e91bba0SGirish Moodalbail ipadm_delete_aobjname(ipadm_handle_t iph, const char *ifname, sa_family_t af,
3756e91bba0SGirish Moodalbail     const char *aobjname, ipadm_addr_type_t atype, int lnum)
3766e91bba0SGirish Moodalbail {
3776e91bba0SGirish Moodalbail 	struct ipadm_addrobj_s	aobj;
3786e91bba0SGirish Moodalbail 
3796e91bba0SGirish Moodalbail 	i_ipadm_init_addr(&aobj, ifname, aobjname, atype);
3806e91bba0SGirish Moodalbail 	aobj.ipadm_af = af;
3816e91bba0SGirish Moodalbail 	aobj.ipadm_lifnum = lnum;
3826e91bba0SGirish Moodalbail 	return (i_ipadm_delete_addrobj(iph, &aobj, IPADM_OPT_ACTIVE));
3836e91bba0SGirish Moodalbail }
3846e91bba0SGirish Moodalbail 
3856e91bba0SGirish Moodalbail /*
3866e91bba0SGirish Moodalbail  * Gets all the addresses from active configuration and populates the
3876e91bba0SGirish Moodalbail  * address information in `addrinfo'.
3886e91bba0SGirish Moodalbail  */
389a73be61aSHans Rosenfeld 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)3906e91bba0SGirish Moodalbail i_ipadm_active_addr_info(ipadm_handle_t iph, const char *ifname,
3916e91bba0SGirish Moodalbail     ipadm_addr_info_t **addrinfo, uint32_t ipadm_flags, int64_t lifc_flags)
3926e91bba0SGirish Moodalbail {
3936e91bba0SGirish Moodalbail 	ipadm_status_t		status;
3946e91bba0SGirish Moodalbail 	struct ifaddrs		*ifap, *ifa;
3956e91bba0SGirish Moodalbail 	ipadm_addr_info_t	*curr, *prev = NULL;
3966e91bba0SGirish Moodalbail 	struct ifaddrs		*cifaddr;
3976e91bba0SGirish Moodalbail 	struct lifreq		lifr;
3986e91bba0SGirish Moodalbail 	int			sock;
3996e91bba0SGirish Moodalbail 	uint64_t		flags;
4006e91bba0SGirish Moodalbail 	char			cifname[LIFNAMSIZ];
4016e91bba0SGirish Moodalbail 	struct sockaddr_in6	*sin6;
4026e91bba0SGirish Moodalbail 	struct ipadm_addrobj_s	ipaddr;
4036e91bba0SGirish Moodalbail 	char			*sep;
4046e91bba0SGirish Moodalbail 	int			lnum;
4056e91bba0SGirish Moodalbail 
4066e91bba0SGirish Moodalbail retry:
4076e91bba0SGirish Moodalbail 	*addrinfo = NULL;
4086e91bba0SGirish Moodalbail 
4096e91bba0SGirish Moodalbail 	/* Get all the configured addresses */
4106e91bba0SGirish Moodalbail 	if (getallifaddrs(AF_UNSPEC, &ifa, lifc_flags) < 0)
4116e91bba0SGirish Moodalbail 		return (ipadm_errno2status(errno));
4126e91bba0SGirish Moodalbail 	/* Return if there is nothing to process. */
4136e91bba0SGirish Moodalbail 	if (ifa == NULL)
4146e91bba0SGirish Moodalbail 		return (IPADM_SUCCESS);
4156e91bba0SGirish Moodalbail 	bzero(&lifr, sizeof (lifr));
4166e91bba0SGirish Moodalbail 	for (ifap = ifa; ifap != NULL; ifap = ifap->ifa_next) {
41764639aafSDarren Reed 		struct sockaddr_storage data;
41864639aafSDarren Reed 
4193ee59242SSebastian Wiedenroth 		if (ifap->ifa_addr->sa_family == AF_LINK)
4203ee59242SSebastian Wiedenroth 			continue;
4213ee59242SSebastian Wiedenroth 
4226e91bba0SGirish Moodalbail 		(void) strlcpy(cifname, ifap->ifa_name, sizeof (cifname));
4236e91bba0SGirish Moodalbail 		lnum = 0;
4246e91bba0SGirish Moodalbail 		if ((sep = strrchr(cifname, ':')) != NULL) {
4256e91bba0SGirish Moodalbail 			*sep++ = '\0';
4266e91bba0SGirish Moodalbail 			lnum = atoi(sep);
4276e91bba0SGirish Moodalbail 		}
4286e91bba0SGirish Moodalbail 		if (ifname != NULL && strcmp(cifname, ifname) != 0)
4296e91bba0SGirish Moodalbail 			continue;
430ec3706caSVasumathi Sundaram 		if (!(ipadm_flags & IPADM_OPT_ZEROADDR) &&
431ec3706caSVasumathi Sundaram 		    sockaddrunspec(ifap->ifa_addr) &&
432ec3706caSVasumathi Sundaram 		    !(ifap->ifa_flags & IFF_DHCPRUNNING))
433ec3706caSVasumathi Sundaram 			continue;
4346e91bba0SGirish Moodalbail 
4356e91bba0SGirish Moodalbail 		/* Allocate and populate the current node in the list. */
4366e91bba0SGirish Moodalbail 		if ((curr = calloc(1, sizeof (ipadm_addr_info_t))) == NULL)
4376e91bba0SGirish Moodalbail 			goto fail;
4386e91bba0SGirish Moodalbail 
4396e91bba0SGirish Moodalbail 		/* Link to the list in `addrinfo'. */
4406e91bba0SGirish Moodalbail 		if (prev != NULL)
4416e91bba0SGirish Moodalbail 			prev->ia_ifa.ifa_next = &curr->ia_ifa;
4426e91bba0SGirish Moodalbail 		else
4436e91bba0SGirish Moodalbail 			*addrinfo = curr;
4446e91bba0SGirish Moodalbail 		prev = curr;
4456e91bba0SGirish Moodalbail 
4466e91bba0SGirish Moodalbail 		cifaddr = &curr->ia_ifa;
4476e91bba0SGirish Moodalbail 		if ((cifaddr->ifa_name = strdup(ifap->ifa_name)) == NULL)
4486e91bba0SGirish Moodalbail 			goto fail;
4496e91bba0SGirish Moodalbail 		cifaddr->ifa_flags = ifap->ifa_flags;
4506e91bba0SGirish Moodalbail 		cifaddr->ifa_addr = malloc(sizeof (struct sockaddr_storage));
4516e91bba0SGirish Moodalbail 		if (cifaddr->ifa_addr == NULL)
4526e91bba0SGirish Moodalbail 			goto fail;
45364639aafSDarren Reed 		(void) memcpy(cifaddr->ifa_addr, ifap->ifa_addr,
45464639aafSDarren Reed 		    sizeof (struct sockaddr_storage));
4556e91bba0SGirish Moodalbail 		cifaddr->ifa_netmask = malloc(sizeof (struct sockaddr_storage));
4566e91bba0SGirish Moodalbail 		if (cifaddr->ifa_netmask == NULL)
4576e91bba0SGirish Moodalbail 			goto fail;
45864639aafSDarren Reed 		(void) memcpy(cifaddr->ifa_netmask, ifap->ifa_netmask,
45964639aafSDarren Reed 		    sizeof (struct sockaddr_storage));
4606e91bba0SGirish Moodalbail 		if (ifap->ifa_flags & IFF_POINTOPOINT) {
4616e91bba0SGirish Moodalbail 			cifaddr->ifa_dstaddr = malloc(
4626e91bba0SGirish Moodalbail 			    sizeof (struct sockaddr_storage));
4636e91bba0SGirish Moodalbail 			if (cifaddr->ifa_dstaddr == NULL)
4646e91bba0SGirish Moodalbail 				goto fail;
46564639aafSDarren Reed 			(void) memcpy(cifaddr->ifa_dstaddr, ifap->ifa_dstaddr,
46664639aafSDarren Reed 			    sizeof (struct sockaddr_storage));
4676e91bba0SGirish Moodalbail 		} else if (ifap->ifa_flags & IFF_BROADCAST) {
4686e91bba0SGirish Moodalbail 			cifaddr->ifa_broadaddr = malloc(
4696e91bba0SGirish Moodalbail 			    sizeof (struct sockaddr_storage));
4706e91bba0SGirish Moodalbail 			if (cifaddr->ifa_broadaddr == NULL)
4716e91bba0SGirish Moodalbail 				goto fail;
47264639aafSDarren Reed 			(void) memcpy(cifaddr->ifa_broadaddr,
47364639aafSDarren Reed 			    ifap->ifa_broadaddr,
47464639aafSDarren Reed 			    sizeof (struct sockaddr_storage));
4756e91bba0SGirish Moodalbail 		}
4766e91bba0SGirish Moodalbail 		/* Get the addrobj name stored for this logical interface. */
4776e91bba0SGirish Moodalbail 		ipaddr.ipadm_aobjname[0] = '\0';
4786e91bba0SGirish Moodalbail 		(void) strlcpy(ipaddr.ipadm_ifname, cifname,
4796e91bba0SGirish Moodalbail 		    sizeof (ipaddr.ipadm_ifname));
4806e91bba0SGirish Moodalbail 		ipaddr.ipadm_lifnum = lnum;
48164639aafSDarren Reed 		ipaddr.ipadm_af = ifap->ifa_addr->sa_family;
4826e91bba0SGirish Moodalbail 		status = i_ipadm_get_lif2addrobj(iph, &ipaddr);
4836e91bba0SGirish Moodalbail 
4846e91bba0SGirish Moodalbail 		/*
4856e91bba0SGirish Moodalbail 		 * Find address type from ifa_flags, if we could not get it
4866e91bba0SGirish Moodalbail 		 * from daemon.
4876e91bba0SGirish Moodalbail 		 */
48864639aafSDarren Reed 		(void) memcpy(&data, ifap->ifa_addr,
48964639aafSDarren Reed 		    sizeof (struct sockaddr_in6));
49064639aafSDarren Reed 		sin6 = SIN6(&data);
4916e91bba0SGirish Moodalbail 		flags = ifap->ifa_flags;
4926e91bba0SGirish Moodalbail 		if (status == IPADM_SUCCESS) {
4936e91bba0SGirish Moodalbail 			(void) strlcpy(curr->ia_aobjname, ipaddr.ipadm_aobjname,
4946e91bba0SGirish Moodalbail 			    sizeof (curr->ia_aobjname));
4956e91bba0SGirish Moodalbail 			curr->ia_atype = ipaddr.ipadm_atype;
4966e91bba0SGirish Moodalbail 		} else if ((flags & IFF_DHCPRUNNING) && (!(flags & IFF_IPV6) ||
4976e91bba0SGirish Moodalbail 		    !IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))) {
4986e91bba0SGirish Moodalbail 			curr->ia_atype = IPADM_ADDR_DHCP;
4996e91bba0SGirish Moodalbail 		} else if (flags & IFF_ADDRCONF) {
5006e91bba0SGirish Moodalbail 			curr->ia_atype = IPADM_ADDR_IPV6_ADDRCONF;
5016e91bba0SGirish Moodalbail 		} else {
5026e91bba0SGirish Moodalbail 			curr->ia_atype = IPADM_ADDR_STATIC;
5036e91bba0SGirish Moodalbail 		}
5046e91bba0SGirish Moodalbail 		/*
5056e91bba0SGirish Moodalbail 		 * Populate the flags for the active configuration from the
5066e91bba0SGirish Moodalbail 		 * `ifa_flags'.
5076e91bba0SGirish Moodalbail 		 */
5086e91bba0SGirish Moodalbail 		if (!(flags & IFF_UP)) {
5096e91bba0SGirish Moodalbail 			if (flags & IFF_DUPLICATE)
5106e91bba0SGirish Moodalbail 				curr->ia_state = IFA_DUPLICATE;
5116e91bba0SGirish Moodalbail 			else
5126e91bba0SGirish Moodalbail 				curr->ia_state = IFA_DOWN;
5136e91bba0SGirish Moodalbail 		} else {
5146e91bba0SGirish Moodalbail 			curr->ia_cflags |= IA_UP;
5156e91bba0SGirish Moodalbail 			if (flags & IFF_RUNNING) {
5166e91bba0SGirish Moodalbail 				(void) strlcpy(lifr.lifr_name, ifap->ifa_name,
5176e91bba0SGirish Moodalbail 				    sizeof (lifr.lifr_name));
51864639aafSDarren Reed 				sock = (ifap->ifa_addr->sa_family == AF_INET) ?
5196e91bba0SGirish Moodalbail 				    iph->iph_sock : iph->iph_sock6;
5206e91bba0SGirish Moodalbail 				if (ioctl(sock, SIOCGLIFDADSTATE,
5216e91bba0SGirish Moodalbail 				    (caddr_t)&lifr) < 0) {
5226e91bba0SGirish Moodalbail 					if (errno == ENXIO) {
5236e91bba0SGirish Moodalbail 						freeifaddrs(ifa);
5246e91bba0SGirish Moodalbail 						ipadm_free_addr_info(*addrinfo);
5256e91bba0SGirish Moodalbail 						goto retry;
5266e91bba0SGirish Moodalbail 					}
5276e91bba0SGirish Moodalbail 					goto fail;
5286e91bba0SGirish Moodalbail 				}
5296e91bba0SGirish Moodalbail 				if (lifr.lifr_dadstate == DAD_IN_PROGRESS)
5306e91bba0SGirish Moodalbail 					curr->ia_state = IFA_TENTATIVE;
5316e91bba0SGirish Moodalbail 				else
5326e91bba0SGirish Moodalbail 					curr->ia_state = IFA_OK;
5336e91bba0SGirish Moodalbail 			} else {
5346e91bba0SGirish Moodalbail 				curr->ia_state = IFA_INACCESSIBLE;
5356e91bba0SGirish Moodalbail 			}
5366e91bba0SGirish Moodalbail 		}
5376e91bba0SGirish Moodalbail 		if (flags & IFF_UNNUMBERED)
5386e91bba0SGirish Moodalbail 			curr->ia_cflags |= IA_UNNUMBERED;
5396e91bba0SGirish Moodalbail 		if (flags & IFF_PRIVATE)
5406e91bba0SGirish Moodalbail 			curr->ia_cflags |= IA_PRIVATE;
5416e91bba0SGirish Moodalbail 		if (flags & IFF_TEMPORARY)
5426e91bba0SGirish Moodalbail 			curr->ia_cflags |= IA_TEMPORARY;
5436e91bba0SGirish Moodalbail 		if (flags & IFF_DEPRECATED)
5446e91bba0SGirish Moodalbail 			curr->ia_cflags |= IA_DEPRECATED;
5456e91bba0SGirish Moodalbail 
5466e91bba0SGirish Moodalbail 	}
5476e91bba0SGirish Moodalbail 
5486e91bba0SGirish Moodalbail 	freeifaddrs(ifa);
5496e91bba0SGirish Moodalbail 	return (IPADM_SUCCESS);
5506e91bba0SGirish Moodalbail 
5516e91bba0SGirish Moodalbail fail:
5526e91bba0SGirish Moodalbail 	/* On error, cleanup everything and return. */
5536e91bba0SGirish Moodalbail 	ipadm_free_addr_info(*addrinfo);
5546e91bba0SGirish Moodalbail 	*addrinfo = NULL;
5556e91bba0SGirish Moodalbail 	freeifaddrs(ifa);
5566e91bba0SGirish Moodalbail 	return (ipadm_errno2status(errno));
5576e91bba0SGirish Moodalbail }
5586e91bba0SGirish Moodalbail 
5596e91bba0SGirish Moodalbail /*
5606e91bba0SGirish Moodalbail  * From the given `name', i_ipadm_name2atype() deduces the address type
5616e91bba0SGirish Moodalbail  * and address family. If the `name' implies an address, it returns B_TRUE.
5626e91bba0SGirish Moodalbail  * Else, returns B_FALSE and leaves the output parameters unchanged.
5636e91bba0SGirish Moodalbail  */
5646e91bba0SGirish Moodalbail boolean_t
i_ipadm_name2atype(const char * name,sa_family_t * af,ipadm_addr_type_t * type)5656e91bba0SGirish Moodalbail i_ipadm_name2atype(const char *name, sa_family_t *af, ipadm_addr_type_t *type)
5666e91bba0SGirish Moodalbail {
5676e91bba0SGirish Moodalbail 	boolean_t	is_addr = B_TRUE;
5686e91bba0SGirish Moodalbail 
5696e91bba0SGirish Moodalbail 	if (strcmp(name, IPADM_NVP_IPV4ADDR) == 0) {
5706e91bba0SGirish Moodalbail 		*af = AF_INET;
5716e91bba0SGirish Moodalbail 		*type = IPADM_ADDR_STATIC;
5726e91bba0SGirish Moodalbail 	} else if (strcmp(name, IPADM_NVP_IPV6ADDR) == 0) {
5736e91bba0SGirish Moodalbail 		*af = AF_INET6;
5746e91bba0SGirish Moodalbail 		*type = IPADM_ADDR_STATIC;
5756e91bba0SGirish Moodalbail 	} else if (strcmp(name, IPADM_NVP_DHCP) == 0) {
5766e91bba0SGirish Moodalbail 		*af = AF_INET;
5776e91bba0SGirish Moodalbail 		*type = IPADM_ADDR_DHCP;
5786e91bba0SGirish Moodalbail 	} else if (strcmp(name, IPADM_NVP_INTFID) == 0) {
5796e91bba0SGirish Moodalbail 		*af = AF_INET6;
5806e91bba0SGirish Moodalbail 		*type = IPADM_ADDR_IPV6_ADDRCONF;
5816e91bba0SGirish Moodalbail 	} else {
5826e91bba0SGirish Moodalbail 		is_addr = B_FALSE;
5836e91bba0SGirish Moodalbail 	}
5846e91bba0SGirish Moodalbail 
5856e91bba0SGirish Moodalbail 	return (is_addr);
5866e91bba0SGirish Moodalbail }
5876e91bba0SGirish Moodalbail 
5886e91bba0SGirish Moodalbail /*
5896e91bba0SGirish Moodalbail  * Parses the given nvlist `nvl' for an address or an address property.
5906e91bba0SGirish Moodalbail  * The input nvlist must contain either an address or an address property.
5916e91bba0SGirish Moodalbail  * `ainfo' is an input as well as output parameter. When an address or an
5926e91bba0SGirish Moodalbail  * address property is found, `ainfo' is updated with the information found.
5936e91bba0SGirish Moodalbail  * Some of the fields may be already filled in by the calling function.
5946e91bba0SGirish Moodalbail  *
5956e91bba0SGirish Moodalbail  * The fields that will be filled/updated by this function are `ia_pflags',
5966e91bba0SGirish Moodalbail  * `ia_sname' and `ia_dname'. Values for `ia_pflags' are obtained if the `nvl'
5976e91bba0SGirish Moodalbail  * contains an address property. `ia_sname', `ia_dname', and `ia_pflags' are
5986e91bba0SGirish Moodalbail  * obtained if `nvl' contains an address.
5996e91bba0SGirish Moodalbail  */
6006e91bba0SGirish Moodalbail static ipadm_status_t
i_ipadm_nvl2ainfo_common(nvlist_t * nvl,ipadm_addr_info_t * ainfo)6016e91bba0SGirish Moodalbail i_ipadm_nvl2ainfo_common(nvlist_t *nvl, ipadm_addr_info_t *ainfo)
6026e91bba0SGirish Moodalbail {
6036e91bba0SGirish Moodalbail 	nvlist_t		*nvladdr;
6046e91bba0SGirish Moodalbail 	char			*name;
6056e91bba0SGirish Moodalbail 	char			*propstr = NULL;
6066e91bba0SGirish Moodalbail 	char			*sname, *dname;
6076e91bba0SGirish Moodalbail 	nvpair_t		*nvp;
6086e91bba0SGirish Moodalbail 	sa_family_t		af;
6096e91bba0SGirish Moodalbail 	ipadm_addr_type_t	atype;
6106e91bba0SGirish Moodalbail 	boolean_t		is_addr = B_FALSE;
6116e91bba0SGirish Moodalbail 	int			err;
6126e91bba0SGirish Moodalbail 
6136e91bba0SGirish Moodalbail 	for (nvp = nvlist_next_nvpair(nvl, NULL); nvp != NULL;
6146e91bba0SGirish Moodalbail 	    nvp = nvlist_next_nvpair(nvl, nvp)) {
6156e91bba0SGirish Moodalbail 		name = nvpair_name(nvp);
6166e91bba0SGirish Moodalbail 		if (i_ipadm_name2atype(name, &af, &atype)) {
6176e91bba0SGirish Moodalbail 			err = nvpair_value_nvlist(nvp, &nvladdr);
6186e91bba0SGirish Moodalbail 			is_addr = B_TRUE;
6196e91bba0SGirish Moodalbail 		} else if (IPADM_PRIV_NVP(name)) {
6206e91bba0SGirish Moodalbail 			continue;
6216e91bba0SGirish Moodalbail 		} else {
6226e91bba0SGirish Moodalbail 			err = nvpair_value_string(nvp, &propstr);
6236e91bba0SGirish Moodalbail 		}
6246e91bba0SGirish Moodalbail 		if (err != 0)
6256e91bba0SGirish Moodalbail 			return (ipadm_errno2status(err));
6266e91bba0SGirish Moodalbail 	}
6276e91bba0SGirish Moodalbail 
6286e91bba0SGirish Moodalbail 	if (is_addr) {
6296e91bba0SGirish Moodalbail 		/*
6306e91bba0SGirish Moodalbail 		 * We got an address from the nvlist `nvl'.
6316e91bba0SGirish Moodalbail 		 * Parse `nvladdr' and populate relevant information
6326e91bba0SGirish Moodalbail 		 * in `ainfo'.
6336e91bba0SGirish Moodalbail 		 */
6346e91bba0SGirish Moodalbail 		switch (atype) {
6356e91bba0SGirish Moodalbail 		case IPADM_ADDR_STATIC:
6366e91bba0SGirish Moodalbail 			if (strcmp(name, "up") == 0 &&
6376e91bba0SGirish Moodalbail 			    strcmp(propstr, "yes") == 0) {
6386e91bba0SGirish Moodalbail 				ainfo->ia_pflags |= IA_UP;
6396e91bba0SGirish Moodalbail 			}
6406e91bba0SGirish Moodalbail 			/*
6416e91bba0SGirish Moodalbail 			 * For static addresses, we need to get the hostnames.
6426e91bba0SGirish Moodalbail 			 */
6436e91bba0SGirish Moodalbail 			err = nvlist_lookup_string(nvladdr,
6446e91bba0SGirish Moodalbail 			    IPADM_NVP_IPADDRHNAME, &sname);
6456e91bba0SGirish Moodalbail 			if (err != 0)
6466e91bba0SGirish Moodalbail 				return (ipadm_errno2status(err));
6476e91bba0SGirish Moodalbail 			(void) strlcpy(ainfo->ia_sname, sname,
6486e91bba0SGirish Moodalbail 			    sizeof (ainfo->ia_sname));
6496e91bba0SGirish Moodalbail 			err = nvlist_lookup_string(nvladdr,
6506e91bba0SGirish Moodalbail 			    IPADM_NVP_IPDADDRHNAME, &dname);
6516e91bba0SGirish Moodalbail 			if (err == 0) {
6526e91bba0SGirish Moodalbail 				(void) strlcpy(ainfo->ia_dname, dname,
6536e91bba0SGirish Moodalbail 				    sizeof (ainfo->ia_dname));
6546e91bba0SGirish Moodalbail 			}
6556e91bba0SGirish Moodalbail 			break;
6566e91bba0SGirish Moodalbail 		case IPADM_ADDR_DHCP:
6576e91bba0SGirish Moodalbail 		case IPADM_ADDR_IPV6_ADDRCONF:
6586e91bba0SGirish Moodalbail 			/*
6596e91bba0SGirish Moodalbail 			 * dhcp and addrconf address objects are always
6606e91bba0SGirish Moodalbail 			 * marked up when re-enabled.
6616e91bba0SGirish Moodalbail 			 */
6626e91bba0SGirish Moodalbail 			ainfo->ia_pflags |= IA_UP;
6636e91bba0SGirish Moodalbail 			break;
6646e91bba0SGirish Moodalbail 		default:
6656e91bba0SGirish Moodalbail 			return (IPADM_FAILURE);
6666e91bba0SGirish Moodalbail 		}
6676e91bba0SGirish Moodalbail 	} else {
6686e91bba0SGirish Moodalbail 		/*
6696e91bba0SGirish Moodalbail 		 * We got an address property from `nvl'. Parse the
6706e91bba0SGirish Moodalbail 		 * name and the property value. Update the `ainfo->ia_pflags'
6716e91bba0SGirish Moodalbail 		 * for the flags.
6726e91bba0SGirish Moodalbail 		 */
6736e91bba0SGirish Moodalbail 		if (strcmp(name, "deprecated") == 0) {
6746e91bba0SGirish Moodalbail 			if (strcmp(propstr, IPADM_ONSTR) == 0)
6756e91bba0SGirish Moodalbail 				ainfo->ia_pflags |= IA_DEPRECATED;
6766e91bba0SGirish Moodalbail 		} else if (strcmp(name, "private") == 0) {
6776e91bba0SGirish Moodalbail 			if (strcmp(propstr, IPADM_ONSTR) == 0)
6786e91bba0SGirish Moodalbail 				ainfo->ia_pflags |= IA_PRIVATE;
6796e91bba0SGirish Moodalbail 		}
6806e91bba0SGirish Moodalbail 	}
6816e91bba0SGirish Moodalbail 
6826e91bba0SGirish Moodalbail 	return (IPADM_SUCCESS);
6836e91bba0SGirish Moodalbail }
6846e91bba0SGirish Moodalbail 
6856e91bba0SGirish Moodalbail /*
6866e91bba0SGirish Moodalbail  * Parses the given nvlist `nvl' for an address or an address property.
6876e91bba0SGirish Moodalbail  * The input nvlist must contain either an address or an address property.
6886e91bba0SGirish Moodalbail  * `ainfo' is an input as well as output parameter. When an address or an
6896e91bba0SGirish Moodalbail  * address property is found, `ainfo' is updated with the information found.
6906e91bba0SGirish Moodalbail  * Some of the fields may be already filled in by the calling function,
6916e91bba0SGirish Moodalbail  * because of previous calls to i_ipadm_nvl2ainfo_active().
6926e91bba0SGirish Moodalbail  *
6936e91bba0SGirish Moodalbail  * Since the address object in `nvl' is also in the active configuration, the
6946e91bba0SGirish Moodalbail  * fields that will be filled/updated by this function are `ia_pflags',
6956e91bba0SGirish Moodalbail  * `ia_sname' and `ia_dname'.
6966e91bba0SGirish Moodalbail  *
6976e91bba0SGirish Moodalbail  * If this function returns an error, the calling function will take
6986e91bba0SGirish Moodalbail  * care of freeing the fields in `ainfo'.
6996e91bba0SGirish Moodalbail  */
7006e91bba0SGirish Moodalbail static ipadm_status_t
i_ipadm_nvl2ainfo_active(nvlist_t * nvl,ipadm_addr_info_t * ainfo)7016e91bba0SGirish Moodalbail i_ipadm_nvl2ainfo_active(nvlist_t *nvl, ipadm_addr_info_t *ainfo)
7026e91bba0SGirish Moodalbail {
7036e91bba0SGirish Moodalbail 	return (i_ipadm_nvl2ainfo_common(nvl, ainfo));
7046e91bba0SGirish Moodalbail }
7056e91bba0SGirish Moodalbail 
7066e91bba0SGirish Moodalbail /*
7076e91bba0SGirish Moodalbail  * Parses the given nvlist `nvl' for an address or an address property.
7086e91bba0SGirish Moodalbail  * The input nvlist must contain either an address or an address property.
7096e91bba0SGirish Moodalbail  * `ainfo' is an input as well as output parameter. When an address or an
7106e91bba0SGirish Moodalbail  * address property is found, `ainfo' is updated with the information found.
7116e91bba0SGirish Moodalbail  * Some of the fields may be already filled in by the calling function,
7126e91bba0SGirish Moodalbail  * because of previous calls to i_ipadm_nvl2ainfo_persist().
7136e91bba0SGirish Moodalbail  *
7146e91bba0SGirish Moodalbail  * All the relevant fields in `ainfo' will be filled by this function based
7156e91bba0SGirish Moodalbail  * on what we find in `nvl'.
7166e91bba0SGirish Moodalbail  *
7176e91bba0SGirish Moodalbail  * If this function returns an error, the calling function will take
7186e91bba0SGirish Moodalbail  * care of freeing the fields in `ainfo'.
7196e91bba0SGirish Moodalbail  */
7206e91bba0SGirish Moodalbail static ipadm_status_t
i_ipadm_nvl2ainfo_persist(nvlist_t * nvl,ipadm_addr_info_t * ainfo)7216e91bba0SGirish Moodalbail i_ipadm_nvl2ainfo_persist(nvlist_t *nvl, ipadm_addr_info_t *ainfo)
7226e91bba0SGirish Moodalbail {
7236e91bba0SGirish Moodalbail 	nvlist_t		*nvladdr;
7246e91bba0SGirish Moodalbail 	struct ifaddrs		*ifa;
7256e91bba0SGirish Moodalbail 	char			*name;
7266e91bba0SGirish Moodalbail 	char			*ifname = NULL;
7276e91bba0SGirish Moodalbail 	char			*aobjname = NULL;
7286e91bba0SGirish Moodalbail 	char			*propstr = NULL;
7296e91bba0SGirish Moodalbail 	nvpair_t		*nvp;
7306e91bba0SGirish Moodalbail 	sa_family_t		af;
7316e91bba0SGirish Moodalbail 	ipadm_addr_type_t	atype;
7326e91bba0SGirish Moodalbail 	boolean_t		is_addr = B_FALSE;
7336e91bba0SGirish Moodalbail 	size_t			size = sizeof (struct sockaddr_storage);
7346e91bba0SGirish Moodalbail 	uint32_t		plen = 0;
7356e91bba0SGirish Moodalbail 	int			err;
7366e91bba0SGirish Moodalbail 	ipadm_status_t		status;
7376e91bba0SGirish Moodalbail 
7386e91bba0SGirish Moodalbail 	status = i_ipadm_nvl2ainfo_common(nvl, ainfo);
7396e91bba0SGirish Moodalbail 	if (status != IPADM_SUCCESS)
7406e91bba0SGirish Moodalbail 		return (status);
7416e91bba0SGirish Moodalbail 
7426e91bba0SGirish Moodalbail 	for (nvp = nvlist_next_nvpair(nvl, NULL); nvp != NULL;
7436e91bba0SGirish Moodalbail 	    nvp = nvlist_next_nvpair(nvl, nvp)) {
7446e91bba0SGirish Moodalbail 		name = nvpair_name(nvp);
7456e91bba0SGirish Moodalbail 		if (strcmp(name, IPADM_NVP_IFNAME) == 0) {
7466e91bba0SGirish Moodalbail 			err = nvpair_value_string(nvp, &ifname);
7476e91bba0SGirish Moodalbail 		} else if (strcmp(name, IPADM_NVP_AOBJNAME) == 0) {
7486e91bba0SGirish Moodalbail 			err = nvpair_value_string(nvp, &aobjname);
7496e91bba0SGirish Moodalbail 		} else if (i_ipadm_name2atype(name, &af, &atype)) {
7506e91bba0SGirish Moodalbail 			err = nvpair_value_nvlist(nvp, &nvladdr);
7516e91bba0SGirish Moodalbail 			is_addr = B_TRUE;
7526e91bba0SGirish Moodalbail 		} else {
7536e91bba0SGirish Moodalbail 			err = nvpair_value_string(nvp, &propstr);
7546e91bba0SGirish Moodalbail 		}
7556e91bba0SGirish Moodalbail 		if (err != 0)
7566e91bba0SGirish Moodalbail 			return (ipadm_errno2status(err));
7576e91bba0SGirish Moodalbail 	}
7586e91bba0SGirish Moodalbail 
7596e91bba0SGirish Moodalbail 	ifa = &ainfo->ia_ifa;
7606e91bba0SGirish Moodalbail 	(void) strlcpy(ainfo->ia_aobjname, aobjname,
7616e91bba0SGirish Moodalbail 	    sizeof (ainfo->ia_aobjname));
7626e91bba0SGirish Moodalbail 	if (ifa->ifa_name == NULL && (ifa->ifa_name = strdup(ifname)) == NULL)
7636e91bba0SGirish Moodalbail 		return (IPADM_NO_MEMORY);
7646e91bba0SGirish Moodalbail 	if (is_addr) {
76564639aafSDarren Reed 		struct sockaddr_in6 data;
76664639aafSDarren Reed 
7676e91bba0SGirish Moodalbail 		/*
7686e91bba0SGirish Moodalbail 		 * We got an address from the nvlist `nvl'.
7696e91bba0SGirish Moodalbail 		 * Parse `nvladdr' and populate `ifa->ifa_addr'.
7706e91bba0SGirish Moodalbail 		 */
7716e91bba0SGirish Moodalbail 		ainfo->ia_atype = atype;
7726e91bba0SGirish Moodalbail 		if ((ifa->ifa_addr = calloc(1, size)) == NULL)
7736e91bba0SGirish Moodalbail 			return (IPADM_NO_MEMORY);
7746e91bba0SGirish Moodalbail 		switch (atype) {
7756e91bba0SGirish Moodalbail 		case IPADM_ADDR_STATIC:
77664639aafSDarren Reed 			ifa->ifa_addr->sa_family = af;
7776e91bba0SGirish Moodalbail 			break;
7786e91bba0SGirish Moodalbail 		case IPADM_ADDR_DHCP:
77964639aafSDarren Reed 			ifa->ifa_addr->sa_family = AF_INET;
7806e91bba0SGirish Moodalbail 			break;
7816e91bba0SGirish Moodalbail 		case IPADM_ADDR_IPV6_ADDRCONF:
78264639aafSDarren Reed 			data.sin6_family = AF_INET6;
7836e91bba0SGirish Moodalbail 			if (i_ipadm_nvl2in6_addr(nvladdr, IPADM_NVP_IPNUMADDR,
78464639aafSDarren Reed 			    &data.sin6_addr) != IPADM_SUCCESS)
7856e91bba0SGirish Moodalbail 				return (IPADM_NO_MEMORY);
7866e91bba0SGirish Moodalbail 			err = nvlist_lookup_uint32(nvladdr, IPADM_NVP_PREFIXLEN,
7876e91bba0SGirish Moodalbail 			    &plen);
7886e91bba0SGirish Moodalbail 			if (err != 0)
7896e91bba0SGirish Moodalbail 				return (ipadm_errno2status(err));
7906e91bba0SGirish Moodalbail 			if ((ifa->ifa_netmask = malloc(size)) == NULL)
7916e91bba0SGirish Moodalbail 				return (IPADM_NO_MEMORY);
7926e91bba0SGirish Moodalbail 			if ((err = plen2mask(plen, af, ifa->ifa_netmask)) != 0)
7936e91bba0SGirish Moodalbail 				return (ipadm_errno2status(err));
79464639aafSDarren Reed 			(void) memcpy(ifa->ifa_addr, &data, sizeof (data));
7956e91bba0SGirish Moodalbail 			break;
7966e91bba0SGirish Moodalbail 		default:
7976e91bba0SGirish Moodalbail 			return (IPADM_FAILURE);
7986e91bba0SGirish Moodalbail 		}
7996e91bba0SGirish Moodalbail 	} else {
8006e91bba0SGirish Moodalbail 		if (strcmp(name, "prefixlen") == 0) {
8016e91bba0SGirish Moodalbail 			/*
8026e91bba0SGirish Moodalbail 			 * If a prefixlen was found, update the
8036e91bba0SGirish Moodalbail 			 * `ainfo->ia_ifa.ifa_netmask'.
8046e91bba0SGirish Moodalbail 			 */
8056e91bba0SGirish Moodalbail 
8066e91bba0SGirish Moodalbail 			if ((ifa->ifa_netmask = malloc(size)) == NULL)
8076e91bba0SGirish Moodalbail 				return (IPADM_NO_MEMORY);
8086e91bba0SGirish Moodalbail 			/*
8096e91bba0SGirish Moodalbail 			 * Address property lines always follow the address
8106e91bba0SGirish Moodalbail 			 * line itself in the persistent db. We must have
8116e91bba0SGirish Moodalbail 			 * found a valid `ainfo->ia_ifa.ifa_addr' by now.
8126e91bba0SGirish Moodalbail 			 */
8136e91bba0SGirish Moodalbail 			assert(ifa->ifa_addr != NULL);
81464639aafSDarren Reed 			err = plen2mask(atoi(propstr), ifa->ifa_addr->sa_family,
8156e91bba0SGirish Moodalbail 			    ifa->ifa_netmask);
8166e91bba0SGirish Moodalbail 			if (err != 0)
8176e91bba0SGirish Moodalbail 				return (ipadm_errno2status(err));
8186e91bba0SGirish Moodalbail 		}
8196e91bba0SGirish Moodalbail 	}
8206e91bba0SGirish Moodalbail 
8216e91bba0SGirish Moodalbail 	return (IPADM_SUCCESS);
8226e91bba0SGirish Moodalbail }
8236e91bba0SGirish Moodalbail 
8246e91bba0SGirish Moodalbail /*
8256e91bba0SGirish Moodalbail  * Retrieves all addresses from active config and appends to it the
8266e91bba0SGirish Moodalbail  * addresses that are found only in persistent config. In addition,
8276e91bba0SGirish Moodalbail  * it updates the persistent fields for each address from information
8286e91bba0SGirish Moodalbail  * found in persistent config. The output parameter `addrinfo' contains
8296e91bba0SGirish Moodalbail  * complete information regarding all addresses in active as well as
8306e91bba0SGirish Moodalbail  * persistent config.
8316e91bba0SGirish Moodalbail  */
8326e91bba0SGirish 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)8336e91bba0SGirish Moodalbail i_ipadm_get_all_addr_info(ipadm_handle_t iph, const char *ifname,
8346e91bba0SGirish Moodalbail     ipadm_addr_info_t **addrinfo, uint32_t ipadm_flags, int64_t lifc_flags)
8356e91bba0SGirish Moodalbail {
8366e91bba0SGirish Moodalbail 	nvlist_t		*nvladdr = NULL;
8376e91bba0SGirish Moodalbail 	nvlist_t		*onvl = NULL;
8386e91bba0SGirish Moodalbail 	nvpair_t		*nvp;
8396e91bba0SGirish Moodalbail 	ipadm_status_t		status;
8406e91bba0SGirish Moodalbail 	ipadm_addr_info_t	*ainfo = NULL;
8416e91bba0SGirish Moodalbail 	ipadm_addr_info_t	*curr;
8426e91bba0SGirish Moodalbail 	ipadm_addr_info_t	*last = NULL;
8436e91bba0SGirish Moodalbail 	char			*aobjname;
8446e91bba0SGirish Moodalbail 
8456e91bba0SGirish Moodalbail 	/* Get all addresses from active config. */
8466e91bba0SGirish Moodalbail 	status = i_ipadm_active_addr_info(iph, ifname, &ainfo, ipadm_flags,
8476e91bba0SGirish Moodalbail 	    lifc_flags);
8486e91bba0SGirish Moodalbail 	if (status != IPADM_SUCCESS)
8496e91bba0SGirish Moodalbail 		goto fail;
8506e91bba0SGirish Moodalbail 
8516e91bba0SGirish Moodalbail 	/* Get all addresses from persistent config. */
8526e91bba0SGirish Moodalbail 	status = i_ipadm_get_db_addr(iph, ifname, NULL, &onvl);
8536e91bba0SGirish Moodalbail 	/*
8546e91bba0SGirish Moodalbail 	 * If no address was found in persistent config, just
8556e91bba0SGirish Moodalbail 	 * return what we found in active config.
8566e91bba0SGirish Moodalbail 	 */
8576e91bba0SGirish Moodalbail 	if (status == IPADM_NOTFOUND) {
8586e91bba0SGirish Moodalbail 		/*
8596e91bba0SGirish Moodalbail 		 * If nothing was found neither active nor persistent
8606e91bba0SGirish Moodalbail 		 * config, this means that the interface does not exist,
8616e91bba0SGirish Moodalbail 		 * if one was provided in `ifname'.
8626e91bba0SGirish Moodalbail 		 */
8636e91bba0SGirish Moodalbail 		if (ainfo == NULL && ifname != NULL)
8646e91bba0SGirish Moodalbail 			return (IPADM_ENXIO);
8656e91bba0SGirish Moodalbail 		*addrinfo = ainfo;
8666e91bba0SGirish Moodalbail 		return (IPADM_SUCCESS);
8676e91bba0SGirish Moodalbail 	}
8686e91bba0SGirish Moodalbail 	/* In case of any other error, cleanup and return. */
8696e91bba0SGirish Moodalbail 	if (status != IPADM_SUCCESS)
8706e91bba0SGirish Moodalbail 		goto fail;
8716e91bba0SGirish Moodalbail 	/* we append to make sure, loopback addresses are first */
8726e91bba0SGirish Moodalbail 	if (ainfo != NULL) {
8736e91bba0SGirish Moodalbail 		for (curr = ainfo; IA_NEXT(curr) != NULL; curr = IA_NEXT(curr))
8746e91bba0SGirish Moodalbail 			;
8756e91bba0SGirish Moodalbail 		last = curr;
8766e91bba0SGirish Moodalbail 	}
8776e91bba0SGirish Moodalbail 
8786e91bba0SGirish Moodalbail 	/*
8796e91bba0SGirish Moodalbail 	 * `onvl' will contain all the address lines from the db. Each line
8806e91bba0SGirish Moodalbail 	 * could contain the address itself or an address property. Addresses
8816e91bba0SGirish Moodalbail 	 * and address properties are found in separate lines.
8826e91bba0SGirish Moodalbail 	 *
8836e91bba0SGirish Moodalbail 	 * If an address A was found in active, we will already have `ainfo',
8846e91bba0SGirish Moodalbail 	 * and it is present in persistent configuration as well, we need to
8856e91bba0SGirish Moodalbail 	 * update `ainfo' with persistent information (`ia_pflags).
8866e91bba0SGirish Moodalbail 	 * For each address B found only in persistent configuration,
8876e91bba0SGirish Moodalbail 	 * append the address to the list with the address info for B from
8886e91bba0SGirish Moodalbail 	 * `onvl'.
8896e91bba0SGirish Moodalbail 	 */
8906e91bba0SGirish Moodalbail 	for (nvp = nvlist_next_nvpair(onvl, NULL); nvp != NULL;
8916e91bba0SGirish Moodalbail 	    nvp = nvlist_next_nvpair(onvl, nvp)) {
8926e91bba0SGirish Moodalbail 		if (nvpair_value_nvlist(nvp, &nvladdr) != 0)
8936e91bba0SGirish Moodalbail 			continue;
8946e91bba0SGirish Moodalbail 		if (nvlist_lookup_string(nvladdr, IPADM_NVP_AOBJNAME,
8956e91bba0SGirish Moodalbail 		    &aobjname) != 0)
8966e91bba0SGirish Moodalbail 			continue;
8976e91bba0SGirish Moodalbail 		for (curr = ainfo; curr != NULL; curr = IA_NEXT(curr)) {
8986e91bba0SGirish Moodalbail 			if (strcmp(curr->ia_aobjname, aobjname) == 0)
8996e91bba0SGirish Moodalbail 				break;
9006e91bba0SGirish Moodalbail 		}
9016e91bba0SGirish Moodalbail 		if (curr == NULL) {
9026e91bba0SGirish Moodalbail 			/*
9036e91bba0SGirish Moodalbail 			 * We did not find this address object in `ainfo'.
9046e91bba0SGirish Moodalbail 			 * This means that the address object exists only
9056e91bba0SGirish Moodalbail 			 * in the persistent configuration. Get its
9066e91bba0SGirish Moodalbail 			 * details and append to `ainfo'.
9076e91bba0SGirish Moodalbail 			 */
9086e91bba0SGirish Moodalbail 			curr = calloc(1, sizeof (ipadm_addr_info_t));
9096e91bba0SGirish Moodalbail 			if (curr == NULL)
9106e91bba0SGirish Moodalbail 				goto fail;
9116e91bba0SGirish Moodalbail 			curr->ia_state = IFA_DISABLED;
9126e91bba0SGirish Moodalbail 			if (last != NULL)
9136e91bba0SGirish Moodalbail 				last->ia_ifa.ifa_next = &curr->ia_ifa;
9146e91bba0SGirish Moodalbail 			else
9156e91bba0SGirish Moodalbail 				ainfo = curr;
9166e91bba0SGirish Moodalbail 			last = curr;
9176e91bba0SGirish Moodalbail 		}
9186e91bba0SGirish Moodalbail 		/*
9196e91bba0SGirish Moodalbail 		 * Fill relevant fields of `curr' from the persistent info
9206e91bba0SGirish Moodalbail 		 * in `nvladdr'. Call the appropriate function based on the
9216e91bba0SGirish Moodalbail 		 * `ia_state' value.
9226e91bba0SGirish Moodalbail 		 */
9236e91bba0SGirish Moodalbail 		if (curr->ia_state == IFA_DISABLED)
9246e91bba0SGirish Moodalbail 			status = i_ipadm_nvl2ainfo_persist(nvladdr, curr);
9256e91bba0SGirish Moodalbail 		else
9266e91bba0SGirish Moodalbail 			status = i_ipadm_nvl2ainfo_active(nvladdr, curr);
9276e91bba0SGirish Moodalbail 		if (status != IPADM_SUCCESS)
9286e91bba0SGirish Moodalbail 			goto fail;
9296e91bba0SGirish Moodalbail 	}
9306e91bba0SGirish Moodalbail 	*addrinfo = ainfo;
9316e91bba0SGirish Moodalbail 	nvlist_free(onvl);
9326e91bba0SGirish Moodalbail 	return (status);
9336e91bba0SGirish Moodalbail fail:
9346e91bba0SGirish Moodalbail 	/* On error, cleanup and return. */
9356e91bba0SGirish Moodalbail 	nvlist_free(onvl);
9366e91bba0SGirish Moodalbail 	ipadm_free_addr_info(ainfo);
9376e91bba0SGirish Moodalbail 	*addrinfo = NULL;
9386e91bba0SGirish Moodalbail 	return (status);
9396e91bba0SGirish Moodalbail }
9406e91bba0SGirish Moodalbail 
9416e91bba0SGirish Moodalbail /*
9426e91bba0SGirish Moodalbail  * Callback function that sets the property `prefixlen' on the address
9436e91bba0SGirish Moodalbail  * object in `arg' to the value in `pval'.
9446e91bba0SGirish Moodalbail  */
9456e91bba0SGirish Moodalbail /* ARGSUSED */
9466e91bba0SGirish 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)9476e91bba0SGirish Moodalbail i_ipadm_set_prefixlen(ipadm_handle_t iph, const void *arg,
9486e91bba0SGirish Moodalbail     ipadm_prop_desc_t *pdp, const void *pval, uint_t af, uint_t flags)
9496e91bba0SGirish Moodalbail {
9506e91bba0SGirish Moodalbail 	struct sockaddr_storage	netmask;
9516e91bba0SGirish Moodalbail 	struct lifreq		lifr;
9526e91bba0SGirish Moodalbail 	int			err, s;
9536e91bba0SGirish Moodalbail 	unsigned long		prefixlen, abits;
9546e91bba0SGirish Moodalbail 	char			*end;
9556e91bba0SGirish Moodalbail 	ipadm_addrobj_t		ipaddr = (ipadm_addrobj_t)arg;
9566e91bba0SGirish Moodalbail 
9576e91bba0SGirish Moodalbail 	if (ipaddr->ipadm_atype == IPADM_ADDR_DHCP)
9586e91bba0SGirish Moodalbail 		return (IPADM_NOTSUP);
9596e91bba0SGirish Moodalbail 
9606e91bba0SGirish Moodalbail 	errno = 0;
9616e91bba0SGirish Moodalbail 	prefixlen = strtoul(pval, &end, 10);
9626e91bba0SGirish Moodalbail 	if (errno != 0 || *end != '\0')
9636e91bba0SGirish Moodalbail 		return (IPADM_INVALID_ARG);
9646e91bba0SGirish Moodalbail 
9656e91bba0SGirish Moodalbail 	abits = (af == AF_INET ? IP_ABITS : IPV6_ABITS);
9666e91bba0SGirish Moodalbail 	if (prefixlen == 0 || prefixlen == (abits - 1))
9676e91bba0SGirish Moodalbail 		return (IPADM_INVALID_ARG);
9686e91bba0SGirish Moodalbail 
96964639aafSDarren Reed 	if ((err = plen2mask(prefixlen, af, (struct sockaddr *)&netmask)) != 0)
9706e91bba0SGirish Moodalbail 		return (ipadm_errno2status(err));
9716e91bba0SGirish Moodalbail 
9726e91bba0SGirish Moodalbail 	s = (af == AF_INET ? iph->iph_sock : iph->iph_sock6);
9736e91bba0SGirish Moodalbail 
9746e91bba0SGirish Moodalbail 	bzero(&lifr, sizeof (lifr));
9756e91bba0SGirish Moodalbail 	i_ipadm_addrobj2lifname(ipaddr, lifr.lifr_name,
9766e91bba0SGirish Moodalbail 	    sizeof (lifr.lifr_name));
9776e91bba0SGirish Moodalbail 	(void) memcpy(&lifr.lifr_addr, &netmask, sizeof (netmask));
9786e91bba0SGirish Moodalbail 	if (ioctl(s, SIOCSLIFNETMASK, (caddr_t)&lifr) < 0)
9796e91bba0SGirish Moodalbail 		return (ipadm_errno2status(errno));
9806e91bba0SGirish Moodalbail 
9816e91bba0SGirish Moodalbail 	/* now, change the broadcast address to reflect the prefixlen */
9826e91bba0SGirish Moodalbail 	if (af == AF_INET) {
9836e91bba0SGirish Moodalbail 		/*
9846e91bba0SGirish Moodalbail 		 * get the interface address and set it, this should reset
9856e91bba0SGirish Moodalbail 		 * the broadcast address.
9866e91bba0SGirish Moodalbail 		 */
9876e91bba0SGirish Moodalbail 		(void) ioctl(s, SIOCGLIFADDR, (caddr_t)&lifr);
9886e91bba0SGirish Moodalbail 		(void) ioctl(s, SIOCSLIFADDR, (caddr_t)&lifr);
9896e91bba0SGirish Moodalbail 	}
9906e91bba0SGirish Moodalbail 
9916e91bba0SGirish Moodalbail 	return (IPADM_SUCCESS);
9926e91bba0SGirish Moodalbail }
9936e91bba0SGirish Moodalbail 
9946e91bba0SGirish Moodalbail 
9956e91bba0SGirish Moodalbail /*
9966e91bba0SGirish Moodalbail  * Callback function that sets the given value `pval' to one of the
9976e91bba0SGirish Moodalbail  * properties among `deprecated', `private', and `transmit' as defined in
9986e91bba0SGirish Moodalbail  * `pdp', on the address object in `arg'.
9996e91bba0SGirish Moodalbail  */
10006e91bba0SGirish Moodalbail /* ARGSUSED */
10016e91bba0SGirish 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)10026e91bba0SGirish Moodalbail i_ipadm_set_addr_flag(ipadm_handle_t iph, const void *arg,
10036e91bba0SGirish Moodalbail     ipadm_prop_desc_t *pdp, const void *pval, uint_t af, uint_t flags)
10046e91bba0SGirish Moodalbail {
10056e91bba0SGirish Moodalbail 	char		lifname[LIFNAMSIZ];
10066e91bba0SGirish Moodalbail 	uint64_t	on_flags = 0, off_flags = 0;
10076e91bba0SGirish Moodalbail 	boolean_t	on;
10086e91bba0SGirish Moodalbail 	ipadm_addrobj_t	ipaddr = (ipadm_addrobj_t)arg;
10096e91bba0SGirish Moodalbail 
10106e91bba0SGirish Moodalbail 	if (ipaddr->ipadm_atype == IPADM_ADDR_DHCP &&
10116e91bba0SGirish Moodalbail 	    strcmp(pdp->ipd_name, "deprecated") == 0)
10126e91bba0SGirish Moodalbail 		return (IPADM_NOTSUP);
10136e91bba0SGirish Moodalbail 
10146e91bba0SGirish Moodalbail 	if (strcmp(pval, IPADM_ONSTR) == 0)
10156e91bba0SGirish Moodalbail 		on = B_TRUE;
10166e91bba0SGirish Moodalbail 	else if (strcmp(pval, IPADM_OFFSTR) == 0)
10176e91bba0SGirish Moodalbail 		on = B_FALSE;
10186e91bba0SGirish Moodalbail 	else
10196e91bba0SGirish Moodalbail 		return (IPADM_INVALID_ARG);
10206e91bba0SGirish Moodalbail 
10216e91bba0SGirish Moodalbail 	if (strcmp(pdp->ipd_name, "private") == 0) {
10226e91bba0SGirish Moodalbail 		if (on)
10236e91bba0SGirish Moodalbail 			on_flags = IFF_PRIVATE;
10246e91bba0SGirish Moodalbail 		else
10256e91bba0SGirish Moodalbail 			off_flags = IFF_PRIVATE;
10266e91bba0SGirish Moodalbail 	} else if (strcmp(pdp->ipd_name, "transmit") == 0) {
10276e91bba0SGirish Moodalbail 		if (on)
10286e91bba0SGirish Moodalbail 			off_flags = IFF_NOXMIT;
10296e91bba0SGirish Moodalbail 		else
10306e91bba0SGirish Moodalbail 			on_flags = IFF_NOXMIT;
10316e91bba0SGirish Moodalbail 	} else if (strcmp(pdp->ipd_name, "deprecated") == 0) {
10326e91bba0SGirish Moodalbail 		if (on)
10336e91bba0SGirish Moodalbail 			on_flags = IFF_DEPRECATED;
10346e91bba0SGirish Moodalbail 		else
10356e91bba0SGirish Moodalbail 			off_flags = IFF_DEPRECATED;
10366e91bba0SGirish Moodalbail 	} else {
10376e91bba0SGirish Moodalbail 		return (IPADM_PROP_UNKNOWN);
10386e91bba0SGirish Moodalbail 	}
10396e91bba0SGirish Moodalbail 
10406e91bba0SGirish Moodalbail 	i_ipadm_addrobj2lifname(ipaddr, lifname, sizeof (lifname));
10416e91bba0SGirish Moodalbail 	return (i_ipadm_set_flags(iph, lifname, af, on_flags, off_flags));
10426e91bba0SGirish Moodalbail }
10436e91bba0SGirish Moodalbail 
10446e91bba0SGirish Moodalbail /*
10456e91bba0SGirish Moodalbail  * Callback function that sets the property `zone' on the address
10466e91bba0SGirish Moodalbail  * object in `arg' to the value in `pval'.
10476e91bba0SGirish Moodalbail  */
10486e91bba0SGirish Moodalbail /* ARGSUSED */
10496e91bba0SGirish 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)10506e91bba0SGirish Moodalbail i_ipadm_set_zone(ipadm_handle_t iph, const void *arg,
10516e91bba0SGirish Moodalbail     ipadm_prop_desc_t *pdp, const void *pval, uint_t af, uint_t flags)
10526e91bba0SGirish Moodalbail {
10536e91bba0SGirish Moodalbail 	struct lifreq	lifr;
10546e91bba0SGirish Moodalbail 	zoneid_t	zoneid;
10556e91bba0SGirish Moodalbail 	int		s;
10566e91bba0SGirish Moodalbail 
10576e91bba0SGirish Moodalbail 	/*
10586e91bba0SGirish Moodalbail 	 * To modify the zone assignment such that it persists across
1059bbf21555SRichard Lowe 	 * reboots, zonecfg(8) must be used.
10606e91bba0SGirish Moodalbail 	 */
10616e91bba0SGirish Moodalbail 	if (flags & IPADM_OPT_PERSIST) {
10626e91bba0SGirish Moodalbail 		return (IPADM_NOTSUP);
10636e91bba0SGirish Moodalbail 	} else if (flags & IPADM_OPT_ACTIVE) {
10646e91bba0SGirish Moodalbail 		/* put logical interface into all zones */
10656e91bba0SGirish Moodalbail 		if (strcmp(pval, "all-zones") == 0) {
10666e91bba0SGirish Moodalbail 			zoneid = ALL_ZONES;
10676e91bba0SGirish Moodalbail 		} else {
10686e91bba0SGirish Moodalbail 			/* zone must be ready or running */
10696e91bba0SGirish Moodalbail 			if ((zoneid = getzoneidbyname(pval)) == -1)
10706e91bba0SGirish Moodalbail 				return (ipadm_errno2status(errno));
10716e91bba0SGirish Moodalbail 		}
10726e91bba0SGirish Moodalbail 	} else {
10736e91bba0SGirish Moodalbail 		return (IPADM_INVALID_ARG);
10746e91bba0SGirish Moodalbail 	}
10756e91bba0SGirish Moodalbail 
10766e91bba0SGirish Moodalbail 	s = (af == AF_INET ? iph->iph_sock : iph->iph_sock6);
10776e91bba0SGirish Moodalbail 	bzero(&lifr, sizeof (lifr));
10786e91bba0SGirish Moodalbail 	i_ipadm_addrobj2lifname((ipadm_addrobj_t)arg, lifr.lifr_name,
10796e91bba0SGirish Moodalbail 	    sizeof (lifr.lifr_name));
10806e91bba0SGirish Moodalbail 	lifr.lifr_zoneid = zoneid;
10816e91bba0SGirish Moodalbail 	if (ioctl(s, SIOCSLIFZONE, (caddr_t)&lifr) < 0)
10826e91bba0SGirish Moodalbail 		return (ipadm_errno2status(errno));
10836e91bba0SGirish Moodalbail 
10846e91bba0SGirish Moodalbail 	return (IPADM_SUCCESS);
10856e91bba0SGirish Moodalbail }
10866e91bba0SGirish Moodalbail 
1087b31320a7SChris Fraire /*
1088b31320a7SChris Fraire  * Callback function that sets the property `reqhost' on the address
1089b31320a7SChris Fraire  * object in `arg' to the value in `pval'.
1090b31320a7SChris Fraire  */
1091b31320a7SChris Fraire /* ARGSUSED */
1092b31320a7SChris Fraire static ipadm_status_t
i_ipadm_set_reqhost(ipadm_handle_t iph,const void * arg,ipadm_prop_desc_t * pdp,const void * pval,uint_t af,uint_t flags)1093b31320a7SChris Fraire i_ipadm_set_reqhost(ipadm_handle_t iph, const void *arg,
1094b31320a7SChris Fraire     ipadm_prop_desc_t *pdp, const void *pval, uint_t af, uint_t flags)
1095b31320a7SChris Fraire {
1096b31320a7SChris Fraire 	ipadm_status_t		status;
1097b31320a7SChris Fraire 	ipadm_addrobj_t		ipaddr = (ipadm_addrobj_t)arg;
1098b31320a7SChris Fraire 
1099b31320a7SChris Fraire 	if (ipaddr->ipadm_atype != IPADM_ADDR_DHCP)
1100b31320a7SChris Fraire 		return (IPADM_NOTSUP);
1101b31320a7SChris Fraire 
1102b31320a7SChris Fraire 	/*
1103b31320a7SChris Fraire 	 * If requested to set reqhost just from active config but the
1104b31320a7SChris Fraire 	 * address is not in active config, return error.
1105b31320a7SChris Fraire 	 */
1106b31320a7SChris Fraire 	if (!(ipaddr->ipadm_flags & IPMGMT_ACTIVE) &&
1107b31320a7SChris Fraire 	    (flags & IPADM_OPT_ACTIVE) && !(flags & IPADM_OPT_PERSIST)) {
1108b31320a7SChris Fraire 		return (IPADM_NOTFOUND);
1109b31320a7SChris Fraire 	}
1110b31320a7SChris Fraire 
1111b31320a7SChris Fraire 	status = ipadm_set_reqhost(ipaddr, pval);
1112b31320a7SChris Fraire 	if (status != IPADM_SUCCESS)
1113b31320a7SChris Fraire 		return (status);
1114b31320a7SChris Fraire 
1115b31320a7SChris Fraire 	if (ipaddr->ipadm_flags & IPMGMT_ACTIVE) {
1116b31320a7SChris Fraire 		status = i_ipadm_refresh_dhcp(ipaddr);
1117b31320a7SChris Fraire 
1118b31320a7SChris Fraire 		/*
1119b31320a7SChris Fraire 		 * We do not report a problem for IPADM_DHCP_IPC_TIMEOUT since
1120b31320a7SChris Fraire 		 * it is only a soft error to indicate the caller that the
1121b31320a7SChris Fraire 		 * lease might be renewed after the function returns.
1122b31320a7SChris Fraire 		 */
1123b31320a7SChris Fraire 		if (status != IPADM_SUCCESS && status != IPADM_DHCP_IPC_TIMEOUT)
1124b31320a7SChris Fraire 			return (status);
1125b31320a7SChris Fraire 	}
1126b31320a7SChris Fraire 
1127b31320a7SChris Fraire 	status = i_ipadm_set_aobj_addrprop(iph, ipaddr, flags,
1128b31320a7SChris Fraire 	    IPADM_NVP_REQHOST);
1129b31320a7SChris Fraire 	return (status);
1130b31320a7SChris Fraire }
1131b31320a7SChris Fraire 
1132b31320a7SChris Fraire /*
1133b31320a7SChris Fraire  * Used by address object property callback functions that need to do a
1134b31320a7SChris Fraire  * two-stage update because the addrprop is cached on the address object.
1135b31320a7SChris Fraire  */
1136b31320a7SChris Fraire static ipadm_status_t
i_ipadm_set_aobj_addrprop(ipadm_handle_t iph,ipadm_addrobj_t ipaddr,uint_t flags,const char * propname)1137b31320a7SChris Fraire i_ipadm_set_aobj_addrprop(ipadm_handle_t iph, ipadm_addrobj_t ipaddr,
1138b31320a7SChris Fraire     uint_t flags, const char *propname)
1139b31320a7SChris Fraire {
1140b31320a7SChris Fraire 	ipadm_status_t	status;
1141b31320a7SChris Fraire 	uint32_t	two_stage_flags;
1142b31320a7SChris Fraire 
1143b31320a7SChris Fraire 	/*
1144b31320a7SChris Fraire 	 * Send the updated address object information to ipmgmtd, since the
1145b31320a7SChris Fraire 	 * cached version of an addrprop resides on an aobjmap, but do
1146b31320a7SChris Fraire 	 * not change the ACTIVE/PERSIST state of the aobjmap. Instead, request
1147b31320a7SChris Fraire 	 * a two-stage, SET_PROPS update with ACTIVE/PERSIST as the first stage
1148b31320a7SChris Fraire 	 * per the existing aobjmap flags and a second stage encoded in
1149b31320a7SChris Fraire 	 * IPADM_OPT_PERSIST_PROPS.
1150b31320a7SChris Fraire 	 */
1151b31320a7SChris Fraire 	two_stage_flags = (flags | IPADM_OPT_SET_PROPS)
1152b31320a7SChris Fraire 	    & ~(IPADM_OPT_ACTIVE | IPADM_OPT_PERSIST);
1153b31320a7SChris Fraire 	if (ipaddr->ipadm_flags & IPMGMT_ACTIVE)
1154b31320a7SChris Fraire 		two_stage_flags |= IPADM_OPT_ACTIVE;
1155b31320a7SChris Fraire 	if (ipaddr->ipadm_flags & IPMGMT_PERSIST)
1156b31320a7SChris Fraire 		two_stage_flags |= IPADM_OPT_PERSIST;
1157b31320a7SChris Fraire 	if (flags & IPADM_OPT_PERSIST)
1158b31320a7SChris Fraire 		two_stage_flags |= IPADM_OPT_PERSIST_PROPS;
1159b31320a7SChris Fraire 
1160b31320a7SChris Fraire 	status = i_ipadm_addr_persist(iph, ipaddr, B_FALSE, two_stage_flags,
1161b31320a7SChris Fraire 	    propname);
1162b31320a7SChris Fraire 	return (status);
1163b31320a7SChris Fraire }
1164b31320a7SChris Fraire 
11656e91bba0SGirish Moodalbail /*
11666e91bba0SGirish Moodalbail  * Callback function that gets the property `broadcast' for the address
11676e91bba0SGirish Moodalbail  * object in `arg'.
11686e91bba0SGirish Moodalbail  */
11696e91bba0SGirish Moodalbail /* ARGSUSED */
11706e91bba0SGirish 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)11716e91bba0SGirish Moodalbail i_ipadm_get_broadcast(ipadm_handle_t iph, const void *arg,
11726e91bba0SGirish Moodalbail     ipadm_prop_desc_t *pdp, char *buf, uint_t *bufsize, uint_t af,
11736e91bba0SGirish Moodalbail     uint_t valtype)
11746e91bba0SGirish Moodalbail {
11756e91bba0SGirish Moodalbail 	struct sockaddr_in	*sin;
11766e91bba0SGirish Moodalbail 	struct lifreq		lifr;
11776e91bba0SGirish Moodalbail 	char			lifname[LIFNAMSIZ];
11786e91bba0SGirish Moodalbail 	ipadm_addrobj_t		ipaddr = (ipadm_addrobj_t)arg;
11796e91bba0SGirish Moodalbail 	ipadm_status_t		status;
11806e91bba0SGirish Moodalbail 	size_t			nbytes = 0;
11816e91bba0SGirish Moodalbail 	uint64_t		ifflags = 0;
11826e91bba0SGirish Moodalbail 
11836e91bba0SGirish Moodalbail 	i_ipadm_addrobj2lifname(ipaddr, lifname, sizeof (lifname));
11846e91bba0SGirish Moodalbail 	if (ipaddr->ipadm_flags & IPMGMT_ACTIVE) {
11856e91bba0SGirish Moodalbail 		status = i_ipadm_get_flags(iph, lifname, af, &ifflags);
11866e91bba0SGirish Moodalbail 		if (status != IPADM_SUCCESS)
11876e91bba0SGirish Moodalbail 			return (status);
11886e91bba0SGirish Moodalbail 		if (!(ifflags & IFF_BROADCAST)) {
11896e91bba0SGirish Moodalbail 			buf[0] = '\0';
11906e91bba0SGirish Moodalbail 			return (IPADM_SUCCESS);
11916e91bba0SGirish Moodalbail 		}
11926e91bba0SGirish Moodalbail 	}
11936e91bba0SGirish Moodalbail 
11946e91bba0SGirish Moodalbail 	switch (valtype) {
11956e91bba0SGirish Moodalbail 	case MOD_PROP_DEFAULT: {
11966e91bba0SGirish Moodalbail 		struct sockaddr_storage	mask;
11976e91bba0SGirish Moodalbail 		struct in_addr		broadaddr;
11986e91bba0SGirish Moodalbail 		uint_t			plen;
11996e91bba0SGirish Moodalbail 		in_addr_t		addr, maddr;
12006e91bba0SGirish Moodalbail 		char			val[MAXPROPVALLEN];
12016e91bba0SGirish Moodalbail 		uint_t			valsz = MAXPROPVALLEN;
12026e91bba0SGirish Moodalbail 		ipadm_status_t		status;
12036e91bba0SGirish Moodalbail 		int			err;
12046e91bba0SGirish Moodalbail 		struct sockaddr_in	*sin;
12056e91bba0SGirish Moodalbail 
12066e91bba0SGirish Moodalbail 		if (!(ipaddr->ipadm_flags & IPMGMT_ACTIVE)) {
12076e91bba0SGirish Moodalbail 			/*
12086e91bba0SGirish Moodalbail 			 * Since the address is unknown we cannot
12096e91bba0SGirish Moodalbail 			 * obtain default prefixlen
12106e91bba0SGirish Moodalbail 			 */
12116e91bba0SGirish Moodalbail 			if (ipaddr->ipadm_atype == IPADM_ADDR_DHCP ||
12126e91bba0SGirish Moodalbail 			    ipaddr->ipadm_af == AF_INET6) {
12136e91bba0SGirish Moodalbail 				buf[0] = '\0';
12146e91bba0SGirish Moodalbail 				return (IPADM_SUCCESS);
12156e91bba0SGirish Moodalbail 			}
12166e91bba0SGirish Moodalbail 			/*
12176e91bba0SGirish Moodalbail 			 * For the static address, we get the address from the
12186e91bba0SGirish Moodalbail 			 * persistent db.
12196e91bba0SGirish Moodalbail 			 */
12206e91bba0SGirish Moodalbail 			status = i_ipadm_get_static_addr_db(iph, ipaddr);
12216e91bba0SGirish Moodalbail 			if (status != IPADM_SUCCESS)
12226e91bba0SGirish Moodalbail 				return (status);
12236e91bba0SGirish Moodalbail 			sin = SIN(&ipaddr->ipadm_static_addr);
12246e91bba0SGirish Moodalbail 			addr = sin->sin_addr.s_addr;
12256e91bba0SGirish Moodalbail 		} else {
12266e91bba0SGirish Moodalbail 			/*
12276e91bba0SGirish Moodalbail 			 * If the address object is active, we retrieve the
12286e91bba0SGirish Moodalbail 			 * address from kernel.
12296e91bba0SGirish Moodalbail 			 */
12306e91bba0SGirish Moodalbail 			bzero(&lifr, sizeof (lifr));
12316e91bba0SGirish Moodalbail 			(void) strlcpy(lifr.lifr_name, lifname,
12326e91bba0SGirish Moodalbail 			    sizeof (lifr.lifr_name));
12336e91bba0SGirish Moodalbail 			if (ioctl(iph->iph_sock, SIOCGLIFADDR,
12346e91bba0SGirish Moodalbail 			    (caddr_t)&lifr) < 0)
12356e91bba0SGirish Moodalbail 				return (ipadm_errno2status(errno));
12366e91bba0SGirish Moodalbail 
12376e91bba0SGirish Moodalbail 			addr = (SIN(&lifr.lifr_addr))->sin_addr.s_addr;
12386e91bba0SGirish Moodalbail 		}
12396e91bba0SGirish Moodalbail 		/*
12406e91bba0SGirish Moodalbail 		 * For default broadcast address, get the address and the
12416e91bba0SGirish Moodalbail 		 * default prefixlen for that address and then compute the
12426e91bba0SGirish Moodalbail 		 * broadcast address.
12436e91bba0SGirish Moodalbail 		 */
12446e91bba0SGirish Moodalbail 		status = i_ipadm_get_prefixlen(iph, arg, NULL, val, &valsz, af,
12456e91bba0SGirish Moodalbail 		    MOD_PROP_DEFAULT);
12466e91bba0SGirish Moodalbail 		if (status != IPADM_SUCCESS)
12476e91bba0SGirish Moodalbail 			return (status);
12486e91bba0SGirish Moodalbail 
12496e91bba0SGirish Moodalbail 		plen = atoi(val);
125064639aafSDarren Reed 		if ((err = plen2mask(plen, AF_INET,
125164639aafSDarren Reed 		    (struct sockaddr *)&mask)) != 0)
12526e91bba0SGirish Moodalbail 			return (ipadm_errno2status(err));
12536e91bba0SGirish Moodalbail 		maddr = (SIN(&mask))->sin_addr.s_addr;
12546e91bba0SGirish Moodalbail 		broadaddr.s_addr = (addr & maddr) | ~maddr;
12556e91bba0SGirish Moodalbail 		nbytes = snprintf(buf, *bufsize, "%s", inet_ntoa(broadaddr));
12566e91bba0SGirish Moodalbail 		break;
12576e91bba0SGirish Moodalbail 	}
12586e91bba0SGirish Moodalbail 	case MOD_PROP_ACTIVE:
12596e91bba0SGirish Moodalbail 		bzero(&lifr, sizeof (lifr));
12606e91bba0SGirish Moodalbail 		(void) strlcpy(lifr.lifr_name, lifname,
12616e91bba0SGirish Moodalbail 		    sizeof (lifr.lifr_name));
12626e91bba0SGirish Moodalbail 		if (ioctl(iph->iph_sock, SIOCGLIFBRDADDR,
12636e91bba0SGirish Moodalbail 		    (caddr_t)&lifr) < 0) {
12646e91bba0SGirish Moodalbail 			return (ipadm_errno2status(errno));
12656e91bba0SGirish Moodalbail 		} else {
12666e91bba0SGirish Moodalbail 			sin = SIN(&lifr.lifr_addr);
12676e91bba0SGirish Moodalbail 			nbytes = snprintf(buf, *bufsize, "%s",
12686e91bba0SGirish Moodalbail 			    inet_ntoa(sin->sin_addr));
12696e91bba0SGirish Moodalbail 		}
12706e91bba0SGirish Moodalbail 		break;
12716e91bba0SGirish Moodalbail 	default:
12726e91bba0SGirish Moodalbail 		return (IPADM_INVALID_ARG);
12736e91bba0SGirish Moodalbail 	}
12746e91bba0SGirish Moodalbail 	if (nbytes >= *bufsize) {
12756e91bba0SGirish Moodalbail 		/* insufficient buffer space */
12766e91bba0SGirish Moodalbail 		*bufsize = nbytes + 1;
12776e91bba0SGirish Moodalbail 		return (IPADM_NO_BUFS);
12786e91bba0SGirish Moodalbail 	}
12796e91bba0SGirish Moodalbail 	return (IPADM_SUCCESS);
12806e91bba0SGirish Moodalbail }
12816e91bba0SGirish Moodalbail 
12826e91bba0SGirish Moodalbail /*
12836e91bba0SGirish Moodalbail  * Callback function that retrieves the value of the property `prefixlen'
12846e91bba0SGirish Moodalbail  * for the address object in `arg'.
12856e91bba0SGirish Moodalbail  */
12866e91bba0SGirish Moodalbail /* ARGSUSED */
12876e91bba0SGirish 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)12886e91bba0SGirish Moodalbail i_ipadm_get_prefixlen(ipadm_handle_t iph, const void *arg,
12896e91bba0SGirish Moodalbail     ipadm_prop_desc_t *pdp, char *buf, uint_t *bufsize, uint_t af,
12906e91bba0SGirish Moodalbail     uint_t valtype)
12916e91bba0SGirish Moodalbail {
12926e91bba0SGirish Moodalbail 	struct lifreq	lifr;
12936e91bba0SGirish Moodalbail 	ipadm_addrobj_t	ipaddr = (ipadm_addrobj_t)arg;
12946e91bba0SGirish Moodalbail 	char		lifname[LIFNAMSIZ];
12956e91bba0SGirish Moodalbail 	int		s;
12966e91bba0SGirish Moodalbail 	uint32_t	prefixlen;
12976e91bba0SGirish Moodalbail 	size_t		nbytes;
12986e91bba0SGirish Moodalbail 	ipadm_status_t	status;
12996e91bba0SGirish Moodalbail 	uint64_t	lifflags;
13006e91bba0SGirish Moodalbail 
13016e91bba0SGirish Moodalbail 	i_ipadm_addrobj2lifname(ipaddr, lifname, sizeof (lifname));
13026e91bba0SGirish Moodalbail 	if (ipaddr->ipadm_flags & IPMGMT_ACTIVE) {
13036e91bba0SGirish Moodalbail 		status = i_ipadm_get_flags(iph, lifname, af, &lifflags);
13046e91bba0SGirish Moodalbail 		if (status != IPADM_SUCCESS) {
13056e91bba0SGirish Moodalbail 			return (status);
13066e91bba0SGirish Moodalbail 		} else if (lifflags & IFF_POINTOPOINT) {
13076e91bba0SGirish Moodalbail 			buf[0] = '\0';
13086e91bba0SGirish Moodalbail 			return (status);
13096e91bba0SGirish Moodalbail 		}
13106e91bba0SGirish Moodalbail 	}
13116e91bba0SGirish Moodalbail 
13126e91bba0SGirish Moodalbail 	s = (af == AF_INET ? iph->iph_sock : iph->iph_sock6);
13136e91bba0SGirish Moodalbail 	bzero(&lifr, sizeof (lifr));
13146e91bba0SGirish Moodalbail 	(void) strlcpy(lifr.lifr_name, lifname, sizeof (lifr.lifr_name));
13156e91bba0SGirish Moodalbail 	switch (valtype) {
13166e91bba0SGirish Moodalbail 	case MOD_PROP_POSSIBLE:
13176e91bba0SGirish Moodalbail 		if (af == AF_INET)
13186e91bba0SGirish Moodalbail 			nbytes = snprintf(buf, *bufsize, "1-30,32");
13196e91bba0SGirish Moodalbail 		else
13206e91bba0SGirish Moodalbail 			nbytes = snprintf(buf, *bufsize, "1-126,128");
13216e91bba0SGirish Moodalbail 		break;
13226e91bba0SGirish Moodalbail 	case MOD_PROP_DEFAULT:
13236e91bba0SGirish Moodalbail 		if (ipaddr->ipadm_flags & IPMGMT_ACTIVE) {
13246e91bba0SGirish Moodalbail 			/*
13256e91bba0SGirish Moodalbail 			 * For static addresses, we retrieve the address
13266e91bba0SGirish Moodalbail 			 * from kernel if it is active.
13276e91bba0SGirish Moodalbail 			 */
13286e91bba0SGirish Moodalbail 			if (ioctl(s, SIOCGLIFADDR, (caddr_t)&lifr) < 0)
13296e91bba0SGirish Moodalbail 				return (ipadm_errno2status(errno));
13306e91bba0SGirish Moodalbail 			status = i_ipadm_get_default_prefixlen(
13316e91bba0SGirish Moodalbail 			    &lifr.lifr_addr, &prefixlen);
13326e91bba0SGirish Moodalbail 			if (status != IPADM_SUCCESS)
13336e91bba0SGirish Moodalbail 				return (status);
13346e91bba0SGirish Moodalbail 		} else if ((ipaddr->ipadm_flags & IPMGMT_PERSIST) &&
13356e91bba0SGirish Moodalbail 		    ipaddr->ipadm_atype == IPADM_ADDR_DHCP) {
13366e91bba0SGirish Moodalbail 			/*
13376e91bba0SGirish Moodalbail 			 * Since the address is unknown we cannot
13386e91bba0SGirish Moodalbail 			 * obtain default prefixlen
13396e91bba0SGirish Moodalbail 			 */
13406e91bba0SGirish Moodalbail 			buf[0] = '\0';
13416e91bba0SGirish Moodalbail 			return (IPADM_SUCCESS);
13426e91bba0SGirish Moodalbail 		} else {
13436e91bba0SGirish Moodalbail 			/*
13446e91bba0SGirish Moodalbail 			 * If not in active config, we use the address
13456e91bba0SGirish Moodalbail 			 * from persistent store.
13466e91bba0SGirish Moodalbail 			 */
13476e91bba0SGirish Moodalbail 			status = i_ipadm_get_static_addr_db(iph, ipaddr);
13486e91bba0SGirish Moodalbail 			if (status != IPADM_SUCCESS)
13496e91bba0SGirish Moodalbail 				return (status);
13506e91bba0SGirish Moodalbail 			status = i_ipadm_get_default_prefixlen(
13516e91bba0SGirish Moodalbail 			    &ipaddr->ipadm_static_addr, &prefixlen);
13526e91bba0SGirish Moodalbail 			if (status != IPADM_SUCCESS)
13536e91bba0SGirish Moodalbail 				return (status);
13546e91bba0SGirish Moodalbail 		}
13556e91bba0SGirish Moodalbail 		nbytes = snprintf(buf, *bufsize, "%u", prefixlen);
13566e91bba0SGirish Moodalbail 		break;
13576e91bba0SGirish Moodalbail 	case MOD_PROP_ACTIVE:
13586e91bba0SGirish Moodalbail 		if (ioctl(s, SIOCGLIFNETMASK, (caddr_t)&lifr) < 0)
13596e91bba0SGirish Moodalbail 			return (ipadm_errno2status(errno));
13606e91bba0SGirish Moodalbail 		prefixlen = lifr.lifr_addrlen;
13616e91bba0SGirish Moodalbail 		nbytes = snprintf(buf, *bufsize, "%u", prefixlen);
13626e91bba0SGirish Moodalbail 		break;
13636e91bba0SGirish Moodalbail 	default:
13646e91bba0SGirish Moodalbail 		return (IPADM_INVALID_ARG);
13656e91bba0SGirish Moodalbail 	}
13666e91bba0SGirish Moodalbail 	if (nbytes >= *bufsize) {
13676e91bba0SGirish Moodalbail 		/* insufficient buffer space */
13686e91bba0SGirish Moodalbail 		*bufsize = nbytes + 1;
13696e91bba0SGirish Moodalbail 		return (IPADM_NO_BUFS);
13706e91bba0SGirish Moodalbail 	}
13716e91bba0SGirish Moodalbail 	return (IPADM_SUCCESS);
13726e91bba0SGirish Moodalbail }
13736e91bba0SGirish Moodalbail 
13746e91bba0SGirish Moodalbail /*
13756e91bba0SGirish Moodalbail  * Callback function that retrieves the value of one of the properties
13766e91bba0SGirish Moodalbail  * among `deprecated', `private', and `transmit' for the address object
13776e91bba0SGirish Moodalbail  * in `arg'.
13786e91bba0SGirish Moodalbail  */
13796e91bba0SGirish Moodalbail /* ARGSUSED */
13806e91bba0SGirish 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)13816e91bba0SGirish Moodalbail i_ipadm_get_addr_flag(ipadm_handle_t iph, const void *arg,
13826e91bba0SGirish Moodalbail     ipadm_prop_desc_t *pdp, char *buf, uint_t *bufsize, uint_t af,
13836e91bba0SGirish Moodalbail     uint_t valtype)
13846e91bba0SGirish Moodalbail {
13856e91bba0SGirish Moodalbail 	boolean_t	on = B_FALSE;
13866e91bba0SGirish Moodalbail 	char		lifname[LIFNAMSIZ];
13876e91bba0SGirish Moodalbail 	ipadm_status_t	status = IPADM_SUCCESS;
13886e91bba0SGirish Moodalbail 	uint64_t	ifflags;
13896e91bba0SGirish Moodalbail 	size_t		nbytes;
13906e91bba0SGirish Moodalbail 	ipadm_addrobj_t	ipaddr = (ipadm_addrobj_t)arg;
13916e91bba0SGirish Moodalbail 
13926e91bba0SGirish Moodalbail 	switch (valtype) {
13936e91bba0SGirish Moodalbail 	case MOD_PROP_DEFAULT:
13946e91bba0SGirish Moodalbail 		if (strcmp(pdp->ipd_name, "private") == 0 ||
13956e91bba0SGirish Moodalbail 		    strcmp(pdp->ipd_name, "deprecated") == 0) {
13966e91bba0SGirish Moodalbail 			on = B_FALSE;
13976e91bba0SGirish Moodalbail 		} else if (strcmp(pdp->ipd_name, "transmit") == 0) {
13986e91bba0SGirish Moodalbail 			on = B_TRUE;
13996e91bba0SGirish Moodalbail 		} else {
14006e91bba0SGirish Moodalbail 			return (IPADM_PROP_UNKNOWN);
14016e91bba0SGirish Moodalbail 		}
14026e91bba0SGirish Moodalbail 		break;
14036e91bba0SGirish Moodalbail 	case MOD_PROP_ACTIVE:
14046e91bba0SGirish Moodalbail 		/*
14056e91bba0SGirish Moodalbail 		 * If the address is present in active configuration, we
14066e91bba0SGirish Moodalbail 		 * retrieve it from kernel to get the property value.
14076e91bba0SGirish Moodalbail 		 * Else, there is no value to return.
14086e91bba0SGirish Moodalbail 		 */
14096e91bba0SGirish Moodalbail 		i_ipadm_addrobj2lifname(ipaddr, lifname, sizeof (lifname));
14106e91bba0SGirish Moodalbail 		status = i_ipadm_get_flags(iph, lifname, af, &ifflags);
14116e91bba0SGirish Moodalbail 		if (status != IPADM_SUCCESS)
14126e91bba0SGirish Moodalbail 			return (status);
14136e91bba0SGirish Moodalbail 		if (strcmp(pdp->ipd_name, "private") == 0)
14146e91bba0SGirish Moodalbail 			on = (ifflags & IFF_PRIVATE);
14156e91bba0SGirish Moodalbail 		else if (strcmp(pdp->ipd_name, "transmit") == 0)
14166e91bba0SGirish Moodalbail 			on = !(ifflags & IFF_NOXMIT);
14176e91bba0SGirish Moodalbail 		else if (strcmp(pdp->ipd_name, "deprecated") == 0)
14186e91bba0SGirish Moodalbail 			on = (ifflags & IFF_DEPRECATED);
14196e91bba0SGirish Moodalbail 		break;
14206e91bba0SGirish Moodalbail 	default:
14216e91bba0SGirish Moodalbail 		return (IPADM_INVALID_ARG);
14226e91bba0SGirish Moodalbail 	}
14236e91bba0SGirish Moodalbail 	nbytes = snprintf(buf, *bufsize, "%s",
14246e91bba0SGirish Moodalbail 	    (on ? IPADM_ONSTR : IPADM_OFFSTR));
14256e91bba0SGirish Moodalbail 	if (nbytes >= *bufsize) {
14266e91bba0SGirish Moodalbail 		/* insufficient buffer space */
14276e91bba0SGirish Moodalbail 		*bufsize = nbytes + 1;
14286e91bba0SGirish Moodalbail 		status = IPADM_NO_BUFS;
14296e91bba0SGirish Moodalbail 	}
14306e91bba0SGirish Moodalbail 
14316e91bba0SGirish Moodalbail 	return (status);
14326e91bba0SGirish Moodalbail }
14336e91bba0SGirish Moodalbail 
14346e91bba0SGirish Moodalbail /*
14356e91bba0SGirish Moodalbail  * Callback function that retrieves the value of the property `zone'
14366e91bba0SGirish Moodalbail  * for the address object in `arg'.
14376e91bba0SGirish Moodalbail  */
14386e91bba0SGirish Moodalbail /* ARGSUSED */
14396e91bba0SGirish 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)14406e91bba0SGirish Moodalbail i_ipadm_get_zone(ipadm_handle_t iph, const void *arg,
14416e91bba0SGirish Moodalbail     ipadm_prop_desc_t *pdp, char *buf, uint_t *bufsize, uint_t af,
14426e91bba0SGirish Moodalbail     uint_t valtype)
14436e91bba0SGirish Moodalbail {
14446e91bba0SGirish Moodalbail 	struct lifreq	lifr;
14456e91bba0SGirish Moodalbail 	char		zone_name[ZONENAME_MAX];
14466e91bba0SGirish Moodalbail 	int		s;
14476e91bba0SGirish Moodalbail 	size_t		nbytes = 0;
14486e91bba0SGirish Moodalbail 
1449550b6e40SSowmini Varadhan 	if (iph->iph_zoneid != GLOBAL_ZONEID) {
14506e91bba0SGirish Moodalbail 		buf[0] = '\0';
14516e91bba0SGirish Moodalbail 		return (IPADM_SUCCESS);
14526e91bba0SGirish Moodalbail 	}
14536e91bba0SGirish Moodalbail 
14546e91bba0SGirish Moodalbail 	/*
14556e91bba0SGirish Moodalbail 	 * we are in global zone. See if the lifname is assigned to shared-ip
14566e91bba0SGirish Moodalbail 	 * zone or global zone.
14576e91bba0SGirish Moodalbail 	 */
14586e91bba0SGirish Moodalbail 	switch (valtype) {
14596e91bba0SGirish Moodalbail 	case MOD_PROP_DEFAULT:
14606e91bba0SGirish Moodalbail 		if (getzonenamebyid(GLOBAL_ZONEID, zone_name,
14616e91bba0SGirish Moodalbail 		    sizeof (zone_name)) > 0)
14626e91bba0SGirish Moodalbail 			nbytes = snprintf(buf, *bufsize, "%s", zone_name);
14636e91bba0SGirish Moodalbail 		else
14646e91bba0SGirish Moodalbail 			return (ipadm_errno2status(errno));
14656e91bba0SGirish Moodalbail 		break;
14666e91bba0SGirish Moodalbail 	case MOD_PROP_ACTIVE:
14676e91bba0SGirish Moodalbail 		bzero(&lifr, sizeof (lifr));
14686e91bba0SGirish Moodalbail 		i_ipadm_addrobj2lifname((ipadm_addrobj_t)arg, lifr.lifr_name,
14696e91bba0SGirish Moodalbail 		    sizeof (lifr.lifr_name));
14706e91bba0SGirish Moodalbail 		s = (af == AF_INET ? iph->iph_sock : iph->iph_sock6);
14716e91bba0SGirish Moodalbail 
14726e91bba0SGirish Moodalbail 		if (ioctl(s, SIOCGLIFZONE, (caddr_t)&lifr) == -1)
14736e91bba0SGirish Moodalbail 			return (ipadm_errno2status(errno));
14746e91bba0SGirish Moodalbail 
14756e91bba0SGirish Moodalbail 		if (lifr.lifr_zoneid == ALL_ZONES) {
14766e91bba0SGirish Moodalbail 			nbytes = snprintf(buf, *bufsize, "%s", "all-zones");
14776e91bba0SGirish Moodalbail 		} else if (getzonenamebyid(lifr.lifr_zoneid, zone_name,
14786e91bba0SGirish Moodalbail 		    sizeof (zone_name)) < 0) {
14796e91bba0SGirish Moodalbail 			return (ipadm_errno2status(errno));
14806e91bba0SGirish Moodalbail 		} else {
14816e91bba0SGirish Moodalbail 			nbytes = snprintf(buf, *bufsize, "%s", zone_name);
14826e91bba0SGirish Moodalbail 		}
14836e91bba0SGirish Moodalbail 		break;
14846e91bba0SGirish Moodalbail 	default:
14856e91bba0SGirish Moodalbail 		return (IPADM_INVALID_ARG);
14866e91bba0SGirish Moodalbail 	}
14876e91bba0SGirish Moodalbail 	if (nbytes >= *bufsize) {
14886e91bba0SGirish Moodalbail 		/* insufficient buffer space */
14896e91bba0SGirish Moodalbail 		*bufsize = nbytes + 1;
14906e91bba0SGirish Moodalbail 		return (IPADM_NO_BUFS);
14916e91bba0SGirish Moodalbail 	}
14926e91bba0SGirish Moodalbail 
14936e91bba0SGirish Moodalbail 	return (IPADM_SUCCESS);
14946e91bba0SGirish Moodalbail }
14956e91bba0SGirish Moodalbail 
1496b31320a7SChris Fraire /*
1497b31320a7SChris Fraire  * Callback function that retrieves the value of the property `primary'
1498b31320a7SChris Fraire  * for the address object in `arg'.
1499b31320a7SChris Fraire  */
1500b31320a7SChris Fraire /* ARGSUSED */
1501b31320a7SChris Fraire static ipadm_status_t
i_ipadm_get_primary(ipadm_handle_t iph,const void * arg,ipadm_prop_desc_t * pdp,char * buf,uint_t * bufsize,uint_t af,uint_t valtype)1502b31320a7SChris Fraire i_ipadm_get_primary(ipadm_handle_t iph, const void *arg,
1503b31320a7SChris Fraire     ipadm_prop_desc_t *pdp, char *buf, uint_t *bufsize, uint_t af,
1504b31320a7SChris Fraire     uint_t valtype)
1505b31320a7SChris Fraire {
1506b31320a7SChris Fraire 	ipadm_addrobj_t	ipaddr = (ipadm_addrobj_t)arg;
1507b31320a7SChris Fraire 	const char		*onoff = "";
1508b31320a7SChris Fraire 	size_t			nbytes;
1509b31320a7SChris Fraire 
1510b31320a7SChris Fraire 	switch (valtype) {
1511b31320a7SChris Fraire 	case MOD_PROP_DEFAULT:
1512b31320a7SChris Fraire 		if (ipaddr->ipadm_atype == IPADM_ADDR_DHCP)
1513b31320a7SChris Fraire 			onoff = IPADM_OFFSTR;
1514b31320a7SChris Fraire 		break;
1515b31320a7SChris Fraire 	case MOD_PROP_ACTIVE:
1516b31320a7SChris Fraire 		if (ipaddr->ipadm_atype == IPADM_ADDR_DHCP) {
1517b31320a7SChris Fraire 			dhcp_status_t	dhcp_status;
1518b31320a7SChris Fraire 			ipadm_status_t	ipc_status;
1519b31320a7SChris Fraire 			int			error;
1520b31320a7SChris Fraire 
1521b31320a7SChris Fraire 			ipc_status = i_ipadm_dhcp_status(ipaddr, &dhcp_status,
1522b31320a7SChris Fraire 			    &error);
1523b31320a7SChris Fraire 			if (ipc_status != IPADM_SUCCESS &&
1524b31320a7SChris Fraire 			    ipc_status != IPADM_NOTFOUND)
1525b31320a7SChris Fraire 				return (ipc_status);
1526b31320a7SChris Fraire 
1527b31320a7SChris Fraire 			onoff = dhcp_status.if_dflags & DHCP_IF_PRIMARY ?
1528b31320a7SChris Fraire 			    IPADM_ONSTR : IPADM_OFFSTR;
1529b31320a7SChris Fraire 		}
1530b31320a7SChris Fraire 		break;
1531b31320a7SChris Fraire 	default:
1532b31320a7SChris Fraire 		return (IPADM_INVALID_ARG);
1533b31320a7SChris Fraire 	}
1534b31320a7SChris Fraire 
1535b31320a7SChris Fraire 	nbytes = strlcpy(buf, onoff, *bufsize);
1536b31320a7SChris Fraire 	if (nbytes >= *bufsize) {
1537b31320a7SChris Fraire 		/* insufficient buffer space */
1538b31320a7SChris Fraire 		*bufsize = nbytes + 1;
1539b31320a7SChris Fraire 		return (IPADM_NO_BUFS);
1540b31320a7SChris Fraire 	}
1541b31320a7SChris Fraire 
1542b31320a7SChris Fraire 	return (IPADM_SUCCESS);
1543b31320a7SChris Fraire }
1544b31320a7SChris Fraire 
1545b31320a7SChris Fraire /*
1546b31320a7SChris Fraire  * Callback function that retrieves the value of the property `reqhost'
1547b31320a7SChris Fraire  * for the address object in `arg'.
1548b31320a7SChris Fraire  */
1549b31320a7SChris Fraire /* ARGSUSED */
1550b31320a7SChris Fraire static ipadm_status_t
i_ipadm_get_reqhost(ipadm_handle_t iph,const void * arg,ipadm_prop_desc_t * pdp,char * buf,uint_t * bufsize,uint_t af,uint_t valtype)1551b31320a7SChris Fraire i_ipadm_get_reqhost(ipadm_handle_t iph, const void *arg,
1552b31320a7SChris Fraire     ipadm_prop_desc_t *pdp, char *buf, uint_t *bufsize, uint_t af,
1553b31320a7SChris Fraire     uint_t valtype)
1554b31320a7SChris Fraire {
1555b31320a7SChris Fraire 	ipadm_addrobj_t	ipaddr = (ipadm_addrobj_t)arg;
1556b31320a7SChris Fraire 	const char	*reqhost = "";
1557b31320a7SChris Fraire 	size_t		nbytes;
1558b31320a7SChris Fraire 
1559b31320a7SChris Fraire 	switch (valtype) {
1560b31320a7SChris Fraire 	case MOD_PROP_DEFAULT:
1561b31320a7SChris Fraire 		break;
1562b31320a7SChris Fraire 	case MOD_PROP_ACTIVE:
1563b31320a7SChris Fraire 		if (ipaddr->ipadm_atype == IPADM_ADDR_DHCP)
1564b31320a7SChris Fraire 			reqhost = ipaddr->ipadm_reqhost;
1565b31320a7SChris Fraire 		break;
1566b31320a7SChris Fraire 	default:
1567b31320a7SChris Fraire 		return (IPADM_INVALID_ARG);
1568b31320a7SChris Fraire 	}
1569b31320a7SChris Fraire 
1570b31320a7SChris Fraire 	nbytes = strlcpy(buf, reqhost, *bufsize);
1571b31320a7SChris Fraire 	if (nbytes >= *bufsize) {
1572b31320a7SChris Fraire 		/* insufficient buffer space */
1573b31320a7SChris Fraire 		*bufsize = nbytes + 1;
1574b31320a7SChris Fraire 		return (IPADM_NO_BUFS);
1575b31320a7SChris Fraire 	}
1576b31320a7SChris Fraire 
1577b31320a7SChris Fraire 	return (IPADM_SUCCESS);
1578b31320a7SChris Fraire }
1579b31320a7SChris Fraire 
15806e91bba0SGirish Moodalbail static ipadm_prop_desc_t *
i_ipadm_get_addrprop_desc(const char * pname)15818887b57dSGirish Moodalbail i_ipadm_get_addrprop_desc(const char *pname)
15826e91bba0SGirish Moodalbail {
15836e91bba0SGirish Moodalbail 	int i;
15846e91bba0SGirish Moodalbail 
15856e91bba0SGirish Moodalbail 	for (i = 0; ipadm_addrprop_table[i].ipd_name != NULL; i++) {
1586299625c6SSebastien Roy 		if (strcmp(pname, ipadm_addrprop_table[i].ipd_name) == 0 ||
1587299625c6SSebastien Roy 		    (ipadm_addrprop_table[i].ipd_old_name != NULL &&
1588299625c6SSebastien Roy 		    strcmp(pname, ipadm_addrprop_table[i].ipd_old_name) == 0))
15896e91bba0SGirish Moodalbail 			return (&ipadm_addrprop_table[i]);
15906e91bba0SGirish Moodalbail 	}
15916e91bba0SGirish Moodalbail 	return (NULL);
15926e91bba0SGirish Moodalbail }
15936e91bba0SGirish Moodalbail 
15946e91bba0SGirish Moodalbail /*
15956e91bba0SGirish Moodalbail  * Gets the value of the given address property `pname' for the address
15966e91bba0SGirish Moodalbail  * object with name `aobjname'.
15976e91bba0SGirish Moodalbail  */
15986e91bba0SGirish 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)15996e91bba0SGirish Moodalbail ipadm_get_addrprop(ipadm_handle_t iph, const char *pname, char *buf,
16006e91bba0SGirish Moodalbail     uint_t *bufsize, const char *aobjname, uint_t valtype)
16016e91bba0SGirish Moodalbail {
16026e91bba0SGirish Moodalbail 	struct ipadm_addrobj_s	ipaddr;
16036e91bba0SGirish Moodalbail 	ipadm_status_t		status = IPADM_SUCCESS;
16046e91bba0SGirish Moodalbail 	sa_family_t		af;
16056e91bba0SGirish Moodalbail 	ipadm_prop_desc_t	*pdp = NULL;
16066e91bba0SGirish Moodalbail 
16076e91bba0SGirish Moodalbail 	if (iph == NULL || pname == NULL || buf == NULL ||
16086e91bba0SGirish Moodalbail 	    bufsize == NULL || *bufsize == 0 || aobjname == NULL) {
16096e91bba0SGirish Moodalbail 		return (IPADM_INVALID_ARG);
16106e91bba0SGirish Moodalbail 	}
16116e91bba0SGirish Moodalbail 
16126e91bba0SGirish Moodalbail 	/* find the property in the property description table */
16138887b57dSGirish Moodalbail 	if ((pdp = i_ipadm_get_addrprop_desc(pname)) == NULL)
16146e91bba0SGirish Moodalbail 		return (IPADM_PROP_UNKNOWN);
16156e91bba0SGirish Moodalbail 
16166e91bba0SGirish Moodalbail 	/*
16176e91bba0SGirish Moodalbail 	 * For the given aobjname, get the addrobj it represents and
16186e91bba0SGirish Moodalbail 	 * retrieve the property value for that object.
16196e91bba0SGirish Moodalbail 	 */
16206e91bba0SGirish Moodalbail 	i_ipadm_init_addr(&ipaddr, "", aobjname, IPADM_ADDR_NONE);
16216e91bba0SGirish Moodalbail 	if ((status = i_ipadm_get_addrobj(iph, &ipaddr)) != IPADM_SUCCESS)
16226e91bba0SGirish Moodalbail 		return (status);
16236e91bba0SGirish Moodalbail 
16246e91bba0SGirish Moodalbail 	if (ipaddr.ipadm_atype == IPADM_ADDR_IPV6_ADDRCONF)
16256e91bba0SGirish Moodalbail 		return (IPADM_NOTSUP);
16266e91bba0SGirish Moodalbail 	af = ipaddr.ipadm_af;
16276e91bba0SGirish Moodalbail 
16286e91bba0SGirish Moodalbail 	/*
16296e91bba0SGirish Moodalbail 	 * Call the appropriate callback function to based on the field
16306e91bba0SGirish Moodalbail 	 * that was asked for.
16316e91bba0SGirish Moodalbail 	 */
16326e91bba0SGirish Moodalbail 	switch (valtype) {
16336e91bba0SGirish Moodalbail 	case IPADM_OPT_PERM:
16346e91bba0SGirish Moodalbail 		status = i_ipadm_pd2permstr(pdp, buf, bufsize);
16356e91bba0SGirish Moodalbail 		break;
16366e91bba0SGirish Moodalbail 	case IPADM_OPT_ACTIVE:
16376e91bba0SGirish Moodalbail 		if (!(ipaddr.ipadm_flags & IPMGMT_ACTIVE)) {
16386e91bba0SGirish Moodalbail 			buf[0] = '\0';
16396e91bba0SGirish Moodalbail 		} else {
16406e91bba0SGirish Moodalbail 			status = pdp->ipd_get(iph, &ipaddr, pdp, buf, bufsize,
16416e91bba0SGirish Moodalbail 			    af, MOD_PROP_ACTIVE);
16426e91bba0SGirish Moodalbail 		}
16436e91bba0SGirish Moodalbail 		break;
16446e91bba0SGirish Moodalbail 	case IPADM_OPT_DEFAULT:
16456e91bba0SGirish Moodalbail 		status = pdp->ipd_get(iph, &ipaddr, pdp, buf, bufsize,
16466e91bba0SGirish Moodalbail 		    af, MOD_PROP_DEFAULT);
16476e91bba0SGirish Moodalbail 		break;
16486e91bba0SGirish Moodalbail 	case IPADM_OPT_POSSIBLE:
16496e91bba0SGirish Moodalbail 		if (pdp->ipd_get_range != NULL) {
16506e91bba0SGirish Moodalbail 			status = pdp->ipd_get_range(iph, &ipaddr, pdp, buf,
16516e91bba0SGirish Moodalbail 			    bufsize, af, MOD_PROP_POSSIBLE);
16526e91bba0SGirish Moodalbail 			break;
16536e91bba0SGirish Moodalbail 		}
16546e91bba0SGirish Moodalbail 		buf[0] = '\0';
16556e91bba0SGirish Moodalbail 		break;
16566e91bba0SGirish Moodalbail 	case IPADM_OPT_PERSIST:
16576e91bba0SGirish Moodalbail 		status = i_ipadm_get_persist_propval(iph, pdp, buf, bufsize,
16586e91bba0SGirish Moodalbail 		    &ipaddr);
16596e91bba0SGirish Moodalbail 		break;
16606e91bba0SGirish Moodalbail 	default:
16616e91bba0SGirish Moodalbail 		status = IPADM_INVALID_ARG;
16626e91bba0SGirish Moodalbail 		break;
16636e91bba0SGirish Moodalbail 	}
16646e91bba0SGirish Moodalbail 
16656e91bba0SGirish Moodalbail 	return (status);
16666e91bba0SGirish Moodalbail }
16676e91bba0SGirish Moodalbail 
16686e91bba0SGirish Moodalbail /*
16696e91bba0SGirish Moodalbail  * Sets the value of the given address property `pname' to `pval' for the
16706e91bba0SGirish Moodalbail  * address object with name `aobjname'.
16716e91bba0SGirish Moodalbail  */
16726e91bba0SGirish Moodalbail ipadm_status_t
ipadm_set_addrprop(ipadm_handle_t iph,const char * pname,const char * pval,const char * aobjname,uint_t pflags)16736e91bba0SGirish Moodalbail ipadm_set_addrprop(ipadm_handle_t iph, const char *pname,
16746e91bba0SGirish Moodalbail     const char *pval, const char *aobjname, uint_t pflags)
16756e91bba0SGirish Moodalbail {
16766e91bba0SGirish Moodalbail 	struct ipadm_addrobj_s	ipaddr;
16776e91bba0SGirish Moodalbail 	sa_family_t		af;
16786e91bba0SGirish Moodalbail 	ipadm_prop_desc_t	*pdp = NULL;
16796e91bba0SGirish Moodalbail 	char			defbuf[MAXPROPVALLEN];
16806e91bba0SGirish Moodalbail 	uint_t			defbufsize = MAXPROPVALLEN;
16810d1087e8SHans Rosenfeld 	boolean_t		reset = (pflags & IPADM_OPT_DEFAULT);
16826e91bba0SGirish Moodalbail 	ipadm_status_t		status = IPADM_SUCCESS;
16836e91bba0SGirish Moodalbail 
16846e91bba0SGirish Moodalbail 	/* Check for solaris.network.interface.config authorization */
16856e91bba0SGirish Moodalbail 	if (!ipadm_check_auth())
16866e91bba0SGirish Moodalbail 		return (IPADM_EAUTH);
16876e91bba0SGirish Moodalbail 
16886e91bba0SGirish Moodalbail 	if (iph == NULL || pname == NULL || aobjname == NULL || pflags == 0 ||
16896e91bba0SGirish Moodalbail 	    pflags == IPADM_OPT_PERSIST ||
16906e91bba0SGirish Moodalbail 	    (pflags & ~(IPADM_COMMON_OPT_MASK|IPADM_OPT_DEFAULT)) ||
16916e91bba0SGirish Moodalbail 	    (!reset && pval == NULL)) {
16926e91bba0SGirish Moodalbail 		return (IPADM_INVALID_ARG);
16936e91bba0SGirish Moodalbail 	}
16946e91bba0SGirish Moodalbail 
16956e91bba0SGirish Moodalbail 	/* find the property in the property description table */
16968887b57dSGirish Moodalbail 	if ((pdp = i_ipadm_get_addrprop_desc(pname)) == NULL)
16976e91bba0SGirish Moodalbail 		return (IPADM_PROP_UNKNOWN);
16986e91bba0SGirish Moodalbail 
16996e91bba0SGirish Moodalbail 	if (pdp->ipd_set == NULL || (reset && pdp->ipd_get == NULL))
17006e91bba0SGirish Moodalbail 		return (IPADM_NOTSUP);
17016e91bba0SGirish Moodalbail 
17028b88711aSGirish Moodalbail 	if (!(pdp->ipd_flags & IPADMPROP_MULVAL) &&
17038b88711aSGirish Moodalbail 	    (pflags & (IPADM_OPT_APPEND|IPADM_OPT_REMOVE))) {
17048b88711aSGirish Moodalbail 		return (IPADM_INVALID_ARG);
17058b88711aSGirish Moodalbail 	}
17068b88711aSGirish Moodalbail 
17076e91bba0SGirish Moodalbail 	/*
17086e91bba0SGirish Moodalbail 	 * For the given aobjname, get the addrobj it represents and
17096e91bba0SGirish Moodalbail 	 * set the property value for that object.
17106e91bba0SGirish Moodalbail 	 */
17116e91bba0SGirish Moodalbail 	i_ipadm_init_addr(&ipaddr, "", aobjname, IPADM_ADDR_NONE);
17126e91bba0SGirish Moodalbail 	if ((status = i_ipadm_get_addrobj(iph, &ipaddr)) != IPADM_SUCCESS)
17136e91bba0SGirish Moodalbail 		return (status);
17146e91bba0SGirish Moodalbail 
17156e91bba0SGirish Moodalbail 	if (!(ipaddr.ipadm_flags & IPMGMT_ACTIVE))
17166e91bba0SGirish Moodalbail 		return (IPADM_OP_DISABLE_OBJ);
17176e91bba0SGirish Moodalbail 
17186e91bba0SGirish Moodalbail 	/* Persistent operation not allowed on a temporary object. */
17196e91bba0SGirish Moodalbail 	if ((pflags & IPADM_OPT_PERSIST) &&
17206e91bba0SGirish Moodalbail 	    !(ipaddr.ipadm_flags & IPMGMT_PERSIST))
17216e91bba0SGirish Moodalbail 		return (IPADM_TEMPORARY_OBJ);
17226e91bba0SGirish Moodalbail 	/*
17236e91bba0SGirish Moodalbail 	 * Currently, setting an address property on an address object of type
17246e91bba0SGirish Moodalbail 	 * IPADM_ADDR_IPV6_ADDRCONF is not supported. Supporting it involves
17256e91bba0SGirish Moodalbail 	 * in.ndpd retrieving the address properties from ipmgmtd for given
17266e91bba0SGirish Moodalbail 	 * address object and then setting them on auto-configured addresses,
17276e91bba0SGirish Moodalbail 	 * whenever in.ndpd gets a new prefix. This will be supported in
17286e91bba0SGirish Moodalbail 	 * future releases.
17296e91bba0SGirish Moodalbail 	 */
17306e91bba0SGirish Moodalbail 	if (ipaddr.ipadm_atype == IPADM_ADDR_IPV6_ADDRCONF)
17316e91bba0SGirish Moodalbail 		return (IPADM_NOTSUP);
17326e91bba0SGirish Moodalbail 
17336e91bba0SGirish Moodalbail 	/*
17346e91bba0SGirish Moodalbail 	 * Setting an address property on an address object that is
17356e91bba0SGirish Moodalbail 	 * not present in active configuration is not supported.
17366e91bba0SGirish Moodalbail 	 */
17376e91bba0SGirish Moodalbail 	if (!(ipaddr.ipadm_flags & IPMGMT_ACTIVE))
17386e91bba0SGirish Moodalbail 		return (IPADM_NOTSUP);
17396e91bba0SGirish Moodalbail 
17406e91bba0SGirish Moodalbail 	af = ipaddr.ipadm_af;
17416e91bba0SGirish Moodalbail 	if (reset) {
17426e91bba0SGirish Moodalbail 		/*
17436e91bba0SGirish Moodalbail 		 * If we were asked to reset the value, we need to fetch
17446e91bba0SGirish Moodalbail 		 * the default value and set the default value.
17456e91bba0SGirish Moodalbail 		 */
17466e91bba0SGirish Moodalbail 		status = pdp->ipd_get(iph, &ipaddr, pdp, defbuf, &defbufsize,
17476e91bba0SGirish Moodalbail 		    af, MOD_PROP_DEFAULT);
17486e91bba0SGirish Moodalbail 		if (status != IPADM_SUCCESS)
17496e91bba0SGirish Moodalbail 			return (status);
17506e91bba0SGirish Moodalbail 		pval = defbuf;
17516e91bba0SGirish Moodalbail 	}
17526e91bba0SGirish Moodalbail 	/* set the user provided or default property value */
17536e91bba0SGirish Moodalbail 	status = pdp->ipd_set(iph, &ipaddr, pdp, pval, af, pflags);
17546e91bba0SGirish Moodalbail 	if (status != IPADM_SUCCESS)
17556e91bba0SGirish Moodalbail 		return (status);
17566e91bba0SGirish Moodalbail 
17576e91bba0SGirish Moodalbail 	/*
17586e91bba0SGirish Moodalbail 	 * If IPADM_OPT_PERSIST was set in `flags', we need to store
17596e91bba0SGirish Moodalbail 	 * property and its value in persistent DB.
17606e91bba0SGirish Moodalbail 	 */
17616e91bba0SGirish Moodalbail 	if (pflags & IPADM_OPT_PERSIST) {
17626e91bba0SGirish Moodalbail 		status = i_ipadm_persist_propval(iph, pdp, pval, &ipaddr,
17636e91bba0SGirish Moodalbail 		    pflags);
17646e91bba0SGirish Moodalbail 	}
17656e91bba0SGirish Moodalbail 
17666e91bba0SGirish Moodalbail 	return (status);
17676e91bba0SGirish Moodalbail }
17686e91bba0SGirish Moodalbail 
17696e91bba0SGirish Moodalbail /*
17706e91bba0SGirish Moodalbail  * Remove the address specified by the address object in `addr'
17716e91bba0SGirish Moodalbail  * from kernel. If the address is on a non-zero logical interface, we do a
17726e91bba0SGirish Moodalbail  * SIOCLIFREMOVEIF, otherwise we set the address to INADDR_ANY for IPv4 or
17736e91bba0SGirish Moodalbail  * :: for IPv6.
17746e91bba0SGirish Moodalbail  */
17756e91bba0SGirish Moodalbail ipadm_status_t
i_ipadm_delete_addr(ipadm_handle_t iph,ipadm_addrobj_t addr)17766e91bba0SGirish Moodalbail i_ipadm_delete_addr(ipadm_handle_t iph, ipadm_addrobj_t addr)
17776e91bba0SGirish Moodalbail {
17786e91bba0SGirish Moodalbail 	struct lifreq	lifr;
17796e91bba0SGirish Moodalbail 	int		sock;
17806e91bba0SGirish Moodalbail 	ipadm_status_t	status;
17816e91bba0SGirish Moodalbail 
17826e91bba0SGirish Moodalbail 	bzero(&lifr, sizeof (lifr));
17836e91bba0SGirish Moodalbail 	i_ipadm_addrobj2lifname(addr, lifr.lifr_name, sizeof (lifr.lifr_name));
17846e91bba0SGirish Moodalbail 	sock = (addr->ipadm_af == AF_INET ? iph->iph_sock : iph->iph_sock6);
17856e91bba0SGirish Moodalbail 	if (addr->ipadm_lifnum == 0) {
17866e91bba0SGirish Moodalbail 		/*
17876e91bba0SGirish Moodalbail 		 * Fake the deletion of the 0'th address by
17886e91bba0SGirish Moodalbail 		 * clearing IFF_UP and setting it to as 0.0.0.0 or ::.
17896e91bba0SGirish Moodalbail 		 */
17906e91bba0SGirish Moodalbail 		status = i_ipadm_set_flags(iph, addr->ipadm_ifname,
17916e91bba0SGirish Moodalbail 		    addr->ipadm_af, 0, IFF_UP);
17926e91bba0SGirish Moodalbail 		if (status != IPADM_SUCCESS)
17936e91bba0SGirish Moodalbail 			return (status);
17946e91bba0SGirish Moodalbail 		bzero(&lifr.lifr_addr, sizeof (lifr.lifr_addr));
17956e91bba0SGirish Moodalbail 		lifr.lifr_addr.ss_family = addr->ipadm_af;
17966e91bba0SGirish Moodalbail 		if (ioctl(sock, SIOCSLIFADDR, (caddr_t)&lifr) < 0)
17976e91bba0SGirish Moodalbail 			return (ipadm_errno2status(errno));
17986e91bba0SGirish Moodalbail 		if (ioctl(sock, SIOCSLIFDSTADDR, (caddr_t)&lifr) < 0)
17996e91bba0SGirish Moodalbail 			return (ipadm_errno2status(errno));
18006e91bba0SGirish Moodalbail 	} else if (ioctl(sock, SIOCLIFREMOVEIF, (caddr_t)&lifr) < 0) {
18016e91bba0SGirish Moodalbail 		return (ipadm_errno2status(errno));
18026e91bba0SGirish Moodalbail 	}
18036e91bba0SGirish Moodalbail 
18046e91bba0SGirish Moodalbail 	return (IPADM_SUCCESS);
18056e91bba0SGirish Moodalbail }
18066e91bba0SGirish Moodalbail 
18076e91bba0SGirish Moodalbail /*
18086e91bba0SGirish Moodalbail  * Extracts the IPv6 address from the nvlist in `nvl'.
18096e91bba0SGirish Moodalbail  */
18106e91bba0SGirish Moodalbail ipadm_status_t
i_ipadm_nvl2in6_addr(nvlist_t * nvl,char * addr_type,in6_addr_t * in6_addr)18116e91bba0SGirish Moodalbail i_ipadm_nvl2in6_addr(nvlist_t *nvl, char *addr_type, in6_addr_t *in6_addr)
18126e91bba0SGirish Moodalbail {
18136e91bba0SGirish Moodalbail 	uint8_t	*addr6;
18146e91bba0SGirish Moodalbail 	uint_t	n;
18156e91bba0SGirish Moodalbail 
18166e91bba0SGirish Moodalbail 	if (nvlist_lookup_uint8_array(nvl, addr_type, &addr6, &n) != 0)
18176e91bba0SGirish Moodalbail 		return (IPADM_NOTFOUND);
18186e91bba0SGirish Moodalbail 	assert(n == 16);
18196e91bba0SGirish Moodalbail 	bcopy(addr6, in6_addr->s6_addr, n);
18206e91bba0SGirish Moodalbail 	return (IPADM_SUCCESS);
18216e91bba0SGirish Moodalbail }
18226e91bba0SGirish Moodalbail 
18236e91bba0SGirish Moodalbail /*
18246e91bba0SGirish Moodalbail  * Used to validate the given addrobj name string. Length of `aobjname'
18256e91bba0SGirish Moodalbail  * cannot exceed IPADM_AOBJ_USTRSIZ. `aobjname' should start with an
18266e91bba0SGirish Moodalbail  * alphabetic character and it can only contain alphanumeric characters.
18276e91bba0SGirish Moodalbail  */
18286e91bba0SGirish Moodalbail static boolean_t
i_ipadm_is_user_aobjname_valid(const char * aobjname)18296e91bba0SGirish Moodalbail i_ipadm_is_user_aobjname_valid(const char *aobjname)
18306e91bba0SGirish Moodalbail {
18316e91bba0SGirish Moodalbail 	const char	*cp;
18326e91bba0SGirish Moodalbail 
18336e91bba0SGirish Moodalbail 	if (aobjname == NULL || strlen(aobjname) >= IPADM_AOBJ_USTRSIZ ||
18346e91bba0SGirish Moodalbail 	    !isalpha(*aobjname)) {
18356e91bba0SGirish Moodalbail 		return (B_FALSE);
18366e91bba0SGirish Moodalbail 	}
18376e91bba0SGirish Moodalbail 	for (cp = aobjname + 1; *cp && isalnum(*cp); cp++)
18386e91bba0SGirish Moodalbail 		;
18396e91bba0SGirish Moodalbail 	return (*cp == '\0');
18406e91bba0SGirish Moodalbail }
18416e91bba0SGirish Moodalbail 
18426e91bba0SGirish Moodalbail /*
18436e91bba0SGirish Moodalbail  * Computes the prefixlen for the given `addr' based on the netmask found using
18446e91bba0SGirish Moodalbail  * the order specified in /etc/nsswitch.conf. If not found, then the
18456e91bba0SGirish Moodalbail  * prefixlen is computed using the Classful subnetting semantics defined
18466e91bba0SGirish Moodalbail  * in RFC 791 for IPv4 and RFC 4291 for IPv6.
18476e91bba0SGirish Moodalbail  */
18486e91bba0SGirish Moodalbail static ipadm_status_t
i_ipadm_get_default_prefixlen(struct sockaddr_storage * addr,uint32_t * plen)18496e91bba0SGirish Moodalbail i_ipadm_get_default_prefixlen(struct sockaddr_storage *addr, uint32_t *plen)
18506e91bba0SGirish Moodalbail {
18516e91bba0SGirish Moodalbail 	sa_family_t af = addr->ss_family;
18526e91bba0SGirish Moodalbail 	struct sockaddr_storage mask;
18536e91bba0SGirish Moodalbail 	struct sockaddr_in *m = (struct sockaddr_in *)&mask;
18546e91bba0SGirish Moodalbail 	struct sockaddr_in6 *sin6;
18556e91bba0SGirish Moodalbail 	struct sockaddr_in *sin;
18566e91bba0SGirish Moodalbail 	struct in_addr ia;
18576e91bba0SGirish Moodalbail 	uint32_t prefixlen = 0;
18586e91bba0SGirish Moodalbail 
18596e91bba0SGirish Moodalbail 	switch (af) {
18606e91bba0SGirish Moodalbail 	case AF_INET:
18616e91bba0SGirish Moodalbail 		sin = SIN(addr);
18626e91bba0SGirish Moodalbail 		ia.s_addr = ntohl(sin->sin_addr.s_addr);
18636e91bba0SGirish Moodalbail 		get_netmask4(&ia, &m->sin_addr);
18646e91bba0SGirish Moodalbail 		m->sin_addr.s_addr = htonl(m->sin_addr.s_addr);
18656e91bba0SGirish Moodalbail 		m->sin_family = AF_INET;
186664639aafSDarren Reed 		prefixlen = mask2plen((struct sockaddr *)&mask);
18676e91bba0SGirish Moodalbail 		break;
18686e91bba0SGirish Moodalbail 	case AF_INET6:
18696e91bba0SGirish Moodalbail 		sin6 = SIN6(addr);
18706e91bba0SGirish Moodalbail 		if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))
18716e91bba0SGirish Moodalbail 			prefixlen = 10;
18726e91bba0SGirish Moodalbail 		else
18736e91bba0SGirish Moodalbail 			prefixlen = 64;
18746e91bba0SGirish Moodalbail 		break;
18756e91bba0SGirish Moodalbail 	default:
18766e91bba0SGirish Moodalbail 		return (IPADM_INVALID_ARG);
18776e91bba0SGirish Moodalbail 	}
18786e91bba0SGirish Moodalbail 	*plen = prefixlen;
18796e91bba0SGirish Moodalbail 	return (IPADM_SUCCESS);
18806e91bba0SGirish Moodalbail }
18816e91bba0SGirish Moodalbail 
1882550b6e40SSowmini Varadhan ipadm_status_t
i_ipadm_resolve_addr(const char * name,sa_family_t af,struct sockaddr_storage * ss)18836e91bba0SGirish Moodalbail i_ipadm_resolve_addr(const char *name, sa_family_t af,
18846e91bba0SGirish Moodalbail     struct sockaddr_storage *ss)
18856e91bba0SGirish Moodalbail {
18866e91bba0SGirish Moodalbail 	struct addrinfo hints, *ai;
18876e91bba0SGirish Moodalbail 	int rc;
18886e91bba0SGirish Moodalbail 	struct sockaddr_in6 *sin6;
18896e91bba0SGirish Moodalbail 	struct sockaddr_in *sin;
18906e91bba0SGirish Moodalbail 	boolean_t is_mapped;
18916e91bba0SGirish Moodalbail 
18926e91bba0SGirish Moodalbail 	(void) memset(&hints, 0, sizeof (hints));
18936e91bba0SGirish Moodalbail 	hints.ai_family = af;
18946e91bba0SGirish Moodalbail 	hints.ai_flags = (AI_ALL | AI_V4MAPPED);
18956e91bba0SGirish Moodalbail 	rc = getaddrinfo(name, NULL, &hints, &ai);
18966e91bba0SGirish Moodalbail 	if (rc != 0) {
18976e91bba0SGirish Moodalbail 		if (rc == EAI_NONAME)
18986e91bba0SGirish Moodalbail 			return (IPADM_BAD_ADDR);
18996e91bba0SGirish Moodalbail 		else
19006e91bba0SGirish Moodalbail 			return (IPADM_FAILURE);
19016e91bba0SGirish Moodalbail 	}
19026e91bba0SGirish Moodalbail 	if (ai->ai_next != NULL) {
19036e91bba0SGirish Moodalbail 		/* maps to more than one hostname */
19046e91bba0SGirish Moodalbail 		freeaddrinfo(ai);
19056e91bba0SGirish Moodalbail 		return (IPADM_BAD_HOSTNAME);
19066e91bba0SGirish Moodalbail 	}
19076e91bba0SGirish Moodalbail 	/* LINTED E_BAD_PTR_CAST_ALIGN */
19086e91bba0SGirish Moodalbail 	is_mapped = IN6_IS_ADDR_V4MAPPED(&(SIN6(ai->ai_addr))->sin6_addr);
19096e91bba0SGirish Moodalbail 	if (is_mapped) {
19106e91bba0SGirish Moodalbail 		sin = SIN(ss);
19116e91bba0SGirish Moodalbail 		sin->sin_family = AF_INET;
19126e91bba0SGirish Moodalbail 		/* LINTED E_BAD_PTR_CAST_ALIGN */
19136e91bba0SGirish Moodalbail 		IN6_V4MAPPED_TO_INADDR(&(SIN6(ai->ai_addr))->sin6_addr,
19146e91bba0SGirish Moodalbail 		    &sin->sin_addr);
19156e91bba0SGirish Moodalbail 	} else {
19166e91bba0SGirish Moodalbail 		sin6 = SIN6(ss);
19176e91bba0SGirish Moodalbail 		sin6->sin6_family = AF_INET6;
19186e91bba0SGirish Moodalbail 		bcopy(ai->ai_addr, sin6, sizeof (*sin6));
19196e91bba0SGirish Moodalbail 	}
19206e91bba0SGirish Moodalbail 	freeaddrinfo(ai);
19216e91bba0SGirish Moodalbail 	return (IPADM_SUCCESS);
19226e91bba0SGirish Moodalbail }
19236e91bba0SGirish Moodalbail 
19246e91bba0SGirish Moodalbail /*
19256e91bba0SGirish Moodalbail  * This takes a static address string <addr>[/<mask>] or a hostname
19266e91bba0SGirish Moodalbail  * and maps it to a single numeric IP address, consulting DNS if
19276e91bba0SGirish Moodalbail  * hostname was provided. If a specific address family was requested,
19286e91bba0SGirish Moodalbail  * an error is returned if the given hostname does not map to an address
19296e91bba0SGirish Moodalbail  * of the given family. Note that this function returns failure
19306e91bba0SGirish Moodalbail  * if the name maps to more than one IP address.
19316e91bba0SGirish Moodalbail  */
19326e91bba0SGirish Moodalbail ipadm_status_t
ipadm_set_addr(ipadm_addrobj_t ipaddr,const char * astr,sa_family_t af)19336e91bba0SGirish Moodalbail ipadm_set_addr(ipadm_addrobj_t ipaddr, const char *astr, sa_family_t af)
19346e91bba0SGirish Moodalbail {
19356e91bba0SGirish Moodalbail 	char		*prefixlenstr;
19366e91bba0SGirish Moodalbail 	uint32_t	prefixlen = 0;
19376e91bba0SGirish Moodalbail 	char		*endp;
19386e91bba0SGirish Moodalbail 	/*
19396e91bba0SGirish Moodalbail 	 * We use (NI_MAXHOST + 5) because the longest possible
19406e91bba0SGirish Moodalbail 	 * astr will have (NI_MAXHOST + '/' + {a maximum of 32 for IPv4
19416e91bba0SGirish Moodalbail 	 * or a maximum of 128 for IPv6 + '\0') chars
19426e91bba0SGirish Moodalbail 	 */
19436e91bba0SGirish Moodalbail 	char		addrstr[NI_MAXHOST + 5];
19446e91bba0SGirish Moodalbail 	ipadm_status_t	status;
19456e91bba0SGirish Moodalbail 
19466e91bba0SGirish Moodalbail 	(void) snprintf(addrstr, sizeof (addrstr), "%s", astr);
19476e91bba0SGirish Moodalbail 	if ((prefixlenstr = strchr(addrstr, '/')) != NULL) {
19486e91bba0SGirish Moodalbail 		*prefixlenstr++ = '\0';
19496e91bba0SGirish Moodalbail 		errno = 0;
19506e91bba0SGirish Moodalbail 		prefixlen = strtoul(prefixlenstr, &endp, 10);
19516e91bba0SGirish Moodalbail 		if (errno != 0 || *endp != '\0')
19526e91bba0SGirish Moodalbail 			return (IPADM_INVALID_ARG);
19536e91bba0SGirish Moodalbail 		if ((af == AF_INET && prefixlen > IP_ABITS) ||
19546e91bba0SGirish Moodalbail 		    (af == AF_INET6 && prefixlen > IPV6_ABITS))
19556e91bba0SGirish Moodalbail 			return (IPADM_INVALID_ARG);
19566e91bba0SGirish Moodalbail 	}
19576e91bba0SGirish Moodalbail 
19586e91bba0SGirish Moodalbail 	status = i_ipadm_resolve_addr(addrstr, af, &ipaddr->ipadm_static_addr);
19596e91bba0SGirish Moodalbail 	if (status == IPADM_SUCCESS) {
19606e91bba0SGirish Moodalbail 		(void) strlcpy(ipaddr->ipadm_static_aname, addrstr,
19616e91bba0SGirish Moodalbail 		    sizeof (ipaddr->ipadm_static_aname));
19626e91bba0SGirish Moodalbail 		ipaddr->ipadm_af = ipaddr->ipadm_static_addr.ss_family;
19636e91bba0SGirish Moodalbail 		ipaddr->ipadm_static_prefixlen = prefixlen;
19646e91bba0SGirish Moodalbail 	}
19656e91bba0SGirish Moodalbail 	return (status);
19666e91bba0SGirish Moodalbail }
19676e91bba0SGirish Moodalbail 
1968f6da83d4SAnurag S. Maskey /*
1969f6da83d4SAnurag S. Maskey  * Gets the static source address from the address object in `ipaddr'.
1970f6da83d4SAnurag S. Maskey  * Memory for `addr' should be already allocated by the caller.
1971f6da83d4SAnurag S. Maskey  */
1972f6da83d4SAnurag S. Maskey ipadm_status_t
ipadm_get_addr(const ipadm_addrobj_t ipaddr,struct sockaddr_storage * addr)1973f6da83d4SAnurag S. Maskey ipadm_get_addr(const ipadm_addrobj_t ipaddr, struct sockaddr_storage *addr)
1974f6da83d4SAnurag S. Maskey {
1975f6da83d4SAnurag S. Maskey 	if (ipaddr == NULL || ipaddr->ipadm_atype != IPADM_ADDR_STATIC ||
1976f6da83d4SAnurag S. Maskey 	    addr == NULL) {
1977f6da83d4SAnurag S. Maskey 		return (IPADM_INVALID_ARG);
1978f6da83d4SAnurag S. Maskey 	}
1979f6da83d4SAnurag S. Maskey 	*addr = ipaddr->ipadm_static_addr;
1980f6da83d4SAnurag S. Maskey 
1981f6da83d4SAnurag S. Maskey 	return (IPADM_SUCCESS);
1982f6da83d4SAnurag S. Maskey }
1983b31320a7SChris Fraire 
19846e91bba0SGirish Moodalbail /*
19856e91bba0SGirish Moodalbail  * Set up tunnel destination address in ipaddr by contacting DNS.
19866e91bba0SGirish Moodalbail  * The function works similar to ipadm_set_addr().
19876e91bba0SGirish Moodalbail  * The dst_addr must resolve to exactly one address. IPADM_BAD_ADDR is returned
19886e91bba0SGirish Moodalbail  * if dst_addr resolves to more than one address. The caller has to verify
19896e91bba0SGirish Moodalbail  * that ipadm_static_addr and ipadm_static_dst_addr have the same ss_family
19906e91bba0SGirish Moodalbail  */
19916e91bba0SGirish Moodalbail ipadm_status_t
ipadm_set_dst_addr(ipadm_addrobj_t ipaddr,const char * daddrstr,sa_family_t af)19926e91bba0SGirish Moodalbail ipadm_set_dst_addr(ipadm_addrobj_t ipaddr, const char *daddrstr, sa_family_t af)
19936e91bba0SGirish Moodalbail {
19946e91bba0SGirish Moodalbail 	ipadm_status_t	status;
19956e91bba0SGirish Moodalbail 
19966e91bba0SGirish Moodalbail 	/* mask lengths are not meaningful for point-to-point interfaces. */
19976e91bba0SGirish Moodalbail 	if (strchr(daddrstr, '/') != NULL)
19986e91bba0SGirish Moodalbail 		return (IPADM_BAD_ADDR);
19996e91bba0SGirish Moodalbail 
20006e91bba0SGirish Moodalbail 	status = i_ipadm_resolve_addr(daddrstr, af,
20016e91bba0SGirish Moodalbail 	    &ipaddr->ipadm_static_dst_addr);
20026e91bba0SGirish Moodalbail 	if (status == IPADM_SUCCESS) {
20036e91bba0SGirish Moodalbail 		(void) strlcpy(ipaddr->ipadm_static_dname, daddrstr,
20046e91bba0SGirish Moodalbail 		    sizeof (ipaddr->ipadm_static_dname));
20056e91bba0SGirish Moodalbail 	}
20066e91bba0SGirish Moodalbail 	return (status);
20076e91bba0SGirish Moodalbail }
20086e91bba0SGirish Moodalbail 
20096e91bba0SGirish Moodalbail /*
20106e91bba0SGirish Moodalbail  * Sets the interface ID in the address object `ipaddr' with the address
20116e91bba0SGirish Moodalbail  * in the string `interface_id'. This interface ID will be used when
20126e91bba0SGirish Moodalbail  * ipadm_create_addr() is called with `ipaddr' with address type
20136e91bba0SGirish Moodalbail  * set to IPADM_ADDR_IPV6_ADDRCONF.
20146e91bba0SGirish Moodalbail  */
20156e91bba0SGirish Moodalbail ipadm_status_t
ipadm_set_interface_id(ipadm_addrobj_t ipaddr,const char * interface_id)20166e91bba0SGirish Moodalbail ipadm_set_interface_id(ipadm_addrobj_t ipaddr, const char *interface_id)
20176e91bba0SGirish Moodalbail {
20186e91bba0SGirish Moodalbail 	struct sockaddr_in6	*sin6;
20196e91bba0SGirish Moodalbail 	char			*end;
20206e91bba0SGirish Moodalbail 	char			*cp;
20216e91bba0SGirish Moodalbail 	uint32_t		prefixlen;
20226e91bba0SGirish Moodalbail 	char			addrstr[INET6_ADDRSTRLEN + 1];
20236e91bba0SGirish Moodalbail 
20246e91bba0SGirish Moodalbail 	if (ipaddr == NULL || interface_id == NULL ||
20256e91bba0SGirish Moodalbail 	    ipaddr->ipadm_atype != IPADM_ADDR_IPV6_ADDRCONF)
20266e91bba0SGirish Moodalbail 		return (IPADM_INVALID_ARG);
20276e91bba0SGirish Moodalbail 
20286e91bba0SGirish Moodalbail 	(void) strlcpy(addrstr, interface_id, sizeof (addrstr));
20296e91bba0SGirish Moodalbail 	if ((cp = strchr(addrstr, '/')) == NULL)
20306e91bba0SGirish Moodalbail 		return (IPADM_INVALID_ARG);
20316e91bba0SGirish Moodalbail 	*cp++ = '\0';
20326e91bba0SGirish Moodalbail 	sin6 = &ipaddr->ipadm_intfid;
20336e91bba0SGirish Moodalbail 	if (inet_pton(AF_INET6, addrstr, &sin6->sin6_addr) == 1) {
20346e91bba0SGirish Moodalbail 		errno = 0;
20356e91bba0SGirish Moodalbail 		prefixlen = strtoul(cp, &end, 10);
20366e91bba0SGirish Moodalbail 		if (errno != 0 || *end != '\0' || prefixlen > IPV6_ABITS)
20376e91bba0SGirish Moodalbail 			return (IPADM_INVALID_ARG);
20386e91bba0SGirish Moodalbail 		sin6->sin6_family = AF_INET6;
20396e91bba0SGirish Moodalbail 		ipaddr->ipadm_intfidlen = prefixlen;
20406e91bba0SGirish Moodalbail 		return (IPADM_SUCCESS);
20416e91bba0SGirish Moodalbail 	}
20426e91bba0SGirish Moodalbail 	return (IPADM_INVALID_ARG);
20436e91bba0SGirish Moodalbail }
20446e91bba0SGirish Moodalbail 
20456e91bba0SGirish Moodalbail /*
20466e91bba0SGirish Moodalbail  * Sets the value for the field `ipadm_stateless' in address object `ipaddr'.
20476e91bba0SGirish Moodalbail  */
20486e91bba0SGirish Moodalbail ipadm_status_t
ipadm_set_stateless(ipadm_addrobj_t ipaddr,boolean_t stateless)20496e91bba0SGirish Moodalbail ipadm_set_stateless(ipadm_addrobj_t ipaddr, boolean_t stateless)
20506e91bba0SGirish Moodalbail {
20516e91bba0SGirish Moodalbail 	if (ipaddr == NULL ||
20526e91bba0SGirish Moodalbail 	    ipaddr->ipadm_atype != IPADM_ADDR_IPV6_ADDRCONF)
20536e91bba0SGirish Moodalbail 		return (IPADM_INVALID_ARG);
20546e91bba0SGirish Moodalbail 	ipaddr->ipadm_stateless = stateless;
20556e91bba0SGirish Moodalbail 
20566e91bba0SGirish Moodalbail 	return (IPADM_SUCCESS);
20576e91bba0SGirish Moodalbail }
20586e91bba0SGirish Moodalbail 
20596e91bba0SGirish Moodalbail /*
20606e91bba0SGirish Moodalbail  * Sets the value for the field `ipadm_stateful' in address object `ipaddr'.
20616e91bba0SGirish Moodalbail  */
20626e91bba0SGirish Moodalbail ipadm_status_t
ipadm_set_stateful(ipadm_addrobj_t ipaddr,boolean_t stateful)20636e91bba0SGirish Moodalbail ipadm_set_stateful(ipadm_addrobj_t ipaddr, boolean_t stateful)
20646e91bba0SGirish Moodalbail {
20656e91bba0SGirish Moodalbail 	if (ipaddr == NULL ||
20666e91bba0SGirish Moodalbail 	    ipaddr->ipadm_atype != IPADM_ADDR_IPV6_ADDRCONF)
20676e91bba0SGirish Moodalbail 		return (IPADM_INVALID_ARG);
20686e91bba0SGirish Moodalbail 	ipaddr->ipadm_stateful = stateful;
20696e91bba0SGirish Moodalbail 
20706e91bba0SGirish Moodalbail 	return (IPADM_SUCCESS);
20716e91bba0SGirish Moodalbail }
20726e91bba0SGirish Moodalbail 
20736e91bba0SGirish Moodalbail /*
20746e91bba0SGirish Moodalbail  * Sets the dhcp parameter `ipadm_primary' in the address object `ipaddr'.
20756e91bba0SGirish Moodalbail  * The field is used during the address creation with address
20766e91bba0SGirish Moodalbail  * type IPADM_ADDR_DHCP. It specifies if the interface should be set
20776e91bba0SGirish Moodalbail  * as a primary interface for getting dhcp global options from the DHCP server.
20786e91bba0SGirish Moodalbail  */
20796e91bba0SGirish Moodalbail ipadm_status_t
ipadm_set_primary(ipadm_addrobj_t ipaddr,boolean_t primary)20806e91bba0SGirish Moodalbail ipadm_set_primary(ipadm_addrobj_t ipaddr, boolean_t primary)
20816e91bba0SGirish Moodalbail {
20826e91bba0SGirish Moodalbail 	if (ipaddr == NULL || ipaddr->ipadm_atype != IPADM_ADDR_DHCP)
20836e91bba0SGirish Moodalbail 		return (IPADM_INVALID_ARG);
20846e91bba0SGirish Moodalbail 	ipaddr->ipadm_primary = primary;
20856e91bba0SGirish Moodalbail 
20866e91bba0SGirish Moodalbail 	return (IPADM_SUCCESS);
20876e91bba0SGirish Moodalbail }
20886e91bba0SGirish Moodalbail 
20896e91bba0SGirish Moodalbail /*
20906e91bba0SGirish Moodalbail  * Sets the dhcp parameter `ipadm_wait' in the address object `ipaddr'.
20916e91bba0SGirish Moodalbail  * This field is used during the address creation with address type
20926e91bba0SGirish Moodalbail  * IPADM_ADDR_DHCP. It specifies how long the API ipadm_create_addr()
20936e91bba0SGirish Moodalbail  * should wait before returning while the dhcp address is being acquired
20946e91bba0SGirish Moodalbail  * by the dhcpagent.
20956e91bba0SGirish Moodalbail  * Possible values:
20966e91bba0SGirish Moodalbail  * - IPADM_DHCP_WAIT_FOREVER : Do not return until dhcpagent returns.
20976e91bba0SGirish Moodalbail  * - IPADM_DHCP_WAIT_DEFAULT : Wait a default amount of time before returning.
20986e91bba0SGirish Moodalbail  * - <integer>	   : Wait the specified number of seconds before returning.
20996e91bba0SGirish Moodalbail  */
21006e91bba0SGirish Moodalbail ipadm_status_t
ipadm_set_wait_time(ipadm_addrobj_t ipaddr,int32_t wait)21016e91bba0SGirish Moodalbail ipadm_set_wait_time(ipadm_addrobj_t ipaddr, int32_t wait)
21026e91bba0SGirish Moodalbail {
21036e91bba0SGirish Moodalbail 	if (ipaddr == NULL || ipaddr->ipadm_atype != IPADM_ADDR_DHCP)
21046e91bba0SGirish Moodalbail 		return (IPADM_INVALID_ARG);
21056e91bba0SGirish Moodalbail 	ipaddr->ipadm_wait = wait;
21066e91bba0SGirish Moodalbail 	return (IPADM_SUCCESS);
21076e91bba0SGirish Moodalbail }
21086e91bba0SGirish Moodalbail 
2109b31320a7SChris Fraire /*
2110b31320a7SChris Fraire  * Sets the dhcp parameter `ipadm_reqhost' in the address object `ipaddr',
2111b31320a7SChris Fraire  * but validate any non-nil value using ipadm_is_valid_hostname() and also
2112b31320a7SChris Fraire  * check length.
2113b31320a7SChris Fraire  */
2114b31320a7SChris Fraire ipadm_status_t
ipadm_set_reqhost(ipadm_addrobj_t ipaddr,const char * reqhost)2115b31320a7SChris Fraire ipadm_set_reqhost(ipadm_addrobj_t ipaddr, const char *reqhost)
2116b31320a7SChris Fraire {
2117b31320a7SChris Fraire 	const size_t HNLEN = sizeof (ipaddr->ipadm_reqhost);
2118b31320a7SChris Fraire 
2119b31320a7SChris Fraire 	if (ipaddr == NULL || ipaddr->ipadm_atype != IPADM_ADDR_DHCP)
2120b31320a7SChris Fraire 		return (IPADM_INVALID_ARG);
2121b31320a7SChris Fraire 
2122b31320a7SChris Fraire 	if (ipadm_is_nil_hostname(reqhost))
2123b31320a7SChris Fraire 		*ipaddr->ipadm_reqhost = '\0';
2124b31320a7SChris Fraire 	else if (!ipadm_is_valid_hostname(reqhost))
2125b31320a7SChris Fraire 		return (IPADM_INVALID_ARG);
2126b31320a7SChris Fraire 	else if (strlcpy(ipaddr->ipadm_reqhost, reqhost, HNLEN) >= HNLEN)
2127b31320a7SChris Fraire 		return (IPADM_INVALID_ARG);
2128b31320a7SChris Fraire 	return (IPADM_SUCCESS);
2129b31320a7SChris Fraire }
2130b31320a7SChris Fraire 
21316e91bba0SGirish Moodalbail /*
21326e91bba0SGirish Moodalbail  * Creates a placeholder for the `ipadm_aobjname' in the ipmgmtd `aobjmap'.
21336e91bba0SGirish Moodalbail  * If the `aobjname' already exists in the daemon's `aobjmap' then
21346e91bba0SGirish Moodalbail  * IPADM_ADDROBJ_EXISTS will be returned.
21356e91bba0SGirish Moodalbail  *
21366e91bba0SGirish Moodalbail  * If the libipadm consumer set `ipaddr.ipadm_aobjname[0]' to `\0', then the
21376e91bba0SGirish Moodalbail  * daemon will generate an `aobjname' for the given `ipaddr'.
21386e91bba0SGirish Moodalbail  */
21396e91bba0SGirish Moodalbail ipadm_status_t
i_ipadm_lookupadd_addrobj(ipadm_handle_t iph,ipadm_addrobj_t ipaddr)21406e91bba0SGirish Moodalbail i_ipadm_lookupadd_addrobj(ipadm_handle_t iph, ipadm_addrobj_t ipaddr)
21416e91bba0SGirish Moodalbail {
21426e91bba0SGirish Moodalbail 	ipmgmt_aobjop_arg_t	larg;
21436e91bba0SGirish Moodalbail 	ipmgmt_aobjop_rval_t	rval, *rvalp;
21446e91bba0SGirish Moodalbail 	int			err;
21456e91bba0SGirish Moodalbail 
21466e91bba0SGirish Moodalbail 	bzero(&larg, sizeof (larg));
21476e91bba0SGirish Moodalbail 	larg.ia_cmd = IPMGMT_CMD_ADDROBJ_LOOKUPADD;
21486e91bba0SGirish Moodalbail 	(void) strlcpy(larg.ia_aobjname, ipaddr->ipadm_aobjname,
21496e91bba0SGirish Moodalbail 	    sizeof (larg.ia_aobjname));
21506e91bba0SGirish Moodalbail 	(void) strlcpy(larg.ia_ifname, ipaddr->ipadm_ifname,
21516e91bba0SGirish Moodalbail 	    sizeof (larg.ia_ifname));
21526e91bba0SGirish Moodalbail 	larg.ia_family = ipaddr->ipadm_af;
2153ec3706caSVasumathi Sundaram 	larg.ia_atype = ipaddr->ipadm_atype;
21546e91bba0SGirish Moodalbail 
21556e91bba0SGirish Moodalbail 	rvalp = &rval;
21566e91bba0SGirish Moodalbail 	err = ipadm_door_call(iph, &larg, sizeof (larg), (void **)&rvalp,
21576e91bba0SGirish Moodalbail 	    sizeof (rval), B_FALSE);
2158*499f5187SDan Cross 	if (err == 0) {
2159*499f5187SDan Cross 		/*
2160*499f5187SDan Cross 		 * Save daemon-generated state.  Copy the `lnum` from
2161*499f5187SDan Cross 		 * the daemon if this is not a legacy case, and copy
2162*499f5187SDan Cross 		 * `aobjname' if we did not give a name.
2163*499f5187SDan Cross 		 */
2164*499f5187SDan Cross 		if ((iph->iph_flags & IPH_LEGACY) == 0)
2165*499f5187SDan Cross 			ipaddr->ipadm_lifnum = rval.ir_lnum;
2166*499f5187SDan Cross 		if (ipaddr->ipadm_aobjname[0] == '\0') {
2167*499f5187SDan Cross 			(void) strlcpy(ipaddr->ipadm_aobjname,
2168*499f5187SDan Cross 			    rval.ir_aobjname,
2169*499f5187SDan Cross 			    sizeof (ipaddr->ipadm_aobjname));
2170*499f5187SDan Cross 		}
21716e91bba0SGirish Moodalbail 	}
21726e91bba0SGirish Moodalbail 	if (err == EEXIST)
21736e91bba0SGirish Moodalbail 		return (IPADM_ADDROBJ_EXISTS);
21746e91bba0SGirish Moodalbail 	return (ipadm_errno2status(err));
21756e91bba0SGirish Moodalbail }
21766e91bba0SGirish Moodalbail 
2177ec3706caSVasumathi Sundaram /*
2178ec3706caSVasumathi Sundaram  * Sets the logical interface number in the ipmgmtd's memory map for the
2179ec3706caSVasumathi Sundaram  * address object `ipaddr'. If another address object has the same
2180ec3706caSVasumathi Sundaram  * logical interface number, IPADM_ADDROBJ_EXISTS is returned.
2181ec3706caSVasumathi Sundaram  */
2182ec3706caSVasumathi Sundaram ipadm_status_t
i_ipadm_setlifnum_addrobj(ipadm_handle_t iph,ipadm_addrobj_t ipaddr)2183ec3706caSVasumathi Sundaram i_ipadm_setlifnum_addrobj(ipadm_handle_t iph, ipadm_addrobj_t ipaddr)
2184ec3706caSVasumathi Sundaram {
2185ec3706caSVasumathi Sundaram 	ipmgmt_aobjop_arg_t	larg;
2186ec3706caSVasumathi Sundaram 	ipmgmt_retval_t		rval, *rvalp;
2187ec3706caSVasumathi Sundaram 	int			err;
2188ec3706caSVasumathi Sundaram 
2189550b6e40SSowmini Varadhan 	if (iph->iph_flags & IPH_IPMGMTD)
2190550b6e40SSowmini Varadhan 		return (IPADM_SUCCESS);
2191550b6e40SSowmini Varadhan 
2192ec3706caSVasumathi Sundaram 	bzero(&larg, sizeof (larg));
2193ec3706caSVasumathi Sundaram 	larg.ia_cmd = IPMGMT_CMD_ADDROBJ_SETLIFNUM;
2194ec3706caSVasumathi Sundaram 	(void) strlcpy(larg.ia_aobjname, ipaddr->ipadm_aobjname,
2195ec3706caSVasumathi Sundaram 	    sizeof (larg.ia_aobjname));
2196ec3706caSVasumathi Sundaram 	larg.ia_lnum = ipaddr->ipadm_lifnum;
2197ec3706caSVasumathi Sundaram 	(void) strlcpy(larg.ia_ifname, ipaddr->ipadm_ifname,
2198ec3706caSVasumathi Sundaram 	    sizeof (larg.ia_ifname));
2199ec3706caSVasumathi Sundaram 	larg.ia_family = ipaddr->ipadm_af;
2200ec3706caSVasumathi Sundaram 
2201ec3706caSVasumathi Sundaram 	rvalp = &rval;
2202ec3706caSVasumathi Sundaram 	err = ipadm_door_call(iph, &larg, sizeof (larg), (void **)&rvalp,
2203ec3706caSVasumathi Sundaram 	    sizeof (rval), B_FALSE);
2204ec3706caSVasumathi Sundaram 	if (err == EEXIST)
2205ec3706caSVasumathi Sundaram 		return (IPADM_ADDROBJ_EXISTS);
2206ec3706caSVasumathi Sundaram 	return (ipadm_errno2status(err));
2207ec3706caSVasumathi Sundaram }
2208ec3706caSVasumathi Sundaram 
22096e91bba0SGirish Moodalbail /*
22106e91bba0SGirish Moodalbail  * Creates the IPv4 or IPv6 address in the nvlist `nvl' on the interface
22116e91bba0SGirish Moodalbail  * `ifname'. If a hostname is present, it is resolved before the address
22126e91bba0SGirish Moodalbail  * is created.
22136e91bba0SGirish Moodalbail  */
22146e91bba0SGirish Moodalbail ipadm_status_t
i_ipadm_enable_static(ipadm_handle_t iph,const char * ifname,nvlist_t * nvl,sa_family_t af)22156e91bba0SGirish Moodalbail i_ipadm_enable_static(ipadm_handle_t iph, const char *ifname, nvlist_t *nvl,
22166e91bba0SGirish Moodalbail     sa_family_t af)
22176e91bba0SGirish Moodalbail {
22186e91bba0SGirish Moodalbail 	char			*prefixlenstr = NULL;
22196e91bba0SGirish Moodalbail 	char			*upstr = NULL;
22206e91bba0SGirish Moodalbail 	char			*sname = NULL, *dname = NULL;
22216e91bba0SGirish Moodalbail 	struct ipadm_addrobj_s	ipaddr;
22226e91bba0SGirish Moodalbail 	char			*aobjname = NULL;
22236e91bba0SGirish Moodalbail 	nvlist_t		*nvaddr = NULL;
22246e91bba0SGirish Moodalbail 	nvpair_t		*nvp;
22256e91bba0SGirish Moodalbail 	char			*cidraddr;
22266e91bba0SGirish Moodalbail 	char			*name;
22276e91bba0SGirish Moodalbail 	ipadm_status_t		status;
22286e91bba0SGirish Moodalbail 	int			err = 0;
22296e91bba0SGirish Moodalbail 	uint32_t		flags = IPADM_OPT_ACTIVE;
22306e91bba0SGirish Moodalbail 
22316e91bba0SGirish Moodalbail 	/* retrieve the address information */
22326e91bba0SGirish Moodalbail 	for (nvp = nvlist_next_nvpair(nvl, NULL); nvp != NULL;
22336e91bba0SGirish Moodalbail 	    nvp = nvlist_next_nvpair(nvl, nvp)) {
22346e91bba0SGirish Moodalbail 		name = nvpair_name(nvp);
22356e91bba0SGirish Moodalbail 		if (strcmp(name, IPADM_NVP_IPV4ADDR) == 0 ||
22366e91bba0SGirish Moodalbail 		    strcmp(name, IPADM_NVP_IPV6ADDR) == 0) {
22376e91bba0SGirish Moodalbail 			err = nvpair_value_nvlist(nvp, &nvaddr);
22386e91bba0SGirish Moodalbail 		} else if (strcmp(name, IPADM_NVP_AOBJNAME) == 0) {
22396e91bba0SGirish Moodalbail 			err = nvpair_value_string(nvp, &aobjname);
22406e91bba0SGirish Moodalbail 		} else if (strcmp(name, IPADM_NVP_PREFIXLEN) == 0) {
22416e91bba0SGirish Moodalbail 			err = nvpair_value_string(nvp, &prefixlenstr);
22426e91bba0SGirish Moodalbail 		} else if (strcmp(name, "up") == 0) {
22436e91bba0SGirish Moodalbail 			err = nvpair_value_string(nvp, &upstr);
22446e91bba0SGirish Moodalbail 		}
22456e91bba0SGirish Moodalbail 		if (err != 0)
22466e91bba0SGirish Moodalbail 			return (ipadm_errno2status(err));
22476e91bba0SGirish Moodalbail 	}
22486e91bba0SGirish Moodalbail 	for (nvp = nvlist_next_nvpair(nvaddr, NULL); nvp != NULL;
22496e91bba0SGirish Moodalbail 	    nvp = nvlist_next_nvpair(nvaddr, nvp)) {
22506e91bba0SGirish Moodalbail 		name = nvpair_name(nvp);
22516e91bba0SGirish Moodalbail 		if (strcmp(name, IPADM_NVP_IPADDRHNAME) == 0)
22526e91bba0SGirish Moodalbail 			err = nvpair_value_string(nvp, &sname);
22536e91bba0SGirish Moodalbail 		else if (strcmp(name, IPADM_NVP_IPDADDRHNAME) == 0)
22546e91bba0SGirish Moodalbail 			err = nvpair_value_string(nvp, &dname);
22556e91bba0SGirish Moodalbail 		if (err != 0)
22566e91bba0SGirish Moodalbail 			return (ipadm_errno2status(err));
22576e91bba0SGirish Moodalbail 	}
22586e91bba0SGirish Moodalbail 
22596e91bba0SGirish Moodalbail 	if (strcmp(upstr, "yes") == 0)
22606e91bba0SGirish Moodalbail 		flags |= IPADM_OPT_UP;
22616e91bba0SGirish Moodalbail 
22626e91bba0SGirish Moodalbail 	/* build the address object from the above information */
22636e91bba0SGirish Moodalbail 	i_ipadm_init_addr(&ipaddr, ifname, aobjname, IPADM_ADDR_STATIC);
22646e91bba0SGirish Moodalbail 	if (prefixlenstr != NULL && atoi(prefixlenstr) > 0) {
22656e91bba0SGirish Moodalbail 		if (asprintf(&cidraddr, "%s/%s", sname, prefixlenstr) == -1)
22666e91bba0SGirish Moodalbail 			return (IPADM_NO_MEMORY);
22676e91bba0SGirish Moodalbail 		status = ipadm_set_addr(&ipaddr, cidraddr, af);
22686e91bba0SGirish Moodalbail 		free(cidraddr);
22696e91bba0SGirish Moodalbail 	} else {
22706e91bba0SGirish Moodalbail 		status = ipadm_set_addr(&ipaddr, sname, af);
22716e91bba0SGirish Moodalbail 	}
22726e91bba0SGirish Moodalbail 	if (status != IPADM_SUCCESS)
22736e91bba0SGirish Moodalbail 		return (status);
22746e91bba0SGirish Moodalbail 
22756e91bba0SGirish Moodalbail 	if (dname != NULL) {
22766e91bba0SGirish Moodalbail 		status = ipadm_set_dst_addr(&ipaddr, dname, af);
22776e91bba0SGirish Moodalbail 		if (status != IPADM_SUCCESS)
22786e91bba0SGirish Moodalbail 			return (status);
22796e91bba0SGirish Moodalbail 	}
22806e91bba0SGirish Moodalbail 	return (i_ipadm_create_addr(iph, &ipaddr, flags));
22816e91bba0SGirish Moodalbail }
22826e91bba0SGirish Moodalbail 
22836e91bba0SGirish Moodalbail /*
22846e91bba0SGirish Moodalbail  * Creates a dhcp address on the interface `ifname' based on the
22856e91bba0SGirish Moodalbail  * IPADM_ADDR_DHCP address object parameters from the nvlist `nvl'.
22866e91bba0SGirish Moodalbail  */
22876e91bba0SGirish Moodalbail ipadm_status_t
i_ipadm_enable_dhcp(ipadm_handle_t iph,const char * ifname,nvlist_t * nvl)22886e91bba0SGirish Moodalbail i_ipadm_enable_dhcp(ipadm_handle_t iph, const char *ifname, nvlist_t *nvl)
22896e91bba0SGirish Moodalbail {
2290b31320a7SChris Fraire 	int32_t			wait = IPADM_DHCP_WAIT_DEFAULT;
2291b31320a7SChris Fraire 	boolean_t		primary = B_FALSE;
2292b31320a7SChris Fraire 	nvlist_t		*nvdhcp = NULL;
22936e91bba0SGirish Moodalbail 	nvpair_t		*nvp;
22946e91bba0SGirish Moodalbail 	char			*name;
22956e91bba0SGirish Moodalbail 	struct ipadm_addrobj_s	ipaddr;
2296b31320a7SChris Fraire 	char			*aobjname = NULL, *reqhost = NULL;
22976e91bba0SGirish Moodalbail 	int			err = 0;
2298b31320a7SChris Fraire 	ipadm_status_t		ipadm_err = IPADM_SUCCESS;
22996e91bba0SGirish Moodalbail 
23006e91bba0SGirish Moodalbail 	/* Extract the dhcp parameters */
23016e91bba0SGirish Moodalbail 	for (nvp = nvlist_next_nvpair(nvl, NULL); nvp != NULL;
23026e91bba0SGirish Moodalbail 	    nvp = nvlist_next_nvpair(nvl, nvp)) {
23036e91bba0SGirish Moodalbail 		name = nvpair_name(nvp);
23046e91bba0SGirish Moodalbail 		if (strcmp(name, IPADM_NVP_DHCP) == 0)
23056e91bba0SGirish Moodalbail 			err = nvpair_value_nvlist(nvp, &nvdhcp);
23066e91bba0SGirish Moodalbail 		else if (strcmp(name, IPADM_NVP_AOBJNAME) == 0)
23076e91bba0SGirish Moodalbail 			err = nvpair_value_string(nvp, &aobjname);
2308b31320a7SChris Fraire 		else if (strcmp(name, IPADM_NVP_REQHOST) == 0)
2309b31320a7SChris Fraire 			err = nvpair_value_string(nvp, &reqhost);
23106e91bba0SGirish Moodalbail 		if (err != 0)
23116e91bba0SGirish Moodalbail 			return (ipadm_errno2status(err));
23126e91bba0SGirish Moodalbail 	}
23136e91bba0SGirish Moodalbail 	for (nvp = nvlist_next_nvpair(nvdhcp, NULL); nvp != NULL;
23146e91bba0SGirish Moodalbail 	    nvp = nvlist_next_nvpair(nvdhcp, nvp)) {
23156e91bba0SGirish Moodalbail 		name = nvpair_name(nvp);
23166e91bba0SGirish Moodalbail 		if (strcmp(name, IPADM_NVP_WAIT) == 0)
23176e91bba0SGirish Moodalbail 			err = nvpair_value_int32(nvp, &wait);
23186e91bba0SGirish Moodalbail 		else if (strcmp(name, IPADM_NVP_PRIMARY) == 0)
23196e91bba0SGirish Moodalbail 			err = nvpair_value_boolean_value(nvp, &primary);
23206e91bba0SGirish Moodalbail 		if (err != 0)
23216e91bba0SGirish Moodalbail 			return (ipadm_errno2status(err));
23226e91bba0SGirish Moodalbail 	}
23236e91bba0SGirish Moodalbail 
23246e91bba0SGirish Moodalbail 	/* Build the address object */
23256e91bba0SGirish Moodalbail 	i_ipadm_init_addr(&ipaddr, ifname, aobjname, IPADM_ADDR_DHCP);
23266e91bba0SGirish Moodalbail 	ipaddr.ipadm_primary = primary;
23276e91bba0SGirish Moodalbail 	if (iph->iph_flags & IPH_INIT)
23286e91bba0SGirish Moodalbail 		ipaddr.ipadm_wait = 0;
23296e91bba0SGirish Moodalbail 	else
23306e91bba0SGirish Moodalbail 		ipaddr.ipadm_wait = wait;
2331b31320a7SChris Fraire 	ipadm_err = ipadm_set_reqhost(&ipaddr, reqhost);
2332b31320a7SChris Fraire 	if (ipadm_err != IPADM_SUCCESS)
2333b31320a7SChris Fraire 		return (ipadm_err);
2334ec3706caSVasumathi Sundaram 	ipaddr.ipadm_af = AF_INET;
23356e91bba0SGirish Moodalbail 	return (i_ipadm_create_dhcp(iph, &ipaddr, IPADM_OPT_ACTIVE));
23366e91bba0SGirish Moodalbail }
23376e91bba0SGirish Moodalbail 
23386e91bba0SGirish Moodalbail /*
23396e91bba0SGirish Moodalbail  * Creates auto-configured addresses on the interface `ifname' based on
23406e91bba0SGirish Moodalbail  * the IPADM_ADDR_IPV6_ADDRCONF address object parameters from the nvlist `nvl'.
23416e91bba0SGirish Moodalbail  */
23426e91bba0SGirish Moodalbail ipadm_status_t
i_ipadm_enable_addrconf(ipadm_handle_t iph,const char * ifname,nvlist_t * nvl)23436e91bba0SGirish Moodalbail i_ipadm_enable_addrconf(ipadm_handle_t iph, const char *ifname, nvlist_t *nvl)
23446e91bba0SGirish Moodalbail {
23456e91bba0SGirish Moodalbail 	struct ipadm_addrobj_s	ipaddr;
23466e91bba0SGirish Moodalbail 	char		*stateful = NULL, *stateless = NULL;
23476e91bba0SGirish Moodalbail 	uint_t		n;
23486e91bba0SGirish Moodalbail 	uint8_t		*addr6 = NULL;
23496e91bba0SGirish Moodalbail 	uint32_t	intfidlen = 0;
23506e91bba0SGirish Moodalbail 	char		*aobjname;
23516e91bba0SGirish Moodalbail 	nvlist_t	*nvaddr;
23526e91bba0SGirish Moodalbail 	nvpair_t	*nvp;
23536e91bba0SGirish Moodalbail 	char		*name;
23546e91bba0SGirish Moodalbail 	int		err = 0;
23556e91bba0SGirish Moodalbail 
23566e91bba0SGirish Moodalbail 	/* Extract the parameters */
23576e91bba0SGirish Moodalbail 	for (nvp = nvlist_next_nvpair(nvl, NULL); nvp != NULL;
23586e91bba0SGirish Moodalbail 	    nvp = nvlist_next_nvpair(nvl, nvp)) {
23596e91bba0SGirish Moodalbail 		name = nvpair_name(nvp);
23606e91bba0SGirish Moodalbail 		if (strcmp(name, IPADM_NVP_INTFID) == 0)
23616e91bba0SGirish Moodalbail 			err = nvpair_value_nvlist(nvp, &nvaddr);
23626e91bba0SGirish Moodalbail 		else if (strcmp(name, IPADM_NVP_AOBJNAME) == 0)
23636e91bba0SGirish Moodalbail 			err = nvpair_value_string(nvp, &aobjname);
23646e91bba0SGirish Moodalbail 		if (err != 0)
23656e91bba0SGirish Moodalbail 			return (ipadm_errno2status(err));
23666e91bba0SGirish Moodalbail 	}
23676e91bba0SGirish Moodalbail 	for (nvp = nvlist_next_nvpair(nvaddr, NULL); nvp != NULL;
23686e91bba0SGirish Moodalbail 	    nvp = nvlist_next_nvpair(nvaddr, nvp)) {
23696e91bba0SGirish Moodalbail 		name = nvpair_name(nvp);
23706e91bba0SGirish Moodalbail 		if (strcmp(name, IPADM_NVP_IPNUMADDR) == 0)
23716e91bba0SGirish Moodalbail 			err = nvpair_value_uint8_array(nvp, &addr6, &n);
23726e91bba0SGirish Moodalbail 		if (strcmp(name, IPADM_NVP_PREFIXLEN) == 0)
23736e91bba0SGirish Moodalbail 			err = nvpair_value_uint32(nvp, &intfidlen);
23746e91bba0SGirish Moodalbail 		else if (strcmp(name, IPADM_NVP_STATELESS) == 0)
23756e91bba0SGirish Moodalbail 			err = nvpair_value_string(nvp, &stateless);
23766e91bba0SGirish Moodalbail 		else if (strcmp(name, IPADM_NVP_STATEFUL) == 0)
23776e91bba0SGirish Moodalbail 			err = nvpair_value_string(nvp, &stateful);
23786e91bba0SGirish Moodalbail 		if (err != 0)
23796e91bba0SGirish Moodalbail 			return (ipadm_errno2status(err));
23806e91bba0SGirish Moodalbail 	}
23816e91bba0SGirish Moodalbail 	/* Build the address object. */
23826e91bba0SGirish Moodalbail 	i_ipadm_init_addr(&ipaddr, ifname, aobjname, IPADM_ADDR_IPV6_ADDRCONF);
23836e91bba0SGirish Moodalbail 	if (intfidlen > 0) {
23846e91bba0SGirish Moodalbail 		ipaddr.ipadm_intfidlen = intfidlen;
23856e91bba0SGirish Moodalbail 		bcopy(addr6, &ipaddr.ipadm_intfid.sin6_addr.s6_addr, n);
23866e91bba0SGirish Moodalbail 	}
23876e91bba0SGirish Moodalbail 	ipaddr.ipadm_stateless = (strcmp(stateless, "yes") == 0);
23886e91bba0SGirish Moodalbail 	ipaddr.ipadm_stateful = (strcmp(stateful, "yes") == 0);
23896e91bba0SGirish Moodalbail 	return (i_ipadm_create_ipv6addrs(iph, &ipaddr, IPADM_OPT_ACTIVE));
23906e91bba0SGirish Moodalbail }
23916e91bba0SGirish Moodalbail 
23926e91bba0SGirish Moodalbail /*
23936e91bba0SGirish Moodalbail  * Allocates `ipadm_addrobj_t' and populates the relevant member fields based on
23946e91bba0SGirish Moodalbail  * the provided `type'. `aobjname' represents the address object name, which
23956e91bba0SGirish Moodalbail  * is of the form `<ifname>/<addressname>'.
23966e91bba0SGirish Moodalbail  *
23976e91bba0SGirish Moodalbail  * The caller has to minimally provide <ifname>. If <addressname> is not
23986e91bba0SGirish Moodalbail  * provided, then a default one will be generated by the API.
23996e91bba0SGirish Moodalbail  */
24006e91bba0SGirish Moodalbail ipadm_status_t
ipadm_create_addrobj(ipadm_addr_type_t type,const char * aobjname,ipadm_addrobj_t * ipaddr)24016e91bba0SGirish Moodalbail ipadm_create_addrobj(ipadm_addr_type_t type, const char *aobjname,
24026e91bba0SGirish Moodalbail     ipadm_addrobj_t *ipaddr)
24036e91bba0SGirish Moodalbail {
24046e91bba0SGirish Moodalbail 	ipadm_addrobj_t	newaddr;
24056e91bba0SGirish Moodalbail 	ipadm_status_t	status;
24066e91bba0SGirish Moodalbail 	char		*aname, *cp;
24076e91bba0SGirish Moodalbail 	char		ifname[IPADM_AOBJSIZ];
24080d1087e8SHans Rosenfeld 	ifspec_t	ifsp;
24096e91bba0SGirish Moodalbail 
24106e91bba0SGirish Moodalbail 	if (ipaddr == NULL)
24116e91bba0SGirish Moodalbail 		return (IPADM_INVALID_ARG);
24126e91bba0SGirish Moodalbail 	*ipaddr = NULL;
24136e91bba0SGirish Moodalbail 
24146e91bba0SGirish Moodalbail 	if (aobjname == NULL || aobjname[0] == '\0')
24156e91bba0SGirish Moodalbail 		return (IPADM_INVALID_ARG);
24166e91bba0SGirish Moodalbail 
24176e91bba0SGirish Moodalbail 	if (strlcpy(ifname, aobjname, IPADM_AOBJSIZ) >= IPADM_AOBJSIZ)
24186e91bba0SGirish Moodalbail 		return (IPADM_INVALID_ARG);
24196e91bba0SGirish Moodalbail 
24206e91bba0SGirish Moodalbail 	if ((aname = strchr(ifname, '/')) != NULL)
24216e91bba0SGirish Moodalbail 		*aname++ = '\0';
24226e91bba0SGirish Moodalbail 
24236e91bba0SGirish Moodalbail 	/* Check if the interface name is valid. */
24246e91bba0SGirish Moodalbail 	if (!ifparse_ifspec(ifname, &ifsp))
24256e91bba0SGirish Moodalbail 		return (IPADM_INVALID_ARG);
24266e91bba0SGirish Moodalbail 	/* Check if the given addrobj name is valid. */
24276e91bba0SGirish Moodalbail 	if (aname != NULL && !i_ipadm_is_user_aobjname_valid(aname))
24286e91bba0SGirish Moodalbail 		return (IPADM_INVALID_ARG);
24296e91bba0SGirish Moodalbail 	if ((newaddr = calloc(1, sizeof (struct ipadm_addrobj_s))) == NULL)
24306e91bba0SGirish Moodalbail 		return (IPADM_NO_MEMORY);
24316e91bba0SGirish Moodalbail 
24326e91bba0SGirish Moodalbail 	/*
24336e91bba0SGirish Moodalbail 	 * If the ifname has logical interface number, extract it and assign
24346e91bba0SGirish Moodalbail 	 * it to `ipadm_lifnum'. Only applications with IPH_LEGACY set will do
24356e91bba0SGirish Moodalbail 	 * this today. We will check for the validity later in
24366e91bba0SGirish Moodalbail 	 * i_ipadm_validate_create_addr().
24376e91bba0SGirish Moodalbail 	 */
24386e91bba0SGirish Moodalbail 	if (ifsp.ifsp_lunvalid) {
24396e91bba0SGirish Moodalbail 		newaddr->ipadm_lifnum = ifsp.ifsp_lun;
24406e91bba0SGirish Moodalbail 		cp = strchr(ifname, IPADM_LOGICAL_SEP);
24416e91bba0SGirish Moodalbail 		*cp = '\0';
24426e91bba0SGirish Moodalbail 	}
24436e91bba0SGirish Moodalbail 	(void) strlcpy(newaddr->ipadm_ifname, ifname,
24446e91bba0SGirish Moodalbail 	    sizeof (newaddr->ipadm_ifname));
24456e91bba0SGirish Moodalbail 
24466e91bba0SGirish Moodalbail 	if (aname != NULL) {
24476e91bba0SGirish Moodalbail 		(void) snprintf(newaddr->ipadm_aobjname,
24486e91bba0SGirish Moodalbail 		    sizeof (newaddr->ipadm_aobjname), "%s/%s", ifname, aname);
24496e91bba0SGirish Moodalbail 	}
24506e91bba0SGirish Moodalbail 
24516e91bba0SGirish Moodalbail 	switch (type) {
24526e91bba0SGirish Moodalbail 	case IPADM_ADDR_IPV6_ADDRCONF:
24536e91bba0SGirish Moodalbail 		newaddr->ipadm_intfidlen = 0;
24546e91bba0SGirish Moodalbail 		newaddr->ipadm_stateful = B_TRUE;
24556e91bba0SGirish Moodalbail 		newaddr->ipadm_stateless = B_TRUE;
24566e91bba0SGirish Moodalbail 		newaddr->ipadm_af = AF_INET6;
24576e91bba0SGirish Moodalbail 		break;
24586e91bba0SGirish Moodalbail 
24596e91bba0SGirish Moodalbail 	case IPADM_ADDR_DHCP:
24606e91bba0SGirish Moodalbail 		newaddr->ipadm_primary = B_FALSE;
24616e91bba0SGirish Moodalbail 		newaddr->ipadm_wait = IPADM_DHCP_WAIT_DEFAULT;
24626e91bba0SGirish Moodalbail 		newaddr->ipadm_af = AF_INET;
24636e91bba0SGirish Moodalbail 		break;
24646e91bba0SGirish Moodalbail 
24658b88711aSGirish Moodalbail 	case IPADM_ADDR_STATIC:
24668b88711aSGirish Moodalbail 		newaddr->ipadm_af = AF_UNSPEC;
24678b88711aSGirish Moodalbail 		newaddr->ipadm_static_prefixlen = 0;
24688b88711aSGirish Moodalbail 		break;
24698b88711aSGirish Moodalbail 
24708b88711aSGirish Moodalbail 	default:
24718b88711aSGirish Moodalbail 		status = IPADM_INVALID_ARG;
24728b88711aSGirish Moodalbail 		goto fail;
24736e91bba0SGirish Moodalbail 	}
24746e91bba0SGirish Moodalbail 	newaddr->ipadm_atype = type;
24756e91bba0SGirish Moodalbail 	*ipaddr = newaddr;
24766e91bba0SGirish Moodalbail 	return (IPADM_SUCCESS);
24776e91bba0SGirish Moodalbail fail:
24786e91bba0SGirish Moodalbail 	free(newaddr);
24796e91bba0SGirish Moodalbail 	return (status);
24806e91bba0SGirish Moodalbail }
24816e91bba0SGirish Moodalbail 
2482f6da83d4SAnurag S. Maskey /*
2483f6da83d4SAnurag S. Maskey  * Returns `aobjname' from the address object in `ipaddr'.
2484f6da83d4SAnurag S. Maskey  */
2485f6da83d4SAnurag S. Maskey ipadm_status_t
ipadm_get_aobjname(const ipadm_addrobj_t ipaddr,char * aobjname,size_t len)2486f6da83d4SAnurag S. Maskey ipadm_get_aobjname(const ipadm_addrobj_t ipaddr, char *aobjname, size_t len)
2487f6da83d4SAnurag S. Maskey {
2488f6da83d4SAnurag S. Maskey 	if (ipaddr == NULL || aobjname == NULL)
2489f6da83d4SAnurag S. Maskey 		return (IPADM_INVALID_ARG);
2490f6da83d4SAnurag S. Maskey 	if (strlcpy(aobjname, ipaddr->ipadm_aobjname, len) >= len)
2491f6da83d4SAnurag S. Maskey 		return (IPADM_INVALID_ARG);
2492f6da83d4SAnurag S. Maskey 
2493f6da83d4SAnurag S. Maskey 	return (IPADM_SUCCESS);
2494f6da83d4SAnurag S. Maskey }
2495f6da83d4SAnurag S. Maskey 
24966e91bba0SGirish Moodalbail /*
24976e91bba0SGirish Moodalbail  * Frees the address object in `ipaddr'.
24986e91bba0SGirish Moodalbail  */
24996e91bba0SGirish Moodalbail void
ipadm_destroy_addrobj(ipadm_addrobj_t ipaddr)25006e91bba0SGirish Moodalbail ipadm_destroy_addrobj(ipadm_addrobj_t ipaddr)
25016e91bba0SGirish Moodalbail {
25026e91bba0SGirish Moodalbail 	free(ipaddr);
25036e91bba0SGirish Moodalbail }
25046e91bba0SGirish Moodalbail 
25056e91bba0SGirish Moodalbail /*
25066e91bba0SGirish Moodalbail  * Retrieves the logical interface name from `ipaddr' and stores the
25076e91bba0SGirish Moodalbail  * string in `lifname'.
25086e91bba0SGirish Moodalbail  */
25096e91bba0SGirish Moodalbail void
i_ipadm_addrobj2lifname(ipadm_addrobj_t ipaddr,char * lifname,int lifnamesize)25106e91bba0SGirish Moodalbail i_ipadm_addrobj2lifname(ipadm_addrobj_t ipaddr, char *lifname, int lifnamesize)
25116e91bba0SGirish Moodalbail {
25126e91bba0SGirish Moodalbail 	if (ipaddr->ipadm_lifnum != 0) {
25136e91bba0SGirish Moodalbail 		(void) snprintf(lifname, lifnamesize, "%s:%d",
25146e91bba0SGirish Moodalbail 		    ipaddr->ipadm_ifname, ipaddr->ipadm_lifnum);
25156e91bba0SGirish Moodalbail 	} else {
25166e91bba0SGirish Moodalbail 		(void) snprintf(lifname, lifnamesize, "%s",
25176e91bba0SGirish Moodalbail 		    ipaddr->ipadm_ifname);
25186e91bba0SGirish Moodalbail 	}
25196e91bba0SGirish Moodalbail }
25206e91bba0SGirish Moodalbail 
25216e91bba0SGirish Moodalbail /*
25226e91bba0SGirish Moodalbail  * Checks if a non-zero static address is present on the 0th logical interface
25236e91bba0SGirish Moodalbail  * of the given IPv4 or IPv6 physical interface. For an IPv4 interface, it
25246e91bba0SGirish Moodalbail  * also checks if the interface is under DHCP control. If the condition is true,
25256e91bba0SGirish Moodalbail  * the output argument `exists' will be set to B_TRUE. Otherwise, `exists'
25266e91bba0SGirish Moodalbail  * is set to B_FALSE.
2527550b6e40SSowmini Varadhan  *
2528550b6e40SSowmini Varadhan  * Note that *exists will not be initialized if an error is encountered.
25296e91bba0SGirish Moodalbail  */
25306e91bba0SGirish 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)25316e91bba0SGirish Moodalbail i_ipadm_addr_exists_on_if(ipadm_handle_t iph, const char *ifname,
25326e91bba0SGirish Moodalbail     sa_family_t af, boolean_t *exists)
25336e91bba0SGirish Moodalbail {
25346e91bba0SGirish Moodalbail 	struct lifreq	lifr;
25356e91bba0SGirish Moodalbail 	int		sock;
25366e91bba0SGirish Moodalbail 
25376e91bba0SGirish Moodalbail 	/* For IPH_LEGACY, a new logical interface will never be added. */
25386e91bba0SGirish Moodalbail 	if (iph->iph_flags & IPH_LEGACY) {
25396e91bba0SGirish Moodalbail 		*exists = B_FALSE;
25406e91bba0SGirish Moodalbail 		return (IPADM_SUCCESS);
25416e91bba0SGirish Moodalbail 	}
25426e91bba0SGirish Moodalbail 	bzero(&lifr, sizeof (lifr));
25436e91bba0SGirish Moodalbail 	(void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
25446e91bba0SGirish Moodalbail 	if (af == AF_INET) {
25456e91bba0SGirish Moodalbail 		sock = iph->iph_sock;
25466e91bba0SGirish Moodalbail 		if (ioctl(sock, SIOCGLIFFLAGS, (caddr_t)&lifr) < 0)
25476e91bba0SGirish Moodalbail 			return (ipadm_errno2status(errno));
25486e91bba0SGirish Moodalbail 		if (lifr.lifr_flags & IFF_DHCPRUNNING) {
25496e91bba0SGirish Moodalbail 			*exists = B_TRUE;
25506e91bba0SGirish Moodalbail 			return (IPADM_SUCCESS);
25516e91bba0SGirish Moodalbail 		}
25526e91bba0SGirish Moodalbail 	} else {
25536e91bba0SGirish Moodalbail 		sock = iph->iph_sock6;
25546e91bba0SGirish Moodalbail 	}
25556e91bba0SGirish Moodalbail 	if (ioctl(sock, SIOCGLIFADDR, (caddr_t)&lifr) < 0)
25566e91bba0SGirish Moodalbail 		return (ipadm_errno2status(errno));
255764639aafSDarren Reed 	*exists = !sockaddrunspec((struct sockaddr *)&lifr.lifr_addr);
25586e91bba0SGirish Moodalbail 
25596e91bba0SGirish Moodalbail 	return (IPADM_SUCCESS);
25606e91bba0SGirish Moodalbail }
25616e91bba0SGirish Moodalbail 
2562ec3706caSVasumathi Sundaram /*
2563ec3706caSVasumathi Sundaram  * Adds a new logical interface in the kernel for interface
2564ec3706caSVasumathi Sundaram  * `addr->ipadm_ifname', if there is a non-zero address on the 0th
2565ec3706caSVasumathi Sundaram  * logical interface or if the 0th logical interface is under DHCP
2566ec3706caSVasumathi Sundaram  * control. On success, it sets the lifnum in the address object `addr'.
2567ec3706caSVasumathi Sundaram  */
2568ec3706caSVasumathi Sundaram ipadm_status_t
i_ipadm_do_addif(ipadm_handle_t iph,ipadm_addrobj_t addr,boolean_t * added)2569c8152f8fSAndy Fiddaman i_ipadm_do_addif(ipadm_handle_t iph, ipadm_addrobj_t addr, boolean_t *added)
2570ec3706caSVasumathi Sundaram {
2571ec3706caSVasumathi Sundaram 	ipadm_status_t	status;
2572ec3706caSVasumathi Sundaram 	boolean_t	addif;
2573ec3706caSVasumathi Sundaram 	struct lifreq	lifr;
2574ec3706caSVasumathi Sundaram 	int		sock;
2575ec3706caSVasumathi Sundaram 
2576ec3706caSVasumathi Sundaram 	status = i_ipadm_addr_exists_on_if(iph, addr->ipadm_ifname,
2577ec3706caSVasumathi Sundaram 	    addr->ipadm_af, &addif);
2578ec3706caSVasumathi Sundaram 	if (status != IPADM_SUCCESS)
2579ec3706caSVasumathi Sundaram 		return (status);
2580ec3706caSVasumathi Sundaram 	if (addif) {
2581ec3706caSVasumathi Sundaram 		/*
2582ec3706caSVasumathi Sundaram 		 * If there is an address on 0th logical interface,
2583ec3706caSVasumathi Sundaram 		 * add a new logical interface.
2584ec3706caSVasumathi Sundaram 		 */
2585ec3706caSVasumathi Sundaram 		bzero(&lifr, sizeof (lifr));
2586ec3706caSVasumathi Sundaram 		(void) strlcpy(lifr.lifr_name, addr->ipadm_ifname,
2587ec3706caSVasumathi Sundaram 		    sizeof (lifr.lifr_name));
2588ec3706caSVasumathi Sundaram 		sock = (addr->ipadm_af == AF_INET ? iph->iph_sock :
2589ec3706caSVasumathi Sundaram 		    iph->iph_sock6);
2590ec3706caSVasumathi Sundaram 		if (ioctl(sock, SIOCLIFADDIF, (caddr_t)&lifr) < 0)
2591ec3706caSVasumathi Sundaram 			return (ipadm_errno2status(errno));
2592ec3706caSVasumathi Sundaram 		addr->ipadm_lifnum = i_ipadm_get_lnum(lifr.lifr_name);
2593c8152f8fSAndy Fiddaman 		if (added != NULL)
2594c8152f8fSAndy Fiddaman 			*added = B_TRUE;
2595c8152f8fSAndy Fiddaman 	} else {
2596c8152f8fSAndy Fiddaman 		/*
2597c8152f8fSAndy Fiddaman 		 * The first logical interface (0) has a zero address, and is
2598c8152f8fSAndy Fiddaman 		 * not under DHCP control, use it.
2599c8152f8fSAndy Fiddaman 		 */
2600c8152f8fSAndy Fiddaman 		addr->ipadm_lifnum = 0;
2601ec3706caSVasumathi Sundaram 	}
2602ec3706caSVasumathi Sundaram 	return (IPADM_SUCCESS);
2603ec3706caSVasumathi Sundaram }
2604ec3706caSVasumathi Sundaram 
26056e91bba0SGirish Moodalbail /*
26066e91bba0SGirish Moodalbail  * Reads all the address lines from the persistent DB into the nvlist `onvl',
26076e91bba0SGirish Moodalbail  * when both `ifname' and `aobjname' are NULL. If an `ifname' is provided,
26086e91bba0SGirish Moodalbail  * it returns all the addresses for the given interface `ifname'.
26096e91bba0SGirish Moodalbail  * If an `aobjname' is specified, then the address line corresponding to
26106e91bba0SGirish Moodalbail  * that name will be returned.
26116e91bba0SGirish Moodalbail  */
26126e91bba0SGirish Moodalbail static ipadm_status_t
i_ipadm_get_db_addr(ipadm_handle_t iph,const char * ifname,const char * aobjname,nvlist_t ** onvl)26136e91bba0SGirish Moodalbail i_ipadm_get_db_addr(ipadm_handle_t iph, const char *ifname,
26146e91bba0SGirish Moodalbail     const char *aobjname, nvlist_t **onvl)
26156e91bba0SGirish Moodalbail {
26166e91bba0SGirish Moodalbail 	ipmgmt_getaddr_arg_t	garg;
26176e91bba0SGirish Moodalbail 
26186e91bba0SGirish Moodalbail 	/* Populate the door_call argument structure */
26196e91bba0SGirish Moodalbail 	bzero(&garg, sizeof (garg));
26206e91bba0SGirish Moodalbail 	garg.ia_cmd = IPMGMT_CMD_GETADDR;
26216e91bba0SGirish Moodalbail 	if (aobjname != NULL)
26226e91bba0SGirish Moodalbail 		(void) strlcpy(garg.ia_aobjname, aobjname,
26236e91bba0SGirish Moodalbail 		    sizeof (garg.ia_aobjname));
26246e91bba0SGirish Moodalbail 	if (ifname != NULL)
26256e91bba0SGirish Moodalbail 		(void) strlcpy(garg.ia_ifname, ifname, sizeof (garg.ia_ifname));
26266e91bba0SGirish Moodalbail 
2627a73be61aSHans Rosenfeld 	return (i_ipadm_call_ipmgmtd(iph, (void *) &garg, sizeof (garg), onvl));
26286e91bba0SGirish Moodalbail }
26296e91bba0SGirish Moodalbail 
26306e91bba0SGirish Moodalbail /*
26316e91bba0SGirish Moodalbail  * Adds the IP address contained in the 'ipaddr' argument to the physical
26326e91bba0SGirish Moodalbail  * interface represented by 'ifname' after doing the required validation.
26336e91bba0SGirish Moodalbail  * If the interface does not exist, it is created before the address is
26346e91bba0SGirish Moodalbail  * added.
26356e91bba0SGirish Moodalbail  *
26366e91bba0SGirish Moodalbail  * If IPH_LEGACY is set in iph_flags, flags has to be IPADM_OPT_ACTIVE
26376e91bba0SGirish Moodalbail  * and a default addrobj name will be generated. Input `addr->ipadm_aobjname',
26386e91bba0SGirish Moodalbail  * if provided, will be ignored and replaced with the newly generated name.
26396e91bba0SGirish Moodalbail  * The interface name provided has to be a logical interface name that
26406e91bba0SGirish Moodalbail  * already exists. No new logical interface will be added in this function.
2641f6da83d4SAnurag S. Maskey  *
2642f6da83d4SAnurag S. Maskey  * If IPADM_OPT_V46 is passed in the flags, then both IPv4 and IPv6 interfaces
2643f6da83d4SAnurag S. Maskey  * are plumbed (if they haven't been already).  Otherwise, just the interface
2644f6da83d4SAnurag S. Maskey  * specified in `addr' is plumbed.
26456e91bba0SGirish Moodalbail  */
26466e91bba0SGirish Moodalbail ipadm_status_t
ipadm_create_addr(ipadm_handle_t iph,ipadm_addrobj_t addr,uint32_t flags)26476e91bba0SGirish Moodalbail ipadm_create_addr(ipadm_handle_t iph, ipadm_addrobj_t addr, uint32_t flags)
26486e91bba0SGirish Moodalbail {
26496e91bba0SGirish Moodalbail 	ipadm_status_t		status;
26506e91bba0SGirish Moodalbail 	sa_family_t		af;
26516e91bba0SGirish Moodalbail 	sa_family_t		daf;
26526e91bba0SGirish Moodalbail 	sa_family_t		other_af;
26536e91bba0SGirish Moodalbail 	boolean_t		created_af = B_FALSE;
26546e91bba0SGirish Moodalbail 	boolean_t		created_other_af = B_FALSE;
26556e91bba0SGirish Moodalbail 	ipadm_addr_type_t	type;
26566e91bba0SGirish Moodalbail 	char			*ifname = addr->ipadm_ifname;
26576e91bba0SGirish Moodalbail 	boolean_t		legacy = (iph->iph_flags & IPH_LEGACY);
2658c8152f8fSAndy Fiddaman 	boolean_t		aobjfound = B_FALSE;
26596e91bba0SGirish Moodalbail 	boolean_t		is_6to4;
26606e91bba0SGirish Moodalbail 	struct lifreq		lifr;
26616e91bba0SGirish Moodalbail 	uint64_t		ifflags;
2662550b6e40SSowmini Varadhan 	boolean_t		is_boot = (iph->iph_flags & IPH_IPMGMTD);
2663a73be61aSHans Rosenfeld 	boolean_t		is_ipmp;
2664a73be61aSHans Rosenfeld 	char			gifname[LIFGRNAMSIZ];
26656e91bba0SGirish Moodalbail 
26666e91bba0SGirish Moodalbail 	/* check for solaris.network.interface.config authorization */
26676e91bba0SGirish Moodalbail 	if (!ipadm_check_auth())
26686e91bba0SGirish Moodalbail 		return (IPADM_EAUTH);
26696e91bba0SGirish Moodalbail 
26706e91bba0SGirish Moodalbail 	/* Validate the addrobj. This also fills in addr->ipadm_ifname. */
26716e91bba0SGirish Moodalbail 	status = i_ipadm_validate_create_addr(iph, addr, flags);
26726e91bba0SGirish Moodalbail 	if (status != IPADM_SUCCESS)
26736e91bba0SGirish Moodalbail 		return (status);
26746e91bba0SGirish Moodalbail 	/*
26756e91bba0SGirish Moodalbail 	 * For Legacy case, check if an addrobj already exists for the
26766e91bba0SGirish Moodalbail 	 * given logical interface name. If one does not exist,
26776e91bba0SGirish Moodalbail 	 * a default name will be generated and added to the daemon's
26786e91bba0SGirish Moodalbail 	 * aobjmap.
26796e91bba0SGirish Moodalbail 	 */
26806e91bba0SGirish Moodalbail 	if (legacy) {
26816e91bba0SGirish Moodalbail 		struct ipadm_addrobj_s	ipaddr;
26826e91bba0SGirish Moodalbail 
26836e91bba0SGirish Moodalbail 		ipaddr = *addr;
26846e91bba0SGirish Moodalbail 		status = i_ipadm_get_lif2addrobj(iph, &ipaddr);
26856e91bba0SGirish Moodalbail 		if (status == IPADM_SUCCESS) {
26866e91bba0SGirish Moodalbail 			aobjfound = B_TRUE;
26876e91bba0SGirish Moodalbail 			/*
26886e91bba0SGirish Moodalbail 			 * With IPH_LEGACY, modifying an address that is not
26896e91bba0SGirish Moodalbail 			 * a static address will return with an error.
26906e91bba0SGirish Moodalbail 			 */
26916e91bba0SGirish Moodalbail 			if (ipaddr.ipadm_atype != IPADM_ADDR_STATIC)
26926e91bba0SGirish Moodalbail 				return (IPADM_NOTSUP);
26936e91bba0SGirish Moodalbail 			/*
26946e91bba0SGirish Moodalbail 			 * we found the addrobj in daemon, copy over the
26956e91bba0SGirish Moodalbail 			 * aobjname to `addr'.
26966e91bba0SGirish Moodalbail 			 */
26976e91bba0SGirish Moodalbail 			(void) strlcpy(addr->ipadm_aobjname,
26986e91bba0SGirish Moodalbail 			    ipaddr.ipadm_aobjname, IPADM_AOBJSIZ);
26996e91bba0SGirish Moodalbail 		} else if (status == IPADM_NOTFOUND) {
27006e91bba0SGirish Moodalbail 			aobjfound = B_FALSE;
27016e91bba0SGirish Moodalbail 		} else {
27026e91bba0SGirish Moodalbail 			return (status);
27036e91bba0SGirish Moodalbail 		}
27046e91bba0SGirish Moodalbail 	}
27056e91bba0SGirish Moodalbail 
27066e91bba0SGirish Moodalbail 	af = addr->ipadm_af;
27076e91bba0SGirish Moodalbail 	/*
27086e91bba0SGirish Moodalbail 	 * Create a placeholder for this address object in the daemon.
2709550b6e40SSowmini Varadhan 	 * Skip this step if we are booting a zone (and therefore being called
2710550b6e40SSowmini Varadhan 	 * from ipmgmtd itself), and, for IPH_LEGACY case if the
2711550b6e40SSowmini Varadhan 	 * addrobj already exists.
2712550b6e40SSowmini Varadhan 	 *
2713550b6e40SSowmini Varadhan 	 * Note that the placeholder is not needed in the NGZ boot case,
2714550b6e40SSowmini Varadhan 	 * when zoneadmd has itself applied the "allowed-ips" property to clamp
2715550b6e40SSowmini Varadhan 	 * down any interface configuration, so the namespace for the interface
2716550b6e40SSowmini Varadhan 	 * is fully controlled by the GZ.
27176e91bba0SGirish Moodalbail 	 */
2718550b6e40SSowmini Varadhan 	if (!is_boot && (!legacy || !aobjfound)) {
27196e91bba0SGirish Moodalbail 		status = i_ipadm_lookupadd_addrobj(iph, addr);
27206e91bba0SGirish Moodalbail 		if (status != IPADM_SUCCESS)
27216e91bba0SGirish Moodalbail 			return (status);
27226e91bba0SGirish Moodalbail 	}
27236e91bba0SGirish Moodalbail 
27246e91bba0SGirish Moodalbail 	is_6to4 = i_ipadm_is_6to4(iph, ifname);
27256e91bba0SGirish Moodalbail 	/* Plumb the IP interfaces if necessary */
27266e91bba0SGirish Moodalbail 	status = i_ipadm_create_if(iph, ifname, af, flags);
27276e91bba0SGirish Moodalbail 	if (status != IPADM_SUCCESS && status != IPADM_IF_EXISTS) {
27286e91bba0SGirish Moodalbail 		(void) i_ipadm_delete_addrobj(iph, addr, IPADM_OPT_ACTIVE);
27296e91bba0SGirish Moodalbail 		return (status);
27306e91bba0SGirish Moodalbail 	}
27316e91bba0SGirish Moodalbail 	if (status == IPADM_SUCCESS)
27326e91bba0SGirish Moodalbail 		created_af = B_TRUE;
2733f6da83d4SAnurag S. Maskey 	if (!is_6to4 && !legacy && (flags & IPADM_OPT_V46)) {
27346e91bba0SGirish Moodalbail 		other_af = (af == AF_INET ? AF_INET6 : AF_INET);
27356e91bba0SGirish Moodalbail 		status = i_ipadm_create_if(iph, ifname, other_af, flags);
27366e91bba0SGirish Moodalbail 		if (status != IPADM_SUCCESS && status != IPADM_IF_EXISTS) {
27376e91bba0SGirish Moodalbail 			(void) i_ipadm_delete_if(iph, ifname, af, flags);
27386e91bba0SGirish Moodalbail 			return (status);
27396e91bba0SGirish Moodalbail 		}
27406e91bba0SGirish Moodalbail 		if (status == IPADM_SUCCESS)
27416e91bba0SGirish Moodalbail 			created_other_af = B_TRUE;
27426e91bba0SGirish Moodalbail 	}
27436e91bba0SGirish Moodalbail 
2744550b6e40SSowmini Varadhan 	/*
2745550b6e40SSowmini Varadhan 	 * Some input validation based on the interface flags:
2746550b6e40SSowmini Varadhan 	 * 1. in non-global zones, make sure that we are not persistently
2747550b6e40SSowmini Varadhan 	 *    creating addresses on interfaces that are acquiring
2748550b6e40SSowmini Varadhan 	 *    address from the global zone.
2749550b6e40SSowmini Varadhan 	 * 2. Validate static addresses for IFF_POINTOPOINT interfaces.
2750550b6e40SSowmini Varadhan 	 */
27516e91bba0SGirish Moodalbail 	if (addr->ipadm_atype == IPADM_ADDR_STATIC) {
27526e91bba0SGirish Moodalbail 		status = i_ipadm_get_flags(iph, ifname, af, &ifflags);
27536e91bba0SGirish Moodalbail 		if (status != IPADM_SUCCESS)
27546e91bba0SGirish Moodalbail 			goto fail;
2755550b6e40SSowmini Varadhan 
2756550b6e40SSowmini Varadhan 		if (iph->iph_zoneid != GLOBAL_ZONEID &&
2757550b6e40SSowmini Varadhan 		    (ifflags & IFF_L3PROTECT) && (flags & IPADM_OPT_PERSIST)) {
2758550b6e40SSowmini Varadhan 			status = IPADM_GZ_PERM;
2759550b6e40SSowmini Varadhan 			goto fail;
2760550b6e40SSowmini Varadhan 		}
27616e91bba0SGirish Moodalbail 		daf = addr->ipadm_static_dst_addr.ss_family;
27626e91bba0SGirish Moodalbail 		if (ifflags & IFF_POINTOPOINT) {
27636e91bba0SGirish Moodalbail 			if (is_6to4) {
27646e91bba0SGirish Moodalbail 				if (af != AF_INET6 || daf != AF_UNSPEC) {
27656e91bba0SGirish Moodalbail 					status = IPADM_INVALID_ARG;
27666e91bba0SGirish Moodalbail 					goto fail;
27676e91bba0SGirish Moodalbail 				}
27686e91bba0SGirish Moodalbail 			} else {
27696e91bba0SGirish Moodalbail 				if (daf != af) {
27706e91bba0SGirish Moodalbail 					status = IPADM_INVALID_ARG;
27716e91bba0SGirish Moodalbail 					goto fail;
27726e91bba0SGirish Moodalbail 				}
27736e91bba0SGirish Moodalbail 				/* Check for a valid dst address. */
27746e91bba0SGirish Moodalbail 				if (!legacy && sockaddrunspec(
277564639aafSDarren Reed 				    (struct sockaddr *)
27766e91bba0SGirish Moodalbail 				    &addr->ipadm_static_dst_addr)) {
27776e91bba0SGirish Moodalbail 					status = IPADM_BAD_ADDR;
27786e91bba0SGirish Moodalbail 					goto fail;
27796e91bba0SGirish Moodalbail 				}
27806e91bba0SGirish Moodalbail 			}
27816e91bba0SGirish Moodalbail 		} else {
27826e91bba0SGirish Moodalbail 			/*
27836e91bba0SGirish Moodalbail 			 * Disallow setting of dstaddr when the link is not
27846e91bba0SGirish Moodalbail 			 * a point-to-point link.
27856e91bba0SGirish Moodalbail 			 */
27866e91bba0SGirish Moodalbail 			if (daf != AF_UNSPEC)
27876e91bba0SGirish Moodalbail 				return (IPADM_INVALID_ARG);
27886e91bba0SGirish Moodalbail 		}
27896e91bba0SGirish Moodalbail 	}
27906e91bba0SGirish Moodalbail 
27916e91bba0SGirish Moodalbail 	/*
27926e91bba0SGirish Moodalbail 	 * For 6to4 interfaces, kernel configures a default link-local
27936e91bba0SGirish Moodalbail 	 * address. We need to replace it, if the caller has provided
27946e91bba0SGirish Moodalbail 	 * an address that is different from the default link-local.
27956e91bba0SGirish Moodalbail 	 */
27966e91bba0SGirish Moodalbail 	if (status == IPADM_SUCCESS && is_6to4) {
27976e91bba0SGirish Moodalbail 		bzero(&lifr, sizeof (lifr));
27986e91bba0SGirish Moodalbail 		(void) strlcpy(lifr.lifr_name, addr->ipadm_ifname,
27996e91bba0SGirish Moodalbail 		    sizeof (lifr.lifr_name));
28006e91bba0SGirish Moodalbail 		if (ioctl(iph->iph_sock6, SIOCGLIFADDR, &lifr) < 0) {
28016e91bba0SGirish Moodalbail 			status = ipadm_errno2status(errno);
28026e91bba0SGirish Moodalbail 			goto fail;
28036e91bba0SGirish Moodalbail 		}
28046e91bba0SGirish Moodalbail 		if (sockaddrcmp(&lifr.lifr_addr, &addr->ipadm_static_addr))
28056e91bba0SGirish Moodalbail 			return (IPADM_SUCCESS);
28066e91bba0SGirish Moodalbail 	}
28076e91bba0SGirish Moodalbail 
2808a73be61aSHans Rosenfeld 	/*
2809a73be61aSHans Rosenfeld 	 * If interface is an IPMP group member, move it out of the group before
2810a73be61aSHans Rosenfeld 	 * performing any operations on it.
2811a73be61aSHans Rosenfeld 	 */
2812a73be61aSHans Rosenfeld 	if ((is_ipmp = i_ipadm_is_under_ipmp(iph, addr->ipadm_ifname))) {
2813a73be61aSHans Rosenfeld 		(void) i_ipadm_get_groupname_active(iph, addr->ipadm_ifname,
2814a73be61aSHans Rosenfeld 		    gifname, sizeof (gifname));
2815a73be61aSHans Rosenfeld 		(void) i_ipadm_set_groupname_active(iph, addr->ipadm_ifname,
2816a73be61aSHans Rosenfeld 		    "");
2817a73be61aSHans Rosenfeld 	}
2818a73be61aSHans Rosenfeld 
28196e91bba0SGirish Moodalbail 	/* Create the address. */
28206e91bba0SGirish Moodalbail 	type = addr->ipadm_atype;
28216e91bba0SGirish Moodalbail 	switch (type) {
28226e91bba0SGirish Moodalbail 	case IPADM_ADDR_STATIC:
28236e91bba0SGirish Moodalbail 		status = i_ipadm_create_addr(iph, addr, flags);
28246e91bba0SGirish Moodalbail 		break;
28256e91bba0SGirish Moodalbail 	case IPADM_ADDR_DHCP:
28266e91bba0SGirish Moodalbail 		status = i_ipadm_create_dhcp(iph, addr, flags);
28276e91bba0SGirish Moodalbail 		break;
28286e91bba0SGirish Moodalbail 	case IPADM_ADDR_IPV6_ADDRCONF:
28296e91bba0SGirish Moodalbail 		status = i_ipadm_create_ipv6addrs(iph, addr, flags);
28306e91bba0SGirish Moodalbail 		break;
28316e91bba0SGirish Moodalbail 	default:
28326e91bba0SGirish Moodalbail 		status = IPADM_INVALID_ARG;
28336e91bba0SGirish Moodalbail 		break;
28346e91bba0SGirish Moodalbail 	}
28356e91bba0SGirish Moodalbail 
2836a73be61aSHans Rosenfeld 	/* Move the underlying IPMP interface back to the group */
2837a73be61aSHans Rosenfeld 	if (is_ipmp) {
2838a73be61aSHans Rosenfeld 		(void) i_ipadm_set_groupname_active(iph, addr->ipadm_ifname,
2839a73be61aSHans Rosenfeld 		    gifname);
2840a73be61aSHans Rosenfeld 	}
2841a73be61aSHans Rosenfeld 
28426e91bba0SGirish Moodalbail 	/*
28436e91bba0SGirish Moodalbail 	 * If address was not created successfully, unplumb the interface
28446e91bba0SGirish Moodalbail 	 * if it was plumbed implicitly in this function and remove the
28456e91bba0SGirish Moodalbail 	 * addrobj created by the ipmgmtd daemon as a placeholder.
28466e91bba0SGirish Moodalbail 	 * If IPH_LEGACY is set, then remove the addrobj only if it was
28476e91bba0SGirish Moodalbail 	 * created in this function.
28486e91bba0SGirish Moodalbail 	 */
28496e91bba0SGirish Moodalbail fail:
28506e91bba0SGirish Moodalbail 	if (status != IPADM_DHCP_IPC_TIMEOUT &&
28516e91bba0SGirish Moodalbail 	    status != IPADM_SUCCESS) {
28526e91bba0SGirish Moodalbail 		if (!legacy) {
28536e91bba0SGirish Moodalbail 			if (created_af || created_other_af) {
28546e91bba0SGirish Moodalbail 				if (created_af) {
28556e91bba0SGirish Moodalbail 					(void) i_ipadm_delete_if(iph, ifname,
28566e91bba0SGirish Moodalbail 					    af, flags);
28576e91bba0SGirish Moodalbail 				}
28586e91bba0SGirish Moodalbail 				if (created_other_af) {
28596e91bba0SGirish Moodalbail 					(void) i_ipadm_delete_if(iph, ifname,
28606e91bba0SGirish Moodalbail 					    other_af, flags);
28616e91bba0SGirish Moodalbail 				}
28626e91bba0SGirish Moodalbail 			} else {
28636e91bba0SGirish Moodalbail 				(void) i_ipadm_delete_addrobj(iph, addr, flags);
28646e91bba0SGirish Moodalbail 			}
28656e91bba0SGirish Moodalbail 		} else if (!aobjfound) {
28666e91bba0SGirish Moodalbail 			(void) i_ipadm_delete_addrobj(iph, addr, flags);
28676e91bba0SGirish Moodalbail 		}
28686e91bba0SGirish Moodalbail 	}
28696e91bba0SGirish Moodalbail 
28706e91bba0SGirish Moodalbail 	return (status);
28716e91bba0SGirish Moodalbail }
28726e91bba0SGirish Moodalbail 
28736e91bba0SGirish Moodalbail /*
28746e91bba0SGirish Moodalbail  * Creates the static address in `ipaddr' in kernel. After successfully
28756e91bba0SGirish Moodalbail  * creating it, it updates the ipmgmtd daemon's aobjmap with the logical
28766e91bba0SGirish Moodalbail  * interface information.
28776e91bba0SGirish Moodalbail  */
28786e91bba0SGirish Moodalbail static ipadm_status_t
i_ipadm_create_addr(ipadm_handle_t iph,ipadm_addrobj_t ipaddr,uint32_t flags)28796e91bba0SGirish Moodalbail i_ipadm_create_addr(ipadm_handle_t iph, ipadm_addrobj_t ipaddr, uint32_t flags)
28806e91bba0SGirish Moodalbail {
28816e91bba0SGirish Moodalbail 	struct lifreq			lifr;
28826e91bba0SGirish Moodalbail 	ipadm_status_t			status = IPADM_SUCCESS;
28836e91bba0SGirish Moodalbail 	int				sock;
28846e91bba0SGirish Moodalbail 	struct sockaddr_storage		m, *mask = &m;
28856e91bba0SGirish Moodalbail 	const struct sockaddr_storage	*addr = &ipaddr->ipadm_static_addr;
28866e91bba0SGirish Moodalbail 	const struct sockaddr_storage	*daddr = &ipaddr->ipadm_static_dst_addr;
28876e91bba0SGirish Moodalbail 	sa_family_t			af;
28886e91bba0SGirish Moodalbail 	boolean_t			legacy = (iph->iph_flags & IPH_LEGACY);
28896e91bba0SGirish Moodalbail 	struct ipadm_addrobj_s		legacy_addr;
28906e91bba0SGirish Moodalbail 	boolean_t			default_prefixlen = B_FALSE;
2891550b6e40SSowmini Varadhan 	boolean_t			is_boot;
28926e91bba0SGirish Moodalbail 
2893550b6e40SSowmini Varadhan 	is_boot = ((iph->iph_flags & IPH_IPMGMTD) != 0);
28946e91bba0SGirish Moodalbail 	af = ipaddr->ipadm_af;
28956e91bba0SGirish Moodalbail 	sock = (af == AF_INET ? iph->iph_sock : iph->iph_sock6);
28966e91bba0SGirish Moodalbail 
28976e91bba0SGirish Moodalbail 	/* If prefixlen was not provided, get default prefixlen */
28986e91bba0SGirish Moodalbail 	if (ipaddr->ipadm_static_prefixlen == 0) {
28996e91bba0SGirish Moodalbail 		/* prefixlen was not provided, get default prefixlen */
29006e91bba0SGirish Moodalbail 		status = i_ipadm_get_default_prefixlen(
29016e91bba0SGirish Moodalbail 		    &ipaddr->ipadm_static_addr,
29026e91bba0SGirish Moodalbail 		    &ipaddr->ipadm_static_prefixlen);
29036e91bba0SGirish Moodalbail 		if (status != IPADM_SUCCESS)
29046e91bba0SGirish Moodalbail 			return (status);
29056e91bba0SGirish Moodalbail 		default_prefixlen = B_TRUE;
29066e91bba0SGirish Moodalbail 	}
290764639aafSDarren Reed 	(void) plen2mask(ipaddr->ipadm_static_prefixlen, af,
290864639aafSDarren Reed 	    (struct sockaddr *)mask);
29096e91bba0SGirish Moodalbail 
29106e91bba0SGirish Moodalbail 	/*
2911ec3706caSVasumathi Sundaram 	 * Create a new logical interface if needed; otherwise, just
2912ec3706caSVasumathi Sundaram 	 * use the 0th logical interface.
29136e91bba0SGirish Moodalbail 	 */
2914ec3706caSVasumathi Sundaram 	if (!(iph->iph_flags & IPH_LEGACY)) {
2915c8152f8fSAndy Fiddaman 		status = i_ipadm_do_addif(iph, ipaddr, NULL);
2916ec3706caSVasumathi Sundaram 		if (status != IPADM_SUCCESS)
2917ec3706caSVasumathi Sundaram 			return (status);
29186e91bba0SGirish Moodalbail 	}
29196e91bba0SGirish Moodalbail 	i_ipadm_addrobj2lifname(ipaddr, lifr.lifr_name,
29206e91bba0SGirish Moodalbail 	    sizeof (lifr.lifr_name));
29216e91bba0SGirish Moodalbail 	lifr.lifr_addr = *mask;
29226e91bba0SGirish Moodalbail 	if (ioctl(sock, SIOCSLIFNETMASK, (caddr_t)&lifr) < 0) {
29236e91bba0SGirish Moodalbail 		status = ipadm_errno2status(errno);
29246e91bba0SGirish Moodalbail 		goto ret;
29256e91bba0SGirish Moodalbail 	}
29266e91bba0SGirish Moodalbail 	lifr.lifr_addr = *addr;
29276e91bba0SGirish Moodalbail 	if (ioctl(sock, SIOCSLIFADDR, (caddr_t)&lifr) < 0) {
29286e91bba0SGirish Moodalbail 		status = ipadm_errno2status(errno);
29296e91bba0SGirish Moodalbail 		goto ret;
29306e91bba0SGirish Moodalbail 	}
29316e91bba0SGirish Moodalbail 	/* Set the destination address, if one is given. */
29326e91bba0SGirish Moodalbail 	if (daddr->ss_family != AF_UNSPEC) {
29336e91bba0SGirish Moodalbail 		lifr.lifr_addr = *daddr;
29346e91bba0SGirish Moodalbail 		if (ioctl(sock, SIOCSLIFDSTADDR, (caddr_t)&lifr) < 0) {
29356e91bba0SGirish Moodalbail 			status = ipadm_errno2status(errno);
29366e91bba0SGirish Moodalbail 			goto ret;
29376e91bba0SGirish Moodalbail 		}
29386e91bba0SGirish Moodalbail 	}
29396e91bba0SGirish Moodalbail 
29406e91bba0SGirish Moodalbail 	if (flags & IPADM_OPT_UP) {
2941a73be61aSHans Rosenfeld 		uint32_t	iff_flags = IFF_UP;
2942a73be61aSHans Rosenfeld 
2943a73be61aSHans Rosenfeld 		/*
2944a73be61aSHans Rosenfeld 		 * Set the NOFAILOVER flag only on underlying IPMP interface
2945a73be61aSHans Rosenfeld 		 * and not the IPMP group interface itself.
2946a73be61aSHans Rosenfeld 		 */
2947a73be61aSHans Rosenfeld 		if (i_ipadm_is_under_ipmp(iph, lifr.lifr_name) &&
2948a73be61aSHans Rosenfeld 		    !i_ipadm_is_ipmp(iph, lifr.lifr_name))
2949a73be61aSHans Rosenfeld 			iff_flags |= IFF_NOFAILOVER;
2950a73be61aSHans Rosenfeld 
2951a73be61aSHans Rosenfeld 		status = i_ipadm_set_flags(iph, lifr.lifr_name,
2952a73be61aSHans Rosenfeld 		    af, iff_flags, 0);
29536e91bba0SGirish Moodalbail 
29546e91bba0SGirish Moodalbail 		/*
29556e91bba0SGirish Moodalbail 		 * IPADM_DAD_FOUND is a soft-error for create-addr.
29566e91bba0SGirish Moodalbail 		 * No need to tear down the address.
29576e91bba0SGirish Moodalbail 		 */
29586e91bba0SGirish Moodalbail 		if (status == IPADM_DAD_FOUND)
29596e91bba0SGirish Moodalbail 			status = IPADM_SUCCESS;
29606e91bba0SGirish Moodalbail 	}
29616e91bba0SGirish Moodalbail 
2962550b6e40SSowmini Varadhan 	if (status == IPADM_SUCCESS && !is_boot) {
29636e91bba0SGirish Moodalbail 		/*
29646e91bba0SGirish Moodalbail 		 * For IPH_LEGACY, we might be modifying the address on
29656e91bba0SGirish Moodalbail 		 * an address object that already exists e.g. by doing
29666e91bba0SGirish Moodalbail 		 * "ifconfig bge0:1 <addr>; ifconfig bge0:1 <newaddr>"
29676e91bba0SGirish Moodalbail 		 * So, we need to store the object only if it does not
29686e91bba0SGirish Moodalbail 		 * already exist in ipmgmtd.
29696e91bba0SGirish Moodalbail 		 */
29706e91bba0SGirish Moodalbail 		if (legacy) {
29716e91bba0SGirish Moodalbail 			bzero(&legacy_addr, sizeof (legacy_addr));
29726e91bba0SGirish Moodalbail 			(void) strlcpy(legacy_addr.ipadm_aobjname,
29736e91bba0SGirish Moodalbail 			    ipaddr->ipadm_aobjname,
29746e91bba0SGirish Moodalbail 			    sizeof (legacy_addr.ipadm_aobjname));
29756e91bba0SGirish Moodalbail 			status = i_ipadm_get_addrobj(iph, &legacy_addr);
29766e91bba0SGirish Moodalbail 			if (status == IPADM_SUCCESS &&
29776e91bba0SGirish Moodalbail 			    legacy_addr.ipadm_lifnum >= 0) {
29786e91bba0SGirish Moodalbail 				return (status);
29796e91bba0SGirish Moodalbail 			}
29806e91bba0SGirish Moodalbail 		}
29816e91bba0SGirish Moodalbail 		status = i_ipadm_addr_persist(iph, ipaddr, default_prefixlen,
2982b31320a7SChris Fraire 		    flags, NULL);
29836e91bba0SGirish Moodalbail 	}
29846e91bba0SGirish Moodalbail ret:
29856e91bba0SGirish Moodalbail 	if (status != IPADM_SUCCESS && !legacy)
29866e91bba0SGirish Moodalbail 		(void) i_ipadm_delete_addr(iph, ipaddr);
2987a73be61aSHans Rosenfeld 
29886e91bba0SGirish Moodalbail 	return (status);
29896e91bba0SGirish Moodalbail }
29906e91bba0SGirish Moodalbail 
29916e91bba0SGirish Moodalbail /*
29926e91bba0SGirish Moodalbail  * Removes the address object identified by `aobjname' from both active and
29936e91bba0SGirish Moodalbail  * persistent configuration. The address object will be removed from only
29946e91bba0SGirish Moodalbail  * active configuration if IPH_LEGACY is set in `iph->iph_flags'.
29956e91bba0SGirish Moodalbail  *
29966e91bba0SGirish Moodalbail  * If the address type is IPADM_ADDR_STATIC or IPADM_ADDR_DHCP, the address
29976e91bba0SGirish Moodalbail  * in the address object will be removed from the physical interface.
29986e91bba0SGirish Moodalbail  * If the address type is IPADM_ADDR_DHCP, the flag IPADM_OPT_RELEASE specifies
29996e91bba0SGirish Moodalbail  * whether the lease should be released. If IPADM_OPT_RELEASE is not
3000f6da83d4SAnurag S. Maskey  * specified, the lease will be dropped. This option is not supported
30016e91bba0SGirish Moodalbail  * for other address types.
30026e91bba0SGirish Moodalbail  *
30036e91bba0SGirish Moodalbail  * If the address type is IPADM_ADDR_IPV6_ADDRCONF, the link-local address and
30046e91bba0SGirish Moodalbail  * all the autoconfigured addresses will be removed.
30056e91bba0SGirish Moodalbail  * Finally, the address object is also removed from ipmgmtd's aobjmap and from
30066e91bba0SGirish Moodalbail  * the persistent DB.
30076e91bba0SGirish Moodalbail  */
30086e91bba0SGirish Moodalbail ipadm_status_t
ipadm_delete_addr(ipadm_handle_t iph,const char * aobjname,uint32_t flags)30096e91bba0SGirish Moodalbail ipadm_delete_addr(ipadm_handle_t iph, const char *aobjname, uint32_t flags)
30106e91bba0SGirish Moodalbail {
30116e91bba0SGirish Moodalbail 	ipadm_status_t		status;
30126e91bba0SGirish Moodalbail 	struct ipadm_addrobj_s	ipaddr;
30136e91bba0SGirish Moodalbail 	boolean_t		release = ((flags & IPADM_OPT_RELEASE) != 0);
3014a73be61aSHans Rosenfeld 	boolean_t		is_ipmp = B_FALSE;
3015a73be61aSHans Rosenfeld 	char			gifname[LIFGRNAMSIZ];
30166e91bba0SGirish Moodalbail 
30176e91bba0SGirish Moodalbail 	/* check for solaris.network.interface.config authorization */
30186e91bba0SGirish Moodalbail 	if (!ipadm_check_auth())
30196e91bba0SGirish Moodalbail 		return (IPADM_EAUTH);
30206e91bba0SGirish Moodalbail 
30216e91bba0SGirish Moodalbail 	/* validate input */
30226e91bba0SGirish Moodalbail 	if (flags == 0 || ((flags & IPADM_OPT_PERSIST) &&
30236e91bba0SGirish Moodalbail 	    !(flags & IPADM_OPT_ACTIVE)) ||
30246e91bba0SGirish Moodalbail 	    (flags & ~(IPADM_COMMON_OPT_MASK|IPADM_OPT_RELEASE))) {
30256e91bba0SGirish Moodalbail 		return (IPADM_INVALID_ARG);
30266e91bba0SGirish Moodalbail 	}
30276e91bba0SGirish Moodalbail 	bzero(&ipaddr, sizeof (ipaddr));
30286e91bba0SGirish Moodalbail 	if (aobjname == NULL || strlcpy(ipaddr.ipadm_aobjname, aobjname,
30296e91bba0SGirish Moodalbail 	    IPADM_AOBJSIZ) >= IPADM_AOBJSIZ) {
30306e91bba0SGirish Moodalbail 		return (IPADM_INVALID_ARG);
30316e91bba0SGirish Moodalbail 	}
30326e91bba0SGirish Moodalbail 
30336e91bba0SGirish Moodalbail 	/* Retrieve the address object information from ipmgmtd. */
30346e91bba0SGirish Moodalbail 	status = i_ipadm_get_addrobj(iph, &ipaddr);
30356e91bba0SGirish Moodalbail 	if (status != IPADM_SUCCESS)
30366e91bba0SGirish Moodalbail 		return (status);
30376e91bba0SGirish Moodalbail 
30386e91bba0SGirish Moodalbail 	if (release && ipaddr.ipadm_atype != IPADM_ADDR_DHCP)
30396e91bba0SGirish Moodalbail 		return (IPADM_NOTSUP);
30406e91bba0SGirish Moodalbail 	/*
30416e91bba0SGirish Moodalbail 	 * If requested to delete just from active config but the address
30426e91bba0SGirish Moodalbail 	 * is not in active config, return error.
30436e91bba0SGirish Moodalbail 	 */
30446e91bba0SGirish Moodalbail 	if (!(ipaddr.ipadm_flags & IPMGMT_ACTIVE) &&
30456e91bba0SGirish Moodalbail 	    (flags & IPADM_OPT_ACTIVE) && !(flags & IPADM_OPT_PERSIST)) {
30466e91bba0SGirish Moodalbail 		return (IPADM_NOTFOUND);
30476e91bba0SGirish Moodalbail 	}
30486e91bba0SGirish Moodalbail 
30496e91bba0SGirish Moodalbail 	/*
30506e91bba0SGirish Moodalbail 	 * If address is present in active config, remove it from
30516e91bba0SGirish Moodalbail 	 * kernel.
30526e91bba0SGirish Moodalbail 	 */
30536e91bba0SGirish Moodalbail 	if (ipaddr.ipadm_flags & IPMGMT_ACTIVE) {
3054a73be61aSHans Rosenfeld 
3055a73be61aSHans Rosenfeld 		/*
3056a73be61aSHans Rosenfeld 		 * If interface is an IPMP group member, move it out of the
3057a73be61aSHans Rosenfeld 		 * group before performing any operations on it.
3058a73be61aSHans Rosenfeld 		 */
3059a73be61aSHans Rosenfeld 		if ((is_ipmp = i_ipadm_is_under_ipmp(iph,
3060a73be61aSHans Rosenfeld 		    ipaddr.ipadm_ifname))) {
3061a73be61aSHans Rosenfeld 			(void) i_ipadm_get_groupname_active(iph,
3062a73be61aSHans Rosenfeld 			    ipaddr.ipadm_ifname, gifname, sizeof (gifname));
3063a73be61aSHans Rosenfeld 			(void) i_ipadm_set_groupname_active(iph,
3064a73be61aSHans Rosenfeld 			    ipaddr.ipadm_ifname, "");
3065a73be61aSHans Rosenfeld 		}
3066a73be61aSHans Rosenfeld 
30676e91bba0SGirish Moodalbail 		switch (ipaddr.ipadm_atype) {
30686e91bba0SGirish Moodalbail 		case IPADM_ADDR_STATIC:
30696e91bba0SGirish Moodalbail 			status = i_ipadm_delete_addr(iph, &ipaddr);
30706e91bba0SGirish Moodalbail 			break;
30716e91bba0SGirish Moodalbail 		case IPADM_ADDR_DHCP:
30726e91bba0SGirish Moodalbail 			status = i_ipadm_delete_dhcp(iph, &ipaddr, release);
30736e91bba0SGirish Moodalbail 			break;
30746e91bba0SGirish Moodalbail 		case IPADM_ADDR_IPV6_ADDRCONF:
30756e91bba0SGirish Moodalbail 			status = i_ipadm_delete_ipv6addrs(iph, &ipaddr);
30766e91bba0SGirish Moodalbail 			break;
30776e91bba0SGirish Moodalbail 		default:
30786e91bba0SGirish Moodalbail 			/*
30796e91bba0SGirish Moodalbail 			 * This is the case of address object name residing in
30806e91bba0SGirish Moodalbail 			 * daemon's aobjmap (added by ADDROBJ_LOOKUPADD). Fall
30816e91bba0SGirish Moodalbail 			 * through and delete that address object.
30826e91bba0SGirish Moodalbail 			 */
30836e91bba0SGirish Moodalbail 			break;
30846e91bba0SGirish Moodalbail 		}
30856e91bba0SGirish Moodalbail 
30866e91bba0SGirish Moodalbail 		/*
30876e91bba0SGirish Moodalbail 		 * If the address was previously deleted from the active
30886e91bba0SGirish Moodalbail 		 * config, we will get a IPADM_ENXIO from kernel.
30896e91bba0SGirish Moodalbail 		 * We will still proceed and purge the address information
30906e91bba0SGirish Moodalbail 		 * in the DB.
30916e91bba0SGirish Moodalbail 		 */
30926e91bba0SGirish Moodalbail 		if (status == IPADM_ENXIO)
30936e91bba0SGirish Moodalbail 			status = IPADM_SUCCESS;
30946e91bba0SGirish Moodalbail 		else if (status != IPADM_SUCCESS)
3095a73be61aSHans Rosenfeld 			goto out;
30966e91bba0SGirish Moodalbail 	}
30976e91bba0SGirish Moodalbail 
30986e91bba0SGirish Moodalbail 	if (!(ipaddr.ipadm_flags & IPMGMT_PERSIST) &&
30996e91bba0SGirish Moodalbail 	    (flags & IPADM_OPT_PERSIST)) {
31006e91bba0SGirish Moodalbail 		flags &= ~IPADM_OPT_PERSIST;
31016e91bba0SGirish Moodalbail 	}
31026e91bba0SGirish Moodalbail 	status = i_ipadm_delete_addrobj(iph, &ipaddr, flags);
3103a73be61aSHans Rosenfeld 
3104a73be61aSHans Rosenfeld 	if (status != IPADM_NOTFOUND)
3105a73be61aSHans Rosenfeld 		status = IPADM_SUCCESS;
3106a73be61aSHans Rosenfeld 
3107a73be61aSHans Rosenfeld out:
3108a73be61aSHans Rosenfeld 	/*
3109a73be61aSHans Rosenfeld 	 * Move the underlying IPMP interface back to the group.
3110a73be61aSHans Rosenfeld 	 * This cannot be done until the persistent configuration has been
3111a73be61aSHans Rosenfeld 	 * deleted as it will otherwise cause the active configuration to be
3112a73be61aSHans Rosenfeld 	 * restored.
3113a73be61aSHans Rosenfeld 	 */
3114a73be61aSHans Rosenfeld 	if (is_ipmp) {
3115a73be61aSHans Rosenfeld 		(void) i_ipadm_set_groupname_active(iph,
3116a73be61aSHans Rosenfeld 		    ipaddr.ipadm_ifname, gifname);
3117a73be61aSHans Rosenfeld 	}
3118a73be61aSHans Rosenfeld 	return (status);
31196e91bba0SGirish Moodalbail }
31206e91bba0SGirish Moodalbail 
31216e91bba0SGirish Moodalbail /*
31226e91bba0SGirish Moodalbail  * Starts the dhcpagent and sends it the message DHCP_START to start
31236e91bba0SGirish Moodalbail  * configuring a dhcp address on the given interface in `addr'.
31246e91bba0SGirish Moodalbail  * After making the dhcpagent request, it also updates the
31256e91bba0SGirish Moodalbail  * address object information in ipmgmtd's aobjmap and creates an
31266e91bba0SGirish Moodalbail  * entry in persistent DB if IPADM_OPT_PERSIST is set in `flags'.
31276e91bba0SGirish Moodalbail  */
31286e91bba0SGirish Moodalbail static ipadm_status_t
i_ipadm_create_dhcp(ipadm_handle_t iph,ipadm_addrobj_t addr,uint32_t flags)31296e91bba0SGirish Moodalbail i_ipadm_create_dhcp(ipadm_handle_t iph, ipadm_addrobj_t addr, uint32_t flags)
31306e91bba0SGirish Moodalbail {
31316e91bba0SGirish Moodalbail 	ipadm_status_t	status;
31326e91bba0SGirish Moodalbail 	ipadm_status_t	dh_status;
31336e91bba0SGirish Moodalbail 
31346e91bba0SGirish Moodalbail 	if (dhcp_start_agent(DHCP_IPC_MAX_WAIT) == -1)
31356e91bba0SGirish Moodalbail 		return (IPADM_DHCP_START_ERROR);
31366e91bba0SGirish Moodalbail 	/*
3137ec3706caSVasumathi Sundaram 	 * Create a new logical interface if needed; otherwise, just
3138ec3706caSVasumathi Sundaram 	 * use the 0th logical interface.
31396e91bba0SGirish Moodalbail 	 */
3140ec3706caSVasumathi Sundaram retry:
3141c8152f8fSAndy Fiddaman 	status = i_ipadm_do_addif(iph, addr, NULL);
31426e91bba0SGirish Moodalbail 	if (status != IPADM_SUCCESS)
31436e91bba0SGirish Moodalbail 		return (status);
3144ec3706caSVasumathi Sundaram 	/*
3145ec3706caSVasumathi Sundaram 	 * We don't have to set the lifnum for IPH_INIT case, because
3146ec3706caSVasumathi Sundaram 	 * there is no placeholder created for the address object in this
3147ec3706caSVasumathi Sundaram 	 * case.
3148ec3706caSVasumathi Sundaram 	 */
3149ec3706caSVasumathi Sundaram 	if (!(iph->iph_flags & IPH_INIT)) {
3150ec3706caSVasumathi Sundaram 		status = i_ipadm_setlifnum_addrobj(iph, addr);
3151ec3706caSVasumathi Sundaram 		if (status == IPADM_ADDROBJ_EXISTS)
3152ec3706caSVasumathi Sundaram 			goto retry;
3153ec3706caSVasumathi Sundaram 		if (status != IPADM_SUCCESS)
3154ec3706caSVasumathi Sundaram 			return (status);
31556e91bba0SGirish Moodalbail 	}
31566e91bba0SGirish Moodalbail 	/* Send DHCP_START to the dhcpagent. */
31576e91bba0SGirish Moodalbail 	status = i_ipadm_op_dhcp(addr, DHCP_START, NULL);
31586e91bba0SGirish Moodalbail 	/*
31596e91bba0SGirish Moodalbail 	 * We do not undo the create-addr operation for IPADM_DHCP_IPC_TIMEOUT
31606e91bba0SGirish Moodalbail 	 * since it is only a soft error to indicate the caller that the lease
31616e91bba0SGirish Moodalbail 	 * might be required after the function returns.
31626e91bba0SGirish Moodalbail 	 */
31636e91bba0SGirish Moodalbail 	if (status != IPADM_SUCCESS && status != IPADM_DHCP_IPC_TIMEOUT)
31646e91bba0SGirish Moodalbail 		goto fail;
31656e91bba0SGirish Moodalbail 	dh_status = status;
31666e91bba0SGirish Moodalbail 
31676e91bba0SGirish Moodalbail 	/* Persist the address object information in ipmgmtd. */
3168b31320a7SChris Fraire 	status = i_ipadm_addr_persist(iph, addr, B_FALSE, flags, NULL);
31696e91bba0SGirish Moodalbail 	if (status != IPADM_SUCCESS)
31706e91bba0SGirish Moodalbail 		goto fail;
31716e91bba0SGirish Moodalbail 
31726e91bba0SGirish Moodalbail 	return (dh_status);
31736e91bba0SGirish Moodalbail fail:
31746e91bba0SGirish Moodalbail 	/* In case of error, delete the dhcp address */
31756e91bba0SGirish Moodalbail 	(void) i_ipadm_delete_dhcp(iph, addr, B_TRUE);
31766e91bba0SGirish Moodalbail 	return (status);
31776e91bba0SGirish Moodalbail }
31786e91bba0SGirish Moodalbail 
31796e91bba0SGirish Moodalbail /*
31806e91bba0SGirish Moodalbail  * Releases/drops the dhcp lease on the logical interface in the address
31816e91bba0SGirish Moodalbail  * object `addr'. If `release' is set to B_FALSE, the lease will be dropped.
31826e91bba0SGirish Moodalbail  */
31836e91bba0SGirish Moodalbail static ipadm_status_t
i_ipadm_delete_dhcp(ipadm_handle_t iph,ipadm_addrobj_t addr,boolean_t release)31846e91bba0SGirish Moodalbail i_ipadm_delete_dhcp(ipadm_handle_t iph, ipadm_addrobj_t addr, boolean_t release)
31856e91bba0SGirish Moodalbail {
31866e91bba0SGirish Moodalbail 	ipadm_status_t	status;
31876e91bba0SGirish Moodalbail 	int		dherr;
31886e91bba0SGirish Moodalbail 
31896e91bba0SGirish Moodalbail 	/* Send DHCP_RELEASE or DHCP_DROP to the dhcpagent */
31906e91bba0SGirish Moodalbail 	if (release) {
31916e91bba0SGirish Moodalbail 		status = i_ipadm_op_dhcp(addr, DHCP_RELEASE, &dherr);
31926e91bba0SGirish Moodalbail 		/*
31936e91bba0SGirish Moodalbail 		 * If no lease was obtained on the object, we should
31946e91bba0SGirish Moodalbail 		 * drop the dhcp control on the interface.
31956e91bba0SGirish Moodalbail 		 */
31966e91bba0SGirish Moodalbail 		if (status != IPADM_SUCCESS && dherr == DHCP_IPC_E_OUTSTATE)
31976e91bba0SGirish Moodalbail 			status = i_ipadm_op_dhcp(addr, DHCP_DROP, NULL);
31986e91bba0SGirish Moodalbail 	} else {
31996e91bba0SGirish Moodalbail 		status = i_ipadm_op_dhcp(addr, DHCP_DROP, NULL);
32006e91bba0SGirish Moodalbail 	}
32016e91bba0SGirish Moodalbail 	if (status != IPADM_SUCCESS)
32026e91bba0SGirish Moodalbail 		return (status);
32036e91bba0SGirish Moodalbail 
32046e91bba0SGirish Moodalbail 	/* Delete the logical interface */
32056e91bba0SGirish Moodalbail 	if (addr->ipadm_lifnum != 0) {
32066e91bba0SGirish Moodalbail 		struct lifreq lifr;
32076e91bba0SGirish Moodalbail 
32086e91bba0SGirish Moodalbail 		bzero(&lifr, sizeof (lifr));
32096e91bba0SGirish Moodalbail 		i_ipadm_addrobj2lifname(addr, lifr.lifr_name,
32106e91bba0SGirish Moodalbail 		    sizeof (lifr.lifr_name));
32116e91bba0SGirish Moodalbail 		if (ioctl(iph->iph_sock, SIOCLIFREMOVEIF, (caddr_t)&lifr) < 0)
32126e91bba0SGirish Moodalbail 			return (ipadm_errno2status(errno));
32136e91bba0SGirish Moodalbail 	}
32146e91bba0SGirish Moodalbail 
32156e91bba0SGirish Moodalbail 	return (IPADM_SUCCESS);
32166e91bba0SGirish Moodalbail }
32176e91bba0SGirish Moodalbail 
32186e91bba0SGirish Moodalbail /*
32196e91bba0SGirish Moodalbail  * Communicates with the dhcpagent to send a dhcp message of type `type'.
32206e91bba0SGirish Moodalbail  * It returns the dhcp error in `dhcperror' if a non-null pointer is provided
32216e91bba0SGirish Moodalbail  * in `dhcperror'.
32226e91bba0SGirish Moodalbail  */
32236e91bba0SGirish Moodalbail static ipadm_status_t
i_ipadm_op_dhcp(ipadm_addrobj_t addr,dhcp_ipc_type_t type,int * dhcperror)32246e91bba0SGirish Moodalbail i_ipadm_op_dhcp(ipadm_addrobj_t addr, dhcp_ipc_type_t type, int *dhcperror)
32256e91bba0SGirish Moodalbail {
32266e91bba0SGirish Moodalbail 	dhcp_ipc_request_t	*request;
32276e91bba0SGirish Moodalbail 	dhcp_ipc_reply_t	*reply	= NULL;
3228b31320a7SChris Fraire 	dhcp_symbol_t		*entry = NULL;
3229b31320a7SChris Fraire 	dhcp_data_type_t	dtype = DHCP_TYPE_NONE;
3230b31320a7SChris Fraire 	void			*d4o = NULL;
3231b31320a7SChris Fraire 	uint16_t		d4olen = 0;
32326e91bba0SGirish Moodalbail 	char			ifname[LIFNAMSIZ];
32336e91bba0SGirish Moodalbail 	int			error;
32346e91bba0SGirish Moodalbail 	int			dhcp_timeout;
32356e91bba0SGirish Moodalbail 
32366e91bba0SGirish Moodalbail 	/* Construct a message to the dhcpagent. */
32376e91bba0SGirish Moodalbail 	bzero(&ifname, sizeof (ifname));
32386e91bba0SGirish Moodalbail 	i_ipadm_addrobj2lifname(addr, ifname, sizeof (ifname));
32396e91bba0SGirish Moodalbail 	if (addr->ipadm_primary)
32406e91bba0SGirish Moodalbail 		type |= DHCP_PRIMARY;
3241b31320a7SChris Fraire 
3242b31320a7SChris Fraire 	/* Set up a CD_HOSTNAME option, if applicable, to send through IPC */
3243b31320a7SChris Fraire 	switch (DHCP_IPC_CMD(type)) {
3244b31320a7SChris Fraire 	case DHCP_START:
3245b31320a7SChris Fraire 	case DHCP_EXTEND:
3246638e3f10SToomas Soome 		if (addr->ipadm_af == AF_INET && *addr->ipadm_reqhost != '\0') {
3247b31320a7SChris Fraire 			entry = inittab_getbycode(ITAB_CAT_STANDARD,
3248b31320a7SChris Fraire 			    ITAB_CONS_INFO, CD_HOSTNAME);
3249b31320a7SChris Fraire 			if (entry == NULL) {
3250b31320a7SChris Fraire 				return (IPADM_FAILURE);
3251b31320a7SChris Fraire 			} else {
3252b31320a7SChris Fraire 				d4o = inittab_encode(entry, addr->ipadm_reqhost,
3253b31320a7SChris Fraire 				    &d4olen, B_FALSE);
3254b31320a7SChris Fraire 				free(entry);
3255b31320a7SChris Fraire 				entry = NULL;
3256b31320a7SChris Fraire 				if (d4o == NULL)
3257b31320a7SChris Fraire 					return (IPADM_FAILURE);
3258b31320a7SChris Fraire 				dtype = DHCP_TYPE_OPTION;
3259b31320a7SChris Fraire 			}
3260b31320a7SChris Fraire 		}
3261b31320a7SChris Fraire 		break;
3262b31320a7SChris Fraire 	default:
3263b31320a7SChris Fraire 		break;
3264b31320a7SChris Fraire 	}
3265b31320a7SChris Fraire 
3266b31320a7SChris Fraire 	request = dhcp_ipc_alloc_request(type, ifname, d4o, d4olen, dtype);
3267b31320a7SChris Fraire 	if (request == NULL) {
3268b31320a7SChris Fraire 		free(d4o);
32696e91bba0SGirish Moodalbail 		return (IPADM_NO_MEMORY);
3270b31320a7SChris Fraire 	}
32716e91bba0SGirish Moodalbail 
32726e91bba0SGirish Moodalbail 	if (addr->ipadm_wait == IPADM_DHCP_WAIT_FOREVER)
32736e91bba0SGirish Moodalbail 		dhcp_timeout = DHCP_IPC_WAIT_FOREVER;
32746e91bba0SGirish Moodalbail 	else if (addr->ipadm_wait == IPADM_DHCP_WAIT_DEFAULT)
32756e91bba0SGirish Moodalbail 		dhcp_timeout = DHCP_IPC_WAIT_DEFAULT;
32766e91bba0SGirish Moodalbail 	else
32776e91bba0SGirish Moodalbail 		dhcp_timeout = addr->ipadm_wait;
32786e91bba0SGirish Moodalbail 	/* Send the message to dhcpagent. */
32796e91bba0SGirish Moodalbail 	error = dhcp_ipc_make_request(request, &reply, dhcp_timeout);
32806e91bba0SGirish Moodalbail 	free(request);
3281b31320a7SChris Fraire 	free(d4o);
32826e91bba0SGirish Moodalbail 	if (error == 0) {
32836e91bba0SGirish Moodalbail 		error = reply->return_code;
32846e91bba0SGirish Moodalbail 		free(reply);
32856e91bba0SGirish Moodalbail 	}
32866e91bba0SGirish Moodalbail 	if (error != 0) {
32876e91bba0SGirish Moodalbail 		if (dhcperror != NULL)
32886e91bba0SGirish Moodalbail 			*dhcperror = error;
32896e91bba0SGirish Moodalbail 		if (error != DHCP_IPC_E_TIMEOUT)
32906e91bba0SGirish Moodalbail 			return (IPADM_DHCP_IPC_ERROR);
32916e91bba0SGirish Moodalbail 		else if (dhcp_timeout != 0)
32926e91bba0SGirish Moodalbail 			return (IPADM_DHCP_IPC_TIMEOUT);
32936e91bba0SGirish Moodalbail 	}
32946e91bba0SGirish Moodalbail 
32956e91bba0SGirish Moodalbail 	return (IPADM_SUCCESS);
32966e91bba0SGirish Moodalbail }
32976e91bba0SGirish Moodalbail 
3298b31320a7SChris Fraire /*
3299b31320a7SChris Fraire  * Communicates with the dhcpagent to send a dhcp message of type
3300b31320a7SChris Fraire  * DHCP_STATUS, and copy on success into the `status' instance owned by the
3301b31320a7SChris Fraire  * caller. It returns any dhcp error in `dhcperror' if a non-null pointer
3302b31320a7SChris Fraire  * is provided.
3303b31320a7SChris Fraire  */
3304b31320a7SChris Fraire static ipadm_status_t
i_ipadm_dhcp_status(ipadm_addrobj_t addr,dhcp_status_t * status,int * dhcperror)3305b31320a7SChris Fraire i_ipadm_dhcp_status(ipadm_addrobj_t addr, dhcp_status_t *status,
3306b31320a7SChris Fraire     int *dhcperror)
3307b31320a7SChris Fraire {
3308b31320a7SChris Fraire 	dhcp_ipc_type_t		type = DHCP_STATUS;
3309b31320a7SChris Fraire 	dhcp_ipc_request_t	*request;
3310b31320a7SChris Fraire 	dhcp_ipc_reply_t	*reply;
3311b31320a7SChris Fraire 	dhcp_status_t		*private_status;
3312b31320a7SChris Fraire 	size_t			reply_size;
3313b31320a7SChris Fraire 	int			error;
3314b31320a7SChris Fraire 
3315b31320a7SChris Fraire 	if (addr->ipadm_af == AF_INET6)
3316b31320a7SChris Fraire 		type |= DHCP_V6;
3317b31320a7SChris Fraire 
3318b31320a7SChris Fraire 	request = dhcp_ipc_alloc_request(type, addr->ipadm_ifname, NULL, 0,
3319b31320a7SChris Fraire 	    DHCP_TYPE_NONE);
3320b31320a7SChris Fraire 	if (request == NULL)
3321b31320a7SChris Fraire 		return (IPADM_NO_MEMORY);
3322b31320a7SChris Fraire 
3323b31320a7SChris Fraire 	error = dhcp_ipc_make_request(request, &reply, DHCP_IPC_WAIT_DEFAULT);
3324b31320a7SChris Fraire 	free(request);
3325b31320a7SChris Fraire 	if (error != 0) {
3326b31320a7SChris Fraire 		if (dhcperror != NULL)
3327b31320a7SChris Fraire 			*dhcperror = error;
3328b31320a7SChris Fraire 		return (error != DHCP_IPC_E_TIMEOUT ? IPADM_DHCP_IPC_ERROR
3329b31320a7SChris Fraire 		    : IPADM_DHCP_IPC_TIMEOUT);
3330b31320a7SChris Fraire 	}
3331b31320a7SChris Fraire 
3332b31320a7SChris Fraire 	error = reply->return_code;
3333b31320a7SChris Fraire 	if (error == DHCP_IPC_E_UNKIF) {
3334b31320a7SChris Fraire 		free(reply);
3335b31320a7SChris Fraire 		bzero(status, sizeof (dhcp_status_t));
3336b31320a7SChris Fraire 		return (IPADM_NOTFOUND);
3337b31320a7SChris Fraire 	}
3338b31320a7SChris Fraire 
3339b31320a7SChris Fraire 	private_status = dhcp_ipc_get_data(reply, &reply_size, NULL);
3340b31320a7SChris Fraire 	if (reply_size < DHCP_STATUS_VER1_SIZE) {
3341b31320a7SChris Fraire 		free(reply);
3342b31320a7SChris Fraire 		return (IPADM_DHCP_IPC_ERROR);
3343b31320a7SChris Fraire 	}
3344b31320a7SChris Fraire 
3345b31320a7SChris Fraire 	/*
3346b31320a7SChris Fraire 	 * Copy the status out of the memory allocated by this function into
3347b31320a7SChris Fraire 	 * memory owned by the caller.
3348b31320a7SChris Fraire 	 */
3349b31320a7SChris Fraire 	*status = *private_status;
3350b31320a7SChris Fraire 	free(reply);
3351b31320a7SChris Fraire 	return (IPADM_SUCCESS);
3352b31320a7SChris Fraire }
3353b31320a7SChris Fraire 
33546e91bba0SGirish Moodalbail /*
33556e91bba0SGirish Moodalbail  * Returns the IP addresses of the specified interface in both the
33566e91bba0SGirish Moodalbail  * active and the persistent configuration. If no
33576e91bba0SGirish Moodalbail  * interface is specified, it returns all non-zero IP addresses
33586e91bba0SGirish Moodalbail  * configured on all interfaces in active and persistent
33596e91bba0SGirish Moodalbail  * configurations.
33606e91bba0SGirish Moodalbail  * `addrinfo' will contain addresses that are
33616e91bba0SGirish Moodalbail  * (1) in both active and persistent configuration (created persistently)
33626e91bba0SGirish Moodalbail  * (2) only in active configuration (created temporarily)
33636e91bba0SGirish Moodalbail  * (3) only in persistent configuration (disabled addresses)
33646e91bba0SGirish Moodalbail  *
33656e91bba0SGirish Moodalbail  * Address list that is returned by this function must be freed
33666e91bba0SGirish Moodalbail  * using the ipadm_freeaddr_info() function.
33676e91bba0SGirish Moodalbail  */
33686e91bba0SGirish 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)33696e91bba0SGirish Moodalbail ipadm_addr_info(ipadm_handle_t iph, const char *ifname,
33706e91bba0SGirish Moodalbail     ipadm_addr_info_t **addrinfo, uint32_t flags, int64_t lifc_flags)
33716e91bba0SGirish Moodalbail {
33726e91bba0SGirish Moodalbail 	ifspec_t	ifsp;
33736e91bba0SGirish Moodalbail 
33746e91bba0SGirish Moodalbail 	if (addrinfo == NULL || iph == NULL)
33756e91bba0SGirish Moodalbail 		return (IPADM_INVALID_ARG);
33766e91bba0SGirish Moodalbail 	if (ifname != NULL &&
33776e91bba0SGirish Moodalbail 	    (!ifparse_ifspec(ifname, &ifsp) || ifsp.ifsp_lunvalid)) {
33786e91bba0SGirish Moodalbail 		return (IPADM_INVALID_ARG);
33796e91bba0SGirish Moodalbail 	}
33806e91bba0SGirish Moodalbail 	return (i_ipadm_get_all_addr_info(iph, ifname, addrinfo,
33816e91bba0SGirish Moodalbail 	    flags, lifc_flags));
33826e91bba0SGirish Moodalbail }
33836e91bba0SGirish Moodalbail 
33846e91bba0SGirish Moodalbail /*
33856e91bba0SGirish Moodalbail  * Frees the structure allocated by ipadm_addr_info().
33866e91bba0SGirish Moodalbail  */
33876e91bba0SGirish Moodalbail void
ipadm_free_addr_info(ipadm_addr_info_t * ainfo)33886e91bba0SGirish Moodalbail ipadm_free_addr_info(ipadm_addr_info_t *ainfo)
33896e91bba0SGirish Moodalbail {
33906e91bba0SGirish Moodalbail 	freeifaddrs((struct ifaddrs *)ainfo);
33916e91bba0SGirish Moodalbail }
33926e91bba0SGirish Moodalbail 
33936e91bba0SGirish Moodalbail /*
33946e91bba0SGirish Moodalbail  * Makes a door call to ipmgmtd to update its `aobjmap' with the address
3395b31320a7SChris Fraire  * object in `ipaddr'. This door call also can update the persistent DB to
33966e91bba0SGirish Moodalbail  * remember address object to be recreated on next reboot or on an
33976e91bba0SGirish Moodalbail  * ipadm_enable_addr()/ipadm_enable_if() call.
33986e91bba0SGirish Moodalbail  */
33996e91bba0SGirish Moodalbail ipadm_status_t
i_ipadm_addr_persist(ipadm_handle_t iph,const ipadm_addrobj_t ipaddr,boolean_t default_prefixlen,uint32_t flags,const char * propname)34006e91bba0SGirish Moodalbail i_ipadm_addr_persist(ipadm_handle_t iph, const ipadm_addrobj_t ipaddr,
3401b31320a7SChris Fraire     boolean_t default_prefixlen, uint32_t flags, const char *propname)
34026e91bba0SGirish Moodalbail {
34036e91bba0SGirish Moodalbail 	char			*aname = ipaddr->ipadm_aobjname;
34046e91bba0SGirish Moodalbail 	nvlist_t		*nvl;
34056e91bba0SGirish Moodalbail 	int			err = 0;
34066e91bba0SGirish Moodalbail 	ipadm_status_t		status;
34076e91bba0SGirish Moodalbail 	uint_t			pflags = 0;
34086e91bba0SGirish Moodalbail 
34096e91bba0SGirish Moodalbail 	/*
34106e91bba0SGirish Moodalbail 	 * Construct the nvl to send to the door.
34116e91bba0SGirish Moodalbail 	 */
34126e91bba0SGirish Moodalbail 	if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0)
34136e91bba0SGirish Moodalbail 		return (IPADM_NO_MEMORY);
34146e91bba0SGirish Moodalbail 	if ((err = nvlist_add_string(nvl, IPADM_NVP_IFNAME,
34156e91bba0SGirish Moodalbail 	    ipaddr->ipadm_ifname)) != 0 ||
34166e91bba0SGirish Moodalbail 	    (err = nvlist_add_string(nvl, IPADM_NVP_AOBJNAME, aname)) != 0 ||
34176e91bba0SGirish Moodalbail 	    (err = nvlist_add_int32(nvl, IPADM_NVP_LIFNUM,
34186e91bba0SGirish Moodalbail 	    ipaddr->ipadm_lifnum)) != 0) {
34196e91bba0SGirish Moodalbail 		status = ipadm_errno2status(err);
34206e91bba0SGirish Moodalbail 		goto ret;
34216e91bba0SGirish Moodalbail 	}
34226e91bba0SGirish Moodalbail 	switch (ipaddr->ipadm_atype) {
34236e91bba0SGirish Moodalbail 	case IPADM_ADDR_STATIC:
34246e91bba0SGirish Moodalbail 		status = i_ipadm_add_ipaddr2nvl(nvl, ipaddr);
34256e91bba0SGirish Moodalbail 		if (status != IPADM_SUCCESS)
34266e91bba0SGirish Moodalbail 			goto ret;
34276e91bba0SGirish Moodalbail 		if (flags & IPADM_OPT_UP)
34286e91bba0SGirish Moodalbail 			err = nvlist_add_string(nvl, "up", "yes");
34296e91bba0SGirish Moodalbail 		else
34306e91bba0SGirish Moodalbail 			err = nvlist_add_string(nvl, "up", "no");
34316e91bba0SGirish Moodalbail 		status = ipadm_errno2status(err);
34326e91bba0SGirish Moodalbail 		break;
34336e91bba0SGirish Moodalbail 	case IPADM_ADDR_DHCP:
34346e91bba0SGirish Moodalbail 		status = i_ipadm_add_dhcp2nvl(nvl, ipaddr->ipadm_primary,
34356e91bba0SGirish Moodalbail 		    ipaddr->ipadm_wait);
3436b31320a7SChris Fraire 		if (status != IPADM_SUCCESS)
3437b31320a7SChris Fraire 			goto ret;
3438b31320a7SChris Fraire 
3439b31320a7SChris Fraire 		/*
3440b31320a7SChris Fraire 		 * For purposes of updating the ipmgmtd cached representation of
3441b31320a7SChris Fraire 		 * reqhost (ipmgmt_am_reqhost), include a value here in `nvl',
3442b31320a7SChris Fraire 		 * but the value is actually fully persisted as a separate
3443b31320a7SChris Fraire 		 * i_ipadm_persist_propval below.
3444b31320a7SChris Fraire 		 */
3445b31320a7SChris Fraire 		err = nvlist_add_string(nvl, IPADM_NVP_REQHOST,
3446b31320a7SChris Fraire 		    ipaddr->ipadm_reqhost);
3447b31320a7SChris Fraire 		status = ipadm_errno2status(err);
34486e91bba0SGirish Moodalbail 		break;
34496e91bba0SGirish Moodalbail 	case IPADM_ADDR_IPV6_ADDRCONF:
34506e91bba0SGirish Moodalbail 		status = i_ipadm_add_intfid2nvl(nvl, ipaddr);
34516e91bba0SGirish Moodalbail 		break;
34526e91bba0SGirish Moodalbail 	}
34536e91bba0SGirish Moodalbail 	if (status != IPADM_SUCCESS)
34546e91bba0SGirish Moodalbail 		goto ret;
34556e91bba0SGirish Moodalbail 
34566e91bba0SGirish Moodalbail 	if (iph->iph_flags & IPH_INIT) {
34576e91bba0SGirish Moodalbail 		/*
34586e91bba0SGirish Moodalbail 		 * IPMGMT_INIT tells the ipmgmtd to set both IPMGMT_ACTIVE and
34596e91bba0SGirish Moodalbail 		 * IPMGMT_PERSIST on the address object in its `aobjmap'.
34606e91bba0SGirish Moodalbail 		 * For the callers ipadm_enable_if() and ipadm_enable_addr(),
34616e91bba0SGirish Moodalbail 		 * IPADM_OPT_PERSIST is not set in their flags. They send
34626e91bba0SGirish Moodalbail 		 * IPH_INIT in iph_flags, so that the address object will be
34636e91bba0SGirish Moodalbail 		 * set as both IPMGMT_ACTIVE and IPMGMT_PERSIST.
34646e91bba0SGirish Moodalbail 		 */
34656e91bba0SGirish Moodalbail 		pflags |= IPMGMT_INIT;
34666e91bba0SGirish Moodalbail 	} else {
34676e91bba0SGirish Moodalbail 		if (flags & IPADM_OPT_ACTIVE)
34686e91bba0SGirish Moodalbail 			pflags |= IPMGMT_ACTIVE;
34696e91bba0SGirish Moodalbail 		if (flags & IPADM_OPT_PERSIST)
34706e91bba0SGirish Moodalbail 			pflags |= IPMGMT_PERSIST;
3471b31320a7SChris Fraire 		if (flags & IPADM_OPT_SET_PROPS)
3472b31320a7SChris Fraire 			pflags |= IPMGMT_PROPS_ONLY;
34736e91bba0SGirish Moodalbail 	}
34746e91bba0SGirish Moodalbail 	status = i_ipadm_addr_persist_nvl(iph, nvl, pflags);
3475b31320a7SChris Fraire 
3476b31320a7SChris Fraire 	if (flags & IPADM_OPT_SET_PROPS) {
3477b31320a7SChris Fraire 		/*
3478b31320a7SChris Fraire 		 * Set PERSIST per IPADM_OPT_PROPS_PERSIST, and then un-set the
3479b31320a7SChris Fraire 		 * SET_PROPS bits.
3480b31320a7SChris Fraire 		 */
3481b31320a7SChris Fraire 		flags |= IPADM_OPT_ACTIVE;
3482b31320a7SChris Fraire 		if (flags & IPADM_OPT_PERSIST_PROPS)
3483b31320a7SChris Fraire 			flags |= IPADM_OPT_PERSIST;
3484b31320a7SChris Fraire 		else
3485b31320a7SChris Fraire 			flags &= ~IPADM_OPT_PERSIST;
3486b31320a7SChris Fraire 		flags &= ~(IPADM_OPT_SET_PROPS | IPADM_OPT_PERSIST_PROPS);
3487b31320a7SChris Fraire 	}
3488b31320a7SChris Fraire 
3489b31320a7SChris Fraire 	if (status == IPADM_SUCCESS && (flags & IPADM_OPT_PERSIST)) {
3490b31320a7SChris Fraire 		char		pbuf[MAXPROPVALLEN], *pval = NULL;
3491b31320a7SChris Fraire 		ipadm_prop_desc_t	*pdp = NULL;
3492b31320a7SChris Fraire 
3493b31320a7SChris Fraire 		/*
3494b31320a7SChris Fraire 		 * addprop properties are stored on separate lines in the DB and
3495b31320a7SChris Fraire 		 * not along with the address itself. Call the function that
3496b31320a7SChris Fraire 		 * persists address properties.
3497b31320a7SChris Fraire 		 */
3498b31320a7SChris Fraire 
3499b31320a7SChris Fraire 		switch (ipaddr->ipadm_atype) {
3500b31320a7SChris Fraire 		case IPADM_ADDR_STATIC:
3501b31320a7SChris Fraire 			if (!default_prefixlen && (propname == NULL ||
3502b31320a7SChris Fraire 			    strcmp(propname, IPADM_NVP_PREFIXLEN) == 0)) {
3503b31320a7SChris Fraire 				pdp = i_ipadm_get_addrprop_desc(
3504b31320a7SChris Fraire 				    IPADM_NVP_PREFIXLEN);
3505b31320a7SChris Fraire 				(void) snprintf(pbuf, sizeof (pbuf), "%u",
3506b31320a7SChris Fraire 				    ipaddr->ipadm_static_prefixlen);
3507b31320a7SChris Fraire 				pval = pbuf;
3508b31320a7SChris Fraire 			}
3509b31320a7SChris Fraire 			break;
3510b31320a7SChris Fraire 		case IPADM_ADDR_DHCP:
3511b31320a7SChris Fraire 			if (propname == NULL ||
3512b31320a7SChris Fraire 			    strcmp(propname, IPADM_NVP_REQHOST) == 0) {
3513b31320a7SChris Fraire 				pdp = i_ipadm_get_addrprop_desc(
3514b31320a7SChris Fraire 				    IPADM_NVP_REQHOST);
3515b31320a7SChris Fraire 				pval = ipaddr->ipadm_reqhost;
3516b31320a7SChris Fraire 			}
3517b31320a7SChris Fraire 			break;
3518b31320a7SChris Fraire 		default:
3519b31320a7SChris Fraire 			break;
3520b31320a7SChris Fraire 		}
3521b31320a7SChris Fraire 
3522b31320a7SChris Fraire 		if (pval != NULL) {
3523b31320a7SChris Fraire 			assert(pdp != NULL);
3524b31320a7SChris Fraire 			status = i_ipadm_persist_propval(iph, pdp, pval,
3525b31320a7SChris Fraire 			    ipaddr, flags);
35266e91bba0SGirish Moodalbail 		}
35276e91bba0SGirish Moodalbail 	}
3528b31320a7SChris Fraire 
35296e91bba0SGirish Moodalbail ret:
35306e91bba0SGirish Moodalbail 	nvlist_free(nvl);
35316e91bba0SGirish Moodalbail 	return (status);
35326e91bba0SGirish Moodalbail }
35336e91bba0SGirish Moodalbail 
35346e91bba0SGirish Moodalbail /*
35356e91bba0SGirish Moodalbail  * Makes the door call to ipmgmtd to store the address object in the
35366e91bba0SGirish Moodalbail  * nvlist `nvl'.
35376e91bba0SGirish Moodalbail  */
35386e91bba0SGirish Moodalbail static ipadm_status_t
i_ipadm_addr_persist_nvl(ipadm_handle_t iph,nvlist_t * nvl,uint32_t flags)35396e91bba0SGirish Moodalbail i_ipadm_addr_persist_nvl(ipadm_handle_t iph, nvlist_t *nvl, uint32_t flags)
35406e91bba0SGirish Moodalbail {
35416e91bba0SGirish Moodalbail 	char			*buf = NULL, *nvlbuf = NULL;
35426e91bba0SGirish Moodalbail 	size_t			nvlsize, bufsize;
35436e91bba0SGirish Moodalbail 	ipmgmt_setaddr_arg_t	*sargp;
35446e91bba0SGirish Moodalbail 	int			err;
35456e91bba0SGirish Moodalbail 
35466e91bba0SGirish Moodalbail 	err = nvlist_pack(nvl, &nvlbuf, &nvlsize, NV_ENCODE_NATIVE, 0);
35476e91bba0SGirish Moodalbail 	if (err != 0)
35486e91bba0SGirish Moodalbail 		return (ipadm_errno2status(err));
35496e91bba0SGirish Moodalbail 	bufsize = sizeof (*sargp) + nvlsize;
35506e91bba0SGirish Moodalbail 	buf = calloc(1, bufsize);
35516e91bba0SGirish Moodalbail 	sargp = (void *)buf;
35526e91bba0SGirish Moodalbail 	sargp->ia_cmd = IPMGMT_CMD_SETADDR;
35536e91bba0SGirish Moodalbail 	sargp->ia_flags = flags;
35546e91bba0SGirish Moodalbail 	sargp->ia_nvlsize = nvlsize;
35556e91bba0SGirish Moodalbail 	(void) bcopy(nvlbuf, buf + sizeof (*sargp), nvlsize);
35566e91bba0SGirish Moodalbail 	err = ipadm_door_call(iph, buf, bufsize, NULL, 0, B_FALSE);
35576e91bba0SGirish Moodalbail 	free(buf);
35586e91bba0SGirish Moodalbail 	free(nvlbuf);
35596e91bba0SGirish Moodalbail 	return (ipadm_errno2status(err));
35606e91bba0SGirish Moodalbail }
35616e91bba0SGirish Moodalbail 
35626e91bba0SGirish Moodalbail /*
35636e91bba0SGirish Moodalbail  * Makes a door call to ipmgmtd to remove the address object in `ipaddr'
35646e91bba0SGirish Moodalbail  * from its `aobjmap'. This door call also removes the address object and all
35656e91bba0SGirish Moodalbail  * its properties from the persistent DB if IPADM_OPT_PERSIST is set in
35666e91bba0SGirish Moodalbail  * `flags', so that the object will not be recreated on next reboot or on an
35676e91bba0SGirish Moodalbail  * ipadm_enable_addr()/ipadm_enable_if() call.
35686e91bba0SGirish Moodalbail  */
35696e91bba0SGirish Moodalbail ipadm_status_t
i_ipadm_delete_addrobj(ipadm_handle_t iph,const ipadm_addrobj_t ipaddr,uint32_t flags)35706e91bba0SGirish Moodalbail i_ipadm_delete_addrobj(ipadm_handle_t iph, const ipadm_addrobj_t ipaddr,
35716e91bba0SGirish Moodalbail     uint32_t flags)
35726e91bba0SGirish Moodalbail {
35736e91bba0SGirish Moodalbail 	ipmgmt_addr_arg_t	arg;
35746e91bba0SGirish Moodalbail 	int			err;
35756e91bba0SGirish Moodalbail 
35766e91bba0SGirish Moodalbail 	arg.ia_cmd = IPMGMT_CMD_RESETADDR;
35776e91bba0SGirish Moodalbail 	arg.ia_flags = 0;
35786e91bba0SGirish Moodalbail 	if (flags & IPADM_OPT_ACTIVE)
35796e91bba0SGirish Moodalbail 		arg.ia_flags |= IPMGMT_ACTIVE;
35806e91bba0SGirish Moodalbail 	if (flags & IPADM_OPT_PERSIST)
35816e91bba0SGirish Moodalbail 		arg.ia_flags |= IPMGMT_PERSIST;
35826e91bba0SGirish Moodalbail 	(void) strlcpy(arg.ia_aobjname, ipaddr->ipadm_aobjname,
35836e91bba0SGirish Moodalbail 	    sizeof (arg.ia_aobjname));
35846e91bba0SGirish Moodalbail 	arg.ia_lnum = ipaddr->ipadm_lifnum;
35856e91bba0SGirish Moodalbail 	err = ipadm_door_call(iph, &arg, sizeof (arg), NULL, 0, B_FALSE);
35866e91bba0SGirish Moodalbail 	return (ipadm_errno2status(err));
35876e91bba0SGirish Moodalbail }
35886e91bba0SGirish Moodalbail 
35896e91bba0SGirish Moodalbail /*
35906e91bba0SGirish Moodalbail  * Checks if the caller is authorized for the up/down operation.
35916e91bba0SGirish Moodalbail  * Retrieves the address object corresponding to `aobjname' from ipmgmtd
35926e91bba0SGirish Moodalbail  * and retrieves the address flags for that object from kernel.
35936e91bba0SGirish Moodalbail  * The arguments `ipaddr' and `ifflags' must be allocated by the caller.
35946e91bba0SGirish Moodalbail  */
35956e91bba0SGirish 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)35966e91bba0SGirish Moodalbail i_ipadm_updown_common(ipadm_handle_t iph, const char *aobjname,
35976e91bba0SGirish Moodalbail     ipadm_addrobj_t ipaddr, uint32_t ipadm_flags, uint64_t *ifflags)
35986e91bba0SGirish Moodalbail {
35996e91bba0SGirish Moodalbail 	ipadm_status_t	status;
36006e91bba0SGirish Moodalbail 	char		lifname[LIFNAMSIZ];
36016e91bba0SGirish Moodalbail 
36026e91bba0SGirish Moodalbail 	/* check for solaris.network.interface.config authorization */
36036e91bba0SGirish Moodalbail 	if (!ipadm_check_auth())
36046e91bba0SGirish Moodalbail 		return (IPADM_EAUTH);
36056e91bba0SGirish Moodalbail 
36066e91bba0SGirish Moodalbail 	/* validate input */
36076e91bba0SGirish Moodalbail 	if (aobjname == NULL || strlcpy(ipaddr->ipadm_aobjname, aobjname,
36086e91bba0SGirish Moodalbail 	    IPADM_AOBJSIZ) >= IPADM_AOBJSIZ) {
36096e91bba0SGirish Moodalbail 		return (IPADM_INVALID_ARG);
36106e91bba0SGirish Moodalbail 	}
36116e91bba0SGirish Moodalbail 
36126e91bba0SGirish Moodalbail 	/* Retrieve the address object information. */
36136e91bba0SGirish Moodalbail 	status = i_ipadm_get_addrobj(iph, ipaddr);
36146e91bba0SGirish Moodalbail 	if (status != IPADM_SUCCESS)
36156e91bba0SGirish Moodalbail 		return (status);
36166e91bba0SGirish Moodalbail 
36176e91bba0SGirish Moodalbail 	if (!(ipaddr->ipadm_flags & IPMGMT_ACTIVE))
36186e91bba0SGirish Moodalbail 		return (IPADM_OP_DISABLE_OBJ);
3619a73be61aSHans Rosenfeld 
36206e91bba0SGirish Moodalbail 	if ((ipadm_flags & IPADM_OPT_PERSIST) &&
36216e91bba0SGirish Moodalbail 	    !(ipaddr->ipadm_flags & IPMGMT_PERSIST))
36226e91bba0SGirish Moodalbail 		return (IPADM_TEMPORARY_OBJ);
3623a73be61aSHans Rosenfeld 
36246e91bba0SGirish Moodalbail 	if (ipaddr->ipadm_atype == IPADM_ADDR_IPV6_ADDRCONF ||
36256e91bba0SGirish Moodalbail 	    (ipaddr->ipadm_atype == IPADM_ADDR_DHCP &&
36266e91bba0SGirish Moodalbail 	    (ipadm_flags & IPADM_OPT_PERSIST)))
36276e91bba0SGirish Moodalbail 		return (IPADM_NOTSUP);
36286e91bba0SGirish Moodalbail 
36296e91bba0SGirish Moodalbail 	i_ipadm_addrobj2lifname(ipaddr, lifname, sizeof (lifname));
3630a73be61aSHans Rosenfeld 
36316e91bba0SGirish Moodalbail 	return (i_ipadm_get_flags(iph, lifname, ipaddr->ipadm_af, ifflags));
36326e91bba0SGirish Moodalbail }
36336e91bba0SGirish Moodalbail 
36346e91bba0SGirish Moodalbail /*
36356e91bba0SGirish Moodalbail  * Marks the address in the address object `aobjname' up. This operation is
36366e91bba0SGirish Moodalbail  * not supported for an address object of type IPADM_ADDR_IPV6_ADDRCONF.
36376e91bba0SGirish Moodalbail  * For an address object of type IPADM_ADDR_DHCP, this operation can
36386e91bba0SGirish Moodalbail  * only be temporary and no updates will be made to the persistent DB.
36396e91bba0SGirish Moodalbail  */
36406e91bba0SGirish Moodalbail ipadm_status_t
ipadm_up_addr(ipadm_handle_t iph,const char * aobjname,uint32_t ipadm_flags)36416e91bba0SGirish Moodalbail ipadm_up_addr(ipadm_handle_t iph, const char *aobjname, uint32_t ipadm_flags)
36426e91bba0SGirish Moodalbail {
36436e91bba0SGirish Moodalbail 	struct ipadm_addrobj_s ipaddr;
36446e91bba0SGirish Moodalbail 	ipadm_status_t	status;
36456e91bba0SGirish Moodalbail 	uint64_t	flags;
36466e91bba0SGirish Moodalbail 	char		lifname[LIFNAMSIZ];
36476e91bba0SGirish Moodalbail 
36486e91bba0SGirish Moodalbail 	status = i_ipadm_updown_common(iph, aobjname, &ipaddr, ipadm_flags,
36496e91bba0SGirish Moodalbail 	    &flags);
36506e91bba0SGirish Moodalbail 	if (status != IPADM_SUCCESS)
36516e91bba0SGirish Moodalbail 		return (status);
36526e91bba0SGirish Moodalbail 	if (flags & IFF_UP)
36536e91bba0SGirish Moodalbail 		goto persist;
36546e91bba0SGirish Moodalbail 	/*
36556e91bba0SGirish Moodalbail 	 * If the address is already a duplicate, then refresh-addr
36566e91bba0SGirish Moodalbail 	 * should be used to mark it up.
36576e91bba0SGirish Moodalbail 	 */
36586e91bba0SGirish Moodalbail 	if (flags & IFF_DUPLICATE)
36596e91bba0SGirish Moodalbail 		return (IPADM_DAD_FOUND);
36606e91bba0SGirish Moodalbail 
36616e91bba0SGirish Moodalbail 	i_ipadm_addrobj2lifname(&ipaddr, lifname, sizeof (lifname));
36626e91bba0SGirish Moodalbail 	status = i_ipadm_set_flags(iph, lifname, ipaddr.ipadm_af, IFF_UP, 0);
36636e91bba0SGirish Moodalbail 	if (status != IPADM_SUCCESS)
36646e91bba0SGirish Moodalbail 		return (status);
36656e91bba0SGirish Moodalbail 
36666e91bba0SGirish Moodalbail persist:
36676e91bba0SGirish Moodalbail 	/* Update persistent DB. */
36686e91bba0SGirish Moodalbail 	if (ipadm_flags & IPADM_OPT_PERSIST) {
36696e91bba0SGirish Moodalbail 		status = i_ipadm_persist_propval(iph, &up_addrprop,
36706e91bba0SGirish Moodalbail 		    "yes", &ipaddr, 0);
36716e91bba0SGirish Moodalbail 	}
36726e91bba0SGirish Moodalbail 
36736e91bba0SGirish Moodalbail 	return (status);
36746e91bba0SGirish Moodalbail }
36756e91bba0SGirish Moodalbail 
36766e91bba0SGirish Moodalbail /*
36776e91bba0SGirish Moodalbail  * Marks the address in the address object `aobjname' down. This operation is
36786e91bba0SGirish Moodalbail  * not supported for an address object of type IPADM_ADDR_IPV6_ADDRCONF.
36796e91bba0SGirish Moodalbail  * For an address object of type IPADM_ADDR_DHCP, this operation can
36806e91bba0SGirish Moodalbail  * only be temporary and no updates will be made to the persistent DB.
36816e91bba0SGirish Moodalbail  */
36826e91bba0SGirish Moodalbail ipadm_status_t
ipadm_down_addr(ipadm_handle_t iph,const char * aobjname,uint32_t ipadm_flags)36836e91bba0SGirish Moodalbail ipadm_down_addr(ipadm_handle_t iph, const char *aobjname, uint32_t ipadm_flags)
36846e91bba0SGirish Moodalbail {
36856e91bba0SGirish Moodalbail 	struct ipadm_addrobj_s ipaddr;
36866e91bba0SGirish Moodalbail 	ipadm_status_t	status;
36876e91bba0SGirish Moodalbail 	struct lifreq	lifr;
36886e91bba0SGirish Moodalbail 	uint64_t	flags;
36896e91bba0SGirish Moodalbail 
36906e91bba0SGirish Moodalbail 	status = i_ipadm_updown_common(iph, aobjname, &ipaddr, ipadm_flags,
36916e91bba0SGirish Moodalbail 	    &flags);
36926e91bba0SGirish Moodalbail 	if (status != IPADM_SUCCESS)
36936e91bba0SGirish Moodalbail 		return (status);
36946e91bba0SGirish Moodalbail 	i_ipadm_addrobj2lifname(&ipaddr, lifr.lifr_name,
36956e91bba0SGirish Moodalbail 	    sizeof (lifr.lifr_name));
36966e91bba0SGirish Moodalbail 	if (flags & IFF_UP) {
36976e91bba0SGirish Moodalbail 		status = i_ipadm_set_flags(iph, lifr.lifr_name,
36986e91bba0SGirish Moodalbail 		    ipaddr.ipadm_af, 0, IFF_UP);
36996e91bba0SGirish Moodalbail 		if (status != IPADM_SUCCESS)
37006e91bba0SGirish Moodalbail 			return (status);
37016e91bba0SGirish Moodalbail 	} else if (flags & IFF_DUPLICATE) {
37026e91bba0SGirish Moodalbail 		/*
37036e91bba0SGirish Moodalbail 		 * Clear the IFF_DUPLICATE flag.
37046e91bba0SGirish Moodalbail 		 */
37056e91bba0SGirish Moodalbail 		if (ioctl(iph->iph_sock, SIOCGLIFADDR, &lifr) < 0)
37066e91bba0SGirish Moodalbail 			return (ipadm_errno2status(errno));
37076e91bba0SGirish Moodalbail 		if (ioctl(iph->iph_sock, SIOCSLIFADDR, &lifr) < 0)
37086e91bba0SGirish Moodalbail 			return (ipadm_errno2status(errno));
37096e91bba0SGirish Moodalbail 	}
37106e91bba0SGirish Moodalbail 
37116e91bba0SGirish Moodalbail 	/* Update persistent DB */
37126e91bba0SGirish Moodalbail 	if (ipadm_flags & IPADM_OPT_PERSIST) {
37136e91bba0SGirish Moodalbail 		status = i_ipadm_persist_propval(iph, &up_addrprop,
37146e91bba0SGirish Moodalbail 		    "no", &ipaddr, 0);
37156e91bba0SGirish Moodalbail 	}
37166e91bba0SGirish Moodalbail 
37176e91bba0SGirish Moodalbail 	return (status);
37186e91bba0SGirish Moodalbail }
37196e91bba0SGirish Moodalbail 
37206e91bba0SGirish Moodalbail /*
37216e91bba0SGirish Moodalbail  * Refreshes the address in the address object `aobjname'. If the address object
37226e91bba0SGirish Moodalbail  * is of type IPADM_ADDR_STATIC, DAD is re-initiated on the address. If
37236e91bba0SGirish Moodalbail  * `ipadm_flags' has IPADM_OPT_INFORM set, a DHCP_INFORM message is sent to the
37246e91bba0SGirish Moodalbail  * dhcpagent for this static address. If the address object is of type
37256e91bba0SGirish Moodalbail  * IPADM_ADDR_DHCP, a DHCP_EXTEND message is sent to the dhcpagent.
37266e91bba0SGirish Moodalbail  * If a dhcp address has not yet been acquired, a DHCP_START is sent to the
37276e91bba0SGirish Moodalbail  * dhcpagent. This operation is not supported for an address object of
37286e91bba0SGirish Moodalbail  * type IPADM_ADDR_IPV6_ADDRCONF.
37296e91bba0SGirish Moodalbail  */
37306e91bba0SGirish Moodalbail ipadm_status_t
ipadm_refresh_addr(ipadm_handle_t iph,const char * aobjname,uint32_t ipadm_flags)37316e91bba0SGirish Moodalbail ipadm_refresh_addr(ipadm_handle_t iph, const char *aobjname,
37326e91bba0SGirish Moodalbail     uint32_t ipadm_flags)
37336e91bba0SGirish Moodalbail {
37346e91bba0SGirish Moodalbail 	ipadm_status_t		status = IPADM_SUCCESS;
37356e91bba0SGirish Moodalbail 	uint64_t		flags;
37366e91bba0SGirish Moodalbail 	struct ipadm_addrobj_s	ipaddr;
37376e91bba0SGirish Moodalbail 	sa_family_t		af;
37386e91bba0SGirish Moodalbail 	char			lifname[LIFNAMSIZ];
37396e91bba0SGirish Moodalbail 	boolean_t		inform =
37406e91bba0SGirish Moodalbail 	    ((ipadm_flags & IPADM_OPT_INFORM) != 0);
37416e91bba0SGirish Moodalbail 
37426e91bba0SGirish Moodalbail 	/* check for solaris.network.interface.config authorization */
37436e91bba0SGirish Moodalbail 	if (!ipadm_check_auth())
37446e91bba0SGirish Moodalbail 		return (IPADM_EAUTH);
37456e91bba0SGirish Moodalbail 
37464630c8beSGirish Moodalbail 	bzero(&ipaddr, sizeof (ipaddr));
37476e91bba0SGirish Moodalbail 	/* validate input */
37486e91bba0SGirish Moodalbail 	if (aobjname == NULL || strlcpy(ipaddr.ipadm_aobjname, aobjname,
37496e91bba0SGirish Moodalbail 	    IPADM_AOBJSIZ) >= IPADM_AOBJSIZ) {
37506e91bba0SGirish Moodalbail 		return (IPADM_INVALID_ARG);
37516e91bba0SGirish Moodalbail 	}
37526e91bba0SGirish Moodalbail 
37536e91bba0SGirish Moodalbail 	/* Retrieve the address object information. */
37546e91bba0SGirish Moodalbail 	status = i_ipadm_get_addrobj(iph, &ipaddr);
37556e91bba0SGirish Moodalbail 	if (status != IPADM_SUCCESS)
37566e91bba0SGirish Moodalbail 		return (status);
37576e91bba0SGirish Moodalbail 
37586e91bba0SGirish Moodalbail 	if (!(ipaddr.ipadm_flags & IPMGMT_ACTIVE))
37596e91bba0SGirish Moodalbail 		return (IPADM_OP_DISABLE_OBJ);
37606e91bba0SGirish Moodalbail 
37616e91bba0SGirish Moodalbail 	if (i_ipadm_is_vni(ipaddr.ipadm_ifname))
37626e91bba0SGirish Moodalbail 		return (IPADM_NOTSUP);
37636e91bba0SGirish Moodalbail 	if (inform && ipaddr.ipadm_atype != IPADM_ADDR_STATIC)
37646e91bba0SGirish Moodalbail 		return (IPADM_INVALID_ARG);
37656e91bba0SGirish Moodalbail 	af = ipaddr.ipadm_af;
37666e91bba0SGirish Moodalbail 	if (ipaddr.ipadm_atype == IPADM_ADDR_STATIC) {
37676e91bba0SGirish Moodalbail 		i_ipadm_addrobj2lifname(&ipaddr, lifname, sizeof (lifname));
37686e91bba0SGirish Moodalbail 		status = i_ipadm_get_flags(iph, lifname, af, &flags);
37696e91bba0SGirish Moodalbail 		if (status != IPADM_SUCCESS)
37706e91bba0SGirish Moodalbail 			return (status);
37716e91bba0SGirish Moodalbail 		if (inform) {
37724630c8beSGirish Moodalbail 			if (dhcp_start_agent(DHCP_IPC_MAX_WAIT) == -1)
37734630c8beSGirish Moodalbail 				return (IPADM_DHCP_START_ERROR);
37744630c8beSGirish Moodalbail 
37756e91bba0SGirish Moodalbail 			ipaddr.ipadm_wait = IPADM_DHCP_WAIT_DEFAULT;
37766e91bba0SGirish Moodalbail 			return (i_ipadm_op_dhcp(&ipaddr, DHCP_INFORM, NULL));
37776e91bba0SGirish Moodalbail 		}
37786e91bba0SGirish Moodalbail 		if (!(flags & IFF_DUPLICATE))
37796e91bba0SGirish Moodalbail 			return (IPADM_SUCCESS);
37806e91bba0SGirish Moodalbail 		status = i_ipadm_set_flags(iph, lifname, af, IFF_UP, 0);
37816e91bba0SGirish Moodalbail 	} else if (ipaddr.ipadm_atype == IPADM_ADDR_DHCP) {
3782b31320a7SChris Fraire 		status = i_ipadm_refresh_dhcp(&ipaddr);
37836e91bba0SGirish Moodalbail 	} else {
37846e91bba0SGirish Moodalbail 		status = IPADM_NOTSUP;
37856e91bba0SGirish Moodalbail 	}
37866e91bba0SGirish Moodalbail 	return (status);
37876e91bba0SGirish Moodalbail }
37886e91bba0SGirish Moodalbail 
3789b31320a7SChris Fraire /*
3790b31320a7SChris Fraire  * This is called from ipadm_refresh_addr() and i_ipadm_set_reqhost() to
3791b31320a7SChris Fraire  * send a DHCP_EXTEND message and possibly a DHCP_START message
3792b31320a7SChris Fraire  * to the dhcpagent.
3793b31320a7SChris Fraire  */
3794b31320a7SChris Fraire static ipadm_status_t
i_ipadm_refresh_dhcp(ipadm_addrobj_t ipaddr)3795b31320a7SChris Fraire i_ipadm_refresh_dhcp(ipadm_addrobj_t ipaddr)
3796b31320a7SChris Fraire {
3797b31320a7SChris Fraire 	ipadm_status_t		status;
3798b31320a7SChris Fraire 	int			dherr;
3799b31320a7SChris Fraire 
3800b31320a7SChris Fraire 	status = i_ipadm_op_dhcp(ipaddr, DHCP_EXTEND, &dherr);
3801b31320a7SChris Fraire 	/*
3802b31320a7SChris Fraire 	 * Restart the dhcp address negotiation with server if no
3803b31320a7SChris Fraire 	 * address has been acquired yet.
3804b31320a7SChris Fraire 	 */
3805b31320a7SChris Fraire 	if (status != IPADM_SUCCESS && dherr == DHCP_IPC_E_OUTSTATE) {
3806b31320a7SChris Fraire 		ipaddr->ipadm_wait = IPADM_DHCP_WAIT_DEFAULT;
3807b31320a7SChris Fraire 		status = i_ipadm_op_dhcp(ipaddr, DHCP_START, NULL);
3808b31320a7SChris Fraire 	}
3809b31320a7SChris Fraire 
3810b31320a7SChris Fraire 	return (status);
3811b31320a7SChris Fraire }
3812b31320a7SChris Fraire 
38136e91bba0SGirish Moodalbail /*
38146e91bba0SGirish Moodalbail  * This is called from ipadm_create_addr() to validate the address parameters.
38156e91bba0SGirish Moodalbail  * It does the following steps:
38166e91bba0SGirish Moodalbail  * 1. Validates the interface name.
38176e91bba0SGirish Moodalbail  * 2. Verifies that the interface is not an IPMP meta-interface or an
38186e91bba0SGirish Moodalbail  *	underlying interface.
38196e91bba0SGirish Moodalbail  * 3. In case of a persistent operation, verifies that the interface
38206e91bba0SGirish Moodalbail  *	is persistent. Returns error if interface is not enabled but
38216e91bba0SGirish Moodalbail  *	is in persistent config.
38226e91bba0SGirish Moodalbail  * 4. Verifies that the destination address is not set or the address type is
38236e91bba0SGirish Moodalbail  *	not DHCP or ADDRCONF when the interface is a loopback interface.
38246e91bba0SGirish Moodalbail  * 5. Verifies that the address type is not DHCP or ADDRCONF when the interface
38256e91bba0SGirish Moodalbail  *	has IFF_VRRP interface flag set.
38266e91bba0SGirish Moodalbail  */
38276e91bba0SGirish Moodalbail static ipadm_status_t
i_ipadm_validate_create_addr(ipadm_handle_t iph,ipadm_addrobj_t ipaddr,uint32_t flags)38286e91bba0SGirish Moodalbail i_ipadm_validate_create_addr(ipadm_handle_t iph, ipadm_addrobj_t ipaddr,
38296e91bba0SGirish Moodalbail     uint32_t flags)
38306e91bba0SGirish Moodalbail {
38316e91bba0SGirish Moodalbail 	sa_family_t		af;
38326e91bba0SGirish Moodalbail 	sa_family_t		other_af;
38336e91bba0SGirish Moodalbail 	char			*ifname;
38346e91bba0SGirish Moodalbail 	ipadm_status_t		status;
38356e91bba0SGirish Moodalbail 	boolean_t		legacy = (iph->iph_flags & IPH_LEGACY);
38366e91bba0SGirish Moodalbail 	boolean_t		islo, isvni;
38376e91bba0SGirish Moodalbail 	uint64_t		ifflags = 0;
38386e91bba0SGirish Moodalbail 	boolean_t		p_exists;
38396e91bba0SGirish Moodalbail 	boolean_t		af_exists, other_af_exists, a_exists;
38406e91bba0SGirish Moodalbail 
38416e91bba0SGirish Moodalbail 	if (ipaddr == NULL || flags == 0 || flags == IPADM_OPT_PERSIST ||
3842f6da83d4SAnurag S. Maskey 	    (flags & ~(IPADM_COMMON_OPT_MASK|IPADM_OPT_UP|IPADM_OPT_V46))) {
38436e91bba0SGirish Moodalbail 		return (IPADM_INVALID_ARG);
38446e91bba0SGirish Moodalbail 	}
38456e91bba0SGirish Moodalbail 
38466e91bba0SGirish Moodalbail 	if (ipaddr->ipadm_af == AF_UNSPEC)
38476e91bba0SGirish Moodalbail 		return (IPADM_BAD_ADDR);
38486e91bba0SGirish Moodalbail 
38496e91bba0SGirish Moodalbail 	if (!legacy && ipaddr->ipadm_lifnum != 0)
38506e91bba0SGirish Moodalbail 		return (IPADM_INVALID_ARG);
38516e91bba0SGirish Moodalbail 
38526e91bba0SGirish Moodalbail 	if (legacy && ipaddr->ipadm_atype != IPADM_ADDR_STATIC)
38536e91bba0SGirish Moodalbail 		return (IPADM_NOTSUP);
38546e91bba0SGirish Moodalbail 
38556e91bba0SGirish Moodalbail 	ifname = ipaddr->ipadm_ifname;
38566e91bba0SGirish Moodalbail 
3857a73be61aSHans Rosenfeld 	/*
3858a73be61aSHans Rosenfeld 	 * Do not go further when we are under ipmp.
3859a73be61aSHans Rosenfeld 	 * The interface is plumbed up and we are going to add
3860a73be61aSHans Rosenfeld 	 * NOFAILOVER address to make in.mpathd happy.
3861a73be61aSHans Rosenfeld 	 */
3862a73be61aSHans Rosenfeld 	if (i_ipadm_is_under_ipmp(iph, ifname))
3863a73be61aSHans Rosenfeld 		return (IPADM_SUCCESS);
38646e91bba0SGirish Moodalbail 
38656e91bba0SGirish Moodalbail 	af = ipaddr->ipadm_af;
38666e91bba0SGirish Moodalbail 	af_exists = ipadm_if_enabled(iph, ifname, af);
38676e91bba0SGirish Moodalbail 	/*
38686e91bba0SGirish Moodalbail 	 * For legacy case, interfaces are not implicitly plumbed. We need to
38696e91bba0SGirish Moodalbail 	 * check if the interface exists in the active configuration.
38706e91bba0SGirish Moodalbail 	 */
38716e91bba0SGirish Moodalbail 	if (legacy && !af_exists)
38726e91bba0SGirish Moodalbail 		return (IPADM_ENXIO);
38736e91bba0SGirish Moodalbail 
38746e91bba0SGirish Moodalbail 	other_af = (af == AF_INET ? AF_INET6 : AF_INET);
38756e91bba0SGirish Moodalbail 	other_af_exists = ipadm_if_enabled(iph, ifname, other_af);
38766e91bba0SGirish Moodalbail 	/*
38776e91bba0SGirish Moodalbail 	 * Check if one of the v4 or the v6 interfaces exists in the
38786e91bba0SGirish Moodalbail 	 * active configuration. An interface is considered disabled only
38796e91bba0SGirish Moodalbail 	 * if both v4 and v6 are not active.
38806e91bba0SGirish Moodalbail 	 */
38816e91bba0SGirish Moodalbail 	a_exists = (af_exists || other_af_exists);
38826e91bba0SGirish Moodalbail 
38836e91bba0SGirish Moodalbail 	/* Check if interface exists in the persistent configuration. */
38846e91bba0SGirish Moodalbail 	status = i_ipadm_if_pexists(iph, ifname, af, &p_exists);
38856e91bba0SGirish Moodalbail 	if (status != IPADM_SUCCESS)
38866e91bba0SGirish Moodalbail 		return (status);
3887a73be61aSHans Rosenfeld 
38886e91bba0SGirish Moodalbail 	if (!a_exists && p_exists)
38896e91bba0SGirish Moodalbail 		return (IPADM_OP_DISABLE_OBJ);
3890a73be61aSHans Rosenfeld 
38916e91bba0SGirish Moodalbail 	if (af_exists) {
38926e91bba0SGirish Moodalbail 		status = i_ipadm_get_flags(iph, ifname, af, &ifflags);
38936e91bba0SGirish Moodalbail 		if (status != IPADM_SUCCESS)
38946e91bba0SGirish Moodalbail 			return (status);
38956e91bba0SGirish Moodalbail 	}
38966e91bba0SGirish Moodalbail 
38976e91bba0SGirish Moodalbail 	/* Perform validation steps (4) and (5) */
38986e91bba0SGirish Moodalbail 	islo = i_ipadm_is_loopback(ifname);
38996e91bba0SGirish Moodalbail 	isvni = i_ipadm_is_vni(ifname);
39006e91bba0SGirish Moodalbail 	switch (ipaddr->ipadm_atype) {
39016e91bba0SGirish Moodalbail 	case IPADM_ADDR_STATIC:
39026e91bba0SGirish Moodalbail 		if ((islo || isvni) && ipaddr->ipadm_static_dname[0] != '\0')
39036e91bba0SGirish Moodalbail 			return (IPADM_INVALID_ARG);
39046e91bba0SGirish Moodalbail 		/* Check for a valid src address */
390564639aafSDarren Reed 		if (!legacy && sockaddrunspec(
390664639aafSDarren Reed 		    (struct sockaddr *)&ipaddr->ipadm_static_addr))
39076e91bba0SGirish Moodalbail 			return (IPADM_BAD_ADDR);
39086e91bba0SGirish Moodalbail 		break;
39096e91bba0SGirish Moodalbail 	case IPADM_ADDR_DHCP:
39106e91bba0SGirish Moodalbail 		if (islo || (ifflags & IFF_VRRP))
39116e91bba0SGirish Moodalbail 			return (IPADM_NOTSUP);
39126e91bba0SGirish Moodalbail 		break;
39136e91bba0SGirish Moodalbail 	case IPADM_ADDR_IPV6_ADDRCONF:
39146e91bba0SGirish Moodalbail 		if (islo || (ifflags & IFF_VRRP) ||
39156e91bba0SGirish Moodalbail 		    i_ipadm_is_6to4(iph, ifname)) {
39166e91bba0SGirish Moodalbail 			return (IPADM_NOTSUP);
39176e91bba0SGirish Moodalbail 		}
39186e91bba0SGirish Moodalbail 		break;
39196e91bba0SGirish Moodalbail 	default:
39206e91bba0SGirish Moodalbail 		return (IPADM_INVALID_ARG);
39216e91bba0SGirish Moodalbail 	}
39226e91bba0SGirish Moodalbail 
39236e91bba0SGirish Moodalbail 	return (IPADM_SUCCESS);
39246e91bba0SGirish Moodalbail }
39256e91bba0SGirish Moodalbail 
39266e91bba0SGirish Moodalbail ipadm_status_t
i_ipadm_merge_addrprops_from_nvl(nvlist_t * invl,nvlist_t * onvl,const char * aobjname)3927b31320a7SChris Fraire i_ipadm_merge_addrprops_from_nvl(nvlist_t *invl, nvlist_t *onvl,
39286e91bba0SGirish Moodalbail     const char *aobjname)
39296e91bba0SGirish Moodalbail {
3930b31320a7SChris Fraire 	const char * const	ADDRPROPS[] =
3931b31320a7SChris Fraire 	    { IPADM_NVP_PREFIXLEN, IPADM_NVP_REQHOST };
3932b31320a7SChris Fraire 	const size_t		ADDRPROPSLEN =
3933b31320a7SChris Fraire 	    sizeof (ADDRPROPS) / sizeof (*ADDRPROPS);
3934b31320a7SChris Fraire 	nvpair_t	*nvp, *propnvp;
39356e91bba0SGirish Moodalbail 	nvlist_t	*tnvl;
39366e91bba0SGirish Moodalbail 	char		*aname;
3937b31320a7SChris Fraire 	const char	*propname;
3938b31320a7SChris Fraire 	size_t		i;
39396e91bba0SGirish Moodalbail 	int		err;
39406e91bba0SGirish Moodalbail 
3941b31320a7SChris Fraire 	for (i = 0; i < ADDRPROPSLEN; ++i) {
3942b31320a7SChris Fraire 		propname = ADDRPROPS[i];
3943b31320a7SChris Fraire 
3944b31320a7SChris Fraire 		for (nvp = nvlist_next_nvpair(invl, NULL); nvp != NULL;
3945b31320a7SChris Fraire 		    nvp = nvlist_next_nvpair(invl, nvp)) {
3946b31320a7SChris Fraire 			if (nvpair_value_nvlist(nvp, &tnvl) == 0 &&
3947b31320a7SChris Fraire 			    nvlist_exists(tnvl, propname) &&
3948b31320a7SChris Fraire 			    nvlist_lookup_string(tnvl, IPADM_NVP_AOBJNAME,
3949b31320a7SChris Fraire 			    &aname) == 0 && strcmp(aname, aobjname) == 0) {
3950b31320a7SChris Fraire 
3951b31320a7SChris Fraire 				/*
3952b31320a7SChris Fraire 				 * property named `propname' exists for given
3953b31320a7SChris Fraire 				 * aobj
3954b31320a7SChris Fraire 				 */
3955b31320a7SChris Fraire 				(void) nvlist_lookup_nvpair(tnvl, propname,
3956b31320a7SChris Fraire 				    &propnvp);
3957b31320a7SChris Fraire 				err = nvlist_add_nvpair(onvl, propnvp);
3958b31320a7SChris Fraire 				if (err == 0) {
3959b31320a7SChris Fraire 					err = nvlist_remove(invl,
3960b31320a7SChris Fraire 					    nvpair_name(nvp), nvpair_type(nvp));
3961b31320a7SChris Fraire 				}
3962b31320a7SChris Fraire 				if (err != 0)
3963b31320a7SChris Fraire 					return (ipadm_errno2status(err));
3964b31320a7SChris Fraire 				break;
39656e91bba0SGirish Moodalbail 			}
39666e91bba0SGirish Moodalbail 		}
39676e91bba0SGirish Moodalbail 	}
39686e91bba0SGirish Moodalbail 	return (IPADM_SUCCESS);
39696e91bba0SGirish Moodalbail }
39706e91bba0SGirish Moodalbail 
39716e91bba0SGirish Moodalbail /*
39726e91bba0SGirish Moodalbail  * Re-enables the address object `aobjname' based on the saved
39736e91bba0SGirish Moodalbail  * configuration for `aobjname'.
39746e91bba0SGirish Moodalbail  */
39756e91bba0SGirish Moodalbail ipadm_status_t
ipadm_enable_addr(ipadm_handle_t iph,const char * aobjname,uint32_t flags)39766e91bba0SGirish Moodalbail ipadm_enable_addr(ipadm_handle_t iph, const char *aobjname, uint32_t flags)
39776e91bba0SGirish Moodalbail {
39786e91bba0SGirish Moodalbail 	nvlist_t	*addrnvl, *nvl;
39796e91bba0SGirish Moodalbail 	nvpair_t	*nvp;
39806e91bba0SGirish Moodalbail 	ipadm_status_t	status;
39816e91bba0SGirish Moodalbail 	struct ipadm_addrobj_s ipaddr;
39826e91bba0SGirish Moodalbail 
39836e91bba0SGirish Moodalbail 	/* check for solaris.network.interface.config authorization */
39846e91bba0SGirish Moodalbail 	if (!ipadm_check_auth())
39856e91bba0SGirish Moodalbail 		return (IPADM_EAUTH);
39866e91bba0SGirish Moodalbail 
39876e91bba0SGirish Moodalbail 	/* validate input */
39886e91bba0SGirish Moodalbail 	if (flags & IPADM_OPT_PERSIST)
39896e91bba0SGirish Moodalbail 		return (IPADM_NOTSUP);
39906e91bba0SGirish Moodalbail 	if (aobjname == NULL || strlcpy(ipaddr.ipadm_aobjname, aobjname,
39916e91bba0SGirish Moodalbail 	    IPADM_AOBJSIZ) >= IPADM_AOBJSIZ) {
39926e91bba0SGirish Moodalbail 		return (IPADM_INVALID_ARG);
39936e91bba0SGirish Moodalbail 	}
39946e91bba0SGirish Moodalbail 
39956e91bba0SGirish Moodalbail 	/* Retrieve the address object information. */
39966e91bba0SGirish Moodalbail 	status = i_ipadm_get_addrobj(iph, &ipaddr);
39976e91bba0SGirish Moodalbail 	if (status != IPADM_SUCCESS)
39986e91bba0SGirish Moodalbail 		return (status);
39996e91bba0SGirish Moodalbail 	if (ipaddr.ipadm_flags & IPMGMT_ACTIVE)
40006e91bba0SGirish Moodalbail 		return (IPADM_ADDROBJ_EXISTS);
40016e91bba0SGirish Moodalbail 
40026e91bba0SGirish Moodalbail 	status = i_ipadm_get_db_addr(iph, NULL, aobjname, &addrnvl);
40036e91bba0SGirish Moodalbail 	if (status != IPADM_SUCCESS)
40046e91bba0SGirish Moodalbail 		return (status);
40056e91bba0SGirish Moodalbail 
40066e91bba0SGirish Moodalbail 	assert(addrnvl != NULL);
40076e91bba0SGirish Moodalbail 
40086e91bba0SGirish Moodalbail 	for (nvp = nvlist_next_nvpair(addrnvl, NULL); nvp != NULL;
40096e91bba0SGirish Moodalbail 	    nvp = nvlist_next_nvpair(addrnvl, nvp)) {
4010a73be61aSHans Rosenfeld 		boolean_t set_init = B_FALSE;
4011a73be61aSHans Rosenfeld 
40126e91bba0SGirish Moodalbail 		if (nvpair_value_nvlist(nvp, &nvl) != 0)
40136e91bba0SGirish Moodalbail 			continue;
40146e91bba0SGirish Moodalbail 
40156e91bba0SGirish Moodalbail 		if (nvlist_exists(nvl, IPADM_NVP_IPV4ADDR) ||
4016b31320a7SChris Fraire 		    nvlist_exists(nvl, IPADM_NVP_IPV6ADDR) ||
4017b31320a7SChris Fraire 		    nvlist_exists(nvl, IPADM_NVP_DHCP)) {
4018b31320a7SChris Fraire 			status = i_ipadm_merge_addrprops_from_nvl(addrnvl, nvl,
40196e91bba0SGirish Moodalbail 			    aobjname);
40206e91bba0SGirish Moodalbail 			if (status != IPADM_SUCCESS)
40216e91bba0SGirish Moodalbail 				continue;
40226e91bba0SGirish Moodalbail 		}
4023a73be61aSHans Rosenfeld 
4024a73be61aSHans Rosenfeld 		/*
4025a73be61aSHans Rosenfeld 		 * ipadm_enable_addr() is never a persistent operation. We need
4026a73be61aSHans Rosenfeld 		 * to set IPH_INIT because ipmgmtd daemon does not have to write
4027a73be61aSHans Rosenfeld 		 * the address to the persistent db. The address is already
4028a73be61aSHans Rosenfeld 		 * available in the persistent db and we are here to re-enable
4029a73be61aSHans Rosenfeld 		 * the persistent configuration.
4030a73be61aSHans Rosenfeld 		 *
4031a73be61aSHans Rosenfeld 		 * But we need to make sure we're not accidentally clearing an
4032a73be61aSHans Rosenfeld 		 * IPH_INIT flag that was already set when we were called.
4033a73be61aSHans Rosenfeld 		 */
4034a73be61aSHans Rosenfeld 		if ((iph->iph_flags & IPH_INIT) == 0) {
4035a73be61aSHans Rosenfeld 			iph->iph_flags |= IPH_INIT;
4036a73be61aSHans Rosenfeld 			set_init = B_TRUE;
4037a73be61aSHans Rosenfeld 		}
4038a73be61aSHans Rosenfeld 
40396e91bba0SGirish Moodalbail 		status = i_ipadm_init_addrobj(iph, nvl);
4040a73be61aSHans Rosenfeld 
4041a73be61aSHans Rosenfeld 		if (set_init)
4042a73be61aSHans Rosenfeld 			iph->iph_flags &= ~IPH_INIT;
4043a73be61aSHans Rosenfeld 
40446e91bba0SGirish Moodalbail 		if (status != IPADM_SUCCESS)
40456e91bba0SGirish Moodalbail 			break;
40466e91bba0SGirish Moodalbail 	}
40476e91bba0SGirish Moodalbail 
4048b130c204SYuri Pankov 	nvlist_free(addrnvl);
40496e91bba0SGirish Moodalbail 	return (status);
40506e91bba0SGirish Moodalbail }
40516e91bba0SGirish Moodalbail 
40526e91bba0SGirish Moodalbail /*
40536e91bba0SGirish Moodalbail  * Disables the address object in `aobjname' from the active configuration.
40546e91bba0SGirish Moodalbail  * Error code return values follow the model in ipadm_delete_addr().
40556e91bba0SGirish Moodalbail  */
40566e91bba0SGirish Moodalbail ipadm_status_t
ipadm_disable_addr(ipadm_handle_t iph,const char * aobjname,uint32_t flags)40576e91bba0SGirish Moodalbail ipadm_disable_addr(ipadm_handle_t iph, const char *aobjname, uint32_t flags)
40586e91bba0SGirish Moodalbail {
40596e91bba0SGirish Moodalbail 	/* validate input */
40606e91bba0SGirish Moodalbail 	if (flags & IPADM_OPT_PERSIST)
40616e91bba0SGirish Moodalbail 		return (IPADM_NOTSUP);
40626e91bba0SGirish Moodalbail 
40636e91bba0SGirish Moodalbail 	return (ipadm_delete_addr(iph, aobjname, IPADM_OPT_ACTIVE));
40646e91bba0SGirish Moodalbail }
4065