13147Sxc151355 /*
23147Sxc151355  * CDDL HEADER START
33147Sxc151355  *
43147Sxc151355  * The contents of this file are subject to the terms of the
53147Sxc151355  * Common Development and Distribution License (the "License").
63147Sxc151355  * You may not use this file except in compliance with the License.
73147Sxc151355  *
83147Sxc151355  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
93147Sxc151355  * or http://www.opensolaris.org/os/licensing.
103147Sxc151355  * See the License for the specific language governing permissions
113147Sxc151355  * and limitations under the License.
123147Sxc151355  *
133147Sxc151355  * When distributing Covered Code, include this CDDL HEADER in each
143147Sxc151355  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
153147Sxc151355  * If applicable, add the following below this CDDL HEADER, with the
163147Sxc151355  * fields enclosed by brackets "[]" replaced with your own identifying
173147Sxc151355  * information: Portions Copyright [yyyy] [name of copyright owner]
183147Sxc151355  *
193147Sxc151355  * CDDL HEADER END
203147Sxc151355  */
213147Sxc151355 /*
225895Syz147064  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
233147Sxc151355  * Use is subject to license terms.
243147Sxc151355  */
253147Sxc151355 
263147Sxc151355 #include <stdlib.h>
273147Sxc151355 #include <strings.h>
283147Sxc151355 #include <errno.h>
293147Sxc151355 #include <ctype.h>
305895Syz147064 #include <stddef.h>
313448Sdh155122 #include <sys/types.h>
323147Sxc151355 #include <sys/stat.h>
333448Sdh155122 #include <sys/dld.h>
343448Sdh155122 #include <sys/zone.h>
353448Sdh155122 #include <fcntl.h>
363448Sdh155122 #include <unistd.h>
373448Sdh155122 #include <libdevinfo.h>
383448Sdh155122 #include <zone.h>
393871Syz147064 #include <libdllink.h>
403147Sxc151355 #include <libdladm_impl.h>
415895Syz147064 #include <libdlwlan_impl.h>
423871Syz147064 #include <libdlwlan.h>
435895Syz147064 #include <libdlvlan.h>
44*8275SEric Cheng #include <libdlvnic.h>
45*8275SEric Cheng #include <libintl.h>
463448Sdh155122 #include <dlfcn.h>
473448Sdh155122 #include <link.h>
485895Syz147064 #include <inet/wifi_ioctl.h>
495903Ssowmini #include <libdladm.h>
50*8275SEric Cheng #include <libdlstat.h>
515903Ssowmini #include <sys/param.h>
52*8275SEric Cheng #include <sys/debug.h>
53*8275SEric Cheng #include <sys/dld.h>
54*8275SEric Cheng #include <sys/mac_flow.h>
555903Ssowmini #include <inttypes.h>
565903Ssowmini #include <sys/ethernet.h>
577663SSowmini.Varadhan@Sun.COM #include <net/wpa.h>
587663SSowmini.Varadhan@Sun.COM #include <sys/sysmacros.h>
593448Sdh155122 
605895Syz147064 /*
615895Syz147064  * The linkprop get() callback.
62*8275SEric Cheng  * - pd: 	pointer to the prop_desc_t
635895Syz147064  * - propstrp:	a property string array to keep the returned property.
645895Syz147064  *		Caller allocated.
655895Syz147064  * - cntp:	number of returned properties.
665895Syz147064  *		Caller also uses it to indicate how many it expects.
675895Syz147064  */
685903Ssowmini struct prop_desc;
69*8275SEric Cheng typedef struct prop_desc prop_desc_t;
70*8275SEric Cheng 
71*8275SEric Cheng typedef dladm_status_t	pd_getf_t(prop_desc_t *pdp,
725960Ssowmini 			datalink_id_t, char **propstp, uint_t *cntp,
738118SVasumathi.Sundaram@Sun.COM 			datalink_media_t, uint_t, uint_t *);
745895Syz147064 
755895Syz147064 /*
765895Syz147064  * The linkprop set() callback.
775895Syz147064  * - propval:	a val_desc_t array which keeps the property values to be set.
785895Syz147064  * - cnt:	number of properties to be set.
795903Ssowmini  * - flags: 	additional flags passed down the system call.
805903Ssowmini  *
815903Ssowmini  * pd_set takes val_desc_t given by pd_check(), translates it into
825903Ssowmini  * a format suitable for kernel consumption. This may require allocation
835903Ssowmini  * of ioctl buffers etc. pd_set() may call another common routine (used
845903Ssowmini  * by all other pd_sets) which invokes the ioctl.
855895Syz147064  */
86*8275SEric Cheng typedef dladm_status_t	pd_setf_t(prop_desc_t *, datalink_id_t,
87*8275SEric Cheng 			    val_desc_t *propval, uint_t cnt, uint_t flags,
88*8275SEric Cheng 			    datalink_media_t);
893448Sdh155122 
905895Syz147064 /*
915895Syz147064  * The linkprop check() callback.
925895Syz147064  * - propstrp:	property string array which keeps the property to be checked.
935895Syz147064  * - cnt:	number of properties.
945895Syz147064  * - propval:	return value; the property values of the given property strings.
955903Ssowmini  *
965903Ssowmini  * pd_check checks that the input values are valid. It does so by
975903Ssowmini  * iteraring through the pd_modval list for the property. If
985903Ssowmini  * the modifiable values cannot be expressed as a list, a pd_check
995903Ssowmini  * specific to this property can be used. If the input values are
1005903Ssowmini  * verified to be valid, pd_check allocates a val_desc_t and fills it
1015903Ssowmini  * with either a val_desc_t found on the pd_modval list or something
1025903Ssowmini  * generated on the fly.
1035895Syz147064  */
104*8275SEric Cheng typedef dladm_status_t	pd_checkf_t(prop_desc_t *pdp, datalink_id_t,
105*8275SEric Cheng 			    char **propstrp, uint_t cnt, val_desc_t *propval,
1065960Ssowmini 			    datalink_media_t);
1073448Sdh155122 
1087663SSowmini.Varadhan@Sun.COM typedef struct link_attr_s {
1096789Sam223141 	mac_prop_id_t	pp_id;
1105903Ssowmini 	size_t		pp_valsize;
1115903Ssowmini 	char		*pp_name;
1127663SSowmini.Varadhan@Sun.COM } link_attr_t;
1135903Ssowmini 
1147663SSowmini.Varadhan@Sun.COM static dld_ioc_macprop_t *i_dladm_buf_alloc_by_name(size_t, datalink_id_t,
115*8275SEric Cheng 			    const char *, uint_t, dladm_status_t *);
1167663SSowmini.Varadhan@Sun.COM static dld_ioc_macprop_t *i_dladm_buf_alloc_by_id(size_t, datalink_id_t,
117*8275SEric Cheng 			    mac_prop_id_t, uint_t, dladm_status_t *);
118*8275SEric Cheng static dld_ioc_macprop_t *i_dladm_get_public_prop(datalink_id_t, char *, uint_t,
119*8275SEric Cheng 			    dladm_status_t *, uint_t *);
120*8275SEric Cheng 
1217342SAruna.Ramakrishna@Sun.COM static dladm_status_t i_dladm_set_prop(datalink_id_t, const char *, char **,
1225903Ssowmini 					uint_t, uint_t);
1237342SAruna.Ramakrishna@Sun.COM static dladm_status_t i_dladm_get_prop(datalink_id_t, const char *, char **,
1246512Ssowmini 					uint_t *, dladm_prop_type_t, uint_t);
1257663SSowmini.Varadhan@Sun.COM static link_attr_t *dladm_name2prop(const char *);
1267663SSowmini.Varadhan@Sun.COM static link_attr_t *dladm_id2prop(mac_prop_id_t);
127*8275SEric Cheng 
1285895Syz147064 static pd_getf_t	do_get_zone, do_get_autopush, do_get_rate_mod,
1295895Syz147064 			do_get_rate_prop, do_get_channel_prop,
1305903Ssowmini 			do_get_powermode_prop, do_get_radio_prop,
1317342SAruna.Ramakrishna@Sun.COM 			i_dladm_duplex_get, i_dladm_status_get,
1327342SAruna.Ramakrishna@Sun.COM 			i_dladm_binary_get, i_dladm_uint32_get,
133*8275SEric Cheng 			i_dladm_flowctl_get, dld_maxbw_get, dld_cpus_get,
134*8275SEric Cheng 			dld_priority_get;
135*8275SEric Cheng 
1367342SAruna.Ramakrishna@Sun.COM static pd_setf_t	do_set_zone, do_set_rate_prop,
1375903Ssowmini 			do_set_powermode_prop, do_set_radio_prop,
138*8275SEric Cheng 			i_dladm_set_public_prop, do_set_res, do_set_cpus;
139*8275SEric Cheng 
1405903Ssowmini static pd_checkf_t	do_check_zone, do_check_autopush, do_check_rate,
141*8275SEric Cheng 			i_dladm_defmtu_check, do_check_maxbw, do_check_cpus,
142*8275SEric Cheng 			do_check_priority;
143*8275SEric Cheng 
144*8275SEric Cheng static dladm_status_t	i_dladm_speed_get(prop_desc_t *, datalink_id_t,
145*8275SEric Cheng 			char **, uint_t *, uint_t, uint_t *);
1467663SSowmini.Varadhan@Sun.COM static dladm_status_t	i_dladm_wlan_get_legacy_ioctl(datalink_id_t, void *,
1477663SSowmini.Varadhan@Sun.COM 			    uint_t, uint_t);
1487663SSowmini.Varadhan@Sun.COM static dladm_status_t	i_dladm_wlan_set_legacy_ioctl(datalink_id_t, void *,
1497663SSowmini.Varadhan@Sun.COM 			    uint_t, uint_t);
1507663SSowmini.Varadhan@Sun.COM static dladm_status_t	i_dladm_macprop(void *, boolean_t);
151*8275SEric Cheng static const char	*dladm_perm2str(uint_t, char *);
152*8275SEric Cheng 
153*8275SEric Cheng struct prop_desc {
1545895Syz147064 	/*
1555895Syz147064 	 * link property name
1565895Syz147064 	 */
1575895Syz147064 	char			*pd_name;
1585895Syz147064 
1595895Syz147064 	/*
1605895Syz147064 	 * default property value, can be set to { "", NULL }
1615895Syz147064 	 */
1625895Syz147064 	val_desc_t		pd_defval;
1635895Syz147064 
1645895Syz147064 	/*
1655895Syz147064 	 * list of optional property values, can be NULL.
1665895Syz147064 	 *
1675895Syz147064 	 * This is set to non-NULL if there is a list of possible property
1685895Syz147064 	 * values.  pd_optval would point to the array of possible values.
1695895Syz147064 	 */
1705895Syz147064 	val_desc_t		*pd_optval;
1715895Syz147064 
1725895Syz147064 	/*
1735895Syz147064 	 * count of the above optional property values. 0 if pd_optval is NULL.
1745895Syz147064 	 */
1755895Syz147064 	uint_t			pd_noptval;
1765895Syz147064 
1775895Syz147064 	/*
1785895Syz147064 	 * callback to set link property;
1795895Syz147064 	 * set to NULL if this property is read-only
1805895Syz147064 	 */
1815895Syz147064 	pd_setf_t		*pd_set;
1825895Syz147064 
1835895Syz147064 	/*
1845895Syz147064 	 * callback to get modifiable link property
1855895Syz147064 	 */
1865895Syz147064 	pd_getf_t		*pd_getmod;
1875895Syz147064 
1885895Syz147064 	/*
1895895Syz147064 	 * callback to get current link property
1905895Syz147064 	 */
1915895Syz147064 	pd_getf_t		*pd_get;
1925895Syz147064 
1935895Syz147064 	/*
1945895Syz147064 	 * callback to validate link property value, set to NULL if pd_optval
1955895Syz147064 	 * is not NULL. In that case, validate the value by comparing it with
1965895Syz147064 	 * the pd_optval. Return a val_desc_t array pointer if the value is
1975895Syz147064 	 * valid.
1985895Syz147064 	 */
1995895Syz147064 	pd_checkf_t		*pd_check;
2005895Syz147064 
2015895Syz147064 	uint_t			pd_flags;
2025903Ssowmini #define	PD_TEMPONLY	0x1	/* property is temporary only */
2035903Ssowmini #define	PD_CHECK_ALLOC	0x2	/* alloc vd_val as part of pd_check */
2045895Syz147064 	/*
2055895Syz147064 	 * indicate link classes this property applies to.
2065895Syz147064 	 */
2075895Syz147064 	datalink_class_t	pd_class;
2085895Syz147064 
2095895Syz147064 	/*
2105895Syz147064 	 * indicate link media type this property applies to.
2115895Syz147064 	 */
2125895Syz147064 	datalink_media_t	pd_dmedia;
213*8275SEric Cheng };
2143448Sdh155122 
2156789Sam223141 #define	MAC_PROP_BUFSIZE(v)	sizeof (dld_ioc_macprop_t) + (v) - 1
2165903Ssowmini 
2177663SSowmini.Varadhan@Sun.COM /*
2187663SSowmini.Varadhan@Sun.COM  * Supported link properties enumerated in the prop_table[] array are
2197663SSowmini.Varadhan@Sun.COM  * computed using the callback functions in that array. To compute the
2207663SSowmini.Varadhan@Sun.COM  * property value, multiple distinct system calls may be needed (e.g.,
2217663SSowmini.Varadhan@Sun.COM  * for wifi speed, we need to issue system calls to get desired/supported
2227663SSowmini.Varadhan@Sun.COM  * rates). The link_attr[] table enumerates the interfaces to the kernel,
2237663SSowmini.Varadhan@Sun.COM  * and the type/size of the data passed in the user-kernel interface.
2247663SSowmini.Varadhan@Sun.COM  */
2257663SSowmini.Varadhan@Sun.COM static link_attr_t link_attr[] = {
2267663SSowmini.Varadhan@Sun.COM 	{ MAC_PROP_DUPLEX,	sizeof (link_duplex_t),	"duplex"},
2275903Ssowmini 
2287663SSowmini.Varadhan@Sun.COM 	{ MAC_PROP_SPEED,	sizeof (uint64_t),	"speed"},
2297663SSowmini.Varadhan@Sun.COM 
2307663SSowmini.Varadhan@Sun.COM 	{ MAC_PROP_STATUS,	sizeof (link_state_t),	"state"},
2317663SSowmini.Varadhan@Sun.COM 
2327663SSowmini.Varadhan@Sun.COM 	{ MAC_PROP_AUTONEG,	sizeof (uint8_t),	"adv_autoneg_cap"},
2335903Ssowmini 
2347663SSowmini.Varadhan@Sun.COM 	{ MAC_PROP_MTU,		sizeof (uint32_t),	"mtu"},
2355903Ssowmini 
2367663SSowmini.Varadhan@Sun.COM 	{ MAC_PROP_FLOWCTRL,	sizeof (link_flowctrl_t), "flowctrl"},
2377663SSowmini.Varadhan@Sun.COM 
2387663SSowmini.Varadhan@Sun.COM 	{ MAC_PROP_ZONE,	sizeof (dld_ioc_zid_t),	"zone"},
2395903Ssowmini 
2407663SSowmini.Varadhan@Sun.COM 	{ MAC_PROP_AUTOPUSH,	sizeof (struct dlautopush), "autopush"},
2417663SSowmini.Varadhan@Sun.COM 
2427663SSowmini.Varadhan@Sun.COM 	{ MAC_PROP_ADV_1000FDX_CAP, sizeof (uint8_t),	"adv_1000fdx_cap"},
2437663SSowmini.Varadhan@Sun.COM 
2447663SSowmini.Varadhan@Sun.COM 	{ MAC_PROP_EN_1000FDX_CAP, sizeof (uint8_t),	"en_1000fdx_cap"},
2455903Ssowmini 
2467663SSowmini.Varadhan@Sun.COM 	{ MAC_PROP_ADV_1000HDX_CAP, sizeof (uint8_t),	"adv_1000hdx_cap"},
2475903Ssowmini 
2487663SSowmini.Varadhan@Sun.COM 	{ MAC_PROP_EN_1000HDX_CAP, sizeof (uint8_t),	"en_1000hdx_cap"},
2497663SSowmini.Varadhan@Sun.COM 
2507663SSowmini.Varadhan@Sun.COM 	{ MAC_PROP_ADV_100FDX_CAP, sizeof (uint8_t),	"adv_100fdx_cap"},
2517342SAruna.Ramakrishna@Sun.COM 
2527663SSowmini.Varadhan@Sun.COM 	{ MAC_PROP_EN_100FDX_CAP, sizeof (uint8_t),	"en_100fdx_cap"},
2537663SSowmini.Varadhan@Sun.COM 
2547663SSowmini.Varadhan@Sun.COM 	{ MAC_PROP_ADV_100HDX_CAP, sizeof (uint8_t),	"adv_100hdx_cap"},
2557663SSowmini.Varadhan@Sun.COM 
2567663SSowmini.Varadhan@Sun.COM 	{ MAC_PROP_EN_100HDX_CAP, sizeof (uint8_t),	"en_100hdx_cap"},
2577342SAruna.Ramakrishna@Sun.COM 
2587663SSowmini.Varadhan@Sun.COM 	{ MAC_PROP_ADV_10FDX_CAP, sizeof (uint8_t),	"adv_10fdx_cap"},
2597663SSowmini.Varadhan@Sun.COM 
2607663SSowmini.Varadhan@Sun.COM 	{ MAC_PROP_EN_10FDX_CAP, sizeof (uint8_t),	"en_10fdx_cap"},
2615903Ssowmini 
2627663SSowmini.Varadhan@Sun.COM 	{ MAC_PROP_ADV_10HDX_CAP, sizeof (uint8_t),	"adv_10hdx_cap"},
2637663SSowmini.Varadhan@Sun.COM 
2647663SSowmini.Varadhan@Sun.COM 	{ MAC_PROP_EN_10HDX_CAP, sizeof (uint8_t),	"en_10hdx_cap"},
2655903Ssowmini 
2667663SSowmini.Varadhan@Sun.COM 	{ MAC_PROP_WL_ESSID,	sizeof (wl_linkstatus_t), "essid"},
2677663SSowmini.Varadhan@Sun.COM 
2687663SSowmini.Varadhan@Sun.COM 	{ MAC_PROP_WL_BSSID,	sizeof (wl_bssid_t),	"bssid"},
2695903Ssowmini 
2707663SSowmini.Varadhan@Sun.COM 	{ MAC_PROP_WL_BSSTYPE,	sizeof (wl_bss_type_t),	"bsstype"},
2717663SSowmini.Varadhan@Sun.COM 
2727663SSowmini.Varadhan@Sun.COM 	{ MAC_PROP_WL_LINKSTATUS, sizeof (wl_linkstatus_t), "wl_linkstatus"},
2737663SSowmini.Varadhan@Sun.COM 
2747663SSowmini.Varadhan@Sun.COM 	/* wl_rates_t has variable length */
2757663SSowmini.Varadhan@Sun.COM 	{ MAC_PROP_WL_DESIRED_RATES, sizeof (wl_rates_t), "desired_rates"},
2765903Ssowmini 
2777663SSowmini.Varadhan@Sun.COM 	/* wl_rates_t has variable length */
2787663SSowmini.Varadhan@Sun.COM 	{ MAC_PROP_WL_SUPPORTED_RATES, sizeof (wl_rates_t), "supported_rates"},
2797663SSowmini.Varadhan@Sun.COM 
2807663SSowmini.Varadhan@Sun.COM 	{ MAC_PROP_WL_AUTH_MODE, sizeof (wl_authmode_t), "authmode"},
2815903Ssowmini 
2827663SSowmini.Varadhan@Sun.COM 	{ MAC_PROP_WL_ENCRYPTION, sizeof (wl_encryption_t), "encryption"},
2837663SSowmini.Varadhan@Sun.COM 
2847663SSowmini.Varadhan@Sun.COM 	{ MAC_PROP_WL_RSSI,	sizeof (wl_rssi_t),	"signal"},
2855903Ssowmini 
2867663SSowmini.Varadhan@Sun.COM 	{ MAC_PROP_WL_PHY_CONFIG, sizeof (wl_phy_conf_t), "phy_conf"},
2877663SSowmini.Varadhan@Sun.COM 
2887663SSowmini.Varadhan@Sun.COM 	{ MAC_PROP_WL_CAPABILITY, sizeof (wl_capability_t), "capability"},
2895903Ssowmini 
2907663SSowmini.Varadhan@Sun.COM 	{ MAC_PROP_WL_WPA,	sizeof (wl_wpa_t),	"wpa"},
2917663SSowmini.Varadhan@Sun.COM 
2927663SSowmini.Varadhan@Sun.COM 	/*  wl_wpa_ess_t has variable length */
2937663SSowmini.Varadhan@Sun.COM 	{ MAC_PROP_WL_SCANRESULTS, sizeof (wl_wpa_ess_t), "scan_results"},
2945903Ssowmini 
2957663SSowmini.Varadhan@Sun.COM 	{ MAC_PROP_WL_POWER_MODE, sizeof (wl_ps_mode_t), "powermode"},
2967663SSowmini.Varadhan@Sun.COM 
2977663SSowmini.Varadhan@Sun.COM 	{ MAC_PROP_WL_RADIO,	sizeof (dladm_wlan_radio_t), "wl_radio"},
2985903Ssowmini 
2997663SSowmini.Varadhan@Sun.COM 	{ MAC_PROP_WL_ESS_LIST, sizeof (wl_ess_list_t),	"wl_ess_list"},
3007663SSowmini.Varadhan@Sun.COM 
3017663SSowmini.Varadhan@Sun.COM 	{ MAC_PROP_WL_KEY_TAB,	sizeof (wl_wep_key_tab_t), "wl_wep_key"},
3025903Ssowmini 
3037663SSowmini.Varadhan@Sun.COM 	{ MAC_PROP_WL_CREATE_IBSS, sizeof (wl_create_ibss_t), "createibss"},
3047663SSowmini.Varadhan@Sun.COM 
3057663SSowmini.Varadhan@Sun.COM 	/* wl_wpa_ie_t has variable length */
3067663SSowmini.Varadhan@Sun.COM 	{ MAC_PROP_WL_SETOPTIE,	sizeof (wl_wpa_ie_t),	"set_ie"},
3075903Ssowmini 
3087663SSowmini.Varadhan@Sun.COM 	{ MAC_PROP_WL_DELKEY,	sizeof (wl_del_key_t),	"wpa_del_key"},
3097663SSowmini.Varadhan@Sun.COM 
3107663SSowmini.Varadhan@Sun.COM 	{ MAC_PROP_WL_KEY,	sizeof (wl_key_t),	"wl_key"},
3115903Ssowmini 
3127663SSowmini.Varadhan@Sun.COM 	{ MAC_PROP_WL_MLME,	sizeof (wl_mlme_t),	"mlme"},
3137663SSowmini.Varadhan@Sun.COM 
314*8275SEric Cheng 	{ MAC_PROP_MAXBW,	sizeof (mac_resource_props_t),	"maxbw"},
315*8275SEric Cheng 
316*8275SEric Cheng 	{ MAC_PROP_PRIO,	sizeof (mac_resource_props_t),	"priority"},
317*8275SEric Cheng 
318*8275SEric Cheng 	{ MAC_PROP_BIND_CPU,	sizeof (mac_resource_props_t),	"cpus"},
319*8275SEric Cheng 
3207663SSowmini.Varadhan@Sun.COM 	{ MAC_PROP_PRIVATE,	0,			"driver-private"}
321*8275SEric Cheng 
3225903Ssowmini };
3235903Ssowmini 
3245903Ssowmini static  val_desc_t	link_duplex_vals[] = {
3255903Ssowmini 	{ "half", 	LINK_DUPLEX_HALF	},
3265903Ssowmini 	{ "full", 	LINK_DUPLEX_HALF	}
3275903Ssowmini };
3285903Ssowmini static  val_desc_t	link_status_vals[] = {
3295903Ssowmini 	{ "up",		LINK_STATE_UP		},
3305903Ssowmini 	{ "down",	LINK_STATE_DOWN		}
3315903Ssowmini };
3325903Ssowmini static  val_desc_t	link_01_vals[] = {
3335903Ssowmini 	{ "1",		1			},
3345903Ssowmini 	{ "0",		0			}
3355903Ssowmini };
3365903Ssowmini static  val_desc_t	link_flow_vals[] = {
3375903Ssowmini 	{ "no",		LINK_FLOWCTRL_NONE	},
3385903Ssowmini 	{ "tx",		LINK_FLOWCTRL_TX	},
3395903Ssowmini 	{ "rx",		LINK_FLOWCTRL_RX	},
3405903Ssowmini 	{ "bi",		LINK_FLOWCTRL_BI	}
3415903Ssowmini };
342*8275SEric Cheng static  val_desc_t	link_priority_vals[] = {
343*8275SEric Cheng 	{ "low",	MPL_LOW	},
344*8275SEric Cheng 	{ "medium",	MPL_MEDIUM	},
345*8275SEric Cheng 	{ "high",	MPL_HIGH	}
346*8275SEric Cheng };
3475903Ssowmini 
3485895Syz147064 static val_desc_t	dladm_wlan_radio_vals[] = {
3495895Syz147064 	{ "on",		DLADM_WLAN_RADIO_ON	},
3505895Syz147064 	{ "off",	DLADM_WLAN_RADIO_OFF	}
3515895Syz147064 };
3525895Syz147064 
3535895Syz147064 static val_desc_t	dladm_wlan_powermode_vals[] = {
3545895Syz147064 	{ "off",	DLADM_WLAN_PM_OFF	},
3555895Syz147064 	{ "fast",	DLADM_WLAN_PM_FAST	},
3565895Syz147064 	{ "max",	DLADM_WLAN_PM_MAX	}
3575895Syz147064 };
3585895Syz147064 
359*8275SEric Cheng #define	VALCNT(vals)    (sizeof ((vals)) / sizeof (val_desc_t))
360*8275SEric Cheng #define	RESET_VAL	((uintptr_t)-1)
361*8275SEric Cheng 
3623448Sdh155122 static prop_desc_t	prop_table[] = {
3635903Ssowmini 	{ "channel",	{ NULL, 0 },
3645903Ssowmini 	    NULL, 0, NULL, NULL,
3655895Syz147064 	    do_get_channel_prop, NULL, 0,
3665903Ssowmini 	    DATALINK_CLASS_PHYS, DL_WIFI },
3675895Syz147064 
3685895Syz147064 	{ "powermode",	{ "off", DLADM_WLAN_PM_OFF },
3695895Syz147064 	    dladm_wlan_powermode_vals, VALCNT(dladm_wlan_powermode_vals),
3705895Syz147064 	    do_set_powermode_prop, NULL,
3715895Syz147064 	    do_get_powermode_prop, NULL, 0,
3725903Ssowmini 	    DATALINK_CLASS_PHYS, DL_WIFI },
3735895Syz147064 
3745895Syz147064 	{ "radio",	{ "on", DLADM_WLAN_RADIO_ON },
3755895Syz147064 	    dladm_wlan_radio_vals, VALCNT(dladm_wlan_radio_vals),
3765895Syz147064 	    do_set_radio_prop, NULL,
3775895Syz147064 	    do_get_radio_prop, NULL, 0,
3785903Ssowmini 	    DATALINK_CLASS_PHYS, DL_WIFI },
3795895Syz147064 
3805895Syz147064 	{ "speed",	{ "", 0 }, NULL, 0,
3815895Syz147064 	    do_set_rate_prop, do_get_rate_mod,
3825895Syz147064 	    do_get_rate_prop, do_check_rate, 0,
3835960Ssowmini 	    DATALINK_CLASS_PHYS, DATALINK_ANY_MEDIATYPE },
3845895Syz147064 
3856512Ssowmini 	{ "autopush",	{ "", 0 }, NULL, 0,
3867342SAruna.Ramakrishna@Sun.COM 	    i_dladm_set_public_prop, NULL,
3877342SAruna.Ramakrishna@Sun.COM 	    do_get_autopush, do_check_autopush, PD_CHECK_ALLOC,
3885903Ssowmini 	    DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
3895895Syz147064 
3906512Ssowmini 	{ "zone",	{ "", 0 }, NULL, 0,
3913448Sdh155122 	    do_set_zone, NULL,
3927342SAruna.Ramakrishna@Sun.COM 	    do_get_zone, do_check_zone, PD_TEMPONLY|PD_CHECK_ALLOC,
3935903Ssowmini 	    DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
3945903Ssowmini 
395*8275SEric Cheng 	{ "duplex",	{ "", 0 },
3965903Ssowmini 	    link_duplex_vals, VALCNT(link_duplex_vals),
3977342SAruna.Ramakrishna@Sun.COM 	    NULL, NULL, i_dladm_duplex_get, NULL,
3985903Ssowmini 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
3995903Ssowmini 
400*8275SEric Cheng 	{ "state",	{ "up", LINK_STATE_UP },
4015903Ssowmini 	    link_status_vals, VALCNT(link_status_vals),
4027342SAruna.Ramakrishna@Sun.COM 	    NULL, NULL, i_dladm_status_get, NULL,
4036512Ssowmini 	    0, DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
4045903Ssowmini 
4055903Ssowmini 	{ "adv_autoneg_cap", { "1", 1 },
4065903Ssowmini 	    link_01_vals, VALCNT(link_01_vals),
4077342SAruna.Ramakrishna@Sun.COM 	    i_dladm_set_public_prop, NULL, i_dladm_binary_get, NULL,
4085903Ssowmini 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
4095903Ssowmini 
4106512Ssowmini 	{ "mtu", { "", 0 }, NULL, 0,
4117342SAruna.Ramakrishna@Sun.COM 	    i_dladm_set_public_prop, NULL, i_dladm_uint32_get,
4127342SAruna.Ramakrishna@Sun.COM 	    i_dladm_defmtu_check, 0, DATALINK_CLASS_ALL,
4137342SAruna.Ramakrishna@Sun.COM 	    DATALINK_ANY_MEDIATYPE },
4145903Ssowmini 
4156512Ssowmini 	{ "flowctrl", { "", 0 },
4165903Ssowmini 	    link_flow_vals, VALCNT(link_flow_vals),
4177342SAruna.Ramakrishna@Sun.COM 	    i_dladm_set_public_prop, NULL, i_dladm_flowctl_get, NULL,
4185903Ssowmini 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
4195903Ssowmini 
4206512Ssowmini 	{ "adv_1000fdx_cap", { "", 0 },
4216512Ssowmini 	    link_01_vals, VALCNT(link_01_vals),
4227342SAruna.Ramakrishna@Sun.COM 	    NULL, NULL, i_dladm_binary_get, NULL,
4235903Ssowmini 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
4245903Ssowmini 
4256512Ssowmini 	{ "en_1000fdx_cap", { "", 0 },
4265903Ssowmini 	    link_01_vals, VALCNT(link_01_vals),
4277342SAruna.Ramakrishna@Sun.COM 	    i_dladm_set_public_prop, NULL, i_dladm_binary_get, NULL,
4285903Ssowmini 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
4295903Ssowmini 
4306512Ssowmini 	{ "adv_1000hdx_cap", { "", 0 },
4315903Ssowmini 	    link_01_vals, VALCNT(link_01_vals),
4327342SAruna.Ramakrishna@Sun.COM 	    NULL, NULL, i_dladm_binary_get, NULL,
4335903Ssowmini 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
4345903Ssowmini 
4356512Ssowmini 	{ "en_1000hdx_cap", { "", 0 },
4365903Ssowmini 	    link_01_vals, VALCNT(link_01_vals),
4377342SAruna.Ramakrishna@Sun.COM 	    i_dladm_set_public_prop, NULL, i_dladm_binary_get, NULL,
4385903Ssowmini 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
4395903Ssowmini 
4406512Ssowmini 	{ "adv_100fdx_cap", { "", 0 },
4415903Ssowmini 	    link_01_vals, VALCNT(link_01_vals),
4427342SAruna.Ramakrishna@Sun.COM 	    NULL, NULL, i_dladm_binary_get, NULL,
4435903Ssowmini 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
4445903Ssowmini 
4456512Ssowmini 	{ "en_100fdx_cap", { "", 0 },
4465903Ssowmini 	    link_01_vals, VALCNT(link_01_vals),
4477342SAruna.Ramakrishna@Sun.COM 	    i_dladm_set_public_prop, NULL, i_dladm_binary_get, NULL,
4485903Ssowmini 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
4495903Ssowmini 
4506512Ssowmini 	{ "adv_100hdx_cap", { "", 0 },
4515903Ssowmini 	    link_01_vals, VALCNT(link_01_vals),
4527342SAruna.Ramakrishna@Sun.COM 	    NULL, NULL, i_dladm_binary_get, NULL,
4535903Ssowmini 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
4545903Ssowmini 
4556512Ssowmini 	{ "en_100hdx_cap", { "", 0 },
4565903Ssowmini 	    link_01_vals, VALCNT(link_01_vals),
4577342SAruna.Ramakrishna@Sun.COM 	    i_dladm_set_public_prop, NULL, i_dladm_binary_get, NULL,
4585903Ssowmini 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
4595903Ssowmini 
4606512Ssowmini 	{ "adv_10fdx_cap", { "", 0 },
4615903Ssowmini 	    link_01_vals, VALCNT(link_01_vals),
4627342SAruna.Ramakrishna@Sun.COM 	    NULL, NULL, i_dladm_binary_get, NULL,
4635903Ssowmini 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
4645903Ssowmini 
4656512Ssowmini 	{ "en_10fdx_cap", { "", 0 },
4665903Ssowmini 	    link_01_vals, VALCNT(link_01_vals),
4677342SAruna.Ramakrishna@Sun.COM 	    i_dladm_set_public_prop, NULL, i_dladm_binary_get, NULL,
4685903Ssowmini 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
4695903Ssowmini 
4706512Ssowmini 	{ "adv_10hdx_cap", { "", 0 },
4715903Ssowmini 	    link_01_vals, VALCNT(link_01_vals),
4727342SAruna.Ramakrishna@Sun.COM 	    NULL, NULL, i_dladm_binary_get, NULL,
4735903Ssowmini 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
4745903Ssowmini 
4756512Ssowmini 	{ "en_10hdx_cap", { "", 0 },
4765903Ssowmini 	    link_01_vals, VALCNT(link_01_vals),
4777342SAruna.Ramakrishna@Sun.COM 	    i_dladm_set_public_prop, NULL, i_dladm_binary_get, NULL,
478*8275SEric Cheng 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
479*8275SEric Cheng 
480*8275SEric Cheng 	{ "maxbw", { "--", RESET_VAL }, NULL, 0,
481*8275SEric Cheng 	    do_set_res, NULL,
482*8275SEric Cheng 	    dld_maxbw_get, do_check_maxbw, PD_CHECK_ALLOC,
483*8275SEric Cheng 	    DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
484*8275SEric Cheng 
485*8275SEric Cheng 	{ "cpus", { "--", RESET_VAL }, NULL, 0,
486*8275SEric Cheng 	    do_set_cpus, NULL,
487*8275SEric Cheng 	    dld_cpus_get, do_check_cpus, 0,
488*8275SEric Cheng 	    DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
489*8275SEric Cheng 
490*8275SEric Cheng 	{ "priority", { "high", RESET_VAL },
491*8275SEric Cheng 	    link_priority_vals, VALCNT(link_priority_vals), do_set_res, NULL,
492*8275SEric Cheng 	    dld_priority_get, do_check_priority, PD_CHECK_ALLOC,
493*8275SEric Cheng 	    DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
4943448Sdh155122 };
4953448Sdh155122 
4965895Syz147064 #define	DLADM_MAX_PROPS	(sizeof (prop_table) / sizeof (prop_desc_t))
4975895Syz147064 
498*8275SEric Cheng static resource_prop_t rsrc_prop_table[] = {
499*8275SEric Cheng 	{"maxbw",	do_extract_maxbw},
500*8275SEric Cheng 	{"priority",	do_extract_priority},
501*8275SEric Cheng 	{"cpus",	do_extract_cpus}
502*8275SEric Cheng };
503*8275SEric Cheng #define	DLADM_MAX_RSRC_PROP (sizeof (rsrc_prop_table) / \
504*8275SEric Cheng 	sizeof (resource_prop_t))
505*8275SEric Cheng 
5067663SSowmini.Varadhan@Sun.COM /*
5077663SSowmini.Varadhan@Sun.COM  * when retrieving  private properties, we pass down a buffer with
5087663SSowmini.Varadhan@Sun.COM  * DLADM_PROP_BUF_CHUNK of space for the driver to return the property value.
5097663SSowmini.Varadhan@Sun.COM  */
5107663SSowmini.Varadhan@Sun.COM #define	DLADM_PROP_BUF_CHUNK	1024
5117663SSowmini.Varadhan@Sun.COM 
5125895Syz147064 static dladm_status_t	i_dladm_set_linkprop_db(datalink_id_t, const char *,
5135895Syz147064 			    char **, uint_t);
5145895Syz147064 static dladm_status_t	i_dladm_get_linkprop_db(datalink_id_t, const char *,
5155895Syz147064 			    char **, uint_t *);
5165895Syz147064 static dladm_status_t	i_dladm_set_single_prop(datalink_id_t, datalink_class_t,
5175895Syz147064 			    uint32_t, prop_desc_t *, char **, uint_t, uint_t);
5185895Syz147064 static dladm_status_t	i_dladm_set_linkprop(datalink_id_t, const char *,
5195895Syz147064 			    char **, uint_t, uint_t);
5206512Ssowmini static dladm_status_t	i_dladm_getset_defval(prop_desc_t *, datalink_id_t,
5216512Ssowmini 			    datalink_media_t, uint_t);
522*8275SEric Cheng 
523*8275SEric Cheng static dladm_status_t	link_proplist_check(dladm_arg_list_t *);
524*8275SEric Cheng 
5255895Syz147064 /*
5265895Syz147064  * Unfortunately, MAX_SCAN_SUPPORT_RATES is too small to allow all
5275895Syz147064  * rates to be retrieved. However, we cannot increase it at this
5285895Syz147064  * time because it will break binary compatibility with unbundled
5295895Syz147064  * WiFi drivers and utilities. So for now we define an additional
5305895Syz147064  * constant, MAX_SUPPORT_RATES, to allow all rates to be retrieved.
5315895Syz147064  */
5325895Syz147064 #define	MAX_SUPPORT_RATES	64
5335895Syz147064 
5345895Syz147064 #define	AP_ANCHOR	"[anchor]"
5355895Syz147064 #define	AP_DELIMITER	'.'
5365895Syz147064 
5375895Syz147064 static dladm_status_t
5385895Syz147064 do_check_prop(prop_desc_t *pdp, char **prop_val, uint_t val_cnt,
5395895Syz147064     val_desc_t *vdp)
5405895Syz147064 {
5415895Syz147064 	int		i, j;
5425895Syz147064 	dladm_status_t	status = DLADM_STATUS_OK;
5433147Sxc151355 
5445895Syz147064 	for (j = 0; j < val_cnt; j++) {
5455895Syz147064 		for (i = 0; i < pdp->pd_noptval; i++) {
5465895Syz147064 			if (strcasecmp(*prop_val,
5475895Syz147064 			    pdp->pd_optval[i].vd_name) == 0) {
5485895Syz147064 				break;
5495895Syz147064 			}
5505895Syz147064 		}
5515895Syz147064 		if (i == pdp->pd_noptval) {
5525895Syz147064 			status = DLADM_STATUS_BADVAL;
5535895Syz147064 			goto done;
5545895Syz147064 		}
5555895Syz147064 		(void) memcpy(vdp + j, &pdp->pd_optval[i], sizeof (val_desc_t));
5565895Syz147064 	}
5575895Syz147064 
5585895Syz147064 done:
5595895Syz147064 	return (status);
5605895Syz147064 }
5615895Syz147064 
5625895Syz147064 static dladm_status_t
5635895Syz147064 i_dladm_set_single_prop(datalink_id_t linkid, datalink_class_t class,
5645895Syz147064     uint32_t media, prop_desc_t *pdp, char **prop_val, uint_t val_cnt,
5655895Syz147064     uint_t flags)
5663147Sxc151355 {
5675895Syz147064 	dladm_status_t	status = DLADM_STATUS_OK;
5685895Syz147064 	val_desc_t	*vdp = NULL;
5695895Syz147064 	boolean_t	needfree = B_FALSE;
5705895Syz147064 	uint_t		cnt, i;
5713147Sxc151355 
5725895Syz147064 	if (!(pdp->pd_class & class))
5735895Syz147064 		return (DLADM_STATUS_BADARG);
5745895Syz147064 
5755895Syz147064 	if (!DATALINK_MEDIA_ACCEPTED(pdp->pd_dmedia, media))
5763147Sxc151355 		return (DLADM_STATUS_BADARG);
5773147Sxc151355 
5785895Syz147064 	if ((flags & DLADM_OPT_PERSIST) && (pdp->pd_flags & PD_TEMPONLY))
5795895Syz147064 		return (DLADM_STATUS_TEMPONLY);
5805895Syz147064 
5815895Syz147064 	if (!(flags & DLADM_OPT_ACTIVE))
5825895Syz147064 		return (DLADM_STATUS_OK);
5835895Syz147064 
5845895Syz147064 	if (pdp->pd_set == NULL)
5855895Syz147064 		return (DLADM_STATUS_PROPRDONLY);
5863448Sdh155122 
5875895Syz147064 	if (prop_val != NULL) {
5885895Syz147064 		vdp = malloc(sizeof (val_desc_t) * val_cnt);
5895895Syz147064 		if (vdp == NULL)
5905895Syz147064 			return (DLADM_STATUS_NOMEM);
5915895Syz147064 
5925895Syz147064 		if (pdp->pd_check != NULL) {
593*8275SEric Cheng 			needfree = ((pdp->pd_flags & PD_CHECK_ALLOC) != 0);
5945903Ssowmini 			status = pdp->pd_check(pdp, linkid, prop_val, val_cnt,
5955960Ssowmini 			    vdp, media);
5965895Syz147064 		} else if (pdp->pd_optval != NULL) {
5975895Syz147064 			status = do_check_prop(pdp, prop_val, val_cnt, vdp);
5985895Syz147064 		} else {
5993448Sdh155122 			status = DLADM_STATUS_BADARG;
6003147Sxc151355 		}
6015895Syz147064 
6023147Sxc151355 		if (status != DLADM_STATUS_OK)
6035895Syz147064 			goto done;
6045895Syz147064 
6055895Syz147064 		cnt = val_cnt;
6065895Syz147064 	} else {
607*8275SEric Cheng 		boolean_t	defval = B_FALSE;
608*8275SEric Cheng 
6095895Syz147064 		if (pdp->pd_defval.vd_name == NULL)
6105895Syz147064 			return (DLADM_STATUS_NOTSUP);
6115895Syz147064 
6127342SAruna.Ramakrishna@Sun.COM 		cnt = 1;
613*8275SEric Cheng 		defval = (strlen(pdp->pd_defval.vd_name) > 0);
614*8275SEric Cheng 		if ((pdp->pd_flags & PD_CHECK_ALLOC) != 0 || defval) {
6156512Ssowmini 			if ((vdp = malloc(sizeof (val_desc_t))) == NULL)
6166512Ssowmini 				return (DLADM_STATUS_NOMEM);
6177342SAruna.Ramakrishna@Sun.COM 
618*8275SEric Cheng 			if (defval) {
619*8275SEric Cheng 				(void) memcpy(vdp, &pdp->pd_defval,
620*8275SEric Cheng 				    sizeof (val_desc_t));
621*8275SEric Cheng 			} else if (pdp->pd_check != NULL) {
6227342SAruna.Ramakrishna@Sun.COM 				status = pdp->pd_check(pdp, linkid, prop_val,
6237342SAruna.Ramakrishna@Sun.COM 				    cnt, vdp, media);
6247342SAruna.Ramakrishna@Sun.COM 				if (status != DLADM_STATUS_OK)
6257342SAruna.Ramakrishna@Sun.COM 					goto done;
6267342SAruna.Ramakrishna@Sun.COM 			}
6276512Ssowmini 		} else {
6286512Ssowmini 			status = i_dladm_getset_defval(pdp, linkid,
6296512Ssowmini 			    media, flags);
6306512Ssowmini 			return (status);
6316512Ssowmini 		}
6325895Syz147064 	}
6335960Ssowmini 	status = pdp->pd_set(pdp, linkid, vdp, cnt, flags, media);
6345895Syz147064 	if (needfree) {
6355895Syz147064 		for (i = 0; i < cnt; i++)
6365903Ssowmini 			free((void *)((val_desc_t *)vdp + i)->vd_val);
6373147Sxc151355 	}
6385895Syz147064 done:
6395895Syz147064 	free(vdp);
6405895Syz147064 	return (status);
6415895Syz147064 }
6425895Syz147064 
6435895Syz147064 static dladm_status_t
6445895Syz147064 i_dladm_set_linkprop(datalink_id_t linkid, const char *prop_name,
6455895Syz147064     char **prop_val, uint_t val_cnt, uint_t flags)
6465895Syz147064 {
6475895Syz147064 	int			i;
6485895Syz147064 	boolean_t		found = B_FALSE;
6495895Syz147064 	datalink_class_t	class;
6505895Syz147064 	uint32_t		media;
6515895Syz147064 	dladm_status_t		status = DLADM_STATUS_OK;
6525895Syz147064 
6535895Syz147064 	status = dladm_datalink_id2info(linkid, NULL, &class, &media, NULL, 0);
6545895Syz147064 	if (status != DLADM_STATUS_OK)
6555895Syz147064 		return (status);
6565895Syz147064 
6575895Syz147064 	for (i = 0; i < DLADM_MAX_PROPS; i++) {
6585895Syz147064 		prop_desc_t	*pdp = &prop_table[i];
6595895Syz147064 		dladm_status_t	s;
6605895Syz147064 
6615895Syz147064 		if (prop_name != NULL &&
6625895Syz147064 		    (strcasecmp(prop_name, pdp->pd_name) != 0))
6635895Syz147064 			continue;
6645895Syz147064 		found = B_TRUE;
6655895Syz147064 		s = i_dladm_set_single_prop(linkid, class, media, pdp, prop_val,
6665895Syz147064 		    val_cnt, flags);
6673448Sdh155122 
6685895Syz147064 		if (prop_name != NULL) {
6695895Syz147064 			status = s;
6705895Syz147064 			break;
6715895Syz147064 		} else {
6725895Syz147064 			if (s != DLADM_STATUS_OK &&
6735895Syz147064 			    s != DLADM_STATUS_NOTSUP)
6745895Syz147064 				status = s;
6755895Syz147064 		}
6765895Syz147064 	}
6775903Ssowmini 	if (!found) {
6785903Ssowmini 		if (prop_name[0] == '_') {
6795903Ssowmini 			/* other private properties */
6807342SAruna.Ramakrishna@Sun.COM 			status = i_dladm_set_prop(linkid, prop_name, prop_val,
6815903Ssowmini 			    val_cnt, flags);
6825903Ssowmini 		} else  {
6835903Ssowmini 			status = DLADM_STATUS_NOTFOUND;
6845903Ssowmini 		}
6855903Ssowmini 	}
6865895Syz147064 
6875895Syz147064 	return (status);
6885895Syz147064 }
6895895Syz147064 
6905895Syz147064 /*
6915895Syz147064  * Set/reset link property for specific link
6925895Syz147064  */
6935895Syz147064 dladm_status_t
6945895Syz147064 dladm_set_linkprop(datalink_id_t linkid, const char *prop_name, char **prop_val,
6955895Syz147064     uint_t val_cnt, uint_t flags)
6965895Syz147064 {
6975895Syz147064 	dladm_status_t	status = DLADM_STATUS_OK;
6985895Syz147064 
6995895Syz147064 	if ((linkid == DATALINK_INVALID_LINKID) || (flags == 0) ||
7005895Syz147064 	    (prop_val == NULL && val_cnt > 0) ||
7015895Syz147064 	    (prop_val != NULL && val_cnt == 0) ||
7025895Syz147064 	    (prop_name == NULL && prop_val != NULL)) {
7035895Syz147064 		return (DLADM_STATUS_BADARG);
7045895Syz147064 	}
7055895Syz147064 
7065895Syz147064 	status = i_dladm_set_linkprop(linkid, prop_name, prop_val,
7075895Syz147064 	    val_cnt, flags);
7085895Syz147064 	if (status != DLADM_STATUS_OK)
7095895Syz147064 		return (status);
7105895Syz147064 
7115895Syz147064 	if (flags & DLADM_OPT_PERSIST) {
7125895Syz147064 		status = i_dladm_set_linkprop_db(linkid, prop_name,
7133147Sxc151355 		    prop_val, val_cnt);
7143147Sxc151355 	}
7153147Sxc151355 	return (status);
7163147Sxc151355 }
7173147Sxc151355 
7185895Syz147064 /*
7195895Syz147064  * Walk link properties of the given specific link.
7205895Syz147064  */
7213147Sxc151355 dladm_status_t
7225895Syz147064 dladm_walk_linkprop(datalink_id_t linkid, void *arg,
7235895Syz147064     int (*func)(datalink_id_t, const char *, void *))
7243147Sxc151355 {
7255895Syz147064 	dladm_status_t		status;
7265895Syz147064 	datalink_class_t	class;
7275895Syz147064 	uint_t			media;
7285895Syz147064 	int			i;
7295895Syz147064 
7305895Syz147064 	if (linkid == DATALINK_INVALID_LINKID || func == NULL)
7315895Syz147064 		return (DLADM_STATUS_BADARG);
7325895Syz147064 
7335895Syz147064 	status = dladm_datalink_id2info(linkid, NULL, &class, &media, NULL, 0);
7345895Syz147064 	if (status != DLADM_STATUS_OK)
7355895Syz147064 		return (status);
7365895Syz147064 
7375895Syz147064 	for (i = 0; i < DLADM_MAX_PROPS; i++) {
7385895Syz147064 		if (!(prop_table[i].pd_class & class))
7395895Syz147064 			continue;
7405895Syz147064 
7415895Syz147064 		if (!DATALINK_MEDIA_ACCEPTED(prop_table[i].pd_dmedia, media))
7425895Syz147064 			continue;
7435895Syz147064 
7445895Syz147064 		if (func(linkid, prop_table[i].pd_name, arg) ==
7455895Syz147064 		    DLADM_WALK_TERMINATE) {
7465895Syz147064 			break;
7475895Syz147064 		}
7485895Syz147064 	}
7495895Syz147064 
7505895Syz147064 	return (DLADM_STATUS_OK);
7515895Syz147064 }
7523448Sdh155122 
7535895Syz147064 /*
7545895Syz147064  * Get linkprop of the given specific link.
7555895Syz147064  */
7565895Syz147064 dladm_status_t
7575895Syz147064 dladm_get_linkprop(datalink_id_t linkid, dladm_prop_type_t type,
7585895Syz147064     const char *prop_name, char **prop_val, uint_t *val_cntp)
7595895Syz147064 {
7605895Syz147064 	dladm_status_t		status = DLADM_STATUS_OK;
7615895Syz147064 	datalink_class_t	class;
7625895Syz147064 	uint_t			media;
7635895Syz147064 	prop_desc_t		*pdp;
7646512Ssowmini 	uint_t			cnt, dld_flags = 0;
7655895Syz147064 	int			i;
7668118SVasumathi.Sundaram@Sun.COM 	uint_t			perm_flags;
7675895Syz147064 
7686512Ssowmini 	if (type == DLADM_PROP_VAL_DEFAULT)
7696789Sam223141 		dld_flags = MAC_PROP_DEFAULT;
7706512Ssowmini 
7715895Syz147064 	if (linkid == DATALINK_INVALID_LINKID || prop_name == NULL ||
7725895Syz147064 	    prop_val == NULL || val_cntp == NULL || *val_cntp == 0)
7735895Syz147064 		return (DLADM_STATUS_BADARG);
7745895Syz147064 
7755895Syz147064 	for (i = 0; i < DLADM_MAX_PROPS; i++)
7765895Syz147064 		if (strcasecmp(prop_name, prop_table[i].pd_name) == 0)
7775895Syz147064 			break;
7785895Syz147064 
7795903Ssowmini 	if (i == DLADM_MAX_PROPS) {
7805903Ssowmini 		if (prop_name[0] == '_') {
7815903Ssowmini 			/*
7825903Ssowmini 			 * private property.
7835903Ssowmini 			 */
7847342SAruna.Ramakrishna@Sun.COM 			return (i_dladm_get_prop(linkid, prop_name,
7856512Ssowmini 			    prop_val, val_cntp, type, dld_flags));
7865903Ssowmini 		} else {
7875903Ssowmini 			return (DLADM_STATUS_NOTFOUND);
7885903Ssowmini 		}
7895903Ssowmini 	}
7905895Syz147064 
7915895Syz147064 	pdp = &prop_table[i];
7925895Syz147064 
7935895Syz147064 	status = dladm_datalink_id2info(linkid, NULL, &class, &media, NULL, 0);
7945895Syz147064 	if (status != DLADM_STATUS_OK)
7955895Syz147064 		return (status);
7965895Syz147064 
7975895Syz147064 	if (!(pdp->pd_class & class))
7985895Syz147064 		return (DLADM_STATUS_BADARG);
7995895Syz147064 
8005895Syz147064 	if (!DATALINK_MEDIA_ACCEPTED(pdp->pd_dmedia, media))
8013147Sxc151355 		return (DLADM_STATUS_BADARG);
8023147Sxc151355 
8035895Syz147064 	switch (type) {
8045895Syz147064 	case DLADM_PROP_VAL_CURRENT:
8056512Ssowmini 		status = pdp->pd_get(pdp, linkid, prop_val, val_cntp, media,
8068118SVasumathi.Sundaram@Sun.COM 		    dld_flags, &perm_flags);
8078118SVasumathi.Sundaram@Sun.COM 		break;
8088118SVasumathi.Sundaram@Sun.COM 
8098118SVasumathi.Sundaram@Sun.COM 	case DLADM_PROP_VAL_PERM:
8108118SVasumathi.Sundaram@Sun.COM 		if (pdp->pd_set == NULL) {
8118118SVasumathi.Sundaram@Sun.COM 			perm_flags = MAC_PROP_PERM_READ;
8128118SVasumathi.Sundaram@Sun.COM 			*val_cntp = 1;
8138118SVasumathi.Sundaram@Sun.COM 		} else {
8148118SVasumathi.Sundaram@Sun.COM 			status = pdp->pd_get(pdp, linkid, prop_val, val_cntp,
8158118SVasumathi.Sundaram@Sun.COM 			    media, dld_flags, &perm_flags);
8168118SVasumathi.Sundaram@Sun.COM 		}
8178118SVasumathi.Sundaram@Sun.COM 
8188118SVasumathi.Sundaram@Sun.COM 		*prop_val[0] = '\0';
819*8275SEric Cheng 		if (status == DLADM_STATUS_OK)
820*8275SEric Cheng 			(void) dladm_perm2str(perm_flags, *prop_val);
8215895Syz147064 		break;
8225895Syz147064 
8235895Syz147064 	case DLADM_PROP_VAL_DEFAULT:
8246768Sar224390 		/*
8256768Sar224390 		 * If defaults are not defined for the property,
8266768Sar224390 		 * pd_defval.vd_name should be null. If the driver
8276768Sar224390 		 * has to be contacted for the value, vd_name should
8286768Sar224390 		 * be the empty string (""). Otherwise, dladm will
8296768Sar224390 		 * just print whatever is in the table.
8306768Sar224390 		 */
8315895Syz147064 		if (pdp->pd_defval.vd_name == NULL) {
8325895Syz147064 			status = DLADM_STATUS_NOTSUP;
8335895Syz147064 			break;
8345895Syz147064 		}
8356512Ssowmini 
8366512Ssowmini 		if (strlen(pdp->pd_defval.vd_name) == 0) {
8376512Ssowmini 			status = pdp->pd_get(pdp, linkid, prop_val, val_cntp,
8388118SVasumathi.Sundaram@Sun.COM 			    media, dld_flags, &perm_flags);
8396512Ssowmini 		} else {
8406512Ssowmini 			(void) strcpy(*prop_val, pdp->pd_defval.vd_name);
8416512Ssowmini 		}
8425895Syz147064 		*val_cntp = 1;
8435895Syz147064 		break;
8443448Sdh155122 
8455895Syz147064 	case DLADM_PROP_VAL_MODIFIABLE:
8465895Syz147064 		if (pdp->pd_getmod != NULL) {
8475903Ssowmini 			status = pdp->pd_getmod(pdp, linkid, prop_val,
8488118SVasumathi.Sundaram@Sun.COM 			    val_cntp, media, dld_flags, &perm_flags);
8495895Syz147064 			break;
8505895Syz147064 		}
8515895Syz147064 		cnt = pdp->pd_noptval;
8525895Syz147064 		if (cnt == 0) {
8535895Syz147064 			status = DLADM_STATUS_NOTSUP;
8545895Syz147064 		} else if (cnt > *val_cntp) {
8555895Syz147064 			status = DLADM_STATUS_TOOSMALL;
8565895Syz147064 		} else {
8575895Syz147064 			for (i = 0; i < cnt; i++) {
8585895Syz147064 				(void) strcpy(prop_val[i],
8595895Syz147064 				    pdp->pd_optval[i].vd_name);
8605895Syz147064 			}
8615895Syz147064 			*val_cntp = cnt;
8625895Syz147064 		}
8635895Syz147064 		break;
8645895Syz147064 	case DLADM_PROP_VAL_PERSISTENT:
8655895Syz147064 		if (pdp->pd_flags & PD_TEMPONLY)
8665895Syz147064 			return (DLADM_STATUS_TEMPONLY);
8675895Syz147064 		status = i_dladm_get_linkprop_db(linkid, prop_name,
8685895Syz147064 		    prop_val, val_cntp);
8695895Syz147064 		break;
8705895Syz147064 	default:
8715895Syz147064 		status = DLADM_STATUS_BADARG;
8725895Syz147064 		break;
8733147Sxc151355 	}
8743448Sdh155122 
8755895Syz147064 	return (status);
8765895Syz147064 }
8775895Syz147064 
8785895Syz147064 /*ARGSUSED*/
8795895Syz147064 static int
8805895Syz147064 i_dladm_init_one_prop(datalink_id_t linkid, const char *prop_name, void *arg)
8815895Syz147064 {
8825895Syz147064 	char	*buf, **propvals;
8835895Syz147064 	uint_t	i, valcnt = DLADM_MAX_PROP_VALCNT;
8845895Syz147064 
8855895Syz147064 	if ((buf = malloc((sizeof (char *) + DLADM_PROP_VAL_MAX) *
8865895Syz147064 	    DLADM_MAX_PROP_VALCNT)) == NULL) {
8875895Syz147064 		return (DLADM_WALK_CONTINUE);
8885895Syz147064 	}
8895895Syz147064 
8905895Syz147064 	propvals = (char **)(void *)buf;
8915895Syz147064 	for (i = 0; i < valcnt; i++) {
8925895Syz147064 		propvals[i] = buf +
8935895Syz147064 		    sizeof (char *) * DLADM_MAX_PROP_VALCNT +
8945895Syz147064 		    i * DLADM_PROP_VAL_MAX;
8955895Syz147064 	}
8965895Syz147064 
8975895Syz147064 	if (dladm_get_linkprop(linkid, DLADM_PROP_VAL_PERSISTENT, prop_name,
8985895Syz147064 	    propvals, &valcnt) != DLADM_STATUS_OK) {
8995895Syz147064 		goto done;
9005895Syz147064 	}
9015895Syz147064 
9025895Syz147064 	(void) dladm_set_linkprop(linkid, prop_name, propvals, valcnt,
9035895Syz147064 	    DLADM_OPT_ACTIVE);
9045895Syz147064 
9055895Syz147064 done:
9065895Syz147064 	if (buf != NULL)
9075895Syz147064 		free(buf);
9085895Syz147064 
9095895Syz147064 	return (DLADM_WALK_CONTINUE);
9105895Syz147064 }
9115895Syz147064 
9125895Syz147064 /*ARGSUSED*/
9135895Syz147064 static int
9145895Syz147064 i_dladm_init_linkprop(datalink_id_t linkid, void *arg)
9155895Syz147064 {
916*8275SEric Cheng 	datalink_class_t	class;
917*8275SEric Cheng 	dladm_status_t		status;
918*8275SEric Cheng 
919*8275SEric Cheng 	status = dladm_datalink_id2info(linkid, NULL, &class, NULL, NULL, 0);
920*8275SEric Cheng 	if (status != DLADM_STATUS_OK)
921*8275SEric Cheng 		return (DLADM_WALK_TERMINATE);
922*8275SEric Cheng 
923*8275SEric Cheng 	if ((class & (DATALINK_CLASS_VNIC | DATALINK_CLASS_VLAN)) == 0)
924*8275SEric Cheng 		(void) dladm_init_linkprop(linkid, B_TRUE);
925*8275SEric Cheng 
9265895Syz147064 	return (DLADM_WALK_CONTINUE);
9275895Syz147064 }
9285895Syz147064 
9295895Syz147064 dladm_status_t
9306916Sartem dladm_init_linkprop(datalink_id_t linkid, boolean_t any_media)
9315895Syz147064 {
9326916Sartem 	datalink_media_t	dmedia;
9336916Sartem 	uint32_t		media;
9346916Sartem 
9356916Sartem 	dmedia = any_media ? DATALINK_ANY_MEDIATYPE : DL_WIFI;
9366916Sartem 
9375895Syz147064 	if (linkid == DATALINK_ALL_LINKID) {
9385895Syz147064 		(void) dladm_walk_datalink_id(i_dladm_init_linkprop, NULL,
9396916Sartem 		    DATALINK_CLASS_ALL, dmedia, DLADM_OPT_PERSIST);
9406916Sartem 	} else if (any_media || ((dladm_datalink_id2info(linkid, NULL, NULL,
9416916Sartem 	    &media, NULL, 0) == DLADM_STATUS_OK) &&
9426916Sartem 	    DATALINK_MEDIA_ACCEPTED(dmedia, media))) {
9435895Syz147064 		(void) dladm_walk_linkprop(linkid, NULL, i_dladm_init_one_prop);
9443448Sdh155122 	}
9453448Sdh155122 	return (DLADM_STATUS_OK);
9463147Sxc151355 }
9473147Sxc151355 
9485903Ssowmini /* ARGSUSED */
9495895Syz147064 static dladm_status_t
950*8275SEric Cheng do_get_zone(prop_desc_t *pdp, datalink_id_t linkid,
951*8275SEric Cheng     char **prop_val, uint_t *val_cnt, datalink_media_t media,
952*8275SEric Cheng     uint_t flags, uint_t *perm_flags)
9533147Sxc151355 {
954*8275SEric Cheng 	char			zone_name[ZONENAME_MAX];
955*8275SEric Cheng 	zoneid_t		zid;
956*8275SEric Cheng 	dladm_status_t		status;
957*8275SEric Cheng 	char			*cp;
9587342SAruna.Ramakrishna@Sun.COM 	dld_ioc_macprop_t	*dip;
9593147Sxc151355 
9606512Ssowmini 	if (flags != 0)
9616512Ssowmini 		return (DLADM_STATUS_NOTSUP);
9626512Ssowmini 
963*8275SEric Cheng 	dip = i_dladm_get_public_prop(linkid, pdp->pd_name, flags,
964*8275SEric Cheng 	    &status, perm_flags);
9655895Syz147064 	if (status != DLADM_STATUS_OK)
9663448Sdh155122 		return (status);
9673448Sdh155122 
9687342SAruna.Ramakrishna@Sun.COM 	cp = dip->pr_val;
9697342SAruna.Ramakrishna@Sun.COM 	(void) memcpy(&zid, cp, sizeof (zid));
9707342SAruna.Ramakrishna@Sun.COM 	free(dip);
9717342SAruna.Ramakrishna@Sun.COM 
9725895Syz147064 	*val_cnt = 1;
9735895Syz147064 	if (zid != GLOBAL_ZONEID) {
9748118SVasumathi.Sundaram@Sun.COM 		if (getzonenamebyid(zid, zone_name, sizeof (zone_name)) < 0) {
9755895Syz147064 			return (dladm_errno2status(errno));
9768118SVasumathi.Sundaram@Sun.COM 		}
9773147Sxc151355 
9785895Syz147064 		(void) strncpy(*prop_val, zone_name, DLADM_PROP_VAL_MAX);
9793147Sxc151355 	} else {
9805895Syz147064 		*prop_val[0] = '\0';
9813147Sxc151355 	}
9823147Sxc151355 
9833448Sdh155122 	return (DLADM_STATUS_OK);
9843448Sdh155122 }
9853448Sdh155122 
9863448Sdh155122 typedef int (*zone_get_devroot_t)(char *, char *, size_t);
9873448Sdh155122 
9883448Sdh155122 static int
9893448Sdh155122 i_dladm_get_zone_dev(char *zone_name, char *dev, size_t devlen)
9903448Sdh155122 {
9913448Sdh155122 	char			root[MAXPATHLEN];
9923448Sdh155122 	zone_get_devroot_t	real_zone_get_devroot;
9933448Sdh155122 	void			*dlhandle;
9943448Sdh155122 	void			*sym;
9953448Sdh155122 	int			ret;
9963448Sdh155122 
9973448Sdh155122 	if ((dlhandle = dlopen("libzonecfg.so.1", RTLD_LAZY)) == NULL)
9983448Sdh155122 		return (-1);
9993448Sdh155122 
10003448Sdh155122 	if ((sym = dlsym(dlhandle, "zone_get_devroot")) == NULL) {
10013448Sdh155122 		(void) dlclose(dlhandle);
10023448Sdh155122 		return (-1);
10033448Sdh155122 	}
10043448Sdh155122 
10053448Sdh155122 	real_zone_get_devroot = (zone_get_devroot_t)sym;
10063448Sdh155122 
10073448Sdh155122 	if ((ret = real_zone_get_devroot(zone_name, root, sizeof (root))) == 0)
10083448Sdh155122 		(void) snprintf(dev, devlen, "%s%s", root, "/dev");
10093448Sdh155122 	(void) dlclose(dlhandle);
10103448Sdh155122 	return (ret);
10113448Sdh155122 }
10123448Sdh155122 
10133448Sdh155122 static dladm_status_t
10145895Syz147064 i_dladm_update_deventry(zoneid_t zid, datalink_id_t linkid, boolean_t add)
10153448Sdh155122 {
10163448Sdh155122 	char		path[MAXPATHLEN];
10175895Syz147064 	char		name[MAXLINKNAMELEN];
10183448Sdh155122 	di_prof_t	prof = NULL;
10193448Sdh155122 	char		zone_name[ZONENAME_MAX];
10203448Sdh155122 	dladm_status_t	status;
10215895Syz147064 	int		ret;
10223448Sdh155122 
10233448Sdh155122 	if (getzonenamebyid(zid, zone_name, sizeof (zone_name)) < 0)
10243448Sdh155122 		return (dladm_errno2status(errno));
10253448Sdh155122 	if (i_dladm_get_zone_dev(zone_name, path, sizeof (path)) != 0)
10263448Sdh155122 		return (dladm_errno2status(errno));
10273448Sdh155122 	if (di_prof_init(path, &prof) != 0)
10283448Sdh155122 		return (dladm_errno2status(errno));
10293448Sdh155122 
10305895Syz147064 	status = dladm_linkid2legacyname(linkid, name, MAXLINKNAMELEN);
10315895Syz147064 	if (status != DLADM_STATUS_OK)
10325895Syz147064 		goto cleanup;
10335895Syz147064 
10345895Syz147064 	if (add)
10355895Syz147064 		ret = di_prof_add_dev(prof, name);
10365895Syz147064 	else
10375895Syz147064 		ret = di_prof_add_exclude(prof, name);
10385895Syz147064 
10395895Syz147064 	if (ret != 0) {
10403448Sdh155122 		status = dladm_errno2status(errno);
10413448Sdh155122 		goto cleanup;
10423448Sdh155122 	}
10433448Sdh155122 
10443448Sdh155122 	if (di_prof_commit(prof) != 0)
10453448Sdh155122 		status = dladm_errno2status(errno);
10463448Sdh155122 cleanup:
10473448Sdh155122 	if (prof)
10483448Sdh155122 		di_prof_fini(prof);
10493448Sdh155122 
10503448Sdh155122 	return (status);
10513448Sdh155122 }
10523448Sdh155122 
10535903Ssowmini /* ARGSUSED */
10543448Sdh155122 static dladm_status_t
1055*8275SEric Cheng do_set_zone(prop_desc_t *pdp, datalink_id_t linkid, val_desc_t *vdp,
10565960Ssowmini     uint_t val_cnt, uint_t flags, datalink_media_t media)
10573448Sdh155122 {
1058*8275SEric Cheng 	dladm_status_t		status = DLADM_STATUS_OK;
1059*8275SEric Cheng 	zoneid_t		zid_old, zid_new;
1060*8275SEric Cheng 	char			link[MAXLINKNAMELEN];
1061*8275SEric Cheng 	char			*cp;
10627342SAruna.Ramakrishna@Sun.COM 	dld_ioc_macprop_t	*dip;
10637342SAruna.Ramakrishna@Sun.COM 	dld_ioc_zid_t		*dzp;
10643448Sdh155122 
10653448Sdh155122 	if (val_cnt != 1)
10663448Sdh155122 		return (DLADM_STATUS_BADVALCNT);
10673448Sdh155122 
10687342SAruna.Ramakrishna@Sun.COM 	dzp = (dld_ioc_zid_t *)vdp->vd_val;
10697342SAruna.Ramakrishna@Sun.COM 
1070*8275SEric Cheng 	dip = i_dladm_get_public_prop(linkid, pdp->pd_name, flags,
1071*8275SEric Cheng 	    &status, NULL);
1072*8275SEric Cheng 	if (status != DLADM_STATUS_OK)
1073*8275SEric Cheng 		return (status);
1074*8275SEric Cheng 
1075*8275SEric Cheng 	cp = dip->pr_val;
1076*8275SEric Cheng 	(void) memcpy(&zid_old, cp, sizeof (zid_old));
1077*8275SEric Cheng 	free(dip);
10787342SAruna.Ramakrishna@Sun.COM 
10797342SAruna.Ramakrishna@Sun.COM 	zid_new = dzp->diz_zid;
10807342SAruna.Ramakrishna@Sun.COM 	(void) strlcpy(link, dzp->diz_link, MAXLINKNAMELEN);
10813448Sdh155122 
10823448Sdh155122 	/* Do nothing if setting to current value */
10833448Sdh155122 	if (zid_new == zid_old)
10845895Syz147064 		return (status);
10855895Syz147064 
10865895Syz147064 	if (zid_new != GLOBAL_ZONEID) {
10875895Syz147064 		/*
10885895Syz147064 		 * If the new zoneid is the global zone, we could destroy
10895895Syz147064 		 * the link (in the case of an implicitly-created VLAN) as a
10907342SAruna.Ramakrishna@Sun.COM 		 * result of setting the zoneid. In that case, we defer the
10917342SAruna.Ramakrishna@Sun.COM 		 * operation to the end of this function to avoid recreating
10927342SAruna.Ramakrishna@Sun.COM 		 * the VLAN and getting a different linkid during the rollback
10937342SAruna.Ramakrishna@Sun.COM 		 * if other operation fails.
10945895Syz147064 		 *
10957342SAruna.Ramakrishna@Sun.COM 		 * Otherwise, this operation will hold a reference to the
10965895Syz147064 		 * link and prevent a link renaming, so we need to do it
10975895Syz147064 		 * before other operations.
10985895Syz147064 		 */
1099*8275SEric Cheng 		status = i_dladm_set_public_prop(pdp, linkid, vdp, val_cnt,
11007342SAruna.Ramakrishna@Sun.COM 		    flags, media);
11015895Syz147064 		if (status != DLADM_STATUS_OK)
11025895Syz147064 			return (status);
11035895Syz147064 	}
11045895Syz147064 
11053448Sdh155122 	if (zid_old != GLOBAL_ZONEID) {
11065895Syz147064 		if (zone_remove_datalink(zid_old, link) != 0 &&
11073448Sdh155122 		    errno != ENXIO) {
11083448Sdh155122 			status = dladm_errno2status(errno);
11093448Sdh155122 			goto rollback1;
11103448Sdh155122 		}
11113448Sdh155122 
11125895Syz147064 		/*
11135895Syz147064 		 * It is okay to fail to update the /dev entry (some
11145895Syz147064 		 * vanity-named links do not have a /dev entry).
11155895Syz147064 		 */
11165895Syz147064 		(void) i_dladm_update_deventry(zid_old, linkid, B_FALSE);
11175895Syz147064 	}
11185895Syz147064 
11195895Syz147064 	if (zid_new != GLOBAL_ZONEID) {
11205895Syz147064 		if (zone_add_datalink(zid_new, link) != 0) {
11215895Syz147064 			status = dladm_errno2status(errno);
11225895Syz147064 			goto rollback2;
11235895Syz147064 		}
11245895Syz147064 
11255895Syz147064 		(void) i_dladm_update_deventry(zid_new, linkid, B_TRUE);
11265895Syz147064 	} else {
1127*8275SEric Cheng 		status = i_dladm_set_public_prop(pdp, linkid, vdp, val_cnt,
11287342SAruna.Ramakrishna@Sun.COM 		    flags, media);
11293448Sdh155122 		if (status != DLADM_STATUS_OK)
11303448Sdh155122 			goto rollback2;
11313448Sdh155122 	}
11323448Sdh155122 
11333448Sdh155122 	return (DLADM_STATUS_OK);
11343448Sdh155122 
11353448Sdh155122 rollback2:
11363448Sdh155122 	if (zid_old != GLOBAL_ZONEID)
11375895Syz147064 		(void) i_dladm_update_deventry(zid_old, linkid, B_TRUE);
11385895Syz147064 	if (zid_old != GLOBAL_ZONEID)
11395895Syz147064 		(void) zone_add_datalink(zid_old, link);
11403448Sdh155122 rollback1:
11417342SAruna.Ramakrishna@Sun.COM 	if (zid_new != GLOBAL_ZONEID) {
11427342SAruna.Ramakrishna@Sun.COM 		dzp->diz_zid = zid_old;
1143*8275SEric Cheng 		(void) i_dladm_set_public_prop(pdp, linkid, vdp, val_cnt,
11447342SAruna.Ramakrishna@Sun.COM 		    flags, media);
11457342SAruna.Ramakrishna@Sun.COM 	}
11467342SAruna.Ramakrishna@Sun.COM 
11473448Sdh155122 	return (status);
11483448Sdh155122 }
11493448Sdh155122 
11503448Sdh155122 /* ARGSUSED */
11513448Sdh155122 static dladm_status_t
1152*8275SEric Cheng do_check_zone(prop_desc_t *pdp, datalink_id_t linkid, char **prop_val,
11535960Ssowmini     uint_t val_cnt, val_desc_t *vdp, datalink_media_t media)
11543448Sdh155122 {
11557342SAruna.Ramakrishna@Sun.COM 	char		*zone_name;
11567342SAruna.Ramakrishna@Sun.COM 	char		linkname[MAXLINKNAMELEN];
11577342SAruna.Ramakrishna@Sun.COM 	zoneid_t	zoneid;
11587342SAruna.Ramakrishna@Sun.COM 	dladm_status_t	status = DLADM_STATUS_OK;
11597342SAruna.Ramakrishna@Sun.COM 	dld_ioc_zid_t	*dzp;
11603448Sdh155122 
11613448Sdh155122 	if (val_cnt != 1)
11623448Sdh155122 		return (DLADM_STATUS_BADVALCNT);
11633448Sdh155122 
11647342SAruna.Ramakrishna@Sun.COM 	dzp = malloc(sizeof (dld_ioc_zid_t));
11657342SAruna.Ramakrishna@Sun.COM 	if (dzp == NULL)
11667342SAruna.Ramakrishna@Sun.COM 		return (DLADM_STATUS_NOMEM);
11673448Sdh155122 
1168*8275SEric Cheng 	if ((status = dladm_datalink_id2info(linkid, NULL, NULL, NULL,
1169*8275SEric Cheng 	    linkname, MAXLINKNAMELEN)) != DLADM_STATUS_OK) {
1170*8275SEric Cheng 		goto done;
11717342SAruna.Ramakrishna@Sun.COM 	}
11727342SAruna.Ramakrishna@Sun.COM 
1173*8275SEric Cheng 	zone_name = (prop_val != NULL) ? *prop_val : GLOBAL_ZONENAME;
11747342SAruna.Ramakrishna@Sun.COM 	if (strlen(linkname) > MAXLINKNAMELEN) {
11757342SAruna.Ramakrishna@Sun.COM 		status = DLADM_STATUS_BADVAL;
11767342SAruna.Ramakrishna@Sun.COM 		goto done;
11777342SAruna.Ramakrishna@Sun.COM 	}
11787342SAruna.Ramakrishna@Sun.COM 
11797342SAruna.Ramakrishna@Sun.COM 	if ((zoneid = getzoneidbyname(zone_name)) == -1) {
11807342SAruna.Ramakrishna@Sun.COM 		status = DLADM_STATUS_BADVAL;
11817342SAruna.Ramakrishna@Sun.COM 		goto done;
11827342SAruna.Ramakrishna@Sun.COM 	}
11837342SAruna.Ramakrishna@Sun.COM 
11847342SAruna.Ramakrishna@Sun.COM 	if (zoneid != GLOBAL_ZONEID) {
11853448Sdh155122 		ushort_t	flags;
11863448Sdh155122 
11877342SAruna.Ramakrishna@Sun.COM 		if (zone_getattr(zoneid, ZONE_ATTR_FLAGS, &flags,
11883448Sdh155122 		    sizeof (flags)) < 0) {
11897342SAruna.Ramakrishna@Sun.COM 			status = dladm_errno2status(errno);
11907342SAruna.Ramakrishna@Sun.COM 			goto done;
11913448Sdh155122 		}
11923448Sdh155122 
11933448Sdh155122 		if (!(flags & ZF_NET_EXCL)) {
11947342SAruna.Ramakrishna@Sun.COM 			status = DLADM_STATUS_BADVAL;
11957342SAruna.Ramakrishna@Sun.COM 			goto done;
11963448Sdh155122 		}
11973448Sdh155122 	}
11983448Sdh155122 
11997342SAruna.Ramakrishna@Sun.COM 	(void) memset(dzp, 0, sizeof (dld_ioc_zid_t));
12007342SAruna.Ramakrishna@Sun.COM 
12017342SAruna.Ramakrishna@Sun.COM 	dzp->diz_zid = zoneid;
12027342SAruna.Ramakrishna@Sun.COM 	(void) strlcpy(dzp->diz_link, linkname, MAXLINKNAMELEN);
12037342SAruna.Ramakrishna@Sun.COM 
12047342SAruna.Ramakrishna@Sun.COM 	vdp->vd_val = (uintptr_t)dzp;
12055895Syz147064 	return (DLADM_STATUS_OK);
12067342SAruna.Ramakrishna@Sun.COM done:
12077342SAruna.Ramakrishna@Sun.COM 	free(dzp);
12087342SAruna.Ramakrishna@Sun.COM 	return (status);
12095895Syz147064 }
12105895Syz147064 
12115903Ssowmini /* ARGSUSED */
12125895Syz147064 static dladm_status_t
1213*8275SEric Cheng dld_maxbw_get(prop_desc_t *pdp, datalink_id_t linkid,
1214*8275SEric Cheng     char **prop_val, uint_t *val_cnt, datalink_media_t media,
1215*8275SEric Cheng     uint_t flags, uint_t *perm_flags)
1216*8275SEric Cheng {
1217*8275SEric Cheng 	dld_ioc_macprop_t	*dip;
1218*8275SEric Cheng 	mac_resource_props_t	mrp;
1219*8275SEric Cheng 	dladm_status_t		status;
1220*8275SEric Cheng 
1221*8275SEric Cheng 	dip = i_dladm_get_public_prop(linkid, pdp->pd_name, flags,
1222*8275SEric Cheng 	    &status, perm_flags);
1223*8275SEric Cheng 	if (dip == NULL)
1224*8275SEric Cheng 		return (status);
1225*8275SEric Cheng 
1226*8275SEric Cheng 	bcopy(dip->pr_val, &mrp, sizeof (mac_resource_props_t));
1227*8275SEric Cheng 	free(dip);
1228*8275SEric Cheng 
1229*8275SEric Cheng 	if ((mrp.mrp_mask & MRP_MAXBW) == 0) {
1230*8275SEric Cheng 		(*prop_val)[0] = '\0';
1231*8275SEric Cheng 	} else {
1232*8275SEric Cheng 		(void) dladm_bw2str(mrp.mrp_maxbw, prop_val[0]);
1233*8275SEric Cheng 	}
1234*8275SEric Cheng 	*val_cnt = 1;
1235*8275SEric Cheng 	return (DLADM_STATUS_OK);
1236*8275SEric Cheng }
1237*8275SEric Cheng 
1238*8275SEric Cheng /* ARGSUSED */
1239*8275SEric Cheng static dladm_status_t
1240*8275SEric Cheng do_check_maxbw(prop_desc_t *pdp, datalink_id_t linkid, char **prop_val,
1241*8275SEric Cheng     uint_t val_cnt, val_desc_t *vdp, datalink_media_t media)
1242*8275SEric Cheng {
1243*8275SEric Cheng 	uint64_t	*maxbw;
1244*8275SEric Cheng 	dladm_status_t	status = DLADM_STATUS_OK;
1245*8275SEric Cheng 
1246*8275SEric Cheng 	if (val_cnt != 1)
1247*8275SEric Cheng 		return (DLADM_STATUS_BADVALCNT);
1248*8275SEric Cheng 
1249*8275SEric Cheng 	maxbw = malloc(sizeof (uint64_t));
1250*8275SEric Cheng 	if (maxbw == NULL)
1251*8275SEric Cheng 		return (DLADM_STATUS_NOMEM);
1252*8275SEric Cheng 
1253*8275SEric Cheng 	status = dladm_str2bw(*prop_val, maxbw);
1254*8275SEric Cheng 	if (status != DLADM_STATUS_OK) {
1255*8275SEric Cheng 		free(maxbw);
1256*8275SEric Cheng 		return (status);
1257*8275SEric Cheng 	}
1258*8275SEric Cheng 
1259*8275SEric Cheng 	if ((*maxbw < MRP_MAXBW_MINVAL) && (*maxbw != 0)) {
1260*8275SEric Cheng 		free(maxbw);
1261*8275SEric Cheng 		return (DLADM_STATUS_MINMAXBW);
1262*8275SEric Cheng 	}
1263*8275SEric Cheng 
1264*8275SEric Cheng 	vdp->vd_val = (uintptr_t)maxbw;
1265*8275SEric Cheng 	return (DLADM_STATUS_OK);
1266*8275SEric Cheng }
1267*8275SEric Cheng 
1268*8275SEric Cheng /* ARGSUSED */
1269*8275SEric Cheng dladm_status_t
1270*8275SEric Cheng do_extract_maxbw(val_desc_t *vdp, void *arg, uint_t cnt)
1271*8275SEric Cheng {
1272*8275SEric Cheng 	mac_resource_props_t *mrp = (mac_resource_props_t *)arg;
1273*8275SEric Cheng 
1274*8275SEric Cheng 	bcopy((char *)vdp->vd_val, &mrp->mrp_maxbw, sizeof (uint64_t));
1275*8275SEric Cheng 	mrp->mrp_mask |= MRP_MAXBW;
1276*8275SEric Cheng 
1277*8275SEric Cheng 	return (DLADM_STATUS_OK);
1278*8275SEric Cheng }
1279*8275SEric Cheng 
1280*8275SEric Cheng /* ARGSUSED */
1281*8275SEric Cheng static dladm_status_t
1282*8275SEric Cheng dld_cpus_get(prop_desc_t *pdp, datalink_id_t linkid,
1283*8275SEric Cheng     char **prop_val, uint_t *val_cnt, datalink_media_t media,
1284*8275SEric Cheng     uint_t flags, uint_t *perm_flags)
1285*8275SEric Cheng {
1286*8275SEric Cheng 	dld_ioc_macprop_t	*dip;
1287*8275SEric Cheng 	mac_resource_props_t	mrp;
1288*8275SEric Cheng 	int			i;
1289*8275SEric Cheng 	uint32_t		ncpus;
1290*8275SEric Cheng 	uchar_t			*cp;
1291*8275SEric Cheng 	dladm_status_t		status;
1292*8275SEric Cheng 
1293*8275SEric Cheng 	dip = i_dladm_get_public_prop(linkid, pdp->pd_name, flags,
1294*8275SEric Cheng 	    &status, perm_flags);
1295*8275SEric Cheng 	if (dip == NULL)
1296*8275SEric Cheng 		return (status);
1297*8275SEric Cheng 
1298*8275SEric Cheng 	cp = (uchar_t *)dip->pr_val;
1299*8275SEric Cheng 	(void) memcpy(&mrp, cp, sizeof (mac_resource_props_t));
1300*8275SEric Cheng 	free(dip);
1301*8275SEric Cheng 
1302*8275SEric Cheng 	ncpus = mrp.mrp_ncpus;
1303*8275SEric Cheng 
1304*8275SEric Cheng 	if (ncpus > *val_cnt)
1305*8275SEric Cheng 		return (DLADM_STATUS_TOOSMALL);
1306*8275SEric Cheng 
1307*8275SEric Cheng 	if (ncpus == 0) {
1308*8275SEric Cheng 		(*prop_val)[0] = '\0';
1309*8275SEric Cheng 		*val_cnt = 1;
1310*8275SEric Cheng 		return (DLADM_STATUS_OK);
1311*8275SEric Cheng 	}
1312*8275SEric Cheng 
1313*8275SEric Cheng 	*val_cnt = ncpus;
1314*8275SEric Cheng 	for (i = 0; i < ncpus; i++) {
1315*8275SEric Cheng 		(void) snprintf(prop_val[i], DLADM_PROP_VAL_MAX,
1316*8275SEric Cheng 		    "%u", mrp.mrp_cpu[i]);
1317*8275SEric Cheng 	}
1318*8275SEric Cheng 	return (DLADM_STATUS_OK);
1319*8275SEric Cheng }
1320*8275SEric Cheng 
1321*8275SEric Cheng /* ARGSUSED */
1322*8275SEric Cheng static dladm_status_t
1323*8275SEric Cheng do_set_res(prop_desc_t *pdp, datalink_id_t linkid, val_desc_t *vdp,
1324*8275SEric Cheng     uint_t val_cnt, uint_t flags, datalink_media_t media)
1325*8275SEric Cheng {
1326*8275SEric Cheng 	mac_resource_props_t	mrp;
1327*8275SEric Cheng 	dladm_status_t		status = DLADM_STATUS_OK;
1328*8275SEric Cheng 	dld_ioc_macprop_t	*dip;
1329*8275SEric Cheng 
1330*8275SEric Cheng 	bzero(&mrp, sizeof (mac_resource_props_t));
1331*8275SEric Cheng 	dip = i_dladm_buf_alloc_by_name(0, linkid, pdp->pd_name,
1332*8275SEric Cheng 	    flags, &status);
1333*8275SEric Cheng 
1334*8275SEric Cheng 	if (dip == NULL)
1335*8275SEric Cheng 		return (status);
1336*8275SEric Cheng 
1337*8275SEric Cheng 	if (vdp->vd_val == RESET_VAL) {
1338*8275SEric Cheng 		switch (dip->pr_num) {
1339*8275SEric Cheng 		case MAC_PROP_MAXBW:
1340*8275SEric Cheng 			mrp.mrp_maxbw = MRP_MAXBW_RESETVAL;
1341*8275SEric Cheng 			mrp.mrp_mask = MRP_MAXBW;
1342*8275SEric Cheng 			break;
1343*8275SEric Cheng 		case MAC_PROP_PRIO:
1344*8275SEric Cheng 			mrp.mrp_priority = MPL_RESET;
1345*8275SEric Cheng 			mrp.mrp_mask = MRP_PRIORITY;
1346*8275SEric Cheng 			break;
1347*8275SEric Cheng 		default:
1348*8275SEric Cheng 			free(dip);
1349*8275SEric Cheng 			return (DLADM_STATUS_BADARG);
1350*8275SEric Cheng 		}
1351*8275SEric Cheng 	} else {
1352*8275SEric Cheng 		switch (dip->pr_num) {
1353*8275SEric Cheng 		case MAC_PROP_MAXBW:
1354*8275SEric Cheng 			bcopy((void *)vdp->vd_val, &mrp.mrp_maxbw,
1355*8275SEric Cheng 			    sizeof (uint64_t));
1356*8275SEric Cheng 			mrp.mrp_mask = MRP_MAXBW;
1357*8275SEric Cheng 			break;
1358*8275SEric Cheng 		case MAC_PROP_PRIO:
1359*8275SEric Cheng 			bcopy((void *)vdp->vd_val, &mrp.mrp_priority,
1360*8275SEric Cheng 			    sizeof (mac_priority_level_t));
1361*8275SEric Cheng 			mrp.mrp_mask = MRP_PRIORITY;
1362*8275SEric Cheng 			break;
1363*8275SEric Cheng 		default:
1364*8275SEric Cheng 			free(dip);
1365*8275SEric Cheng 			return (DLADM_STATUS_BADARG);
1366*8275SEric Cheng 		}
1367*8275SEric Cheng 	}
1368*8275SEric Cheng 
1369*8275SEric Cheng 	(void) memcpy(dip->pr_val, &mrp, dip->pr_valsize);
1370*8275SEric Cheng 	status = i_dladm_macprop(dip, B_TRUE);
1371*8275SEric Cheng 	free(dip);
1372*8275SEric Cheng 	return (status);
1373*8275SEric Cheng }
1374*8275SEric Cheng 
1375*8275SEric Cheng /* ARGSUSED */
1376*8275SEric Cheng static dladm_status_t
1377*8275SEric Cheng do_set_cpus(prop_desc_t *pdp, datalink_id_t linkid, val_desc_t *vdp,
1378*8275SEric Cheng     uint_t val_cnt, uint_t flags, datalink_media_t media)
1379*8275SEric Cheng {
1380*8275SEric Cheng 	mac_resource_props_t	mrp;
1381*8275SEric Cheng 	dladm_status_t		status;
1382*8275SEric Cheng 	dld_ioc_macprop_t	*dip;
1383*8275SEric Cheng 	datalink_class_t	class;
1384*8275SEric Cheng 
1385*8275SEric Cheng 	/*
1386*8275SEric Cheng 	 * CPU bindings can be set on VNIC and regular physical links.
1387*8275SEric Cheng 	 * However VNICs fails the dladm_phys_info test(). So apply
1388*8275SEric Cheng 	 * the phys_info test only on physical links.
1389*8275SEric Cheng 	 */
1390*8275SEric Cheng 	if ((status = dladm_datalink_id2info(linkid, NULL, &class,
1391*8275SEric Cheng 	    NULL, NULL, 0)) != DLADM_STATUS_OK) {
1392*8275SEric Cheng 		return (status);
1393*8275SEric Cheng 	}
1394*8275SEric Cheng 
1395*8275SEric Cheng 	/*
1396*8275SEric Cheng 	 * We set intr_cpu to -1. The interrupt will be retargetted,
1397*8275SEric Cheng 	 * if possible when the setup is complete in MAC.
1398*8275SEric Cheng 	 */
1399*8275SEric Cheng 	bzero(&mrp, sizeof (mac_resource_props_t));
1400*8275SEric Cheng 	mrp.mrp_mask = MRP_CPUS;
1401*8275SEric Cheng 	if (vdp != NULL && vdp->vd_val != RESET_VAL) {
1402*8275SEric Cheng 		mac_resource_props_t	*vmrp;
1403*8275SEric Cheng 
1404*8275SEric Cheng 		vmrp = (mac_resource_props_t *)vdp->vd_val;
1405*8275SEric Cheng 		if (vmrp->mrp_ncpus > 0) {
1406*8275SEric Cheng 			bcopy(vmrp, &mrp, sizeof (mac_resource_props_t));
1407*8275SEric Cheng 			mrp.mrp_mask = MRP_CPUS;
1408*8275SEric Cheng 		}
1409*8275SEric Cheng 		mrp.mrp_mask |= MRP_CPUS_USERSPEC;
1410*8275SEric Cheng 		mrp.mrp_fanout_mode = MCM_CPUS;
1411*8275SEric Cheng 		mrp.mrp_intr_cpu = -1;
1412*8275SEric Cheng 	}
1413*8275SEric Cheng 
1414*8275SEric Cheng 	dip = i_dladm_buf_alloc_by_name(0, linkid, pdp->pd_name,
1415*8275SEric Cheng 	    flags, &status);
1416*8275SEric Cheng 	if (dip == NULL)
1417*8275SEric Cheng 		return (status);
1418*8275SEric Cheng 
1419*8275SEric Cheng 	(void) memcpy(dip->pr_val, &mrp, dip->pr_valsize);
1420*8275SEric Cheng 	status = i_dladm_macprop(dip, B_TRUE);
1421*8275SEric Cheng 	free(dip);
1422*8275SEric Cheng 	return (status);
1423*8275SEric Cheng }
1424*8275SEric Cheng 
1425*8275SEric Cheng /* ARGSUSED */
1426*8275SEric Cheng static dladm_status_t
1427*8275SEric Cheng do_check_cpus(prop_desc_t *pdp, datalink_id_t linkid, char **prop_val,
1428*8275SEric Cheng     uint_t val_cnt, val_desc_t *vdp, datalink_media_t media)
1429*8275SEric Cheng {
1430*8275SEric Cheng 	uint32_t		cpuid;
1431*8275SEric Cheng 	int			i, j, rc;
1432*8275SEric Cheng 	long			nproc = sysconf(_SC_NPROCESSORS_CONF);
1433*8275SEric Cheng 	mac_resource_props_t	*mrp;
1434*8275SEric Cheng 
1435*8275SEric Cheng 	mrp = malloc(sizeof (mac_resource_props_t));
1436*8275SEric Cheng 	if (mrp == NULL)
1437*8275SEric Cheng 		return (DLADM_STATUS_NOMEM);
1438*8275SEric Cheng 
1439*8275SEric Cheng 	for (i = 0; i < val_cnt; i++) {
1440*8275SEric Cheng 		errno = 0;
1441*8275SEric Cheng 		cpuid = strtol(prop_val[i], (char **)NULL, 10);
1442*8275SEric Cheng 		if (errno != 0 || cpuid >= nproc) {
1443*8275SEric Cheng 			free(mrp);
1444*8275SEric Cheng 			return (DLADM_STATUS_CPUMAX);
1445*8275SEric Cheng 		}
1446*8275SEric Cheng 		rc = p_online(cpuid, P_STATUS);
1447*8275SEric Cheng 		if (rc < 1) {
1448*8275SEric Cheng 			free(mrp);
1449*8275SEric Cheng 			return (DLADM_STATUS_CPUERR);
1450*8275SEric Cheng 		}
1451*8275SEric Cheng 		if (rc != P_ONLINE) {
1452*8275SEric Cheng 			free(mrp);
1453*8275SEric Cheng 			return (DLADM_STATUS_CPUNOTONLINE);
1454*8275SEric Cheng 		}
1455*8275SEric Cheng 		mrp->mrp_cpu[i] = cpuid;
1456*8275SEric Cheng 	}
1457*8275SEric Cheng 	mrp->mrp_ncpus = (uint32_t)val_cnt;
1458*8275SEric Cheng 
1459*8275SEric Cheng 	/* Check for duplicates */
1460*8275SEric Cheng 	for (i = 0; i < val_cnt; i++) {
1461*8275SEric Cheng 		for (j = 0; j < val_cnt; j++) {
1462*8275SEric Cheng 			if (i != j && mrp->mrp_cpu[i] == mrp->mrp_cpu[j]) {
1463*8275SEric Cheng 				free(mrp);
1464*8275SEric Cheng 				return (DLADM_STATUS_BADARG);
1465*8275SEric Cheng 			}
1466*8275SEric Cheng 		}
1467*8275SEric Cheng 	}
1468*8275SEric Cheng 	vdp->vd_val = (uintptr_t)mrp;
1469*8275SEric Cheng 
1470*8275SEric Cheng 	return (DLADM_STATUS_OK);
1471*8275SEric Cheng }
1472*8275SEric Cheng 
1473*8275SEric Cheng /* ARGSUSED */
1474*8275SEric Cheng dladm_status_t
1475*8275SEric Cheng do_extract_cpus(val_desc_t *vdp, void *arg, uint_t cnt)
1476*8275SEric Cheng {
1477*8275SEric Cheng 	mac_resource_props_t	*mrp = (mac_resource_props_t *)arg;
1478*8275SEric Cheng 	mac_resource_props_t	*vmrp = (mac_resource_props_t *)vdp->vd_val;
1479*8275SEric Cheng 	int			i;
1480*8275SEric Cheng 
1481*8275SEric Cheng 	for (i = 0; i < vmrp->mrp_ncpus; i++) {
1482*8275SEric Cheng 		mrp->mrp_cpu[i] = vmrp->mrp_cpu[i];
1483*8275SEric Cheng 	}
1484*8275SEric Cheng 	mrp->mrp_ncpus = vmrp->mrp_ncpus;
1485*8275SEric Cheng 	mrp->mrp_mask |= (MRP_CPUS|MRP_CPUS_USERSPEC);
1486*8275SEric Cheng 	mrp->mrp_fanout_mode = MCM_CPUS;
1487*8275SEric Cheng 
1488*8275SEric Cheng 	return (DLADM_STATUS_OK);
1489*8275SEric Cheng }
1490*8275SEric Cheng 
1491*8275SEric Cheng /* ARGSUSED */
1492*8275SEric Cheng static dladm_status_t
1493*8275SEric Cheng dld_priority_get(prop_desc_t *pdp, datalink_id_t linkid,
1494*8275SEric Cheng     char **prop_val, uint_t *val_cnt, datalink_media_t media,
1495*8275SEric Cheng     uint_t flags, uint_t *perm_flags)
1496*8275SEric Cheng {
1497*8275SEric Cheng 	dld_ioc_macprop_t	*dip;
1498*8275SEric Cheng 	mac_resource_props_t	mrp;
1499*8275SEric Cheng 	mac_priority_level_t	pri;
1500*8275SEric Cheng 	dladm_status_t		status;
1501*8275SEric Cheng 
1502*8275SEric Cheng 	dip = i_dladm_get_public_prop(linkid, pdp->pd_name, flags,
1503*8275SEric Cheng 	    &status, perm_flags);
1504*8275SEric Cheng 	if (dip == NULL)
1505*8275SEric Cheng 		return (status);
1506*8275SEric Cheng 
1507*8275SEric Cheng 	bcopy(dip->pr_val, &mrp, sizeof (mac_resource_props_t));
1508*8275SEric Cheng 	free(dip);
1509*8275SEric Cheng 
1510*8275SEric Cheng 	pri = ((mrp.mrp_mask & MRP_PRIORITY) == 0) ? MPL_HIGH :
1511*8275SEric Cheng 	    mrp.mrp_priority;
1512*8275SEric Cheng 
1513*8275SEric Cheng 	(void) dladm_pri2str(pri, prop_val[0]);
1514*8275SEric Cheng 	*val_cnt = 1;
1515*8275SEric Cheng 	return (DLADM_STATUS_OK);
1516*8275SEric Cheng }
1517*8275SEric Cheng 
1518*8275SEric Cheng /* ARGSUSED */
1519*8275SEric Cheng static dladm_status_t
1520*8275SEric Cheng do_check_priority(prop_desc_t *pdp, datalink_id_t linkid, char **prop_val,
1521*8275SEric Cheng     uint_t val_cnt, val_desc_t *vdp, datalink_media_t media)
1522*8275SEric Cheng {
1523*8275SEric Cheng 	mac_priority_level_t	*pri;
1524*8275SEric Cheng 	dladm_status_t	status = DLADM_STATUS_OK;
1525*8275SEric Cheng 
1526*8275SEric Cheng 	if (val_cnt != 1)
1527*8275SEric Cheng 		return (DLADM_STATUS_BADVALCNT);
1528*8275SEric Cheng 
1529*8275SEric Cheng 	pri = malloc(sizeof (mac_priority_level_t));
1530*8275SEric Cheng 	if (pri == NULL)
1531*8275SEric Cheng 		return (DLADM_STATUS_NOMEM);
1532*8275SEric Cheng 
1533*8275SEric Cheng 	status = dladm_str2pri(*prop_val, pri);
1534*8275SEric Cheng 	if (status != DLADM_STATUS_OK) {
1535*8275SEric Cheng 		free(pri);
1536*8275SEric Cheng 		return (status);
1537*8275SEric Cheng 	}
1538*8275SEric Cheng 
1539*8275SEric Cheng 	if (*pri < MPL_LOW || *pri > MPL_HIGH) {
1540*8275SEric Cheng 		free(pri);
1541*8275SEric Cheng 		return (DLADM_STATUS_BADVAL);
1542*8275SEric Cheng 	}
1543*8275SEric Cheng 
1544*8275SEric Cheng 	vdp->vd_val = (uintptr_t)pri;
1545*8275SEric Cheng 	return (DLADM_STATUS_OK);
1546*8275SEric Cheng }
1547*8275SEric Cheng 
1548*8275SEric Cheng /* ARGSUSED */
1549*8275SEric Cheng dladm_status_t
1550*8275SEric Cheng do_extract_priority(val_desc_t *vdp, void *arg, uint_t cnt)
1551*8275SEric Cheng {
1552*8275SEric Cheng 	mac_resource_props_t *mrp = (mac_resource_props_t *)arg;
1553*8275SEric Cheng 
1554*8275SEric Cheng 	bcopy((char *)vdp->vd_val, &mrp->mrp_priority,
1555*8275SEric Cheng 	    sizeof (mac_priority_level_t));
1556*8275SEric Cheng 	mrp->mrp_mask |= MRP_PRIORITY;
1557*8275SEric Cheng 
1558*8275SEric Cheng 	return (DLADM_STATUS_OK);
1559*8275SEric Cheng }
1560*8275SEric Cheng 
1561*8275SEric Cheng /* ARGSUSED */
1562*8275SEric Cheng static dladm_status_t
1563*8275SEric Cheng do_get_autopush(prop_desc_t *pdp, datalink_id_t linkid,
1564*8275SEric Cheng     char **prop_val, uint_t *val_cnt, datalink_media_t media,
1565*8275SEric Cheng     uint_t flags, uint_t *perm_flags)
15665895Syz147064 {
15677342SAruna.Ramakrishna@Sun.COM 	struct		dlautopush dlap;
15687342SAruna.Ramakrishna@Sun.COM 	int		i, len;
15697342SAruna.Ramakrishna@Sun.COM 	dladm_status_t	status;
15707342SAruna.Ramakrishna@Sun.COM 	dld_ioc_macprop_t	*dip;
15715895Syz147064 
15726789Sam223141 	if (flags & MAC_PROP_DEFAULT)
15737776SSowmini.Varadhan@Sun.COM 		return (DLADM_STATUS_NOTDEFINED);
15746512Ssowmini 
15755895Syz147064 	*val_cnt = 1;
1576*8275SEric Cheng 	dip = i_dladm_get_public_prop(linkid, pdp->pd_name, flags,
1577*8275SEric Cheng 	    &status, perm_flags);
15787342SAruna.Ramakrishna@Sun.COM 	if (dip == NULL) {
15795895Syz147064 		(*prop_val)[0] = '\0';
1580*8275SEric Cheng 		return (DLADM_STATUS_OK);
15815895Syz147064 	}
15827342SAruna.Ramakrishna@Sun.COM 	(void) memcpy(&dlap, dip->pr_val, sizeof (dlap));
15835895Syz147064 
15847342SAruna.Ramakrishna@Sun.COM 	for (i = 0, len = 0; i < dlap.dap_npush; i++) {
15855895Syz147064 		if (i != 0) {
15865895Syz147064 			(void) snprintf(*prop_val + len,
15875895Syz147064 			    DLADM_PROP_VAL_MAX - len, "%c", AP_DELIMITER);
15885895Syz147064 			len += 1;
15895895Syz147064 		}
15905895Syz147064 		(void) snprintf(*prop_val + len, DLADM_PROP_VAL_MAX - len,
15917342SAruna.Ramakrishna@Sun.COM 		    "%s", dlap.dap_aplist[i]);
15927342SAruna.Ramakrishna@Sun.COM 		len += strlen(dlap.dap_aplist[i]);
15937342SAruna.Ramakrishna@Sun.COM 		if (dlap.dap_anchor - 1 == i) {
15945895Syz147064 			(void) snprintf(*prop_val + len,
15955895Syz147064 			    DLADM_PROP_VAL_MAX - len, "%c%s", AP_DELIMITER,
15965895Syz147064 			    AP_ANCHOR);
15975895Syz147064 			len += (strlen(AP_ANCHOR) + 1);
15985895Syz147064 		}
15995895Syz147064 	}
16007342SAruna.Ramakrishna@Sun.COM 	free(dip);
16015895Syz147064 done:
16025895Syz147064 	return (DLADM_STATUS_OK);
16035895Syz147064 }
16045895Syz147064 
16055895Syz147064 /*
16065895Syz147064  * Add the specified module to the dlautopush structure; returns a
16075895Syz147064  * DLADM_STATUS_* code.
16085895Syz147064  */
16095895Syz147064 dladm_status_t
16105895Syz147064 i_dladm_add_ap_module(const char *module, struct dlautopush *dlap)
16115895Syz147064 {
16125895Syz147064 	if ((strlen(module) == 0) || (strlen(module) > FMNAMESZ))
16135895Syz147064 		return (DLADM_STATUS_BADVAL);
16145895Syz147064 
16155895Syz147064 	if (strncasecmp(module, AP_ANCHOR, strlen(AP_ANCHOR)) == 0) {
16165895Syz147064 		/*
16175895Syz147064 		 * We don't allow multiple anchors, and the anchor must
16185895Syz147064 		 * be after at least one module.
16195895Syz147064 		 */
16205895Syz147064 		if (dlap->dap_anchor != 0)
16215895Syz147064 			return (DLADM_STATUS_BADVAL);
16225895Syz147064 		if (dlap->dap_npush == 0)
16235895Syz147064 			return (DLADM_STATUS_BADVAL);
16245895Syz147064 
16255895Syz147064 		dlap->dap_anchor = dlap->dap_npush;
16265895Syz147064 		return (DLADM_STATUS_OK);
16275895Syz147064 	}
16285895Syz147064 	if (dlap->dap_npush > MAXAPUSH)
16295895Syz147064 		return (DLADM_STATUS_BADVALCNT);
16305895Syz147064 
16315895Syz147064 	(void) strlcpy(dlap->dap_aplist[dlap->dap_npush++], module,
16325895Syz147064 	    FMNAMESZ + 1);
16335895Syz147064 
16345895Syz147064 	return (DLADM_STATUS_OK);
16355895Syz147064 }
16365895Syz147064 
16375895Syz147064 /*
16385895Syz147064  * Currently, both '.' and ' '(space) can be used as the delimiters between
16395895Syz147064  * autopush modules. The former is used in dladm set-linkprop, and the
16405895Syz147064  * latter is used in the autopush(1M) file.
16415895Syz147064  */
16425895Syz147064 /* ARGSUSED */
16435895Syz147064 static dladm_status_t
1644*8275SEric Cheng do_check_autopush(prop_desc_t *pdp, datalink_id_t linkid, char **prop_val,
16455960Ssowmini     uint_t val_cnt, val_desc_t *vdp, datalink_media_t media)
16465895Syz147064 {
16475895Syz147064 	char			*module;
16485895Syz147064 	struct dlautopush	*dlap;
16495895Syz147064 	dladm_status_t		status;
16505895Syz147064 	char			val[DLADM_PROP_VAL_MAX];
16515895Syz147064 	char			delimiters[4];
16525895Syz147064 
16535895Syz147064 	if (val_cnt != 1)
16545895Syz147064 		return (DLADM_STATUS_BADVALCNT);
16555895Syz147064 
16567342SAruna.Ramakrishna@Sun.COM 	if (prop_val != NULL) {
16577342SAruna.Ramakrishna@Sun.COM 		dlap = malloc(sizeof (struct dlautopush));
16587342SAruna.Ramakrishna@Sun.COM 		if (dlap == NULL)
16597342SAruna.Ramakrishna@Sun.COM 			return (DLADM_STATUS_NOMEM);
16603448Sdh155122 
16617342SAruna.Ramakrishna@Sun.COM 		(void) memset(dlap, 0, sizeof (struct dlautopush));
16627342SAruna.Ramakrishna@Sun.COM 		(void) snprintf(delimiters, 4, " %c\n", AP_DELIMITER);
16637342SAruna.Ramakrishna@Sun.COM 		bcopy(*prop_val, val, DLADM_PROP_VAL_MAX);
16647342SAruna.Ramakrishna@Sun.COM 		module = strtok(val, delimiters);
16657342SAruna.Ramakrishna@Sun.COM 		while (module != NULL) {
16667342SAruna.Ramakrishna@Sun.COM 			status = i_dladm_add_ap_module(module, dlap);
16677342SAruna.Ramakrishna@Sun.COM 			if (status != DLADM_STATUS_OK)
16687342SAruna.Ramakrishna@Sun.COM 				return (status);
16697342SAruna.Ramakrishna@Sun.COM 			module = strtok(NULL, delimiters);
16707342SAruna.Ramakrishna@Sun.COM 		}
16717342SAruna.Ramakrishna@Sun.COM 
16727342SAruna.Ramakrishna@Sun.COM 		vdp->vd_val = (uintptr_t)dlap;
16737342SAruna.Ramakrishna@Sun.COM 	} else {
16747342SAruna.Ramakrishna@Sun.COM 		vdp->vd_val = 0;
16755895Syz147064 	}
16763448Sdh155122 	return (DLADM_STATUS_OK);
16773448Sdh155122 }
16783448Sdh155122 
16797663SSowmini.Varadhan@Sun.COM #define	WLDP_BUFSIZE (MAX_BUF_LEN - WIFI_BUF_OFFSET)
16807663SSowmini.Varadhan@Sun.COM 
16815903Ssowmini /* ARGSUSED */
16823448Sdh155122 static dladm_status_t
1683*8275SEric Cheng do_get_rate_common(prop_desc_t *pdp, datalink_id_t linkid,
1684*8275SEric Cheng     char **prop_val, uint_t *val_cnt, uint_t id, uint_t *perm_flags)
16853448Sdh155122 {
16865895Syz147064 	wl_rates_t	*wrp;
16875895Syz147064 	uint_t		i;
16885895Syz147064 	dladm_status_t	status = DLADM_STATUS_OK;
16895895Syz147064 
16907663SSowmini.Varadhan@Sun.COM 	wrp = malloc(WLDP_BUFSIZE);
16917663SSowmini.Varadhan@Sun.COM 	if (wrp == NULL)
16927663SSowmini.Varadhan@Sun.COM 		return (DLADM_STATUS_NOMEM);
16935895Syz147064 
16947663SSowmini.Varadhan@Sun.COM 	status = i_dladm_wlan_param(linkid, wrp, id, WLDP_BUFSIZE, B_FALSE);
16955895Syz147064 	if (status != DLADM_STATUS_OK)
16965895Syz147064 		goto done;
16975895Syz147064 
16985895Syz147064 	if (wrp->wl_rates_num > *val_cnt) {
16995895Syz147064 		status = DLADM_STATUS_TOOSMALL;
17005895Syz147064 		goto done;
17015895Syz147064 	}
17025895Syz147064 
17035895Syz147064 	if (wrp->wl_rates_rates[0] == 0) {
17045895Syz147064 		prop_val[0][0] = '\0';
17055895Syz147064 		*val_cnt = 1;
17065895Syz147064 		goto done;
17075895Syz147064 	}
17085895Syz147064 
17095895Syz147064 	for (i = 0; i < wrp->wl_rates_num; i++) {
17105895Syz147064 		(void) snprintf(prop_val[i], DLADM_STRSIZE, "%.*f",
17115895Syz147064 		    wrp->wl_rates_rates[i] % 2,
17125895Syz147064 		    (float)wrp->wl_rates_rates[i] / 2);
17135895Syz147064 	}
17145895Syz147064 	*val_cnt = wrp->wl_rates_num;
1715*8275SEric Cheng 	*perm_flags = MAC_PROP_PERM_RW;
17163448Sdh155122 
17175895Syz147064 done:
17187663SSowmini.Varadhan@Sun.COM 	free(wrp);
17195895Syz147064 	return (status);
17205895Syz147064 }
17215895Syz147064 
17225895Syz147064 static dladm_status_t
1723*8275SEric Cheng do_get_rate_prop(prop_desc_t *pdp, datalink_id_t linkid,
1724*8275SEric Cheng     char **prop_val, uint_t *val_cnt, datalink_media_t media,
1725*8275SEric Cheng     uint_t flags, uint_t *perm_flags)
17265895Syz147064 {
17278118SVasumathi.Sundaram@Sun.COM 	if (media != DL_WIFI) {
1728*8275SEric Cheng 		return (i_dladm_speed_get(pdp, linkid, prop_val,
1729*8275SEric Cheng 		    val_cnt, flags, perm_flags));
17308118SVasumathi.Sundaram@Sun.COM 	}
17315960Ssowmini 
1732*8275SEric Cheng 	return (do_get_rate_common(pdp, linkid, prop_val, val_cnt,
1733*8275SEric Cheng 	    MAC_PROP_WL_DESIRED_RATES, perm_flags));
17345895Syz147064 }
17355895Syz147064 
17366512Ssowmini /* ARGSUSED */
17375895Syz147064 static dladm_status_t
1738*8275SEric Cheng do_get_rate_mod(prop_desc_t *pdp, datalink_id_t linkid,
1739*8275SEric Cheng     char **prop_val, uint_t *val_cnt, datalink_media_t media,
1740*8275SEric Cheng     uint_t flags, uint_t *perm_flags)
17415895Syz147064 {
17425960Ssowmini 	switch (media) {
17435960Ssowmini 	case DL_ETHER:
17446512Ssowmini 		/*
17456512Ssowmini 		 * Speed for ethernet links is unbounded. E.g., 802.11b
17466512Ssowmini 		 * links can have a speed of 5.5 Gbps.
17476512Ssowmini 		 */
17486512Ssowmini 		return (DLADM_STATUS_NOTSUP);
17495960Ssowmini 
17505960Ssowmini 	case DL_WIFI:
1751*8275SEric Cheng 		return (do_get_rate_common(pdp, linkid, prop_val, val_cnt,
1752*8275SEric Cheng 		    MAC_PROP_WL_SUPPORTED_RATES, perm_flags));
17535960Ssowmini 	default:
17545960Ssowmini 		return (DLADM_STATUS_BADARG);
17555960Ssowmini 	}
17565895Syz147064 }
17575895Syz147064 
17585895Syz147064 static dladm_status_t
17595895Syz147064 do_set_rate(datalink_id_t linkid, dladm_wlan_rates_t *rates)
17605895Syz147064 {
17615895Syz147064 	int		i;
17625895Syz147064 	uint_t		len;
17635895Syz147064 	wl_rates_t	*wrp;
17645895Syz147064 	dladm_status_t	status = DLADM_STATUS_OK;
17655895Syz147064 
17667663SSowmini.Varadhan@Sun.COM 	wrp = malloc(WLDP_BUFSIZE);
17677663SSowmini.Varadhan@Sun.COM 	if (wrp == NULL)
17685895Syz147064 		return (DLADM_STATUS_NOMEM);
17695895Syz147064 
17707663SSowmini.Varadhan@Sun.COM 	bzero(wrp, WLDP_BUFSIZE);
17715895Syz147064 	for (i = 0; i < rates->wr_cnt; i++)
17725895Syz147064 		wrp->wl_rates_rates[i] = rates->wr_rates[i];
17735895Syz147064 	wrp->wl_rates_num = rates->wr_cnt;
17745895Syz147064 
17755895Syz147064 	len = offsetof(wl_rates_t, wl_rates_rates) +
17765895Syz147064 	    (rates->wr_cnt * sizeof (char)) + WIFI_BUF_OFFSET;
17777663SSowmini.Varadhan@Sun.COM 	status = i_dladm_wlan_param(linkid, wrp, MAC_PROP_WL_DESIRED_RATES,
17787663SSowmini.Varadhan@Sun.COM 	    len, B_TRUE);
17795895Syz147064 
17807663SSowmini.Varadhan@Sun.COM 	free(wrp);
17815895Syz147064 	return (status);
17825895Syz147064 }
17833448Sdh155122 
17845903Ssowmini /* ARGSUSED */
17855895Syz147064 static dladm_status_t
1786*8275SEric Cheng do_set_rate_prop(prop_desc_t *pdp, datalink_id_t linkid,
17875960Ssowmini     val_desc_t *vdp, uint_t val_cnt, uint_t flags, datalink_media_t media)
17885895Syz147064 {
17895895Syz147064 	dladm_wlan_rates_t	rates;
17905895Syz147064 	dladm_status_t		status;
17915895Syz147064 
17925960Ssowmini 	/*
17935960Ssowmini 	 * can currently set rate on WIFI links only.
17945960Ssowmini 	 */
17955960Ssowmini 	if (media != DL_WIFI)
17965960Ssowmini 		return (DLADM_STATUS_PROPRDONLY);
17975960Ssowmini 
17985895Syz147064 	if (val_cnt != 1)
17995895Syz147064 		return (DLADM_STATUS_BADVALCNT);
18005895Syz147064 
18015895Syz147064 	rates.wr_cnt = 1;
18025895Syz147064 	rates.wr_rates[0] = vdp[0].vd_val;
18035895Syz147064 
18045895Syz147064 	status = do_set_rate(linkid, &rates);
18055895Syz147064 
18065895Syz147064 done:
18075895Syz147064 	return (status);
18085895Syz147064 }
18093448Sdh155122 
18105895Syz147064 /* ARGSUSED */
18115895Syz147064 static dladm_status_t
1812*8275SEric Cheng do_check_rate(prop_desc_t *pdp, datalink_id_t linkid, char **prop_val,
18135960Ssowmini     uint_t val_cnt, val_desc_t *vdp, datalink_media_t media)
18145895Syz147064 {
18155895Syz147064 	int		i;
18165895Syz147064 	uint_t		modval_cnt = MAX_SUPPORT_RATES;
18175895Syz147064 	char		*buf, **modval;
18185895Syz147064 	dladm_status_t	status;
18198118SVasumathi.Sundaram@Sun.COM 	uint_t 		perm_flags;
18205895Syz147064 
18215895Syz147064 	if (val_cnt != 1)
18225895Syz147064 		return (DLADM_STATUS_BADVALCNT);
18235895Syz147064 
18245895Syz147064 	buf = malloc((sizeof (char *) + DLADM_STRSIZE) *
18255895Syz147064 	    MAX_SUPPORT_RATES);
18265895Syz147064 	if (buf == NULL) {
18275895Syz147064 		status = DLADM_STATUS_NOMEM;
18285895Syz147064 		goto done;
18295895Syz147064 	}
18303448Sdh155122 
18315895Syz147064 	modval = (char **)(void *)buf;
18325895Syz147064 	for (i = 0; i < MAX_SUPPORT_RATES; i++) {
18335895Syz147064 		modval[i] = buf + sizeof (char *) * MAX_SUPPORT_RATES +
18345895Syz147064 		    i * DLADM_STRSIZE;
18355895Syz147064 	}
18365895Syz147064 
18378118SVasumathi.Sundaram@Sun.COM 	status = do_get_rate_mod(NULL, linkid, modval, &modval_cnt, media,
18388118SVasumathi.Sundaram@Sun.COM 	    0, &perm_flags);
18395895Syz147064 	if (status != DLADM_STATUS_OK)
18405895Syz147064 		goto done;
18415895Syz147064 
18425895Syz147064 	for (i = 0; i < modval_cnt; i++) {
18435895Syz147064 		if (strcasecmp(*prop_val, modval[i]) == 0) {
18445903Ssowmini 			vdp->vd_val = (uintptr_t)(uint_t)
18455903Ssowmini 			    (atof(*prop_val) * 2);
18465895Syz147064 			status = DLADM_STATUS_OK;
18473448Sdh155122 			break;
18483448Sdh155122 		}
18495895Syz147064 	}
18505895Syz147064 	if (i == modval_cnt)
18515895Syz147064 		status = DLADM_STATUS_BADVAL;
18525895Syz147064 done:
18535895Syz147064 	free(buf);
18545895Syz147064 	return (status);
18555895Syz147064 }
18565895Syz147064 
18575895Syz147064 static dladm_status_t
18587663SSowmini.Varadhan@Sun.COM do_get_phyconf(datalink_id_t linkid, void *buf, int buflen)
18595895Syz147064 {
18607663SSowmini.Varadhan@Sun.COM 	return (i_dladm_wlan_param(linkid, buf, MAC_PROP_WL_PHY_CONFIG,
18617663SSowmini.Varadhan@Sun.COM 	    buflen, B_FALSE));
18625895Syz147064 }
18635895Syz147064 
18645903Ssowmini /* ARGSUSED */
18655895Syz147064 static dladm_status_t
1866*8275SEric Cheng do_get_channel_prop(prop_desc_t *pdp, datalink_id_t linkid,
1867*8275SEric Cheng     char **prop_val, uint_t *val_cnt, datalink_media_t media,
1868*8275SEric Cheng     uint_t flags, uint_t *perm_flags)
18695895Syz147064 {
18705895Syz147064 	uint32_t	channel;
18717663SSowmini.Varadhan@Sun.COM 	char		buf[WLDP_BUFSIZE];
18725895Syz147064 	dladm_status_t	status = DLADM_STATUS_OK;
18737663SSowmini.Varadhan@Sun.COM 	wl_phy_conf_t	wl_phy_conf;
18745895Syz147064 
18757663SSowmini.Varadhan@Sun.COM 	if ((status = do_get_phyconf(linkid, buf, sizeof (buf)))
18767663SSowmini.Varadhan@Sun.COM 	    != DLADM_STATUS_OK)
18775895Syz147064 		goto done;
18785895Syz147064 
18797663SSowmini.Varadhan@Sun.COM 	(void) memcpy(&wl_phy_conf, buf, sizeof (wl_phy_conf));
18807663SSowmini.Varadhan@Sun.COM 	if (!i_dladm_wlan_convert_chan(&wl_phy_conf, &channel)) {
18815895Syz147064 		status = DLADM_STATUS_NOTFOUND;
18825895Syz147064 		goto done;
18835895Syz147064 	}
18845895Syz147064 
18855895Syz147064 	(void) snprintf(*prop_val, DLADM_STRSIZE, "%u", channel);
18865895Syz147064 	*val_cnt = 1;
1887*8275SEric Cheng 	*perm_flags = MAC_PROP_PERM_READ;
18885895Syz147064 done:
18895895Syz147064 	return (status);
18905895Syz147064 }
18915895Syz147064 
18925895Syz147064 static dladm_status_t
18937663SSowmini.Varadhan@Sun.COM do_get_powermode(datalink_id_t linkid, void *buf, int buflen)
18945895Syz147064 {
18957663SSowmini.Varadhan@Sun.COM 	return (i_dladm_wlan_param(linkid, buf, MAC_PROP_WL_POWER_MODE,
18967663SSowmini.Varadhan@Sun.COM 	    buflen, B_FALSE));
18975895Syz147064 }
18985895Syz147064 
18995903Ssowmini /* ARGSUSED */
19005895Syz147064 static dladm_status_t
1901*8275SEric Cheng do_get_powermode_prop(prop_desc_t *pdp, datalink_id_t linkid,
1902*8275SEric Cheng     char **prop_val, uint_t *val_cnt, datalink_media_t media,
1903*8275SEric Cheng     uint_t flags, uint_t *perm_flags)
19045895Syz147064 {
19057663SSowmini.Varadhan@Sun.COM 	wl_ps_mode_t	mode;
19065895Syz147064 	const char	*s;
19077663SSowmini.Varadhan@Sun.COM 	char		buf[WLDP_BUFSIZE];
19085895Syz147064 	dladm_status_t	status = DLADM_STATUS_OK;
19095895Syz147064 
19107663SSowmini.Varadhan@Sun.COM 	if ((status = do_get_powermode(linkid, buf, sizeof (buf)))
19117663SSowmini.Varadhan@Sun.COM 	    != DLADM_STATUS_OK)
19125895Syz147064 		goto done;
19135895Syz147064 
19147663SSowmini.Varadhan@Sun.COM 	(void) memcpy(&mode, buf, sizeof (mode));
19157663SSowmini.Varadhan@Sun.COM 	switch (mode.wl_ps_mode) {
19165895Syz147064 	case WL_PM_AM:
19175895Syz147064 		s = "off";
19185895Syz147064 		break;
19195895Syz147064 	case WL_PM_MPS:
19205895Syz147064 		s = "max";
19215895Syz147064 		break;
19225895Syz147064 	case WL_PM_FAST:
19235895Syz147064 		s = "fast";
19243448Sdh155122 		break;
19253448Sdh155122 	default:
19265895Syz147064 		status = DLADM_STATUS_NOTFOUND;
19275895Syz147064 		goto done;
19285895Syz147064 	}
19295895Syz147064 	(void) snprintf(*prop_val, DLADM_STRSIZE, "%s", s);
19305895Syz147064 	*val_cnt = 1;
1931*8275SEric Cheng 	*perm_flags = MAC_PROP_PERM_RW;
19325895Syz147064 done:
19335895Syz147064 	return (status);
19345895Syz147064 }
19355895Syz147064 
19365895Syz147064 static dladm_status_t
19375895Syz147064 do_set_powermode(datalink_id_t linkid, dladm_wlan_powermode_t *pm)
19385895Syz147064 {
19395895Syz147064 	wl_ps_mode_t    ps_mode;
19405895Syz147064 
19415895Syz147064 	(void) memset(&ps_mode, 0xff, sizeof (ps_mode));
19425895Syz147064 
19435895Syz147064 	switch (*pm) {
19445895Syz147064 	case DLADM_WLAN_PM_OFF:
19455895Syz147064 		ps_mode.wl_ps_mode = WL_PM_AM;
19463448Sdh155122 		break;
19475895Syz147064 	case DLADM_WLAN_PM_MAX:
19485895Syz147064 		ps_mode.wl_ps_mode = WL_PM_MPS;
19495895Syz147064 		break;
19505895Syz147064 	case DLADM_WLAN_PM_FAST:
19515895Syz147064 		ps_mode.wl_ps_mode = WL_PM_FAST;
19525895Syz147064 		break;
19535895Syz147064 	default:
19545895Syz147064 		return (DLADM_STATUS_NOTSUP);
19553448Sdh155122 	}
19567663SSowmini.Varadhan@Sun.COM 	return (i_dladm_wlan_param(linkid, &ps_mode, MAC_PROP_WL_POWER_MODE,
19577663SSowmini.Varadhan@Sun.COM 	    sizeof (ps_mode), B_TRUE));
19585895Syz147064 }
19595895Syz147064 
19605895Syz147064 /* ARGSUSED */
19615895Syz147064 static dladm_status_t
1962*8275SEric Cheng do_set_powermode_prop(prop_desc_t *pdp, datalink_id_t linkid,
19635960Ssowmini     val_desc_t *vdp, uint_t val_cnt, uint_t flags, datalink_media_t media)
19645895Syz147064 {
19655895Syz147064 	dladm_wlan_powermode_t powermode = (dladm_wlan_powermode_t)vdp->vd_val;
19665895Syz147064 	dladm_status_t status;
19675895Syz147064 
19685895Syz147064 	if (val_cnt != 1)
19695895Syz147064 		return (DLADM_STATUS_BADVALCNT);
19705895Syz147064 
19715895Syz147064 	status = do_set_powermode(linkid, &powermode);
19723448Sdh155122 
19733448Sdh155122 	return (status);
19743448Sdh155122 }
19753448Sdh155122 
19763448Sdh155122 static dladm_status_t
19777663SSowmini.Varadhan@Sun.COM do_get_radio(datalink_id_t linkid, void *buf, int buflen)
19783448Sdh155122 {
19797663SSowmini.Varadhan@Sun.COM 	return (i_dladm_wlan_param(linkid, buf, MAC_PROP_WL_RADIO, buflen,
19807663SSowmini.Varadhan@Sun.COM 	    B_FALSE));
19815895Syz147064 }
19823448Sdh155122 
19835903Ssowmini /* ARGSUSED */
19845895Syz147064 static dladm_status_t
1985*8275SEric Cheng do_get_radio_prop(prop_desc_t *pdp, datalink_id_t linkid,
1986*8275SEric Cheng     char **prop_val, uint_t *val_cnt, datalink_media_t media,
1987*8275SEric Cheng     uint_t flags, uint_t *perm_flags)
19885895Syz147064 {
19895895Syz147064 	wl_radio_t	radio;
19905895Syz147064 	const char	*s;
19917663SSowmini.Varadhan@Sun.COM 	char		buf[WLDP_BUFSIZE];
19925895Syz147064 	dladm_status_t	status = DLADM_STATUS_OK;
19933448Sdh155122 
19947663SSowmini.Varadhan@Sun.COM 	if ((status = do_get_radio(linkid, buf, sizeof (buf)))
19957663SSowmini.Varadhan@Sun.COM 	    != DLADM_STATUS_OK)
19965895Syz147064 		goto done;
19973448Sdh155122 
19987663SSowmini.Varadhan@Sun.COM 	(void) memcpy(&radio, buf, sizeof (radio));
19995895Syz147064 	switch (radio) {
20005895Syz147064 	case B_TRUE:
20015895Syz147064 		s = "on";
20025895Syz147064 		break;
20035895Syz147064 	case B_FALSE:
20045895Syz147064 		s = "off";
20055895Syz147064 		break;
20065895Syz147064 	default:
20075895Syz147064 		status = DLADM_STATUS_NOTFOUND;
20085895Syz147064 		goto done;
20095895Syz147064 	}
20105895Syz147064 	(void) snprintf(*prop_val, DLADM_STRSIZE, "%s", s);
20115895Syz147064 	*val_cnt = 1;
2012*8275SEric Cheng 	*perm_flags = MAC_PROP_PERM_RW;
20135895Syz147064 done:
20143448Sdh155122 	return (status);
20153448Sdh155122 }
20163448Sdh155122 
20173448Sdh155122 static dladm_status_t
20185895Syz147064 do_set_radio(datalink_id_t linkid, dladm_wlan_radio_t *radio)
20193448Sdh155122 {
20205895Syz147064 	wl_radio_t r;
20213448Sdh155122 
20225895Syz147064 	switch (*radio) {
20235895Syz147064 	case DLADM_WLAN_RADIO_ON:
20245895Syz147064 		r = B_TRUE;
20255895Syz147064 		break;
20265895Syz147064 	case DLADM_WLAN_RADIO_OFF:
20275895Syz147064 		r = B_FALSE;
20285895Syz147064 		break;
20295895Syz147064 	default:
20305895Syz147064 		return (DLADM_STATUS_NOTSUP);
20315895Syz147064 	}
20327663SSowmini.Varadhan@Sun.COM 	return (i_dladm_wlan_param(linkid, &r, MAC_PROP_WL_RADIO,
20337663SSowmini.Varadhan@Sun.COM 	    sizeof (r), B_TRUE));
20345895Syz147064 }
20353448Sdh155122 
20365895Syz147064 /* ARGSUSED */
20375895Syz147064 static dladm_status_t
2038*8275SEric Cheng do_set_radio_prop(prop_desc_t *pdp, datalink_id_t linkid,
20395960Ssowmini     val_desc_t *vdp, uint_t val_cnt, uint_t fags, datalink_media_t media)
20405895Syz147064 {
20415895Syz147064 	dladm_wlan_radio_t radio = (dladm_wlan_radio_t)vdp->vd_val;
20425895Syz147064 	dladm_status_t status;
20433448Sdh155122 
20445895Syz147064 	if (val_cnt != 1)
20455895Syz147064 		return (DLADM_STATUS_BADVALCNT);
20465895Syz147064 
20475895Syz147064 	status = do_set_radio(linkid, &radio);
20483448Sdh155122 
20493448Sdh155122 	return (status);
20503448Sdh155122 }
20513448Sdh155122 
20525895Syz147064 static dladm_status_t
20535895Syz147064 i_dladm_set_linkprop_db(datalink_id_t linkid, const char *prop_name,
20545895Syz147064     char **prop_val, uint_t val_cnt)
20553448Sdh155122 {
20565895Syz147064 	char		buf[MAXLINELEN];
20575895Syz147064 	int		i;
20585895Syz147064 	dladm_conf_t	conf;
20595895Syz147064 	dladm_status_t	status;
20603448Sdh155122 
20615895Syz147064 	status = dladm_read_conf(linkid, &conf);
20625895Syz147064 	if (status != DLADM_STATUS_OK)
20635895Syz147064 		return (status);
20643448Sdh155122 
20655895Syz147064 	/*
20665895Syz147064 	 * reset case.
20675895Syz147064 	 */
20685895Syz147064 	if (val_cnt == 0) {
20695895Syz147064 		status = dladm_unset_conf_field(conf, prop_name);
20705895Syz147064 		if (status == DLADM_STATUS_OK)
20715895Syz147064 			status = dladm_write_conf(conf);
20725895Syz147064 		goto done;
20735895Syz147064 	}
20743448Sdh155122 
20755895Syz147064 	buf[0] = '\0';
20765895Syz147064 	for (i = 0; i < val_cnt; i++) {
20775895Syz147064 		(void) strlcat(buf, prop_val[i], MAXLINELEN);
20785895Syz147064 		if (i != val_cnt - 1)
20795895Syz147064 			(void) strlcat(buf, ",", MAXLINELEN);
20803448Sdh155122 	}
20813448Sdh155122 
20825895Syz147064 	status = dladm_set_conf_field(conf, prop_name, DLADM_TYPE_STR, buf);
20835895Syz147064 	if (status == DLADM_STATUS_OK)
20845895Syz147064 		status = dladm_write_conf(conf);
20855895Syz147064 
20865895Syz147064 done:
20875895Syz147064 	dladm_destroy_conf(conf);
20885895Syz147064 	return (status);
20893448Sdh155122 }
20905895Syz147064 
20915895Syz147064 static dladm_status_t
20925895Syz147064 i_dladm_get_linkprop_db(datalink_id_t linkid, const char *prop_name,
20935895Syz147064     char **prop_val, uint_t *val_cntp)
20945895Syz147064 {
20955895Syz147064 	char		buf[MAXLINELEN], *str;
20965895Syz147064 	uint_t		cnt = 0;
20975895Syz147064 	dladm_conf_t	conf;
20985895Syz147064 	dladm_status_t	status;
20995895Syz147064 
21005895Syz147064 	status = dladm_read_conf(linkid, &conf);
21015895Syz147064 	if (status != DLADM_STATUS_OK)
21025895Syz147064 		return (status);
21035895Syz147064 
21045895Syz147064 	status = dladm_get_conf_field(conf, prop_name, buf, MAXLINELEN);
21055895Syz147064 	if (status != DLADM_STATUS_OK)
21065895Syz147064 		goto done;
21075895Syz147064 
21085895Syz147064 	str = strtok(buf, ",");
21095895Syz147064 	while (str != NULL) {
21105895Syz147064 		if (cnt == *val_cntp) {
21115895Syz147064 			status = DLADM_STATUS_TOOSMALL;
21125895Syz147064 			goto done;
21135895Syz147064 		}
21145895Syz147064 		(void) strlcpy(prop_val[cnt++], str, DLADM_PROP_VAL_MAX);
21155895Syz147064 		str = strtok(NULL, ",");
21165895Syz147064 	}
21175895Syz147064 
21185895Syz147064 	*val_cntp = cnt;
21195895Syz147064 
21205895Syz147064 done:
21215895Syz147064 	dladm_destroy_conf(conf);
21225895Syz147064 	return (status);
21235895Syz147064 }
21245903Ssowmini 
21257663SSowmini.Varadhan@Sun.COM static link_attr_t *
21265903Ssowmini dladm_name2prop(const char *prop_name)
21275903Ssowmini {
21287663SSowmini.Varadhan@Sun.COM 	link_attr_t *p;
21295903Ssowmini 
21307663SSowmini.Varadhan@Sun.COM 	for (p = link_attr; p->pp_id != MAC_PROP_PRIVATE; p++) {
21315903Ssowmini 		if (strcmp(p->pp_name, prop_name) == 0)
21325903Ssowmini 			break;
21335903Ssowmini 	}
21345903Ssowmini 	return (p);
21355903Ssowmini }
21365903Ssowmini 
21377663SSowmini.Varadhan@Sun.COM static link_attr_t *
21387663SSowmini.Varadhan@Sun.COM dladm_id2prop(mac_prop_id_t propid)
21397663SSowmini.Varadhan@Sun.COM {
21407663SSowmini.Varadhan@Sun.COM 	link_attr_t *p;
21417663SSowmini.Varadhan@Sun.COM 
21427663SSowmini.Varadhan@Sun.COM 	for (p = link_attr; p->pp_id != MAC_PROP_PRIVATE; p++) {
21437663SSowmini.Varadhan@Sun.COM 		if (p->pp_id == propid)
21447663SSowmini.Varadhan@Sun.COM 			break;
21457663SSowmini.Varadhan@Sun.COM 	}
21467663SSowmini.Varadhan@Sun.COM 	return (p);
21477663SSowmini.Varadhan@Sun.COM }
21485903Ssowmini 
21496789Sam223141 static dld_ioc_macprop_t *
21507663SSowmini.Varadhan@Sun.COM i_dladm_buf_alloc_impl(size_t valsize, datalink_id_t linkid,
21517663SSowmini.Varadhan@Sun.COM     const char *prop_name, mac_prop_id_t propid, uint_t flags,
21527663SSowmini.Varadhan@Sun.COM     dladm_status_t *status)
21535903Ssowmini {
21545903Ssowmini 	int dsize;
21556789Sam223141 	dld_ioc_macprop_t *dip;
21565903Ssowmini 
21575903Ssowmini 	*status = DLADM_STATUS_OK;
21586789Sam223141 	dsize = MAC_PROP_BUFSIZE(valsize);
21595903Ssowmini 	dip = malloc(dsize);
21605903Ssowmini 	if (dip == NULL) {
21615903Ssowmini 		*status = DLADM_STATUS_NOMEM;
21625903Ssowmini 		return (NULL);
21635903Ssowmini 	}
21645903Ssowmini 	bzero(dip, dsize);
21655903Ssowmini 	dip->pr_valsize = valsize;
21666512Ssowmini 	(void) strlcpy(dip->pr_name, prop_name, sizeof (dip->pr_name));
21676789Sam223141 	dip->pr_version = MAC_PROP_VERSION;
21685960Ssowmini 	dip->pr_linkid = linkid;
21697663SSowmini.Varadhan@Sun.COM 	dip->pr_num = propid;
21706512Ssowmini 	dip->pr_flags = flags;
21715903Ssowmini 	return (dip);
21725903Ssowmini }
21735903Ssowmini 
21747663SSowmini.Varadhan@Sun.COM static dld_ioc_macprop_t *
21757663SSowmini.Varadhan@Sun.COM i_dladm_buf_alloc_by_name(size_t valsize, datalink_id_t linkid,
21767663SSowmini.Varadhan@Sun.COM     const char *prop_name, uint_t flags, dladm_status_t *status)
21777663SSowmini.Varadhan@Sun.COM {
21787663SSowmini.Varadhan@Sun.COM 	link_attr_t *p;
21797663SSowmini.Varadhan@Sun.COM 
21807663SSowmini.Varadhan@Sun.COM 	p = dladm_name2prop(prop_name);
21817663SSowmini.Varadhan@Sun.COM 	valsize = MAX(p->pp_valsize, valsize);
21827663SSowmini.Varadhan@Sun.COM 	return (i_dladm_buf_alloc_impl(valsize, linkid, prop_name, p->pp_id,
21837663SSowmini.Varadhan@Sun.COM 	    flags, status));
21847663SSowmini.Varadhan@Sun.COM }
21857663SSowmini.Varadhan@Sun.COM 
21867663SSowmini.Varadhan@Sun.COM static dld_ioc_macprop_t *
21877663SSowmini.Varadhan@Sun.COM i_dladm_buf_alloc_by_id(size_t valsize, datalink_id_t linkid,
21887663SSowmini.Varadhan@Sun.COM     mac_prop_id_t propid, uint_t flags, dladm_status_t *status)
21897663SSowmini.Varadhan@Sun.COM {
21907663SSowmini.Varadhan@Sun.COM 	link_attr_t *p;
21917663SSowmini.Varadhan@Sun.COM 
21927663SSowmini.Varadhan@Sun.COM 	p = dladm_id2prop(propid);
21937663SSowmini.Varadhan@Sun.COM 	valsize = MAX(p->pp_valsize, valsize);
21947663SSowmini.Varadhan@Sun.COM 	return (i_dladm_buf_alloc_impl(valsize, linkid, p->pp_name, propid,
21957663SSowmini.Varadhan@Sun.COM 	    flags, status));
21967663SSowmini.Varadhan@Sun.COM }
21977663SSowmini.Varadhan@Sun.COM 
21985903Ssowmini /* ARGSUSED */
21995903Ssowmini static dladm_status_t
2200*8275SEric Cheng i_dladm_set_public_prop(prop_desc_t *pdp, datalink_id_t linkid,
22015960Ssowmini     val_desc_t *vdp, uint_t val_cnt, uint_t flags, datalink_media_t media)
22025903Ssowmini {
22036789Sam223141 	dld_ioc_macprop_t	*dip;
22045903Ssowmini 	dladm_status_t	status = DLADM_STATUS_OK;
22055903Ssowmini 	uint8_t		u8;
22065903Ssowmini 	uint16_t	u16;
22075903Ssowmini 	uint32_t	u32;
22085903Ssowmini 	void		*val;
22095903Ssowmini 
2210*8275SEric Cheng 	dip = i_dladm_buf_alloc_by_name(0, linkid, pdp->pd_name, 0, &status);
22115903Ssowmini 	if (dip == NULL)
22125903Ssowmini 		return (status);
22135903Ssowmini 
2214*8275SEric Cheng 	if (pdp->pd_flags & PD_CHECK_ALLOC)
22155903Ssowmini 		val = (void *)vdp->vd_val;
22165903Ssowmini 	else {
22175903Ssowmini 		/*
22185903Ssowmini 		 * Currently all 1/2/4-byte size properties are byte/word/int.
22195903Ssowmini 		 * No need (yet) to distinguish these from arrays of same size.
22205903Ssowmini 		 */
22215903Ssowmini 		switch (dip->pr_valsize) {
22225903Ssowmini 		case 1:
22235903Ssowmini 			u8 = vdp->vd_val;
22245903Ssowmini 			val = &u8;
22255903Ssowmini 			break;
22265903Ssowmini 		case 2:
22275903Ssowmini 			u16 = vdp->vd_val;
22285903Ssowmini 			val = &u16;
22295903Ssowmini 			break;
22305903Ssowmini 		case 4:
22315903Ssowmini 			u32 = vdp->vd_val;
22325903Ssowmini 			val = &u32;
22335903Ssowmini 			break;
22345903Ssowmini 		default:
22355903Ssowmini 			val = &vdp->vd_val;
22365903Ssowmini 			break;
22375903Ssowmini 		}
22385903Ssowmini 	}
22395903Ssowmini 
22407342SAruna.Ramakrishna@Sun.COM 	if (val != NULL)
22417342SAruna.Ramakrishna@Sun.COM 		(void) memcpy(dip->pr_val, val, dip->pr_valsize);
22427342SAruna.Ramakrishna@Sun.COM 	else
22437342SAruna.Ramakrishna@Sun.COM 		dip->pr_valsize = 0;
22447342SAruna.Ramakrishna@Sun.COM 
22457663SSowmini.Varadhan@Sun.COM 	status = i_dladm_macprop(dip, B_TRUE);
22467663SSowmini.Varadhan@Sun.COM 
22477663SSowmini.Varadhan@Sun.COM done:
22487663SSowmini.Varadhan@Sun.COM 	free(dip);
22497663SSowmini.Varadhan@Sun.COM 	return (status);
22507663SSowmini.Varadhan@Sun.COM }
22517663SSowmini.Varadhan@Sun.COM 
22527663SSowmini.Varadhan@Sun.COM dladm_status_t
22537663SSowmini.Varadhan@Sun.COM i_dladm_macprop(void *dip, boolean_t set)
22547663SSowmini.Varadhan@Sun.COM {
22557663SSowmini.Varadhan@Sun.COM 	int fd;
22567663SSowmini.Varadhan@Sun.COM 	dladm_status_t status = DLADM_STATUS_OK;
22577663SSowmini.Varadhan@Sun.COM 
22585903Ssowmini 	if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) {
22595903Ssowmini 		status = dladm_errno2status(errno);
22607663SSowmini.Varadhan@Sun.COM 		return (status);
22615903Ssowmini 	}
22627663SSowmini.Varadhan@Sun.COM 	if (ioctl(fd, (set ? DLDIOC_SETMACPROP : DLDIOC_GETMACPROP), dip))
22635903Ssowmini 		status = dladm_errno2status(errno);
22645903Ssowmini 
22655903Ssowmini 	(void) close(fd);
22665903Ssowmini 	return (status);
22675903Ssowmini }
22685903Ssowmini 
22696789Sam223141 static dld_ioc_macprop_t *
22707342SAruna.Ramakrishna@Sun.COM i_dladm_get_public_prop(datalink_id_t linkid, char *prop_name, uint_t flags,
2271*8275SEric Cheng     dladm_status_t *status, uint_t *perm_flags)
22725903Ssowmini {
22736789Sam223141 	dld_ioc_macprop_t *dip = NULL;
22746512Ssowmini 
22757663SSowmini.Varadhan@Sun.COM 	dip = i_dladm_buf_alloc_by_name(0, linkid, prop_name, flags, status);
22766512Ssowmini 	if (dip == NULL)
22776512Ssowmini 		return (NULL);
22785903Ssowmini 
22797663SSowmini.Varadhan@Sun.COM 	*status = i_dladm_macprop(dip, B_FALSE);
22806512Ssowmini 	if (*status != DLADM_STATUS_OK) {
22816512Ssowmini 		free(dip);
22826512Ssowmini 		return (NULL);
22836512Ssowmini 	}
2284*8275SEric Cheng 	if (perm_flags != NULL)
2285*8275SEric Cheng 		*perm_flags = dip->pr_perm_flags;
2286*8275SEric Cheng 
22876512Ssowmini 	return (dip);
22885903Ssowmini }
22895903Ssowmini 
22905903Ssowmini /* ARGSUSED */
22915903Ssowmini static dladm_status_t
2292*8275SEric Cheng i_dladm_defmtu_check(prop_desc_t *pdp, datalink_id_t linkid,
22937342SAruna.Ramakrishna@Sun.COM     char **prop_val, uint_t val_cnt, val_desc_t *v, datalink_media_t media)
22945903Ssowmini {
22955903Ssowmini 	if (val_cnt != 1)
22965903Ssowmini 		return (DLADM_STATUS_BADVAL);
22976512Ssowmini 	v->vd_val = atoi(prop_val[0]);
22985903Ssowmini 	return (DLADM_STATUS_OK);
22995903Ssowmini }
23005903Ssowmini 
23015903Ssowmini /* ARGSUSED */
23025903Ssowmini static dladm_status_t
2303*8275SEric Cheng i_dladm_duplex_get(prop_desc_t *pdp, datalink_id_t linkid,
2304*8275SEric Cheng     char **prop_val, uint_t *val_cnt, datalink_media_t media,
2305*8275SEric Cheng     uint_t flags, uint_t *perm_flags)
23065903Ssowmini {
23075903Ssowmini 	link_duplex_t   link_duplex;
23085903Ssowmini 	dladm_status_t  status;
23095903Ssowmini 
23105903Ssowmini 	if ((status = dladm_get_single_mac_stat(linkid, "link_duplex",
23115903Ssowmini 	    KSTAT_DATA_UINT32, &link_duplex)) != 0)
23125903Ssowmini 		return (status);
23135903Ssowmini 
23145903Ssowmini 	switch (link_duplex) {
23155903Ssowmini 	case LINK_DUPLEX_FULL:
23165903Ssowmini 		(void) strcpy(*prop_val, "full");
23175903Ssowmini 		break;
23185903Ssowmini 	case LINK_DUPLEX_HALF:
23195903Ssowmini 		(void) strcpy(*prop_val, "half");
23205903Ssowmini 		break;
23215903Ssowmini 	default:
23225903Ssowmini 		(void) strcpy(*prop_val, "unknown");
23235903Ssowmini 		break;
23245903Ssowmini 	}
23255903Ssowmini 	*val_cnt = 1;
23265903Ssowmini 	return (DLADM_STATUS_OK);
23275903Ssowmini }
23285903Ssowmini 
23295903Ssowmini /* ARGSUSED */
23305903Ssowmini static dladm_status_t
2331*8275SEric Cheng i_dladm_speed_get(prop_desc_t *pdp, datalink_id_t linkid,
2332*8275SEric Cheng     char **prop_val, uint_t *val_cnt, uint_t flags, uint_t *perm_flags)
23335903Ssowmini {
23345903Ssowmini 	uint64_t	ifspeed = 0;
23355903Ssowmini 	dladm_status_t status;
23365903Ssowmini 
23375903Ssowmini 	if ((status = dladm_get_single_mac_stat(linkid, "ifspeed",
23385903Ssowmini 	    KSTAT_DATA_UINT64, &ifspeed)) != 0)
23395903Ssowmini 		return (status);
23406512Ssowmini 
23415960Ssowmini 	if ((ifspeed % 1000000) != 0) {
23425960Ssowmini 		(void) snprintf(*prop_val, DLADM_PROP_VAL_MAX,
23435960Ssowmini 		    "%llf", ifspeed / (float)1000000); /* Mbps */
23445960Ssowmini 	} else {
23455960Ssowmini 		(void) snprintf(*prop_val, DLADM_PROP_VAL_MAX,
23465960Ssowmini 		    "%llu", ifspeed / 1000000); /* Mbps */
23475960Ssowmini 	}
23485903Ssowmini 	*val_cnt = 1;
2349*8275SEric Cheng 	*perm_flags = MAC_PROP_PERM_READ;
23505903Ssowmini 	return (DLADM_STATUS_OK);
23515903Ssowmini }
23525903Ssowmini 
23535903Ssowmini /* ARGSUSED */
23545903Ssowmini static dladm_status_t
2355*8275SEric Cheng i_dladm_status_get(prop_desc_t *pdp, datalink_id_t linkid,
2356*8275SEric Cheng     char **prop_val, uint_t *val_cnt, datalink_media_t media,
2357*8275SEric Cheng     uint_t flags, uint_t *perm_flags)
23585903Ssowmini {
2359*8275SEric Cheng 	link_state_t		link_state;
2360*8275SEric Cheng 	dladm_status_t		status;
2361*8275SEric Cheng 	uchar_t 		*cp;
2362*8275SEric Cheng 	dld_ioc_macprop_t	*dip;
2363*8275SEric Cheng 
2364*8275SEric Cheng 	dip = i_dladm_get_public_prop(linkid, pdp->pd_name, flags,
2365*8275SEric Cheng 	    &status, perm_flags);
23666512Ssowmini 	if (status != DLADM_STATUS_OK)
23675903Ssowmini 		return (status);
2368*8275SEric Cheng 
23696512Ssowmini 	cp = (uchar_t *)dip->pr_val;
23706512Ssowmini 	(void) memcpy(&link_state, cp, sizeof (link_state));
23715903Ssowmini 
23725903Ssowmini 	switch (link_state) {
23735903Ssowmini 	case LINK_STATE_UP:
23745903Ssowmini 		(void) strcpy(*prop_val, "up");
23755903Ssowmini 		break;
23765903Ssowmini 	case LINK_STATE_DOWN:
23775903Ssowmini 		(void) strcpy(*prop_val, "down");
23785903Ssowmini 		break;
23795903Ssowmini 	default:
23805903Ssowmini 		(void) strcpy(*prop_val, "unknown");
23815903Ssowmini 		break;
23825903Ssowmini 	}
23835903Ssowmini 	*val_cnt = 1;
23846512Ssowmini 	free(dip);
23855903Ssowmini 	return (DLADM_STATUS_OK);
23865903Ssowmini }
23875903Ssowmini 
23885903Ssowmini /* ARGSUSED */
23895903Ssowmini static dladm_status_t
2390*8275SEric Cheng i_dladm_binary_get(prop_desc_t *pdp, datalink_id_t linkid,
2391*8275SEric Cheng     char **prop_val, uint_t *val_cnt, datalink_media_t media,
2392*8275SEric Cheng     uint_t flags, uint_t *perm_flags)
23935903Ssowmini {
23946789Sam223141 	dld_ioc_macprop_t *dip;
23955903Ssowmini 	dladm_status_t status;
23965903Ssowmini 
2397*8275SEric Cheng 	dip = i_dladm_get_public_prop(linkid, pdp->pd_name, flags,
2398*8275SEric Cheng 	    &status, perm_flags);
23996512Ssowmini 	if (dip == NULL)
24005903Ssowmini 		return (status);
2401*8275SEric Cheng 
24025903Ssowmini 	(void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "%x", dip->pr_val[0]);
24035903Ssowmini 	free(dip);
24045903Ssowmini 	*val_cnt = 1;
24055903Ssowmini 	return (DLADM_STATUS_OK);
24065903Ssowmini }
24075903Ssowmini 
24085960Ssowmini /* ARGSUSED */
24095903Ssowmini static dladm_status_t
2410*8275SEric Cheng i_dladm_uint32_get(prop_desc_t *pdp, datalink_id_t linkid,
2411*8275SEric Cheng     char **prop_val, uint_t *val_cnt, datalink_media_t media,
2412*8275SEric Cheng     uint_t flags, uint_t *perm_flags)
24135903Ssowmini {
24146789Sam223141 	dld_ioc_macprop_t *dip;
2415*8275SEric Cheng 	uint32_t v = 0;
24165903Ssowmini 	uchar_t *cp;
24175903Ssowmini 	dladm_status_t status;
24185903Ssowmini 
2419*8275SEric Cheng 	dip = i_dladm_get_public_prop(linkid, pdp->pd_name, flags,
2420*8275SEric Cheng 	    &status, perm_flags);
24216512Ssowmini 	if (dip == NULL)
24225903Ssowmini 		return (status);
2423*8275SEric Cheng 
24245903Ssowmini 	cp = (uchar_t *)dip->pr_val;
24255903Ssowmini 	(void) memcpy(&v, cp, sizeof (v));
24266512Ssowmini 	(void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "%ld", v);
24275903Ssowmini 	free(dip);
24285903Ssowmini 	*val_cnt = 1;
24295903Ssowmini 	return (DLADM_STATUS_OK);
24305903Ssowmini }
24315903Ssowmini 
24325960Ssowmini /* ARGSUSED */
24335903Ssowmini static dladm_status_t
2434*8275SEric Cheng i_dladm_flowctl_get(prop_desc_t *pdp, datalink_id_t linkid,
2435*8275SEric Cheng     char **prop_val, uint_t *val_cnt, datalink_media_t media,
2436*8275SEric Cheng     uint_t flags, uint_t *perm_flags)
24375903Ssowmini {
24386789Sam223141 	dld_ioc_macprop_t *dip;
24395903Ssowmini 	link_flowctrl_t v;
24405903Ssowmini 	dladm_status_t status;
24415903Ssowmini 	uchar_t *cp;
24425903Ssowmini 
2443*8275SEric Cheng 	dip = i_dladm_get_public_prop(linkid, pdp->pd_name, flags,
2444*8275SEric Cheng 	    &status, perm_flags);
24456512Ssowmini 	if (dip == NULL)
24465903Ssowmini 		return (status);
2447*8275SEric Cheng 
24485903Ssowmini 	cp = (uchar_t *)dip->pr_val;
24495903Ssowmini 	(void) memcpy(&v, cp, sizeof (v));
24505903Ssowmini 	switch (v) {
24515903Ssowmini 	case LINK_FLOWCTRL_NONE:
24525903Ssowmini 		(void) sprintf(*prop_val, "no");
24535903Ssowmini 		break;
24545903Ssowmini 	case LINK_FLOWCTRL_RX:
24555903Ssowmini 		(void) sprintf(*prop_val, "rx");
24565903Ssowmini 		break;
24575903Ssowmini 	case LINK_FLOWCTRL_TX:
24585903Ssowmini 		(void) sprintf(*prop_val, "tx");
24595903Ssowmini 		break;
24605903Ssowmini 	case LINK_FLOWCTRL_BI:
24615903Ssowmini 		(void) sprintf(*prop_val, "bi");
24625903Ssowmini 		break;
24635903Ssowmini 	}
24645903Ssowmini 	free(dip);
24655903Ssowmini 	*val_cnt = 1;
24665903Ssowmini 	return (DLADM_STATUS_OK);
24675903Ssowmini }
24685903Ssowmini 
24695903Ssowmini 
24705903Ssowmini /* ARGSUSED */
24715903Ssowmini static dladm_status_t
24727342SAruna.Ramakrishna@Sun.COM i_dladm_set_prop(datalink_id_t linkid, const char *prop_name,
24735903Ssowmini     char **prop_val, uint_t val_cnt, uint_t flags)
24745903Ssowmini {
24757663SSowmini.Varadhan@Sun.COM 	int		i, slen;
24767408SSebastien.Roy@Sun.COM 	int 		bufsize = 0;
24776789Sam223141 	dld_ioc_macprop_t *dip = NULL;
24785903Ssowmini 	uchar_t 	*dp;
24797663SSowmini.Varadhan@Sun.COM 	link_attr_t *p;
24806512Ssowmini 	dladm_status_t	status = DLADM_STATUS_OK;
24815903Ssowmini 
24825903Ssowmini 	if ((prop_name == NULL && prop_val != NULL) ||
24835903Ssowmini 	    (prop_val != NULL && val_cnt == 0))
24845903Ssowmini 		return (DLADM_STATUS_BADARG);
24855903Ssowmini 	p = dladm_name2prop(prop_name);
24866789Sam223141 	if (p->pp_id != MAC_PROP_PRIVATE)
24875903Ssowmini 		return (DLADM_STATUS_BADARG);
24885903Ssowmini 
24895903Ssowmini 	/*
24905903Ssowmini 	 * private properties: all parsing is done in the kernel.
24915903Ssowmini 	 * allocate a enough space for each property + its separator (',').
24925903Ssowmini 	 */
24935903Ssowmini 	for (i = 0; i < val_cnt; i++) {
24945903Ssowmini 		bufsize += strlen(prop_val[i]) + 1;
24955903Ssowmini 	}
24966512Ssowmini 
24976512Ssowmini 	if (prop_val == NULL) {
24986512Ssowmini 		/*
24996512Ssowmini 		 * getting default value. so use more buffer space.
25006512Ssowmini 		 */
25017663SSowmini.Varadhan@Sun.COM 		bufsize += DLADM_PROP_BUF_CHUNK;
25026512Ssowmini 	}
25036512Ssowmini 
25047663SSowmini.Varadhan@Sun.COM 	dip = i_dladm_buf_alloc_by_name(bufsize + 1, linkid, prop_name,
25056789Sam223141 	    (prop_val != NULL ? 0 : MAC_PROP_DEFAULT), &status);
25065903Ssowmini 	if (dip == NULL)
25075903Ssowmini 		return (status);
25085903Ssowmini 
25095903Ssowmini 	dp = (uchar_t *)dip->pr_val;
25105903Ssowmini 	slen = 0;
25117663SSowmini.Varadhan@Sun.COM 
25126512Ssowmini 	if (prop_val == NULL) {
25137663SSowmini.Varadhan@Sun.COM 		status = i_dladm_macprop(dip, B_FALSE);
25146512Ssowmini 	} else {
25156512Ssowmini 		for (i = 0; i < val_cnt; i++) {
25166512Ssowmini 			int plen = 0;
25175903Ssowmini 
25186512Ssowmini 			plen = strlen(prop_val[i]);
25196512Ssowmini 			bcopy(prop_val[i], dp, plen);
25206512Ssowmini 			slen += plen;
25216512Ssowmini 			/*
25226512Ssowmini 			 * add a "," separator and update dp.
25236512Ssowmini 			 */
25246512Ssowmini 			if (i != (val_cnt -1))
25256512Ssowmini 				dp[slen++] = ',';
25266512Ssowmini 			dp += (plen + 1);
25276512Ssowmini 		}
25287663SSowmini.Varadhan@Sun.COM 		status = i_dladm_macprop(dip, B_TRUE);
25295903Ssowmini 	}
25306512Ssowmini 
25315903Ssowmini 	free(dip);
25326512Ssowmini 	return (status);
25335903Ssowmini }
25345903Ssowmini 
25355903Ssowmini static dladm_status_t
25367342SAruna.Ramakrishna@Sun.COM i_dladm_get_prop(datalink_id_t linkid, const char *prop_name,
25376512Ssowmini     char **prop_val, uint_t *val_cnt, dladm_prop_type_t type, uint_t dld_flags)
25385903Ssowmini {
25397663SSowmini.Varadhan@Sun.COM 	dladm_status_t	status = DLADM_STATUS_OK;
25406789Sam223141 	dld_ioc_macprop_t *dip = NULL;
25417663SSowmini.Varadhan@Sun.COM 	link_attr_t *p;
25425903Ssowmini 	char tmp = '\0';
25435903Ssowmini 
25445903Ssowmini 	if ((prop_name == NULL && prop_val != NULL) ||
25455903Ssowmini 	    (prop_val != NULL && val_cnt == 0))
25465903Ssowmini 		return (DLADM_STATUS_BADARG);
25475903Ssowmini 
25485903Ssowmini 	p = dladm_name2prop(prop_name);
25496789Sam223141 	if (p->pp_id != MAC_PROP_PRIVATE)
25505903Ssowmini 		return (DLADM_STATUS_BADARG);
25515903Ssowmini 
25526512Ssowmini 	if (type == DLADM_PROP_VAL_MODIFIABLE) {
25535903Ssowmini 		*prop_val = &tmp;
25545903Ssowmini 		*val_cnt = 1;
25555903Ssowmini 		return (DLADM_STATUS_OK);
25565903Ssowmini 	}
25575903Ssowmini 
25585903Ssowmini 	/*
25595903Ssowmini 	 * private properties: all parsing is done in the kernel.
25605903Ssowmini 	 */
25617663SSowmini.Varadhan@Sun.COM 	dip = i_dladm_buf_alloc_by_name(DLADM_PROP_BUF_CHUNK, linkid, prop_name,
25627663SSowmini.Varadhan@Sun.COM 	    dld_flags, &status);
25635903Ssowmini 	if (dip == NULL)
25645903Ssowmini 		return (status);
25655903Ssowmini 
25667663SSowmini.Varadhan@Sun.COM 	if ((status = i_dladm_macprop(dip, B_FALSE)) == DLADM_STATUS_OK) {
25678118SVasumathi.Sundaram@Sun.COM 		if (type == DLADM_PROP_VAL_PERM) {
2568*8275SEric Cheng 			(void) dladm_perm2str(dip->pr_perm_flags, *prop_val);
25698118SVasumathi.Sundaram@Sun.COM 		} else {
25708118SVasumathi.Sundaram@Sun.COM 			(void) strncpy(*prop_val, dip->pr_val,
25718118SVasumathi.Sundaram@Sun.COM 			    DLADM_PROP_VAL_MAX);
25728118SVasumathi.Sundaram@Sun.COM 		}
25735903Ssowmini 		*val_cnt = 1;
25745903Ssowmini 	}
25756512Ssowmini 	free(dip);
25765903Ssowmini 	return (status);
25775903Ssowmini }
25786512Ssowmini 
25796512Ssowmini 
25806512Ssowmini static dladm_status_t
25816512Ssowmini i_dladm_getset_defval(prop_desc_t *pdp, datalink_id_t linkid,
25826512Ssowmini     datalink_media_t media, uint_t flags)
25836512Ssowmini {
25846512Ssowmini 	dladm_status_t status;
25856512Ssowmini 	char **prop_vals = NULL, *buf;
25866512Ssowmini 	size_t bufsize;
25876512Ssowmini 	uint_t cnt;
25886512Ssowmini 	int i;
25898118SVasumathi.Sundaram@Sun.COM 	uint_t perm_flags;
25906512Ssowmini 
25916512Ssowmini 	/*
25926512Ssowmini 	 * Allocate buffer needed for prop_vals array. We can have at most
25936512Ssowmini 	 * DLADM_MAX_PROP_VALCNT char *prop_vals[] entries, where
25946512Ssowmini 	 * each entry has max size DLADM_PROP_VAL_MAX
25956512Ssowmini 	 */
25966512Ssowmini 	bufsize =
25976512Ssowmini 	    (sizeof (char *) + DLADM_PROP_VAL_MAX) * DLADM_MAX_PROP_VALCNT;
25986512Ssowmini 	buf = malloc(bufsize);
25996512Ssowmini 	prop_vals = (char **)(void *)buf;
26006512Ssowmini 	for (i = 0; i < DLADM_MAX_PROP_VALCNT; i++) {
26016512Ssowmini 		prop_vals[i] = buf +
26026512Ssowmini 		    sizeof (char *) * DLADM_MAX_PROP_VALCNT +
26036512Ssowmini 		    i * DLADM_PROP_VAL_MAX;
26046512Ssowmini 	}
26056768Sar224390 
26066768Sar224390 	/*
26077342SAruna.Ramakrishna@Sun.COM 	 * For properties which have pdp->pd_defval.vd_name as a non-empty
26087342SAruna.Ramakrishna@Sun.COM 	 * string, the "" itself is used to reset the property (exceptions
26097342SAruna.Ramakrishna@Sun.COM 	 * are zone and autopush, which populate vdp->vd_val). So
26107342SAruna.Ramakrishna@Sun.COM 	 * libdladm can copy pdp->pd_defval over to the val_desc_t passed
26117342SAruna.Ramakrishna@Sun.COM 	 * down on the setprop using the global values in the table. For
26127342SAruna.Ramakrishna@Sun.COM 	 * other cases (vd_name is ""), doing reset-linkprop will cause
26137342SAruna.Ramakrishna@Sun.COM 	 * libdladm to do a getprop to find the default value and then do
26147342SAruna.Ramakrishna@Sun.COM 	 * a setprop to reset the value to default.
26156768Sar224390 	 */
26166789Sam223141 	status = pdp->pd_get(pdp, linkid, prop_vals, &cnt, media,
26178118SVasumathi.Sundaram@Sun.COM 	    MAC_PROP_DEFAULT, &perm_flags);
26186512Ssowmini 	if (status == DLADM_STATUS_OK) {
26198118SVasumathi.Sundaram@Sun.COM 		if (perm_flags == MAC_PROP_PERM_RW) {
26208118SVasumathi.Sundaram@Sun.COM 			status = i_dladm_set_single_prop(linkid, pdp->pd_class,
26218118SVasumathi.Sundaram@Sun.COM 			    media, pdp, prop_vals, cnt, flags);
26228118SVasumathi.Sundaram@Sun.COM 		}
26238118SVasumathi.Sundaram@Sun.COM 		else
26248118SVasumathi.Sundaram@Sun.COM 			status = DLADM_STATUS_NOTSUP;
26256512Ssowmini 	}
26266512Ssowmini 	free(buf);
26276512Ssowmini 	return (status);
26286512Ssowmini }
26297663SSowmini.Varadhan@Sun.COM 
26307663SSowmini.Varadhan@Sun.COM int
26317663SSowmini.Varadhan@Sun.COM macprop_to_wifi(mac_prop_id_t wl_prop)
26327663SSowmini.Varadhan@Sun.COM {
26337663SSowmini.Varadhan@Sun.COM 	switch (wl_prop) {
26347663SSowmini.Varadhan@Sun.COM 	case MAC_PROP_WL_ESSID:
26357663SSowmini.Varadhan@Sun.COM 		return (WL_ESSID);
26367663SSowmini.Varadhan@Sun.COM 	case MAC_PROP_WL_BSSID:
26377663SSowmini.Varadhan@Sun.COM 		return (WL_BSSID);
26387663SSowmini.Varadhan@Sun.COM 	case MAC_PROP_WL_BSSTYPE:
26397663SSowmini.Varadhan@Sun.COM 		return (WL_BSS_TYPE);
26407663SSowmini.Varadhan@Sun.COM 	case MAC_PROP_WL_LINKSTATUS:
26417663SSowmini.Varadhan@Sun.COM 		return (WL_LINKSTATUS);
26427663SSowmini.Varadhan@Sun.COM 	case MAC_PROP_WL_DESIRED_RATES:
26437663SSowmini.Varadhan@Sun.COM 		return (WL_DESIRED_RATES);
26447663SSowmini.Varadhan@Sun.COM 	case MAC_PROP_WL_SUPPORTED_RATES:
26457663SSowmini.Varadhan@Sun.COM 		return (WL_SUPPORTED_RATES);
26467663SSowmini.Varadhan@Sun.COM 	case MAC_PROP_WL_AUTH_MODE:
26477663SSowmini.Varadhan@Sun.COM 		return (WL_AUTH_MODE);
26487663SSowmini.Varadhan@Sun.COM 	case MAC_PROP_WL_ENCRYPTION:
26497663SSowmini.Varadhan@Sun.COM 		return (WL_ENCRYPTION);
26507663SSowmini.Varadhan@Sun.COM 	case MAC_PROP_WL_RSSI:
26517663SSowmini.Varadhan@Sun.COM 		return (WL_RSSI);
26527663SSowmini.Varadhan@Sun.COM 	case MAC_PROP_WL_PHY_CONFIG:
26537663SSowmini.Varadhan@Sun.COM 		return (WL_PHY_CONFIG);
26547663SSowmini.Varadhan@Sun.COM 	case MAC_PROP_WL_CAPABILITY:
26557663SSowmini.Varadhan@Sun.COM 		return (WL_CAPABILITY);
26567663SSowmini.Varadhan@Sun.COM 	case MAC_PROP_WL_WPA:
26577663SSowmini.Varadhan@Sun.COM 		return (WL_WPA);
26587663SSowmini.Varadhan@Sun.COM 	case MAC_PROP_WL_SCANRESULTS:
26597663SSowmini.Varadhan@Sun.COM 		return (WL_SCANRESULTS);
26607663SSowmini.Varadhan@Sun.COM 	case MAC_PROP_WL_POWER_MODE:
26617663SSowmini.Varadhan@Sun.COM 		return (WL_POWER_MODE);
26627663SSowmini.Varadhan@Sun.COM 	case MAC_PROP_WL_RADIO:
26637663SSowmini.Varadhan@Sun.COM 		return (WL_RADIO);
26647663SSowmini.Varadhan@Sun.COM 	case MAC_PROP_WL_ESS_LIST:
26657663SSowmini.Varadhan@Sun.COM 		return (WL_ESS_LIST);
26667663SSowmini.Varadhan@Sun.COM 	case MAC_PROP_WL_KEY_TAB:
26677663SSowmini.Varadhan@Sun.COM 		return (WL_WEP_KEY_TAB);
26687663SSowmini.Varadhan@Sun.COM 	case MAC_PROP_WL_CREATE_IBSS:
26697663SSowmini.Varadhan@Sun.COM 		return (WL_CREATE_IBSS);
26707663SSowmini.Varadhan@Sun.COM 	case MAC_PROP_WL_SETOPTIE:
26717663SSowmini.Varadhan@Sun.COM 		return (WL_SETOPTIE);
26727663SSowmini.Varadhan@Sun.COM 	case MAC_PROP_WL_DELKEY:
26737663SSowmini.Varadhan@Sun.COM 		return (WL_DELKEY);
26747663SSowmini.Varadhan@Sun.COM 	case MAC_PROP_WL_KEY:
26757663SSowmini.Varadhan@Sun.COM 		return (WL_KEY);
26767663SSowmini.Varadhan@Sun.COM 	case MAC_PROP_WL_MLME:
26777663SSowmini.Varadhan@Sun.COM 		return (WL_MLME);
26787663SSowmini.Varadhan@Sun.COM 	default:
26797663SSowmini.Varadhan@Sun.COM 		return (-1);
26807663SSowmini.Varadhan@Sun.COM 	}
26817663SSowmini.Varadhan@Sun.COM }
26827663SSowmini.Varadhan@Sun.COM 
26837663SSowmini.Varadhan@Sun.COM dladm_status_t
26847663SSowmini.Varadhan@Sun.COM i_dladm_wlan_param(datalink_id_t linkid, void *buf, mac_prop_id_t cmd,
26857663SSowmini.Varadhan@Sun.COM     size_t len, boolean_t set)
26867663SSowmini.Varadhan@Sun.COM {
26877663SSowmini.Varadhan@Sun.COM 	uint32_t		flags;
26887663SSowmini.Varadhan@Sun.COM 	dladm_status_t		status;
26897663SSowmini.Varadhan@Sun.COM 	uint32_t		media;
26907663SSowmini.Varadhan@Sun.COM 	dld_ioc_macprop_t	*dip;
26917663SSowmini.Varadhan@Sun.COM 	void			*dp;
26927663SSowmini.Varadhan@Sun.COM 
26937663SSowmini.Varadhan@Sun.COM 	if ((status = dladm_datalink_id2info(linkid, &flags, NULL, &media,
26947663SSowmini.Varadhan@Sun.COM 	    NULL, 0)) != DLADM_STATUS_OK) {
26957663SSowmini.Varadhan@Sun.COM 		return (status);
26967663SSowmini.Varadhan@Sun.COM 	}
26977663SSowmini.Varadhan@Sun.COM 
26987663SSowmini.Varadhan@Sun.COM 	if (media != DL_WIFI)
26997663SSowmini.Varadhan@Sun.COM 		return (DLADM_STATUS_BADARG);
27007663SSowmini.Varadhan@Sun.COM 
27017663SSowmini.Varadhan@Sun.COM 	if (!(flags & DLADM_OPT_ACTIVE))
27027663SSowmini.Varadhan@Sun.COM 		return (DLADM_STATUS_TEMPONLY);
27037663SSowmini.Varadhan@Sun.COM 
27047663SSowmini.Varadhan@Sun.COM 	if (len == (MAX_BUF_LEN - WIFI_BUF_OFFSET))
27057663SSowmini.Varadhan@Sun.COM 		len = MAX_BUF_LEN - sizeof (dld_ioc_macprop_t) - 1;
27067663SSowmini.Varadhan@Sun.COM 
27077663SSowmini.Varadhan@Sun.COM 	dip = i_dladm_buf_alloc_by_id(len, linkid, cmd, 0, &status);
27087663SSowmini.Varadhan@Sun.COM 	if (dip == NULL)
27097663SSowmini.Varadhan@Sun.COM 		return (DLADM_STATUS_NOMEM);
27107663SSowmini.Varadhan@Sun.COM 
27117663SSowmini.Varadhan@Sun.COM 	dp = (uchar_t *)dip->pr_val;
27127663SSowmini.Varadhan@Sun.COM 	if (set)
27137663SSowmini.Varadhan@Sun.COM 		(void) memcpy(dp, buf, len);
27147663SSowmini.Varadhan@Sun.COM 
27157663SSowmini.Varadhan@Sun.COM 	status = i_dladm_macprop(dip, set);
27167663SSowmini.Varadhan@Sun.COM 	if (status == DLADM_STATUS_NOTSUP) {
27177663SSowmini.Varadhan@Sun.COM 		if (set) {
27187663SSowmini.Varadhan@Sun.COM 			status = i_dladm_wlan_set_legacy_ioctl(linkid,
27197663SSowmini.Varadhan@Sun.COM 			    buf, len, macprop_to_wifi(cmd));
27207663SSowmini.Varadhan@Sun.COM 		} else {
27217663SSowmini.Varadhan@Sun.COM 			status = i_dladm_wlan_get_legacy_ioctl(linkid,
27227663SSowmini.Varadhan@Sun.COM 			    buf, len, macprop_to_wifi(cmd));
27237663SSowmini.Varadhan@Sun.COM 		}
27247663SSowmini.Varadhan@Sun.COM 	} else if (status == DLADM_STATUS_OK) {
27257663SSowmini.Varadhan@Sun.COM 		if (!set)
27267663SSowmini.Varadhan@Sun.COM 			(void) memcpy(buf, dp, len);
27277663SSowmini.Varadhan@Sun.COM 	}
27287663SSowmini.Varadhan@Sun.COM 
27297663SSowmini.Varadhan@Sun.COM 	free(dip);
27307663SSowmini.Varadhan@Sun.COM 	return (status);
27317663SSowmini.Varadhan@Sun.COM }
27327663SSowmini.Varadhan@Sun.COM 
27337663SSowmini.Varadhan@Sun.COM static dladm_status_t
27347663SSowmini.Varadhan@Sun.COM i_dladm_wlan_get_legacy_ioctl(datalink_id_t linkid, void *buf, uint_t buflen,
27357663SSowmini.Varadhan@Sun.COM     uint_t id)
27367663SSowmini.Varadhan@Sun.COM {
27377663SSowmini.Varadhan@Sun.COM 	wldp_t *gbuf;
27387663SSowmini.Varadhan@Sun.COM 	dladm_status_t status;
27397663SSowmini.Varadhan@Sun.COM 
27407663SSowmini.Varadhan@Sun.COM 	if ((gbuf = malloc(MAX_BUF_LEN)) == NULL)
27417663SSowmini.Varadhan@Sun.COM 		return (DLADM_STATUS_NOMEM);
27427663SSowmini.Varadhan@Sun.COM 
27437663SSowmini.Varadhan@Sun.COM 	(void) memset(gbuf, 0, MAX_BUF_LEN);
27447663SSowmini.Varadhan@Sun.COM 	status = i_dladm_wlan_legacy_ioctl(linkid, gbuf, id, MAX_BUF_LEN,
27457663SSowmini.Varadhan@Sun.COM 	    WLAN_GET_PARAM, sizeof (wldp_t));
27467663SSowmini.Varadhan@Sun.COM 	if (status == DLADM_STATUS_OK)
27477663SSowmini.Varadhan@Sun.COM 		(void) memcpy(buf, gbuf->wldp_buf, buflen);
27487663SSowmini.Varadhan@Sun.COM 
27497663SSowmini.Varadhan@Sun.COM 	free(gbuf);
27507663SSowmini.Varadhan@Sun.COM 	return (status);
27517663SSowmini.Varadhan@Sun.COM }
27527663SSowmini.Varadhan@Sun.COM 
27537663SSowmini.Varadhan@Sun.COM static dladm_status_t
27547663SSowmini.Varadhan@Sun.COM i_dladm_wlan_set_legacy_ioctl(datalink_id_t linkid,  void *buf, uint_t buflen,
27557663SSowmini.Varadhan@Sun.COM     uint_t id)
27567663SSowmini.Varadhan@Sun.COM {
27577663SSowmini.Varadhan@Sun.COM 	wldp_t *gbuf;
27587663SSowmini.Varadhan@Sun.COM 	dladm_status_t status = DLADM_STATUS_OK;
27597663SSowmini.Varadhan@Sun.COM 
27607663SSowmini.Varadhan@Sun.COM 	if ((gbuf = malloc(MAX_BUF_LEN)) == NULL)
27617663SSowmini.Varadhan@Sun.COM 		return (DLADM_STATUS_NOMEM);
27627663SSowmini.Varadhan@Sun.COM 
27637663SSowmini.Varadhan@Sun.COM 	(void) memset(gbuf, 0, MAX_BUF_LEN);
27647663SSowmini.Varadhan@Sun.COM 	(void) memcpy(gbuf->wldp_buf, buf, buflen);
27657663SSowmini.Varadhan@Sun.COM 	buflen += WIFI_BUF_OFFSET;
27667663SSowmini.Varadhan@Sun.COM 	status = i_dladm_wlan_legacy_ioctl(linkid, gbuf, id, buflen,
27677663SSowmini.Varadhan@Sun.COM 	    WLAN_SET_PARAM, buflen);
27687663SSowmini.Varadhan@Sun.COM 
27697663SSowmini.Varadhan@Sun.COM 	free(gbuf);
27707663SSowmini.Varadhan@Sun.COM 	return (status);
27717663SSowmini.Varadhan@Sun.COM }
2772*8275SEric Cheng 
2773*8275SEric Cheng static dladm_status_t
2774*8275SEric Cheng link_proplist_check(dladm_arg_list_t *proplist)
2775*8275SEric Cheng {
2776*8275SEric Cheng 	int		i, j;
2777*8275SEric Cheng 	boolean_t	matched;
2778*8275SEric Cheng 
2779*8275SEric Cheng 	for (i = 0; i < proplist->al_count; i++) {
2780*8275SEric Cheng 		matched = B_FALSE;
2781*8275SEric Cheng 		for (j = 0; j < DLADM_MAX_PROPS; j++) {
2782*8275SEric Cheng 			if (strcmp(proplist->al_info[i].ai_name,
2783*8275SEric Cheng 			    prop_table[j].pd_name) == 0)
2784*8275SEric Cheng 				matched = B_TRUE;
2785*8275SEric Cheng 		}
2786*8275SEric Cheng 		if (!matched)
2787*8275SEric Cheng 			return (DLADM_STATUS_BADPROP);
2788*8275SEric Cheng 	}
2789*8275SEric Cheng 	return (DLADM_STATUS_OK);
2790*8275SEric Cheng }
2791*8275SEric Cheng 
2792*8275SEric Cheng dladm_status_t
2793*8275SEric Cheng dladm_parse_link_props(char *str, dladm_arg_list_t **listp, boolean_t novalues)
2794*8275SEric Cheng {
2795*8275SEric Cheng 	dladm_status_t	status;
2796*8275SEric Cheng 
2797*8275SEric Cheng 	status = dladm_parse_args(str, listp, novalues);
2798*8275SEric Cheng 	if (status != DLADM_STATUS_OK)
2799*8275SEric Cheng 		return (status);
2800*8275SEric Cheng 
2801*8275SEric Cheng 	status = link_proplist_check(*listp);
2802*8275SEric Cheng 	if (status != DLADM_STATUS_OK) {
2803*8275SEric Cheng 		dladm_free_props(*listp);
2804*8275SEric Cheng 		return (status);
2805*8275SEric Cheng 	}
2806*8275SEric Cheng 
2807*8275SEric Cheng 	return (DLADM_STATUS_OK);
2808*8275SEric Cheng }
2809*8275SEric Cheng 
2810*8275SEric Cheng /*
2811*8275SEric Cheng  * Retrieve the one link property from the database
2812*8275SEric Cheng  */
2813*8275SEric Cheng /*ARGSUSED*/
2814*8275SEric Cheng static int
2815*8275SEric Cheng i_dladm_get_one_prop(datalink_id_t linkid, const char *prop_name, void *arg)
2816*8275SEric Cheng {
2817*8275SEric Cheng 	dladm_arg_list_t	*proplist = arg;
2818*8275SEric Cheng 	dladm_arg_info_t	*aip = NULL;
2819*8275SEric Cheng 
2820*8275SEric Cheng 	aip = &proplist->al_info[proplist->al_count];
2821*8275SEric Cheng 	/*
2822*8275SEric Cheng 	 * it is fine to point to prop_name since prop_name points to the
2823*8275SEric Cheng 	 * prop_table[n].pd_name.
2824*8275SEric Cheng 	 */
2825*8275SEric Cheng 	aip->ai_name = prop_name;
2826*8275SEric Cheng 
2827*8275SEric Cheng 	(void) dladm_get_linkprop(linkid, DLADM_PROP_VAL_PERSISTENT, prop_name,
2828*8275SEric Cheng 	    aip->ai_val, &aip->ai_count);
2829*8275SEric Cheng 
2830*8275SEric Cheng 	if (aip->ai_count != 0)
2831*8275SEric Cheng 		proplist->al_count++;
2832*8275SEric Cheng 
2833*8275SEric Cheng 	return (DLADM_WALK_CONTINUE);
2834*8275SEric Cheng }
2835*8275SEric Cheng 
2836*8275SEric Cheng 
2837*8275SEric Cheng /*
2838*8275SEric Cheng  * Retrieve all link properties for a link from the database and
2839*8275SEric Cheng  * return a property list.
2840*8275SEric Cheng  */
2841*8275SEric Cheng dladm_status_t
2842*8275SEric Cheng dladm_link_get_proplist(datalink_id_t linkid, dladm_arg_list_t **listp)
2843*8275SEric Cheng {
2844*8275SEric Cheng 	dladm_arg_list_t	*list;
2845*8275SEric Cheng 	dladm_status_t		status = DLADM_STATUS_OK;
2846*8275SEric Cheng 
2847*8275SEric Cheng 	list = calloc(1, sizeof (dladm_arg_list_t));
2848*8275SEric Cheng 	if (list == NULL)
2849*8275SEric Cheng 		return (dladm_errno2status(errno));
2850*8275SEric Cheng 
2851*8275SEric Cheng 	status = dladm_walk_linkprop(linkid, list, i_dladm_get_one_prop);
2852*8275SEric Cheng 
2853*8275SEric Cheng 	*listp = list;
2854*8275SEric Cheng 	return (status);
2855*8275SEric Cheng }
2856*8275SEric Cheng 
2857*8275SEric Cheng /*
2858*8275SEric Cheng  * Retrieve the named property from a proplist, check the value and
2859*8275SEric Cheng  * convert to a kernel structure.
2860*8275SEric Cheng  */
2861*8275SEric Cheng static dladm_status_t
2862*8275SEric Cheng i_dladm_link_proplist_extract_one(dladm_arg_list_t *proplist,
2863*8275SEric Cheng     const char *name, void *val)
2864*8275SEric Cheng {
2865*8275SEric Cheng 	dladm_status_t		status;
2866*8275SEric Cheng 	dladm_arg_info_t	*aip = NULL;
2867*8275SEric Cheng 	int			i, j;
2868*8275SEric Cheng 
2869*8275SEric Cheng 	/* Find named property in proplist */
2870*8275SEric Cheng 	for (i = 0; i < proplist->al_count; i++) {
2871*8275SEric Cheng 		aip = &proplist->al_info[i];
2872*8275SEric Cheng 		if (strcasecmp(aip->ai_name, name) == 0)
2873*8275SEric Cheng 			break;
2874*8275SEric Cheng 	}
2875*8275SEric Cheng 
2876*8275SEric Cheng 	/* Property not in list */
2877*8275SEric Cheng 	if (i == proplist->al_count)
2878*8275SEric Cheng 		return (DLADM_STATUS_OK);
2879*8275SEric Cheng 
2880*8275SEric Cheng 	for (i = 0; i < DLADM_MAX_PROPS; i++) {
2881*8275SEric Cheng 		prop_desc_t	*pdp = &prop_table[i];
2882*8275SEric Cheng 		val_desc_t	*vdp;
2883*8275SEric Cheng 
2884*8275SEric Cheng 		vdp = malloc(sizeof (val_desc_t) * aip->ai_count);
2885*8275SEric Cheng 		if (vdp == NULL)
2886*8275SEric Cheng 			return (DLADM_STATUS_NOMEM);
2887*8275SEric Cheng 
2888*8275SEric Cheng 		if (strcasecmp(aip->ai_name, pdp->pd_name) != 0)
2889*8275SEric Cheng 			continue;
2890*8275SEric Cheng 
2891*8275SEric Cheng 		if (aip->ai_val == NULL)
2892*8275SEric Cheng 			return (DLADM_STATUS_BADARG);
2893*8275SEric Cheng 
2894*8275SEric Cheng 		/* Check property value */
2895*8275SEric Cheng 		if (pdp->pd_check != NULL) {
2896*8275SEric Cheng 			status = pdp->pd_check(pdp, 0, aip->ai_val,
2897*8275SEric Cheng 			    aip->ai_count, vdp, 0);
2898*8275SEric Cheng 		} else {
2899*8275SEric Cheng 			status = DLADM_STATUS_BADARG;
2900*8275SEric Cheng 		}
2901*8275SEric Cheng 
2902*8275SEric Cheng 		if (status != DLADM_STATUS_OK)
2903*8275SEric Cheng 			return (status);
2904*8275SEric Cheng 
2905*8275SEric Cheng 		for (j = 0; j < DLADM_MAX_RSRC_PROP; j++) {
2906*8275SEric Cheng 			resource_prop_t	*rpp = &rsrc_prop_table[j];
2907*8275SEric Cheng 
2908*8275SEric Cheng 			if (strcasecmp(aip->ai_name, rpp->rp_name) != 0)
2909*8275SEric Cheng 				continue;
2910*8275SEric Cheng 
2911*8275SEric Cheng 			/* Extract kernel structure */
2912*8275SEric Cheng 			if (rpp->rp_extract != NULL) {
2913*8275SEric Cheng 				status = rpp->rp_extract(vdp, val,
2914*8275SEric Cheng 				    aip->ai_count);
2915*8275SEric Cheng 			} else {
2916*8275SEric Cheng 				status = DLADM_STATUS_BADARG;
2917*8275SEric Cheng 			}
2918*8275SEric Cheng 			break;
2919*8275SEric Cheng 		}
2920*8275SEric Cheng 
2921*8275SEric Cheng 		if (status != DLADM_STATUS_OK)
2922*8275SEric Cheng 			return (status);
2923*8275SEric Cheng 
2924*8275SEric Cheng 		break;
2925*8275SEric Cheng 	}
2926*8275SEric Cheng 	return (status);
2927*8275SEric Cheng }
2928*8275SEric Cheng 
2929*8275SEric Cheng /*
2930*8275SEric Cheng  * Extract properties from a proplist and convert to mac_resource_props_t.
2931*8275SEric Cheng  */
2932*8275SEric Cheng dladm_status_t
2933*8275SEric Cheng dladm_link_proplist_extract(dladm_arg_list_t *proplist,
2934*8275SEric Cheng     mac_resource_props_t *mrp)
2935*8275SEric Cheng {
2936*8275SEric Cheng 	dladm_status_t	status = DLADM_STATUS_OK;
2937*8275SEric Cheng 
2938*8275SEric Cheng 	status = i_dladm_link_proplist_extract_one(proplist, "maxbw", mrp);
2939*8275SEric Cheng 	if (status != DLADM_STATUS_OK)
2940*8275SEric Cheng 		return (status);
2941*8275SEric Cheng 	status = i_dladm_link_proplist_extract_one(proplist, "priority", mrp);
2942*8275SEric Cheng 	if (status != DLADM_STATUS_OK)
2943*8275SEric Cheng 		return (status);
2944*8275SEric Cheng 	status = i_dladm_link_proplist_extract_one(proplist, "cpus", mrp);
2945*8275SEric Cheng 	if (status != DLADM_STATUS_OK)
2946*8275SEric Cheng 		return (status);
2947*8275SEric Cheng 	return (status);
2948*8275SEric Cheng }
2949*8275SEric Cheng 
2950*8275SEric Cheng static const char *
2951*8275SEric Cheng dladm_perm2str(uint_t perm, char *buf)
2952*8275SEric Cheng {
2953*8275SEric Cheng 	(void) snprintf(buf, DLADM_STRSIZE, "%c%c",
2954*8275SEric Cheng 	    ((perm & MAC_PROP_PERM_READ) != 0) ? 'r' : '-',
2955*8275SEric Cheng 	    ((perm & MAC_PROP_PERM_WRITE) != 0) ? 'w' : '-');
2956*8275SEric Cheng 	return (buf);
2957*8275SEric Cheng }
2958