16e91bba0SGirish Moodalbail /*
26e91bba0SGirish Moodalbail  * CDDL HEADER START
36e91bba0SGirish Moodalbail  *
46e91bba0SGirish Moodalbail  * The contents of this file are subject to the terms of the
56e91bba0SGirish Moodalbail  * Common Development and Distribution License (the "License").
66e91bba0SGirish Moodalbail  * You may not use this file except in compliance with the License.
76e91bba0SGirish Moodalbail  *
86e91bba0SGirish Moodalbail  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
96e91bba0SGirish Moodalbail  * or http://www.opensolaris.org/os/licensing.
106e91bba0SGirish Moodalbail  * See the License for the specific language governing permissions
116e91bba0SGirish Moodalbail  * and limitations under the License.
126e91bba0SGirish Moodalbail  *
136e91bba0SGirish Moodalbail  * When distributing Covered Code, include this CDDL HEADER in each
146e91bba0SGirish Moodalbail  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
156e91bba0SGirish Moodalbail  * If applicable, add the following below this CDDL HEADER, with the
166e91bba0SGirish Moodalbail  * fields enclosed by brackets "[]" replaced with your own identifying
176e91bba0SGirish Moodalbail  * information: Portions Copyright [yyyy] [name of copyright owner]
186e91bba0SGirish Moodalbail  *
196e91bba0SGirish Moodalbail  * CDDL HEADER END
206e91bba0SGirish Moodalbail  */
216e91bba0SGirish Moodalbail 
226e91bba0SGirish Moodalbail /*
23ec3706caSVasumathi Sundaram  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
24b31320a7SChris Fraire  * Copyright (c) 2016-2017, Chris Fraire <cfraire@me.com>.
250a8fc1cbSHans Rosenfeld  * Copyright 2021, Tintri by DDN. All rights reserved.
266e91bba0SGirish Moodalbail  */
276e91bba0SGirish Moodalbail 
286e91bba0SGirish Moodalbail /*
296e91bba0SGirish Moodalbail  * Main door handler functions used by ipmgmtd to process the different door
306e91bba0SGirish Moodalbail  * call requests, issued by the library libipadm.so.
316e91bba0SGirish Moodalbail  */
326e91bba0SGirish Moodalbail 
336e91bba0SGirish Moodalbail #include <alloca.h>
346e91bba0SGirish Moodalbail #include <pwd.h>
356e91bba0SGirish Moodalbail #include <auth_attr.h>
366e91bba0SGirish Moodalbail #include <secdb.h>
376e91bba0SGirish Moodalbail #include <stdlib.h>
386e91bba0SGirish Moodalbail #include <stdio.h>
396e91bba0SGirish Moodalbail #include <string.h>
406e91bba0SGirish Moodalbail #include <strings.h>
416e91bba0SGirish Moodalbail #include <errno.h>
426e91bba0SGirish Moodalbail #include <assert.h>
436e91bba0SGirish Moodalbail #include <libnvpair.h>
446e91bba0SGirish Moodalbail #include "ipmgmt_impl.h"
456e91bba0SGirish Moodalbail 
46*a73be61aSHans Rosenfeld 
47*a73be61aSHans Rosenfeld static void ipmgmt_common_handler(char *, char *, db_wfunc_t *);
48*a73be61aSHans Rosenfeld 
496e91bba0SGirish Moodalbail /* Handler declaration for each door command */
506e91bba0SGirish Moodalbail typedef void ipmgmt_door_handler_t(void *argp);
516e91bba0SGirish Moodalbail 
526e91bba0SGirish Moodalbail static ipmgmt_door_handler_t	ipmgmt_getaddr_handler,
536e91bba0SGirish Moodalbail 				ipmgmt_getprop_handler,
546e91bba0SGirish Moodalbail 				ipmgmt_getif_handler,
556e91bba0SGirish Moodalbail 				ipmgmt_initif_handler,
566e91bba0SGirish Moodalbail 				ipmgmt_aobjop_handler,
576e91bba0SGirish Moodalbail 				ipmgmt_resetaddr_handler,
586e91bba0SGirish Moodalbail 				ipmgmt_setif_handler,
596e91bba0SGirish Moodalbail 				ipmgmt_resetif_handler,
606e91bba0SGirish Moodalbail 				ipmgmt_resetprop_handler,
616e91bba0SGirish Moodalbail 				ipmgmt_setaddr_handler,
62*a73be61aSHans Rosenfeld 				ipmgmt_setprop_handler,
63*a73be61aSHans Rosenfeld 				ipmgmt_ipmp_update_handler;
646e91bba0SGirish Moodalbail 
656e91bba0SGirish Moodalbail typedef struct ipmgmt_door_info_s {
666e91bba0SGirish Moodalbail 	uint_t			idi_cmd;
676e91bba0SGirish Moodalbail 	boolean_t		idi_set;
686e91bba0SGirish Moodalbail 	ipmgmt_door_handler_t	*idi_handler;
696e91bba0SGirish Moodalbail } ipmgmt_door_info_t;
706e91bba0SGirish Moodalbail 
716e91bba0SGirish Moodalbail /* maps door commands to door handler functions */
726e91bba0SGirish Moodalbail static ipmgmt_door_info_t i_ipmgmt_door_info_tbl[] = {
736e91bba0SGirish Moodalbail 	{ IPMGMT_CMD_SETPROP,		B_TRUE,  ipmgmt_setprop_handler },
746e91bba0SGirish Moodalbail 	{ IPMGMT_CMD_SETIF,		B_TRUE,  ipmgmt_setif_handler },
756e91bba0SGirish Moodalbail 	{ IPMGMT_CMD_SETADDR,		B_TRUE,  ipmgmt_setaddr_handler },
766e91bba0SGirish Moodalbail 	{ IPMGMT_CMD_GETPROP,		B_FALSE, ipmgmt_getprop_handler },
776e91bba0SGirish Moodalbail 	{ IPMGMT_CMD_GETIF,		B_FALSE, ipmgmt_getif_handler },
786e91bba0SGirish Moodalbail 	{ IPMGMT_CMD_GETADDR,		B_FALSE, ipmgmt_getaddr_handler },
796e91bba0SGirish Moodalbail 	{ IPMGMT_CMD_RESETIF,		B_TRUE,  ipmgmt_resetif_handler },
806e91bba0SGirish Moodalbail 	{ IPMGMT_CMD_RESETADDR,		B_TRUE,  ipmgmt_resetaddr_handler },
816e91bba0SGirish Moodalbail 	{ IPMGMT_CMD_RESETPROP,		B_TRUE,  ipmgmt_resetprop_handler },
826e91bba0SGirish Moodalbail 	{ IPMGMT_CMD_INITIF,		B_TRUE,  ipmgmt_initif_handler },
836e91bba0SGirish Moodalbail 	{ IPMGMT_CMD_ADDROBJ_LOOKUPADD,	B_TRUE,  ipmgmt_aobjop_handler },
84ec3706caSVasumathi Sundaram 	{ IPMGMT_CMD_ADDROBJ_SETLIFNUM,	B_TRUE,  ipmgmt_aobjop_handler },
856e91bba0SGirish Moodalbail 	{ IPMGMT_CMD_ADDROBJ_ADD,	B_TRUE,  ipmgmt_aobjop_handler },
866e91bba0SGirish Moodalbail 	{ IPMGMT_CMD_AOBJNAME2ADDROBJ,	B_FALSE, ipmgmt_aobjop_handler },
876e91bba0SGirish Moodalbail 	{ IPMGMT_CMD_LIF2ADDROBJ,	B_FALSE, ipmgmt_aobjop_handler },
88*a73be61aSHans Rosenfeld 	{ IPMGMT_CMD_IPMP_UPDATE,	B_FALSE, ipmgmt_ipmp_update_handler},
896e91bba0SGirish Moodalbail 	{ 0, 0, NULL },
906e91bba0SGirish Moodalbail };
916e91bba0SGirish Moodalbail 
926e91bba0SGirish Moodalbail /*
936e91bba0SGirish Moodalbail  * The main server procedure function that gets invoked for any of the incoming
946e91bba0SGirish Moodalbail  * door commands. Inside this function we identify the incoming command and
956e91bba0SGirish Moodalbail  * invoke the right door handler function.
966e91bba0SGirish Moodalbail  */
976e91bba0SGirish Moodalbail /* ARGSUSED */
986e91bba0SGirish Moodalbail void
996e91bba0SGirish Moodalbail ipmgmt_handler(void *cookie, char *argp, size_t argsz, door_desc_t *dp,
1006e91bba0SGirish Moodalbail     uint_t n_desc)
1016e91bba0SGirish Moodalbail {
1026e91bba0SGirish Moodalbail 	ipmgmt_door_info_t	*infop = NULL;
1036e91bba0SGirish Moodalbail 	ipmgmt_retval_t		retval;
1046e91bba0SGirish Moodalbail 	int			i;
1056e91bba0SGirish Moodalbail 	uint_t			err;
1066e91bba0SGirish Moodalbail 	ucred_t			*cred = NULL;
1076e91bba0SGirish Moodalbail 
1086e91bba0SGirish Moodalbail 	for (i = 0; i_ipmgmt_door_info_tbl[i].idi_cmd != 0; i++) {
1096e91bba0SGirish Moodalbail 		if (i_ipmgmt_door_info_tbl[i].idi_cmd ==
1106e91bba0SGirish Moodalbail 		    ((ipmgmt_arg_t *)(void *)argp)->ia_cmd) {
1116e91bba0SGirish Moodalbail 			infop = &i_ipmgmt_door_info_tbl[i];
1126e91bba0SGirish Moodalbail 			break;
1136e91bba0SGirish Moodalbail 		}
1146e91bba0SGirish Moodalbail 	}
1156e91bba0SGirish Moodalbail 
1166e91bba0SGirish Moodalbail 	if (infop == NULL) {
1176e91bba0SGirish Moodalbail 		ipmgmt_log(LOG_ERR, "Invalid door command specified");
1186e91bba0SGirish Moodalbail 		err = EINVAL;
1196e91bba0SGirish Moodalbail 		goto fail;
1206e91bba0SGirish Moodalbail 	}
1216e91bba0SGirish Moodalbail 
1226e91bba0SGirish Moodalbail 	/* check for solaris.network.interface.config authorization */
1236e91bba0SGirish Moodalbail 	if (infop->idi_set) {
1246e91bba0SGirish Moodalbail 		uid_t		uid;
1256e91bba0SGirish Moodalbail 		struct passwd	pwd;
1266e91bba0SGirish Moodalbail 		char		buf[1024];
1276e91bba0SGirish Moodalbail 
1286e91bba0SGirish Moodalbail 		if (door_ucred(&cred) != 0) {
1296e91bba0SGirish Moodalbail 			err = errno;
1306e91bba0SGirish Moodalbail 			ipmgmt_log(LOG_ERR, "Could not get user credentials.");
1316e91bba0SGirish Moodalbail 			goto fail;
1326e91bba0SGirish Moodalbail 		}
1336e91bba0SGirish Moodalbail 		uid = ucred_getruid(cred);
1346e91bba0SGirish Moodalbail 		if ((int)uid < 0) {
1356e91bba0SGirish Moodalbail 			err = errno;
1366e91bba0SGirish Moodalbail 			ipmgmt_log(LOG_ERR, "Could not get user id.");
1376e91bba0SGirish Moodalbail 			goto fail;
1386e91bba0SGirish Moodalbail 		}
1396e91bba0SGirish Moodalbail 		if (getpwuid_r(uid, &pwd, buf, sizeof (buf)) ==
1406e91bba0SGirish Moodalbail 		    NULL) {
1416e91bba0SGirish Moodalbail 			err = errno;
1426e91bba0SGirish Moodalbail 			ipmgmt_log(LOG_ERR, "Could not get password entry.");
1436e91bba0SGirish Moodalbail 			goto fail;
1446e91bba0SGirish Moodalbail 		}
1456e91bba0SGirish Moodalbail 		if (chkauthattr(NETWORK_INTERFACE_CONFIG_AUTH,
1466e91bba0SGirish Moodalbail 		    pwd.pw_name) != 1) {
1476e91bba0SGirish Moodalbail 			err = EPERM;
1486e91bba0SGirish Moodalbail 			ipmgmt_log(LOG_ERR, "Not authorized for operation.");
1496e91bba0SGirish Moodalbail 			goto fail;
1506e91bba0SGirish Moodalbail 		}
1516e91bba0SGirish Moodalbail 		ucred_free(cred);
1526e91bba0SGirish Moodalbail 	}
1536e91bba0SGirish Moodalbail 
1546e91bba0SGirish Moodalbail 	/* individual handlers take care of calling door_return */
1556e91bba0SGirish Moodalbail 	infop->idi_handler((void *)argp);
1566e91bba0SGirish Moodalbail 	return;
1576e91bba0SGirish Moodalbail fail:
1586e91bba0SGirish Moodalbail 	ucred_free(cred);
1596e91bba0SGirish Moodalbail 	retval.ir_err = err;
1606e91bba0SGirish Moodalbail 	(void) door_return((char *)&retval, sizeof (retval), NULL, 0);
1616e91bba0SGirish Moodalbail }
1626e91bba0SGirish Moodalbail 
1636e91bba0SGirish Moodalbail /*
1646e91bba0SGirish Moodalbail  * Handles the door command IPMGMT_CMD_GETPROP. It retrieves the persisted
1656e91bba0SGirish Moodalbail  * property value for the given property.
1666e91bba0SGirish Moodalbail  */
1676e91bba0SGirish Moodalbail static void
1686e91bba0SGirish Moodalbail ipmgmt_getprop_handler(void *argp)
1696e91bba0SGirish Moodalbail {
1706e91bba0SGirish Moodalbail 	ipmgmt_prop_arg_t	*pargp = argp;
1716e91bba0SGirish Moodalbail 	ipmgmt_getprop_rval_t	rval, *rvalp = &rval;
1726e91bba0SGirish Moodalbail 
1736e91bba0SGirish Moodalbail 	assert(pargp->ia_cmd == IPMGMT_CMD_GETPROP);
1746e91bba0SGirish Moodalbail 
1756e91bba0SGirish Moodalbail 	rvalp->ir_err = ipmgmt_db_walk(ipmgmt_db_getprop, pargp, IPADM_DB_READ);
1766e91bba0SGirish Moodalbail 	if (rvalp->ir_err == 0)
1776e91bba0SGirish Moodalbail 		(void) strlcpy(rvalp->ir_pval, pargp->ia_pval,
1786e91bba0SGirish Moodalbail 		    sizeof (rvalp->ir_pval));
1796e91bba0SGirish Moodalbail 	(void) door_return((char *)rvalp, sizeof (*rvalp), NULL, 0);
1806e91bba0SGirish Moodalbail }
1816e91bba0SGirish Moodalbail 
1826e91bba0SGirish Moodalbail /*
1836e91bba0SGirish Moodalbail  * Handles the door command IPMGMT_CMD_SETPROP. It persists the property value
1846e91bba0SGirish Moodalbail  * for the given property in the DB.
1856e91bba0SGirish Moodalbail  */
1866e91bba0SGirish Moodalbail static void
1876e91bba0SGirish Moodalbail ipmgmt_setprop_handler(void *argp)
1886e91bba0SGirish Moodalbail {
1896e91bba0SGirish Moodalbail 	ipmgmt_prop_arg_t	*pargp = argp;
1906e91bba0SGirish Moodalbail 	ipmgmt_retval_t		rval;
1916e91bba0SGirish Moodalbail 	ipadm_dbwrite_cbarg_t	cb;
1926e91bba0SGirish Moodalbail 	nvlist_t		*nvl = NULL;
1936e91bba0SGirish Moodalbail 	int			err;
1946e91bba0SGirish Moodalbail 
1956e91bba0SGirish Moodalbail 	assert(pargp->ia_cmd == IPMGMT_CMD_SETPROP);
1966e91bba0SGirish Moodalbail 
1976e91bba0SGirish Moodalbail 	if ((err = nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0)) != 0)
1986e91bba0SGirish Moodalbail 		goto fail;
1996e91bba0SGirish Moodalbail 	if (pargp->ia_module[0] != '\0' &&
2006e91bba0SGirish Moodalbail 	    (err = nvlist_add_string(nvl, IPADM_NVP_PROTONAME,
2016e91bba0SGirish Moodalbail 	    pargp->ia_module)) != 0) {
2026e91bba0SGirish Moodalbail 		goto fail;
2036e91bba0SGirish Moodalbail 	}
2046e91bba0SGirish Moodalbail 	if (pargp->ia_ifname[0] != '\0' &&
2056e91bba0SGirish Moodalbail 	    (err = nvlist_add_string(nvl, IPADM_NVP_IFNAME,
2066e91bba0SGirish Moodalbail 	    pargp->ia_ifname)) != 0)
2076e91bba0SGirish Moodalbail 		goto fail;
2086e91bba0SGirish Moodalbail 	if (pargp->ia_aobjname[0] != '\0' &&
2096e91bba0SGirish Moodalbail 	    (err = nvlist_add_string(nvl, IPADM_NVP_AOBJNAME,
2106e91bba0SGirish Moodalbail 	    pargp->ia_aobjname)) != 0)
2116e91bba0SGirish Moodalbail 		goto fail;
2126e91bba0SGirish Moodalbail 	if ((err = nvlist_add_string(nvl, pargp->ia_pname,
2136e91bba0SGirish Moodalbail 	    pargp->ia_pval)) != 0)
2146e91bba0SGirish Moodalbail 		goto fail;
2156e91bba0SGirish Moodalbail 
2166e91bba0SGirish Moodalbail 	cb.dbw_nvl = nvl;
2176e91bba0SGirish Moodalbail 	cb.dbw_flags = pargp->ia_flags;
2186e91bba0SGirish Moodalbail 	err = ipmgmt_db_walk(ipmgmt_db_update, &cb, IPADM_DB_WRITE);
2196e91bba0SGirish Moodalbail fail:
2206e91bba0SGirish Moodalbail 	nvlist_free(nvl);
2216e91bba0SGirish Moodalbail 	rval.ir_err = err;
2226e91bba0SGirish Moodalbail 	(void) door_return((char *)&rval, sizeof (rval), NULL, 0);
2236e91bba0SGirish Moodalbail }
2246e91bba0SGirish Moodalbail 
2256e91bba0SGirish Moodalbail /*
2266e91bba0SGirish Moodalbail  * Helper function for ipmgmt_setaddr_handler().
2276e91bba0SGirish Moodalbail  * It converts the nvlist_t, `nvl', to aobjmap node `nodep'.
2286e91bba0SGirish Moodalbail  */
2296e91bba0SGirish Moodalbail static int
2306e91bba0SGirish Moodalbail i_ipmgmt_nvl2aobjnode(nvlist_t *nvl, ipmgmt_aobjmap_t *nodep)
2316e91bba0SGirish Moodalbail {
2326e91bba0SGirish Moodalbail 	char			*aobjname = NULL, *ifname = NULL;
2336e91bba0SGirish Moodalbail 	int32_t			lnum;
2346e91bba0SGirish Moodalbail 	nvlist_t		*nvladdr;
2356e91bba0SGirish Moodalbail 	sa_family_t		af = AF_UNSPEC;
2366e91bba0SGirish Moodalbail 	ipadm_addr_type_t	addrtype = IPADM_ADDR_NONE;
2376e91bba0SGirish Moodalbail 	int			err = 0;
2386e91bba0SGirish Moodalbail 
2396e91bba0SGirish Moodalbail 	/*
2406e91bba0SGirish Moodalbail 	 * Retrieve all the information needed to build '*nodep' from
2416e91bba0SGirish Moodalbail 	 * nvlist_t nvl.
2426e91bba0SGirish Moodalbail 	 */
2436e91bba0SGirish Moodalbail 	if ((err = nvlist_lookup_string(nvl, IPADM_NVP_AOBJNAME,
2446e91bba0SGirish Moodalbail 	    &aobjname)) != 0 ||
2456e91bba0SGirish Moodalbail 	    (err = nvlist_lookup_string(nvl, IPADM_NVP_IFNAME, &ifname)) != 0 ||
2466e91bba0SGirish Moodalbail 	    (err = nvlist_lookup_int32(nvl, IPADM_NVP_LIFNUM, &lnum)) != 0) {
2476e91bba0SGirish Moodalbail 		return (err);
2486e91bba0SGirish Moodalbail 	}
2496e91bba0SGirish Moodalbail 	if (nvlist_exists(nvl, IPADM_NVP_IPV4ADDR)) {
2506e91bba0SGirish Moodalbail 		af = AF_INET;
2516e91bba0SGirish Moodalbail 		addrtype = IPADM_ADDR_STATIC;
252b31320a7SChris Fraire 	} else if (nvlist_lookup_nvlist(nvl, IPADM_NVP_DHCP, &nvladdr) == 0) {
253b31320a7SChris Fraire 		char	*reqhost;
254b31320a7SChris Fraire 
2556e91bba0SGirish Moodalbail 		af = AF_INET;
2566e91bba0SGirish Moodalbail 		addrtype = IPADM_ADDR_DHCP;
257b31320a7SChris Fraire 
258b31320a7SChris Fraire 		/*
259b31320a7SChris Fraire 		 * ipmgmt_am_reqhost comes through in `nvl' for purposes of
260b31320a7SChris Fraire 		 * updating the cached representation, but it is persisted as
261b31320a7SChris Fraire 		 * a stand-alone DB line; so remove it after copying it.
262b31320a7SChris Fraire 		 */
263b31320a7SChris Fraire 		if (!nvlist_exists(nvl, IPADM_NVP_REQHOST)) {
264b31320a7SChris Fraire 			*nodep->ipmgmt_am_reqhost = '\0';
265b31320a7SChris Fraire 		} else {
266b31320a7SChris Fraire 			if ((err = nvlist_lookup_string(nvl, IPADM_NVP_REQHOST,
267b31320a7SChris Fraire 			    &reqhost)) != 0)
268b31320a7SChris Fraire 				return (err);
269b31320a7SChris Fraire 
270b31320a7SChris Fraire 			(void) strlcpy(nodep->ipmgmt_am_reqhost, reqhost,
271b31320a7SChris Fraire 			    sizeof (nodep->ipmgmt_am_reqhost));
272b31320a7SChris Fraire 			(void) nvlist_remove(nvl, IPADM_NVP_REQHOST,
273b31320a7SChris Fraire 			    DATA_TYPE_STRING);
274b31320a7SChris Fraire 		}
2756e91bba0SGirish Moodalbail 	} else if (nvlist_exists(nvl, IPADM_NVP_IPV6ADDR)) {
2766e91bba0SGirish Moodalbail 		af = AF_INET6;
2776e91bba0SGirish Moodalbail 		addrtype = IPADM_ADDR_STATIC;
2786e91bba0SGirish Moodalbail 	} else if (nvlist_lookup_nvlist(nvl, IPADM_NVP_INTFID, &nvladdr) == 0) {
279b31320a7SChris Fraire 		struct sockaddr_in6		sin6 = {0};
2806e91bba0SGirish Moodalbail 		uint8_t	*addr6;
2816e91bba0SGirish Moodalbail 		uint32_t plen;
282b31320a7SChris Fraire 		uint_t	n;
2836e91bba0SGirish Moodalbail 
2846e91bba0SGirish Moodalbail 		af = AF_INET6;
2856e91bba0SGirish Moodalbail 		addrtype = IPADM_ADDR_IPV6_ADDRCONF;
2866e91bba0SGirish Moodalbail 		if (nvlist_lookup_uint32(nvladdr, IPADM_NVP_PREFIXLEN,
2876e91bba0SGirish Moodalbail 		    &plen) != 0)
2886e91bba0SGirish Moodalbail 			return (EINVAL);
2896e91bba0SGirish Moodalbail 		if (plen != 0) {
2906e91bba0SGirish Moodalbail 			if (nvlist_lookup_uint8_array(nvladdr,
2916e91bba0SGirish Moodalbail 			    IPADM_NVP_IPNUMADDR, &addr6, &n) != 0)
2926e91bba0SGirish Moodalbail 				return (EINVAL);
293b31320a7SChris Fraire 			bcopy(addr6, &sin6.sin6_addr, n);
2946e91bba0SGirish Moodalbail 		}
295b31320a7SChris Fraire 
296b31320a7SChris Fraire 		nodep->ipmgmt_am_linklocal = B_TRUE;
297b31320a7SChris Fraire 		nodep->ipmgmt_am_ifid = sin6;
2986e91bba0SGirish Moodalbail 	}
2996e91bba0SGirish Moodalbail 
3006e91bba0SGirish Moodalbail 	/*
301b31320a7SChris Fraire 	 * populate the non-addrtype-specific `*nodep' with retrieved values.
3026e91bba0SGirish Moodalbail 	 */
3036e91bba0SGirish Moodalbail 	(void) strlcpy(nodep->am_ifname, ifname, sizeof (nodep->am_ifname));
3046e91bba0SGirish Moodalbail 	(void) strlcpy(nodep->am_aobjname, aobjname,
3056e91bba0SGirish Moodalbail 	    sizeof (nodep->am_aobjname));
3066e91bba0SGirish Moodalbail 	nodep->am_lnum = lnum;
3076e91bba0SGirish Moodalbail 	nodep->am_family = af;
3086e91bba0SGirish Moodalbail 	nodep->am_atype = addrtype;
3096e91bba0SGirish Moodalbail 	nodep->am_next = NULL;
3106e91bba0SGirish Moodalbail 
3116e91bba0SGirish Moodalbail 	/*
3126e91bba0SGirish Moodalbail 	 * Do not store logical interface number in persistent store as it
3136e91bba0SGirish Moodalbail 	 * takes different value on reboot. So remove it from `nvl'.
3146e91bba0SGirish Moodalbail 	 */
3156e91bba0SGirish Moodalbail 	if (nvlist_exists(nvl, IPADM_NVP_LIFNUM))
3166e91bba0SGirish Moodalbail 		(void) nvlist_remove(nvl, IPADM_NVP_LIFNUM, DATA_TYPE_INT32);
3176e91bba0SGirish Moodalbail 
3186e91bba0SGirish Moodalbail 	return (0);
3196e91bba0SGirish Moodalbail }
3206e91bba0SGirish Moodalbail 
3216e91bba0SGirish Moodalbail /*
3226e91bba0SGirish Moodalbail  * Handles the door command IPMGMT_CMD_SETADDR. It adds a new address object
323b31320a7SChris Fraire  * node to the list `aobjmap' and optionally persists the address
324b31320a7SChris Fraire  * information in the DB.
3256e91bba0SGirish Moodalbail  */
3266e91bba0SGirish Moodalbail static void
3276e91bba0SGirish Moodalbail ipmgmt_setaddr_handler(void *argp)
3286e91bba0SGirish Moodalbail {
3296e91bba0SGirish Moodalbail 	ipmgmt_setaddr_arg_t	*sargp = argp;
3306e91bba0SGirish Moodalbail 	ipmgmt_retval_t		rval;
331b31320a7SChris Fraire 	ipmgmt_aobjmap_t	node = {0};
3326e91bba0SGirish Moodalbail 	nvlist_t		*nvl = NULL;
3336e91bba0SGirish Moodalbail 	char			*nvlbuf;
3346e91bba0SGirish Moodalbail 	size_t			nvlsize = sargp->ia_nvlsize;
3356e91bba0SGirish Moodalbail 	uint32_t		flags = sargp->ia_flags;
3366e91bba0SGirish Moodalbail 	int			err = 0;
3376e91bba0SGirish Moodalbail 
3386e91bba0SGirish Moodalbail 	nvlbuf = (char *)argp + sizeof (ipmgmt_setaddr_arg_t);
3390d1087e8SHans Rosenfeld 	if ((err = nvlist_unpack(nvlbuf, nvlsize, &nvl, 0)) != 0)
3406e91bba0SGirish Moodalbail 		goto ret;
3416e91bba0SGirish Moodalbail 	if (flags & (IPMGMT_ACTIVE|IPMGMT_INIT)) {
3426e91bba0SGirish Moodalbail 		if ((err = i_ipmgmt_nvl2aobjnode(nvl, &node)) != 0)
3436e91bba0SGirish Moodalbail 			goto ret;
3446e91bba0SGirish Moodalbail 		if (flags & IPMGMT_INIT)
3456e91bba0SGirish Moodalbail 			node.am_flags = (IPMGMT_ACTIVE|IPMGMT_PERSIST);
3466e91bba0SGirish Moodalbail 		else
347b31320a7SChris Fraire 			node.am_flags = flags & ~IPMGMT_PROPS_ONLY;
3486e91bba0SGirish Moodalbail 		if ((err = ipmgmt_aobjmap_op(&node, ADDROBJ_ADD)) != 0)
3496e91bba0SGirish Moodalbail 			goto ret;
3506e91bba0SGirish Moodalbail 	}
351b31320a7SChris Fraire 	if ((flags & IPMGMT_PERSIST) && !(flags & IPMGMT_PROPS_ONLY)) {
3526e91bba0SGirish Moodalbail 		ipadm_dbwrite_cbarg_t	cb;
3536e91bba0SGirish Moodalbail 
3546e91bba0SGirish Moodalbail 		cb.dbw_nvl = nvl;
3556e91bba0SGirish Moodalbail 		cb.dbw_flags = 0;
3566e91bba0SGirish Moodalbail 		err = ipmgmt_db_walk(ipmgmt_db_add, &cb, IPADM_DB_WRITE);
3576e91bba0SGirish Moodalbail 	}
3586e91bba0SGirish Moodalbail ret:
3596e91bba0SGirish Moodalbail 	nvlist_free(nvl);
3606e91bba0SGirish Moodalbail 	rval.ir_err = err;
3616e91bba0SGirish Moodalbail 	(void) door_return((char *)&rval, sizeof (rval), NULL, 0);
3626e91bba0SGirish Moodalbail }
3636e91bba0SGirish Moodalbail 
3646e91bba0SGirish Moodalbail /*
365b31320a7SChris Fraire  * Handles the door commands that read or modify the `aobjmap' structure.
3666e91bba0SGirish Moodalbail  *
3676e91bba0SGirish Moodalbail  * IPMGMT_CMD_ADDROBJ_LOOKUPADD - places a stub address object in `aobjmap'
3686e91bba0SGirish Moodalbail  *	after ensuring that the namespace is not taken. If required, also
3696e91bba0SGirish Moodalbail  *	generates an `aobjname' for address object for the library to use.
3706e91bba0SGirish Moodalbail  * IPMGMT_CMD_ADDROBJ_ADD - add/update address object in `aobjmap'
3716e91bba0SGirish Moodalbail  * IPMGMT_CMD_LIF2ADDROBJ - given a logical interface, return address object
3726e91bba0SGirish Moodalbail  *	associated with that logical interface.
3736e91bba0SGirish Moodalbail  * IPMGMT_CMD_AOBJNAME2ADDROBJ - given an address object name return logical
3746e91bba0SGirish Moodalbail  *	interface associated with that address object.
3756e91bba0SGirish Moodalbail  */
3766e91bba0SGirish Moodalbail static void
3776e91bba0SGirish Moodalbail ipmgmt_aobjop_handler(void *argp)
3786e91bba0SGirish Moodalbail {
3796e91bba0SGirish Moodalbail 	ipmgmt_aobjop_arg_t	*largp = argp;
3806e91bba0SGirish Moodalbail 	ipmgmt_retval_t		rval;
3816e91bba0SGirish Moodalbail 	ipmgmt_aobjop_rval_t	aobjrval;
3826e91bba0SGirish Moodalbail 	void			*rvalp;
3836e91bba0SGirish Moodalbail 	size_t			rsize;
3846e91bba0SGirish Moodalbail 	ipmgmt_aobjmap_t	node;
3856e91bba0SGirish Moodalbail 	int			err = 0;
3866e91bba0SGirish Moodalbail 	char			*ifname = largp->ia_ifname;
3876e91bba0SGirish Moodalbail 	char			*aobjname = largp->ia_aobjname;
3886e91bba0SGirish Moodalbail 	int32_t			lnum = largp->ia_lnum;
3896e91bba0SGirish Moodalbail 	sa_family_t		af = largp->ia_family;
3906e91bba0SGirish Moodalbail 	ipadm_addr_type_t	atype = largp->ia_atype;
3916e91bba0SGirish Moodalbail 	ipmgmt_aobjmap_t	*head;
3926e91bba0SGirish Moodalbail 
3936e91bba0SGirish Moodalbail 	switch (largp->ia_cmd) {
3946e91bba0SGirish Moodalbail 	case IPMGMT_CMD_ADDROBJ_LOOKUPADD:
3956e91bba0SGirish Moodalbail 		rsize = sizeof (ipmgmt_aobjop_rval_t);
3966e91bba0SGirish Moodalbail 		rvalp = &aobjrval;
3976e91bba0SGirish Moodalbail 		bzero(&node, sizeof (node));
3986e91bba0SGirish Moodalbail 		(void) strlcpy(node.am_aobjname, aobjname,
3996e91bba0SGirish Moodalbail 		    sizeof (node.am_aobjname));
4006e91bba0SGirish Moodalbail 		(void) strlcpy(node.am_ifname, ifname,
4016e91bba0SGirish Moodalbail 		    sizeof (node.am_ifname));
4026e91bba0SGirish Moodalbail 		node.am_family = af;
403ec3706caSVasumathi Sundaram 		node.am_atype = atype;
4046e91bba0SGirish Moodalbail 		/* no logical number is associated with this addrobj yet */
4056e91bba0SGirish Moodalbail 		node.am_lnum = -1;
4066e91bba0SGirish Moodalbail 		/* The address object is not persisted yet. */
4076e91bba0SGirish Moodalbail 		node.am_flags = IPMGMT_ACTIVE;
4086e91bba0SGirish Moodalbail 		err = ipmgmt_aobjmap_op(&node, ADDROBJ_LOOKUPADD);
4096e91bba0SGirish Moodalbail 		if (err == 0) {
4106e91bba0SGirish Moodalbail 			(void) strlcpy(aobjrval.ir_aobjname, node.am_aobjname,
4116e91bba0SGirish Moodalbail 			    sizeof (aobjrval.ir_aobjname));
4126e91bba0SGirish Moodalbail 		}
4136e91bba0SGirish Moodalbail 		break;
414ec3706caSVasumathi Sundaram 	case IPMGMT_CMD_ADDROBJ_SETLIFNUM:
415ec3706caSVasumathi Sundaram 		rsize = sizeof (ipmgmt_retval_t);
416ec3706caSVasumathi Sundaram 		rvalp = &rval;
417ec3706caSVasumathi Sundaram 		bzero(&node, sizeof (node));
418ec3706caSVasumathi Sundaram 		(void) strlcpy(node.am_aobjname, aobjname,
419ec3706caSVasumathi Sundaram 		    sizeof (node.am_aobjname));
420ec3706caSVasumathi Sundaram 		(void) strlcpy(node.am_ifname, ifname,
421ec3706caSVasumathi Sundaram 		    sizeof (node.am_ifname));
422ec3706caSVasumathi Sundaram 		node.am_family = af;
423ec3706caSVasumathi Sundaram 		node.am_lnum = lnum;
424ec3706caSVasumathi Sundaram 		err = ipmgmt_aobjmap_op(&node, ADDROBJ_SETLIFNUM);
425ec3706caSVasumathi Sundaram 		break;
4266e91bba0SGirish Moodalbail 	case IPMGMT_CMD_ADDROBJ_ADD:
4276e91bba0SGirish Moodalbail 		rsize = sizeof (ipmgmt_retval_t);
4286e91bba0SGirish Moodalbail 		rvalp = &rval;
4296e91bba0SGirish Moodalbail 		if (aobjname[0] == '\0' || ifname[0] == '\0' || lnum == -1 ||
4306e91bba0SGirish Moodalbail 		    af == AF_UNSPEC) {
4316e91bba0SGirish Moodalbail 			err = EINVAL;
4326e91bba0SGirish Moodalbail 			break;
4336e91bba0SGirish Moodalbail 		}
4346e91bba0SGirish Moodalbail 		bzero(&node, sizeof (node));
4356e91bba0SGirish Moodalbail 		(void) strlcpy(node.am_aobjname, aobjname,
4366e91bba0SGirish Moodalbail 		    sizeof (node.am_aobjname));
4376e91bba0SGirish Moodalbail 		(void) strlcpy(node.am_ifname, ifname,
4386e91bba0SGirish Moodalbail 		    sizeof (node.am_ifname));
4396e91bba0SGirish Moodalbail 		node.am_atype = atype;
4406e91bba0SGirish Moodalbail 		node.am_lnum = lnum;
4416e91bba0SGirish Moodalbail 		node.am_family = af;
4426e91bba0SGirish Moodalbail 		/* The address object is not persisted. */
4436e91bba0SGirish Moodalbail 		node.am_flags = IPMGMT_ACTIVE;
4446e91bba0SGirish Moodalbail 		err = ipmgmt_aobjmap_op(&node, ADDROBJ_ADD);
4456e91bba0SGirish Moodalbail 		break;
4466e91bba0SGirish Moodalbail 	case IPMGMT_CMD_AOBJNAME2ADDROBJ:
4476e91bba0SGirish Moodalbail 		rsize = sizeof (ipmgmt_aobjop_rval_t);
4486e91bba0SGirish Moodalbail 		rvalp = &aobjrval;
4496e91bba0SGirish Moodalbail 		bzero(&aobjrval, sizeof (aobjrval));
4506e91bba0SGirish Moodalbail 		if (aobjname[0] == '\0') {
4516e91bba0SGirish Moodalbail 			err = EINVAL;
4526e91bba0SGirish Moodalbail 			break;
4536e91bba0SGirish Moodalbail 		}
4546e91bba0SGirish Moodalbail 		(void) pthread_rwlock_rdlock(&aobjmap.aobjmap_rwlock);
4556e91bba0SGirish Moodalbail 		head = aobjmap.aobjmap_head;
4566e91bba0SGirish Moodalbail 		for (; head; head = head->am_next) {
4576e91bba0SGirish Moodalbail 			if (strcmp(head->am_aobjname, aobjname) != 0)
4586e91bba0SGirish Moodalbail 				continue;
4596e91bba0SGirish Moodalbail 			/*
4606e91bba0SGirish Moodalbail 			 * For an auto-configured interface, return
4616e91bba0SGirish Moodalbail 			 * the lifnum that has the link-local on it.
4626e91bba0SGirish Moodalbail 			 * Other logical interfaces were created for
4636e91bba0SGirish Moodalbail 			 * prefixes and dhcpv6 addresses and do not
4646e91bba0SGirish Moodalbail 			 * have am_ifid set.
4656e91bba0SGirish Moodalbail 			 */
4666e91bba0SGirish Moodalbail 			if (head->am_atype != IPADM_ADDR_IPV6_ADDRCONF ||
467b31320a7SChris Fraire 			    head->ipmgmt_am_linklocal) {
4686e91bba0SGirish Moodalbail 				break;
4696e91bba0SGirish Moodalbail 			}
4706e91bba0SGirish Moodalbail 		}
4716e91bba0SGirish Moodalbail 		if (head == NULL) {
4726e91bba0SGirish Moodalbail 			err = ENOENT;
4736e91bba0SGirish Moodalbail 			(void) pthread_rwlock_unlock(&aobjmap.aobjmap_rwlock);
4746e91bba0SGirish Moodalbail 			break;
4756e91bba0SGirish Moodalbail 		}
4766e91bba0SGirish Moodalbail 		(void) strlcpy(aobjrval.ir_ifname, head->am_ifname,
4776e91bba0SGirish Moodalbail 		    sizeof (aobjrval.ir_ifname));
4786e91bba0SGirish Moodalbail 		aobjrval.ir_lnum = head->am_lnum;
4796e91bba0SGirish Moodalbail 		aobjrval.ir_family = head->am_family;
4806e91bba0SGirish Moodalbail 		aobjrval.ir_flags = head->am_flags;
4816e91bba0SGirish Moodalbail 		aobjrval.ir_atype = head->am_atype;
482b31320a7SChris Fraire 		aobjrval.ir_atype_cache = head->am_atype_cache;
4836e91bba0SGirish Moodalbail 		(void) pthread_rwlock_unlock(&aobjmap.aobjmap_rwlock);
4846e91bba0SGirish Moodalbail 		break;
4856e91bba0SGirish Moodalbail 	case IPMGMT_CMD_LIF2ADDROBJ:
4866e91bba0SGirish Moodalbail 		rsize = sizeof (ipmgmt_aobjop_rval_t);
4876e91bba0SGirish Moodalbail 		rvalp = &aobjrval;
4886e91bba0SGirish Moodalbail 		bzero(&aobjrval, sizeof (aobjrval));
4896e91bba0SGirish Moodalbail 		if (ifname[0] == '\0') {
4906e91bba0SGirish Moodalbail 			err = EINVAL;
4916e91bba0SGirish Moodalbail 			break;
4926e91bba0SGirish Moodalbail 		}
4936e91bba0SGirish Moodalbail 		(void) pthread_rwlock_rdlock(&aobjmap.aobjmap_rwlock);
4946e91bba0SGirish Moodalbail 		head = aobjmap.aobjmap_head;
4956e91bba0SGirish Moodalbail 		for (; head; head = head->am_next) {
4966e91bba0SGirish Moodalbail 			if (strcmp(head->am_ifname, ifname) == 0 &&
4976e91bba0SGirish Moodalbail 			    head->am_lnum == lnum &&
4986e91bba0SGirish Moodalbail 			    head->am_family == af) {
4996e91bba0SGirish Moodalbail 				break;
5006e91bba0SGirish Moodalbail 			}
5016e91bba0SGirish Moodalbail 		}
5026e91bba0SGirish Moodalbail 		if (head == NULL) {
5036e91bba0SGirish Moodalbail 			err = ENOENT;
5046e91bba0SGirish Moodalbail 			(void) pthread_rwlock_unlock(&aobjmap.aobjmap_rwlock);
5056e91bba0SGirish Moodalbail 			break;
5066e91bba0SGirish Moodalbail 		}
5076e91bba0SGirish Moodalbail 		(void) strlcpy(aobjrval.ir_aobjname, head->am_aobjname,
5086e91bba0SGirish Moodalbail 		    sizeof (aobjrval.ir_aobjname));
5096e91bba0SGirish Moodalbail 		aobjrval.ir_atype = head->am_atype;
5106e91bba0SGirish Moodalbail 		aobjrval.ir_flags = head->am_flags;
511b31320a7SChris Fraire 		aobjrval.ir_atype_cache = head->am_atype_cache;
5126e91bba0SGirish Moodalbail 		(void) pthread_rwlock_unlock(&aobjmap.aobjmap_rwlock);
5136e91bba0SGirish Moodalbail 		break;
5146e91bba0SGirish Moodalbail 	default:
5156e91bba0SGirish Moodalbail 		rsize = sizeof (ipmgmt_retval_t);
5166e91bba0SGirish Moodalbail 		rvalp = &rval;
5176e91bba0SGirish Moodalbail 		err = EINVAL;
5186e91bba0SGirish Moodalbail 	}
5196e91bba0SGirish Moodalbail 	((ipmgmt_retval_t *)rvalp)->ir_err = err;
5206e91bba0SGirish Moodalbail 	(void) door_return((char *)rvalp, rsize, NULL, 0);
5216e91bba0SGirish Moodalbail }
5226e91bba0SGirish Moodalbail 
5236e91bba0SGirish Moodalbail /*
5246e91bba0SGirish Moodalbail  * Given an interface name and family, deletes all the address objects
5256e91bba0SGirish Moodalbail  * associated with it.
5266e91bba0SGirish Moodalbail  */
5276e91bba0SGirish Moodalbail void
5286e91bba0SGirish Moodalbail i_ipmgmt_delif_aobjs(char *ifname, sa_family_t af, uint32_t flags)
5296e91bba0SGirish Moodalbail {
5306e91bba0SGirish Moodalbail 	ipmgmt_aobjmap_t	*head, *next, *prev;
5316e91bba0SGirish Moodalbail 	ipadm_db_op_t		db_op;
5326e91bba0SGirish Moodalbail 
5336e91bba0SGirish Moodalbail 	prev = NULL;
5346e91bba0SGirish Moodalbail 
5356e91bba0SGirish Moodalbail 	(void) pthread_rwlock_wrlock(&aobjmap.aobjmap_rwlock);
5366e91bba0SGirish Moodalbail 	head = aobjmap.aobjmap_head;
5376e91bba0SGirish Moodalbail 	for (; head; head = next) {
5386e91bba0SGirish Moodalbail 		next = head->am_next;
5396e91bba0SGirish Moodalbail 		if (strcmp(head->am_ifname, ifname) != 0 ||
5406e91bba0SGirish Moodalbail 		    head->am_family != af) {
5416e91bba0SGirish Moodalbail 			prev = head;
5426e91bba0SGirish Moodalbail 			continue;
5436e91bba0SGirish Moodalbail 		}
5446e91bba0SGirish Moodalbail 
5456e91bba0SGirish Moodalbail 		if (head->am_flags == (IPMGMT_ACTIVE|IPMGMT_PERSIST) &&
5466e91bba0SGirish Moodalbail 		    flags == IPMGMT_ACTIVE) {
5476e91bba0SGirish Moodalbail 			/*
5486e91bba0SGirish Moodalbail 			 * If the addres is present in both active and
5496e91bba0SGirish Moodalbail 			 * persistent store, and if we are performing
5506e91bba0SGirish Moodalbail 			 * a temporary delete, we update the node to
5516e91bba0SGirish Moodalbail 			 * indicate that the address is only present in
5526e91bba0SGirish Moodalbail 			 * persistent store and we proceed. Otherwise
5536e91bba0SGirish Moodalbail 			 * we always delete the node from aobjmap.
5546e91bba0SGirish Moodalbail 			 */
5556e91bba0SGirish Moodalbail 			head->am_flags &= ~IPMGMT_ACTIVE;
5566e91bba0SGirish Moodalbail 			head->am_lnum = -1;
5576e91bba0SGirish Moodalbail 			db_op = IPADM_DB_WRITE;
5586e91bba0SGirish Moodalbail 		} else {
5596e91bba0SGirish Moodalbail 			db_op = IPADM_DB_DELETE;
5606e91bba0SGirish Moodalbail 			if (prev == NULL)
5616e91bba0SGirish Moodalbail 				aobjmap.aobjmap_head = next;
5626e91bba0SGirish Moodalbail 			else
5636e91bba0SGirish Moodalbail 				prev->am_next = next;
5646e91bba0SGirish Moodalbail 		}
5656e91bba0SGirish Moodalbail 		(void) ipmgmt_persist_aobjmap(head, db_op);
5666e91bba0SGirish Moodalbail 		if (db_op == IPADM_DB_DELETE)
5676e91bba0SGirish Moodalbail 			free(head);
5686e91bba0SGirish Moodalbail 	}
5696e91bba0SGirish Moodalbail 	(void) pthread_rwlock_unlock(&aobjmap.aobjmap_rwlock);
5706e91bba0SGirish Moodalbail }
5716e91bba0SGirish Moodalbail 
5726e91bba0SGirish Moodalbail /*
5736e91bba0SGirish Moodalbail  * Handles the door command IPMGMT_CMD_SETIF. It persists the interface
5746e91bba0SGirish Moodalbail  * information in the DB.
5756e91bba0SGirish Moodalbail  */
5766e91bba0SGirish Moodalbail static void
5776e91bba0SGirish Moodalbail ipmgmt_setif_handler(void *argp)
5786e91bba0SGirish Moodalbail {
5796e91bba0SGirish Moodalbail 	ipmgmt_retval_t		rval;
5806e91bba0SGirish Moodalbail 
581550b6e40SSowmini Varadhan 	rval.ir_err = ipmgmt_persist_if(argp);
5826e91bba0SGirish Moodalbail 	(void) door_return((char *)&rval, sizeof (rval), NULL, 0);
5836e91bba0SGirish Moodalbail }
5846e91bba0SGirish Moodalbail 
5856e91bba0SGirish Moodalbail /*
5866e91bba0SGirish Moodalbail  * Handles the door command IPMGMT_CMD_RESETIF. For the given interface,
5876e91bba0SGirish Moodalbail  * deletes all the persisted interface configuration. It also deletes, from
5886e91bba0SGirish Moodalbail  * `aobjmap', all the address objects configured on the given interface.
5896e91bba0SGirish Moodalbail  */
5906e91bba0SGirish Moodalbail static void
5916e91bba0SGirish Moodalbail ipmgmt_resetif_handler(void *argp)
5926e91bba0SGirish Moodalbail {
5936e91bba0SGirish Moodalbail 	ipmgmt_if_arg_t		*rargp = argp;
5946e91bba0SGirish Moodalbail 	ipmgmt_retval_t		rval;
5956e91bba0SGirish Moodalbail 	ipmgmt_if_cbarg_t	cbarg;
5966e91bba0SGirish Moodalbail 	uint32_t		flags = rargp->ia_flags;
5976e91bba0SGirish Moodalbail 	int			err = 0;
5986e91bba0SGirish Moodalbail 
5996e91bba0SGirish Moodalbail 	cbarg.cb_family = rargp->ia_family;
6006e91bba0SGirish Moodalbail 	cbarg.cb_ifname = rargp->ia_ifname;
601*a73be61aSHans Rosenfeld 
602*a73be61aSHans Rosenfeld 	cbarg.cb_ipv4exists = B_TRUE;
603*a73be61aSHans Rosenfeld 	cbarg.cb_ipv6exists = B_TRUE;
604*a73be61aSHans Rosenfeld 
6056e91bba0SGirish Moodalbail 	if (flags & IPMGMT_PERSIST)
6066e91bba0SGirish Moodalbail 		err = ipmgmt_db_walk(ipmgmt_db_resetif, &cbarg,
6076e91bba0SGirish Moodalbail 		    IPADM_DB_DELETE);
6086e91bba0SGirish Moodalbail 
6096e91bba0SGirish Moodalbail 	if (flags & IPMGMT_ACTIVE)
6106e91bba0SGirish Moodalbail 		i_ipmgmt_delif_aobjs(rargp->ia_ifname, rargp->ia_family,
6116e91bba0SGirish Moodalbail 		    flags);
6126e91bba0SGirish Moodalbail 
6136e91bba0SGirish Moodalbail 	rval.ir_err = err;
6146e91bba0SGirish Moodalbail 	(void) door_return((char *)&rval, sizeof (rval), NULL, 0);
6156e91bba0SGirish Moodalbail }
6166e91bba0SGirish Moodalbail 
6176e91bba0SGirish Moodalbail /*
6186e91bba0SGirish Moodalbail  * Handles the door command IPMGMT_CMD_RESETADDR. For the given addrobj
6196e91bba0SGirish Moodalbail  * deletes all the persisted addrobj configuration. It also deletes the
6206e91bba0SGirish Moodalbail  * corresponding node, from `aobjmap'.
6216e91bba0SGirish Moodalbail  */
6226e91bba0SGirish Moodalbail static void
6236e91bba0SGirish Moodalbail ipmgmt_resetaddr_handler(void *argp)
6246e91bba0SGirish Moodalbail {
6256e91bba0SGirish Moodalbail 	ipmgmt_addr_arg_t	*rargp = argp;
6266e91bba0SGirish Moodalbail 	ipmgmt_retval_t		rval;
6276e91bba0SGirish Moodalbail 	ipmgmt_aobjmap_t	node;
6286e91bba0SGirish Moodalbail 	uint32_t		flags = rargp->ia_flags;
6296e91bba0SGirish Moodalbail 	int			err = 0;
6306e91bba0SGirish Moodalbail 	ipmgmt_resetaddr_cbarg_t cbarg;
6316e91bba0SGirish Moodalbail 
6326e91bba0SGirish Moodalbail 	cbarg.cb_aobjname = rargp->ia_aobjname;
6336e91bba0SGirish Moodalbail 
6346e91bba0SGirish Moodalbail 	if (flags & IPMGMT_PERSIST)
6356e91bba0SGirish Moodalbail 		err = ipmgmt_db_walk(ipmgmt_db_resetaddr, &cbarg,
6366e91bba0SGirish Moodalbail 		    IPADM_DB_DELETE);
6376e91bba0SGirish Moodalbail 
6386e91bba0SGirish Moodalbail 	if (flags & IPMGMT_ACTIVE) {
6396e91bba0SGirish Moodalbail 		bzero(&node, sizeof (node));
6406e91bba0SGirish Moodalbail 		(void) strlcpy(node.am_aobjname, rargp->ia_aobjname,
6416e91bba0SGirish Moodalbail 		    sizeof (node.am_aobjname));
6426e91bba0SGirish Moodalbail 
6436e91bba0SGirish Moodalbail 		/*
6446e91bba0SGirish Moodalbail 		 * am_lnum is used only for IPv6 autoconf case, since there
6456e91bba0SGirish Moodalbail 		 * can be multiple nodes with the same aobjname.
6466e91bba0SGirish Moodalbail 		 */
6476e91bba0SGirish Moodalbail 		node.am_lnum = rargp->ia_lnum;
6486e91bba0SGirish Moodalbail 		node.am_flags = flags;
6496e91bba0SGirish Moodalbail 		(void) ipmgmt_aobjmap_op(&node, ADDROBJ_DELETE);
6506e91bba0SGirish Moodalbail 	}
6516e91bba0SGirish Moodalbail 
6526e91bba0SGirish Moodalbail 	rval.ir_err = err;
6536e91bba0SGirish Moodalbail 	(void) door_return((char *)&rval, sizeof (rval), NULL, 0);
6546e91bba0SGirish Moodalbail }
6556e91bba0SGirish Moodalbail 
6566e91bba0SGirish Moodalbail /*
6576e91bba0SGirish Moodalbail  * Handles the door command IPMGMT_CMD_GETADDR. It retrieves the persisted
6586e91bba0SGirish Moodalbail  * address for a given `gargp->ia_aobjname'. If it is not defined then it
6596e91bba0SGirish Moodalbail  * retrieves all the addresses configured on `gargp->ia_ifname'. The
6606e91bba0SGirish Moodalbail  * "ipadm show-addr addrobj" or "ipadm show-addr <ifname>/\*" will call this
6616e91bba0SGirish Moodalbail  * handler through library.
6626e91bba0SGirish Moodalbail  */
6636e91bba0SGirish Moodalbail static void
6646e91bba0SGirish Moodalbail ipmgmt_getaddr_handler(void *argp)
6656e91bba0SGirish Moodalbail {
6666e91bba0SGirish Moodalbail 	ipmgmt_getaddr_arg_t    *gargp = argp;
6676e91bba0SGirish Moodalbail 
668*a73be61aSHans Rosenfeld 	ipmgmt_common_handler(gargp->ia_ifname, gargp->ia_aobjname,
669*a73be61aSHans Rosenfeld 	    ipmgmt_db_getaddr);
6706e91bba0SGirish Moodalbail }
6716e91bba0SGirish Moodalbail 
6726e91bba0SGirish Moodalbail /*
6736e91bba0SGirish Moodalbail  * Handles the door command IPMGMT_CMD_RESETPROP. It deletes the property line
6746e91bba0SGirish Moodalbail  * from the DB.
6756e91bba0SGirish Moodalbail  */
6766e91bba0SGirish Moodalbail static void
6776e91bba0SGirish Moodalbail ipmgmt_resetprop_handler(void *argp)
6786e91bba0SGirish Moodalbail {
6796e91bba0SGirish Moodalbail 	ipmgmt_prop_arg_t	*pargp = argp;
6806e91bba0SGirish Moodalbail 	ipmgmt_retval_t		rval;
6816e91bba0SGirish Moodalbail 
6826e91bba0SGirish Moodalbail 	assert(pargp->ia_cmd == IPMGMT_CMD_RESETPROP);
6836e91bba0SGirish Moodalbail 
6846e91bba0SGirish Moodalbail 	rval.ir_err = ipmgmt_db_walk(ipmgmt_db_resetprop, pargp,
6856e91bba0SGirish Moodalbail 	    IPADM_DB_DELETE);
6866e91bba0SGirish Moodalbail 	(void) door_return((char *)&rval, sizeof (rval), NULL, 0);
6876e91bba0SGirish Moodalbail }
6886e91bba0SGirish Moodalbail 
6896e91bba0SGirish Moodalbail /*
690*a73be61aSHans Rosenfeld  * Handles the door command IPMGMT_CMD_GETIF. It retrieves the names of all
691*a73be61aSHans Rosenfeld  * persisted interfaces and the IP protocol families (IPv4 or IPv6) they
692*a73be61aSHans Rosenfeld  * support. Returns the info as a nvlist using door_return() from
693*a73be61aSHans Rosenfeld  * ipmgmt_common_handler().
6946e91bba0SGirish Moodalbail  */
6956e91bba0SGirish Moodalbail static void
6966e91bba0SGirish Moodalbail ipmgmt_getif_handler(void *argp)
6976e91bba0SGirish Moodalbail {
6986e91bba0SGirish Moodalbail 	ipmgmt_getif_arg_t  *getif = argp;
6996e91bba0SGirish Moodalbail 
7006e91bba0SGirish Moodalbail 	assert(getif->ia_cmd == IPMGMT_CMD_GETIF);
7016e91bba0SGirish Moodalbail 
702*a73be61aSHans Rosenfeld 	ipmgmt_common_handler(getif->ia_ifname, NULL,
703*a73be61aSHans Rosenfeld 	    ipmgmt_db_getif);
7046e91bba0SGirish Moodalbail }
7056e91bba0SGirish Moodalbail 
7066e91bba0SGirish Moodalbail /*
7076e91bba0SGirish Moodalbail  * Handles the door command IPMGMT_CMD_INITIF. It retrieves all the persisted
7086e91bba0SGirish Moodalbail  * interface configuration (interface properties and addresses), for all those
7096e91bba0SGirish Moodalbail  * interfaces that need to be initialized.
7106e91bba0SGirish Moodalbail  */
7116e91bba0SGirish Moodalbail static void
7126e91bba0SGirish Moodalbail ipmgmt_initif_handler(void *argp)
7136e91bba0SGirish Moodalbail {
7146e91bba0SGirish Moodalbail 	ipmgmt_initif_arg_t	*initif = argp;
7156e91bba0SGirish Moodalbail 	size_t			buflen, nvlsize;
7166e91bba0SGirish Moodalbail 	char			*buf = NULL, *onvlbuf, *invlbuf;
7176e91bba0SGirish Moodalbail 	ipmgmt_get_rval_t	rval, *rvalp = &rval;
7186e91bba0SGirish Moodalbail 	ipmgmt_initif_cbarg_t	cbarg;
7196e91bba0SGirish Moodalbail 	int			err;
7206e91bba0SGirish Moodalbail 
7216e91bba0SGirish Moodalbail 	assert(initif->ia_cmd == IPMGMT_CMD_INITIF);
7226e91bba0SGirish Moodalbail 
7236e91bba0SGirish Moodalbail 	bzero(&cbarg, sizeof (cbarg));
7246e91bba0SGirish Moodalbail 	invlbuf = (char *)argp + sizeof (ipmgmt_initif_arg_t);
7256e91bba0SGirish Moodalbail 	nvlsize = initif->ia_nvlsize;
7260d1087e8SHans Rosenfeld 	err = nvlist_unpack(invlbuf, nvlsize, &cbarg.cb_invl, 0);
7276e91bba0SGirish Moodalbail 	if (err != 0)
7286e91bba0SGirish Moodalbail 		goto fail;
7296e91bba0SGirish Moodalbail 
7306e91bba0SGirish Moodalbail 	cbarg.cb_family = initif->ia_family;
7316e91bba0SGirish Moodalbail 	if (nvlist_alloc(&cbarg.cb_onvl, NV_UNIQUE_NAME, 0) != 0)
7326e91bba0SGirish Moodalbail 		goto fail;
7336e91bba0SGirish Moodalbail 
7346e91bba0SGirish Moodalbail 	err = ipmgmt_db_walk(ipmgmt_db_initif, &cbarg, IPADM_DB_READ);
7356e91bba0SGirish Moodalbail 	if (err == ENOENT && cbarg.cb_ocnt > 0) {
7366e91bba0SGirish Moodalbail 		/*
7376e91bba0SGirish Moodalbail 		 * If there is at least one entry in the nvlist,
7386e91bba0SGirish Moodalbail 		 * do not return error.
7396e91bba0SGirish Moodalbail 		 */
7406e91bba0SGirish Moodalbail 		err = 0;
7416e91bba0SGirish Moodalbail 	}
7426e91bba0SGirish Moodalbail 	if (err != 0)
7436e91bba0SGirish Moodalbail 		goto fail;
7446e91bba0SGirish Moodalbail 
7456e91bba0SGirish Moodalbail 	if ((err = nvlist_size(cbarg.cb_onvl, &nvlsize, NV_ENCODE_NATIVE)) != 0)
7466e91bba0SGirish Moodalbail 		goto fail;
7470a8fc1cbSHans Rosenfeld 
7480a8fc1cbSHans Rosenfeld 	if (nvlsize > (UINT32_MAX - sizeof (ipmgmt_get_rval_t)))
7490a8fc1cbSHans Rosenfeld 		goto fail;
7500a8fc1cbSHans Rosenfeld 
7516e91bba0SGirish Moodalbail 	buflen = nvlsize + sizeof (ipmgmt_get_rval_t);
7526e91bba0SGirish Moodalbail 	/*
7536e91bba0SGirish Moodalbail 	 * We cannot use malloc() here because door_return never returns, and
7546e91bba0SGirish Moodalbail 	 * memory allocated by malloc() would get leaked. Use alloca() instead.
7556e91bba0SGirish Moodalbail 	 */
7566e91bba0SGirish Moodalbail 	buf = alloca(buflen);
7576e91bba0SGirish Moodalbail 	onvlbuf = buf + sizeof (ipmgmt_get_rval_t);
7586e91bba0SGirish Moodalbail 	if ((err = nvlist_pack(cbarg.cb_onvl, &onvlbuf, &nvlsize,
7596e91bba0SGirish Moodalbail 	    NV_ENCODE_NATIVE, 0)) != 0) {
7606e91bba0SGirish Moodalbail 		goto fail;
7616e91bba0SGirish Moodalbail 	}
7626e91bba0SGirish Moodalbail 	nvlist_free(cbarg.cb_invl);
7636e91bba0SGirish Moodalbail 	nvlist_free(cbarg.cb_onvl);
7646e91bba0SGirish Moodalbail 	rvalp = (ipmgmt_get_rval_t *)(void *)buf;
7656e91bba0SGirish Moodalbail 	rvalp->ir_err = 0;
7666e91bba0SGirish Moodalbail 	rvalp->ir_nvlsize = nvlsize;
7676e91bba0SGirish Moodalbail 
7686e91bba0SGirish Moodalbail 	(void) door_return(buf, buflen, NULL, 0);
7696e91bba0SGirish Moodalbail 	return;
7706e91bba0SGirish Moodalbail fail:
7716e91bba0SGirish Moodalbail 	nvlist_free(cbarg.cb_invl);
7726e91bba0SGirish Moodalbail 	nvlist_free(cbarg.cb_onvl);
7736e91bba0SGirish Moodalbail 	rvalp->ir_err = err;
7746e91bba0SGirish Moodalbail 	(void) door_return((char *)rvalp, sizeof (*rvalp), NULL, 0);
7756e91bba0SGirish Moodalbail }
776550b6e40SSowmini Varadhan 
777550b6e40SSowmini Varadhan int
778550b6e40SSowmini Varadhan ipmgmt_persist_if(ipmgmt_if_arg_t *sargp)
779550b6e40SSowmini Varadhan {
780550b6e40SSowmini Varadhan 	ipadm_dbwrite_cbarg_t	cb;
781550b6e40SSowmini Varadhan 	uint32_t	flags = sargp->ia_flags;
782550b6e40SSowmini Varadhan 	nvlist_t	*nvl = NULL;
783550b6e40SSowmini Varadhan 	char	strval[IPMGMT_STRSIZE];
784*a73be61aSHans Rosenfeld 	int	err = 0;
785550b6e40SSowmini Varadhan 
786550b6e40SSowmini Varadhan 	if (!(flags & IPMGMT_PERSIST) || sargp->ia_family == AF_UNSPEC ||
787550b6e40SSowmini Varadhan 	    sargp->ia_ifname[0] == '\0') {
788550b6e40SSowmini Varadhan 		err = EINVAL;
789550b6e40SSowmini Varadhan 		goto ret;
790550b6e40SSowmini Varadhan 	}
791550b6e40SSowmini Varadhan 	if ((err = nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0)) != 0)
792550b6e40SSowmini Varadhan 		goto ret;
793*a73be61aSHans Rosenfeld 
794550b6e40SSowmini Varadhan 	if ((err = nvlist_add_string(nvl, IPADM_NVP_IFNAME,
795550b6e40SSowmini Varadhan 	    sargp->ia_ifname)) != 0)
796550b6e40SSowmini Varadhan 		goto ret;
797*a73be61aSHans Rosenfeld 
798*a73be61aSHans Rosenfeld 	if ((err = ipmgmt_update_family_nvp(nvl, sargp->ia_family,
799*a73be61aSHans Rosenfeld 	    IPMGMT_APPEND)) != 0)
800550b6e40SSowmini Varadhan 		goto ret;
801*a73be61aSHans Rosenfeld 
802*a73be61aSHans Rosenfeld 	(void) snprintf(strval, IPMGMT_STRSIZE, "%d", sargp->ia_ifclass);
803*a73be61aSHans Rosenfeld 	if ((err = nvlist_add_string(nvl, IPADM_NVP_IFCLASS, strval)) != 0)
804*a73be61aSHans Rosenfeld 		goto ret;
805*a73be61aSHans Rosenfeld 
806550b6e40SSowmini Varadhan 	cb.dbw_nvl = nvl;
807*a73be61aSHans Rosenfeld 	cb.dbw_flags = IPMGMT_APPEND | IPMGMT_UPDATE_IF;
808*a73be61aSHans Rosenfeld 	err = ipmgmt_db_walk(ipmgmt_db_update_if, &cb, IPADM_DB_WRITE);
809550b6e40SSowmini Varadhan ret:
810550b6e40SSowmini Varadhan 	nvlist_free(nvl);
811550b6e40SSowmini Varadhan 	return (err);
812550b6e40SSowmini Varadhan }
813*a73be61aSHans Rosenfeld 
814*a73be61aSHans Rosenfeld /*
815*a73be61aSHans Rosenfeld  * The helper for ipmgmt_getif_handler and ipmgmt_getaddr_handler
816*a73be61aSHans Rosenfeld  */
817*a73be61aSHans Rosenfeld static void
818*a73be61aSHans Rosenfeld ipmgmt_common_handler(char *if_name, char *aobj_name, db_wfunc_t worker)
819*a73be61aSHans Rosenfeld {
820*a73be61aSHans Rosenfeld 	size_t			buflen, onvlsize;
821*a73be61aSHans Rosenfeld 	char			*buf, *onvlbuf;
822*a73be61aSHans Rosenfeld 	ipmgmt_get_cbarg_t	cbarg;
823*a73be61aSHans Rosenfeld 	ipmgmt_get_rval_t	rval, *rvalp = &rval;
824*a73be61aSHans Rosenfeld 	int			err = 0;
825*a73be61aSHans Rosenfeld 
826*a73be61aSHans Rosenfeld 	cbarg.cb_ifname = if_name;
827*a73be61aSHans Rosenfeld 	cbarg.cb_aobjname = aobj_name;
828*a73be61aSHans Rosenfeld 	cbarg.cb_ocnt = 0;
829*a73be61aSHans Rosenfeld 
830*a73be61aSHans Rosenfeld 	if (nvlist_alloc(&cbarg.cb_onvl, NV_UNIQUE_NAME, 0) != 0)
831*a73be61aSHans Rosenfeld 		goto fail;
832*a73be61aSHans Rosenfeld 
833*a73be61aSHans Rosenfeld 	err = ipmgmt_db_walk(worker, &cbarg, IPADM_DB_READ);
834*a73be61aSHans Rosenfeld 	if (err == ENOENT && cbarg.cb_ocnt > 0) {
835*a73be61aSHans Rosenfeld 		/*
836*a73be61aSHans Rosenfeld 		 * If there is at least one entry in the nvlist,
837*a73be61aSHans Rosenfeld 		 * do not return error.
838*a73be61aSHans Rosenfeld 		 */
839*a73be61aSHans Rosenfeld 		err = 0;
840*a73be61aSHans Rosenfeld 	}
841*a73be61aSHans Rosenfeld 	if (err != 0)
842*a73be61aSHans Rosenfeld 		goto fail;
843*a73be61aSHans Rosenfeld 
844*a73be61aSHans Rosenfeld 	if ((err = nvlist_size(cbarg.cb_onvl, &onvlsize,
845*a73be61aSHans Rosenfeld 	    NV_ENCODE_NATIVE)) != 0)
846*a73be61aSHans Rosenfeld 		goto fail;
847*a73be61aSHans Rosenfeld 
848*a73be61aSHans Rosenfeld 	if (onvlsize > (UINT32_MAX - sizeof (ipmgmt_get_rval_t)))
849*a73be61aSHans Rosenfeld 		goto fail;
850*a73be61aSHans Rosenfeld 
851*a73be61aSHans Rosenfeld 	buflen = onvlsize + sizeof (ipmgmt_get_rval_t);
852*a73be61aSHans Rosenfeld 	/*
853*a73be61aSHans Rosenfeld 	 * We cannot use malloc() here because door_return never returns, and
854*a73be61aSHans Rosenfeld 	 * memory allocated by malloc() would get leaked. Use alloca() instead.
855*a73be61aSHans Rosenfeld 	 */
856*a73be61aSHans Rosenfeld 	buf = alloca(buflen);
857*a73be61aSHans Rosenfeld 	onvlbuf = buf + sizeof (ipmgmt_get_rval_t);
858*a73be61aSHans Rosenfeld 	if ((err = nvlist_pack(cbarg.cb_onvl, &onvlbuf,
859*a73be61aSHans Rosenfeld 	    &onvlsize, NV_ENCODE_NATIVE, 0)) != 0)
860*a73be61aSHans Rosenfeld 		goto fail;
861*a73be61aSHans Rosenfeld 
862*a73be61aSHans Rosenfeld 	nvlist_free(cbarg.cb_onvl);
863*a73be61aSHans Rosenfeld 	rvalp = (ipmgmt_get_rval_t *)(void *)buf;
864*a73be61aSHans Rosenfeld 	rvalp->ir_err = 0;
865*a73be61aSHans Rosenfeld 	rvalp->ir_nvlsize = onvlsize;
866*a73be61aSHans Rosenfeld 
867*a73be61aSHans Rosenfeld 	(void) door_return(buf, buflen, NULL, 0);
868*a73be61aSHans Rosenfeld 
869*a73be61aSHans Rosenfeld fail:
870*a73be61aSHans Rosenfeld 	nvlist_free(cbarg.cb_onvl);
871*a73be61aSHans Rosenfeld 	rvalp->ir_err = err;
872*a73be61aSHans Rosenfeld 	(void) door_return((char *)rvalp, sizeof (*rvalp), NULL, 0);
873*a73be61aSHans Rosenfeld }
874*a73be61aSHans Rosenfeld 
875*a73be61aSHans Rosenfeld /*
876*a73be61aSHans Rosenfeld  * Handles the door command IPMGMT_CMD_IPMP_UPDATE
877*a73be61aSHans Rosenfeld  */
878*a73be61aSHans Rosenfeld static void
879*a73be61aSHans Rosenfeld ipmgmt_ipmp_update_handler(void *argp)
880*a73be61aSHans Rosenfeld {
881*a73be61aSHans Rosenfeld 	ipmgmt_ipmp_update_arg_t *uargp = argp;
882*a73be61aSHans Rosenfeld 	ipmgmt_retval_t	rval;
883*a73be61aSHans Rosenfeld 	ipadm_dbwrite_cbarg_t	cb;
884*a73be61aSHans Rosenfeld 
885*a73be61aSHans Rosenfeld 	boolean_t	gif_exists;
886*a73be61aSHans Rosenfeld 	char		gifname[LIFNAMSIZ];
887*a73be61aSHans Rosenfeld 	nvlist_t	*nvl = NULL;
888*a73be61aSHans Rosenfeld 	uint32_t	flags = uargp->ia_flags;
889*a73be61aSHans Rosenfeld 	int		err = 0;
890*a73be61aSHans Rosenfeld 
891*a73be61aSHans Rosenfeld 	assert(uargp->ia_cmd == IPMGMT_CMD_IPMP_UPDATE);
892*a73be61aSHans Rosenfeld 
893*a73be61aSHans Rosenfeld 	gif_exists = ipmgmt_persist_if_exists(uargp->ia_gifname,
894*a73be61aSHans Rosenfeld 	    AF_UNSPEC);
895*a73be61aSHans Rosenfeld 
896*a73be61aSHans Rosenfeld 	if (!ipmgmt_persist_if_exists(uargp->ia_mifname, AF_UNSPEC)) {
897*a73be61aSHans Rosenfeld 		err = EINVAL;
898*a73be61aSHans Rosenfeld 		goto ret;
899*a73be61aSHans Rosenfeld 	}
900*a73be61aSHans Rosenfeld 
901*a73be61aSHans Rosenfeld 	ipmgmt_get_group_interface(uargp->ia_mifname, gifname, LIFNAMSIZ);
902*a73be61aSHans Rosenfeld 
903*a73be61aSHans Rosenfeld 	if (flags & IPMGMT_APPEND) {
904*a73be61aSHans Rosenfeld 		/* Group interface should be available in the DB */
905*a73be61aSHans Rosenfeld 		if (!gif_exists) {
906*a73be61aSHans Rosenfeld 			err = ENOENT;
907*a73be61aSHans Rosenfeld 			goto ret;
908*a73be61aSHans Rosenfeld 		}
909*a73be61aSHans Rosenfeld 
910*a73be61aSHans Rosenfeld 		if (gifname[0] != '\0') {
911*a73be61aSHans Rosenfeld 			err = EEXIST;
912*a73be61aSHans Rosenfeld 			goto ret;
913*a73be61aSHans Rosenfeld 		}
914*a73be61aSHans Rosenfeld 	}
915*a73be61aSHans Rosenfeld 
916*a73be61aSHans Rosenfeld 	if (flags & IPMGMT_REMOVE) {
917*a73be61aSHans Rosenfeld 		/* We cannot remove something that does not exist */
918*a73be61aSHans Rosenfeld 		if (!gif_exists || gifname[0] == '\0') {
919*a73be61aSHans Rosenfeld 			err = ENOENT;
920*a73be61aSHans Rosenfeld 			goto ret;
921*a73be61aSHans Rosenfeld 		}
922*a73be61aSHans Rosenfeld 		if (strcmp(uargp->ia_gifname, gifname) != 0) {
923*a73be61aSHans Rosenfeld 			err = EINVAL;
924*a73be61aSHans Rosenfeld 			goto ret;
925*a73be61aSHans Rosenfeld 		}
926*a73be61aSHans Rosenfeld 	}
927*a73be61aSHans Rosenfeld 
928*a73be61aSHans Rosenfeld 	if (flags & IPMGMT_PERSIST) {
929*a73be61aSHans Rosenfeld 		if ((err = nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0)) != 0)
930*a73be61aSHans Rosenfeld 			goto ret;
931*a73be61aSHans Rosenfeld 
932*a73be61aSHans Rosenfeld 		if ((err = nvlist_add_string(nvl, IPADM_NVP_IFNAME,
933*a73be61aSHans Rosenfeld 		    uargp->ia_gifname)) != 0)
934*a73be61aSHans Rosenfeld 			goto ret;
935*a73be61aSHans Rosenfeld 
936*a73be61aSHans Rosenfeld 		if ((err = nvlist_add_string(nvl, IPADM_NVP_MIFNAMES,
937*a73be61aSHans Rosenfeld 		    uargp->ia_mifname)) != 0)
938*a73be61aSHans Rosenfeld 			goto ret;
939*a73be61aSHans Rosenfeld 
940*a73be61aSHans Rosenfeld 		if ((err = nvlist_add_string(nvl, IPADM_NVP_GIFNAME,
941*a73be61aSHans Rosenfeld 		    uargp->ia_gifname)) != 0)
942*a73be61aSHans Rosenfeld 			goto ret;
943*a73be61aSHans Rosenfeld 
944*a73be61aSHans Rosenfeld 		cb.dbw_nvl = nvl;
945*a73be61aSHans Rosenfeld 		cb.dbw_flags = flags | IPMGMT_UPDATE_IF | IPMGMT_UPDATE_IPMP;
946*a73be61aSHans Rosenfeld 		err = ipmgmt_db_walk(ipmgmt_db_update_if, &cb, IPADM_DB_WRITE);
947*a73be61aSHans Rosenfeld 	}
948*a73be61aSHans Rosenfeld ret:
949*a73be61aSHans Rosenfeld 	nvlist_free(nvl);
950*a73be61aSHans Rosenfeld 	rval.ir_err = err;
951*a73be61aSHans Rosenfeld 	(void) door_return((char *)&rval, sizeof (rval), NULL, 0);
952*a73be61aSHans Rosenfeld }
953