diff options
Diffstat (limited to 'usr/src/lib/libdladm/common/linkprop.c')
-rw-r--r-- | usr/src/lib/libdladm/common/linkprop.c | 508 |
1 files changed, 497 insertions, 11 deletions
diff --git a/usr/src/lib/libdladm/common/linkprop.c b/usr/src/lib/libdladm/common/linkprop.c index 044b963e45..b0c0c32f45 100644 --- a/usr/src/lib/libdladm/common/linkprop.c +++ b/usr/src/lib/libdladm/common/linkprop.c @@ -56,6 +56,9 @@ #include <sys/ethernet.h> #include <net/wpa.h> #include <sys/sysmacros.h> +#include <sys/vlan.h> +#include <libdlbridge.h> +#include <stp_in.h> /* * The linkprop get() callback. @@ -133,15 +136,18 @@ static pd_getf_t do_get_zone, do_get_autopush, do_get_rate_mod, i_dladm_binary_get, i_dladm_uint32_get, i_dladm_flowctl_get, i_dladm_maxbw_get, i_dladm_cpus_get, i_dladm_priority_get, - i_dladm_tagmode_get, i_dladm_range_get; + i_dladm_tagmode_get, i_dladm_range_get, + get_stp_prop, get_bridge_forward, + get_bridge_pvid; static pd_setf_t do_set_zone, do_set_rate_prop, do_set_powermode_prop, do_set_radio_prop, - i_dladm_set_public_prop, do_set_res, do_set_cpus; + i_dladm_set_public_prop, do_set_res, do_set_cpus, + set_stp_prop, set_bridge_forward, set_bridge_pvid; static pd_checkf_t do_check_zone, do_check_autopush, do_check_rate, - i_dladm_defmtu_check, do_check_maxbw, do_check_cpus, - do_check_priority; + i_dladm_uint32_check, do_check_maxbw, do_check_cpus, + do_check_priority, check_stp_prop, check_bridge_pvid; static dladm_status_t i_dladm_speed_get(dladm_handle_t, prop_desc_t *, datalink_id_t, char **, uint_t *, uint_t, uint_t *); @@ -173,8 +179,9 @@ struct prop_desc { uint_t pd_noptval; /* - * callback to set link property; - * set to NULL if this property is read-only + * callback to set link property; set to NULL if this property is + * read-only and may be called before or after permanent update; see + * flags. */ pd_setf_t *pd_set; @@ -199,6 +206,7 @@ struct prop_desc { uint_t pd_flags; #define PD_TEMPONLY 0x1 /* property is temporary only */ #define PD_CHECK_ALLOC 0x2 /* alloc vd_val as part of pd_check */ +#define PD_AFTER_PERM 0x4 /* pd_set after db update; no temporary */ /* * indicate link classes this property applies to. */ @@ -321,10 +329,31 @@ static link_attr_t link_attr[] = { { MAC_PROP_TAGMODE, sizeof (link_tagmode_t), "tagmode"}, + { MAC_PROP_PVID, sizeof (uint16_t), "default_tag"}, + + { MAC_PROP_LLIMIT, sizeof (uint32_t), "learn_limit"}, + + { MAC_PROP_LDECAY, sizeof (uint32_t), "learn_decay"}, + { MAC_PROP_PRIVATE, 0, "driver-private"} }; +typedef struct bridge_public_prop_s { + const char *bpp_name; + int bpp_code; +} bridge_public_prop_t; + +static const bridge_public_prop_t bridge_prop[] = { + { "stp", PT_CFG_NON_STP }, + { "stp_priority", PT_CFG_PRIO }, + { "stp_cost", PT_CFG_COST }, + { "stp_edge", PT_CFG_EDGE }, + { "stp_p2p", PT_CFG_P2P }, + { "stp_mcheck", PT_CFG_MCHECK }, + { NULL, 0 } +}; + static val_desc_t link_duplex_vals[] = { { "half", LINK_DUPLEX_HALF }, { "full", LINK_DUPLEX_HALF } @@ -365,6 +394,12 @@ static val_desc_t dladm_wlan_powermode_vals[] = { { "max", DLADM_WLAN_PM_MAX } }; +static val_desc_t stp_p2p_vals[] = { + { "true", P2P_FORCE_TRUE }, + { "false", P2P_FORCE_FALSE }, + { "auto", P2P_AUTO } +}; + #define VALCNT(vals) (sizeof ((vals)) / sizeof (val_desc_t)) #define RESET_VAL ((uintptr_t)-1) @@ -418,7 +453,7 @@ static prop_desc_t prop_table[] = { { "mtu", { "", 0 }, NULL, 0, i_dladm_set_public_prop, i_dladm_range_get, - i_dladm_uint32_get, i_dladm_defmtu_check, 0, DATALINK_CLASS_ALL, + i_dladm_uint32_get, i_dladm_uint32_check, 0, DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE }, { "flowctrl", { "", 0 }, @@ -516,7 +551,63 @@ static prop_desc_t prop_table[] = { i_dladm_set_public_prop, NULL, i_dladm_tagmode_get, NULL, 0, DATALINK_CLASS_PHYS | DATALINK_CLASS_AGGR | DATALINK_CLASS_VNIC, - DL_ETHER } + DL_ETHER }, + + { "forward", { "1", 1 }, + link_01_vals, VALCNT(link_01_vals), + set_bridge_forward, NULL, get_bridge_forward, NULL, PD_AFTER_PERM, + DATALINK_CLASS_ALL & ~DATALINK_CLASS_VNIC, DL_ETHER }, + + { "default_tag", { "1", 1 }, NULL, 0, + set_bridge_pvid, NULL, get_bridge_pvid, check_bridge_pvid, + 0, DATALINK_CLASS_PHYS|DATALINK_CLASS_AGGR| + DATALINK_CLASS_ETHERSTUB|DATALINK_CLASS_SIMNET, DL_ETHER }, + + { "learn_limit", { "1000", 1000 }, NULL, 0, + i_dladm_set_public_prop, NULL, i_dladm_uint32_get, + i_dladm_uint32_check, 0, + DATALINK_CLASS_PHYS|DATALINK_CLASS_AGGR| + DATALINK_CLASS_ETHERSTUB|DATALINK_CLASS_SIMNET, DL_ETHER }, + + { "learn_decay", { "200", 200 }, NULL, 0, + i_dladm_set_public_prop, NULL, i_dladm_uint32_get, + i_dladm_uint32_check, 0, + DATALINK_CLASS_PHYS|DATALINK_CLASS_AGGR| + DATALINK_CLASS_ETHERSTUB|DATALINK_CLASS_SIMNET, DL_ETHER }, + + { "stp", { "1", 1 }, + link_01_vals, VALCNT(link_01_vals), + set_stp_prop, NULL, get_stp_prop, NULL, PD_AFTER_PERM, + DATALINK_CLASS_PHYS|DATALINK_CLASS_AGGR| + DATALINK_CLASS_ETHERSTUB|DATALINK_CLASS_SIMNET, DL_ETHER }, + + { "stp_priority", { "128", 128 }, NULL, 0, + set_stp_prop, NULL, get_stp_prop, check_stp_prop, PD_AFTER_PERM, + DATALINK_CLASS_PHYS|DATALINK_CLASS_AGGR| + DATALINK_CLASS_ETHERSTUB|DATALINK_CLASS_SIMNET, DL_ETHER }, + + { "stp_cost", { "auto", 0 }, NULL, 0, + set_stp_prop, NULL, get_stp_prop, check_stp_prop, PD_AFTER_PERM, + DATALINK_CLASS_PHYS|DATALINK_CLASS_AGGR| + DATALINK_CLASS_ETHERSTUB|DATALINK_CLASS_SIMNET, DL_ETHER }, + + { "stp_edge", { "1", 1 }, + link_01_vals, VALCNT(link_01_vals), + set_stp_prop, NULL, get_stp_prop, NULL, PD_AFTER_PERM, + DATALINK_CLASS_PHYS|DATALINK_CLASS_AGGR| + DATALINK_CLASS_ETHERSTUB|DATALINK_CLASS_SIMNET, DL_ETHER }, + + { "stp_p2p", { "auto", P2P_AUTO }, + stp_p2p_vals, VALCNT(stp_p2p_vals), + set_stp_prop, NULL, get_stp_prop, NULL, PD_AFTER_PERM, + DATALINK_CLASS_PHYS|DATALINK_CLASS_AGGR| + DATALINK_CLASS_ETHERSTUB|DATALINK_CLASS_SIMNET, DL_ETHER }, + + { "stp_mcheck", { "0", 0 }, + link_01_vals, VALCNT(link_01_vals), + set_stp_prop, NULL, get_stp_prop, check_stp_prop, PD_AFTER_PERM, + DATALINK_CLASS_PHYS|DATALINK_CLASS_AGGR| + DATALINK_CLASS_ETHERSTUB|DATALINK_CLASS_SIMNET, DL_ETHER }, }; #define DLADM_MAX_PROPS (sizeof (prop_table) / sizeof (prop_desc_t)) @@ -658,7 +749,12 @@ i_dladm_set_single_prop(dladm_handle_t handle, datalink_id_t linkid, return (status); } } - status = pdp->pd_set(handle, pdp, linkid, vdp, cnt, flags, media); + if (pdp->pd_flags & PD_AFTER_PERM) + status = (flags & DLADM_OPT_PERSIST) ? DLADM_STATUS_OK : + DLADM_STATUS_PERMONLY; + else + status = pdp->pd_set(handle, pdp, linkid, vdp, cnt, flags, + media); if (needfree) { for (i = 0; i < cnt; i++) free((void *)((val_desc_t *)vdp + i)->vd_val); @@ -744,6 +840,21 @@ dladm_set_linkprop(dladm_handle_t handle, datalink_id_t linkid, if (flags & DLADM_OPT_PERSIST) { status = i_dladm_set_linkprop_db(handle, linkid, prop_name, prop_val, val_cnt); + + if (status == DLADM_STATUS_OK && (flags & DLADM_OPT_ACTIVE)) { + prop_desc_t *pdp = prop_table; + int i; + + for (i = 0; i < DLADM_MAX_PROPS; i++, pdp++) { + if (!(pdp->pd_flags & PD_AFTER_PERM)) + continue; + if (prop_name != NULL && + strcasecmp(prop_name, pdp->pd_name) != 0) + continue; + status = pdp->pd_set(handle, pdp, linkid, NULL, + 0, flags, 0); + } + } } return (status); } @@ -927,6 +1038,140 @@ dladm_get_linkprop(dladm_handle_t handle, datalink_id_t linkid, return (status); } +/* + * Get linkprop of the given specific link and run any possible conversion + * of the values using the check function for the property. Fails if the + * check function doesn't succeed for the property value. + */ +dladm_status_t +dladm_get_linkprop_values(dladm_handle_t handle, datalink_id_t linkid, + dladm_prop_type_t type, const char *prop_name, uint_t *ret_val, + uint_t *val_cntp) +{ + dladm_status_t status; + datalink_class_t class; + uint_t media; + prop_desc_t *pdp; + uint_t dld_flags; + int valc, i; + char **prop_val; + uint_t perm_flags; + + if (linkid == DATALINK_INVALID_LINKID || prop_name == NULL || + ret_val == NULL || val_cntp == NULL || *val_cntp == 0) + return (DLADM_STATUS_BADARG); + + for (pdp = prop_table; pdp < prop_table + DLADM_MAX_PROPS; pdp++) + if (strcasecmp(prop_name, pdp->pd_name) == 0) + break; + + if (pdp == prop_table + DLADM_MAX_PROPS) + return (DLADM_STATUS_NOTFOUND); + + if (pdp->pd_flags & PD_CHECK_ALLOC) + return (DLADM_STATUS_BADARG); + + status = dladm_datalink_id2info(handle, linkid, NULL, &class, &media, + NULL, 0); + if (status != DLADM_STATUS_OK) + return (status); + + if (!(pdp->pd_class & class)) + return (DLADM_STATUS_BADARG); + + if (!DATALINK_MEDIA_ACCEPTED(pdp->pd_dmedia, media)) + return (DLADM_STATUS_BADARG); + + prop_val = malloc(*val_cntp * sizeof (*prop_val) + + *val_cntp * DLADM_PROP_VAL_MAX); + if (prop_val == NULL) + return (DLADM_STATUS_NOMEM); + for (valc = 0; valc < *val_cntp; valc++) + prop_val[valc] = (char *)(prop_val + *val_cntp) + + valc * DLADM_PROP_VAL_MAX; + + dld_flags = (type == DLADM_PROP_VAL_DEFAULT) ? MAC_PROP_DEFAULT : 0; + + switch (type) { + case DLADM_PROP_VAL_CURRENT: + status = pdp->pd_get(handle, pdp, linkid, prop_val, val_cntp, + media, dld_flags, &perm_flags); + break; + + case DLADM_PROP_VAL_DEFAULT: + /* + * If defaults are not defined for the property, + * pd_defval.vd_name should be null. If the driver + * has to be contacted for the value, vd_name should + * be the empty string (""). Otherwise, dladm will + * just print whatever is in the table. + */ + if (pdp->pd_defval.vd_name == NULL) { + status = DLADM_STATUS_NOTSUP; + break; + } + + if (pdp->pd_defval.vd_name[0] != '\0') { + *val_cntp = 1; + *ret_val = pdp->pd_defval.vd_val; + free(prop_val); + return (DLADM_STATUS_OK); + } + status = pdp->pd_get(handle, pdp, linkid, prop_val, val_cntp, + media, dld_flags, &perm_flags); + break; + + case DLADM_PROP_VAL_PERSISTENT: + if (pdp->pd_flags & PD_TEMPONLY) + status = DLADM_STATUS_TEMPONLY; + else + status = i_dladm_get_linkprop_db(handle, linkid, + prop_name, prop_val, val_cntp); + break; + + default: + status = DLADM_STATUS_BADARG; + break; + } + + if (status == DLADM_STATUS_OK) { + if (pdp->pd_check != NULL) { + val_desc_t *vdp; + + vdp = malloc(sizeof (val_desc_t) * *val_cntp); + if (vdp == NULL) + status = DLADM_STATUS_NOMEM; + else + status = pdp->pd_check(handle, pdp, linkid, + prop_val, *val_cntp, vdp, media); + if (status == DLADM_STATUS_OK) { + for (valc = 0; valc < *val_cntp; valc++) + ret_val[valc] = vdp[valc].vd_val; + } + free(vdp); + } else { + for (valc = 0; valc < *val_cntp; valc++) { + for (i = 0; i < pdp->pd_noptval; i++) { + if (strcmp(pdp->pd_optval[i].vd_name, + prop_val[valc]) == 0) { + ret_val[valc] = + pdp->pd_optval[i].vd_val; + break; + } + } + if (i == pdp->pd_noptval) { + status = DLADM_STATUS_FAILED; + break; + } + } + } + } + + free(prop_val); + + return (status); +} + /*ARGSUSED*/ static int i_dladm_init_one_prop(dladm_handle_t handle, datalink_id_t linkid, @@ -2390,13 +2635,13 @@ i_dladm_get_public_prop(dladm_handle_t handle, datalink_id_t linkid, /* ARGSUSED */ static dladm_status_t -i_dladm_defmtu_check(dladm_handle_t handle, prop_desc_t *pdp, +i_dladm_uint32_check(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid, char **prop_val, uint_t val_cnt, val_desc_t *v, datalink_media_t media) { if (val_cnt != 1) return (DLADM_STATUS_BADVAL); - v->vd_val = atoi(prop_val[0]); + v->vd_val = strtoul(prop_val[0], NULL, 0); return (DLADM_STATUS_OK); } @@ -2852,6 +3097,247 @@ i_dladm_getset_defval(dladm_handle_t handle, prop_desc_t *pdp, return (status); } +/* ARGSUSED */ +static dladm_status_t +get_stp_prop(dladm_handle_t handle, struct prop_desc *pd, datalink_id_t linkid, + char **prop_val, uint_t *val_cnt, datalink_media_t media, uint_t flags, + uint_t *perm_flags) +{ + const bridge_public_prop_t *bpp; + dladm_status_t retv; + int val, i; + + if (flags != 0) + return (DLADM_STATUS_NOTSUP); + *perm_flags = MAC_PROP_PERM_RW; + *val_cnt = 1; + for (bpp = bridge_prop; bpp->bpp_name != NULL; bpp++) + if (strcmp(bpp->bpp_name, pd->pd_name) == 0) + break; + retv = dladm_bridge_get_port_cfg(handle, linkid, bpp->bpp_code, &val); + /* If the daemon isn't running, then return the persistent value */ + if (retv == DLADM_STATUS_NOTFOUND) { + if (i_dladm_get_linkprop_db(handle, linkid, pd->pd_name, + prop_val, val_cnt) != DLADM_STATUS_OK) + (void) strlcpy(*prop_val, pd->pd_defval.vd_name, + DLADM_PROP_VAL_MAX); + return (DLADM_STATUS_OK); + } + if (retv != DLADM_STATUS_OK) { + (void) strlcpy(*prop_val, "?", DLADM_PROP_VAL_MAX); + return (retv); + } + if (val == pd->pd_defval.vd_val && pd->pd_defval.vd_name[0] != '\0') { + (void) strlcpy(*prop_val, pd->pd_defval.vd_name, + DLADM_PROP_VAL_MAX); + return (DLADM_STATUS_OK); + } + for (i = 0; i < pd->pd_noptval; i++) { + if (val == pd->pd_optval[i].vd_val) { + (void) strlcpy(*prop_val, pd->pd_optval[i].vd_name, + DLADM_PROP_VAL_MAX); + return (DLADM_STATUS_OK); + } + } + (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "%u", (unsigned)val); + return (DLADM_STATUS_OK); +} + +/* ARGSUSED1 */ +static dladm_status_t +set_stp_prop(dladm_handle_t handle, prop_desc_t *pd, datalink_id_t linkid, + val_desc_t *vdp, uint_t val_cnt, uint_t flags, datalink_media_t media) +{ + /* + * Special case for mcheck: the daemon resets the value to zero, and we + * don't want the daemon to refresh itself; it leads to deadlock. + */ + if (flags & DLADM_OPT_NOREFRESH) + return (DLADM_STATUS_OK); + + /* Tell the running daemon, if any */ + return (dladm_bridge_refresh(handle, linkid)); +} + +/* + * This is used only for stp_priority, stp_cost, and stp_mcheck. + */ +/* ARGSUSED */ +static dladm_status_t +check_stp_prop(dladm_handle_t handle, struct prop_desc *pd, + datalink_id_t linkid, char **prop_val, uint_t val_cnt, val_desc_t *vdp, + datalink_media_t media) +{ + char *cp; + boolean_t iscost; + + if (val_cnt != 1) + return (DLADM_STATUS_BADVALCNT); + + if (prop_val == NULL) { + vdp->vd_val = 0; + } else { + /* Only stp_priority and stp_cost use this function */ + iscost = strcmp(pd->pd_name, "stp_cost") == 0; + + if (iscost && strcmp(prop_val[0], "auto") == 0) { + /* Illegal value 0 is allowed to mean "automatic" */ + vdp->vd_val = 0; + } else { + errno = 0; + vdp->vd_val = strtoul(prop_val[0], &cp, 0); + if (errno != 0 || *cp != '\0') + return (DLADM_STATUS_BADVAL); + } + } + + if (iscost) { + return (vdp->vd_val > 65535 ? DLADM_STATUS_BADVAL : + DLADM_STATUS_OK); + } else { + if (vdp->vd_val > 255) + return (DLADM_STATUS_BADVAL); + /* + * If the user is setting stp_mcheck non-zero, then (per the + * IEEE management standards and UNH testing) we need to check + * whether this link is part of a bridge that is running RSTP. + * If it's not, then setting the flag is an error. Note that + * errors are intentionally discarded here; it's the value + * that's the problem -- it's not a bad value, merely one that + * can't be used now. + */ + if (strcmp(pd->pd_name, "stp_mcheck") == 0 && + vdp->vd_val != 0) { + char bridge[MAXLINKNAMELEN]; + UID_STP_CFG_T cfg; + dladm_bridge_prot_t brprot; + + if (dladm_bridge_getlink(handle, linkid, bridge, + sizeof (bridge)) != DLADM_STATUS_OK || + dladm_bridge_get_properties(bridge, &cfg, + &brprot) != DLADM_STATUS_OK) + return (DLADM_STATUS_FAILED); + if (cfg.force_version <= 1) + return (DLADM_STATUS_FAILED); + } + return (DLADM_STATUS_OK); + } +} + +/* ARGSUSED */ +static dladm_status_t +get_bridge_forward(dladm_handle_t handle, struct prop_desc *pd, + datalink_id_t linkid, char **prop_val, uint_t *val_cnt, + datalink_media_t media, uint_t flags, uint_t *perm_flags) +{ + dladm_status_t retv; + uint_t val; + + if (flags != 0) + return (DLADM_STATUS_NOTSUP); + *perm_flags = MAC_PROP_PERM_RW; + *val_cnt = 1; + retv = dladm_bridge_get_forwarding(handle, linkid, &val); + if (retv == DLADM_STATUS_NOTFOUND) { + if (i_dladm_get_linkprop_db(handle, linkid, pd->pd_name, + prop_val, val_cnt) != DLADM_STATUS_OK) + (void) strlcpy(*prop_val, pd->pd_defval.vd_name, + DLADM_PROP_VAL_MAX); + return (DLADM_STATUS_OK); + } + if (retv == DLADM_STATUS_OK) + (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "%u", val); + else + (void) strlcpy(*prop_val, "?", DLADM_PROP_VAL_MAX); + return (retv); +} + +/* ARGSUSED */ +static dladm_status_t +set_bridge_forward(dladm_handle_t handle, prop_desc_t *pd, datalink_id_t linkid, + val_desc_t *vdp, uint_t val_cnt, uint_t flags, datalink_media_t media) +{ + /* Tell the running daemon, if any */ + return (dladm_bridge_refresh(handle, linkid)); +} + +/* ARGSUSED */ +static dladm_status_t +get_bridge_pvid(dladm_handle_t handle, struct prop_desc *pd, + datalink_id_t linkid, char **prop_val, uint_t *val_cnt, + datalink_media_t media, uint_t flags, uint_t *perm_flags) +{ + dladm_status_t status; + dld_ioc_macprop_t *dip; + uint16_t pvid; + + if (flags != 0) + return (DLADM_STATUS_NOTSUP); + *perm_flags = MAC_PROP_PERM_RW; + *val_cnt = 1; + dip = i_dladm_buf_alloc_by_id(sizeof (uint16_t), linkid, MAC_PROP_PVID, + 0, &status); + if (dip == NULL) + return (status); + status = i_dladm_macprop(handle, dip, B_FALSE); + if (status == DLADM_STATUS_OK) { + (void) memcpy(&pvid, dip->pr_val, sizeof (pvid)); + (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "%u", pvid); + } else { + (void) strlcpy(*prop_val, "?", DLADM_PROP_VAL_MAX); + } + free(dip); + return (status); +} + +/* ARGSUSED */ +static dladm_status_t +set_bridge_pvid(dladm_handle_t handle, prop_desc_t *pd, datalink_id_t linkid, + val_desc_t *vdp, uint_t val_cnt, uint_t flags, datalink_media_t media) +{ + dladm_status_t status; + dld_ioc_macprop_t *dip; + uint16_t pvid; + + dip = i_dladm_buf_alloc_by_id(sizeof (uint16_t), linkid, MAC_PROP_PVID, + 0, &status); + if (dip == NULL) + return (status); + pvid = vdp->vd_val; + (void) memcpy(dip->pr_val, &pvid, sizeof (pvid)); + status = i_dladm_macprop(handle, dip, B_TRUE); + free(dip); + if (status != DLADM_STATUS_OK) + return (status); + + /* Tell the running daemon, if any */ + return (dladm_bridge_refresh(handle, linkid)); +} + +/* ARGSUSED */ +static dladm_status_t +check_bridge_pvid(dladm_handle_t handle, struct prop_desc *pd, + datalink_id_t linkid, char **prop_val, uint_t val_cnt, val_desc_t *vdp, + datalink_media_t media) +{ + char *cp; + + if (val_cnt != 1) + return (DLADM_STATUS_BADVALCNT); + + if (prop_val == NULL) { + vdp->vd_val = 1; + } else { + errno = 0; + vdp->vd_val = strtoul(prop_val[0], &cp, 0); + if (errno != 0 || *cp != '\0') + return (DLADM_STATUS_BADVAL); + } + + return (vdp->vd_val > VLAN_ID_MAX ? DLADM_STATUS_BADVAL : + DLADM_STATUS_OK); +} + dladm_status_t i_dladm_wlan_param(dladm_handle_t handle, datalink_id_t linkid, void *buf, mac_prop_id_t cmd, size_t len, boolean_t set) |