#include <alloca.h>
#include <pwd.h>
#include <auth_attr.h>
#include <secdb.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <strings.h>
#include <errno.h>
#include <assert.h>
#include <libnvpair.h>
#include "ipmgmt_impl.h"
static void ipmgmt_common_handler(char *, char *, db_wfunc_t *);
typedef void ipmgmt_door_handler_t(void *argp);
static ipmgmt_door_handler_t ipmgmt_getaddr_handler,
ipmgmt_getprop_handler,
ipmgmt_getif_handler,
ipmgmt_initif_handler,
ipmgmt_aobjop_handler,
ipmgmt_resetaddr_handler,
ipmgmt_setif_handler,
ipmgmt_resetif_handler,
ipmgmt_resetprop_handler,
ipmgmt_setaddr_handler,
ipmgmt_setprop_handler,
ipmgmt_ipmp_update_handler;
typedef struct ipmgmt_door_info_s {
uint_t idi_cmd;
boolean_t idi_set;
ipmgmt_door_handler_t *idi_handler;
} ipmgmt_door_info_t;
static ipmgmt_door_info_t i_ipmgmt_door_info_tbl[] = {
{ IPMGMT_CMD_SETPROP, B_TRUE, ipmgmt_setprop_handler },
{ IPMGMT_CMD_SETIF, B_TRUE, ipmgmt_setif_handler },
{ IPMGMT_CMD_SETADDR, B_TRUE, ipmgmt_setaddr_handler },
{ IPMGMT_CMD_GETPROP, B_FALSE, ipmgmt_getprop_handler },
{ IPMGMT_CMD_GETIF, B_FALSE, ipmgmt_getif_handler },
{ IPMGMT_CMD_GETADDR, B_FALSE, ipmgmt_getaddr_handler },
{ IPMGMT_CMD_RESETIF, B_TRUE, ipmgmt_resetif_handler },
{ IPMGMT_CMD_RESETADDR, B_TRUE, ipmgmt_resetaddr_handler },
{ IPMGMT_CMD_RESETPROP, B_TRUE, ipmgmt_resetprop_handler },
{ IPMGMT_CMD_INITIF, B_TRUE, ipmgmt_initif_handler },
{ IPMGMT_CMD_ADDROBJ_LOOKUPADD, B_TRUE, ipmgmt_aobjop_handler },
{ IPMGMT_CMD_ADDROBJ_SETLIFNUM, B_TRUE, ipmgmt_aobjop_handler },
{ IPMGMT_CMD_ADDROBJ_ADD, B_TRUE, ipmgmt_aobjop_handler },
{ IPMGMT_CMD_AOBJNAME2ADDROBJ, B_FALSE, ipmgmt_aobjop_handler },
{ IPMGMT_CMD_LIF2ADDROBJ, B_FALSE, ipmgmt_aobjop_handler },
{ IPMGMT_CMD_IPMP_UPDATE, B_FALSE, ipmgmt_ipmp_update_handler},
{ 0, 0, NULL },
};
void
ipmgmt_handler(void *cookie, char *argp, size_t argsz, door_desc_t *dp,
uint_t n_desc)
{
ipmgmt_door_info_t *infop = NULL;
ipmgmt_retval_t retval;
int i;
uint_t err;
ucred_t *cred = NULL;
for (i = 0; i_ipmgmt_door_info_tbl[i].idi_cmd != 0; i++) {
if (i_ipmgmt_door_info_tbl[i].idi_cmd ==
((ipmgmt_arg_t *)(void *)argp)->ia_cmd) {
infop = &i_ipmgmt_door_info_tbl[i];
break;
}
}
if (infop == NULL) {
ipmgmt_log(LOG_ERR, "Invalid door command specified");
err = EINVAL;
goto fail;
}
if (infop->idi_set) {
uid_t uid;
struct passwd pwd;
char buf[1024];
if (door_ucred(&cred) != 0) {
err = errno;
ipmgmt_log(LOG_ERR, "Could not get user credentials.");
goto fail;
}
uid = ucred_getruid(cred);
if ((int)uid < 0) {
err = errno;
ipmgmt_log(LOG_ERR, "Could not get user id.");
goto fail;
}
if (getpwuid_r(uid, &pwd, buf, sizeof (buf)) ==
NULL) {
err = errno;
ipmgmt_log(LOG_ERR, "Could not get password entry.");
goto fail;
}
if (chkauthattr(NETWORK_INTERFACE_CONFIG_AUTH,
pwd.pw_name) != 1) {
err = EPERM;
ipmgmt_log(LOG_ERR, "Not authorized for operation.");
goto fail;
}
ucred_free(cred);
}
infop->idi_handler((void *)argp);
return;
fail:
ucred_free(cred);
retval.ir_err = err;
(void) door_return((char *)&retval, sizeof (retval), NULL, 0);
}
static void
ipmgmt_getprop_handler(void *argp)
{
ipmgmt_prop_arg_t *pargp = argp;
ipmgmt_getprop_rval_t rval, *rvalp = &rval;
assert(pargp->ia_cmd == IPMGMT_CMD_GETPROP);
rvalp->ir_err = ipmgmt_db_walk(ipmgmt_db_getprop, pargp, IPADM_DB_READ);
if (rvalp->ir_err == 0)
(void) strlcpy(rvalp->ir_pval, pargp->ia_pval,
sizeof (rvalp->ir_pval));
(void) door_return((char *)rvalp, sizeof (*rvalp), NULL, 0);
}
static void
ipmgmt_setprop_handler(void *argp)
{
ipmgmt_prop_arg_t *pargp = argp;
ipmgmt_retval_t rval;
ipadm_dbwrite_cbarg_t cb;
nvlist_t *nvl = NULL;
int err;
assert(pargp->ia_cmd == IPMGMT_CMD_SETPROP);
if ((err = nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0)) != 0)
goto fail;
if (pargp->ia_module[0] != '\0' &&
(err = nvlist_add_string(nvl, IPADM_NVP_PROTONAME,
pargp->ia_module)) != 0) {
goto fail;
}
if (pargp->ia_ifname[0] != '\0' &&
(err = nvlist_add_string(nvl, IPADM_NVP_IFNAME,
pargp->ia_ifname)) != 0)
goto fail;
if (pargp->ia_aobjname[0] != '\0' &&
(err = nvlist_add_string(nvl, IPADM_NVP_AOBJNAME,
pargp->ia_aobjname)) != 0)
goto fail;
if ((err = nvlist_add_string(nvl, pargp->ia_pname,
pargp->ia_pval)) != 0)
goto fail;
cb.dbw_nvl = nvl;
cb.dbw_flags = pargp->ia_flags;
err = ipmgmt_db_walk(ipmgmt_db_update, &cb, IPADM_DB_WRITE);
fail:
nvlist_free(nvl);
rval.ir_err = err;
(void) door_return((char *)&rval, sizeof (rval), NULL, 0);
}
static int
i_ipmgmt_nvl2aobjnode(nvlist_t *nvl, ipmgmt_aobjmap_t *nodep)
{
char *aobjname = NULL, *ifname = NULL;
int32_t lnum;
nvlist_t *nvladdr;
sa_family_t af = AF_UNSPEC;
ipadm_addr_type_t addrtype = IPADM_ADDR_NONE;
int err = 0;
if ((err = nvlist_lookup_string(nvl, IPADM_NVP_AOBJNAME,
&aobjname)) != 0 ||
(err = nvlist_lookup_string(nvl, IPADM_NVP_IFNAME, &ifname)) != 0 ||
(err = nvlist_lookup_int32(nvl, IPADM_NVP_LIFNUM, &lnum)) != 0) {
return (err);
}
if (nvlist_exists(nvl, IPADM_NVP_IPV4ADDR)) {
af = AF_INET;
addrtype = IPADM_ADDR_STATIC;
} else if (nvlist_lookup_nvlist(nvl, IPADM_NVP_DHCP, &nvladdr) == 0) {
char *reqhost;
af = AF_INET;
addrtype = IPADM_ADDR_DHCP;
if (!nvlist_exists(nvl, IPADM_NVP_REQHOST)) {
*nodep->ipmgmt_am_reqhost = '\0';
} else {
if ((err = nvlist_lookup_string(nvl, IPADM_NVP_REQHOST,
&reqhost)) != 0)
return (err);
(void) strlcpy(nodep->ipmgmt_am_reqhost, reqhost,
sizeof (nodep->ipmgmt_am_reqhost));
(void) nvlist_remove(nvl, IPADM_NVP_REQHOST,
DATA_TYPE_STRING);
}
} else if (nvlist_exists(nvl, IPADM_NVP_IPV6ADDR)) {
af = AF_INET6;
addrtype = IPADM_ADDR_STATIC;
} else if (nvlist_lookup_nvlist(nvl, IPADM_NVP_INTFID, &nvladdr) == 0) {
struct sockaddr_in6 sin6 = {0};
uint8_t *addr6;
uint32_t plen;
uint_t n;
af = AF_INET6;
addrtype = IPADM_ADDR_IPV6_ADDRCONF;
if (nvlist_lookup_uint32(nvladdr, IPADM_NVP_PREFIXLEN,
&plen) != 0)
return (EINVAL);
if (plen != 0) {
if (nvlist_lookup_uint8_array(nvladdr,
IPADM_NVP_IPNUMADDR, &addr6, &n) != 0)
return (EINVAL);
bcopy(addr6, &sin6.sin6_addr, n);
}
nodep->ipmgmt_am_linklocal = B_TRUE;
nodep->ipmgmt_am_ifid = sin6;
}
(void) strlcpy(nodep->am_ifname, ifname, sizeof (nodep->am_ifname));
(void) strlcpy(nodep->am_aobjname, aobjname,
sizeof (nodep->am_aobjname));
nodep->am_lnum = lnum;
nodep->am_family = af;
nodep->am_atype = addrtype;
nodep->am_next = NULL;
if (nvlist_exists(nvl, IPADM_NVP_LIFNUM))
(void) nvlist_remove(nvl, IPADM_NVP_LIFNUM, DATA_TYPE_INT32);
return (0);
}
static void
ipmgmt_setaddr_handler(void *argp)
{
ipmgmt_setaddr_arg_t *sargp = argp;
ipmgmt_retval_t rval;
ipmgmt_aobjmap_t node = {0};
nvlist_t *nvl = NULL;
char *nvlbuf;
size_t nvlsize = sargp->ia_nvlsize;
uint32_t flags = sargp->ia_flags;
int err = 0;
nvlbuf = (char *)argp + sizeof (ipmgmt_setaddr_arg_t);
if ((err = nvlist_unpack(nvlbuf, nvlsize, &nvl, 0)) != 0)
goto ret;
if (flags & (IPMGMT_ACTIVE|IPMGMT_INIT)) {
if ((err = i_ipmgmt_nvl2aobjnode(nvl, &node)) != 0)
goto ret;
if (flags & IPMGMT_INIT)
node.am_flags = (IPMGMT_ACTIVE|IPMGMT_PERSIST);
else
node.am_flags = flags & ~IPMGMT_PROPS_ONLY;
if ((err = ipmgmt_aobjmap_op(&node, ADDROBJ_ADD)) != 0)
goto ret;
}
if ((flags & IPMGMT_PERSIST) && !(flags & IPMGMT_PROPS_ONLY)) {
ipadm_dbwrite_cbarg_t cb;
cb.dbw_nvl = nvl;
cb.dbw_flags = 0;
err = ipmgmt_db_walk(ipmgmt_db_add, &cb, IPADM_DB_WRITE);
}
ret:
nvlist_free(nvl);
rval.ir_err = err;
(void) door_return((char *)&rval, sizeof (rval), NULL, 0);
}
static void
ipmgmt_aobjop_handler(void *argp)
{
ipmgmt_aobjop_arg_t *largp = argp;
ipmgmt_retval_t rval;
ipmgmt_aobjop_rval_t aobjrval;
void *rvalp;
size_t rsize;
ipmgmt_aobjmap_t node;
int err = 0;
char *ifname = largp->ia_ifname;
char *aobjname = largp->ia_aobjname;
int32_t lnum = largp->ia_lnum;
sa_family_t af = largp->ia_family;
ipadm_addr_type_t atype = largp->ia_atype;
ipmgmt_aobjmap_t *head;
bzero(&aobjrval, sizeof (aobjrval));
switch (largp->ia_cmd) {
case IPMGMT_CMD_ADDROBJ_LOOKUPADD:
rsize = sizeof (ipmgmt_aobjop_rval_t);
rvalp = &aobjrval;
bzero(&node, sizeof (node));
(void) strlcpy(node.am_aobjname, aobjname,
sizeof (node.am_aobjname));
(void) strlcpy(node.am_ifname, ifname,
sizeof (node.am_ifname));
node.am_family = af;
node.am_atype = atype;
if (atype == IPADM_ADDR_IPV6_ADDRCONF) {
node.ipmgmt_am_linklocal = B_TRUE;
}
node.am_lnum = -1;
node.am_flags = IPMGMT_ACTIVE;
err = ipmgmt_aobjmap_op(&node, ADDROBJ_LOOKUPADD);
if (err == 0) {
aobjrval.ir_lnum = node.am_lnum;
(void) strlcpy(aobjrval.ir_aobjname, node.am_aobjname,
sizeof (aobjrval.ir_aobjname));
}
break;
case IPMGMT_CMD_ADDROBJ_SETLIFNUM:
rsize = sizeof (ipmgmt_retval_t);
rvalp = &rval;
bzero(&node, sizeof (node));
(void) strlcpy(node.am_aobjname, aobjname,
sizeof (node.am_aobjname));
(void) strlcpy(node.am_ifname, ifname,
sizeof (node.am_ifname));
node.am_family = af;
node.am_lnum = lnum;
err = ipmgmt_aobjmap_op(&node, ADDROBJ_SETLIFNUM);
break;
case IPMGMT_CMD_ADDROBJ_ADD:
rsize = sizeof (ipmgmt_retval_t);
rvalp = &rval;
if (aobjname[0] == '\0' || ifname[0] == '\0' || lnum == -1 ||
af == AF_UNSPEC) {
err = EINVAL;
break;
}
bzero(&node, sizeof (node));
(void) strlcpy(node.am_aobjname, aobjname,
sizeof (node.am_aobjname));
(void) strlcpy(node.am_ifname, ifname,
sizeof (node.am_ifname));
node.am_atype = atype;
node.am_lnum = lnum;
node.am_family = af;
node.am_flags = IPMGMT_ACTIVE;
err = ipmgmt_aobjmap_op(&node, ADDROBJ_ADD);
break;
case IPMGMT_CMD_AOBJNAME2ADDROBJ:
rsize = sizeof (ipmgmt_aobjop_rval_t);
rvalp = &aobjrval;
bzero(&aobjrval, sizeof (aobjrval));
if (aobjname[0] == '\0') {
err = EINVAL;
break;
}
(void) pthread_rwlock_rdlock(&aobjmap.aobjmap_rwlock);
head = aobjmap.aobjmap_head;
for (; head; head = head->am_next) {
if (strcmp(head->am_aobjname, aobjname) != 0)
continue;
if (head->am_atype != IPADM_ADDR_IPV6_ADDRCONF ||
head->ipmgmt_am_linklocal) {
break;
}
}
if (head == NULL) {
err = ENOENT;
(void) pthread_rwlock_unlock(&aobjmap.aobjmap_rwlock);
break;
}
(void) strlcpy(aobjrval.ir_ifname, head->am_ifname,
sizeof (aobjrval.ir_ifname));
aobjrval.ir_lnum = head->am_lnum;
aobjrval.ir_family = head->am_family;
aobjrval.ir_flags = head->am_flags;
aobjrval.ir_atype = head->am_atype;
aobjrval.ir_atype_cache = head->am_atype_cache;
(void) pthread_rwlock_unlock(&aobjmap.aobjmap_rwlock);
break;
case IPMGMT_CMD_LIF2ADDROBJ:
rsize = sizeof (ipmgmt_aobjop_rval_t);
rvalp = &aobjrval;
bzero(&aobjrval, sizeof (aobjrval));
if (ifname[0] == '\0') {
err = EINVAL;
break;
}
(void) pthread_rwlock_rdlock(&aobjmap.aobjmap_rwlock);
head = aobjmap.aobjmap_head;
for (; head; head = head->am_next) {
if (strcmp(head->am_ifname, ifname) == 0 &&
head->am_lnum == lnum &&
head->am_family == af) {
break;
}
}
if (head == NULL) {
err = ENOENT;
(void) pthread_rwlock_unlock(&aobjmap.aobjmap_rwlock);
break;
}
(void) strlcpy(aobjrval.ir_aobjname, head->am_aobjname,
sizeof (aobjrval.ir_aobjname));
aobjrval.ir_atype = head->am_atype;
aobjrval.ir_flags = head->am_flags;
aobjrval.ir_atype_cache = head->am_atype_cache;
(void) pthread_rwlock_unlock(&aobjmap.aobjmap_rwlock);
break;
default:
rsize = sizeof (ipmgmt_retval_t);
rvalp = &rval;
err = EINVAL;
}
((ipmgmt_retval_t *)rvalp)->ir_err = err;
(void) door_return((char *)rvalp, rsize, NULL, 0);
}
void
i_ipmgmt_delif_aobjs(char *ifname, sa_family_t af, uint32_t flags)
{
ipmgmt_aobjmap_t *head, *next, *prev;
ipadm_db_op_t db_op;
prev = NULL;
(void) pthread_rwlock_wrlock(&aobjmap.aobjmap_rwlock);
head = aobjmap.aobjmap_head;
for (; head; head = next) {
next = head->am_next;
if (strcmp(head->am_ifname, ifname) != 0 ||
head->am_family != af) {
prev = head;
continue;
}
if (head->am_flags == (IPMGMT_ACTIVE|IPMGMT_PERSIST) &&
flags == IPMGMT_ACTIVE) {
head->am_flags &= ~IPMGMT_ACTIVE;
head->am_lnum = -1;
db_op = IPADM_DB_WRITE;
} else {
db_op = IPADM_DB_DELETE;
if (prev == NULL)
aobjmap.aobjmap_head = next;
else
prev->am_next = next;
}
(void) ipmgmt_persist_aobjmap(head, db_op);
if (db_op == IPADM_DB_DELETE)
free(head);
}
(void) pthread_rwlock_unlock(&aobjmap.aobjmap_rwlock);
}
static void
ipmgmt_setif_handler(void *argp)
{
ipmgmt_retval_t rval;
rval.ir_err = ipmgmt_persist_if(argp);
(void) door_return((char *)&rval, sizeof (rval), NULL, 0);
}
static void
ipmgmt_resetif_handler(void *argp)
{
ipmgmt_if_arg_t *rargp = argp;
ipmgmt_retval_t rval;
ipmgmt_if_cbarg_t cbarg;
uint32_t flags = rargp->ia_flags;
int err = 0;
cbarg.cb_family = rargp->ia_family;
cbarg.cb_ifname = rargp->ia_ifname;
cbarg.cb_ipv4exists = B_TRUE;
cbarg.cb_ipv6exists = B_TRUE;
if (flags & IPMGMT_PERSIST)
err = ipmgmt_db_walk(ipmgmt_db_resetif, &cbarg,
IPADM_DB_DELETE);
if (flags & IPMGMT_ACTIVE)
i_ipmgmt_delif_aobjs(rargp->ia_ifname, rargp->ia_family,
flags);
rval.ir_err = err;
(void) door_return((char *)&rval, sizeof (rval), NULL, 0);
}
static void
ipmgmt_resetaddr_handler(void *argp)
{
ipmgmt_addr_arg_t *rargp = argp;
ipmgmt_retval_t rval;
ipmgmt_aobjmap_t node;
uint32_t flags = rargp->ia_flags;
int err = 0;
ipmgmt_resetaddr_cbarg_t cbarg;
cbarg.cb_aobjname = rargp->ia_aobjname;
if (flags & IPMGMT_PERSIST)
err = ipmgmt_db_walk(ipmgmt_db_resetaddr, &cbarg,
IPADM_DB_DELETE);
if (flags & IPMGMT_ACTIVE) {
bzero(&node, sizeof (node));
(void) strlcpy(node.am_aobjname, rargp->ia_aobjname,
sizeof (node.am_aobjname));
node.am_lnum = rargp->ia_lnum;
node.am_flags = flags;
(void) ipmgmt_aobjmap_op(&node, ADDROBJ_DELETE);
}
rval.ir_err = err;
(void) door_return((char *)&rval, sizeof (rval), NULL, 0);
}
static void
ipmgmt_getaddr_handler(void *argp)
{
ipmgmt_getaddr_arg_t *gargp = argp;
ipmgmt_common_handler(gargp->ia_ifname, gargp->ia_aobjname,
ipmgmt_db_getaddr);
}
static void
ipmgmt_resetprop_handler(void *argp)
{
ipmgmt_prop_arg_t *pargp = argp;
ipmgmt_retval_t rval;
assert(pargp->ia_cmd == IPMGMT_CMD_RESETPROP);
rval.ir_err = ipmgmt_db_walk(ipmgmt_db_resetprop, pargp,
IPADM_DB_DELETE);
(void) door_return((char *)&rval, sizeof (rval), NULL, 0);
}
static void
ipmgmt_getif_handler(void *argp)
{
ipmgmt_getif_arg_t *getif = argp;
assert(getif->ia_cmd == IPMGMT_CMD_GETIF);
ipmgmt_common_handler(getif->ia_ifname, NULL,
ipmgmt_db_getif);
}
static void
ipmgmt_initif_handler(void *argp)
{
ipmgmt_initif_arg_t *initif = argp;
size_t buflen, nvlsize;
char *buf = NULL, *onvlbuf, *invlbuf;
ipmgmt_get_rval_t rval, *rvalp = &rval;
ipmgmt_initif_cbarg_t cbarg;
int err;
assert(initif->ia_cmd == IPMGMT_CMD_INITIF);
bzero(&cbarg, sizeof (cbarg));
invlbuf = (char *)argp + sizeof (ipmgmt_initif_arg_t);
nvlsize = initif->ia_nvlsize;
err = nvlist_unpack(invlbuf, nvlsize, &cbarg.cb_invl, 0);
if (err != 0)
goto fail;
cbarg.cb_family = initif->ia_family;
if (nvlist_alloc(&cbarg.cb_onvl, NV_UNIQUE_NAME, 0) != 0)
goto fail;
err = ipmgmt_db_walk(ipmgmt_db_initif, &cbarg, IPADM_DB_READ);
if (err == ENOENT && cbarg.cb_ocnt > 0) {
err = 0;
}
if (err != 0)
goto fail;
if ((err = nvlist_size(cbarg.cb_onvl, &nvlsize, NV_ENCODE_NATIVE)) != 0)
goto fail;
if (nvlsize > (UINT32_MAX - sizeof (ipmgmt_get_rval_t)))
goto fail;
buflen = nvlsize + sizeof (ipmgmt_get_rval_t);
buf = alloca(buflen);
onvlbuf = buf + sizeof (ipmgmt_get_rval_t);
if ((err = nvlist_pack(cbarg.cb_onvl, &onvlbuf, &nvlsize,
NV_ENCODE_NATIVE, 0)) != 0) {
goto fail;
}
nvlist_free(cbarg.cb_invl);
nvlist_free(cbarg.cb_onvl);
rvalp = (ipmgmt_get_rval_t *)(void *)buf;
rvalp->ir_err = 0;
rvalp->ir_nvlsize = nvlsize;
(void) door_return(buf, buflen, NULL, 0);
return;
fail:
nvlist_free(cbarg.cb_invl);
nvlist_free(cbarg.cb_onvl);
rvalp->ir_err = err;
(void) door_return((char *)rvalp, sizeof (*rvalp), NULL, 0);
}
int
ipmgmt_persist_if(ipmgmt_if_arg_t *sargp)
{
ipadm_dbwrite_cbarg_t cb;
uint32_t flags = sargp->ia_flags;
nvlist_t *nvl = NULL;
char strval[IPMGMT_STRSIZE];
int err = 0;
if (!(flags & IPMGMT_PERSIST) || sargp->ia_family == AF_UNSPEC ||
sargp->ia_ifname[0] == '\0') {
err = EINVAL;
goto ret;
}
if ((err = nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0)) != 0)
goto ret;
if ((err = nvlist_add_string(nvl, IPADM_NVP_IFNAME,
sargp->ia_ifname)) != 0)
goto ret;
if ((err = ipmgmt_update_family_nvp(nvl, sargp->ia_family,
IPMGMT_APPEND)) != 0)
goto ret;
(void) snprintf(strval, IPMGMT_STRSIZE, "%d", sargp->ia_ifclass);
if ((err = nvlist_add_string(nvl, IPADM_NVP_IFCLASS, strval)) != 0)
goto ret;
cb.dbw_nvl = nvl;
cb.dbw_flags = IPMGMT_APPEND | IPMGMT_UPDATE_IF;
err = ipmgmt_db_walk(ipmgmt_db_update_if, &cb, IPADM_DB_WRITE);
ret:
nvlist_free(nvl);
return (err);
}
static void
ipmgmt_common_handler(char *if_name, char *aobj_name, db_wfunc_t worker)
{
size_t buflen, onvlsize;
char *buf, *onvlbuf;
ipmgmt_get_cbarg_t cbarg;
ipmgmt_get_rval_t rval, *rvalp = &rval;
int err = 0;
cbarg.cb_ifname = if_name;
cbarg.cb_aobjname = aobj_name;
cbarg.cb_ocnt = 0;
if (nvlist_alloc(&cbarg.cb_onvl, NV_UNIQUE_NAME, 0) != 0)
goto fail;
err = ipmgmt_db_walk(worker, &cbarg, IPADM_DB_READ);
if (err == ENOENT && cbarg.cb_ocnt > 0) {
err = 0;
}
if (err != 0)
goto fail;
if ((err = nvlist_size(cbarg.cb_onvl, &onvlsize,
NV_ENCODE_NATIVE)) != 0)
goto fail;
if (onvlsize > (UINT32_MAX - sizeof (ipmgmt_get_rval_t)))
goto fail;
buflen = onvlsize + sizeof (ipmgmt_get_rval_t);
buf = alloca(buflen);
onvlbuf = buf + sizeof (ipmgmt_get_rval_t);
if ((err = nvlist_pack(cbarg.cb_onvl, &onvlbuf,
&onvlsize, NV_ENCODE_NATIVE, 0)) != 0)
goto fail;
nvlist_free(cbarg.cb_onvl);
rvalp = (ipmgmt_get_rval_t *)(void *)buf;
rvalp->ir_err = 0;
rvalp->ir_nvlsize = onvlsize;
(void) door_return(buf, buflen, NULL, 0);
fail:
nvlist_free(cbarg.cb_onvl);
rvalp->ir_err = err;
(void) door_return((char *)rvalp, sizeof (*rvalp), NULL, 0);
}
static void
ipmgmt_ipmp_update_handler(void *argp)
{
ipmgmt_ipmp_update_arg_t *uargp = argp;
ipmgmt_retval_t rval;
ipadm_dbwrite_cbarg_t cb;
boolean_t gif_exists;
char gifname[LIFNAMSIZ];
nvlist_t *nvl = NULL;
uint32_t flags = uargp->ia_flags;
int err = 0;
assert(uargp->ia_cmd == IPMGMT_CMD_IPMP_UPDATE);
gif_exists = ipmgmt_persist_if_exists(uargp->ia_gifname,
AF_UNSPEC);
if (!ipmgmt_persist_if_exists(uargp->ia_mifname, AF_UNSPEC)) {
err = EINVAL;
goto ret;
}
ipmgmt_get_group_interface(uargp->ia_mifname, gifname, LIFNAMSIZ);
if (flags & IPMGMT_APPEND) {
if (!gif_exists) {
err = ENOENT;
goto ret;
}
if (gifname[0] != '\0') {
err = EEXIST;
goto ret;
}
}
if (flags & IPMGMT_REMOVE) {
if (!gif_exists || gifname[0] == '\0') {
err = ENOENT;
goto ret;
}
if (strcmp(uargp->ia_gifname, gifname) != 0) {
err = EINVAL;
goto ret;
}
}
if (flags & IPMGMT_PERSIST) {
if ((err = nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0)) != 0)
goto ret;
if ((err = nvlist_add_string(nvl, IPADM_NVP_IFNAME,
uargp->ia_gifname)) != 0)
goto ret;
if ((err = nvlist_add_string(nvl, IPADM_NVP_MIFNAMES,
uargp->ia_mifname)) != 0)
goto ret;
if ((err = nvlist_add_string(nvl, IPADM_NVP_GIFNAME,
uargp->ia_gifname)) != 0)
goto ret;
cb.dbw_nvl = nvl;
cb.dbw_flags = flags | IPMGMT_UPDATE_IF | IPMGMT_UPDATE_IPMP;
err = ipmgmt_db_walk(ipmgmt_db_update_if, &cb, IPADM_DB_WRITE);
}
ret:
nvlist_free(nvl);
rval.ir_err = err;
(void) door_return((char *)&rval, sizeof (rval), NULL, 0);
}