Home | History | Annotate | Download | only in common
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 /*
     22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     24  */
     25 
     26 #include <stdlib.h>
     27 #include <strings.h>
     28 #include <errno.h>
     29 #include <ctype.h>
     30 #include <stddef.h>
     31 #include <sys/types.h>
     32 #include <sys/stat.h>
     33 #include <sys/dld.h>
     34 #include <sys/zone.h>
     35 #include <fcntl.h>
     36 #include <unistd.h>
     37 #include <libdevinfo.h>
     38 #include <zone.h>
     39 #include <libdllink.h>
     40 #include <libdladm_impl.h>
     41 #include <libdlwlan_impl.h>
     42 #include <libdlwlan.h>
     43 #include <libdlvlan.h>
     44 #include <libdlvnic.h>
     45 #include <libintl.h>
     46 #include <dlfcn.h>
     47 #include <link.h>
     48 #include <inet/wifi_ioctl.h>
     49 #include <libdladm.h>
     50 #include <libdlstat.h>
     51 #include <sys/param.h>
     52 #include <sys/debug.h>
     53 #include <sys/dld.h>
     54 #include <inttypes.h>
     55 #include <sys/ethernet.h>
     56 #include <inet/iptun.h>
     57 #include <net/wpa.h>
     58 #include <sys/sysmacros.h>
     59 #include <sys/vlan.h>
     60 #include <libdlbridge.h>
     61 #include <stp_in.h>
     62 
     63 /*
     64  * The linkprop get() callback.
     65  * - pd: 	pointer to the prop_desc_t
     66  * - propstrp:	a property string array to keep the returned property.
     67  *		Caller allocated.
     68  * - cntp:	number of returned properties.
     69  *		Caller also uses it to indicate how many it expects.
     70  */
     71 struct prop_desc;
     72 typedef struct prop_desc prop_desc_t;
     73 
     74 typedef dladm_status_t	pd_getf_t(dladm_handle_t, prop_desc_t *pdp,
     75 			datalink_id_t, char **propstp, uint_t *cntp,
     76 			datalink_media_t, uint_t, uint_t *);
     77 
     78 /*
     79  * The linkprop set() callback.
     80  * - propval:	a val_desc_t array which keeps the property values to be set.
     81  * - cnt:	number of properties to be set.
     82  * - flags: 	additional flags passed down the system call.
     83  *
     84  * pd_set takes val_desc_t given by pd_check(), translates it into
     85  * a format suitable for kernel consumption. This may require allocation
     86  * of ioctl buffers etc. pd_set() may call another common routine (used
     87  * by all other pd_sets) which invokes the ioctl.
     88  */
     89 typedef dladm_status_t	pd_setf_t(dladm_handle_t, prop_desc_t *, datalink_id_t,
     90 			    val_desc_t *propval, uint_t cnt, uint_t flags,
     91 			    datalink_media_t);
     92 
     93 /*
     94  * The linkprop check() callback.
     95  * - propstrp:	property string array which keeps the property to be checked.
     96  * - cnt:	number of properties.
     97  * - propval:	return value; the property values of the given property strings.
     98  *
     99  * pd_check checks that the input values are valid. It does so by
    100  * iteraring through the pd_modval list for the property. If
    101  * the modifiable values cannot be expressed as a list, a pd_check
    102  * specific to this property can be used. If the input values are
    103  * verified to be valid, pd_check allocates a val_desc_t and fills it
    104  * with either a val_desc_t found on the pd_modval list or something
    105  * generated on the fly.
    106  */
    107 typedef dladm_status_t	pd_checkf_t(dladm_handle_t, prop_desc_t *pdp,
    108 			    datalink_id_t, char **propstrp, uint_t cnt,
    109 			    val_desc_t *propval, datalink_media_t);
    110 
    111 typedef struct link_attr_s {
    112 	mac_prop_id_t	pp_id;
    113 	size_t		pp_valsize;
    114 	char		*pp_name;
    115 } link_attr_t;
    116 
    117 static dld_ioc_macprop_t *i_dladm_buf_alloc_by_name(size_t, datalink_id_t,
    118 			    const char *, uint_t, dladm_status_t *);
    119 static dld_ioc_macprop_t *i_dladm_buf_alloc_by_id(size_t, datalink_id_t,
    120 			    mac_prop_id_t, uint_t, dladm_status_t *);
    121 static dld_ioc_macprop_t *i_dladm_get_public_prop(dladm_handle_t, datalink_id_t,
    122 			    char *, uint_t, dladm_status_t *, uint_t *);
    123 
    124 static dladm_status_t i_dladm_set_private_prop(dladm_handle_t, datalink_id_t,
    125 			    const char *, char **, uint_t, uint_t);
    126 static dladm_status_t i_dladm_get_priv_prop(dladm_handle_t, datalink_id_t,
    127 			    const char *, char **, uint_t *, dladm_prop_type_t,
    128 			    uint_t);
    129 static link_attr_t *dladm_name2prop(const char *);
    130 static link_attr_t *dladm_id2prop(mac_prop_id_t);
    131 
    132 static pd_getf_t	do_get_zone, do_get_autopush, do_get_rate_mod,
    133 			do_get_rate_prop, do_get_channel_prop,
    134 			do_get_powermode_prop, do_get_radio_prop,
    135 			i_dladm_duplex_get, i_dladm_status_get,
    136 			i_dladm_binary_get, i_dladm_uint32_get,
    137 			i_dladm_flowctl_get, i_dladm_maxbw_get,
    138 			i_dladm_cpus_get, i_dladm_priority_get,
    139 			i_dladm_tagmode_get, i_dladm_range_get,
    140 			get_stp_prop, get_bridge_forward,
    141 			get_bridge_pvid,
    142 			/* the above need to be renamed to "do_get_xxx" */
    143 			do_get_protection;
    144 
    145 static pd_setf_t	do_set_zone, do_set_rate_prop,
    146 			do_set_powermode_prop, do_set_radio_prop,
    147 			i_dladm_set_public_prop, do_set_res, do_set_cpus,
    148 			set_stp_prop, set_bridge_forward, set_bridge_pvid,
    149 			do_set_protection;
    150 
    151 static pd_checkf_t	do_check_zone, do_check_autopush, do_check_rate,
    152 			do_check_hoplimit, do_check_encaplim,
    153 			i_dladm_uint32_check, do_check_maxbw, do_check_cpus,
    154 			do_check_priority, check_stp_prop, check_bridge_pvid,
    155 			do_check_allowedips, do_check_prop;
    156 
    157 static dladm_status_t	i_dladm_speed_get(dladm_handle_t, prop_desc_t *,
    158 			    datalink_id_t, char **, uint_t *, uint_t, uint_t *);
    159 static dladm_status_t	i_dladm_macprop(dladm_handle_t, void *, boolean_t);
    160 static const char	*dladm_perm2str(uint_t, char *);
    161 
    162 struct prop_desc {
    163 	/*
    164 	 * link property name
    165 	 */
    166 	char			*pd_name;
    167 
    168 	/*
    169 	 * default property value, can be set to { "", NULL }
    170 	 */
    171 	val_desc_t		pd_defval;
    172 
    173 	/*
    174 	 * list of optional property values, can be NULL.
    175 	 *
    176 	 * This is set to non-NULL if there is a list of possible property
    177 	 * values.  pd_optval would point to the array of possible values.
    178 	 */
    179 	val_desc_t		*pd_optval;
    180 
    181 	/*
    182 	 * count of the above optional property values. 0 if pd_optval is NULL.
    183 	 */
    184 	uint_t			pd_noptval;
    185 
    186 	/*
    187 	 * callback to set link property; set to NULL if this property is
    188 	 * read-only and may be called before or after permanent update; see
    189 	 * flags.
    190 	 */
    191 	pd_setf_t		*pd_set;
    192 
    193 	/*
    194 	 * callback to get modifiable link property
    195 	 */
    196 	pd_getf_t		*pd_getmod;
    197 
    198 	/*
    199 	 * callback to get current link property
    200 	 */
    201 	pd_getf_t		*pd_get;
    202 
    203 	/*
    204 	 * callback to validate link property value, set to NULL if pd_optval
    205 	 * is not NULL. In that case, validate the value by comparing it with
    206 	 * the pd_optval. Return a val_desc_t array pointer if the value is
    207 	 * valid.
    208 	 */
    209 	pd_checkf_t		*pd_check;
    210 
    211 	uint_t			pd_flags;
    212 #define	PD_TEMPONLY	0x1	/* property is temporary only */
    213 #define	PD_CHECK_ALLOC	0x2	/* alloc vd_val as part of pd_check */
    214 #define	PD_AFTER_PERM	0x4	/* pd_set after db update; no temporary */
    215 	/*
    216 	 * indicate link classes this property applies to.
    217 	 */
    218 	datalink_class_t	pd_class;
    219 
    220 	/*
    221 	 * indicate link media type this property applies to.
    222 	 */
    223 	datalink_media_t	pd_dmedia;
    224 };
    225 
    226 #define	MAC_PROP_BUFSIZE(v)	sizeof (dld_ioc_macprop_t) + (v) - 1
    227 
    228 /*
    229  * Supported link properties enumerated in the prop_table[] array are
    230  * computed using the callback functions in that array. To compute the
    231  * property value, multiple distinct system calls may be needed (e.g.,
    232  * for wifi speed, we need to issue system calls to get desired/supported
    233  * rates). The link_attr[] table enumerates the interfaces to the kernel,
    234  * and the type/size of the data passed in the user-kernel interface.
    235  */
    236 static link_attr_t link_attr[] = {
    237 	{ MAC_PROP_DUPLEX,	sizeof (link_duplex_t),	"duplex"},
    238 
    239 	{ MAC_PROP_SPEED,	sizeof (uint64_t),	"speed"},
    240 
    241 	{ MAC_PROP_STATUS,	sizeof (link_state_t),	"state"},
    242 
    243 	{ MAC_PROP_AUTONEG,	sizeof (uint8_t),	"adv_autoneg_cap"},
    244 
    245 	{ MAC_PROP_MTU,		sizeof (uint32_t),	"mtu"},
    246 
    247 	{ MAC_PROP_FLOWCTRL,	sizeof (link_flowctrl_t), "flowctrl"},
    248 
    249 	{ MAC_PROP_ZONE,	sizeof (dld_ioc_zid_t),	"zone"},
    250 
    251 	{ MAC_PROP_AUTOPUSH,	sizeof (struct dlautopush), "autopush"},
    252 
    253 	{ MAC_PROP_ADV_10GFDX_CAP, sizeof (uint8_t),	"adv_10gfdx_cap"},
    254 
    255 	{ MAC_PROP_EN_10GFDX_CAP, sizeof (uint8_t),	"en_10gfdx_cap"},
    256 
    257 	{ MAC_PROP_ADV_1000FDX_CAP, sizeof (uint8_t),	"adv_1000fdx_cap"},
    258 
    259 	{ MAC_PROP_EN_1000FDX_CAP, sizeof (uint8_t),	"en_1000fdx_cap"},
    260 
    261 	{ MAC_PROP_ADV_1000HDX_CAP, sizeof (uint8_t),	"adv_1000hdx_cap"},
    262 
    263 	{ MAC_PROP_EN_1000HDX_CAP, sizeof (uint8_t),	"en_1000hdx_cap"},
    264 
    265 	{ MAC_PROP_ADV_100FDX_CAP, sizeof (uint8_t),	"adv_100fdx_cap"},
    266 
    267 	{ MAC_PROP_EN_100FDX_CAP, sizeof (uint8_t),	"en_100fdx_cap"},
    268 
    269 	{ MAC_PROP_ADV_100HDX_CAP, sizeof (uint8_t),	"adv_100hdx_cap"},
    270 
    271 	{ MAC_PROP_EN_100HDX_CAP, sizeof (uint8_t),	"en_100hdx_cap"},
    272 
    273 	{ MAC_PROP_ADV_10FDX_CAP, sizeof (uint8_t),	"adv_10fdx_cap"},
    274 
    275 	{ MAC_PROP_EN_10FDX_CAP, sizeof (uint8_t),	"en_10fdx_cap"},
    276 
    277 	{ MAC_PROP_ADV_10HDX_CAP, sizeof (uint8_t),	"adv_10hdx_cap"},
    278 
    279 	{ MAC_PROP_EN_10HDX_CAP, sizeof (uint8_t),	"en_10hdx_cap"},
    280 
    281 	{ MAC_PROP_WL_ESSID,	sizeof (wl_linkstatus_t), "essid"},
    282 
    283 	{ MAC_PROP_WL_BSSID,	sizeof (wl_bssid_t),	"bssid"},
    284 
    285 	{ MAC_PROP_WL_BSSTYPE,	sizeof (wl_bss_type_t),	"bsstype"},
    286 
    287 	{ MAC_PROP_WL_LINKSTATUS, sizeof (wl_linkstatus_t), "wl_linkstatus"},
    288 
    289 	/* wl_rates_t has variable length */
    290 	{ MAC_PROP_WL_DESIRED_RATES, sizeof (wl_rates_t), "desired_rates"},
    291 
    292 	/* wl_rates_t has variable length */
    293 	{ MAC_PROP_WL_SUPPORTED_RATES, sizeof (wl_rates_t), "supported_rates"},
    294 
    295 	{ MAC_PROP_WL_AUTH_MODE, sizeof (wl_authmode_t), "authmode"},
    296 
    297 	{ MAC_PROP_WL_ENCRYPTION, sizeof (wl_encryption_t), "encryption"},
    298 
    299 	{ MAC_PROP_WL_RSSI,	sizeof (wl_rssi_t),	"signal"},
    300 
    301 	{ MAC_PROP_WL_PHY_CONFIG, sizeof (wl_phy_conf_t), "phy_conf"},
    302 
    303 	{ MAC_PROP_WL_CAPABILITY, sizeof (wl_capability_t), "capability"},
    304 
    305 	{ MAC_PROP_WL_WPA,	sizeof (wl_wpa_t),	"wpa"},
    306 
    307 	/*  wl_wpa_ess_t has variable length */
    308 	{ MAC_PROP_WL_SCANRESULTS, sizeof (wl_wpa_ess_t), "scan_results"},
    309 
    310 	{ MAC_PROP_WL_POWER_MODE, sizeof (wl_ps_mode_t), "powermode"},
    311 
    312 	{ MAC_PROP_WL_RADIO,	sizeof (dladm_wlan_radio_t), "wl_radio"},
    313 
    314 	{ MAC_PROP_WL_ESS_LIST, sizeof (wl_ess_list_t),	"wl_ess_list"},
    315 
    316 	{ MAC_PROP_WL_KEY_TAB,	sizeof (wl_wep_key_tab_t), "wl_wep_key"},
    317 
    318 	{ MAC_PROP_WL_CREATE_IBSS, sizeof (wl_create_ibss_t), "createibss"},
    319 
    320 	/* wl_wpa_ie_t has variable length */
    321 	{ MAC_PROP_WL_SETOPTIE,	sizeof (wl_wpa_ie_t),	"set_ie"},
    322 
    323 	{ MAC_PROP_WL_DELKEY,	sizeof (wl_del_key_t),	"wpa_del_key"},
    324 
    325 	{ MAC_PROP_WL_KEY,	sizeof (wl_key_t),	"wl_key"},
    326 
    327 	{ MAC_PROP_WL_MLME,	sizeof (wl_mlme_t),	"mlme"},
    328 
    329 	{ MAC_PROP_MAXBW,	sizeof (mac_resource_props_t),	"maxbw"},
    330 
    331 	{ MAC_PROP_PRIO,	sizeof (mac_resource_props_t),	"priority"},
    332 
    333 	{ MAC_PROP_BIND_CPU,	sizeof (mac_resource_props_t),	"cpus"},
    334 
    335 	{ MAC_PROP_TAGMODE,	sizeof (link_tagmode_t),	"tagmode"},
    336 
    337 	{ MAC_PROP_IPTUN_HOPLIMIT, sizeof (uint32_t),	"hoplimit"},
    338 
    339 	{ MAC_PROP_IPTUN_ENCAPLIMIT, sizeof (uint32_t),	"encaplimit"},
    340 
    341 	{ MAC_PROP_PVID,	sizeof (uint16_t),	"default_tag"},
    342 
    343 	{ MAC_PROP_LLIMIT,	sizeof (uint32_t),	"learn_limit"},
    344 
    345 	{ MAC_PROP_LDECAY,	sizeof (uint32_t),	"learn_decay"},
    346 
    347 	{ MAC_PROP_PROTECT,	sizeof (mac_resource_props_t),	"protection"},
    348 
    349 	{ MAC_PROP_PRIVATE,	0,			"driver-private"}
    350 };
    351 
    352 typedef struct bridge_public_prop_s {
    353 	const char	*bpp_name;
    354 	int		bpp_code;
    355 } bridge_public_prop_t;
    356 
    357 static const bridge_public_prop_t bridge_prop[] = {
    358 	{ "stp", PT_CFG_NON_STP },
    359 	{ "stp_priority", PT_CFG_PRIO },
    360 	{ "stp_cost", PT_CFG_COST },
    361 	{ "stp_edge", PT_CFG_EDGE },
    362 	{ "stp_p2p", PT_CFG_P2P },
    363 	{ "stp_mcheck", PT_CFG_MCHECK },
    364 	{ NULL, 0 }
    365 };
    366 
    367 static  val_desc_t	link_duplex_vals[] = {
    368 	{ "half", 	LINK_DUPLEX_HALF	},
    369 	{ "full", 	LINK_DUPLEX_HALF	}
    370 };
    371 static  val_desc_t	link_status_vals[] = {
    372 	{ "up",		LINK_STATE_UP		},
    373 	{ "down",	LINK_STATE_DOWN		}
    374 };
    375 static  val_desc_t	link_01_vals[] = {
    376 	{ "1",		1			},
    377 	{ "0",		0			}
    378 };
    379 static  val_desc_t	link_flow_vals[] = {
    380 	{ "no",		LINK_FLOWCTRL_NONE	},
    381 	{ "tx",		LINK_FLOWCTRL_TX	},
    382 	{ "rx",		LINK_FLOWCTRL_RX	},
    383 	{ "bi",		LINK_FLOWCTRL_BI	}
    384 };
    385 static  val_desc_t	link_priority_vals[] = {
    386 	{ "low",	MPL_LOW	},
    387 	{ "medium",	MPL_MEDIUM	},
    388 	{ "high",	MPL_HIGH	}
    389 };
    390 
    391 static val_desc_t	link_tagmode_vals[] = {
    392 	{ "normal",	LINK_TAGMODE_NORMAL	},
    393 	{ "vlanonly",	LINK_TAGMODE_VLANONLY	}
    394 };
    395 
    396 static  val_desc_t	link_protect_vals[] = {
    397 	{ "mac-nospoof",	MPT_MACNOSPOOF	},
    398 	{ "ip-nospoof",		MPT_IPNOSPOOF	},
    399 	{ "restricted",		MPT_RESTRICTED	}
    400 };
    401 
    402 static val_desc_t	dladm_wlan_radio_vals[] = {
    403 	{ "on",		DLADM_WLAN_RADIO_ON	},
    404 	{ "off",	DLADM_WLAN_RADIO_OFF	}
    405 };
    406 
    407 static val_desc_t	dladm_wlan_powermode_vals[] = {
    408 	{ "off",	DLADM_WLAN_PM_OFF	},
    409 	{ "fast",	DLADM_WLAN_PM_FAST	},
    410 	{ "max",	DLADM_WLAN_PM_MAX	}
    411 };
    412 
    413 static  val_desc_t	stp_p2p_vals[] = {
    414 	{ "true",	P2P_FORCE_TRUE		},
    415 	{ "false",	P2P_FORCE_FALSE		},
    416 	{ "auto",	P2P_AUTO		}
    417 };
    418 
    419 #define	VALCNT(vals)    (sizeof ((vals)) / sizeof (val_desc_t))
    420 #define	RESET_VAL	((uintptr_t)-1)
    421 
    422 static prop_desc_t	prop_table[] = {
    423 	{ "channel",	{ NULL, 0 },
    424 	    NULL, 0, NULL, NULL,
    425 	    do_get_channel_prop, NULL, 0,
    426 	    DATALINK_CLASS_PHYS, DL_WIFI },
    427 
    428 	{ "powermode",	{ "off", DLADM_WLAN_PM_OFF },
    429 	    dladm_wlan_powermode_vals, VALCNT(dladm_wlan_powermode_vals),
    430 	    do_set_powermode_prop, NULL,
    431 	    do_get_powermode_prop, NULL, 0,
    432 	    DATALINK_CLASS_PHYS, DL_WIFI },
    433 
    434 	{ "radio",	{ "on", DLADM_WLAN_RADIO_ON },
    435 	    dladm_wlan_radio_vals, VALCNT(dladm_wlan_radio_vals),
    436 	    do_set_radio_prop, NULL,
    437 	    do_get_radio_prop, NULL, 0,
    438 	    DATALINK_CLASS_PHYS, DL_WIFI },
    439 
    440 	{ "speed",	{ "", 0 }, NULL, 0,
    441 	    do_set_rate_prop, do_get_rate_mod,
    442 	    do_get_rate_prop, do_check_rate, 0,
    443 	    DATALINK_CLASS_PHYS, DATALINK_ANY_MEDIATYPE },
    444 
    445 	{ "autopush",	{ "", 0 }, NULL, 0,
    446 	    i_dladm_set_public_prop, NULL,
    447 	    do_get_autopush, do_check_autopush, PD_CHECK_ALLOC,
    448 	    DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
    449 
    450 	{ "zone",	{ "", 0 }, NULL, 0,
    451 	    do_set_zone, NULL,
    452 	    do_get_zone, do_check_zone, PD_TEMPONLY|PD_CHECK_ALLOC,
    453 	    DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
    454 
    455 	{ "duplex",	{ "", 0 },
    456 	    link_duplex_vals, VALCNT(link_duplex_vals),
    457 	    NULL, NULL, i_dladm_duplex_get, NULL,
    458 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
    459 
    460 	{ "state",	{ "up", LINK_STATE_UP },
    461 	    link_status_vals, VALCNT(link_status_vals),
    462 	    NULL, NULL, i_dladm_status_get, NULL,
    463 	    0, DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
    464 
    465 	{ "adv_autoneg_cap", { "", 0 },
    466 	    link_01_vals, VALCNT(link_01_vals),
    467 	    i_dladm_set_public_prop, NULL, i_dladm_binary_get, NULL,
    468 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
    469 
    470 	{ "mtu", { "", 0 }, NULL, 0,
    471 	    i_dladm_set_public_prop, i_dladm_range_get,
    472 	    i_dladm_uint32_get, i_dladm_uint32_check, 0, DATALINK_CLASS_ALL,
    473 	    DATALINK_ANY_MEDIATYPE },
    474 
    475 	{ "flowctrl", { "", 0 },
    476 	    link_flow_vals, VALCNT(link_flow_vals),
    477 	    i_dladm_set_public_prop, NULL, i_dladm_flowctl_get, NULL,
    478 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
    479 
    480 	{ "adv_10gfdx_cap", { "", 0 },
    481 	    link_01_vals, VALCNT(link_01_vals),
    482 	    NULL, NULL, i_dladm_binary_get, NULL,
    483 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
    484 
    485 	{ "en_10gfdx_cap", { "", 0 },
    486 	    link_01_vals, VALCNT(link_01_vals),
    487 	    i_dladm_set_public_prop, NULL, i_dladm_binary_get, NULL,
    488 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
    489 
    490 	{ "adv_1000fdx_cap", { "", 0 },
    491 	    link_01_vals, VALCNT(link_01_vals),
    492 	    NULL, NULL, i_dladm_binary_get, NULL,
    493 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
    494 
    495 	{ "en_1000fdx_cap", { "", 0 },
    496 	    link_01_vals, VALCNT(link_01_vals),
    497 	    i_dladm_set_public_prop, NULL, i_dladm_binary_get, NULL,
    498 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
    499 
    500 	{ "adv_1000hdx_cap", { "", 0 },
    501 	    link_01_vals, VALCNT(link_01_vals),
    502 	    NULL, NULL, i_dladm_binary_get, NULL,
    503 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
    504 
    505 	{ "en_1000hdx_cap", { "", 0 },
    506 	    link_01_vals, VALCNT(link_01_vals),
    507 	    i_dladm_set_public_prop, NULL, i_dladm_binary_get, NULL,
    508 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
    509 
    510 	{ "adv_100fdx_cap", { "", 0 },
    511 	    link_01_vals, VALCNT(link_01_vals),
    512 	    NULL, NULL, i_dladm_binary_get, NULL,
    513 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
    514 
    515 	{ "en_100fdx_cap", { "", 0 },
    516 	    link_01_vals, VALCNT(link_01_vals),
    517 	    i_dladm_set_public_prop, NULL, i_dladm_binary_get, NULL,
    518 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
    519 
    520 	{ "adv_100hdx_cap", { "", 0 },
    521 	    link_01_vals, VALCNT(link_01_vals),
    522 	    NULL, NULL, i_dladm_binary_get, NULL,
    523 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
    524 
    525 	{ "en_100hdx_cap", { "", 0 },
    526 	    link_01_vals, VALCNT(link_01_vals),
    527 	    i_dladm_set_public_prop, NULL, i_dladm_binary_get, NULL,
    528 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
    529 
    530 	{ "adv_10fdx_cap", { "", 0 },
    531 	    link_01_vals, VALCNT(link_01_vals),
    532 	    NULL, NULL, i_dladm_binary_get, NULL,
    533 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
    534 
    535 	{ "en_10fdx_cap", { "", 0 },
    536 	    link_01_vals, VALCNT(link_01_vals),
    537 	    i_dladm_set_public_prop, NULL, i_dladm_binary_get, NULL,
    538 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
    539 
    540 	{ "adv_10hdx_cap", { "", 0 },
    541 	    link_01_vals, VALCNT(link_01_vals),
    542 	    NULL, NULL, i_dladm_binary_get, NULL,
    543 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
    544 
    545 	{ "en_10hdx_cap", { "", 0 },
    546 	    link_01_vals, VALCNT(link_01_vals),
    547 	    i_dladm_set_public_prop, NULL, i_dladm_binary_get, NULL,
    548 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
    549 
    550 	{ "maxbw", { "--", RESET_VAL }, NULL, 0,
    551 	    do_set_res, NULL,
    552 	    i_dladm_maxbw_get, do_check_maxbw, PD_CHECK_ALLOC,
    553 	    DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
    554 
    555 	{ "cpus", { "--", RESET_VAL }, NULL, 0,
    556 	    do_set_cpus, NULL,
    557 	    i_dladm_cpus_get, do_check_cpus, 0,
    558 	    DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
    559 
    560 	{ "priority", { "high", RESET_VAL },
    561 	    link_priority_vals, VALCNT(link_priority_vals), do_set_res, NULL,
    562 	    i_dladm_priority_get, do_check_priority, PD_CHECK_ALLOC,
    563 	    DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
    564 
    565 	{ "tagmode", { "vlanonly", LINK_TAGMODE_VLANONLY },
    566 	    link_tagmode_vals, VALCNT(link_tagmode_vals),
    567 	    i_dladm_set_public_prop, NULL, i_dladm_tagmode_get,
    568 	    NULL, 0,
    569 	    DATALINK_CLASS_PHYS | DATALINK_CLASS_AGGR | DATALINK_CLASS_VNIC,
    570 	    DL_ETHER },
    571 
    572 	{ "hoplimit", { "", 0 }, NULL, 0,
    573 	    i_dladm_set_public_prop, i_dladm_range_get, i_dladm_uint32_get,
    574 	    do_check_hoplimit, 0, DATALINK_CLASS_IPTUN, DATALINK_ANY_MEDIATYPE},
    575 
    576 	{ "encaplimit", { "", 0 }, NULL, 0,
    577 	    i_dladm_set_public_prop, i_dladm_range_get, i_dladm_uint32_get,
    578 	    do_check_encaplim, 0, DATALINK_CLASS_IPTUN, DL_IPV6},
    579 
    580 	{ "forward", { "1", 1 },
    581 	    link_01_vals, VALCNT(link_01_vals),
    582 	    set_bridge_forward, NULL, get_bridge_forward, NULL, PD_AFTER_PERM,
    583 	    DATALINK_CLASS_ALL & ~DATALINK_CLASS_VNIC, DL_ETHER },
    584 
    585 	{ "default_tag", { "1", 1 }, NULL, 0,
    586 	    set_bridge_pvid, NULL, get_bridge_pvid, check_bridge_pvid,
    587 	    0, DATALINK_CLASS_PHYS|DATALINK_CLASS_AGGR|
    588 	    DATALINK_CLASS_ETHERSTUB|DATALINK_CLASS_SIMNET, DL_ETHER },
    589 
    590 	{ "learn_limit", { "1000", 1000 }, NULL, 0,
    591 	    i_dladm_set_public_prop, NULL, i_dladm_uint32_get,
    592 	    i_dladm_uint32_check, 0,
    593 	    DATALINK_CLASS_PHYS|DATALINK_CLASS_AGGR|
    594 	    DATALINK_CLASS_ETHERSTUB|DATALINK_CLASS_SIMNET, DL_ETHER },
    595 
    596 	{ "learn_decay", { "200", 200 }, NULL, 0,
    597 	    i_dladm_set_public_prop, NULL, i_dladm_uint32_get,
    598 	    i_dladm_uint32_check, 0,
    599 	    DATALINK_CLASS_PHYS|DATALINK_CLASS_AGGR|
    600 	    DATALINK_CLASS_ETHERSTUB|DATALINK_CLASS_SIMNET, DL_ETHER },
    601 
    602 	{ "stp", { "1", 1 },
    603 	    link_01_vals, VALCNT(link_01_vals),
    604 	    set_stp_prop, NULL, get_stp_prop, NULL, PD_AFTER_PERM,
    605 	    DATALINK_CLASS_PHYS|DATALINK_CLASS_AGGR|
    606 	    DATALINK_CLASS_ETHERSTUB|DATALINK_CLASS_SIMNET, DL_ETHER },
    607 
    608 	{ "stp_priority", { "128", 128 }, NULL, 0,
    609 	    set_stp_prop, NULL, get_stp_prop, check_stp_prop, PD_AFTER_PERM,
    610 	    DATALINK_CLASS_PHYS|DATALINK_CLASS_AGGR|
    611 	    DATALINK_CLASS_ETHERSTUB|DATALINK_CLASS_SIMNET, DL_ETHER },
    612 
    613 	{ "stp_cost", { "auto", 0 }, NULL, 0,
    614 	    set_stp_prop, NULL, get_stp_prop, check_stp_prop, PD_AFTER_PERM,
    615 	    DATALINK_CLASS_PHYS|DATALINK_CLASS_AGGR|
    616 	    DATALINK_CLASS_ETHERSTUB|DATALINK_CLASS_SIMNET, DL_ETHER },
    617 
    618 	{ "stp_edge", { "1", 1 },
    619 	    link_01_vals, VALCNT(link_01_vals),
    620 	    set_stp_prop, NULL, get_stp_prop, NULL, PD_AFTER_PERM,
    621 	    DATALINK_CLASS_PHYS|DATALINK_CLASS_AGGR|
    622 	    DATALINK_CLASS_ETHERSTUB|DATALINK_CLASS_SIMNET, DL_ETHER },
    623 
    624 	{ "stp_p2p", { "auto", P2P_AUTO },
    625 	    stp_p2p_vals, VALCNT(stp_p2p_vals),
    626 	    set_stp_prop, NULL, get_stp_prop, NULL, PD_AFTER_PERM,
    627 	    DATALINK_CLASS_PHYS|DATALINK_CLASS_AGGR|
    628 	    DATALINK_CLASS_ETHERSTUB|DATALINK_CLASS_SIMNET, DL_ETHER },
    629 
    630 	{ "stp_mcheck", { "0", 0 },
    631 	    link_01_vals, VALCNT(link_01_vals),
    632 	    set_stp_prop, NULL, get_stp_prop, check_stp_prop, PD_AFTER_PERM,
    633 	    DATALINK_CLASS_PHYS|DATALINK_CLASS_AGGR|
    634 	    DATALINK_CLASS_ETHERSTUB|DATALINK_CLASS_SIMNET, DL_ETHER },
    635 
    636 	{ "protection", { "--", RESET_VAL },
    637 	    link_protect_vals, VALCNT(link_protect_vals),
    638 	    do_set_protection, NULL, do_get_protection, do_check_prop, 0,
    639 	    DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
    640 
    641 	{ "allowed-ips", { "--", 0 },
    642 	    NULL, 0, do_set_protection, NULL,
    643 	    do_get_protection, do_check_allowedips, 0,
    644 	    DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
    645 };
    646 
    647 #define	DLADM_MAX_PROPS	(sizeof (prop_table) / sizeof (prop_desc_t))
    648 
    649 static resource_prop_t rsrc_prop_table[] = {
    650 	{"maxbw",	do_extract_maxbw},
    651 	{"priority",	do_extract_priority},
    652 	{"cpus",	do_extract_cpus},
    653 	{"protection",	do_extract_protection},
    654 	{"allowed-ips",	do_extract_allowedips}
    655 };
    656 #define	DLADM_MAX_RSRC_PROP (sizeof (rsrc_prop_table) / \
    657 	sizeof (resource_prop_t))
    658 
    659 /*
    660  * when retrieving  private properties, we pass down a buffer with
    661  * DLADM_PROP_BUF_CHUNK of space for the driver to return the property value.
    662  */
    663 #define	DLADM_PROP_BUF_CHUNK	1024
    664 
    665 static dladm_status_t	i_dladm_set_linkprop_db(dladm_handle_t, datalink_id_t,
    666 			    const char *, char **, uint_t);
    667 static dladm_status_t	i_dladm_get_linkprop_db(dladm_handle_t, datalink_id_t,
    668 			    const char *, char **, uint_t *);
    669 static dladm_status_t	i_dladm_walk_linkprop_priv_db(dladm_handle_t,
    670 			    datalink_id_t, void *, int (*)(dladm_handle_t,
    671 			    datalink_id_t, const char *, void *));
    672 static dladm_status_t	i_dladm_set_single_prop(dladm_handle_t, datalink_id_t,
    673 			    datalink_class_t, uint32_t, prop_desc_t *, char **,
    674 			    uint_t, uint_t);
    675 static dladm_status_t	i_dladm_set_linkprop(dladm_handle_t, datalink_id_t,
    676 			    const char *, char **, uint_t, uint_t);
    677 static dladm_status_t	i_dladm_getset_defval(dladm_handle_t, prop_desc_t *,
    678 			    datalink_id_t, datalink_media_t, uint_t);
    679 
    680 /*
    681  * Unfortunately, MAX_SCAN_SUPPORT_RATES is too small to allow all
    682  * rates to be retrieved. However, we cannot increase it at this
    683  * time because it will break binary compatibility with unbundled
    684  * WiFi drivers and utilities. So for now we define an additional
    685  * constant, MAX_SUPPORT_RATES, to allow all rates to be retrieved.
    686  */
    687 #define	MAX_SUPPORT_RATES	64
    688 
    689 #define	AP_ANCHOR	"[anchor]"
    690 #define	AP_DELIMITER	'.'
    691 
    692 /* ARGSUSED */
    693 static dladm_status_t
    694 do_check_prop(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
    695     char **prop_val, uint_t val_cnt, val_desc_t *vdp, datalink_media_t media)
    696 {
    697 	int		i, j;
    698 
    699 	for (j = 0; j < val_cnt; j++) {
    700 		for (i = 0; i < pdp->pd_noptval; i++) {
    701 			if (strcasecmp(prop_val[j],
    702 			    pdp->pd_optval[i].vd_name) == 0) {
    703 				break;
    704 			}
    705 		}
    706 		if (i == pdp->pd_noptval)
    707 			return (DLADM_STATUS_BADVAL);
    708 
    709 		(void) memcpy(&vdp[j], &pdp->pd_optval[i], sizeof (val_desc_t));
    710 	}
    711 	return (DLADM_STATUS_OK);
    712 }
    713 
    714 static dladm_status_t
    715 i_dladm_set_single_prop(dladm_handle_t handle, datalink_id_t linkid,
    716     datalink_class_t class, uint32_t media, prop_desc_t *pdp, char **prop_val,
    717     uint_t val_cnt, uint_t flags)
    718 {
    719 	dladm_status_t	status = DLADM_STATUS_OK;
    720 	val_desc_t	*vdp = NULL;
    721 	boolean_t	needfree = B_FALSE;
    722 	uint_t		cnt, i;
    723 
    724 	if (!(pdp->pd_class & class))
    725 		return (DLADM_STATUS_BADARG);
    726 
    727 	if (!DATALINK_MEDIA_ACCEPTED(pdp->pd_dmedia, media))
    728 		return (DLADM_STATUS_BADARG);
    729 
    730 	if ((flags & DLADM_OPT_PERSIST) && (pdp->pd_flags & PD_TEMPONLY))
    731 		return (DLADM_STATUS_TEMPONLY);
    732 
    733 	if (!(flags & DLADM_OPT_ACTIVE))
    734 		return (DLADM_STATUS_OK);
    735 
    736 	if (pdp->pd_set == NULL)
    737 		return (DLADM_STATUS_PROPRDONLY);
    738 
    739 	if (prop_val != NULL) {
    740 		vdp = malloc(sizeof (val_desc_t) * val_cnt);
    741 		if (vdp == NULL)
    742 			return (DLADM_STATUS_NOMEM);
    743 
    744 		if (pdp->pd_check != NULL) {
    745 			needfree = ((pdp->pd_flags & PD_CHECK_ALLOC) != 0);
    746 			status = pdp->pd_check(handle, pdp, linkid, prop_val,
    747 			    val_cnt, vdp, media);
    748 		} else if (pdp->pd_optval != NULL) {
    749 			status = do_check_prop(handle, pdp, linkid, prop_val,
    750 			    val_cnt, vdp, media);
    751 		} else {
    752 			status = DLADM_STATUS_BADARG;
    753 		}
    754 
    755 		if (status != DLADM_STATUS_OK)
    756 			goto done;
    757 
    758 		cnt = val_cnt;
    759 	} else {
    760 		boolean_t	defval = B_FALSE;
    761 
    762 		if (pdp->pd_defval.vd_name == NULL)
    763 			return (DLADM_STATUS_NOTSUP);
    764 
    765 		cnt = 1;
    766 		defval = (strlen(pdp->pd_defval.vd_name) > 0);
    767 		if ((pdp->pd_flags & PD_CHECK_ALLOC) != 0 || defval) {
    768 			if ((vdp = malloc(sizeof (val_desc_t))) == NULL)
    769 				return (DLADM_STATUS_NOMEM);
    770 
    771 			if (defval) {
    772 				(void) memcpy(vdp, &pdp->pd_defval,
    773 				    sizeof (val_desc_t));
    774 			} else if (pdp->pd_check != NULL) {
    775 				status = pdp->pd_check(handle, pdp, linkid,
    776 				    prop_val, cnt, vdp, media);
    777 				if (status != DLADM_STATUS_OK)
    778 					goto done;
    779 			}
    780 		} else {
    781 			status = i_dladm_getset_defval(handle, pdp, linkid,
    782 			    media, flags);
    783 			return (status);
    784 		}
    785 	}
    786 	if (pdp->pd_flags & PD_AFTER_PERM)
    787 		status = (flags & DLADM_OPT_PERSIST) ? DLADM_STATUS_OK :
    788 		    DLADM_STATUS_PERMONLY;
    789 	else
    790 		status = pdp->pd_set(handle, pdp, linkid, vdp, cnt, flags,
    791 		    media);
    792 	if (needfree) {
    793 		for (i = 0; i < cnt; i++)
    794 			free((void *)((val_desc_t *)vdp + i)->vd_val);
    795 	}
    796 done:
    797 	free(vdp);
    798 	return (status);
    799 }
    800 
    801 static dladm_status_t
    802 i_dladm_set_linkprop(dladm_handle_t handle, datalink_id_t linkid,
    803     const char *prop_name, char **prop_val, uint_t val_cnt, uint_t flags)
    804 {
    805 	int			i;
    806 	boolean_t		found = B_FALSE;
    807 	datalink_class_t	class;
    808 	uint32_t		media;
    809 	dladm_status_t		status = DLADM_STATUS_OK;
    810 
    811 	status = dladm_datalink_id2info(handle, linkid, NULL, &class, &media,
    812 	    NULL, 0);
    813 	if (status != DLADM_STATUS_OK)
    814 		return (status);
    815 
    816 	for (i = 0; i < DLADM_MAX_PROPS; i++) {
    817 		prop_desc_t	*pdp = &prop_table[i];
    818 		dladm_status_t	s;
    819 
    820 		if (prop_name != NULL &&
    821 		    (strcasecmp(prop_name, pdp->pd_name) != 0))
    822 			continue;
    823 		found = B_TRUE;
    824 		s = i_dladm_set_single_prop(handle, linkid, class, media, pdp,
    825 		    prop_val, val_cnt, flags);
    826 
    827 		if (prop_name != NULL) {
    828 			status = s;
    829 			break;
    830 		} else {
    831 			if (s != DLADM_STATUS_OK &&
    832 			    s != DLADM_STATUS_NOTSUP)
    833 				status = s;
    834 		}
    835 	}
    836 	if (!found) {
    837 		if (prop_name[0] == '_') {
    838 			/* other private properties */
    839 			status = i_dladm_set_private_prop(handle, linkid,
    840 			    prop_name, prop_val, val_cnt, flags);
    841 		} else  {
    842 			status = DLADM_STATUS_NOTFOUND;
    843 		}
    844 	}
    845 
    846 	return (status);
    847 }
    848 
    849 /*
    850  * Set/reset link property for specific link
    851  */
    852 dladm_status_t
    853 dladm_set_linkprop(dladm_handle_t handle, datalink_id_t linkid,
    854     const char *prop_name, char **prop_val, uint_t val_cnt, uint_t flags)
    855 {
    856 	dladm_status_t	status = DLADM_STATUS_OK;
    857 
    858 	if ((linkid == DATALINK_INVALID_LINKID) || (flags == 0) ||
    859 	    (prop_val == NULL && val_cnt > 0) ||
    860 	    (prop_val != NULL && val_cnt == 0) ||
    861 	    (prop_name == NULL && prop_val != NULL)) {
    862 		return (DLADM_STATUS_BADARG);
    863 	}
    864 
    865 	/*
    866 	 * Check for valid link property against the flags passed
    867 	 * and set the link property when active flag is passed.
    868 	 */
    869 	status = i_dladm_set_linkprop(handle, linkid, prop_name, prop_val,
    870 	    val_cnt, flags);
    871 	if (status != DLADM_STATUS_OK)
    872 		return (status);
    873 
    874 	if (flags & DLADM_OPT_PERSIST) {
    875 		status = i_dladm_set_linkprop_db(handle, linkid, prop_name,
    876 		    prop_val, val_cnt);
    877 
    878 		if (status == DLADM_STATUS_OK && (flags & DLADM_OPT_ACTIVE)) {
    879 			prop_desc_t *pdp = prop_table;
    880 			int i;
    881 
    882 			for (i = 0; i < DLADM_MAX_PROPS; i++, pdp++) {
    883 				if (!(pdp->pd_flags & PD_AFTER_PERM))
    884 					continue;
    885 				if (prop_name != NULL &&
    886 				    strcasecmp(prop_name, pdp->pd_name) != 0)
    887 					continue;
    888 				status = pdp->pd_set(handle, pdp, linkid, NULL,
    889 				    0, flags, 0);
    890 			}
    891 		}
    892 	}
    893 	return (status);
    894 }
    895 
    896 /*
    897  * Walk all link properties of the given specific link.
    898  *
    899  * Note: this function currently lacks the ability to walk _all_ private
    900  * properties if the link, because there is no kernel interface to
    901  * retrieve all known private property names. Once such an interface
    902  * is added, this function should be fixed accordingly.
    903  */
    904 dladm_status_t
    905 dladm_walk_linkprop(dladm_handle_t handle, datalink_id_t linkid, void *arg,
    906     int (*func)(dladm_handle_t, datalink_id_t, const char *, void *))
    907 {
    908 	dladm_status_t		status;
    909 	datalink_class_t	class;
    910 	uint_t			media;
    911 	int			i;
    912 
    913 	if (linkid == DATALINK_INVALID_LINKID || func == NULL)
    914 		return (DLADM_STATUS_BADARG);
    915 
    916 	status = dladm_datalink_id2info(handle, linkid, NULL, &class, &media,
    917 	    NULL, 0);
    918 	if (status != DLADM_STATUS_OK)
    919 		return (status);
    920 
    921 	/* public */
    922 	for (i = 0; i < DLADM_MAX_PROPS; i++) {
    923 		if (!(prop_table[i].pd_class & class))
    924 			continue;
    925 
    926 		if (!DATALINK_MEDIA_ACCEPTED(prop_table[i].pd_dmedia, media))
    927 			continue;
    928 
    929 		if (func(handle, linkid, prop_table[i].pd_name, arg) ==
    930 		    DLADM_WALK_TERMINATE) {
    931 			break;
    932 		}
    933 	}
    934 
    935 	/* private */
    936 	status = i_dladm_walk_linkprop_priv_db(handle, linkid, arg, func);
    937 
    938 	return (status);
    939 }
    940 
    941 /*
    942  * Get linkprop of the given specific link.
    943  */
    944 dladm_status_t
    945 dladm_get_linkprop(dladm_handle_t handle, datalink_id_t linkid,
    946     dladm_prop_type_t type, const char *prop_name, char **prop_val,
    947     uint_t *val_cntp)
    948 {
    949 	dladm_status_t		status = DLADM_STATUS_OK;
    950 	datalink_class_t	class;
    951 	uint_t			media;
    952 	prop_desc_t		*pdp;
    953 	uint_t			cnt, dld_flags = 0;
    954 	int			i;
    955 	uint_t			perm_flags;
    956 
    957 	if (type == DLADM_PROP_VAL_DEFAULT)
    958 		dld_flags |= MAC_PROP_DEFAULT;
    959 	else if (type == DLADM_PROP_VAL_MODIFIABLE)
    960 		dld_flags |= MAC_PROP_POSSIBLE;
    961 
    962 	if (linkid == DATALINK_INVALID_LINKID || prop_name == NULL ||
    963 	    prop_val == NULL || val_cntp == NULL || *val_cntp == 0)
    964 		return (DLADM_STATUS_BADARG);
    965 
    966 	for (i = 0; i < DLADM_MAX_PROPS; i++)
    967 		if (strcasecmp(prop_name, prop_table[i].pd_name) == 0)
    968 			break;
    969 
    970 	if (i == DLADM_MAX_PROPS) {
    971 		if (prop_name[0] == '_') {
    972 			/*
    973 			 * private property.
    974 			 */
    975 			if (type == DLADM_PROP_VAL_PERSISTENT)
    976 				return (i_dladm_get_linkprop_db(handle, linkid,
    977 				    prop_name, prop_val, val_cntp));
    978 			else
    979 				return (i_dladm_get_priv_prop(handle, linkid,
    980 				    prop_name, prop_val, val_cntp, type,
    981 				    dld_flags));
    982 		} else {
    983 			return (DLADM_STATUS_NOTFOUND);
    984 		}
    985 	}
    986 
    987 	pdp = &prop_table[i];
    988 
    989 	status = dladm_datalink_id2info(handle, linkid, NULL, &class, &media,
    990 	    NULL, 0);
    991 	if (status != DLADM_STATUS_OK)
    992 		return (status);
    993 
    994 	if (!(pdp->pd_class & class))
    995 		return (DLADM_STATUS_BADARG);
    996 
    997 	if (!DATALINK_MEDIA_ACCEPTED(pdp->pd_dmedia, media))
    998 		return (DLADM_STATUS_BADARG);
    999 
   1000 	switch (type) {
   1001 	case DLADM_PROP_VAL_CURRENT:
   1002 		status = pdp->pd_get(handle, pdp, linkid, prop_val, val_cntp,
   1003 		    media, dld_flags, &perm_flags);
   1004 		break;
   1005 
   1006 	case DLADM_PROP_VAL_PERM:
   1007 		if (pdp->pd_set == NULL) {
   1008 			perm_flags = MAC_PROP_PERM_READ;
   1009 		} else {
   1010 			status = pdp->pd_get(handle, pdp, linkid, prop_val,
   1011 			    val_cntp, media, dld_flags, &perm_flags);
   1012 		}
   1013 
   1014 		*prop_val[0] = '\0';
   1015 		*val_cntp = 1;
   1016 		if (status == DLADM_STATUS_OK)
   1017 			(void) dladm_perm2str(perm_flags, *prop_val);
   1018 		break;
   1019 
   1020 	case DLADM_PROP_VAL_DEFAULT:
   1021 		/*
   1022 		 * If defaults are not defined for the property,
   1023 		 * pd_defval.vd_name should be null. If the driver
   1024 		 * has to be contacted for the value, vd_name should
   1025 		 * be the empty string (""). Otherwise, dladm will
   1026 		 * just print whatever is in the table.
   1027 		 */
   1028 		if (pdp->pd_defval.vd_name == NULL) {
   1029 			status = DLADM_STATUS_NOTSUP;
   1030 			break;
   1031 		}
   1032 
   1033 		if (strlen(pdp->pd_defval.vd_name) == 0) {
   1034 			status = pdp->pd_get(handle, pdp, linkid, prop_val,
   1035 			    val_cntp, media, dld_flags, &perm_flags);
   1036 		} else {
   1037 			(void) strcpy(*prop_val, pdp->pd_defval.vd_name);
   1038 		}
   1039 		*val_cntp = 1;
   1040 		break;
   1041 
   1042 	case DLADM_PROP_VAL_MODIFIABLE:
   1043 		if (pdp->pd_getmod != NULL) {
   1044 			status = pdp->pd_getmod(handle, pdp, linkid, prop_val,
   1045 			    val_cntp, media, dld_flags, &perm_flags);
   1046 			break;
   1047 		}
   1048 		cnt = pdp->pd_noptval;
   1049 		if (cnt == 0) {
   1050 			status = DLADM_STATUS_NOTSUP;
   1051 		} else if (cnt > *val_cntp) {
   1052 			status = DLADM_STATUS_TOOSMALL;
   1053 		} else {
   1054 			for (i = 0; i < cnt; i++) {
   1055 				(void) strcpy(prop_val[i],
   1056 				    pdp->pd_optval[i].vd_name);
   1057 			}
   1058 			*val_cntp = cnt;
   1059 		}
   1060 		break;
   1061 	case DLADM_PROP_VAL_PERSISTENT:
   1062 		if (pdp->pd_flags & PD_TEMPONLY)
   1063 			return (DLADM_STATUS_TEMPONLY);
   1064 		status = i_dladm_get_linkprop_db(handle, linkid, prop_name,
   1065 		    prop_val, val_cntp);
   1066 		break;
   1067 	default:
   1068 		status = DLADM_STATUS_BADARG;
   1069 		break;
   1070 	}
   1071 
   1072 	return (status);
   1073 }
   1074 
   1075 /*
   1076  * Get linkprop of the given specific link and run any possible conversion
   1077  * of the values using the check function for the property. Fails if the
   1078  * check function doesn't succeed for the property value.
   1079  */
   1080 dladm_status_t
   1081 dladm_get_linkprop_values(dladm_handle_t handle, datalink_id_t linkid,
   1082     dladm_prop_type_t type, const char *prop_name, uint_t *ret_val,
   1083     uint_t *val_cntp)
   1084 {
   1085 	dladm_status_t		status;
   1086 	datalink_class_t	class;
   1087 	uint_t			media;
   1088 	prop_desc_t		*pdp;
   1089 	uint_t			dld_flags;
   1090 	int			valc, i;
   1091 	char			**prop_val;
   1092 	uint_t			perm_flags;
   1093 
   1094 	if (linkid == DATALINK_INVALID_LINKID || prop_name == NULL ||
   1095 	    ret_val == NULL || val_cntp == NULL || *val_cntp == 0)
   1096 		return (DLADM_STATUS_BADARG);
   1097 
   1098 	for (pdp = prop_table; pdp < prop_table + DLADM_MAX_PROPS; pdp++)
   1099 		if (strcasecmp(prop_name, pdp->pd_name) == 0)
   1100 			break;
   1101 
   1102 	if (pdp == prop_table + DLADM_MAX_PROPS)
   1103 		return (DLADM_STATUS_NOTFOUND);
   1104 
   1105 	if (pdp->pd_flags & PD_CHECK_ALLOC)
   1106 		return (DLADM_STATUS_BADARG);
   1107 
   1108 	status = dladm_datalink_id2info(handle, linkid, NULL, &class, &media,
   1109 	    NULL, 0);
   1110 	if (status != DLADM_STATUS_OK)
   1111 		return (status);
   1112 
   1113 	if (!(pdp->pd_class & class))
   1114 		return (DLADM_STATUS_BADARG);
   1115 
   1116 	if (!DATALINK_MEDIA_ACCEPTED(pdp->pd_dmedia, media))
   1117 		return (DLADM_STATUS_BADARG);
   1118 
   1119 	prop_val = malloc(*val_cntp * sizeof (*prop_val) +
   1120 	    *val_cntp * DLADM_PROP_VAL_MAX);
   1121 	if (prop_val == NULL)
   1122 		return (DLADM_STATUS_NOMEM);
   1123 	for (valc = 0; valc < *val_cntp; valc++)
   1124 		prop_val[valc] = (char *)(prop_val + *val_cntp) +
   1125 		    valc * DLADM_PROP_VAL_MAX;
   1126 
   1127 	dld_flags = (type == DLADM_PROP_VAL_DEFAULT) ? MAC_PROP_DEFAULT : 0;
   1128 
   1129 	switch (type) {
   1130 	case DLADM_PROP_VAL_CURRENT:
   1131 		status = pdp->pd_get(handle, pdp, linkid, prop_val, val_cntp,
   1132 		    media, dld_flags, &perm_flags);
   1133 		break;
   1134 
   1135 	case DLADM_PROP_VAL_DEFAULT:
   1136 		/*
   1137 		 * If defaults are not defined for the property,
   1138 		 * pd_defval.vd_name should be null. If the driver
   1139 		 * has to be contacted for the value, vd_name should
   1140 		 * be the empty string (""). Otherwise, dladm will
   1141 		 * just print whatever is in the table.
   1142 		 */
   1143 		if (pdp->pd_defval.vd_name == NULL) {
   1144 			status = DLADM_STATUS_NOTSUP;
   1145 			break;
   1146 		}
   1147 
   1148 		if (pdp->pd_defval.vd_name[0] != '\0') {
   1149 			*val_cntp = 1;
   1150 			*ret_val = pdp->pd_defval.vd_val;
   1151 			free(prop_val);
   1152 			return (DLADM_STATUS_OK);
   1153 		}
   1154 		status = pdp->pd_get(handle, pdp, linkid, prop_val, val_cntp,
   1155 		    media, dld_flags, &perm_flags);
   1156 		break;
   1157 
   1158 	case DLADM_PROP_VAL_PERSISTENT:
   1159 		if (pdp->pd_flags & PD_TEMPONLY)
   1160 			status = DLADM_STATUS_TEMPONLY;
   1161 		else
   1162 			status = i_dladm_get_linkprop_db(handle, linkid,
   1163 			    prop_name, prop_val, val_cntp);
   1164 		break;
   1165 
   1166 	default:
   1167 		status = DLADM_STATUS_BADARG;
   1168 		break;
   1169 	}
   1170 
   1171 	if (status == DLADM_STATUS_OK) {
   1172 		if (pdp->pd_check != NULL) {
   1173 			val_desc_t *vdp;
   1174 
   1175 			vdp = malloc(sizeof (val_desc_t) * *val_cntp);
   1176 			if (vdp == NULL)
   1177 				status = DLADM_STATUS_NOMEM;
   1178 			else
   1179 				status = pdp->pd_check(handle, pdp, linkid,
   1180 				    prop_val, *val_cntp, vdp, media);
   1181 			if (status == DLADM_STATUS_OK) {
   1182 				for (valc = 0; valc < *val_cntp; valc++)
   1183 					ret_val[valc] = vdp[valc].vd_val;
   1184 			}
   1185 			free(vdp);
   1186 		} else {
   1187 			for (valc = 0; valc < *val_cntp; valc++) {
   1188 				for (i = 0; i < pdp->pd_noptval; i++) {
   1189 					if (strcmp(pdp->pd_optval[i].vd_name,
   1190 					    prop_val[valc]) == 0) {
   1191 						ret_val[valc] =
   1192 						    pdp->pd_optval[i].vd_val;
   1193 						break;
   1194 					}
   1195 				}
   1196 				if (i == pdp->pd_noptval) {
   1197 					status = DLADM_STATUS_FAILED;
   1198 					break;
   1199 				}
   1200 			}
   1201 		}
   1202 	}
   1203 
   1204 	free(prop_val);
   1205 
   1206 	return (status);
   1207 }
   1208 
   1209 /*ARGSUSED*/
   1210 static int
   1211 i_dladm_init_one_prop(dladm_handle_t handle, datalink_id_t linkid,
   1212     const char *prop_name, void *arg)
   1213 {
   1214 	char		*buf, **propvals;
   1215 	uint_t		i, valcnt = DLADM_MAX_PROP_VALCNT;
   1216 	dladm_status_t	status, *retval = arg;
   1217 
   1218 	if ((buf = malloc((sizeof (char *) + DLADM_PROP_VAL_MAX) *
   1219 	    DLADM_MAX_PROP_VALCNT)) == NULL) {
   1220 		return (DLADM_WALK_CONTINUE);
   1221 	}
   1222 
   1223 	propvals = (char **)(void *)buf;
   1224 	for (i = 0; i < valcnt; i++) {
   1225 		propvals[i] = buf +
   1226 		    sizeof (char *) * DLADM_MAX_PROP_VALCNT +
   1227 		    i * DLADM_PROP_VAL_MAX;
   1228 	}
   1229 
   1230 	if (dladm_get_linkprop(handle, linkid, DLADM_PROP_VAL_PERSISTENT,
   1231 	    prop_name, propvals, &valcnt) != DLADM_STATUS_OK) {
   1232 		goto done;
   1233 	}
   1234 
   1235 	status = dladm_set_linkprop(handle, linkid, prop_name, propvals,
   1236 	    valcnt, DLADM_OPT_ACTIVE);
   1237 	if (status != DLADM_STATUS_OK)
   1238 		*retval = status;
   1239 
   1240 done:
   1241 	if (buf != NULL)
   1242 		free(buf);
   1243 
   1244 	return (DLADM_WALK_CONTINUE);
   1245 }
   1246 
   1247 /*ARGSUSED*/
   1248 static int
   1249 i_dladm_init_linkprop(dladm_handle_t handle, datalink_id_t linkid, void *arg)
   1250 {
   1251 	datalink_class_t	class;
   1252 	dladm_status_t		status;
   1253 
   1254 	status = dladm_datalink_id2info(handle, linkid, NULL, &class, NULL,
   1255 	    NULL, 0);
   1256 	if (status != DLADM_STATUS_OK)
   1257 		return (DLADM_WALK_TERMINATE);
   1258 
   1259 	if ((class & (DATALINK_CLASS_VNIC | DATALINK_CLASS_VLAN)) == 0)
   1260 		(void) dladm_init_linkprop(handle, linkid, B_TRUE);
   1261 
   1262 	return (DLADM_WALK_CONTINUE);
   1263 }
   1264 
   1265 dladm_status_t
   1266 dladm_init_linkprop(dladm_handle_t handle, datalink_id_t linkid,
   1267     boolean_t any_media)
   1268 {
   1269 	dladm_status_t		status = DLADM_STATUS_OK;
   1270 	datalink_media_t	dmedia;
   1271 	uint32_t		media;
   1272 
   1273 	dmedia = any_media ? DATALINK_ANY_MEDIATYPE : DL_WIFI;
   1274 
   1275 	if (linkid == DATALINK_ALL_LINKID) {
   1276 		(void) dladm_walk_datalink_id(i_dladm_init_linkprop, handle,
   1277 		    NULL, DATALINK_CLASS_ALL, dmedia, DLADM_OPT_PERSIST);
   1278 	} else if (any_media ||
   1279 	    ((dladm_datalink_id2info(handle, linkid, NULL, NULL, &media, NULL,
   1280 	    0) == DLADM_STATUS_OK) &&
   1281 	    DATALINK_MEDIA_ACCEPTED(dmedia, media))) {
   1282 		(void) dladm_walk_linkprop(handle, linkid, &status,
   1283 		    i_dladm_init_one_prop);
   1284 	}
   1285 	return (status);
   1286 }
   1287 
   1288 /* ARGSUSED */
   1289 static dladm_status_t
   1290 do_get_zone(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
   1291     char **prop_val, uint_t *val_cnt, datalink_media_t media,
   1292     uint_t flags, uint_t *perm_flags)
   1293 {
   1294 	char			zone_name[ZONENAME_MAX];
   1295 	zoneid_t		zid;
   1296 	dladm_status_t		status;
   1297 	char			*cp;
   1298 	dld_ioc_macprop_t	*dip;
   1299 
   1300 	if (flags != 0)
   1301 		return (DLADM_STATUS_NOTSUP);
   1302 
   1303 	dip = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags,
   1304 	    &status, perm_flags);
   1305 	if (status != DLADM_STATUS_OK)
   1306 		return (status);
   1307 
   1308 	cp = dip->pr_val;
   1309 	(void) memcpy(&zid, cp, sizeof (zid));
   1310 	free(dip);
   1311 
   1312 	*val_cnt = 1;
   1313 	if (zid != GLOBAL_ZONEID) {
   1314 		if (getzonenamebyid(zid, zone_name, sizeof (zone_name)) < 0) {
   1315 			return (dladm_errno2status(errno));
   1316 		}
   1317 
   1318 		(void) strncpy(*prop_val, zone_name, DLADM_PROP_VAL_MAX);
   1319 	} else {
   1320 		*prop_val[0] = '\0';
   1321 	}
   1322 
   1323 	return (DLADM_STATUS_OK);
   1324 }
   1325 
   1326 typedef int (*zone_get_devroot_t)(char *, char *, size_t);
   1327 
   1328 static int
   1329 i_dladm_get_zone_dev(char *zone_name, char *dev, size_t devlen)
   1330 {
   1331 	char			root[MAXPATHLEN];
   1332 	zone_get_devroot_t	real_zone_get_devroot;
   1333 	void			*dlhandle;
   1334 	void			*sym;
   1335 	int			ret;
   1336 
   1337 	if ((dlhandle = dlopen("libzonecfg.so.1", RTLD_LAZY)) == NULL)
   1338 		return (-1);
   1339 
   1340 	if ((sym = dlsym(dlhandle, "zone_get_devroot")) == NULL) {
   1341 		(void) dlclose(dlhandle);
   1342 		return (-1);
   1343 	}
   1344 
   1345 	real_zone_get_devroot = (zone_get_devroot_t)sym;
   1346 
   1347 	if ((ret = real_zone_get_devroot(zone_name, root, sizeof (root))) == 0)
   1348 		(void) snprintf(dev, devlen, "%s%s", root, "/dev");
   1349 	(void) dlclose(dlhandle);
   1350 	return (ret);
   1351 }
   1352 
   1353 static dladm_status_t
   1354 i_dladm_update_deventry(dladm_handle_t handle, zoneid_t zid,
   1355     datalink_id_t linkid, boolean_t add)
   1356 {
   1357 	char		path[MAXPATHLEN];
   1358 	char		name[MAXLINKNAMELEN];
   1359 	di_prof_t	prof = NULL;
   1360 	char		zone_name[ZONENAME_MAX];
   1361 	dladm_status_t	status;
   1362 	int		ret;
   1363 
   1364 	if (getzonenamebyid(zid, zone_name, sizeof (zone_name)) < 0)
   1365 		return (dladm_errno2status(errno));
   1366 	if (i_dladm_get_zone_dev(zone_name, path, sizeof (path)) != 0)
   1367 		return (dladm_errno2status(errno));
   1368 	if (di_prof_init(path, &prof) != 0)
   1369 		return (dladm_errno2status(errno));
   1370 
   1371 	status = dladm_linkid2legacyname(handle, linkid, name, MAXLINKNAMELEN);
   1372 	if (status != DLADM_STATUS_OK)
   1373 		goto cleanup;
   1374 
   1375 	if (add)
   1376 		ret = di_prof_add_dev(prof, name);
   1377 	else
   1378 		ret = di_prof_add_exclude(prof, name);
   1379 
   1380 	if (ret != 0) {
   1381 		status = dladm_errno2status(errno);
   1382 		goto cleanup;
   1383 	}
   1384 
   1385 	if (di_prof_commit(prof) != 0)
   1386 		status = dladm_errno2status(errno);
   1387 cleanup:
   1388 	if (prof)
   1389 		di_prof_fini(prof);
   1390 
   1391 	return (status);
   1392 }
   1393 
   1394 /* ARGSUSED */
   1395 static dladm_status_t
   1396 do_set_zone(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
   1397     val_desc_t *vdp, uint_t val_cnt, uint_t flags, datalink_media_t media)
   1398 {
   1399 	dladm_status_t		status = DLADM_STATUS_OK;
   1400 	zoneid_t		zid_old, zid_new;
   1401 	char			*cp;
   1402 	dld_ioc_macprop_t	*dip;
   1403 	dld_ioc_zid_t		*dzp;
   1404 
   1405 	if (val_cnt != 1)
   1406 		return (DLADM_STATUS_BADVALCNT);
   1407 
   1408 	dzp = (dld_ioc_zid_t *)vdp->vd_val;
   1409 
   1410 	dip = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags,
   1411 	    &status, NULL);
   1412 	if (status != DLADM_STATUS_OK)
   1413 		return (status);
   1414 
   1415 	cp = dip->pr_val;
   1416 	(void) memcpy(&zid_old, cp, sizeof (zid_old));
   1417 	free(dip);
   1418 
   1419 	zid_new = dzp->diz_zid;
   1420 	if (zid_new == zid_old)
   1421 		return (DLADM_STATUS_OK);
   1422 
   1423 	if ((status = i_dladm_set_public_prop(handle, pdp, linkid, vdp, val_cnt,
   1424 	    flags, media)) != DLADM_STATUS_OK)
   1425 		return (status);
   1426 
   1427 	/*
   1428 	 * It is okay to fail to update the /dev entry (some vanity-named
   1429 	 * links do not have a /dev entry).
   1430 	 */
   1431 	if (zid_old != GLOBAL_ZONEID) {
   1432 		(void) i_dladm_update_deventry(handle, zid_old, linkid,
   1433 		    B_FALSE);
   1434 	}
   1435 	if (zid_new != GLOBAL_ZONEID)
   1436 		(void) i_dladm_update_deventry(handle, zid_new, linkid, B_TRUE);
   1437 
   1438 	return (DLADM_STATUS_OK);
   1439 }
   1440 
   1441 /* ARGSUSED */
   1442 static dladm_status_t
   1443 do_check_zone(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
   1444     char **prop_val, uint_t val_cnt, val_desc_t *vdp, datalink_media_t media)
   1445 {
   1446 	char		*zone_name;
   1447 	zoneid_t	zoneid;
   1448 	dladm_status_t	status = DLADM_STATUS_OK;
   1449 	dld_ioc_zid_t	*dzp;
   1450 
   1451 	if (val_cnt != 1)
   1452 		return (DLADM_STATUS_BADVALCNT);
   1453 
   1454 	dzp = malloc(sizeof (dld_ioc_zid_t));
   1455 	if (dzp == NULL)
   1456 		return (DLADM_STATUS_NOMEM);
   1457 
   1458 	zone_name = (prop_val != NULL) ? *prop_val : GLOBAL_ZONENAME;
   1459 	if ((zoneid = getzoneidbyname(zone_name)) == -1) {
   1460 		status = DLADM_STATUS_BADVAL;
   1461 		goto done;
   1462 	}
   1463 
   1464 	if (zoneid != GLOBAL_ZONEID) {
   1465 		ushort_t	flags;
   1466 
   1467 		if (zone_getattr(zoneid, ZONE_ATTR_FLAGS, &flags,
   1468 		    sizeof (flags)) < 0) {
   1469 			status = dladm_errno2status(errno);
   1470 			goto done;
   1471 		}
   1472 
   1473 		if (!(flags & ZF_NET_EXCL)) {
   1474 			status = DLADM_STATUS_BADVAL;
   1475 			goto done;
   1476 		}
   1477 	}
   1478 
   1479 	(void) memset(dzp, 0, sizeof (dld_ioc_zid_t));
   1480 
   1481 	dzp->diz_zid = zoneid;
   1482 	dzp->diz_linkid = linkid;
   1483 
   1484 	vdp->vd_val = (uintptr_t)dzp;
   1485 	return (DLADM_STATUS_OK);
   1486 done:
   1487 	free(dzp);
   1488 	return (status);
   1489 }
   1490 
   1491 /* ARGSUSED */
   1492 static dladm_status_t
   1493 i_dladm_maxbw_get(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
   1494     char **prop_val, uint_t *val_cnt, datalink_media_t media,
   1495     uint_t flags, uint_t *perm_flags)
   1496 {
   1497 	dld_ioc_macprop_t	*dip;
   1498 	mac_resource_props_t	mrp;
   1499 	dladm_status_t		status;
   1500 
   1501 	dip = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags,
   1502 	    &status, perm_flags);
   1503 	if (dip == NULL)
   1504 		return (status);
   1505 
   1506 	bcopy(dip->pr_val, &mrp, sizeof (mac_resource_props_t));
   1507 	free(dip);
   1508 
   1509 	if ((mrp.mrp_mask & MRP_MAXBW) == 0) {
   1510 		(*prop_val)[0] = '\0';
   1511 	} else {
   1512 		(void) dladm_bw2str(mrp.mrp_maxbw, prop_val[0]);
   1513 	}
   1514 	*val_cnt = 1;
   1515 	return (DLADM_STATUS_OK);
   1516 }
   1517 
   1518 /* ARGSUSED */
   1519 static dladm_status_t
   1520 do_check_maxbw(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
   1521     char **prop_val, uint_t val_cnt, val_desc_t *vdp, datalink_media_t media)
   1522 {
   1523 	uint64_t	*maxbw;
   1524 	dladm_status_t	status = DLADM_STATUS_OK;
   1525 
   1526 	if (val_cnt != 1)
   1527 		return (DLADM_STATUS_BADVALCNT);
   1528 
   1529 	maxbw = malloc(sizeof (uint64_t));
   1530 	if (maxbw == NULL)
   1531 		return (DLADM_STATUS_NOMEM);
   1532 
   1533 	status = dladm_str2bw(*prop_val, maxbw);
   1534 	if (status != DLADM_STATUS_OK) {
   1535 		free(maxbw);
   1536 		return (status);
   1537 	}
   1538 
   1539 	if ((*maxbw < MRP_MAXBW_MINVAL) && (*maxbw != 0)) {
   1540 		free(maxbw);
   1541 		return (DLADM_STATUS_MINMAXBW);
   1542 	}
   1543 
   1544 	vdp->vd_val = (uintptr_t)maxbw;
   1545 	return (DLADM_STATUS_OK);
   1546 }
   1547 
   1548 /* ARGSUSED */
   1549 dladm_status_t
   1550 do_extract_maxbw(val_desc_t *vdp, uint_t cnt, void *arg)
   1551 {
   1552 	mac_resource_props_t *mrp = arg;
   1553 
   1554 	bcopy((char *)vdp->vd_val, &mrp->mrp_maxbw, sizeof (uint64_t));
   1555 	mrp->mrp_mask |= MRP_MAXBW;
   1556 
   1557 	return (DLADM_STATUS_OK);
   1558 }
   1559 
   1560 /* ARGSUSED */
   1561 static dladm_status_t
   1562 i_dladm_cpus_get(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
   1563     char **prop_val, uint_t *val_cnt, datalink_media_t media,
   1564     uint_t flags, uint_t *perm_flags)
   1565 {
   1566 	dld_ioc_macprop_t	*dip;
   1567 	mac_resource_props_t	mrp;
   1568 	int			i;
   1569 	uint32_t		ncpus;
   1570 	uchar_t			*cp;
   1571 	dladm_status_t		status;
   1572 
   1573 	dip = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags,
   1574 	    &status, perm_flags);
   1575 	if (dip == NULL)
   1576 		return (status);
   1577 
   1578 	cp = (uchar_t *)dip->pr_val;
   1579 	(void) memcpy(&mrp, cp, sizeof (mac_resource_props_t));
   1580 	free(dip);
   1581 
   1582 	ncpus = mrp.mrp_ncpus;
   1583 
   1584 	if (ncpus > *val_cnt)
   1585 		return (DLADM_STATUS_TOOSMALL);
   1586 
   1587 	if (ncpus == 0) {
   1588 		(*prop_val)[0] = '\0';
   1589 		*val_cnt = 1;
   1590 		return (DLADM_STATUS_OK);
   1591 	}
   1592 
   1593 	*val_cnt = ncpus;
   1594 	for (i = 0; i < ncpus; i++) {
   1595 		(void) snprintf(prop_val[i], DLADM_PROP_VAL_MAX,
   1596 		    "%u", mrp.mrp_cpu[i]);
   1597 	}
   1598 	return (DLADM_STATUS_OK);
   1599 }
   1600 
   1601 /* ARGSUSED */
   1602 static dladm_status_t
   1603 do_set_res(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
   1604     val_desc_t *vdp, uint_t val_cnt, uint_t flags, datalink_media_t media)
   1605 {
   1606 	mac_resource_props_t	mrp;
   1607 	dladm_status_t		status = DLADM_STATUS_OK;
   1608 	dld_ioc_macprop_t	*dip;
   1609 
   1610 	bzero(&mrp, sizeof (mac_resource_props_t));
   1611 	dip = i_dladm_buf_alloc_by_name(0, linkid, pdp->pd_name,
   1612 	    flags, &status);
   1613 
   1614 	if (dip == NULL)
   1615 		return (status);
   1616 
   1617 	if (vdp->vd_val == RESET_VAL) {
   1618 		switch (dip->pr_num) {
   1619 		case MAC_PROP_MAXBW:
   1620 			mrp.mrp_maxbw = MRP_MAXBW_RESETVAL;
   1621 			mrp.mrp_mask = MRP_MAXBW;
   1622 			break;
   1623 		case MAC_PROP_PRIO:
   1624 			mrp.mrp_priority = MPL_RESET;
   1625 			mrp.mrp_mask = MRP_PRIORITY;
   1626 			break;
   1627 		default:
   1628 			free(dip);
   1629 			return (DLADM_STATUS_BADARG);
   1630 		}
   1631 	} else {
   1632 		switch (dip->pr_num) {
   1633 		case MAC_PROP_MAXBW:
   1634 			bcopy((void *)vdp->vd_val, &mrp.mrp_maxbw,
   1635 			    sizeof (uint64_t));
   1636 			mrp.mrp_mask = MRP_MAXBW;
   1637 			break;
   1638 		case MAC_PROP_PRIO:
   1639 			bcopy((void *)vdp->vd_val, &mrp.mrp_priority,
   1640 			    sizeof (mac_priority_level_t));
   1641 			mrp.mrp_mask = MRP_PRIORITY;
   1642 			break;
   1643 		default:
   1644 			free(dip);
   1645 			return (DLADM_STATUS_BADARG);
   1646 		}
   1647 	}
   1648 
   1649 	(void) memcpy(dip->pr_val, &mrp, dip->pr_valsize);
   1650 	status = i_dladm_macprop(handle, dip, B_TRUE);
   1651 	free(dip);
   1652 	return (status);
   1653 }
   1654 
   1655 /* ARGSUSED */
   1656 static dladm_status_t
   1657 do_set_cpus(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
   1658     val_desc_t *vdp, uint_t val_cnt, uint_t flags, datalink_media_t media)
   1659 {
   1660 	mac_resource_props_t	mrp;
   1661 	dladm_status_t		status;
   1662 	dld_ioc_macprop_t	*dip;
   1663 	datalink_class_t	class;
   1664 
   1665 	/*
   1666 	 * CPU bindings can be set on VNIC and regular physical links.
   1667 	 * However VNICs fails the dladm_phys_info test(). So apply
   1668 	 * the phys_info test only on physical links.
   1669 	 */
   1670 	if ((status = dladm_datalink_id2info(handle, linkid, NULL, &class,
   1671 	    NULL, NULL, 0)) != DLADM_STATUS_OK) {
   1672 		return (status);
   1673 	}
   1674 
   1675 	/*
   1676 	 * We set intr_cpu to -1. The interrupt will be retargetted,
   1677 	 * if possible when the setup is complete in MAC.
   1678 	 */
   1679 	bzero(&mrp, sizeof (mac_resource_props_t));
   1680 	mrp.mrp_mask = MRP_CPUS;
   1681 	if (vdp != NULL && vdp->vd_val != RESET_VAL) {
   1682 		mac_resource_props_t	*vmrp;
   1683 
   1684 		vmrp = (mac_resource_props_t *)vdp->vd_val;
   1685 		if (vmrp->mrp_ncpus > 0) {
   1686 			bcopy(vmrp, &mrp, sizeof (mac_resource_props_t));
   1687 			mrp.mrp_mask = MRP_CPUS;
   1688 		}
   1689 		mrp.mrp_mask |= MRP_CPUS_USERSPEC;
   1690 		mrp.mrp_fanout_mode = MCM_CPUS;
   1691 		mrp.mrp_intr_cpu = -1;
   1692 	}
   1693 
   1694 	dip = i_dladm_buf_alloc_by_name(0, linkid, pdp->pd_name,
   1695 	    flags, &status);
   1696 	if (dip == NULL)
   1697 		return (status);
   1698 
   1699 	(void) memcpy(dip->pr_val, &mrp, dip->pr_valsize);
   1700 	status = i_dladm_macprop(handle, dip, B_TRUE);
   1701 	free(dip);
   1702 	return (status);
   1703 }
   1704 
   1705 /* ARGSUSED */
   1706 static dladm_status_t
   1707 do_check_cpus(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
   1708     char **prop_val, uint_t val_cnt, val_desc_t *vdp, datalink_media_t media)
   1709 {
   1710 	uint32_t		cpuid;
   1711 	int			i, j, rc;
   1712 	long			nproc = sysconf(_SC_NPROCESSORS_CONF);
   1713 	mac_resource_props_t	*mrp;
   1714 
   1715 	mrp = malloc(sizeof (mac_resource_props_t));
   1716 	if (mrp == NULL)
   1717 		return (DLADM_STATUS_NOMEM);
   1718 
   1719 	for (i = 0; i < val_cnt; i++) {
   1720 		errno = 0;
   1721 		cpuid = strtol(prop_val[i], (char **)NULL, 10);
   1722 		if (errno != 0 || cpuid >= nproc) {
   1723 			free(mrp);
   1724 			return (DLADM_STATUS_CPUMAX);
   1725 		}
   1726 		rc = p_online(cpuid, P_STATUS);
   1727 		if (rc < 1) {
   1728 			free(mrp);
   1729 			return (DLADM_STATUS_CPUERR);
   1730 		}
   1731 		if (rc != P_ONLINE) {
   1732 			free(mrp);
   1733 			return (DLADM_STATUS_CPUNOTONLINE);
   1734 		}
   1735 		mrp->mrp_cpu[i] = cpuid;
   1736 	}
   1737 	mrp->mrp_ncpus = (uint32_t)val_cnt;
   1738 
   1739 	/* Check for duplicates */
   1740 	for (i = 0; i < val_cnt; i++) {
   1741 		for (j = 0; j < val_cnt; j++) {
   1742 			if (i != j && mrp->mrp_cpu[i] == mrp->mrp_cpu[j]) {
   1743 				free(mrp);
   1744 				return (DLADM_STATUS_BADARG);
   1745 			}
   1746 		}
   1747 	}
   1748 	vdp->vd_val = (uintptr_t)mrp;
   1749 
   1750 	return (DLADM_STATUS_OK);
   1751 }
   1752 
   1753 /* ARGSUSED */
   1754 dladm_status_t
   1755 do_extract_cpus(val_desc_t *vdp, uint_t cnt, void *arg)
   1756 {
   1757 	mac_resource_props_t	*mrp = arg;
   1758 	mac_resource_props_t	*vmrp = (mac_resource_props_t *)vdp->vd_val;
   1759 	int			i;
   1760 
   1761 	for (i = 0; i < vmrp->mrp_ncpus; i++) {
   1762 		mrp->mrp_cpu[i] = vmrp->mrp_cpu[i];
   1763 	}
   1764 	mrp->mrp_ncpus = vmrp->mrp_ncpus;
   1765 	mrp->mrp_mask |= (MRP_CPUS|MRP_CPUS_USERSPEC);
   1766 	mrp->mrp_fanout_mode = MCM_CPUS;
   1767 	mrp->mrp_intr_cpu = -1;
   1768 
   1769 	return (DLADM_STATUS_OK);
   1770 }
   1771 
   1772 /* ARGSUSED */
   1773 static dladm_status_t
   1774 i_dladm_priority_get(dladm_handle_t handle, prop_desc_t *pdp,
   1775     datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
   1776     datalink_media_t media, uint_t flags, uint_t *perm_flags)
   1777 {
   1778 	dld_ioc_macprop_t	*dip;
   1779 	mac_resource_props_t	mrp;
   1780 	mac_priority_level_t	pri;
   1781 	dladm_status_t		status;
   1782 
   1783 	dip = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags,
   1784 	    &status, perm_flags);
   1785 	if (dip == NULL)
   1786 		return (status);
   1787 
   1788 	bcopy(dip->pr_val, &mrp, sizeof (mac_resource_props_t));
   1789 	free(dip);
   1790 
   1791 	pri = ((mrp.mrp_mask & MRP_PRIORITY) == 0) ? MPL_HIGH :
   1792 	    mrp.mrp_priority;
   1793 
   1794 	(void) dladm_pri2str(pri, prop_val[0]);
   1795 	*val_cnt = 1;
   1796 	return (DLADM_STATUS_OK);
   1797 }
   1798 
   1799 /* ARGSUSED */
   1800 static dladm_status_t
   1801 do_check_priority(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
   1802     char **prop_val, uint_t val_cnt, val_desc_t *vdp, datalink_media_t media)
   1803 {
   1804 	mac_priority_level_t	*pri;
   1805 	dladm_status_t	status = DLADM_STATUS_OK;
   1806 
   1807 	if (val_cnt != 1)
   1808 		return (DLADM_STATUS_BADVALCNT);
   1809 
   1810 	pri = malloc(sizeof (mac_priority_level_t));
   1811 	if (pri == NULL)
   1812 		return (DLADM_STATUS_NOMEM);
   1813 
   1814 	status = dladm_str2pri(*prop_val, pri);
   1815 	if (status != DLADM_STATUS_OK) {
   1816 		free(pri);
   1817 		return (status);
   1818 	}
   1819 
   1820 	if (*pri < MPL_LOW || *pri > MPL_HIGH) {
   1821 		free(pri);
   1822 		return (DLADM_STATUS_BADVAL);
   1823 	}
   1824 
   1825 	vdp->vd_val = (uintptr_t)pri;
   1826 	return (DLADM_STATUS_OK);
   1827 }
   1828 
   1829 /* ARGSUSED */
   1830 dladm_status_t
   1831 do_extract_priority(val_desc_t *vdp, uint_t cnt, void *arg)
   1832 {
   1833 	mac_resource_props_t *mrp = arg;
   1834 
   1835 	bcopy((char *)vdp->vd_val, &mrp->mrp_priority,
   1836 	    sizeof (mac_priority_level_t));
   1837 	mrp->mrp_mask |= MRP_PRIORITY;
   1838 
   1839 	return (DLADM_STATUS_OK);
   1840 }
   1841 
   1842 /* ARGSUSED */
   1843 static dladm_status_t
   1844 do_set_protection(dladm_handle_t handle, prop_desc_t *pdp,
   1845     datalink_id_t linkid, val_desc_t *vdp, uint_t val_cnt,
   1846     uint_t flags, datalink_media_t media)
   1847 {
   1848 	mac_resource_props_t	mrp;
   1849 	dladm_status_t		status = DLADM_STATUS_OK;
   1850 	dld_ioc_macprop_t	*dip;
   1851 
   1852 	bzero(&mrp, sizeof (mac_resource_props_t));
   1853 	dip = i_dladm_buf_alloc_by_name(0, linkid, "protection",
   1854 	    flags, &status);
   1855 
   1856 	if (dip == NULL)
   1857 		return (status);
   1858 
   1859 	if (strcmp(pdp->pd_name, "protection") == 0) {
   1860 		status = do_extract_protection(vdp, val_cnt, &mrp);
   1861 		if (status != DLADM_STATUS_OK)
   1862 			goto done;
   1863 
   1864 	} else if (strcmp(pdp->pd_name, "allowed-ips") == 0) {
   1865 		status = do_extract_allowedips(vdp, val_cnt, &mrp);
   1866 		if (status != DLADM_STATUS_OK)
   1867 			goto done;
   1868 	} else {
   1869 		status = DLADM_STATUS_BADARG;
   1870 		goto done;
   1871 	}
   1872 
   1873 	(void) memcpy(dip->pr_val, &mrp, dip->pr_valsize);
   1874 	status = i_dladm_macprop(handle, dip, B_TRUE);
   1875 
   1876 done:
   1877 	free(dip);
   1878 	return (status);
   1879 }
   1880 
   1881 /* ARGSUSED */
   1882 static dladm_status_t
   1883 do_get_protection(dladm_handle_t handle, prop_desc_t *pdp,
   1884     datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
   1885     datalink_media_t media, uint_t flags, uint_t *perm_flags)
   1886 {
   1887 	dld_ioc_macprop_t	*dip;
   1888 	mac_resource_props_t	mrp;
   1889 	mac_protect_t		*p;
   1890 	dladm_status_t		status;
   1891 	int			i;
   1892 
   1893 	dip = i_dladm_get_public_prop(handle, linkid, "protection", flags,
   1894 	    &status, perm_flags);
   1895 	if (dip == NULL)
   1896 		return (status);
   1897 
   1898 	bcopy(dip->pr_val, &mrp, sizeof (mac_resource_props_t));
   1899 	free(dip);
   1900 
   1901 	p = &mrp.mrp_protect;
   1902 	if ((mrp.mrp_mask & MRP_PROTECT) != 0 &&
   1903 	    strcmp(pdp->pd_name, "protection") == 0) {
   1904 		uint32_t	cnt = 0, setbits[32];
   1905 
   1906 		dladm_find_setbits32(p->mp_types, setbits, &cnt);
   1907 		if (cnt > *val_cnt)
   1908 			return (DLADM_STATUS_BADVALCNT);
   1909 
   1910 		for (i = 0; i < cnt; i++)
   1911 			(void) dladm_protect2str(setbits[i], prop_val[i]);
   1912 
   1913 		*val_cnt = cnt;
   1914 		return (DLADM_STATUS_OK);
   1915 	}
   1916 
   1917 	if (p->mp_ipaddrcnt > 0 &&
   1918 	    strcmp(pdp->pd_name, "allowed-ips") == 0) {
   1919 		if (p->mp_ipaddrcnt > *val_cnt)
   1920 			return (DLADM_STATUS_BADVALCNT);
   1921 
   1922 		for (i = 0; i < p->mp_ipaddrcnt; i++) {
   1923 			(void) dladm_ipv4addr2str(&p->mp_ipaddrs[i],
   1924 			    prop_val[i]);
   1925 		}
   1926 		*val_cnt = p->mp_ipaddrcnt;
   1927 		return (DLADM_STATUS_OK);
   1928 	}
   1929 
   1930 	*val_cnt = 0;
   1931 	return (DLADM_STATUS_OK);
   1932 }
   1933 
   1934 dladm_status_t
   1935 do_extract_protection(val_desc_t *vdp, uint_t cnt, void *arg)
   1936 {
   1937 	mac_resource_props_t	*mrp = arg;
   1938 	uint32_t		types = 0;
   1939 	int			i;
   1940 
   1941 	for (i = 0; i < cnt; i++)
   1942 		types |= (uint32_t)vdp[i].vd_val;
   1943 
   1944 	mrp->mrp_protect.mp_types = types;
   1945 	mrp->mrp_mask |= MRP_PROTECT;
   1946 	return (DLADM_STATUS_OK);
   1947 }
   1948 
   1949 dladm_status_t
   1950 do_extract_allowedips(val_desc_t *vdp, uint_t cnt, void *arg)
   1951 {
   1952 	mac_resource_props_t	*mrp = arg;
   1953 	mac_protect_t		*p = &mrp->mrp_protect;
   1954 	int			i;
   1955 
   1956 	if (vdp->vd_val == 0) {
   1957 		cnt = (uint_t)-1;
   1958 	} else {
   1959 		for (i = 0; i < cnt; i++)
   1960 			p->mp_ipaddrs[i] = (ipaddr_t)vdp[i].vd_val;
   1961 	}
   1962 	p->mp_ipaddrcnt = cnt;
   1963 	mrp->mrp_mask |= MRP_PROTECT;
   1964 	return (DLADM_STATUS_OK);
   1965 }
   1966 
   1967 /* ARGSUSED */
   1968 static dladm_status_t
   1969 do_check_allowedips(dladm_handle_t handle, prop_desc_t *pdp,
   1970     datalink_id_t linkid, char **prop_val, uint_t val_cnt,
   1971     val_desc_t *vdp, datalink_media_t media)
   1972 {
   1973 	dladm_status_t	status;
   1974 	ipaddr_t	addr;
   1975 	int		i;
   1976 
   1977 	if (val_cnt > MPT_MAXIPADDR)
   1978 		return (DLADM_STATUS_BADVALCNT);
   1979 
   1980 	for (i = 0; i < val_cnt; i++) {
   1981 		status = dladm_str2ipv4addr(prop_val[i], &addr);
   1982 		if (status != DLADM_STATUS_OK)
   1983 			return (status);
   1984 
   1985 		if (addr == 0)
   1986 			return (DLADM_STATUS_BADVAL);
   1987 
   1988 		vdp[i].vd_val = (uintptr_t)addr;
   1989 	}
   1990 	return (DLADM_STATUS_OK);
   1991 }
   1992 
   1993 /* ARGSUSED */
   1994 static dladm_status_t
   1995 do_get_autopush(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
   1996     char **prop_val, uint_t *val_cnt, datalink_media_t media,
   1997     uint_t flags, uint_t *perm_flags)
   1998 {
   1999 	struct		dlautopush dlap;
   2000 	int		i, len;
   2001 	dladm_status_t	status;
   2002 	dld_ioc_macprop_t	*dip;
   2003 
   2004 	if (flags & MAC_PROP_DEFAULT)
   2005 		return (DLADM_STATUS_NOTDEFINED);
   2006 
   2007 	*val_cnt = 1;
   2008 	dip = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags,
   2009 	    &status, perm_flags);
   2010 	if (dip == NULL) {
   2011 		(*prop_val)[0] = '\0';
   2012 		return (DLADM_STATUS_OK);
   2013 	}
   2014 	(void) memcpy(&dlap, dip->pr_val, sizeof (dlap));
   2015 
   2016 	for (i = 0, len = 0; i < dlap.dap_npush; i++) {
   2017 		if (i != 0) {
   2018 			(void) snprintf(*prop_val + len,
   2019 			    DLADM_PROP_VAL_MAX - len, "%c", AP_DELIMITER);
   2020 			len += 1;
   2021 		}
   2022 		(void) snprintf(*prop_val + len, DLADM_PROP_VAL_MAX - len,
   2023 		    "%s", dlap.dap_aplist[i]);
   2024 		len += strlen(dlap.dap_aplist[i]);
   2025 		if (dlap.dap_anchor - 1 == i) {
   2026 			(void) snprintf(*prop_val + len,
   2027 			    DLADM_PROP_VAL_MAX - len, "%c%s", AP_DELIMITER,
   2028 			    AP_ANCHOR);
   2029 			len += (strlen(AP_ANCHOR) + 1);
   2030 		}
   2031 	}
   2032 	free(dip);
   2033 done:
   2034 	return (DLADM_STATUS_OK);
   2035 }
   2036 
   2037 /*
   2038  * Add the specified module to the dlautopush structure; returns a
   2039  * DLADM_STATUS_* code.
   2040  */
   2041 dladm_status_t
   2042 i_dladm_add_ap_module(const char *module, struct dlautopush *dlap)
   2043 {
   2044 	if ((strlen(module) == 0) || (strlen(module) > FMNAMESZ))
   2045 		return (DLADM_STATUS_BADVAL);
   2046 
   2047 	if (strncasecmp(module, AP_ANCHOR, strlen(AP_ANCHOR)) == 0) {
   2048 		/*
   2049 		 * We don't allow multiple anchors, and the anchor must
   2050 		 * be after at least one module.
   2051 		 */
   2052 		if (dlap->dap_anchor != 0)
   2053 			return (DLADM_STATUS_BADVAL);
   2054 		if (dlap->dap_npush == 0)
   2055 			return (DLADM_STATUS_BADVAL);
   2056 
   2057 		dlap->dap_anchor = dlap->dap_npush;
   2058 		return (DLADM_STATUS_OK);
   2059 	}
   2060 	if (dlap->dap_npush >= MAXAPUSH)
   2061 		return (DLADM_STATUS_BADVALCNT);
   2062 
   2063 	(void) strlcpy(dlap->dap_aplist[dlap->dap_npush++], module,
   2064 	    FMNAMESZ + 1);
   2065 
   2066 	return (DLADM_STATUS_OK);
   2067 }
   2068 
   2069 /*
   2070  * Currently, both '.' and ' '(space) can be used as the delimiters between
   2071  * autopush modules. The former is used in dladm set-linkprop, and the
   2072  * latter is used in the autopush(1M) file.
   2073  */
   2074 /* ARGSUSED */
   2075 static dladm_status_t
   2076 do_check_autopush(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
   2077     char **prop_val, uint_t val_cnt, val_desc_t *vdp, datalink_media_t media)
   2078 {
   2079 	char			*module;
   2080 	struct dlautopush	*dlap;
   2081 	dladm_status_t		status;
   2082 	char			val[DLADM_PROP_VAL_MAX];
   2083 	char			delimiters[4];
   2084 
   2085 	if (val_cnt != 1)
   2086 		return (DLADM_STATUS_BADVALCNT);
   2087 
   2088 	if (prop_val != NULL) {
   2089 		dlap = malloc(sizeof (struct dlautopush));
   2090 		if (dlap == NULL)
   2091 			return (DLADM_STATUS_NOMEM);
   2092 
   2093 		(void) memset(dlap, 0, sizeof (struct dlautopush));
   2094 		(void) snprintf(delimiters, 4, " %c\n", AP_DELIMITER);
   2095 		bcopy(*prop_val, val, DLADM_PROP_VAL_MAX);
   2096 		module = strtok(val, delimiters);
   2097 		while (module != NULL) {
   2098 			status = i_dladm_add_ap_module(module, dlap);
   2099 			if (status != DLADM_STATUS_OK)
   2100 				return (status);
   2101 			module = strtok(NULL, delimiters);
   2102 		}
   2103 
   2104 		vdp->vd_val = (uintptr_t)dlap;
   2105 	} else {
   2106 		vdp->vd_val = 0;
   2107 	}
   2108 	return (DLADM_STATUS_OK);
   2109 }
   2110 
   2111 #define	WLDP_BUFSIZE (MAX_BUF_LEN - WIFI_BUF_OFFSET)
   2112 
   2113 /* ARGSUSED */
   2114 static dladm_status_t
   2115 do_get_rate_common(dladm_handle_t handle, prop_desc_t *pdp,
   2116     datalink_id_t linkid, char **prop_val, uint_t *val_cnt, uint_t id,
   2117     uint_t *perm_flags)
   2118 {
   2119 	wl_rates_t	*wrp;
   2120 	uint_t		i;
   2121 	dladm_status_t	status = DLADM_STATUS_OK;
   2122 
   2123 	wrp = malloc(WLDP_BUFSIZE);
   2124 	if (wrp == NULL)
   2125 		return (DLADM_STATUS_NOMEM);
   2126 
   2127 	status = i_dladm_wlan_param(handle, linkid, wrp, id, WLDP_BUFSIZE,
   2128 	    B_FALSE);
   2129 	if (status != DLADM_STATUS_OK)
   2130 		goto done;
   2131 
   2132 	if (wrp->wl_rates_num > *val_cnt) {
   2133 		status = DLADM_STATUS_TOOSMALL;
   2134 		goto done;
   2135 	}
   2136 
   2137 	if (wrp->wl_rates_rates[0] == 0) {
   2138 		prop_val[0][0] = '\0';
   2139 		*val_cnt = 1;
   2140 		goto done;
   2141 	}
   2142 
   2143 	for (i = 0; i < wrp->wl_rates_num; i++) {
   2144 		(void) snprintf(prop_val[i], DLADM_STRSIZE, "%.*f",
   2145 		    wrp->wl_rates_rates[i] % 2,
   2146 		    (float)wrp->wl_rates_rates[i] / 2);
   2147 	}
   2148 	*val_cnt = wrp->wl_rates_num;
   2149 	*perm_flags = MAC_PROP_PERM_RW;
   2150 
   2151 done:
   2152 	free(wrp);
   2153 	return (status);
   2154 }
   2155 
   2156 static dladm_status_t
   2157 do_get_rate_prop(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
   2158     char **prop_val, uint_t *val_cnt, datalink_media_t media,
   2159     uint_t flags, uint_t *perm_flags)
   2160 {
   2161 	if (media != DL_WIFI) {
   2162 		return (i_dladm_speed_get(handle, pdp, linkid, prop_val,
   2163 		    val_cnt, flags, perm_flags));
   2164 	}
   2165 
   2166 	return (do_get_rate_common(handle, pdp, linkid, prop_val, val_cnt,
   2167 	    MAC_PROP_WL_DESIRED_RATES, perm_flags));
   2168 }
   2169 
   2170 /* ARGSUSED */
   2171 static dladm_status_t
   2172 do_get_rate_mod(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
   2173     char **prop_val, uint_t *val_cnt, datalink_media_t media,
   2174     uint_t flags, uint_t *perm_flags)
   2175 {
   2176 	switch (media) {
   2177 	case DL_ETHER:
   2178 		/*
   2179 		 * Speed for ethernet links is unbounded. E.g., 802.11b
   2180 		 * links can have a speed of 5.5 Gbps.
   2181 		 */
   2182 		return (DLADM_STATUS_NOTSUP);
   2183 
   2184 	case DL_WIFI:
   2185 		return (do_get_rate_common(handle, pdp, linkid, prop_val,
   2186 		    val_cnt, MAC_PROP_WL_SUPPORTED_RATES, perm_flags));
   2187 	default:
   2188 		return (DLADM_STATUS_BADARG);
   2189 	}
   2190 }
   2191 
   2192 static dladm_status_t
   2193 do_set_rate(dladm_handle_t handle, datalink_id_t linkid,
   2194     dladm_wlan_rates_t *rates)
   2195 {
   2196 	int		i;
   2197 	uint_t		len;
   2198 	wl_rates_t	*wrp;
   2199 	dladm_status_t	status = DLADM_STATUS_OK;
   2200 
   2201 	wrp = malloc(WLDP_BUFSIZE);
   2202 	if (wrp == NULL)
   2203 		return (DLADM_STATUS_NOMEM);
   2204 
   2205 	bzero(wrp, WLDP_BUFSIZE);
   2206 	for (i = 0; i < rates->wr_cnt; i++)
   2207 		wrp->wl_rates_rates[i] = rates->wr_rates[i];
   2208 	wrp->wl_rates_num = rates->wr_cnt;
   2209 
   2210 	len = offsetof(wl_rates_t, wl_rates_rates) +
   2211 	    (rates->wr_cnt * sizeof (char)) + WIFI_BUF_OFFSET;
   2212 	status = i_dladm_wlan_param(handle, linkid, wrp,
   2213 	    MAC_PROP_WL_DESIRED_RATES, len, B_TRUE);
   2214 
   2215 	free(wrp);
   2216 	return (status);
   2217 }
   2218 
   2219 /* ARGSUSED */
   2220 static dladm_status_t
   2221 do_set_rate_prop(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
   2222     val_desc_t *vdp, uint_t val_cnt, uint_t flags, datalink_media_t media)
   2223 {
   2224 	dladm_wlan_rates_t	rates;
   2225 	dladm_status_t		status;
   2226 
   2227 	/*
   2228 	 * can currently set rate on WIFI links only.
   2229 	 */
   2230 	if (media != DL_WIFI)
   2231 		return (DLADM_STATUS_PROPRDONLY);
   2232 
   2233 	if (val_cnt != 1)
   2234 		return (DLADM_STATUS_BADVALCNT);
   2235 
   2236 	rates.wr_cnt = 1;
   2237 	rates.wr_rates[0] = vdp[0].vd_val;
   2238 
   2239 	status = do_set_rate(handle, linkid, &rates);
   2240 
   2241 done:
   2242 	return (status);
   2243 }
   2244 
   2245 /* ARGSUSED */
   2246 static dladm_status_t
   2247 do_check_rate(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
   2248     char **prop_val, uint_t val_cnt, val_desc_t *vdp, datalink_media_t media)
   2249 {
   2250 	int		i;
   2251 	uint_t		modval_cnt = MAX_SUPPORT_RATES;
   2252 	char		*buf, **modval;
   2253 	dladm_status_t	status;
   2254 	uint_t 		perm_flags;
   2255 
   2256 	if (val_cnt != 1)
   2257 		return (DLADM_STATUS_BADVALCNT);
   2258 
   2259 	buf = malloc((sizeof (char *) + DLADM_STRSIZE) *
   2260 	    MAX_SUPPORT_RATES);
   2261 	if (buf == NULL) {
   2262 		status = DLADM_STATUS_NOMEM;
   2263 		goto done;
   2264 	}
   2265 
   2266 	modval = (char **)(void *)buf;
   2267 	for (i = 0; i < MAX_SUPPORT_RATES; i++) {
   2268 		modval[i] = buf + sizeof (char *) * MAX_SUPPORT_RATES +
   2269 		    i * DLADM_STRSIZE;
   2270 	}
   2271 
   2272 	status = do_get_rate_mod(handle, NULL, linkid, modval, &modval_cnt,
   2273 	    media, 0, &perm_flags);
   2274 	if (status != DLADM_STATUS_OK)
   2275 		goto done;
   2276 
   2277 	for (i = 0; i < modval_cnt; i++) {
   2278 		if (strcasecmp(*prop_val, modval[i]) == 0) {
   2279 			vdp->vd_val = (uintptr_t)(uint_t)
   2280 			    (atof(*prop_val) * 2);
   2281 			status = DLADM_STATUS_OK;
   2282 			break;
   2283 		}
   2284 	}
   2285 	if (i == modval_cnt)
   2286 		status = DLADM_STATUS_BADVAL;
   2287 done:
   2288 	free(buf);
   2289 	return (status);
   2290 }
   2291 
   2292 static dladm_status_t
   2293 do_get_phyconf(dladm_handle_t handle, datalink_id_t linkid, void *buf,
   2294     int buflen)
   2295 {
   2296 	return (i_dladm_wlan_param(handle, linkid, buf, MAC_PROP_WL_PHY_CONFIG,
   2297 	    buflen, B_FALSE));
   2298 }
   2299 
   2300 /* ARGSUSED */
   2301 static dladm_status_t
   2302 do_get_channel_prop(dladm_handle_t handle, prop_desc_t *pdp,
   2303     datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
   2304     datalink_media_t media, uint_t flags, uint_t *perm_flags)
   2305 {
   2306 	uint32_t	channel;
   2307 	char		buf[WLDP_BUFSIZE];
   2308 	dladm_status_t	status = DLADM_STATUS_OK;
   2309 	wl_phy_conf_t	wl_phy_conf;
   2310 
   2311 	if ((status = do_get_phyconf(handle, linkid, buf, sizeof (buf)))
   2312 	    != DLADM_STATUS_OK)
   2313 		goto done;
   2314 
   2315 	(void) memcpy(&wl_phy_conf, buf, sizeof (wl_phy_conf));
   2316 	if (!i_dladm_wlan_convert_chan(&wl_phy_conf, &channel)) {
   2317 		status = DLADM_STATUS_NOTFOUND;
   2318 		goto done;
   2319 	}
   2320 
   2321 	(void) snprintf(*prop_val, DLADM_STRSIZE, "%u", channel);
   2322 	*val_cnt = 1;
   2323 	*perm_flags = MAC_PROP_PERM_READ;
   2324 done:
   2325 	return (status);
   2326 }
   2327 
   2328 static dladm_status_t
   2329 do_get_powermode(dladm_handle_t handle, datalink_id_t linkid, void *buf,
   2330     int buflen)
   2331 {
   2332 	return (i_dladm_wlan_param(handle, linkid, buf, MAC_PROP_WL_POWER_MODE,
   2333 	    buflen, B_FALSE));
   2334 }
   2335 
   2336 /* ARGSUSED */
   2337 static dladm_status_t
   2338 do_get_powermode_prop(dladm_handle_t handle, prop_desc_t *pdp,
   2339     datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
   2340     datalink_media_t media, uint_t flags, uint_t *perm_flags)
   2341 {
   2342 	wl_ps_mode_t	mode;
   2343 	const char	*s;
   2344 	char		buf[WLDP_BUFSIZE];
   2345 	dladm_status_t	status = DLADM_STATUS_OK;
   2346 
   2347 	if ((status = do_get_powermode(handle, linkid, buf, sizeof (buf)))
   2348 	    != DLADM_STATUS_OK)
   2349 		goto done;
   2350 
   2351 	(void) memcpy(&mode, buf, sizeof (mode));
   2352 	switch (mode.wl_ps_mode) {
   2353 	case WL_PM_AM:
   2354 		s = "off";
   2355 		break;
   2356 	case WL_PM_MPS:
   2357 		s = "max";
   2358 		break;
   2359 	case WL_PM_FAST:
   2360 		s = "fast";
   2361 		break;
   2362 	default:
   2363 		status = DLADM_STATUS_NOTFOUND;
   2364 		goto done;
   2365 	}
   2366 	(void) snprintf(*prop_val, DLADM_STRSIZE, "%s", s);
   2367 	*val_cnt = 1;
   2368 	*perm_flags = MAC_PROP_PERM_RW;
   2369 done:
   2370 	return (status);
   2371 }
   2372 
   2373 static dladm_status_t
   2374 do_set_powermode(dladm_handle_t handle, datalink_id_t linkid,
   2375     dladm_wlan_powermode_t *pm)
   2376 {
   2377 	wl_ps_mode_t    ps_mode;
   2378 
   2379 	(void) memset(&ps_mode, 0xff, sizeof (ps_mode));
   2380 
   2381 	switch (*pm) {
   2382 	case DLADM_WLAN_PM_OFF:
   2383 		ps_mode.wl_ps_mode = WL_PM_AM;
   2384 		break;
   2385 	case DLADM_WLAN_PM_MAX:
   2386 		ps_mode.wl_ps_mode = WL_PM_MPS;
   2387 		break;
   2388 	case DLADM_WLAN_PM_FAST:
   2389 		ps_mode.wl_ps_mode = WL_PM_FAST;
   2390 		break;
   2391 	default:
   2392 		return (DLADM_STATUS_NOTSUP);
   2393 	}
   2394 	return (i_dladm_wlan_param(handle, linkid, &ps_mode,
   2395 	    MAC_PROP_WL_POWER_MODE, sizeof (ps_mode), B_TRUE));
   2396 }
   2397 
   2398 /* ARGSUSED */
   2399 static dladm_status_t
   2400 do_set_powermode_prop(dladm_handle_t handle, prop_desc_t *pdp,
   2401     datalink_id_t linkid, val_desc_t *vdp, uint_t val_cnt, uint_t flags,
   2402     datalink_media_t media)
   2403 {
   2404 	dladm_wlan_powermode_t powermode = (dladm_wlan_powermode_t)vdp->vd_val;
   2405 	dladm_status_t status;
   2406 
   2407 	if (val_cnt != 1)
   2408 		return (DLADM_STATUS_BADVALCNT);
   2409 
   2410 	status = do_set_powermode(handle, linkid, &powermode);
   2411 
   2412 	return (status);
   2413 }
   2414 
   2415 static dladm_status_t
   2416 do_get_radio(dladm_handle_t handle, datalink_id_t linkid, void *buf, int buflen)
   2417 {
   2418 	return (i_dladm_wlan_param(handle, linkid, buf, MAC_PROP_WL_RADIO,
   2419 	    buflen, B_FALSE));
   2420 }
   2421 
   2422 /* ARGSUSED */
   2423 static dladm_status_t
   2424 do_get_radio_prop(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
   2425     char **prop_val, uint_t *val_cnt, datalink_media_t media,
   2426     uint_t flags, uint_t *perm_flags)
   2427 {
   2428 	wl_radio_t	radio;
   2429 	const char	*s;
   2430 	char		buf[WLDP_BUFSIZE];
   2431 	dladm_status_t	status = DLADM_STATUS_OK;
   2432 
   2433 	if ((status = do_get_radio(handle, linkid, buf, sizeof (buf)))
   2434 	    != DLADM_STATUS_OK)
   2435 		goto done;
   2436 
   2437 	(void) memcpy(&radio, buf, sizeof (radio));
   2438 	switch (radio) {
   2439 	case B_TRUE:
   2440 		s = "on";
   2441 		break;
   2442 	case B_FALSE:
   2443 		s = "off";
   2444 		break;
   2445 	default:
   2446 		status = DLADM_STATUS_NOTFOUND;
   2447 		goto done;
   2448 	}
   2449 	(void) snprintf(*prop_val, DLADM_STRSIZE, "%s", s);
   2450 	*val_cnt = 1;
   2451 	*perm_flags = MAC_PROP_PERM_RW;
   2452 done:
   2453 	return (status);
   2454 }
   2455 
   2456 static dladm_status_t
   2457 do_set_radio(dladm_handle_t handle, datalink_id_t linkid,
   2458     dladm_wlan_radio_t *radio)
   2459 {
   2460 	wl_radio_t r;
   2461 
   2462 	switch (*radio) {
   2463 	case DLADM_WLAN_RADIO_ON:
   2464 		r = B_TRUE;
   2465 		break;
   2466 	case DLADM_WLAN_RADIO_OFF:
   2467 		r = B_FALSE;
   2468 		break;
   2469 	default:
   2470 		return (DLADM_STATUS_NOTSUP);
   2471 	}
   2472 	return (i_dladm_wlan_param(handle, linkid, &r, MAC_PROP_WL_RADIO,
   2473 	    sizeof (r), B_TRUE));
   2474 }
   2475 
   2476 /* ARGSUSED */
   2477 static dladm_status_t
   2478 do_set_radio_prop(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
   2479     val_desc_t *vdp, uint_t val_cnt, uint_t flags, datalink_media_t media)
   2480 {
   2481 	dladm_wlan_radio_t radio = (dladm_wlan_radio_t)vdp->vd_val;
   2482 	dladm_status_t status;
   2483 
   2484 	if (val_cnt != 1)
   2485 		return (DLADM_STATUS_BADVALCNT);
   2486 
   2487 	status = do_set_radio(handle, linkid, &radio);
   2488 
   2489 	return (status);
   2490 }
   2491 
   2492 /* ARGSUSED */
   2493 static dladm_status_t
   2494 do_check_hoplimit(dladm_handle_t handle, prop_desc_t *pdp,
   2495     datalink_id_t linkid, char **prop_val, uint_t val_cnt, val_desc_t *vdp,
   2496     datalink_media_t media)
   2497 {
   2498 	int32_t	hlim;
   2499 	char	*ep;
   2500 
   2501 	if (val_cnt != 1)
   2502 		return (DLADM_STATUS_BADVALCNT);
   2503 
   2504 	errno = 0;
   2505 	hlim = strtol(*prop_val, &ep, 10);
   2506 	if (errno != 0 || ep == *prop_val || hlim < 1 ||
   2507 	    hlim > (int32_t)UINT8_MAX)
   2508 		return (DLADM_STATUS_BADVAL);
   2509 	vdp->vd_val = hlim;
   2510 	return (DLADM_STATUS_OK);
   2511 }
   2512 
   2513 /* ARGSUSED */
   2514 static dladm_status_t
   2515 do_check_encaplim(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
   2516     char **prop_val, uint_t val_cnt, val_desc_t *vdp, datalink_media_t media)
   2517 {
   2518 	int32_t	elim;
   2519 	char	*ep;
   2520 
   2521 	if (media != DL_IPV6)
   2522 		return (DLADM_STATUS_BADARG);
   2523 
   2524 	if (val_cnt != 1)
   2525 		return (DLADM_STATUS_BADVALCNT);
   2526 
   2527 	errno = 0;
   2528 	elim = strtol(*prop_val, &ep, 10);
   2529 	if (errno != 0 || ep == *prop_val || elim < 0 ||
   2530 	    elim > (int32_t)UINT8_MAX)
   2531 		return (DLADM_STATUS_BADVAL);
   2532 	vdp->vd_val = elim;
   2533 	return (DLADM_STATUS_OK);
   2534 }
   2535 
   2536 static dladm_status_t
   2537 i_dladm_set_linkprop_db(dladm_handle_t handle, datalink_id_t linkid,
   2538     const char *prop_name, char **prop_val, uint_t val_cnt)
   2539 {
   2540 	char		buf[MAXLINELEN];
   2541 	int		i;
   2542 	dladm_conf_t	conf;
   2543 	dladm_status_t	status;
   2544 
   2545 	status = dladm_read_conf(handle, linkid, &conf);
   2546 	if (status != DLADM_STATUS_OK)
   2547 		return (status);
   2548 
   2549 	/*
   2550 	 * reset case.
   2551 	 */
   2552 	if (val_cnt == 0) {
   2553 		status = dladm_unset_conf_field(handle, conf, prop_name);
   2554 		if (status == DLADM_STATUS_OK)
   2555 			status = dladm_write_conf(handle, conf);
   2556 		goto done;
   2557 	}
   2558 
   2559 	buf[0] = '\0';
   2560 	for (i = 0; i < val_cnt; i++) {
   2561 		(void) strlcat(buf, prop_val[i], MAXLINELEN);
   2562 		if (i != val_cnt - 1)
   2563 			(void) strlcat(buf, ",", MAXLINELEN);
   2564 	}
   2565 
   2566 	status = dladm_set_conf_field(handle, conf, prop_name, DLADM_TYPE_STR,
   2567 	    buf);
   2568 	if (status == DLADM_STATUS_OK)
   2569 		status = dladm_write_conf(handle, conf);
   2570 
   2571 done:
   2572 	dladm_destroy_conf(handle, conf);
   2573 	return (status);
   2574 }
   2575 
   2576 static dladm_status_t
   2577 i_dladm_get_linkprop_db(dladm_handle_t handle, datalink_id_t linkid,
   2578     const char *prop_name, char **prop_val, uint_t *val_cntp)
   2579 {
   2580 	char		buf[MAXLINELEN], *str;
   2581 	uint_t		cnt = 0;
   2582 	dladm_conf_t	conf;
   2583 	dladm_status_t	status;
   2584 
   2585 	status = dladm_read_conf(handle, linkid, &conf);
   2586 	if (status != DLADM_STATUS_OK)
   2587 		return (status);
   2588 
   2589 	status = dladm_get_conf_field(handle, conf, prop_name, buf, MAXLINELEN);
   2590 	if (status != DLADM_STATUS_OK)
   2591 		goto done;
   2592 
   2593 	str = strtok(buf, ",");
   2594 	while (str != NULL) {
   2595 		if (cnt == *val_cntp) {
   2596 			status = DLADM_STATUS_TOOSMALL;
   2597 			goto done;
   2598 		}
   2599 		(void) strlcpy(prop_val[cnt++], str, DLADM_PROP_VAL_MAX);
   2600 		str = strtok(NULL, ",");
   2601 	}
   2602 
   2603 	*val_cntp = cnt;
   2604 
   2605 done:
   2606 	dladm_destroy_conf(handle, conf);
   2607 	return (status);
   2608 }
   2609 
   2610 /*
   2611  * Walk persistent private link properties of a link.
   2612  */
   2613 static dladm_status_t
   2614 i_dladm_walk_linkprop_priv_db(dladm_handle_t handle, datalink_id_t linkid,
   2615     void *arg, int (*func)(dladm_handle_t, datalink_id_t, const char *, void *))
   2616 {
   2617 	dladm_status_t		status;
   2618 	dladm_conf_t		conf;
   2619 	char			last_attr[MAXLINKATTRLEN];
   2620 	char			attr[MAXLINKATTRLEN];
   2621 	char			attrval[MAXLINKATTRVALLEN];
   2622 	size_t			attrsz;
   2623 
   2624 	if (linkid == DATALINK_INVALID_LINKID || func == NULL)
   2625 		return (DLADM_STATUS_BADARG);
   2626 
   2627 	status = dladm_read_conf(handle, linkid, &conf);
   2628 	if (status != DLADM_STATUS_OK)
   2629 		return (status);
   2630 
   2631 	last_attr[0] = '\0';
   2632 	while ((status = dladm_getnext_conf_linkprop(handle, conf, last_attr,
   2633 	    attr, attrval, MAXLINKATTRVALLEN, &attrsz)) == DLADM_STATUS_OK) {
   2634 		if (attr[0] == '_') {
   2635 			if (func(handle, linkid, attr, arg) ==
   2636 			    DLADM_WALK_TERMINATE)
   2637 				break;
   2638 		}
   2639 		(void) strlcpy(last_attr, attr, MAXLINKATTRLEN);
   2640 	}
   2641 
   2642 	dladm_destroy_conf(handle, conf);
   2643 	return (DLADM_STATUS_OK);
   2644 }
   2645 
   2646 static link_attr_t *
   2647 dladm_name2prop(const char *prop_name)
   2648 {
   2649 	link_attr_t *p;
   2650 
   2651 	for (p = link_attr; p->pp_id != MAC_PROP_PRIVATE; p++) {
   2652 		if (strcmp(p->pp_name, prop_name) == 0)
   2653 			break;
   2654 	}
   2655 	return (p);
   2656 }
   2657 
   2658 static link_attr_t *
   2659 dladm_id2prop(mac_prop_id_t propid)
   2660 {
   2661 	link_attr_t *p;
   2662 
   2663 	for (p = link_attr; p->pp_id != MAC_PROP_PRIVATE; p++) {
   2664 		if (p->pp_id == propid)
   2665 			break;
   2666 	}
   2667 	return (p);
   2668 }
   2669 
   2670 static dld_ioc_macprop_t *
   2671 i_dladm_buf_alloc_impl(size_t valsize, datalink_id_t linkid,
   2672     const char *prop_name, mac_prop_id_t propid, uint_t flags,
   2673     dladm_status_t *status)
   2674 {
   2675 	int dsize;
   2676 	dld_ioc_macprop_t *dip;
   2677 
   2678 	*status = DLADM_STATUS_OK;
   2679 	dsize = MAC_PROP_BUFSIZE(valsize);
   2680 	dip = malloc(dsize);
   2681 	if (dip == NULL) {
   2682 		*status = DLADM_STATUS_NOMEM;
   2683 		return (NULL);
   2684 	}
   2685 	bzero(dip, dsize);
   2686 	dip->pr_valsize = valsize;
   2687 	(void) strlcpy(dip->pr_name, prop_name, sizeof (dip->pr_name));
   2688 	dip->pr_version = MAC_PROP_VERSION;
   2689 	dip->pr_linkid = linkid;
   2690 	dip->pr_num = propid;
   2691 	dip->pr_flags = flags;
   2692 	return (dip);
   2693 }
   2694 
   2695 static dld_ioc_macprop_t *
   2696 i_dladm_buf_alloc_by_name(size_t valsize, datalink_id_t linkid,
   2697     const char *prop_name, uint_t flags, dladm_status_t *status)
   2698 {
   2699 	link_attr_t *p;
   2700 
   2701 	p = dladm_name2prop(prop_name);
   2702 	valsize = MAX(p->pp_valsize, valsize);
   2703 	return (i_dladm_buf_alloc_impl(valsize, linkid, prop_name, p->pp_id,
   2704 	    flags, status));
   2705 }
   2706 
   2707 static dld_ioc_macprop_t *
   2708 i_dladm_buf_alloc_by_id(size_t valsize, datalink_id_t linkid,
   2709     mac_prop_id_t propid, uint_t flags, dladm_status_t *status)
   2710 {
   2711 	link_attr_t *p;
   2712 
   2713 	p = dladm_id2prop(propid);
   2714 	valsize = MAX(p->pp_valsize, valsize);
   2715 	return (i_dladm_buf_alloc_impl(valsize, linkid, p->pp_name, propid,
   2716 	    flags, status));
   2717 }
   2718 
   2719 /* ARGSUSED */
   2720 static dladm_status_t
   2721 i_dladm_set_public_prop(dladm_handle_t handle, prop_desc_t *pdp,
   2722     datalink_id_t linkid, val_desc_t *vdp, uint_t val_cnt, uint_t flags,
   2723     datalink_media_t media)
   2724 {
   2725 	dld_ioc_macprop_t	*dip;
   2726 	dladm_status_t	status = DLADM_STATUS_OK;
   2727 	uint8_t		u8;
   2728 	uint16_t	u16;
   2729 	uint32_t	u32;
   2730 	void		*val;
   2731 
   2732 	dip = i_dladm_buf_alloc_by_name(0, linkid, pdp->pd_name, 0, &status);
   2733 	if (dip == NULL)
   2734 		return (status);
   2735 
   2736 	if (pdp->pd_flags & PD_CHECK_ALLOC)
   2737 		val = (void *)vdp->vd_val;
   2738 	else {
   2739 		/*
   2740 		 * Currently all 1/2/4-byte size properties are byte/word/int.
   2741 		 * No need (yet) to distinguish these from arrays of same size.
   2742 		 */
   2743 		switch (dip->pr_valsize) {
   2744 		case 1:
   2745 			u8 = vdp->vd_val;
   2746 			val = &u8;
   2747 			break;
   2748 		case 2:
   2749 			u16 = vdp->vd_val;
   2750 			val = &u16;
   2751 			break;
   2752 		case 4:
   2753 			u32 = vdp->vd_val;
   2754 			val = &u32;
   2755 			break;
   2756 		default:
   2757 			val = &vdp->vd_val;
   2758 			break;
   2759 		}
   2760 	}
   2761 
   2762 	if (val != NULL)
   2763 		(void) memcpy(dip->pr_val, val, dip->pr_valsize);
   2764 	else
   2765 		dip->pr_valsize = 0;
   2766 
   2767 	status = i_dladm_macprop(handle, dip, B_TRUE);
   2768 
   2769 done:
   2770 	free(dip);
   2771 	return (status);
   2772 }
   2773 
   2774 dladm_status_t
   2775 i_dladm_macprop(dladm_handle_t handle, void *dip, boolean_t set)
   2776 {
   2777 	dladm_status_t status = DLADM_STATUS_OK;
   2778 
   2779 	if (ioctl(dladm_dld_fd(handle),
   2780 	    (set ? DLDIOC_SETMACPROP : DLDIOC_GETMACPROP), dip))
   2781 		status = dladm_errno2status(errno);
   2782 
   2783 	return (status);
   2784 }
   2785 
   2786 static dld_ioc_macprop_t *
   2787 i_dladm_get_public_prop(dladm_handle_t handle, datalink_id_t linkid,
   2788     char *prop_name, uint_t flags, dladm_status_t *status, uint_t *perm_flags)
   2789 {
   2790 	dld_ioc_macprop_t *dip = NULL;
   2791 
   2792 	dip = i_dladm_buf_alloc_by_name(0, linkid, prop_name, flags, status);
   2793 	if (dip == NULL)
   2794 		return (NULL);
   2795 
   2796 	*status = i_dladm_macprop(handle, dip, B_FALSE);
   2797 	if (*status != DLADM_STATUS_OK) {
   2798 		free(dip);
   2799 		return (NULL);
   2800 	}
   2801 	if (perm_flags != NULL)
   2802 		*perm_flags = dip->pr_perm_flags;
   2803 
   2804 	return (dip);
   2805 }
   2806 
   2807 /* ARGSUSED */
   2808 static dladm_status_t
   2809 i_dladm_uint32_check(dladm_handle_t handle, prop_desc_t *pdp,
   2810     datalink_id_t linkid, char **prop_val, uint_t val_cnt, val_desc_t *v,
   2811     datalink_media_t media)
   2812 {
   2813 	if (val_cnt != 1)
   2814 		return (DLADM_STATUS_BADVAL);
   2815 	v->vd_val = strtoul(prop_val[0], NULL, 0);
   2816 	return (DLADM_STATUS_OK);
   2817 }
   2818 
   2819 /* ARGSUSED */
   2820 static dladm_status_t
   2821 i_dladm_duplex_get(dladm_handle_t handle, prop_desc_t *pdp,
   2822     datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
   2823     datalink_media_t media, uint_t flags, uint_t *perm_flags)
   2824 {
   2825 	link_duplex_t   link_duplex;
   2826 	dladm_status_t  status;
   2827 
   2828 	if ((status = dladm_get_single_mac_stat(handle, linkid, "link_duplex",
   2829 	    KSTAT_DATA_UINT32, &link_duplex)) != 0)
   2830 		return (status);
   2831 
   2832 	switch (link_duplex) {
   2833 	case LINK_DUPLEX_FULL:
   2834 		(void) strcpy(*prop_val, "full");
   2835 		break;
   2836 	case LINK_DUPLEX_HALF:
   2837 		(void) strcpy(*prop_val, "half");
   2838 		break;
   2839 	default:
   2840 		(void) strcpy(*prop_val, "unknown");
   2841 		break;
   2842 	}
   2843 	*val_cnt = 1;
   2844 	return (DLADM_STATUS_OK);
   2845 }
   2846 
   2847 /* ARGSUSED */
   2848 static dladm_status_t
   2849 i_dladm_speed_get(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
   2850     char **prop_val, uint_t *val_cnt, uint_t flags, uint_t *perm_flags)
   2851 {
   2852 	uint64_t	ifspeed = 0;
   2853 	dladm_status_t status;
   2854 
   2855 	if ((status = dladm_get_single_mac_stat(handle, linkid, "ifspeed",
   2856 	    KSTAT_DATA_UINT64, &ifspeed)) != 0)
   2857 		return (status);
   2858 
   2859 	if ((ifspeed % 1000000) != 0) {
   2860 		(void) snprintf(*prop_val, DLADM_PROP_VAL_MAX,
   2861 		    "%llf", ifspeed / (float)1000000); /* Mbps */
   2862 	} else {
   2863 		(void) snprintf(*prop_val, DLADM_PROP_VAL_MAX,
   2864 		    "%llu", ifspeed / 1000000); /* Mbps */
   2865 	}
   2866 	*val_cnt = 1;
   2867 	*perm_flags = MAC_PROP_PERM_READ;
   2868 	return (DLADM_STATUS_OK);
   2869 }
   2870 
   2871 /* ARGSUSED */
   2872 static dladm_status_t
   2873 i_dladm_status_get(dladm_handle_t handle, prop_desc_t *pdp,
   2874     datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
   2875     datalink_media_t media, uint_t flags, uint_t *perm_flags)
   2876 {
   2877 	link_state_t		link_state;
   2878 	dladm_status_t		status;
   2879 
   2880 	status = i_dladm_get_state(handle, linkid, &link_state);
   2881 	if (status != DLADM_STATUS_OK)
   2882 		return (status);
   2883 
   2884 	switch (link_state) {
   2885 	case LINK_STATE_UP:
   2886 		(void) strcpy(*prop_val, "up");
   2887 		break;
   2888 	case LINK_STATE_DOWN:
   2889 		(void) strcpy(*prop_val, "down");
   2890 		break;
   2891 	default:
   2892 		(void) strcpy(*prop_val, "unknown");
   2893 		break;
   2894 	}
   2895 	*val_cnt = 1;
   2896 	*perm_flags = MAC_PROP_PERM_READ;
   2897 	return (DLADM_STATUS_OK);
   2898 }
   2899 
   2900 /* ARGSUSED */
   2901 static dladm_status_t
   2902 i_dladm_binary_get(dladm_handle_t handle, prop_desc_t *pdp,
   2903     datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
   2904     datalink_media_t media, uint_t flags, uint_t *perm_flags)
   2905 {
   2906 	dld_ioc_macprop_t *dip;
   2907 	dladm_status_t status;
   2908 
   2909 	dip = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags,
   2910 	    &status, perm_flags);
   2911 	if (dip == NULL)
   2912 		return (status);
   2913 
   2914 	(void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "%x", dip->pr_val[0]);
   2915 	free(dip);
   2916 	*val_cnt = 1;
   2917 	return (DLADM_STATUS_OK);
   2918 }
   2919 
   2920 /* ARGSUSED */
   2921 static dladm_status_t
   2922 i_dladm_uint32_get(dladm_handle_t handle, prop_desc_t *pdp,
   2923     datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
   2924     datalink_media_t media, uint_t flags, uint_t *perm_flags)
   2925 {
   2926 	dld_ioc_macprop_t *dip;
   2927 	uint32_t v = 0;
   2928 	uchar_t *cp;
   2929 	dladm_status_t status;
   2930 
   2931 	dip = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags,
   2932 	    &status, perm_flags);
   2933 	if (dip == NULL)
   2934 		return (status);
   2935 
   2936 	cp = (uchar_t *)dip->pr_val;
   2937 	(void) memcpy(&v, cp, sizeof (v));
   2938 	(void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "%ld", v);
   2939 	free(dip);
   2940 	*val_cnt = 1;
   2941 	return (DLADM_STATUS_OK);
   2942 }
   2943 
   2944 /*
   2945  * Determines the size of the structure that needs to be sent to drivers
   2946  * for retrieving the property range values.
   2947  */
   2948 static int
   2949 i_dladm_range_size(mac_propval_range_t *r, size_t *sz)
   2950 {
   2951 	uint_t count = r->mpr_count;
   2952 
   2953 	*sz = sizeof (mac_propval_range_t);
   2954 	--count;
   2955 
   2956 	switch (r->mpr_type) {
   2957 	case MAC_PROPVAL_UINT32:
   2958 		*sz += (count * sizeof (mac_propval_uint32_range_t));
   2959 		return (0);
   2960 	default:
   2961 		break;
   2962 	}
   2963 	*sz = 0;
   2964 	return (EINVAL);
   2965 }
   2966 
   2967 /* ARGSUSED */
   2968 static dladm_status_t
   2969 i_dladm_range_get(dladm_handle_t handle, prop_desc_t *pdp,
   2970     datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
   2971     datalink_media_t media, uint_t flags, uint_t *perm_flags)
   2972 {
   2973 	dld_ioc_macprop_t *dip;
   2974 	dladm_status_t status = DLADM_STATUS_OK;
   2975 	size_t	sz;
   2976 	mac_propval_range_t *rangep;
   2977 
   2978 	sz = sizeof (mac_propval_range_t);
   2979 
   2980 	/*
   2981 	 * As caller we don't know number of value ranges, the driver
   2982 	 * supports. To begin with we assume that number to be 1. If the
   2983 	 * buffer size is insufficient, driver returns back with the
   2984 	 * actual count of value ranges. See mac.h for more details.
   2985 	 */
   2986 retry:
   2987 	if ((dip = i_dladm_buf_alloc_by_name(sz, linkid, pdp->pd_name, flags,
   2988 	    &status)) == NULL)
   2989 		return (status);
   2990 
   2991 	status = i_dladm_macprop(handle, dip, B_FALSE);
   2992 	if (status != DLADM_STATUS_OK) {
   2993 		if (status == DLADM_STATUS_TOOSMALL) {
   2994 			int err;
   2995 
   2996 			rangep = (mac_propval_range_t *)(void *)&dip->pr_val;
   2997 			if ((err = i_dladm_range_size(rangep, &sz)) == 0) {
   2998 				free(dip);
   2999 				goto retry;
   3000 			} else {
   3001 				status = dladm_errno2status(err);
   3002 			}
   3003 		}
   3004 		free(dip);
   3005 		return (status);
   3006 	}
   3007 	rangep = (mac_propval_range_t *)(void *)&dip->pr_val;
   3008 
   3009 	switch (rangep->mpr_type) {
   3010 	case MAC_PROPVAL_UINT32: {
   3011 		mac_propval_uint32_range_t *ur;
   3012 		uint_t	count = rangep->mpr_count, i;
   3013 
   3014 		ur = &rangep->range_uint32[0];
   3015 
   3016 		for (i = 0; i < count; i++, ur++) {
   3017 			if (ur->mpur_min == ur->mpur_max) {
   3018 				(void) snprintf(prop_val[i], DLADM_PROP_VAL_MAX,
   3019 				    "%ld", ur->mpur_min);
   3020 			} else {
   3021 				(void) snprintf(prop_val[i], DLADM_PROP_VAL_MAX,
   3022 				    "%ld-%ld", ur->mpur_min, ur->mpur_max);
   3023 			}
   3024 		}
   3025 		*val_cnt = count;
   3026 		break;
   3027 	}
   3028 	default:
   3029 		status = DLADM_STATUS_BADARG;
   3030 		break;
   3031 	}
   3032 	free(dip);
   3033 	return (status);
   3034 }
   3035 
   3036 /* ARGSUSED */
   3037 static dladm_status_t
   3038 i_dladm_tagmode_get(dladm_handle_t handle, prop_desc_t *pdp,
   3039     datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
   3040     datalink_media_t media, uint_t flags, uint_t *perm_flags)
   3041 {
   3042 	dld_ioc_macprop_t	*dip;
   3043 	link_tagmode_t		mode;
   3044 	dladm_status_t		status;
   3045 
   3046 	dip = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags,
   3047 	    &status, perm_flags);
   3048 	if (dip == NULL)
   3049 		return (status);
   3050 	(void) memcpy(&mode, dip->pr_val, sizeof (mode));
   3051 	free(dip);
   3052 
   3053 	switch (mode) {
   3054 	case LINK_TAGMODE_NORMAL:
   3055 		(void) strlcpy(*prop_val, "normal", DLADM_PROP_VAL_MAX);
   3056 		break;
   3057 	case LINK_TAGMODE_VLANONLY:
   3058 		(void) strlcpy(*prop_val, "vlanonly", DLADM_PROP_VAL_MAX);
   3059 		break;
   3060 	default:
   3061 		(void) strlcpy(*prop_val, "unknown", DLADM_PROP_VAL_MAX);
   3062 	}
   3063 	*val_cnt = 1;
   3064 	return (DLADM_STATUS_OK);
   3065 }
   3066 
   3067 /* ARGSUSED */
   3068 static dladm_status_t
   3069 i_dladm_flowctl_get(dladm_handle_t handle, prop_desc_t *pdp,
   3070     datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
   3071     datalink_media_t media, uint_t flags, uint_t *perm_flags)
   3072 {
   3073 	dld_ioc_macprop_t *dip;
   3074 	link_flowctrl_t v;
   3075 	dladm_status_t status;
   3076 	uchar_t *cp;
   3077 
   3078 	dip = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags,
   3079 	    &status, perm_flags);
   3080 	if (dip == NULL)
   3081 		return (status);
   3082 
   3083 	cp = (uchar_t *)dip->pr_val;
   3084 	(void) memcpy(&v, cp, sizeof (v));
   3085 	switch (v) {
   3086 	case LINK_FLOWCTRL_NONE:
   3087 		(void) sprintf(*prop_val, "no");
   3088 		break;
   3089 	case LINK_FLOWCTRL_RX:
   3090 		(void) sprintf(*prop_val, "rx");
   3091 		break;
   3092 	case LINK_FLOWCTRL_TX:
   3093 		(void) sprintf(*prop_val, "tx");
   3094 		break;
   3095 	case LINK_FLOWCTRL_BI:
   3096 		(void) sprintf(*prop_val, "bi");
   3097 		break;
   3098 	}
   3099 	free(dip);
   3100 	*val_cnt = 1;
   3101 	return (DLADM_STATUS_OK);
   3102 }
   3103 
   3104 
   3105 /* ARGSUSED */
   3106 static dladm_status_t
   3107 i_dladm_set_private_prop(dladm_handle_t handle, datalink_id_t linkid,
   3108     const char *prop_name, char **prop_val, uint_t val_cnt, uint_t flags)
   3109 
   3110 {
   3111 	int		i, slen;
   3112 	int 		bufsize = 0;
   3113 	dld_ioc_macprop_t *dip = NULL;
   3114 	uchar_t 	*dp;
   3115 	link_attr_t *p;
   3116 	dladm_status_t	status = DLADM_STATUS_OK;
   3117 
   3118 	if ((prop_name == NULL && prop_val != NULL) ||
   3119 	    (prop_val != NULL && val_cnt == 0))
   3120 		return (DLADM_STATUS_BADARG);
   3121 	p = dladm_name2prop(prop_name);
   3122 	if (p->pp_id != MAC_PROP_PRIVATE)
   3123 		return (DLADM_STATUS_BADARG);
   3124 
   3125 	if (!(flags & DLADM_OPT_ACTIVE))
   3126 		return (DLADM_STATUS_OK);
   3127 
   3128 	/*
   3129 	 * private properties: all parsing is done in the kernel.
   3130 	 * allocate a enough space for each property + its separator (',').
   3131 	 */
   3132 	for (i = 0; i < val_cnt; i++) {
   3133 		bufsize += strlen(prop_val[i]) + 1;
   3134 	}
   3135 
   3136 	if (prop_val == NULL) {
   3137 		/*
   3138 		 * getting default value. so use more buffer space.
   3139 		 */
   3140 		bufsize += DLADM_PROP_BUF_CHUNK;
   3141 	}
   3142 
   3143 	dip = i_dladm_buf_alloc_by_name(bufsize + 1, linkid, prop_name,
   3144 	    (prop_val != NULL ? 0 : MAC_PROP_DEFAULT), &status);
   3145 	if (dip == NULL)
   3146 		return (status);
   3147 
   3148 	dp = (uchar_t *)dip->pr_val;
   3149 	slen = 0;
   3150 
   3151 	if (prop_val == NULL) {
   3152 		status = i_dladm_macprop(handle, dip, B_FALSE);
   3153 		dip->pr_flags = 0;
   3154 	} else {
   3155 		for (i = 0; i < val_cnt; i++) {
   3156 			int plen = 0;
   3157 
   3158 			plen = strlen(prop_val[i]);
   3159 			bcopy(prop_val[i], dp, plen);
   3160 			slen += plen;
   3161 			/*
   3162 			 * add a "," separator and update dp.
   3163 			 */
   3164 			if (i != (val_cnt -1))
   3165 				dp[slen++] = ',';
   3166 			dp += (plen + 1);
   3167 		}
   3168 	}
   3169 	if (status == DLADM_STATUS_OK)
   3170 		status = i_dladm_macprop(handle, dip, B_TRUE);
   3171 
   3172 	free(dip);
   3173 	return (status);
   3174 }
   3175 
   3176 static dladm_status_t
   3177 i_dladm_get_priv_prop(dladm_handle_t handle, datalink_id_t linkid,
   3178     const char *prop_name, char **prop_val, uint_t *val_cnt,
   3179     dladm_prop_type_t type, uint_t dld_flags)
   3180 {
   3181 	dladm_status_t	status = DLADM_STATUS_OK;
   3182 	dld_ioc_macprop_t *dip = NULL;
   3183 	link_attr_t *p;
   3184 
   3185 	if ((prop_name == NULL && prop_val != NULL) ||
   3186 	    (prop_val != NULL && val_cnt == 0))
   3187 		return (DLADM_STATUS_BADARG);
   3188 
   3189 	p = dladm_name2prop(prop_name);
   3190 	if (p->pp_id != MAC_PROP_PRIVATE)
   3191 		return (DLADM_STATUS_BADARG);
   3192 
   3193 	/*
   3194 	 * private properties: all parsing is done in the kernel.
   3195 	 */
   3196 	dip = i_dladm_buf_alloc_by_name(DLADM_PROP_BUF_CHUNK, linkid, prop_name,
   3197 	    dld_flags, &status);
   3198 	if (dip == NULL)
   3199 		return (status);
   3200 
   3201 	if ((status = i_dladm_macprop(handle, dip, B_FALSE)) ==
   3202 	    DLADM_STATUS_OK) {
   3203 		if (type == DLADM_PROP_VAL_PERM) {
   3204 			(void) dladm_perm2str(dip->pr_perm_flags, *prop_val);
   3205 		} else if (type == DLADM_PROP_VAL_MODIFIABLE) {
   3206 			*prop_val[0] = '\0';
   3207 		} else {
   3208 			(void) strncpy(*prop_val, dip->pr_val,
   3209 			    DLADM_PROP_VAL_MAX);
   3210 		}
   3211 		*val_cnt = 1;
   3212 	} else if ((status == DLADM_STATUS_NOTSUP) &&
   3213 	    (type == DLADM_PROP_VAL_CURRENT)) {
   3214 		status = DLADM_STATUS_NOTFOUND;
   3215 	}
   3216 	free(dip);
   3217 	return (status);
   3218 }
   3219 
   3220 
   3221 static dladm_status_t
   3222 i_dladm_getset_defval(dladm_handle_t handle, prop_desc_t *pdp,
   3223     datalink_id_t linkid, datalink_media_t media, uint_t flags)
   3224 {
   3225 	dladm_status_t status;
   3226 	char **prop_vals = NULL, *buf;
   3227 	size_t bufsize;
   3228 	uint_t cnt;
   3229 	int i;
   3230 	uint_t perm_flags;
   3231 
   3232 	/*
   3233 	 * Allocate buffer needed for prop_vals array. We can have at most
   3234 	 * DLADM_MAX_PROP_VALCNT char *prop_vals[] entries, where
   3235 	 * each entry has max size DLADM_PROP_VAL_MAX
   3236 	 */
   3237 	bufsize =
   3238 	    (sizeof (char *) + DLADM_PROP_VAL_MAX) * DLADM_MAX_PROP_VALCNT;
   3239 	buf = malloc(bufsize);
   3240 	prop_vals = (char **)(void *)buf;
   3241 	for (i = 0; i < DLADM_MAX_PROP_VALCNT; i++) {
   3242 		prop_vals[i] = buf +
   3243 		    sizeof (char *) * DLADM_MAX_PROP_VALCNT +
   3244 		    i * DLADM_PROP_VAL_MAX;
   3245 	}
   3246 
   3247 	/*
   3248 	 * For properties which have pdp->pd_defval.vd_name as a non-empty
   3249 	 * string, the "" itself is used to reset the property (exceptions
   3250 	 * are zone and autopush, which populate vdp->vd_val). So
   3251 	 * libdladm can copy pdp->pd_defval over to the val_desc_t passed
   3252 	 * down on the setprop using the global values in the table. For
   3253 	 * other cases (vd_name is ""), doing reset-linkprop will cause
   3254 	 * libdladm to do a getprop to find the default value and then do
   3255 	 * a setprop to reset the value to default.
   3256 	 */
   3257 	status = pdp->pd_get(handle, pdp, linkid, prop_vals, &cnt, media,
   3258 	    MAC_PROP_DEFAULT, &perm_flags);
   3259 	if (status == DLADM_STATUS_OK) {
   3260 		if (perm_flags == MAC_PROP_PERM_RW) {
   3261 			status = i_dladm_set_single_prop(handle, linkid,
   3262 			    pdp->pd_class, media, pdp, prop_vals, cnt, flags);
   3263 		}
   3264 		else
   3265 			status = DLADM_STATUS_NOTSUP;
   3266 	}
   3267 	free(buf);
   3268 	return (status);
   3269 }
   3270 
   3271 /* ARGSUSED */
   3272 static dladm_status_t
   3273 get_stp_prop(dladm_handle_t handle, struct prop_desc *pd, datalink_id_t linkid,
   3274     char **prop_val, uint_t *val_cnt, datalink_media_t media, uint_t flags,
   3275     uint_t *perm_flags)
   3276 {
   3277 	const bridge_public_prop_t *bpp;
   3278 	dladm_status_t retv;
   3279 	int val, i;
   3280 
   3281 	if (flags != 0)
   3282 		return (DLADM_STATUS_NOTSUP);
   3283 	*perm_flags = MAC_PROP_PERM_RW;
   3284 	*val_cnt = 1;
   3285 	for (bpp = bridge_prop; bpp->bpp_name != NULL; bpp++)
   3286 		if (strcmp(bpp->bpp_name, pd->pd_name) == 0)
   3287 			break;
   3288 	retv = dladm_bridge_get_port_cfg(handle, linkid, bpp->bpp_code, &val);
   3289 	/* If the daemon isn't running, then return the persistent value */
   3290 	if (retv == DLADM_STATUS_NOTFOUND) {
   3291 		if (i_dladm_get_linkprop_db(handle, linkid, pd->pd_name,
   3292 		    prop_val, val_cnt) != DLADM_STATUS_OK)
   3293 			(void) strlcpy(*prop_val, pd->pd_defval.vd_name,
   3294 			    DLADM_PROP_VAL_MAX);
   3295 		return (DLADM_STATUS_OK);
   3296 	}
   3297 	if (retv != DLADM_STATUS_OK) {
   3298 		(void) strlcpy(*prop_val, "?", DLADM_PROP_VAL_MAX);
   3299 		return (retv);
   3300 	}
   3301 	if (val == pd->pd_defval.vd_val && pd->pd_defval.vd_name[0] != '\0') {
   3302 		(void) strlcpy(*prop_val, pd->pd_defval.vd_name,
   3303 		    DLADM_PROP_VAL_MAX);
   3304 		return (DLADM_STATUS_OK);
   3305 	}
   3306 	for (i = 0; i < pd->pd_noptval; i++) {
   3307 		if (val == pd->pd_optval[i].vd_val) {
   3308 			(void) strlcpy(*prop_val, pd->pd_optval[i].vd_name,
   3309 			    DLADM_PROP_VAL_MAX);
   3310 			return (DLADM_STATUS_OK);
   3311 		}
   3312 	}
   3313 	(void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "%u", (unsigned)val);
   3314 	return (DLADM_STATUS_OK);
   3315 }
   3316 
   3317 /* ARGSUSED1 */
   3318 static dladm_status_t
   3319 set_stp_prop(dladm_handle_t handle, prop_desc_t *pd, datalink_id_t linkid,
   3320     val_desc_t *vdp, uint_t val_cnt, uint_t flags, datalink_media_t media)
   3321 {
   3322 	/*
   3323 	 * Special case for mcheck: the daemon resets the value to zero, and we
   3324 	 * don't want the daemon to refresh itself; it leads to deadlock.
   3325 	 */
   3326 	if (flags & DLADM_OPT_NOREFRESH)
   3327 		return (DLADM_STATUS_OK);
   3328 
   3329 	/* Tell the running daemon, if any */
   3330 	return (dladm_bridge_refresh(handle, linkid));
   3331 }
   3332 
   3333 /*
   3334  * This is used only for stp_priority, stp_cost, and stp_mcheck.
   3335  */
   3336 /* ARGSUSED */
   3337 static dladm_status_t
   3338 check_stp_prop(dladm_handle_t handle, struct prop_desc *pd,
   3339     datalink_id_t linkid, char **prop_val, uint_t val_cnt, val_desc_t *vdp,
   3340     datalink_media_t media)
   3341 {
   3342 	char *cp;
   3343 	boolean_t iscost;
   3344 
   3345 	if (val_cnt != 1)
   3346 		return (DLADM_STATUS_BADVALCNT);
   3347 
   3348 	if (prop_val == NULL) {
   3349 		vdp->vd_val = 0;
   3350 	} else {
   3351 		/* Only stp_priority and stp_cost use this function */
   3352 		iscost = strcmp(pd->pd_name, "stp_cost") == 0;
   3353 
   3354 		if (iscost && strcmp(prop_val[0], "auto") == 0) {
   3355 			/* Illegal value 0 is allowed to mean "automatic" */
   3356 			vdp->vd_val = 0;
   3357 		} else {
   3358 			errno = 0;
   3359 			vdp->vd_val = strtoul(prop_val[0], &cp, 0);
   3360 			if (errno != 0 || *cp != '\0')
   3361 				return (DLADM_STATUS_BADVAL);
   3362 		}
   3363 	}
   3364 
   3365 	if (iscost) {
   3366 		return (vdp->vd_val > 65535 ? DLADM_STATUS_BADVAL :
   3367 		    DLADM_STATUS_OK);
   3368 	} else {
   3369 		if (vdp->vd_val > 255)
   3370 			return (DLADM_STATUS_BADVAL);
   3371 		/*
   3372 		 * If the user is setting stp_mcheck non-zero, then (per the
   3373 		 * IEEE management standards and UNH testing) we need to check
   3374 		 * whether this link is part of a bridge that is running RSTP.
   3375 		 * If it's not, then setting the flag is an error.  Note that
   3376 		 * errors are intentionally discarded here; it's the value
   3377 		 * that's the problem -- it's not a bad value, merely one that
   3378 		 * can't be used now.
   3379 		 */
   3380 		if (strcmp(pd->pd_name, "stp_mcheck") == 0 &&
   3381 		    vdp->vd_val != 0) {
   3382 			char bridge[MAXLINKNAMELEN];
   3383 			UID_STP_CFG_T cfg;
   3384 			dladm_bridge_prot_t brprot;
   3385 
   3386 			if (dladm_bridge_getlink(handle, linkid, bridge,
   3387 			    sizeof (bridge)) != DLADM_STATUS_OK ||
   3388 			    dladm_bridge_get_properties(bridge, &cfg,
   3389 			    &brprot) != DLADM_STATUS_OK)
   3390 				return (DLADM_STATUS_FAILED);
   3391 			if (cfg.force_version <= 1)
   3392 				return (DLADM_STATUS_FAILED);
   3393 		}
   3394 		return (DLADM_STATUS_OK);
   3395 	}
   3396 }
   3397 
   3398 /* ARGSUSED */
   3399 static dladm_status_t
   3400 get_bridge_forward(dladm_handle_t handle, struct prop_desc *pd,
   3401     datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
   3402     datalink_media_t media, uint_t flags, uint_t *perm_flags)
   3403 {
   3404 	dladm_status_t retv;
   3405 	uint_t val;
   3406 
   3407 	if (flags != 0)
   3408 		return (DLADM_STATUS_NOTSUP);
   3409 	*perm_flags = MAC_PROP_PERM_RW;
   3410 	*val_cnt = 1;
   3411 	retv = dladm_bridge_get_forwarding(handle, linkid, &val);
   3412 	if (retv == DLADM_STATUS_NOTFOUND) {
   3413 		if (i_dladm_get_linkprop_db(handle, linkid, pd->pd_name,
   3414 		    prop_val, val_cnt) != DLADM_STATUS_OK)
   3415 			(void) strlcpy(*prop_val, pd->pd_defval.vd_name,
   3416 			    DLADM_PROP_VAL_MAX);
   3417 		return (DLADM_STATUS_OK);
   3418 	}
   3419 	if (retv == DLADM_STATUS_OK)
   3420 		(void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "%u", val);
   3421 	else
   3422 		(void) strlcpy(*prop_val, "?", DLADM_PROP_VAL_MAX);
   3423 	return (retv);
   3424 }
   3425 
   3426 /* ARGSUSED */
   3427 static dladm_status_t
   3428 set_bridge_forward(dladm_handle_t handle, prop_desc_t *pd, datalink_id_t linkid,
   3429     val_desc_t *vdp, uint_t val_cnt, uint_t flags, datalink_media_t media)
   3430 {
   3431 	/* Tell the running daemon, if any */
   3432 	return (dladm_bridge_refresh(handle, linkid));
   3433 }
   3434 
   3435 /* ARGSUSED */
   3436 static dladm_status_t
   3437 get_bridge_pvid(dladm_handle_t handle, struct prop_desc *pd,
   3438     datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
   3439     datalink_media_t media, uint_t flags, uint_t *perm_flags)
   3440 {
   3441 	dladm_status_t status;
   3442 	dld_ioc_macprop_t *dip;
   3443 	uint16_t pvid;
   3444 
   3445 	if (flags != 0)
   3446 		return (DLADM_STATUS_NOTSUP);
   3447 	*perm_flags = MAC_PROP_PERM_RW;
   3448 	*val_cnt = 1;
   3449 	dip = i_dladm_buf_alloc_by_id(sizeof (uint16_t), linkid, MAC_PROP_PVID,
   3450 	    0, &status);
   3451 	if (dip == NULL)
   3452 		return (status);
   3453 	status = i_dladm_macprop(handle, dip, B_FALSE);
   3454 	if (status == DLADM_STATUS_OK) {
   3455 		(void) memcpy(&pvid, dip->pr_val, sizeof (pvid));
   3456 		(void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "%u", pvid);
   3457 	} else {
   3458 		(void) strlcpy(*prop_val, "?", DLADM_PROP_VAL_MAX);
   3459 	}
   3460 	free(dip);
   3461 	return (status);
   3462 }
   3463 
   3464 /* ARGSUSED */
   3465 static dladm_status_t
   3466 set_bridge_pvid(dladm_handle_t handle, prop_desc_t *pd, datalink_id_t linkid,
   3467     val_desc_t *vdp, uint_t val_cnt, uint_t flags, datalink_media_t media)
   3468 {
   3469 	dladm_status_t status;
   3470 	dld_ioc_macprop_t *dip;
   3471 	uint16_t pvid;
   3472 
   3473 	dip = i_dladm_buf_alloc_by_id(sizeof (uint16_t), linkid, MAC_PROP_PVID,
   3474 	    0, &status);
   3475 	if (dip == NULL)
   3476 		return (status);
   3477 	pvid = vdp->vd_val;
   3478 	(void) memcpy(dip->pr_val, &pvid, sizeof (pvid));
   3479 	status = i_dladm_macprop(handle, dip, B_TRUE);
   3480 	free(dip);
   3481 	if (status != DLADM_STATUS_OK)
   3482 		return (status);
   3483 
   3484 	/* Tell the running daemon, if any */
   3485 	return (dladm_bridge_refresh(handle, linkid));
   3486 }
   3487 
   3488 /* ARGSUSED */
   3489 static dladm_status_t
   3490 check_bridge_pvid(dladm_handle_t handle, struct prop_desc *pd,
   3491     datalink_id_t linkid, char **prop_val, uint_t val_cnt, val_desc_t *vdp,
   3492     datalink_media_t media)
   3493 {
   3494 	char *cp;
   3495 
   3496 	if (val_cnt != 1)
   3497 		return (DLADM_STATUS_BADVALCNT);
   3498 
   3499 	if (prop_val == NULL) {
   3500 		vdp->vd_val = 1;
   3501 	} else {
   3502 		errno = 0;
   3503 		vdp->vd_val = strtoul(prop_val[0], &cp, 0);
   3504 		if (errno != 0 || *cp != '\0')
   3505 			return (DLADM_STATUS_BADVAL);
   3506 	}
   3507 
   3508 	return (vdp->vd_val > VLAN_ID_MAX ? DLADM_STATUS_BADVAL :
   3509 	    DLADM_STATUS_OK);
   3510 }
   3511 
   3512 dladm_status_t
   3513 i_dladm_wlan_param(dladm_handle_t handle, datalink_id_t linkid, void *buf,
   3514     mac_prop_id_t cmd, size_t len, boolean_t set)
   3515 {
   3516 	uint32_t		flags;
   3517 	dladm_status_t		status;
   3518 	uint32_t		media;
   3519 	dld_ioc_macprop_t	*dip;
   3520 	void			*dp;
   3521 
   3522 	if ((status = dladm_datalink_id2info(handle, linkid, &flags, NULL,
   3523 	    &media, NULL, 0)) != DLADM_STATUS_OK) {
   3524 		return (status);
   3525 	}
   3526 
   3527 	if (media != DL_WIFI)
   3528 		return (DLADM_STATUS_BADARG);
   3529 
   3530 	if (!(flags & DLADM_OPT_ACTIVE))
   3531 		return (DLADM_STATUS_TEMPONLY);
   3532 
   3533 	if (len == (MAX_BUF_LEN - WIFI_BUF_OFFSET))
   3534 		len = MAX_BUF_LEN - sizeof (dld_ioc_macprop_t) - 1;
   3535 
   3536 	dip = i_dladm_buf_alloc_by_id(len, linkid, cmd, 0, &status);
   3537 	if (dip == NULL)
   3538 		return (DLADM_STATUS_NOMEM);
   3539 
   3540 	dp = (uchar_t *)dip->pr_val;
   3541 	if (set)
   3542 		(void) memcpy(dp, buf, len);
   3543 
   3544 	status = i_dladm_macprop(handle, dip, set);
   3545 	if (status == DLADM_STATUS_OK) {
   3546 		if (!set)
   3547 			(void) memcpy(buf, dp, len);
   3548 	}
   3549 
   3550 	free(dip);
   3551 	return (status);
   3552 }
   3553 
   3554 dladm_status_t
   3555 dladm_parse_link_props(char *str, dladm_arg_list_t **listp, boolean_t novalues)
   3556 {
   3557 	return (dladm_parse_args(str, listp, novalues));
   3558 }
   3559 
   3560 /*
   3561  * Retrieve the one link property from the database
   3562  */
   3563 /*ARGSUSED*/
   3564 static int
   3565 i_dladm_get_one_prop(dladm_handle_t handle, datalink_id_t linkid,
   3566     const char *prop_name, void *arg)
   3567 {
   3568 	dladm_arg_list_t	*proplist = arg;
   3569 	dladm_arg_info_t	*aip = NULL;
   3570 
   3571 	aip = &proplist->al_info[proplist->al_count];
   3572 	/*
   3573 	 * it is fine to point to prop_name since prop_name points to the
   3574 	 * prop_table[n].pd_name.
   3575 	 */
   3576 	aip->ai_name = prop_name;
   3577 
   3578 	(void) dladm_get_linkprop(handle, linkid, DLADM_PROP_VAL_PERSISTENT,
   3579 	    prop_name, aip->ai_val, &aip->ai_count);
   3580 
   3581 	if (aip->ai_count != 0)
   3582 		proplist->al_count++;
   3583 
   3584 	return (DLADM_WALK_CONTINUE);
   3585 }
   3586 
   3587 
   3588 /*
   3589  * Retrieve all link properties for a link from the database and
   3590  * return a property list.
   3591  */
   3592 dladm_status_t
   3593 dladm_link_get_proplist(dladm_handle_t handle, datalink_id_t linkid,
   3594     dladm_arg_list_t **listp)
   3595 {
   3596 	dladm_arg_list_t	*list;
   3597 	dladm_status_t		status = DLADM_STATUS_OK;
   3598 
   3599 	list = calloc(1, sizeof (dladm_arg_list_t));
   3600 	if (list == NULL)
   3601 		return (dladm_errno2status(errno));
   3602 
   3603 	status = dladm_walk_linkprop(handle, linkid, list,
   3604 	    i_dladm_get_one_prop);
   3605 
   3606 	*listp = list;
   3607 	return (status);
   3608 }
   3609 
   3610 /*
   3611  * Retrieve the named property from a proplist, check the value and
   3612  * convert to a kernel structure.
   3613  */
   3614 static dladm_status_t
   3615 i_dladm_link_proplist_extract_one(dladm_handle_t handle,
   3616     dladm_arg_list_t *proplist, const char *name, void *arg)
   3617 {
   3618 	dladm_status_t		status;
   3619 	dladm_arg_info_t	*aip = NULL;
   3620 	int			i, j;
   3621 
   3622 	/* Find named property in proplist */
   3623 	for (i = 0; i < proplist->al_count; i++) {
   3624 		aip = &proplist->al_info[i];
   3625 		if (strcasecmp(aip->ai_name, name) == 0)
   3626 			break;
   3627 	}
   3628 
   3629 	/* Property not in list */
   3630 	if (i == proplist->al_count)
   3631 		return (DLADM_STATUS_OK);
   3632 
   3633 	for (i = 0; i < DLADM_MAX_PROPS; i++) {
   3634 		prop_desc_t	*pdp = &prop_table[i];
   3635 		val_desc_t	*vdp;
   3636 
   3637 		vdp = malloc(sizeof (val_desc_t) * aip->ai_count);
   3638 		if (vdp == NULL)
   3639 			return (DLADM_STATUS_NOMEM);
   3640 
   3641 		if (strcasecmp(aip->ai_name, pdp->pd_name) != 0)
   3642 			continue;
   3643 
   3644 		if (aip->ai_val == NULL)
   3645 			return (DLADM_STATUS_BADARG);
   3646 
   3647 		/* Check property value */
   3648 		if (pdp->pd_check != NULL) {
   3649 			status = pdp->pd_check(handle, pdp, 0, aip->ai_val,
   3650 			    aip->ai_count, vdp, 0);
   3651 		} else {
   3652 			status = DLADM_STATUS_BADARG;
   3653 		}
   3654 
   3655 		if (status != DLADM_STATUS_OK)
   3656 			return (status);
   3657 
   3658 		for (j = 0; j < DLADM_MAX_RSRC_PROP; j++) {
   3659 			resource_prop_t	*rpp = &rsrc_prop_table[j];
   3660 
   3661 			if (strcasecmp(aip->ai_name, rpp->rp_name) != 0)
   3662 				continue;
   3663 
   3664 			/* Extract kernel structure */
   3665 			if (rpp->rp_extract != NULL) {
   3666 				status = rpp->rp_extract(vdp,
   3667 				    aip->ai_count, arg);
   3668 			} else {
   3669 				status = DLADM_STATUS_BADARG;
   3670 			}
   3671 			break;
   3672 		}
   3673 
   3674 		if (status != DLADM_STATUS_OK)
   3675 			return (status);
   3676 
   3677 		break;
   3678 	}
   3679 	return (status);
   3680 }
   3681 
   3682 /*
   3683  * Extract properties from a proplist and convert to mac_resource_props_t.
   3684  */
   3685 dladm_status_t
   3686 dladm_link_proplist_extract(dladm_handle_t handle, dladm_arg_list_t *proplist,
   3687     mac_resource_props_t *mrp)
   3688 {
   3689 	dladm_status_t	status;
   3690 	int		i;
   3691 
   3692 	for (i = 0; i < DLADM_MAX_RSRC_PROP; i++) {
   3693 		status = i_dladm_link_proplist_extract_one(handle,
   3694 		    proplist, rsrc_prop_table[i].rp_name, mrp);
   3695 		if (status != DLADM_STATUS_OK)
   3696 			return (status);
   3697 	}
   3698 	return (status);
   3699 }
   3700 
   3701 static const char *
   3702 dladm_perm2str(uint_t perm, char *buf)
   3703 {
   3704 	(void) snprintf(buf, DLADM_STRSIZE, "%c%c",
   3705 	    ((perm & MAC_PROP_PERM_READ) != 0) ? 'r' : '-',
   3706 	    ((perm & MAC_PROP_PERM_WRITE) != 0) ? 'w' : '-');
   3707 	return (buf);
   3708 }
   3709 
   3710 dladm_status_t
   3711 i_dladm_get_state(dladm_handle_t handle, datalink_id_t linkid,
   3712     link_state_t *state)
   3713 {
   3714 	dld_ioc_macprop_t	*dip;
   3715 	dladm_status_t		status;
   3716 	uint_t			perms;
   3717 
   3718 	dip = i_dladm_get_public_prop(handle, linkid, "state", 0, &status,
   3719 	    &perms);
   3720 	if (status != DLADM_STATUS_OK)
   3721 		return (status);
   3722 	(void) memcpy(state, dip->pr_val, sizeof (*state));
   3723 	free(dip);
   3724 	return (status);
   3725 }
   3726 
   3727 boolean_t
   3728 dladm_attr_is_linkprop(const char *name)
   3729 {
   3730 	/* non-property attribute names */
   3731 	const char *nonprop[] = {
   3732 		/* dlmgmtd core attributes */
   3733 		"name",
   3734 		"class",
   3735 		"media",
   3736 		FPHYMAJ,
   3737 		FPHYINST,
   3738 		FDEVNAME,
   3739 
   3740 		/* other attributes for vlan, aggr, etc */
   3741 		DLADM_ATTR_NAMES
   3742 	};
   3743 	boolean_t	is_nonprop = B_FALSE;
   3744 	int		i;
   3745 
   3746 	for (i = 0; i < sizeof (nonprop) / sizeof (nonprop[0]); i++) {
   3747 		if (strcmp(name, nonprop[i]) == 0) {
   3748 			is_nonprop = B_TRUE;
   3749 			break;
   3750 		}
   3751 	}
   3752 
   3753 	return (!is_nonprop);
   3754 }
   3755