#include <unistd.h>
#include <errno.h>
#include <ctype.h>
#include <fcntl.h>
#include <strings.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/sockio.h>
#include <assert.h>
#include <libdllink.h>
#include <zone.h>
#include "libipadm_impl.h"
#include <inet/tunables.h>
#define IPADM_NONESTR "none"
#define DEF_METRIC_VAL 0
#define A_CNT(arr) (sizeof (arr) / sizeof (arr[0]))
static ipadm_status_t i_ipadm_validate_if(ipadm_handle_t, const char *,
uint_t, uint_t);
static ipadm_pd_getf_t i_ipadm_get_prop, i_ipadm_get_ifprop_flags,
i_ipadm_get_mtu, i_ipadm_get_metric,
i_ipadm_get_usesrc, i_ipadm_get_forwarding,
i_ipadm_get_ecnsack, i_ipadm_get_hostmodel;
static ipadm_pd_setf_t i_ipadm_set_prop, i_ipadm_set_mtu,
i_ipadm_set_ifprop_flags,
i_ipadm_set_metric, i_ipadm_set_usesrc,
i_ipadm_set_forwarding, i_ipadm_set_eprivport,
i_ipadm_set_ecnsack, i_ipadm_set_hostmodel;
static int protocols[] = { MOD_PROTO_IP, MOD_PROTO_RAWIP,
MOD_PROTO_TCP, MOD_PROTO_UDP,
MOD_PROTO_SCTP };
static ipadm_prop_desc_t ipadm_ip_prop_table[] = {
{ "arp", NULL, IPADMPROP_CLASS_IF, MOD_PROTO_IPV4, 0,
i_ipadm_set_ifprop_flags, i_ipadm_get_onoff,
i_ipadm_get_ifprop_flags },
{ "forwarding", NULL, IPADMPROP_CLASS_MODIF, MOD_PROTO_IPV4, 0,
i_ipadm_set_forwarding, i_ipadm_get_onoff,
i_ipadm_get_forwarding },
{ "metric", NULL, IPADMPROP_CLASS_IF, MOD_PROTO_IPV4, 0,
i_ipadm_set_metric, NULL, i_ipadm_get_metric },
{ "mtu", NULL, IPADMPROP_CLASS_IF, MOD_PROTO_IPV4, 0,
i_ipadm_set_mtu, i_ipadm_get_mtu, i_ipadm_get_mtu },
{ "exchange_routes", NULL, IPADMPROP_CLASS_IF, MOD_PROTO_IPV4, 0,
i_ipadm_set_ifprop_flags, i_ipadm_get_onoff,
i_ipadm_get_ifprop_flags },
{ "usesrc", NULL, IPADMPROP_CLASS_IF, MOD_PROTO_IPV4, 0,
i_ipadm_set_usesrc, NULL, i_ipadm_get_usesrc },
{ "ttl", NULL, IPADMPROP_CLASS_MODULE, MOD_PROTO_IPV4, 0,
i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop },
{ "forwarding", NULL, IPADMPROP_CLASS_MODIF, MOD_PROTO_IPV6, 0,
i_ipadm_set_forwarding, i_ipadm_get_onoff,
i_ipadm_get_forwarding },
{ "hoplimit", NULL, IPADMPROP_CLASS_MODULE, MOD_PROTO_IPV6, 0,
i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop },
{ "metric", NULL, IPADMPROP_CLASS_IF, MOD_PROTO_IPV6, 0,
i_ipadm_set_metric, NULL, i_ipadm_get_metric },
{ "mtu", NULL, IPADMPROP_CLASS_IF, MOD_PROTO_IPV6, 0,
i_ipadm_set_mtu, i_ipadm_get_mtu, i_ipadm_get_mtu },
{ "nud", NULL, IPADMPROP_CLASS_IF, MOD_PROTO_IPV6, 0,
i_ipadm_set_ifprop_flags, i_ipadm_get_onoff,
i_ipadm_get_ifprop_flags },
{ "exchange_routes", NULL, IPADMPROP_CLASS_IF, MOD_PROTO_IPV6, 0,
i_ipadm_set_ifprop_flags, i_ipadm_get_onoff,
i_ipadm_get_ifprop_flags },
{ "usesrc", NULL, IPADMPROP_CLASS_IF, MOD_PROTO_IPV6, 0,
i_ipadm_set_usesrc, NULL, i_ipadm_get_usesrc },
{ "hostmodel", NULL, IPADMPROP_CLASS_MODULE, MOD_PROTO_IPV6, 0,
i_ipadm_set_hostmodel, i_ipadm_get_hostmodel,
i_ipadm_get_hostmodel },
{ "hostmodel", NULL, IPADMPROP_CLASS_MODULE, MOD_PROTO_IPV4, 0,
i_ipadm_set_hostmodel, i_ipadm_get_hostmodel,
i_ipadm_get_hostmodel },
{ "standby", NULL, IPADMPROP_CLASS_IF, MOD_PROTO_IP, 0,
i_ipadm_set_ifprop_flags, i_ipadm_get_onoff,
i_ipadm_get_ifprop_flags },
{ NULL, NULL, 0, 0, 0, NULL, NULL, NULL }
};
static const char *ecn_sack_vals[] = {"never", "passive", "active", NULL};
static ipadm_prop_desc_t ipadm_tcp_prop_table[] = {
{ "congestion_control", NULL, IPADMPROP_CLASS_MODULE, MOD_PROTO_TCP, 0,
i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop },
{ "ecn", NULL, IPADMPROP_CLASS_MODULE, MOD_PROTO_TCP, 0,
i_ipadm_set_ecnsack, i_ipadm_get_ecnsack, i_ipadm_get_ecnsack },
{ "extra_priv_ports", NULL, IPADMPROP_CLASS_MODULE, MOD_PROTO_TCP,
IPADMPROP_MULVAL, i_ipadm_set_eprivport, i_ipadm_get_prop,
i_ipadm_get_prop },
{ "largest_anon_port", NULL, IPADMPROP_CLASS_MODULE, MOD_PROTO_TCP, 0,
i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop },
{ "max_buf", "_max_buf", IPADMPROP_CLASS_MODULE, MOD_PROTO_TCP, 0,
i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop },
{ "recv_buf", "recv_maxbuf", IPADMPROP_CLASS_MODULE, MOD_PROTO_TCP, 0,
i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop },
{ "sack", NULL, IPADMPROP_CLASS_MODULE, MOD_PROTO_TCP, 0,
i_ipadm_set_ecnsack, i_ipadm_get_ecnsack, i_ipadm_get_ecnsack },
{ "send_buf", "send_maxbuf", IPADMPROP_CLASS_MODULE, MOD_PROTO_TCP, 0,
i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop },
{ "smallest_anon_port", NULL, IPADMPROP_CLASS_MODULE, MOD_PROTO_TCP, 0,
i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop },
{ "smallest_nonpriv_port", NULL, IPADMPROP_CLASS_MODULE, MOD_PROTO_TCP,
0, i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop },
{ NULL, NULL, 0, 0, 0, NULL, NULL, NULL }
};
static ipadm_prop_desc_t ipadm_udp_prop_table[] = {
{ "extra_priv_ports", NULL, IPADMPROP_CLASS_MODULE, MOD_PROTO_UDP,
IPADMPROP_MULVAL, i_ipadm_set_eprivport, i_ipadm_get_prop,
i_ipadm_get_prop },
{ "largest_anon_port", NULL, IPADMPROP_CLASS_MODULE, MOD_PROTO_UDP, 0,
i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop },
{ "max_buf", "_max_buf", IPADMPROP_CLASS_MODULE, MOD_PROTO_UDP, 0,
i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop },
{ "recv_buf", "recv_maxbuf", IPADMPROP_CLASS_MODULE, MOD_PROTO_UDP, 0,
i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop },
{ "send_buf", "send_maxbuf", IPADMPROP_CLASS_MODULE, MOD_PROTO_UDP, 0,
i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop },
{ "smallest_anon_port", NULL, IPADMPROP_CLASS_MODULE, MOD_PROTO_UDP, 0,
i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop },
{ "smallest_nonpriv_port", NULL, IPADMPROP_CLASS_MODULE, MOD_PROTO_UDP,
0, i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop },
{ NULL, NULL, 0, 0, 0, NULL, NULL, NULL }
};
static ipadm_prop_desc_t ipadm_sctp_prop_table[] = {
{ "extra_priv_ports", NULL, IPADMPROP_CLASS_MODULE, MOD_PROTO_SCTP,
IPADMPROP_MULVAL, i_ipadm_set_eprivport, i_ipadm_get_prop,
i_ipadm_get_prop },
{ "largest_anon_port", NULL, IPADMPROP_CLASS_MODULE, MOD_PROTO_SCTP, 0,
i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop },
{ "max_buf", "_max_buf", IPADMPROP_CLASS_MODULE, MOD_PROTO_SCTP, 0,
i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop },
{ "recv_buf", "recv_maxbuf", IPADMPROP_CLASS_MODULE, MOD_PROTO_SCTP, 0,
i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop },
{ "send_buf", "send_maxbuf", IPADMPROP_CLASS_MODULE, MOD_PROTO_SCTP, 0,
i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop },
{ "smallest_anon_port", NULL, IPADMPROP_CLASS_MODULE, MOD_PROTO_SCTP, 0,
i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop },
{ "smallest_nonpriv_port", NULL, IPADMPROP_CLASS_MODULE, MOD_PROTO_SCTP,
0, i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop },
{ NULL, NULL, 0, 0, 0, NULL, NULL, NULL }
};
static ipadm_prop_desc_t ipadm_icmp_prop_table[] = {
{ "max_buf", "_max_buf", IPADMPROP_CLASS_MODULE, MOD_PROTO_RAWIP, 0,
i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop },
{ "recv_buf", "recv_maxbuf", IPADMPROP_CLASS_MODULE, MOD_PROTO_RAWIP, 0,
i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop },
{ "send_buf", "send_maxbuf", IPADMPROP_CLASS_MODULE, MOD_PROTO_RAWIP, 0,
i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop },
{ NULL, NULL, 0, 0, 0, NULL, NULL, NULL }
};
static const ipadm_prop_desc_t ipadm_privprop_template =
{ NULL, NULL, IPADMPROP_CLASS_MODULE, MOD_PROTO_NONE, 0,
i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop };
static ipadm_prop_desc_t *
i_ipadm_get_propdesc_table(uint_t proto)
{
switch (proto) {
case MOD_PROTO_IP:
case MOD_PROTO_IPV4:
case MOD_PROTO_IPV6:
return (ipadm_ip_prop_table);
case MOD_PROTO_RAWIP:
return (ipadm_icmp_prop_table);
case MOD_PROTO_TCP:
return (ipadm_tcp_prop_table);
case MOD_PROTO_UDP:
return (ipadm_udp_prop_table);
case MOD_PROTO_SCTP:
return (ipadm_sctp_prop_table);
}
return (NULL);
}
static ipadm_prop_desc_t *
i_ipadm_get_prop_desc(const char *pname, uint_t proto, int *errp)
{
int err = 0;
boolean_t matched_name = B_FALSE;
ipadm_prop_desc_t *ipdp = NULL, *ipdtbl;
if ((ipdtbl = i_ipadm_get_propdesc_table(proto)) == NULL) {
err = EINVAL;
goto ret;
}
for (ipdp = ipdtbl; ipdp->ipd_name != NULL; ipdp++) {
if (strcmp(pname, ipdp->ipd_name) == 0 ||
(ipdp->ipd_old_name != NULL &&
strcmp(pname, ipdp->ipd_old_name) == 0)) {
matched_name = B_TRUE;
if (ipdp->ipd_proto == proto)
break;
}
}
if (ipdp->ipd_name == NULL) {
err = ENOENT;
if (matched_name)
err = EPROTO;
ipdp = NULL;
}
ret:
if (errp != NULL)
*errp = err;
return (ipdp);
}
char *
ipadm_proto2str(uint_t proto)
{
switch (proto) {
case MOD_PROTO_IP:
return ("ip");
case MOD_PROTO_IPV4:
return ("ipv4");
case MOD_PROTO_IPV6:
return ("ipv6");
case MOD_PROTO_RAWIP:
return ("icmp");
case MOD_PROTO_TCP:
return ("tcp");
case MOD_PROTO_UDP:
return ("udp");
case MOD_PROTO_SCTP:
return ("sctp");
}
return (NULL);
}
uint_t
ipadm_str2proto(const char *protostr)
{
if (protostr == NULL)
return (MOD_PROTO_NONE);
if (strcmp(protostr, "tcp") == 0)
return (MOD_PROTO_TCP);
else if (strcmp(protostr, "udp") == 0)
return (MOD_PROTO_UDP);
else if (strcmp(protostr, "ip") == 0)
return (MOD_PROTO_IP);
else if (strcmp(protostr, "ipv4") == 0)
return (MOD_PROTO_IPV4);
else if (strcmp(protostr, "ipv6") == 0)
return (MOD_PROTO_IPV6);
else if (strcmp(protostr, "icmp") == 0)
return (MOD_PROTO_RAWIP);
else if (strcmp(protostr, "sctp") == 0)
return (MOD_PROTO_SCTP);
else if (strcmp(protostr, "arp") == 0)
return (MOD_PROTO_IP);
return (MOD_PROTO_NONE);
}
static ipadm_status_t
i_ipadm_set_mtu(ipadm_handle_t iph, const void *arg,
ipadm_prop_desc_t *pdp, const void *pval, uint_t proto, uint_t flags)
{
struct lifreq lifr;
char *endp;
uint_t mtu;
int s;
const char *ifname = arg;
char val[MAXPROPVALLEN];
if (flags & IPADM_OPT_DEFAULT) {
ipadm_status_t status;
uint_t size = MAXPROPVALLEN;
status = i_ipadm_get_prop(iph, arg, pdp, val, &size,
proto, MOD_PROP_DEFAULT);
if (status != IPADM_SUCCESS)
return (status);
pval = val;
}
errno = 0;
mtu = (uint_t)strtol(pval, &endp, 10);
if (errno != 0 || *endp != '\0')
return (IPADM_INVALID_ARG);
bzero(&lifr, sizeof (lifr));
(void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
lifr.lifr_mtu = mtu;
s = (proto == MOD_PROTO_IPV6 ? iph->iph_sock6 : iph->iph_sock);
if (ioctl(s, SIOCSLIFMTU, (caddr_t)&lifr) < 0)
return (ipadm_errno2status(errno));
return (IPADM_SUCCESS);
}
static ipadm_status_t
i_ipadm_set_metric(ipadm_handle_t iph, const void *arg,
ipadm_prop_desc_t *pdp, const void *pval, uint_t proto, uint_t flags)
{
struct lifreq lifr;
char *endp;
int metric;
const char *ifname = arg;
int s;
if (flags & IPADM_OPT_DEFAULT) {
metric = DEF_METRIC_VAL;
} else {
errno = 0;
metric = (uint_t)strtol(pval, &endp, 10);
if (errno != 0 || *endp != '\0')
return (IPADM_INVALID_ARG);
}
bzero(&lifr, sizeof (lifr));
(void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
lifr.lifr_metric = metric;
s = (proto == MOD_PROTO_IPV6 ? iph->iph_sock6 : iph->iph_sock);
if (ioctl(s, SIOCSLIFMETRIC, (caddr_t)&lifr) < 0)
return (ipadm_errno2status(errno));
return (IPADM_SUCCESS);
}
static ipadm_status_t
i_ipadm_set_usesrc(ipadm_handle_t iph, const void *arg,
ipadm_prop_desc_t *pdp, const void *pval, uint_t proto, uint_t flags)
{
struct lifreq lifr;
const char *ifname = arg;
int s;
uint_t ifindex = 0;
if (flags & IPADM_OPT_DEFAULT)
pval = IPADM_NONESTR;
if (strcmp(pval, IPADM_NONESTR) != 0 &&
!i_ipadm_validate_ifname(iph, pval))
return (IPADM_INVALID_ARG);
bzero(&lifr, sizeof (lifr));
(void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
s = (proto == MOD_PROTO_IPV6 ? iph->iph_sock6 : iph->iph_sock);
if (strcmp(pval, IPADM_NONESTR) != 0) {
if ((ifindex = if_nametoindex(pval)) == 0)
return (ipadm_errno2status(errno));
lifr.lifr_index = ifindex;
} else {
if (ioctl(s, SIOCGLIFUSESRC, (caddr_t)&lifr) < 0)
return (ipadm_errno2status(errno));
lifr.lifr_index = 0;
}
if (ioctl(s, SIOCSLIFUSESRC, (caddr_t)&lifr) < 0)
return (ipadm_errno2status(errno));
return (IPADM_SUCCESS);
}
static struct hostmodel_strval {
char *esm_str;
ip_hostmodel_t esm_val;
} esm_arr[] = {
{"weak", IP_WEAK_ES},
{"src-priority", IP_SRC_PRI_ES},
{"strong", IP_STRONG_ES},
{"custom", IP_MAXVAL_ES}
};
static ip_hostmodel_t
i_ipadm_hostmodel_str2val(const char *pval)
{
int i;
for (i = 0; i < A_CNT(esm_arr); i++) {
if (esm_arr[i].esm_str != NULL &&
strcmp(pval, esm_arr[i].esm_str) == 0) {
return (esm_arr[i].esm_val);
}
}
return (IP_MAXVAL_ES);
}
static char *
i_ipadm_hostmodel_val2str(ip_hostmodel_t pval)
{
int i;
for (i = 0; i < A_CNT(esm_arr); i++) {
if (esm_arr[i].esm_val == pval)
return (esm_arr[i].esm_str);
}
return (NULL);
}
static ipadm_status_t
i_ipadm_set_hostmodel(ipadm_handle_t iph, const void *arg,
ipadm_prop_desc_t *pdp, const void *pval, uint_t proto, uint_t flags)
{
ip_hostmodel_t hostmodel;
char val[11];
if ((flags & IPADM_OPT_DEFAULT) == 0) {
hostmodel = i_ipadm_hostmodel_str2val(pval);
if (hostmodel == IP_MAXVAL_ES)
return (IPADM_INVALID_ARG);
(void) snprintf(val, sizeof (val), "%d", hostmodel);
pval = val;
}
return (i_ipadm_set_prop(iph, NULL, pdp, pval, proto, flags));
}
static ipadm_status_t
i_ipadm_get_hostmodel(ipadm_handle_t iph, const void *arg,
ipadm_prop_desc_t *pdp, char *buf, uint_t *bufsize, uint_t proto,
uint_t valtype)
{
ip_hostmodel_t hostmodel;
char *cp;
size_t nbytes;
ipadm_status_t status;
switch (valtype) {
case MOD_PROP_PERM:
nbytes = snprintf(buf, *bufsize, "%d", MOD_PROP_PERM_RW);
break;
case MOD_PROP_DEFAULT:
nbytes = snprintf(buf, *bufsize, "weak");
break;
case MOD_PROP_ACTIVE:
status = i_ipadm_get_prop(iph, arg, pdp, buf, bufsize, proto,
valtype);
if (status != IPADM_SUCCESS)
return (status);
bcopy(buf, &hostmodel, sizeof (hostmodel));
cp = i_ipadm_hostmodel_val2str(hostmodel);
nbytes = snprintf(buf, *bufsize, "%s",
(cp != NULL ? cp : "?"));
break;
case MOD_PROP_POSSIBLE:
nbytes = snprintf(buf, *bufsize, "strong,src-priority,weak");
break;
default:
return (IPADM_INVALID_ARG);
}
if (nbytes >= *bufsize) {
*bufsize = nbytes + 1;
return (IPADM_NO_BUFS);
}
return (IPADM_SUCCESS);
}
static ipadm_status_t
i_ipadm_set_ifprop_flags(ipadm_handle_t iph, const void *arg,
ipadm_prop_desc_t *pdp, const void *pval, uint_t proto, uint_t flags)
{
ipadm_status_t status = IPADM_SUCCESS;
const char *ifname = arg;
uint64_t on_flags = 0, off_flags = 0;
boolean_t on = B_FALSE;
sa_family_t af = (proto == MOD_PROTO_IPV6 ? AF_INET6 : AF_INET);
if (flags & IPADM_OPT_DEFAULT) {
if (strcmp(pdp->ipd_name, "exchange_routes") == 0 ||
strcmp(pdp->ipd_name, "arp") == 0 ||
strcmp(pdp->ipd_name, "nud") == 0) {
pval = IPADM_ONSTR;
} else if (strcmp(pdp->ipd_name, "forwarding") == 0 ||
strcmp(pdp->ipd_name, "standby") == 0) {
pval = IPADM_OFFSTR;
} else {
return (IPADM_PROP_UNKNOWN);
}
}
if (strcmp(pval, IPADM_ONSTR) == 0)
on = B_TRUE;
else if (strcmp(pval, IPADM_OFFSTR) == 0)
on = B_FALSE;
else
return (IPADM_INVALID_ARG);
if (strcmp(pdp->ipd_name, "exchange_routes") == 0) {
if (on)
off_flags = IFF_NORTEXCH;
else
on_flags = IFF_NORTEXCH;
} else if (strcmp(pdp->ipd_name, "arp") == 0) {
if (on)
off_flags = IFF_NOARP;
else
on_flags = IFF_NOARP;
} else if (strcmp(pdp->ipd_name, "nud") == 0) {
if (on)
off_flags = IFF_NONUD;
else
on_flags = IFF_NONUD;
} else if (strcmp(pdp->ipd_name, "forwarding") == 0) {
if (on)
on_flags = IFF_ROUTER;
else
off_flags = IFF_ROUTER;
} else if (strcmp(pdp->ipd_name, "standby") == 0) {
if (on)
on_flags = IFF_STANDBY;
else
off_flags = IFF_STANDBY;
}
if (on_flags || off_flags) {
status = i_ipadm_set_flags(iph, ifname, af, on_flags,
off_flags);
}
return (status);
}
static ipadm_status_t
i_ipadm_set_eprivport(ipadm_handle_t iph, const void *arg,
ipadm_prop_desc_t *pdp, const void *pval, uint_t proto, uint_t flags)
{
nvlist_t *portsnvl = NULL;
nvpair_t *nvp;
ipadm_status_t status = IPADM_SUCCESS;
uint_t count = 0;
if (flags & IPADM_OPT_DEFAULT) {
assert(pval == NULL);
return (i_ipadm_set_prop(iph, arg, pdp, pval, proto, flags));
}
if ((status = ipadm_str2nvlist(pval, &portsnvl, IPADM_NORVAL)) != 0)
return (status);
for (nvp = nvlist_next_nvpair(portsnvl, NULL); nvp != NULL;
nvp = nvlist_next_nvpair(portsnvl, nvp)) {
++count;
}
if (iph->iph_flags & IPH_INIT) {
flags |= IPADM_OPT_APPEND;
} else if (count > 1) {
nvlist_free(portsnvl);
return (IPADM_INVALID_ARG);
}
for (nvp = nvlist_next_nvpair(portsnvl, NULL); nvp != NULL;
nvp = nvlist_next_nvpair(portsnvl, nvp)) {
status = i_ipadm_set_prop(iph, arg, pdp, nvpair_name(nvp),
proto, flags);
if (status != IPADM_SUCCESS)
break;
}
nvlist_free(portsnvl);
return (status);
}
static ipadm_status_t
i_ipadm_set_forwarding(ipadm_handle_t iph, const void *arg,
ipadm_prop_desc_t *pdp, const void *pval, uint_t proto, uint_t flags)
{
const char *ifname = arg;
ipadm_status_t status;
if (ifname != NULL) {
status = i_ipadm_set_ifprop_flags(iph, ifname, pdp, pval,
proto, flags);
} else {
char *val = NULL;
if (!(flags & IPADM_OPT_DEFAULT) &&
!(iph->iph_flags & IPH_LEGACY)) {
if (strcmp(pval, IPADM_ONSTR) == 0)
val = "1";
else if (strcmp(pval, IPADM_OFFSTR) == 0)
val = "0";
else
return (IPADM_INVALID_ARG);
pval = val;
}
status = i_ipadm_set_prop(iph, ifname, pdp, pval, proto, flags);
}
return (status);
}
static ipadm_status_t
i_ipadm_set_ecnsack(ipadm_handle_t iph, const void *arg,
ipadm_prop_desc_t *pdp, const void *pval, uint_t proto, uint_t flags)
{
uint_t i;
char val[MAXPROPVALLEN];
if (!(flags & IPADM_OPT_DEFAULT) && !(iph->iph_flags & IPH_LEGACY)) {
for (i = 0; ecn_sack_vals[i] != NULL; i++) {
if (strcmp(pval, ecn_sack_vals[i]) == 0)
break;
}
if (ecn_sack_vals[i] == NULL)
return (IPADM_INVALID_ARG);
(void) snprintf(val, MAXPROPVALLEN, "%d", i);
pval = val;
}
return (i_ipadm_set_prop(iph, arg, pdp, pval, proto, flags));
}
ipadm_status_t
i_ipadm_get_ecnsack(ipadm_handle_t iph, const void *arg,
ipadm_prop_desc_t *pdp, char *buf, uint_t *bufsize, uint_t proto,
uint_t valtype)
{
ipadm_status_t status = IPADM_SUCCESS;
uint_t i, nbytes = 0;
switch (valtype) {
case MOD_PROP_POSSIBLE:
for (i = 0; ecn_sack_vals[i] != NULL; i++) {
if (i == 0)
nbytes += snprintf(buf + nbytes,
*bufsize - nbytes, "%s", ecn_sack_vals[i]);
else
nbytes += snprintf(buf + nbytes,
*bufsize - nbytes, ",%s", ecn_sack_vals[i]);
if (nbytes >= *bufsize)
break;
}
break;
case MOD_PROP_PERM:
case MOD_PROP_DEFAULT:
case MOD_PROP_ACTIVE:
status = i_ipadm_get_prop(iph, arg, pdp, buf, bufsize, proto,
valtype);
if (iph->iph_flags & IPH_LEGACY)
break;
if (status == IPADM_SUCCESS && (valtype == MOD_PROP_ACTIVE ||
valtype == MOD_PROP_DEFAULT)) {
i = atoi(buf);
assert(i < 3);
nbytes = snprintf(buf, *bufsize, "%s",
ecn_sack_vals[i]);
}
break;
default:
return (IPADM_INVALID_ARG);
}
if (nbytes >= *bufsize) {
*bufsize = nbytes + 1;
return (IPADM_NO_BUFS);
}
return (status);
}
static ipadm_status_t
i_ipadm_get_forwarding(ipadm_handle_t iph, const void *arg,
ipadm_prop_desc_t *pdp, char *buf, uint_t *bufsize, uint_t proto,
uint_t valtype)
{
const char *ifname = arg;
ipadm_status_t status = IPADM_SUCCESS;
if (ifname != NULL) {
status = i_ipadm_get_ifprop_flags(iph, ifname, pdp,
buf, bufsize, pdp->ipd_proto, valtype);
} else {
status = i_ipadm_get_prop(iph, ifname, pdp, buf,
bufsize, proto, valtype);
if (iph->iph_flags & IPH_LEGACY)
goto ret;
if (status == IPADM_SUCCESS && (valtype == MOD_PROP_ACTIVE ||
valtype == MOD_PROP_DEFAULT)) {
uint_t val = atoi(buf);
(void) snprintf(buf, *bufsize,
(val == 1 ? IPADM_ONSTR : IPADM_OFFSTR));
}
}
ret:
return (status);
}
static ipadm_status_t
i_ipadm_get_mtu(ipadm_handle_t iph, const void *arg,
ipadm_prop_desc_t *pdp, char *buf, uint_t *bufsize, uint_t proto,
uint_t valtype)
{
struct lifreq lifr;
const char *ifname = arg;
size_t nbytes;
int s;
switch (valtype) {
case MOD_PROP_PERM:
nbytes = snprintf(buf, *bufsize, "%d", MOD_PROP_PERM_RW);
break;
case MOD_PROP_DEFAULT:
case MOD_PROP_POSSIBLE:
return (i_ipadm_get_prop(iph, arg, pdp, buf, bufsize,
proto, valtype));
case MOD_PROP_ACTIVE:
bzero(&lifr, sizeof (lifr));
(void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
s = (proto == MOD_PROTO_IPV6 ? iph->iph_sock6 : iph->iph_sock);
if (ioctl(s, SIOCGLIFMTU, (caddr_t)&lifr) < 0)
return (ipadm_errno2status(errno));
nbytes = snprintf(buf, *bufsize, "%u", lifr.lifr_mtu);
break;
default:
return (IPADM_INVALID_ARG);
}
if (nbytes >= *bufsize) {
*bufsize = nbytes + 1;
return (IPADM_NO_BUFS);
}
return (IPADM_SUCCESS);
}
static ipadm_status_t
i_ipadm_get_metric(ipadm_handle_t iph, const void *arg,
ipadm_prop_desc_t *pdp, char *buf, uint_t *bufsize, uint_t proto,
uint_t valtype)
{
struct lifreq lifr;
const char *ifname = arg;
size_t nbytes;
int s, val;
switch (valtype) {
case MOD_PROP_PERM:
val = MOD_PROP_PERM_RW;
break;
case MOD_PROP_DEFAULT:
val = DEF_METRIC_VAL;
break;
case MOD_PROP_ACTIVE:
bzero(&lifr, sizeof (lifr));
(void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
s = (proto == MOD_PROTO_IPV6 ? iph->iph_sock6 : iph->iph_sock);
if (ioctl(s, SIOCGLIFMETRIC, (caddr_t)&lifr) < 0)
return (ipadm_errno2status(errno));
val = lifr.lifr_metric;
break;
default:
return (IPADM_INVALID_ARG);
}
nbytes = snprintf(buf, *bufsize, "%d", val);
if (nbytes >= *bufsize) {
*bufsize = nbytes + 1;
return (IPADM_NO_BUFS);
}
return (IPADM_SUCCESS);
}
static ipadm_status_t
i_ipadm_get_usesrc(ipadm_handle_t iph, const void *arg,
ipadm_prop_desc_t *ipd, char *buf, uint_t *bufsize, uint_t proto,
uint_t valtype)
{
struct lifreq lifr;
const char *ifname = arg;
int s;
char if_name[IF_NAMESIZE];
size_t nbytes;
switch (valtype) {
case MOD_PROP_PERM:
nbytes = snprintf(buf, *bufsize, "%d", MOD_PROP_PERM_RW);
break;
case MOD_PROP_DEFAULT:
nbytes = snprintf(buf, *bufsize, "%s", IPADM_NONESTR);
break;
case MOD_PROP_ACTIVE:
bzero(&lifr, sizeof (lifr));
(void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
s = (proto == MOD_PROTO_IPV6 ? iph->iph_sock6 : iph->iph_sock);
if (ioctl(s, SIOCGLIFUSESRC, (caddr_t)&lifr) < 0)
return (ipadm_errno2status(errno));
if (lifr.lifr_index == 0) {
(void) strlcpy(if_name, IPADM_NONESTR,
sizeof (if_name));
} else if (if_indextoname(lifr.lifr_index, if_name) == NULL) {
return (ipadm_errno2status(errno));
}
nbytes = snprintf(buf, *bufsize, "%s", if_name);
break;
default:
return (IPADM_INVALID_ARG);
}
if (nbytes >= *bufsize) {
*bufsize = nbytes + 1;
return (IPADM_NO_BUFS);
}
return (IPADM_SUCCESS);
}
static ipadm_status_t
i_ipadm_get_ifprop_flags(ipadm_handle_t iph, const void *arg,
ipadm_prop_desc_t *pdp, char *buf, uint_t *bufsize, uint_t proto,
uint_t valtype)
{
uint64_t intf_flags;
char *val;
size_t nbytes;
const char *ifname = arg;
sa_family_t af;
ipadm_status_t status = IPADM_SUCCESS;
switch (valtype) {
case MOD_PROP_PERM:
nbytes = snprintf(buf, *bufsize, "%d", MOD_PROP_PERM_RW);
break;
case MOD_PROP_DEFAULT:
if (strcmp(pdp->ipd_name, "exchange_routes") == 0 ||
strcmp(pdp->ipd_name, "arp") == 0 ||
strcmp(pdp->ipd_name, "nud") == 0) {
val = IPADM_ONSTR;
} else if (strcmp(pdp->ipd_name, "forwarding") == 0 ||
strcmp(pdp->ipd_name, "standby") == 0) {
val = IPADM_OFFSTR;
} else {
return (IPADM_PROP_UNKNOWN);
}
nbytes = snprintf(buf, *bufsize, "%s", val);
break;
case MOD_PROP_ACTIVE:
af = (proto == MOD_PROTO_IPV6 ? AF_INET6 : AF_INET);
status = i_ipadm_get_flags(iph, ifname, af, &intf_flags);
if (status != IPADM_SUCCESS)
return (status);
val = IPADM_OFFSTR;
if (strcmp(pdp->ipd_name, "exchange_routes") == 0) {
if (!(intf_flags & IFF_NORTEXCH))
val = IPADM_ONSTR;
} else if (strcmp(pdp->ipd_name, "forwarding") == 0) {
if (intf_flags & IFF_ROUTER)
val = IPADM_ONSTR;
} else if (strcmp(pdp->ipd_name, "arp") == 0) {
if (!(intf_flags & IFF_NOARP))
val = IPADM_ONSTR;
} else if (strcmp(pdp->ipd_name, "nud") == 0) {
if (!(intf_flags & IFF_NONUD))
val = IPADM_ONSTR;
} else if (strcmp(pdp->ipd_name, "standby") == 0) {
if (intf_flags & IFF_STANDBY)
val = IPADM_ONSTR;
}
nbytes = snprintf(buf, *bufsize, "%s", val);
break;
default:
return (IPADM_INVALID_ARG);
}
if (nbytes >= *bufsize) {
*bufsize = nbytes + 1;
status = IPADM_NO_BUFS;
}
return (status);
}
static void
i_ipadm_perm2str(char *buf, uint_t *bufsize)
{
uint_t perm = atoi(buf);
(void) snprintf(buf, *bufsize, "%c%c",
((perm & MOD_PROP_PERM_READ) != 0) ? 'r' : '-',
((perm & MOD_PROP_PERM_WRITE) != 0) ? 'w' : '-');
}
static ipadm_status_t
i_ipadm_get_prop(ipadm_handle_t iph, const void *arg,
ipadm_prop_desc_t *pdp, char *buf, uint_t *bufsize, uint_t proto,
uint_t valtype)
{
ipadm_status_t status = IPADM_SUCCESS;
const char *ifname = arg;
mod_ioc_prop_t *mip;
char *pname = pdp->ipd_name;
uint_t iocsize;
iocsize = sizeof (mod_ioc_prop_t) + *bufsize - 1;
if ((mip = calloc(1, iocsize)) == NULL)
return (IPADM_NO_BUFS);
mip->mpr_version = MOD_PROP_VERSION;
mip->mpr_flags = valtype;
mip->mpr_proto = proto;
if (ifname != NULL) {
(void) strlcpy(mip->mpr_ifname, ifname,
sizeof (mip->mpr_ifname));
}
(void) strlcpy(mip->mpr_name, pname, sizeof (mip->mpr_name));
mip->mpr_valsize = *bufsize;
if (i_ipadm_strioctl(iph->iph_sock, SIOCGETPROP, (char *)mip,
iocsize) < 0) {
if (errno == ENOENT)
status = IPADM_PROP_UNKNOWN;
else
status = ipadm_errno2status(errno);
} else {
bcopy(mip->mpr_val, buf, *bufsize);
}
free(mip);
return (status);
}
static void
i_ipadm_populate_proparg(ipmgmt_prop_arg_t *pargp, ipadm_prop_desc_t *pdp,
const char *pval, const void *object)
{
const struct ipadm_addrobj_s *ipaddr;
uint_t class = pdp->ipd_class;
uint_t proto = pdp->ipd_proto;
(void) strlcpy(pargp->ia_pname, pdp->ipd_name,
sizeof (pargp->ia_pname));
if (pval != NULL)
(void) strlcpy(pargp->ia_pval, pval, sizeof (pargp->ia_pval));
switch (class) {
case IPADMPROP_CLASS_MODULE:
if (pdp->ipd_name[0] == '_') {
(void) snprintf(pargp->ia_pname,
sizeof (pargp->ia_pname), "_%s", pdp->ipd_name);
}
(void) strlcpy(pargp->ia_module, object,
sizeof (pargp->ia_module));
break;
case IPADMPROP_CLASS_MODIF:
if (ipadm_str2proto(object) != MOD_PROTO_NONE) {
(void) strlcpy(pargp->ia_module, object,
sizeof (pargp->ia_module));
break;
}
case IPADMPROP_CLASS_IF:
(void) strlcpy(pargp->ia_ifname, object,
sizeof (pargp->ia_ifname));
(void) strlcpy(pargp->ia_module, ipadm_proto2str(proto),
sizeof (pargp->ia_module));
break;
case IPADMPROP_CLASS_ADDR:
ipaddr = object;
(void) strlcpy(pargp->ia_ifname, ipaddr->ipadm_ifname,
sizeof (pargp->ia_ifname));
(void) strlcpy(pargp->ia_aobjname, ipaddr->ipadm_aobjname,
sizeof (pargp->ia_aobjname));
break;
}
}
static ipadm_status_t
i_ipadm_getprop_common(ipadm_handle_t iph, const char *ifname,
const char *pname, char *buf, uint_t *bufsize, uint_t proto,
uint_t valtype)
{
ipadm_status_t status = IPADM_SUCCESS;
ipadm_prop_desc_t *pdp;
char priv_propname[MAXPROPNAMELEN];
ipadm_prop_desc_t ipadm_privprop = ipadm_privprop_template;
boolean_t is_if = (ifname != NULL);
int err = 0;
pdp = i_ipadm_get_prop_desc(pname, proto, &err);
if (err == EPROTO)
return (IPADM_BAD_PROTOCOL);
if (is_if && err == ENOENT)
return (IPADM_PROP_UNKNOWN);
if (pdp != NULL) {
if (is_if && !(pdp->ipd_class & IPADMPROP_CLASS_IF))
return (IPADM_INVALID_ARG);
if (!is_if && !(pdp->ipd_class & IPADMPROP_CLASS_MODULE))
return (IPADM_INVALID_ARG);
} else {
pdp = &ipadm_privprop;
(void) strlcpy(priv_propname, pname, sizeof (priv_propname));
pdp->ipd_name = priv_propname;
}
switch (valtype) {
case IPADM_OPT_PERM:
status = pdp->ipd_get(iph, ifname, pdp, buf, bufsize, proto,
MOD_PROP_PERM);
if (status == IPADM_SUCCESS)
i_ipadm_perm2str(buf, bufsize);
break;
case IPADM_OPT_ACTIVE:
status = pdp->ipd_get(iph, ifname, pdp, buf, bufsize, proto,
MOD_PROP_ACTIVE);
break;
case IPADM_OPT_DEFAULT:
status = pdp->ipd_get(iph, ifname, pdp, buf, bufsize, proto,
MOD_PROP_DEFAULT);
break;
case IPADM_OPT_POSSIBLE:
if (pdp->ipd_get_range != NULL) {
status = pdp->ipd_get_range(iph, ifname, pdp, buf,
bufsize, proto, MOD_PROP_POSSIBLE);
break;
}
buf[0] = '\0';
break;
case IPADM_OPT_PERSIST:
if (is_if)
status = i_ipadm_get_persist_propval(iph, pdp, buf,
bufsize, ifname);
else
status = i_ipadm_get_persist_propval(iph, pdp, buf,
bufsize, ipadm_proto2str(proto));
break;
default:
status = IPADM_INVALID_ARG;
break;
}
return (status);
}
ipadm_status_t
ipadm_get_prop(ipadm_handle_t iph, const char *pname, char *buf,
uint_t *bufsize, uint_t proto, uint_t valtype)
{
if (iph == NULL || pname == NULL || buf == NULL ||
bufsize == NULL || *bufsize == 0) {
return (IPADM_INVALID_ARG);
}
if (ipadm_proto2str(proto) == NULL)
return (IPADM_NOTSUP);
return (i_ipadm_getprop_common(iph, NULL, pname, buf, bufsize,
proto, valtype));
}
ipadm_status_t
ipadm_get_ifprop(ipadm_handle_t iph, const char *ifname, const char *pname,
char *buf, uint_t *bufsize, uint_t proto, uint_t valtype)
{
if (iph == NULL || pname == NULL || buf == NULL ||
bufsize == NULL || *bufsize == 0) {
return (IPADM_INVALID_ARG);
}
if (ipadm_proto2str(proto) == NULL)
return (IPADM_NOTSUP);
if (!i_ipadm_validate_ifname(iph, ifname))
return (IPADM_INVALID_ARG);
return (i_ipadm_getprop_common(iph, ifname, pname, buf, bufsize,
proto, valtype));
}
static ipadm_status_t
i_ipadm_set_prop(ipadm_handle_t iph, const void *arg,
ipadm_prop_desc_t *pdp, const void *pval, uint_t proto, uint_t flags)
{
ipadm_status_t status = IPADM_SUCCESS;
const char *ifname = arg;
mod_ioc_prop_t *mip;
char *pname = pdp->ipd_name;
uint_t valsize, iocsize;
uint_t iocflags = 0;
if (flags & IPADM_OPT_DEFAULT) {
iocflags |= MOD_PROP_DEFAULT;
} else if (flags & IPADM_OPT_ACTIVE) {
iocflags |= MOD_PROP_ACTIVE;
if (flags & IPADM_OPT_APPEND)
iocflags |= MOD_PROP_APPEND;
else if (flags & IPADM_OPT_REMOVE)
iocflags |= MOD_PROP_REMOVE;
}
if (pval != NULL) {
valsize = strlen(pval);
iocsize = sizeof (mod_ioc_prop_t) + valsize - 1;
} else {
valsize = 0;
iocsize = sizeof (mod_ioc_prop_t);
}
if ((mip = calloc(1, iocsize)) == NULL)
return (IPADM_NO_BUFS);
mip->mpr_version = MOD_PROP_VERSION;
mip->mpr_flags = iocflags;
mip->mpr_proto = proto;
if (ifname != NULL) {
(void) strlcpy(mip->mpr_ifname, ifname,
sizeof (mip->mpr_ifname));
}
(void) strlcpy(mip->mpr_name, pname, sizeof (mip->mpr_name));
mip->mpr_valsize = valsize;
if (pval != NULL)
bcopy(pval, mip->mpr_val, valsize);
if (i_ipadm_strioctl(iph->iph_sock, SIOCSETPROP, (char *)mip,
iocsize) < 0) {
if (errno == ENOENT)
status = IPADM_PROP_UNKNOWN;
else
status = ipadm_errno2status(errno);
}
free(mip);
return (status);
}
static ipadm_status_t
i_ipadm_setprop_common(ipadm_handle_t iph, const char *ifname,
const char *pname, const char *buf, uint_t proto, uint_t pflags)
{
ipadm_status_t status = IPADM_SUCCESS;
boolean_t persist = (pflags & IPADM_OPT_PERSIST);
boolean_t reset = (pflags & IPADM_OPT_DEFAULT);
ipadm_prop_desc_t *pdp;
boolean_t is_if = (ifname != NULL);
char priv_propname[MAXPROPNAMELEN];
ipadm_prop_desc_t ipadm_privprop = ipadm_privprop_template;
int err = 0;
if (!reset && strnlen(buf, MAXPROPVALLEN) >= MAXPROPVALLEN)
return (IPADM_INVALID_ARG);
pdp = i_ipadm_get_prop_desc(pname, proto, &err);
if (err == EPROTO)
return (IPADM_BAD_PROTOCOL);
if (is_if && err == ENOENT)
return (IPADM_PROP_UNKNOWN);
if (pdp != NULL) {
if (is_if) {
if (!(pdp->ipd_class & IPADMPROP_CLASS_IF))
return (IPADM_INVALID_ARG);
} else {
if (!(pdp->ipd_class & IPADMPROP_CLASS_MODULE))
return (IPADM_INVALID_ARG);
}
if (!(pdp->ipd_flags & IPADMPROP_MULVAL) && (pflags &
(IPADM_OPT_APPEND|IPADM_OPT_REMOVE))) {
return (IPADM_INVALID_ARG);
}
} else {
pdp = &ipadm_privprop;
(void) strlcpy(priv_propname, pname, sizeof (priv_propname));
pdp->ipd_name = priv_propname;
}
status = pdp->ipd_set(iph, ifname, pdp, buf, proto, pflags);
if (status != IPADM_SUCCESS)
return (status);
if (persist) {
if (is_if)
status = i_ipadm_persist_propval(iph, pdp, buf, ifname,
pflags);
else
status = i_ipadm_persist_propval(iph, pdp, buf,
ipadm_proto2str(proto), pflags);
}
return (status);
}
ipadm_status_t
ipadm_set_ifprop(ipadm_handle_t iph, const char *ifname, const char *pname,
const char *buf, uint_t proto, uint_t pflags)
{
boolean_t reset = (pflags & IPADM_OPT_DEFAULT);
ipadm_status_t status;
if (!ipadm_check_auth())
return (IPADM_EAUTH);
if (iph == NULL || pname == NULL || (!reset && buf == NULL) ||
pflags == 0 || pflags == IPADM_OPT_PERSIST ||
(pflags & ~(IPADM_COMMON_OPT_MASK|IPADM_OPT_DEFAULT))) {
return (IPADM_INVALID_ARG);
}
if (ipadm_proto2str(proto) == NULL)
return (IPADM_NOTSUP);
status = i_ipadm_validate_if(iph, ifname, proto, pflags);
if (status != IPADM_SUCCESS)
return (status);
return (i_ipadm_setprop_common(iph, ifname, pname, buf, proto,
pflags));
}
ipadm_status_t
ipadm_set_prop(ipadm_handle_t iph, const char *pname, const char *buf,
uint_t proto, uint_t pflags)
{
boolean_t reset = (pflags & IPADM_OPT_DEFAULT);
if (!ipadm_check_auth())
return (IPADM_EAUTH);
if (iph == NULL || pname == NULL ||(!reset && buf == NULL) ||
pflags == 0 || pflags == IPADM_OPT_PERSIST ||
(pflags & ~(IPADM_COMMON_OPT_MASK|IPADM_OPT_DEFAULT|
IPADM_OPT_APPEND|IPADM_OPT_REMOVE))) {
return (IPADM_INVALID_ARG);
}
if (ipadm_proto2str(proto) == NULL)
return (IPADM_NOTSUP);
return (i_ipadm_setprop_common(iph, NULL, pname, buf, proto,
pflags));
}
static void
i_ipadm_walk_proptbl(ipadm_prop_desc_t *pdtbl, uint_t proto, uint_t class,
ipadm_prop_wfunc_t *func, void *arg)
{
ipadm_prop_desc_t *pdp;
for (pdp = pdtbl; pdp->ipd_name != NULL; pdp++) {
if (!(pdp->ipd_class & class))
continue;
if (proto != MOD_PROTO_NONE && !(pdp->ipd_proto & proto))
continue;
if (func(arg, pdp->ipd_name, pdp->ipd_proto) == B_FALSE)
break;
}
}
ipadm_status_t
ipadm_walk_proptbl(uint_t proto, uint_t class, ipadm_prop_wfunc_t *func,
void *arg)
{
ipadm_prop_desc_t *pdtbl;
ipadm_status_t status = IPADM_SUCCESS;
int i;
int count = A_CNT(protocols);
if (func == NULL)
return (IPADM_INVALID_ARG);
switch (class) {
case IPADMPROP_CLASS_ADDR:
pdtbl = ipadm_addrprop_table;
break;
case IPADMPROP_CLASS_IF:
case IPADMPROP_CLASS_MODULE:
pdtbl = i_ipadm_get_propdesc_table(proto);
if (pdtbl == NULL && proto != MOD_PROTO_NONE)
return (IPADM_INVALID_ARG);
break;
default:
return (IPADM_INVALID_ARG);
}
if (pdtbl != NULL) {
i_ipadm_walk_proptbl(pdtbl, proto, class, func, arg);
} else {
for (i = 0; i < count; i++) {
pdtbl = i_ipadm_get_propdesc_table(protocols[i]);
i_ipadm_walk_proptbl(pdtbl, protocols[i], class, func,
arg);
}
}
return (status);
}
ipadm_status_t
ipadm_walk_prop(const char *pname, uint_t proto, uint_t class,
ipadm_prop_wfunc_t *func, void *arg)
{
ipadm_prop_desc_t *pdtbl, *pdp;
ipadm_status_t status = IPADM_SUCCESS;
boolean_t matched = B_FALSE;
if (pname == NULL || func == NULL)
return (IPADM_INVALID_ARG);
switch (class) {
case IPADMPROP_CLASS_ADDR:
pdtbl = ipadm_addrprop_table;
break;
case IPADMPROP_CLASS_IF:
case IPADMPROP_CLASS_MODULE:
pdtbl = i_ipadm_get_propdesc_table(proto);
break;
default:
return (IPADM_INVALID_ARG);
}
if (pdtbl == NULL)
return (IPADM_INVALID_ARG);
for (pdp = pdtbl; pdp->ipd_name != NULL; pdp++) {
if (strcmp(pname, pdp->ipd_name) != 0)
continue;
if (!(pdp->ipd_proto & proto))
continue;
matched = B_TRUE;
if (func(arg, pdp->ipd_name, pdp->ipd_proto) == B_FALSE)
break;
}
if (!matched)
status = IPADM_PROP_UNKNOWN;
return (status);
}
ipadm_status_t
i_ipadm_get_onoff(ipadm_handle_t iph, const void *arg, ipadm_prop_desc_t *dp,
char *buf, uint_t *bufsize, uint_t proto, uint_t valtype)
{
(void) snprintf(buf, *bufsize, "%s,%s", IPADM_ONSTR, IPADM_OFFSTR);
return (IPADM_SUCCESS);
}
ipadm_status_t
i_ipadm_get_persist_propval(ipadm_handle_t iph, ipadm_prop_desc_t *pdp,
char *gbuf, uint_t *gbufsize, const void *object)
{
ipmgmt_prop_arg_t parg;
ipmgmt_getprop_rval_t rval, *rvalp;
size_t nbytes;
int err = 0;
bzero(&parg, sizeof (parg));
parg.ia_cmd = IPMGMT_CMD_GETPROP;
i_ipadm_populate_proparg(&parg, pdp, NULL, object);
rvalp = &rval;
err = ipadm_door_call(iph, &parg, sizeof (parg), (void **)&rvalp,
sizeof (rval), B_FALSE);
if (err == 0) {
assert(rvalp == &rval);
nbytes = snprintf(gbuf, *gbufsize, "%s", rvalp->ir_pval);
if (nbytes >= *gbufsize) {
*gbufsize = nbytes + 1;
err = ENOBUFS;
}
}
return (ipadm_errno2status(err));
}
ipadm_status_t
i_ipadm_persist_propval(ipadm_handle_t iph, ipadm_prop_desc_t *pdp,
const char *pval, const void *object, uint_t flags)
{
ipmgmt_prop_arg_t parg;
int err = 0;
bzero(&parg, sizeof (parg));
i_ipadm_populate_proparg(&parg, pdp, pval, object);
if (flags & IPADM_OPT_APPEND)
parg.ia_flags |= IPMGMT_APPEND;
if (flags & IPADM_OPT_REMOVE)
parg.ia_flags |= IPMGMT_REMOVE;
if (flags & (IPADM_OPT_DEFAULT|IPADM_OPT_REMOVE))
parg.ia_cmd = IPMGMT_CMD_RESETPROP;
else
parg.ia_cmd = IPMGMT_CMD_SETPROP;
err = ipadm_door_call(iph, &parg, sizeof (parg), NULL, 0, B_FALSE);
if (err == ENOENT)
err = 0;
return (ipadm_errno2status(err));
}
static ipadm_status_t
i_ipadm_validate_if(ipadm_handle_t iph, const char *ifname,
uint_t proto, uint_t flags)
{
sa_family_t af, other_af;
ipadm_status_t status;
boolean_t p_exists;
boolean_t af_exists, other_af_exists, a_exists;
if (!i_ipadm_validate_ifname(iph, ifname))
return (IPADM_INVALID_ARG);
af = (proto == MOD_PROTO_IPV6 ? AF_INET6 : AF_INET);
status = i_ipadm_if_pexists(iph, ifname, af, &p_exists);
if (status != IPADM_SUCCESS)
return (status);
af_exists = ipadm_if_enabled(iph, ifname, af);
other_af = (af == AF_INET ? AF_INET6 : AF_INET);
other_af_exists = ipadm_if_enabled(iph, ifname, other_af);
a_exists = (af_exists || other_af_exists);
if (!a_exists && p_exists)
return (IPADM_OP_DISABLE_OBJ);
if (!af_exists)
return (IPADM_ENXIO);
if ((flags & IPADM_OPT_PERSIST) && !p_exists)
return (IPADM_TEMPORARY_OBJ);
return (IPADM_SUCCESS);
}
typedef struct ipadm_oname2nname_map {
char *iom_oname;
char *iom_nname;
uint_t iom_proto;
} ipadm_oname2nname_map_t;
static ipadm_oname2nname_map_t name_map[] = {
{ "arp_probe_delay", "_arp_probe_delay",
MOD_PROTO_IP },
{ "arp_fastprobe_delay", "_arp_fastprobe_delay",
MOD_PROTO_IP },
{ "arp_probe_interval", "_arp_probe_interval",
MOD_PROTO_IP },
{ "arp_fastprobe_interval", "_arp_fastprobe_interval",
MOD_PROTO_IP },
{ "arp_probe_count", "_arp_probe_count",
MOD_PROTO_IP },
{ "arp_fastprobe_count", "_arp_fastprobe_count",
MOD_PROTO_IP },
{ "arp_defend_interval", "_arp_defend_interval",
MOD_PROTO_IP },
{ "arp_defend_rate", "_arp_defend_rate",
MOD_PROTO_IP },
{ "arp_defend_period", "_arp_defend_period",
MOD_PROTO_IP },
{ "ndp_defend_interval", "_ndp_defend_interval",
MOD_PROTO_IP },
{ "ndp_defend_rate", "_ndp_defend_rate",
MOD_PROTO_IP },
{ "ndp_defend_period", "_ndp_defend_period",
MOD_PROTO_IP },
{ "igmp_max_version", "_igmp_max_version",
MOD_PROTO_IP },
{ "mld_max_version", "_mld_max_version",
MOD_PROTO_IP },
{ "ipsec_override_persocket_policy", "_ipsec_override_persocket_policy",
MOD_PROTO_IP },
{ "ipsec_policy_log_interval", "_ipsec_policy_log_interval",
MOD_PROTO_IP },
{ "icmp_accept_clear_messages", "_icmp_accept_clear_messages",
MOD_PROTO_IP },
{ "igmp_accept_clear_messages", "_igmp_accept_clear_messages",
MOD_PROTO_IP },
{ "pim_accept_clear_messages", "_pim_accept_clear_messages",
MOD_PROTO_IP },
{ "ip_respond_to_echo_multicast", "_respond_to_echo_multicast",
MOD_PROTO_IPV4 },
{ "ip_send_redirects", "_send_redirects",
MOD_PROTO_IPV4 },
{ "ip_forward_src_routed", "_forward_src_routed",
MOD_PROTO_IPV4 },
{ "ip_icmp_return_data_bytes", "_icmp_return_data_bytes",
MOD_PROTO_IPV4 },
{ "ip_ignore_redirect", "_ignore_redirect",
MOD_PROTO_IPV4 },
{ "ip_strict_dst_multihoming", "_strict_dst_multihoming",
MOD_PROTO_IPV4 },
{ "ip_reasm_timeout", "_reasm_timeout",
MOD_PROTO_IPV4 },
{ "ip_strict_src_multihoming", "_strict_src_multihoming",
MOD_PROTO_IPV4 },
{ "ipv4_dad_announce_interval", "_dad_announce_interval",
MOD_PROTO_IPV4 },
{ "ipv4_icmp_return_pmtu", "_icmp_return_pmtu",
MOD_PROTO_IPV4 },
{ "ipv6_dad_announce_interval", "_dad_announce_interval",
MOD_PROTO_IPV6 },
{ "ipv6_icmp_return_pmtu", "_icmp_return_pmtu",
MOD_PROTO_IPV6 },
{ NULL, NULL, MOD_PROTO_NONE }
};
int
ipadm_legacy2new_propname(const char *oname, char *nname, uint_t nnamelen,
uint_t *proto)
{
const char *str;
ipadm_oname2nname_map_t *ionmp;
if (i_ipadm_get_prop_desc(oname, *proto, NULL) != NULL)
return (-1);
str = oname;
switch (*proto) {
case MOD_PROTO_TCP:
if (strstr(oname, "tcp_") == oname)
str += strlen("tcp");
break;
case MOD_PROTO_SCTP:
if (strstr(oname, "sctp_") == oname)
str += strlen("sctp");
break;
case MOD_PROTO_UDP:
if (strstr(oname, "udp_") == oname)
str += strlen("udp");
break;
case MOD_PROTO_RAWIP:
if (strstr(oname, "icmp_") == oname)
str += strlen("icmp");
break;
case MOD_PROTO_IP:
case MOD_PROTO_IPV4:
case MOD_PROTO_IPV6:
if (strstr(oname, "ip6_") == oname) {
*proto = MOD_PROTO_IPV6;
str += strlen("ip6");
} else {
for (ionmp = name_map; ionmp->iom_oname != NULL;
ionmp++) {
if (strcmp(oname, ionmp->iom_oname) == 0) {
str = ionmp->iom_nname;
*proto = ionmp->iom_proto;
break;
}
}
if (ionmp->iom_oname != NULL)
break;
if (strstr(oname, "ip_") == oname) {
*proto = MOD_PROTO_IP;
str += strlen("ip");
}
}
break;
default:
return (-1);
}
(void) snprintf(nname, nnamelen, "%s", str);
return (0);
}
int
ipadm_new2legacy_propname(const char *oname, char *nname,
uint_t nnamelen, uint_t proto)
{
char *prefix;
ipadm_oname2nname_map_t *ionmp;
if (i_ipadm_get_prop_desc(oname, proto, NULL) != NULL)
return (-1);
switch (proto) {
case MOD_PROTO_TCP:
prefix = "tcp";
break;
case MOD_PROTO_SCTP:
prefix = "sctp";
break;
case MOD_PROTO_UDP:
prefix = "udp";
break;
case MOD_PROTO_RAWIP:
prefix = "icmp";
break;
case MOD_PROTO_IP:
case MOD_PROTO_IPV4:
case MOD_PROTO_IPV6:
for (ionmp = name_map; ionmp->iom_oname != NULL; ionmp++) {
if (strcmp(oname, ionmp->iom_nname) == 0 &&
ionmp->iom_proto == proto) {
(void) strlcpy(nname, ionmp->iom_oname,
nnamelen);
return (0);
}
}
if (proto == MOD_PROTO_IPV6)
prefix = "ip6";
else
prefix = "ip";
break;
default:
return (-1);
}
(void) snprintf(nname, nnamelen, "%s%s", prefix, oname);
return (0);
}