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