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>
443448Sdh155122 #include <dlfcn.h>
453448Sdh155122 #include <link.h>
465895Syz147064 #include <inet/wifi_ioctl.h>
475903Ssowmini #include <libdladm.h>
485903Ssowmini #include <sys/param.h>
495903Ssowmini #include <inttypes.h>
505903Ssowmini #include <sys/ethernet.h>
517663SSowmini.Varadhan@Sun.COM #include <net/wpa.h>
527663SSowmini.Varadhan@Sun.COM #include <sys/sysmacros.h>
533448Sdh155122 
54*8118SVasumathi.Sundaram@Sun.COM #define	PERM_READ_ONLY 	"r-"
55*8118SVasumathi.Sundaram@Sun.COM #define	PERM_READ_WRITE	"rw"
56*8118SVasumathi.Sundaram@Sun.COM 
575895Syz147064 /*
585895Syz147064  * The linkprop get() callback.
595903Ssowmini  * - pd: 	pointer to the struct prop_desc
605895Syz147064  * - propstrp:	a property string array to keep the returned property.
615895Syz147064  *		Caller allocated.
625895Syz147064  * - cntp:	number of returned properties.
635895Syz147064  *		Caller also uses it to indicate how many it expects.
645895Syz147064  */
655903Ssowmini struct prop_desc;
665903Ssowmini 
675903Ssowmini typedef dladm_status_t	pd_getf_t(struct prop_desc *pd,
685960Ssowmini 			datalink_id_t, char **propstp, uint_t *cntp,
69*8118SVasumathi.Sundaram@Sun.COM 			datalink_media_t, uint_t, uint_t *);
705895Syz147064 
715895Syz147064 /*
725895Syz147064  * The linkprop set() callback.
735895Syz147064  * - propval:	a val_desc_t array which keeps the property values to be set.
745895Syz147064  * - cnt:	number of properties to be set.
755903Ssowmini  * - flags: 	additional flags passed down the system call.
765903Ssowmini  *
775903Ssowmini  * pd_set takes val_desc_t given by pd_check(), translates it into
785903Ssowmini  * a format suitable for kernel consumption. This may require allocation
795903Ssowmini  * of ioctl buffers etc. pd_set() may call another common routine (used
805903Ssowmini  * by all other pd_sets) which invokes the ioctl.
815895Syz147064  */
825903Ssowmini typedef dladm_status_t	pd_setf_t(struct prop_desc *, datalink_id_t,
835960Ssowmini 			val_desc_t *propval, uint_t cnt, uint_t flags,
845960Ssowmini 			datalink_media_t);
853448Sdh155122 
863448Sdh155122 
875895Syz147064 /*
885895Syz147064  * The linkprop check() callback.
895895Syz147064  * - propstrp:	property string array which keeps the property to be checked.
905895Syz147064  * - cnt:	number of properties.
915895Syz147064  * - propval:	return value; the property values of the given property strings.
925903Ssowmini  *
935903Ssowmini  * pd_check checks that the input values are valid. It does so by
945903Ssowmini  * iteraring through the pd_modval list for the property. If
955903Ssowmini  * the modifiable values cannot be expressed as a list, a pd_check
965903Ssowmini  * specific to this property can be used. If the input values are
975903Ssowmini  * verified to be valid, pd_check allocates a val_desc_t and fills it
985903Ssowmini  * with either a val_desc_t found on the pd_modval list or something
995903Ssowmini  * generated on the fly.
1005895Syz147064  */
1015903Ssowmini typedef dladm_status_t	pd_checkf_t(struct prop_desc *pd,
1025903Ssowmini 			    datalink_id_t, char **propstrp,
1035960Ssowmini 			    uint_t cnt, val_desc_t *propval,
1045960Ssowmini 			    datalink_media_t);
1053448Sdh155122 
1067663SSowmini.Varadhan@Sun.COM typedef struct link_attr_s {
1076789Sam223141 	mac_prop_id_t	pp_id;
1085903Ssowmini 	size_t		pp_valsize;
1095903Ssowmini 	char		*pp_name;
1107663SSowmini.Varadhan@Sun.COM } link_attr_t;
1115903Ssowmini 
1127663SSowmini.Varadhan@Sun.COM static dld_ioc_macprop_t *i_dladm_buf_alloc_by_name(size_t, datalink_id_t,
1137663SSowmini.Varadhan@Sun.COM 					const char *, uint_t, dladm_status_t *);
1147663SSowmini.Varadhan@Sun.COM static dld_ioc_macprop_t *i_dladm_buf_alloc_by_id(size_t, datalink_id_t,
1157663SSowmini.Varadhan@Sun.COM 					mac_prop_id_t, uint_t,
1167663SSowmini.Varadhan@Sun.COM 					dladm_status_t *);
1177342SAruna.Ramakrishna@Sun.COM static dladm_status_t i_dladm_set_prop(datalink_id_t, const char *, char **,
1185903Ssowmini 					uint_t, uint_t);
1197342SAruna.Ramakrishna@Sun.COM static dladm_status_t i_dladm_get_prop(datalink_id_t, const char *, char **,
1206512Ssowmini 					uint_t *, dladm_prop_type_t, uint_t);
1217663SSowmini.Varadhan@Sun.COM static link_attr_t *dladm_name2prop(const char *);
1227663SSowmini.Varadhan@Sun.COM static link_attr_t *dladm_id2prop(mac_prop_id_t);
1237342SAruna.Ramakrishna@Sun.COM static dld_ioc_macprop_t *i_dladm_get_public_prop(datalink_id_t, char *, uint_t,
1247342SAruna.Ramakrishna@Sun.COM 					dladm_status_t *);
1255895Syz147064 static pd_getf_t	do_get_zone, do_get_autopush, do_get_rate_mod,
1265895Syz147064 			do_get_rate_prop, do_get_channel_prop,
1275903Ssowmini 			do_get_powermode_prop, do_get_radio_prop,
1287342SAruna.Ramakrishna@Sun.COM 			i_dladm_duplex_get, i_dladm_status_get,
1297342SAruna.Ramakrishna@Sun.COM 			i_dladm_binary_get, i_dladm_uint32_get,
1307342SAruna.Ramakrishna@Sun.COM 			i_dladm_flowctl_get;
1317342SAruna.Ramakrishna@Sun.COM static pd_setf_t	do_set_zone, do_set_rate_prop,
1325903Ssowmini 			do_set_powermode_prop, do_set_radio_prop,
1337342SAruna.Ramakrishna@Sun.COM 			i_dladm_set_public_prop;
1345903Ssowmini static pd_checkf_t	do_check_zone, do_check_autopush, do_check_rate,
1357342SAruna.Ramakrishna@Sun.COM 			i_dladm_defmtu_check;
1363448Sdh155122 
1377342SAruna.Ramakrishna@Sun.COM static dladm_status_t	i_dladm_speed_get(struct prop_desc *, datalink_id_t,
1386512Ssowmini 			char **, uint_t *, uint_t);
1397663SSowmini.Varadhan@Sun.COM static dladm_status_t	i_dladm_wlan_get_legacy_ioctl(datalink_id_t, void *,
1407663SSowmini.Varadhan@Sun.COM 			    uint_t, uint_t);
1417663SSowmini.Varadhan@Sun.COM static dladm_status_t	i_dladm_wlan_set_legacy_ioctl(datalink_id_t, void *,
1427663SSowmini.Varadhan@Sun.COM 			    uint_t, uint_t);
1437663SSowmini.Varadhan@Sun.COM static dladm_status_t	i_dladm_macprop(void *, boolean_t);
1445960Ssowmini 
1453448Sdh155122 typedef struct prop_desc {
1465895Syz147064 	/*
1475895Syz147064 	 * link property name
1485895Syz147064 	 */
1495895Syz147064 	char			*pd_name;
1505895Syz147064 
1515895Syz147064 	/*
1525895Syz147064 	 * default property value, can be set to { "", NULL }
1535895Syz147064 	 */
1545895Syz147064 	val_desc_t		pd_defval;
1555895Syz147064 
1565895Syz147064 	/*
1575895Syz147064 	 * list of optional property values, can be NULL.
1585895Syz147064 	 *
1595895Syz147064 	 * This is set to non-NULL if there is a list of possible property
1605895Syz147064 	 * values.  pd_optval would point to the array of possible values.
1615895Syz147064 	 */
1625895Syz147064 	val_desc_t		*pd_optval;
1635895Syz147064 
1645895Syz147064 	/*
1655895Syz147064 	 * count of the above optional property values. 0 if pd_optval is NULL.
1665895Syz147064 	 */
1675895Syz147064 	uint_t			pd_noptval;
1685895Syz147064 
1695895Syz147064 	/*
1705895Syz147064 	 * callback to set link property;
1715895Syz147064 	 * set to NULL if this property is read-only
1725895Syz147064 	 */
1735895Syz147064 	pd_setf_t		*pd_set;
1745895Syz147064 
1755895Syz147064 	/*
1765895Syz147064 	 * callback to get modifiable link property
1775895Syz147064 	 */
1785895Syz147064 	pd_getf_t		*pd_getmod;
1795895Syz147064 
1805895Syz147064 	/*
1815895Syz147064 	 * callback to get current link property
1825895Syz147064 	 */
1835895Syz147064 	pd_getf_t		*pd_get;
1845895Syz147064 
1855895Syz147064 	/*
1865895Syz147064 	 * callback to validate link property value, set to NULL if pd_optval
1875895Syz147064 	 * is not NULL. In that case, validate the value by comparing it with
1885895Syz147064 	 * the pd_optval. Return a val_desc_t array pointer if the value is
1895895Syz147064 	 * valid.
1905895Syz147064 	 */
1915895Syz147064 	pd_checkf_t		*pd_check;
1925895Syz147064 
1935895Syz147064 	uint_t			pd_flags;
1945903Ssowmini #define	PD_TEMPONLY	0x1	/* property is temporary only */
1955903Ssowmini #define	PD_CHECK_ALLOC	0x2	/* alloc vd_val as part of pd_check */
1965895Syz147064 	/*
1975895Syz147064 	 * indicate link classes this property applies to.
1985895Syz147064 	 */
1995895Syz147064 	datalink_class_t	pd_class;
2005895Syz147064 
2015895Syz147064 	/*
2025895Syz147064 	 * indicate link media type this property applies to.
2035895Syz147064 	 */
2045895Syz147064 	datalink_media_t	pd_dmedia;
2053448Sdh155122 } prop_desc_t;
2063448Sdh155122 
2076789Sam223141 #define	MAC_PROP_BUFSIZE(v)	sizeof (dld_ioc_macprop_t) + (v) - 1
2085903Ssowmini 
2097663SSowmini.Varadhan@Sun.COM /*
2107663SSowmini.Varadhan@Sun.COM  * Supported link properties enumerated in the prop_table[] array are
2117663SSowmini.Varadhan@Sun.COM  * computed using the callback functions in that array. To compute the
2127663SSowmini.Varadhan@Sun.COM  * property value, multiple distinct system calls may be needed (e.g.,
2137663SSowmini.Varadhan@Sun.COM  * for wifi speed, we need to issue system calls to get desired/supported
2147663SSowmini.Varadhan@Sun.COM  * rates). The link_attr[] table enumerates the interfaces to the kernel,
2157663SSowmini.Varadhan@Sun.COM  * and the type/size of the data passed in the user-kernel interface.
2167663SSowmini.Varadhan@Sun.COM  */
2177663SSowmini.Varadhan@Sun.COM static link_attr_t link_attr[] = {
2187663SSowmini.Varadhan@Sun.COM 	{ MAC_PROP_DUPLEX,	sizeof (link_duplex_t),	"duplex"},
2195903Ssowmini 
2207663SSowmini.Varadhan@Sun.COM 	{ MAC_PROP_SPEED,	sizeof (uint64_t),	"speed"},
2217663SSowmini.Varadhan@Sun.COM 
2227663SSowmini.Varadhan@Sun.COM 	{ MAC_PROP_STATUS,	sizeof (link_state_t),	"state"},
2237663SSowmini.Varadhan@Sun.COM 
2247663SSowmini.Varadhan@Sun.COM 	{ MAC_PROP_AUTONEG,	sizeof (uint8_t),	"adv_autoneg_cap"},
2255903Ssowmini 
2267663SSowmini.Varadhan@Sun.COM 	{ MAC_PROP_MTU,		sizeof (uint32_t),	"mtu"},
2275903Ssowmini 
2287663SSowmini.Varadhan@Sun.COM 	{ MAC_PROP_FLOWCTRL,	sizeof (link_flowctrl_t), "flowctrl"},
2297663SSowmini.Varadhan@Sun.COM 
2307663SSowmini.Varadhan@Sun.COM 	{ MAC_PROP_ZONE,	sizeof (dld_ioc_zid_t),	"zone"},
2315903Ssowmini 
2327663SSowmini.Varadhan@Sun.COM 	{ MAC_PROP_AUTOPUSH,	sizeof (struct dlautopush), "autopush"},
2337663SSowmini.Varadhan@Sun.COM 
2347663SSowmini.Varadhan@Sun.COM 	{ MAC_PROP_ADV_1000FDX_CAP, sizeof (uint8_t),	"adv_1000fdx_cap"},
2357663SSowmini.Varadhan@Sun.COM 
2367663SSowmini.Varadhan@Sun.COM 	{ MAC_PROP_EN_1000FDX_CAP, sizeof (uint8_t),	"en_1000fdx_cap"},
2375903Ssowmini 
2387663SSowmini.Varadhan@Sun.COM 	{ MAC_PROP_ADV_1000HDX_CAP, sizeof (uint8_t),	"adv_1000hdx_cap"},
2395903Ssowmini 
2407663SSowmini.Varadhan@Sun.COM 	{ MAC_PROP_EN_1000HDX_CAP, sizeof (uint8_t),	"en_1000hdx_cap"},
2417663SSowmini.Varadhan@Sun.COM 
2427663SSowmini.Varadhan@Sun.COM 	{ MAC_PROP_ADV_100FDX_CAP, sizeof (uint8_t),	"adv_100fdx_cap"},
2437342SAruna.Ramakrishna@Sun.COM 
2447663SSowmini.Varadhan@Sun.COM 	{ MAC_PROP_EN_100FDX_CAP, sizeof (uint8_t),	"en_100fdx_cap"},
2457663SSowmini.Varadhan@Sun.COM 
2467663SSowmini.Varadhan@Sun.COM 	{ MAC_PROP_ADV_100HDX_CAP, sizeof (uint8_t),	"adv_100hdx_cap"},
2477663SSowmini.Varadhan@Sun.COM 
2487663SSowmini.Varadhan@Sun.COM 	{ MAC_PROP_EN_100HDX_CAP, sizeof (uint8_t),	"en_100hdx_cap"},
2497342SAruna.Ramakrishna@Sun.COM 
2507663SSowmini.Varadhan@Sun.COM 	{ MAC_PROP_ADV_10FDX_CAP, sizeof (uint8_t),	"adv_10fdx_cap"},
2517663SSowmini.Varadhan@Sun.COM 
2527663SSowmini.Varadhan@Sun.COM 	{ MAC_PROP_EN_10FDX_CAP, sizeof (uint8_t),	"en_10fdx_cap"},
2535903Ssowmini 
2547663SSowmini.Varadhan@Sun.COM 	{ MAC_PROP_ADV_10HDX_CAP, sizeof (uint8_t),	"adv_10hdx_cap"},
2557663SSowmini.Varadhan@Sun.COM 
2567663SSowmini.Varadhan@Sun.COM 	{ MAC_PROP_EN_10HDX_CAP, sizeof (uint8_t),	"en_10hdx_cap"},
2575903Ssowmini 
2587663SSowmini.Varadhan@Sun.COM 	{ MAC_PROP_WL_ESSID,	sizeof (wl_linkstatus_t), "essid"},
2597663SSowmini.Varadhan@Sun.COM 
2607663SSowmini.Varadhan@Sun.COM 	{ MAC_PROP_WL_BSSID,	sizeof (wl_bssid_t),	"bssid"},
2615903Ssowmini 
2627663SSowmini.Varadhan@Sun.COM 	{ MAC_PROP_WL_BSSTYPE,	sizeof (wl_bss_type_t),	"bsstype"},
2637663SSowmini.Varadhan@Sun.COM 
2647663SSowmini.Varadhan@Sun.COM 	{ MAC_PROP_WL_LINKSTATUS, sizeof (wl_linkstatus_t), "wl_linkstatus"},
2657663SSowmini.Varadhan@Sun.COM 
2667663SSowmini.Varadhan@Sun.COM 	/* wl_rates_t has variable length */
2677663SSowmini.Varadhan@Sun.COM 	{ MAC_PROP_WL_DESIRED_RATES, sizeof (wl_rates_t), "desired_rates"},
2685903Ssowmini 
2697663SSowmini.Varadhan@Sun.COM 	/* wl_rates_t has variable length */
2707663SSowmini.Varadhan@Sun.COM 	{ MAC_PROP_WL_SUPPORTED_RATES, sizeof (wl_rates_t), "supported_rates"},
2717663SSowmini.Varadhan@Sun.COM 
2727663SSowmini.Varadhan@Sun.COM 	{ MAC_PROP_WL_AUTH_MODE, sizeof (wl_authmode_t), "authmode"},
2735903Ssowmini 
2747663SSowmini.Varadhan@Sun.COM 	{ MAC_PROP_WL_ENCRYPTION, sizeof (wl_encryption_t), "encryption"},
2757663SSowmini.Varadhan@Sun.COM 
2767663SSowmini.Varadhan@Sun.COM 	{ MAC_PROP_WL_RSSI,	sizeof (wl_rssi_t),	"signal"},
2775903Ssowmini 
2787663SSowmini.Varadhan@Sun.COM 	{ MAC_PROP_WL_PHY_CONFIG, sizeof (wl_phy_conf_t), "phy_conf"},
2797663SSowmini.Varadhan@Sun.COM 
2807663SSowmini.Varadhan@Sun.COM 	{ MAC_PROP_WL_CAPABILITY, sizeof (wl_capability_t), "capability"},
2815903Ssowmini 
2827663SSowmini.Varadhan@Sun.COM 	{ MAC_PROP_WL_WPA,	sizeof (wl_wpa_t),	"wpa"},
2837663SSowmini.Varadhan@Sun.COM 
2847663SSowmini.Varadhan@Sun.COM 	/*  wl_wpa_ess_t has variable length */
2857663SSowmini.Varadhan@Sun.COM 	{ MAC_PROP_WL_SCANRESULTS, sizeof (wl_wpa_ess_t), "scan_results"},
2865903Ssowmini 
2877663SSowmini.Varadhan@Sun.COM 	{ MAC_PROP_WL_POWER_MODE, sizeof (wl_ps_mode_t), "powermode"},
2887663SSowmini.Varadhan@Sun.COM 
2897663SSowmini.Varadhan@Sun.COM 	{ MAC_PROP_WL_RADIO,	sizeof (dladm_wlan_radio_t), "wl_radio"},
2905903Ssowmini 
2917663SSowmini.Varadhan@Sun.COM 	{ MAC_PROP_WL_ESS_LIST, sizeof (wl_ess_list_t),	"wl_ess_list"},
2927663SSowmini.Varadhan@Sun.COM 
2937663SSowmini.Varadhan@Sun.COM 	{ MAC_PROP_WL_KEY_TAB,	sizeof (wl_wep_key_tab_t), "wl_wep_key"},
2945903Ssowmini 
2957663SSowmini.Varadhan@Sun.COM 	{ MAC_PROP_WL_CREATE_IBSS, sizeof (wl_create_ibss_t), "createibss"},
2967663SSowmini.Varadhan@Sun.COM 
2977663SSowmini.Varadhan@Sun.COM 	/* wl_wpa_ie_t has variable length */
2987663SSowmini.Varadhan@Sun.COM 	{ MAC_PROP_WL_SETOPTIE,	sizeof (wl_wpa_ie_t),	"set_ie"},
2995903Ssowmini 
3007663SSowmini.Varadhan@Sun.COM 	{ MAC_PROP_WL_DELKEY,	sizeof (wl_del_key_t),	"wpa_del_key"},
3017663SSowmini.Varadhan@Sun.COM 
3027663SSowmini.Varadhan@Sun.COM 	{ MAC_PROP_WL_KEY,	sizeof (wl_key_t),	"wl_key"},
3035903Ssowmini 
3047663SSowmini.Varadhan@Sun.COM 	{ MAC_PROP_WL_MLME,	sizeof (wl_mlme_t),	"mlme"},
3057663SSowmini.Varadhan@Sun.COM 
3067663SSowmini.Varadhan@Sun.COM 	{ MAC_PROP_PRIVATE,	0,			"driver-private"}
3075903Ssowmini };
3085903Ssowmini 
3095903Ssowmini static  val_desc_t	link_duplex_vals[] = {
3105903Ssowmini 	{ "half", 	LINK_DUPLEX_HALF	},
3115903Ssowmini 	{ "full", 	LINK_DUPLEX_HALF	}
3125903Ssowmini };
3135903Ssowmini static  val_desc_t	link_status_vals[] = {
3145903Ssowmini 	{ "up",		LINK_STATE_UP		},
3155903Ssowmini 	{ "down",	LINK_STATE_DOWN		}
3165903Ssowmini };
3175903Ssowmini static  val_desc_t	link_01_vals[] = {
3185903Ssowmini 	{ "1",		1			},
3195903Ssowmini 	{ "0",		0			}
3205903Ssowmini };
3215903Ssowmini static  val_desc_t	link_flow_vals[] = {
3225903Ssowmini 	{ "no",		LINK_FLOWCTRL_NONE	},
3235903Ssowmini 	{ "tx",		LINK_FLOWCTRL_TX	},
3245903Ssowmini 	{ "rx",		LINK_FLOWCTRL_RX	},
3255903Ssowmini 	{ "bi",		LINK_FLOWCTRL_BI	}
3265903Ssowmini };
3275903Ssowmini 
3285903Ssowmini #define	VALCNT(vals)    (sizeof ((vals)) / sizeof (val_desc_t))
3295903Ssowmini 
3305895Syz147064 static val_desc_t	dladm_wlan_radio_vals[] = {
3315895Syz147064 	{ "on",		DLADM_WLAN_RADIO_ON	},
3325895Syz147064 	{ "off",	DLADM_WLAN_RADIO_OFF	}
3335895Syz147064 };
3345895Syz147064 
3355895Syz147064 static val_desc_t	dladm_wlan_powermode_vals[] = {
3365895Syz147064 	{ "off",	DLADM_WLAN_PM_OFF	},
3375895Syz147064 	{ "fast",	DLADM_WLAN_PM_FAST	},
3385895Syz147064 	{ "max",	DLADM_WLAN_PM_MAX	}
3395895Syz147064 };
3405895Syz147064 
3413448Sdh155122 static prop_desc_t	prop_table[] = {
3425895Syz147064 
3435903Ssowmini 	{ "channel",	{ NULL, 0 },
3445903Ssowmini 	    NULL, 0, NULL, NULL,
3455895Syz147064 	    do_get_channel_prop, NULL, 0,
3465903Ssowmini 	    DATALINK_CLASS_PHYS, DL_WIFI },
3475895Syz147064 
3485895Syz147064 	{ "powermode",	{ "off", DLADM_WLAN_PM_OFF },
3495895Syz147064 	    dladm_wlan_powermode_vals, VALCNT(dladm_wlan_powermode_vals),
3505895Syz147064 	    do_set_powermode_prop, NULL,
3515895Syz147064 	    do_get_powermode_prop, NULL, 0,
3525903Ssowmini 	    DATALINK_CLASS_PHYS, DL_WIFI },
3535895Syz147064 
3545895Syz147064 	{ "radio",	{ "on", DLADM_WLAN_RADIO_ON },
3555895Syz147064 	    dladm_wlan_radio_vals, VALCNT(dladm_wlan_radio_vals),
3565895Syz147064 	    do_set_radio_prop, NULL,
3575895Syz147064 	    do_get_radio_prop, NULL, 0,
3585903Ssowmini 	    DATALINK_CLASS_PHYS, DL_WIFI },
3595895Syz147064 
3605895Syz147064 	{ "speed",	{ "", 0 }, NULL, 0,
3615895Syz147064 	    do_set_rate_prop, do_get_rate_mod,
3625895Syz147064 	    do_get_rate_prop, do_check_rate, 0,
3635960Ssowmini 	    DATALINK_CLASS_PHYS, DATALINK_ANY_MEDIATYPE },
3645895Syz147064 
3656512Ssowmini 	{ "autopush",	{ "", 0 }, NULL, 0,
3667342SAruna.Ramakrishna@Sun.COM 	    i_dladm_set_public_prop, NULL,
3677342SAruna.Ramakrishna@Sun.COM 	    do_get_autopush, do_check_autopush, PD_CHECK_ALLOC,
3685903Ssowmini 	    DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
3695895Syz147064 
3706512Ssowmini 	{ "zone",	{ "", 0 }, NULL, 0,
3713448Sdh155122 	    do_set_zone, NULL,
3727342SAruna.Ramakrishna@Sun.COM 	    do_get_zone, do_check_zone, PD_TEMPONLY|PD_CHECK_ALLOC,
3735903Ssowmini 	    DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
3745903Ssowmini 
3756512Ssowmini 	{ "duplex", { "", 0 },
3765903Ssowmini 	    link_duplex_vals, VALCNT(link_duplex_vals),
3777342SAruna.Ramakrishna@Sun.COM 	    NULL, NULL, i_dladm_duplex_get, NULL,
3785903Ssowmini 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
3795903Ssowmini 
3805960Ssowmini 	{ "state", { "up", LINK_STATE_UP },
3815903Ssowmini 	    link_status_vals, VALCNT(link_status_vals),
3827342SAruna.Ramakrishna@Sun.COM 	    NULL, NULL, i_dladm_status_get, NULL,
3836512Ssowmini 	    0, DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
3845903Ssowmini 
3855903Ssowmini 	{ "adv_autoneg_cap", { "1", 1 },
3865903Ssowmini 	    link_01_vals, VALCNT(link_01_vals),
3877342SAruna.Ramakrishna@Sun.COM 	    i_dladm_set_public_prop, NULL, i_dladm_binary_get, NULL,
3885903Ssowmini 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
3895903Ssowmini 
3906512Ssowmini 	{ "mtu", { "", 0 }, NULL, 0,
3917342SAruna.Ramakrishna@Sun.COM 	    i_dladm_set_public_prop, NULL, i_dladm_uint32_get,
3927342SAruna.Ramakrishna@Sun.COM 	    i_dladm_defmtu_check, 0, DATALINK_CLASS_ALL,
3937342SAruna.Ramakrishna@Sun.COM 	    DATALINK_ANY_MEDIATYPE },
3945903Ssowmini 
3956512Ssowmini 	{ "flowctrl", { "", 0 },
3965903Ssowmini 	    link_flow_vals, VALCNT(link_flow_vals),
3977342SAruna.Ramakrishna@Sun.COM 	    i_dladm_set_public_prop, NULL, i_dladm_flowctl_get, NULL,
3985903Ssowmini 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
3995903Ssowmini 
4006512Ssowmini 	{ "adv_1000fdx_cap", { "", 0 },
4016512Ssowmini 	    link_01_vals, VALCNT(link_01_vals),
4027342SAruna.Ramakrishna@Sun.COM 	    NULL, NULL, i_dladm_binary_get, NULL,
4035903Ssowmini 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
4045903Ssowmini 
4056512Ssowmini 	{ "en_1000fdx_cap", { "", 0 },
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 	{ "adv_1000hdx_cap", { "", 0 },
4115903Ssowmini 	    link_01_vals, VALCNT(link_01_vals),
4127342SAruna.Ramakrishna@Sun.COM 	    NULL, NULL, i_dladm_binary_get, NULL,
4135903Ssowmini 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
4145903Ssowmini 
4156512Ssowmini 	{ "en_1000hdx_cap", { "", 0 },
4165903Ssowmini 	    link_01_vals, VALCNT(link_01_vals),
4177342SAruna.Ramakrishna@Sun.COM 	    i_dladm_set_public_prop, NULL, i_dladm_binary_get, NULL,
4185903Ssowmini 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
4195903Ssowmini 
4206512Ssowmini 	{ "adv_100fdx_cap", { "", 0 },
4215903Ssowmini 	    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_100fdx_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_100hdx_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_100hdx_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_10fdx_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_10fdx_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_10hdx_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_10hdx_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 
4603448Sdh155122 };
4613448Sdh155122 
4625895Syz147064 #define	DLADM_MAX_PROPS	(sizeof (prop_table) / sizeof (prop_desc_t))
4635895Syz147064 
4647663SSowmini.Varadhan@Sun.COM /*
4657663SSowmini.Varadhan@Sun.COM  * when retrieving  private properties, we pass down a buffer with
4667663SSowmini.Varadhan@Sun.COM  * DLADM_PROP_BUF_CHUNK of space for the driver to return the property value.
4677663SSowmini.Varadhan@Sun.COM  */
4687663SSowmini.Varadhan@Sun.COM #define	DLADM_PROP_BUF_CHUNK	1024
4697663SSowmini.Varadhan@Sun.COM 
4705895Syz147064 static dladm_status_t	i_dladm_set_linkprop_db(datalink_id_t, const char *,
4715895Syz147064 			    char **, uint_t);
4725895Syz147064 static dladm_status_t	i_dladm_get_linkprop_db(datalink_id_t, const char *,
4735895Syz147064 			    char **, uint_t *);
4745895Syz147064 static dladm_status_t	i_dladm_set_single_prop(datalink_id_t, datalink_class_t,
4755895Syz147064 			    uint32_t, prop_desc_t *, char **, uint_t, uint_t);
4765895Syz147064 static dladm_status_t	i_dladm_set_linkprop(datalink_id_t, const char *,
4775895Syz147064 			    char **, uint_t, uint_t);
4786512Ssowmini static dladm_status_t	i_dladm_getset_defval(prop_desc_t *, datalink_id_t,
4796512Ssowmini 			    datalink_media_t, uint_t);
4805895Syz147064 /*
4815895Syz147064  * Unfortunately, MAX_SCAN_SUPPORT_RATES is too small to allow all
4825895Syz147064  * rates to be retrieved. However, we cannot increase it at this
4835895Syz147064  * time because it will break binary compatibility with unbundled
4845895Syz147064  * WiFi drivers and utilities. So for now we define an additional
4855895Syz147064  * constant, MAX_SUPPORT_RATES, to allow all rates to be retrieved.
4865895Syz147064  */
4875895Syz147064 #define	MAX_SUPPORT_RATES	64
4885895Syz147064 
4895895Syz147064 #define	AP_ANCHOR	"[anchor]"
4905895Syz147064 #define	AP_DELIMITER	'.'
4915895Syz147064 
4925895Syz147064 static dladm_status_t
4935895Syz147064 do_check_prop(prop_desc_t *pdp, char **prop_val, uint_t val_cnt,
4945895Syz147064     val_desc_t *vdp)
4955895Syz147064 {
4965895Syz147064 	int		i, j;
4975895Syz147064 	dladm_status_t	status = DLADM_STATUS_OK;
4983147Sxc151355 
4995895Syz147064 	for (j = 0; j < val_cnt; j++) {
5005895Syz147064 		for (i = 0; i < pdp->pd_noptval; i++) {
5015895Syz147064 			if (strcasecmp(*prop_val,
5025895Syz147064 			    pdp->pd_optval[i].vd_name) == 0) {
5035895Syz147064 				break;
5045895Syz147064 			}
5055895Syz147064 		}
5065895Syz147064 		if (i == pdp->pd_noptval) {
5075895Syz147064 			status = DLADM_STATUS_BADVAL;
5085895Syz147064 			goto done;
5095895Syz147064 		}
5105895Syz147064 		(void) memcpy(vdp + j, &pdp->pd_optval[i], sizeof (val_desc_t));
5115895Syz147064 	}
5125895Syz147064 
5135895Syz147064 done:
5145895Syz147064 	return (status);
5155895Syz147064 }
5165895Syz147064 
5175895Syz147064 static dladm_status_t
5185895Syz147064 i_dladm_set_single_prop(datalink_id_t linkid, datalink_class_t class,
5195895Syz147064     uint32_t media, prop_desc_t *pdp, char **prop_val, uint_t val_cnt,
5205895Syz147064     uint_t flags)
5213147Sxc151355 {
5225895Syz147064 	dladm_status_t	status = DLADM_STATUS_OK;
5235895Syz147064 	val_desc_t	*vdp = NULL;
5245895Syz147064 	boolean_t	needfree = B_FALSE;
5255895Syz147064 	uint_t		cnt, i;
5263147Sxc151355 
5275895Syz147064 	if (!(pdp->pd_class & class))
5285895Syz147064 		return (DLADM_STATUS_BADARG);
5295895Syz147064 
5305895Syz147064 	if (!DATALINK_MEDIA_ACCEPTED(pdp->pd_dmedia, media))
5313147Sxc151355 		return (DLADM_STATUS_BADARG);
5323147Sxc151355 
5335895Syz147064 	if ((flags & DLADM_OPT_PERSIST) && (pdp->pd_flags & PD_TEMPONLY))
5345895Syz147064 		return (DLADM_STATUS_TEMPONLY);
5355895Syz147064 
5365895Syz147064 	if (!(flags & DLADM_OPT_ACTIVE))
5375895Syz147064 		return (DLADM_STATUS_OK);
5385895Syz147064 
5395895Syz147064 	if (pdp->pd_set == NULL)
5405895Syz147064 		return (DLADM_STATUS_PROPRDONLY);
5413448Sdh155122 
5425903Ssowmini 	if (pdp->pd_flags & PD_CHECK_ALLOC)
5435903Ssowmini 		needfree = B_TRUE;
5445903Ssowmini 	else
5455903Ssowmini 		needfree = B_FALSE;
5465895Syz147064 	if (prop_val != NULL) {
5475895Syz147064 		vdp = malloc(sizeof (val_desc_t) * val_cnt);
5485895Syz147064 		if (vdp == NULL)
5495895Syz147064 			return (DLADM_STATUS_NOMEM);
5505895Syz147064 
5515903Ssowmini 
5525895Syz147064 		if (pdp->pd_check != NULL) {
5535903Ssowmini 			status = pdp->pd_check(pdp, linkid, prop_val, val_cnt,
5545960Ssowmini 			    vdp, media);
5555895Syz147064 		} else if (pdp->pd_optval != NULL) {
5565895Syz147064 			status = do_check_prop(pdp, prop_val, val_cnt, vdp);
5575895Syz147064 		} else {
5583448Sdh155122 			status = DLADM_STATUS_BADARG;
5593147Sxc151355 		}
5605895Syz147064 
5613147Sxc151355 		if (status != DLADM_STATUS_OK)
5625895Syz147064 			goto done;
5635895Syz147064 
5645895Syz147064 		cnt = val_cnt;
5655895Syz147064 	} else {
5665895Syz147064 		if (pdp->pd_defval.vd_name == NULL)
5675895Syz147064 			return (DLADM_STATUS_NOTSUP);
5685895Syz147064 
5697342SAruna.Ramakrishna@Sun.COM 		cnt = 1;
5707342SAruna.Ramakrishna@Sun.COM 		if ((pdp->pd_flags & PD_CHECK_ALLOC) != 0 ||
5716512Ssowmini 		    strlen(pdp->pd_defval.vd_name) > 0) {
5726512Ssowmini 			if ((vdp = malloc(sizeof (val_desc_t))) == NULL)
5736512Ssowmini 				return (DLADM_STATUS_NOMEM);
5747342SAruna.Ramakrishna@Sun.COM 
5757342SAruna.Ramakrishna@Sun.COM 			if (pdp->pd_check != NULL) {
5767342SAruna.Ramakrishna@Sun.COM 				status = pdp->pd_check(pdp, linkid, prop_val,
5777342SAruna.Ramakrishna@Sun.COM 				    cnt, vdp, media);
5787342SAruna.Ramakrishna@Sun.COM 				if (status != DLADM_STATUS_OK)
5797342SAruna.Ramakrishna@Sun.COM 					goto done;
5807342SAruna.Ramakrishna@Sun.COM 			} else {
5817342SAruna.Ramakrishna@Sun.COM 				(void) memcpy(vdp, &pdp->pd_defval,
5827342SAruna.Ramakrishna@Sun.COM 				    sizeof (val_desc_t));
5837342SAruna.Ramakrishna@Sun.COM 			}
5846512Ssowmini 		} else {
5856512Ssowmini 			status = i_dladm_getset_defval(pdp, linkid,
5866512Ssowmini 			    media, flags);
5876512Ssowmini 			return (status);
5886512Ssowmini 		}
5895895Syz147064 	}
5905960Ssowmini 	status = pdp->pd_set(pdp, linkid, vdp, cnt, flags, media);
5915895Syz147064 	if (needfree) {
5925895Syz147064 		for (i = 0; i < cnt; i++)
5935903Ssowmini 			free((void *)((val_desc_t *)vdp + i)->vd_val);
5943147Sxc151355 	}
5955895Syz147064 done:
5965895Syz147064 	free(vdp);
5975895Syz147064 	return (status);
5985895Syz147064 }
5995895Syz147064 
6005895Syz147064 static dladm_status_t
6015895Syz147064 i_dladm_set_linkprop(datalink_id_t linkid, const char *prop_name,
6025895Syz147064     char **prop_val, uint_t val_cnt, uint_t flags)
6035895Syz147064 {
6045895Syz147064 	int			i;
6055895Syz147064 	boolean_t		found = B_FALSE;
6065895Syz147064 	datalink_class_t	class;
6075895Syz147064 	uint32_t		media;
6085895Syz147064 	dladm_status_t		status = DLADM_STATUS_OK;
6095895Syz147064 
6105895Syz147064 	status = dladm_datalink_id2info(linkid, NULL, &class, &media, NULL, 0);
6115895Syz147064 	if (status != DLADM_STATUS_OK)
6125895Syz147064 		return (status);
6135895Syz147064 
6145895Syz147064 	for (i = 0; i < DLADM_MAX_PROPS; i++) {
6155895Syz147064 		prop_desc_t	*pdp = &prop_table[i];
6165895Syz147064 		dladm_status_t	s;
6175895Syz147064 
6185895Syz147064 		if (prop_name != NULL &&
6195895Syz147064 		    (strcasecmp(prop_name, pdp->pd_name) != 0))
6205895Syz147064 			continue;
6215895Syz147064 
6225895Syz147064 		found = B_TRUE;
6235895Syz147064 		s = i_dladm_set_single_prop(linkid, class, media, pdp, prop_val,
6245895Syz147064 		    val_cnt, flags);
6253448Sdh155122 
6265895Syz147064 		if (prop_name != NULL) {
6275895Syz147064 			status = s;
6285895Syz147064 			break;
6295895Syz147064 		} else {
6305895Syz147064 			if (s != DLADM_STATUS_OK &&
6315895Syz147064 			    s != DLADM_STATUS_NOTSUP)
6325895Syz147064 				status = s;
6335895Syz147064 		}
6345895Syz147064 	}
6355903Ssowmini 	if (!found) {
6365903Ssowmini 		if (prop_name[0] == '_') {
6375903Ssowmini 			/* other private properties */
6387342SAruna.Ramakrishna@Sun.COM 			status = i_dladm_set_prop(linkid, prop_name, prop_val,
6395903Ssowmini 			    val_cnt, flags);
6405903Ssowmini 		} else  {
6415903Ssowmini 			status = DLADM_STATUS_NOTFOUND;
6425903Ssowmini 		}
6435903Ssowmini 	}
6445895Syz147064 
6455895Syz147064 	return (status);
6465895Syz147064 }
6475895Syz147064 
6485895Syz147064 /*
6495895Syz147064  * Set/reset link property for specific link
6505895Syz147064  */
6515895Syz147064 dladm_status_t
6525895Syz147064 dladm_set_linkprop(datalink_id_t linkid, const char *prop_name, char **prop_val,
6535895Syz147064     uint_t val_cnt, uint_t flags)
6545895Syz147064 {
6555895Syz147064 	dladm_status_t	status = DLADM_STATUS_OK;
6565895Syz147064 
6575895Syz147064 	if ((linkid == DATALINK_INVALID_LINKID) || (flags == 0) ||
6585895Syz147064 	    (prop_val == NULL && val_cnt > 0) ||
6595895Syz147064 	    (prop_val != NULL && val_cnt == 0) ||
6605895Syz147064 	    (prop_name == NULL && prop_val != NULL)) {
6615895Syz147064 		return (DLADM_STATUS_BADARG);
6625895Syz147064 	}
6635895Syz147064 
6645895Syz147064 	status = i_dladm_set_linkprop(linkid, prop_name, prop_val,
6655895Syz147064 	    val_cnt, flags);
6665895Syz147064 	if (status != DLADM_STATUS_OK)
6675895Syz147064 		return (status);
6685895Syz147064 
6695895Syz147064 	if (flags & DLADM_OPT_PERSIST) {
6705895Syz147064 		status = i_dladm_set_linkprop_db(linkid, prop_name,
6713147Sxc151355 		    prop_val, val_cnt);
6723147Sxc151355 	}
6733147Sxc151355 	return (status);
6743147Sxc151355 }
6753147Sxc151355 
6765895Syz147064 /*
6775895Syz147064  * Walk link properties of the given specific link.
6785895Syz147064  */
6793147Sxc151355 dladm_status_t
6805895Syz147064 dladm_walk_linkprop(datalink_id_t linkid, void *arg,
6815895Syz147064     int (*func)(datalink_id_t, const char *, void *))
6823147Sxc151355 {
6835895Syz147064 	dladm_status_t		status;
6845895Syz147064 	datalink_class_t	class;
6855895Syz147064 	uint_t			media;
6865895Syz147064 	int			i;
6875895Syz147064 
6885895Syz147064 	if (linkid == DATALINK_INVALID_LINKID || func == NULL)
6895895Syz147064 		return (DLADM_STATUS_BADARG);
6905895Syz147064 
6915895Syz147064 	status = dladm_datalink_id2info(linkid, NULL, &class, &media, NULL, 0);
6925895Syz147064 	if (status != DLADM_STATUS_OK)
6935895Syz147064 		return (status);
6945895Syz147064 
6955895Syz147064 	for (i = 0; i < DLADM_MAX_PROPS; i++) {
6965895Syz147064 		if (!(prop_table[i].pd_class & class))
6975895Syz147064 			continue;
6985895Syz147064 
6995895Syz147064 		if (!DATALINK_MEDIA_ACCEPTED(prop_table[i].pd_dmedia, media))
7005895Syz147064 			continue;
7015895Syz147064 
7025895Syz147064 		if (func(linkid, prop_table[i].pd_name, arg) ==
7035895Syz147064 		    DLADM_WALK_TERMINATE) {
7045895Syz147064 			break;
7055895Syz147064 		}
7065895Syz147064 	}
7075895Syz147064 
7085895Syz147064 	return (DLADM_STATUS_OK);
7095895Syz147064 }
7103448Sdh155122 
7115895Syz147064 /*
7125895Syz147064  * Get linkprop of the given specific link.
7135895Syz147064  */
7145895Syz147064 dladm_status_t
7155895Syz147064 dladm_get_linkprop(datalink_id_t linkid, dladm_prop_type_t type,
7165895Syz147064     const char *prop_name, char **prop_val, uint_t *val_cntp)
7175895Syz147064 {
7185895Syz147064 	dladm_status_t		status = DLADM_STATUS_OK;
7195895Syz147064 	datalink_class_t	class;
7205895Syz147064 	uint_t			media;
7215895Syz147064 	prop_desc_t		*pdp;
7226512Ssowmini 	uint_t			cnt, dld_flags = 0;
7235895Syz147064 	int			i;
724*8118SVasumathi.Sundaram@Sun.COM 	uint_t			perm_flags;
7255895Syz147064 
7266512Ssowmini 	if (type == DLADM_PROP_VAL_DEFAULT)
7276789Sam223141 		dld_flags = MAC_PROP_DEFAULT;
7286512Ssowmini 
7295895Syz147064 	if (linkid == DATALINK_INVALID_LINKID || prop_name == NULL ||
7305895Syz147064 	    prop_val == NULL || val_cntp == NULL || *val_cntp == 0)
7315895Syz147064 		return (DLADM_STATUS_BADARG);
7325895Syz147064 
7335895Syz147064 	for (i = 0; i < DLADM_MAX_PROPS; i++)
7345895Syz147064 		if (strcasecmp(prop_name, prop_table[i].pd_name) == 0)
7355895Syz147064 			break;
7365895Syz147064 
7375903Ssowmini 	if (i == DLADM_MAX_PROPS) {
7385903Ssowmini 		if (prop_name[0] == '_') {
7395903Ssowmini 			/*
7405903Ssowmini 			 * private property.
7415903Ssowmini 			 */
7427342SAruna.Ramakrishna@Sun.COM 			return (i_dladm_get_prop(linkid, prop_name,
7436512Ssowmini 			    prop_val, val_cntp, type, dld_flags));
7445903Ssowmini 		} else {
7455903Ssowmini 			return (DLADM_STATUS_NOTFOUND);
7465903Ssowmini 		}
7475903Ssowmini 	}
7485895Syz147064 
7495895Syz147064 	pdp = &prop_table[i];
7505895Syz147064 
7515895Syz147064 	status = dladm_datalink_id2info(linkid, NULL, &class, &media, NULL, 0);
7525895Syz147064 	if (status != DLADM_STATUS_OK)
7535895Syz147064 		return (status);
7545895Syz147064 
7555895Syz147064 	if (!(pdp->pd_class & class))
7565895Syz147064 		return (DLADM_STATUS_BADARG);
7575895Syz147064 
7585895Syz147064 	if (!DATALINK_MEDIA_ACCEPTED(pdp->pd_dmedia, media))
7593147Sxc151355 		return (DLADM_STATUS_BADARG);
7603147Sxc151355 
7615895Syz147064 	switch (type) {
7625895Syz147064 	case DLADM_PROP_VAL_CURRENT:
7636512Ssowmini 		status = pdp->pd_get(pdp, linkid, prop_val, val_cntp, media,
764*8118SVasumathi.Sundaram@Sun.COM 		    dld_flags, &perm_flags);
765*8118SVasumathi.Sundaram@Sun.COM 		break;
766*8118SVasumathi.Sundaram@Sun.COM 
767*8118SVasumathi.Sundaram@Sun.COM 	case DLADM_PROP_VAL_PERM:
768*8118SVasumathi.Sundaram@Sun.COM 		if (pdp->pd_set == NULL) {
769*8118SVasumathi.Sundaram@Sun.COM 			perm_flags = MAC_PROP_PERM_READ;
770*8118SVasumathi.Sundaram@Sun.COM 			*val_cntp = 1;
771*8118SVasumathi.Sundaram@Sun.COM 		} else {
772*8118SVasumathi.Sundaram@Sun.COM 			status = pdp->pd_get(pdp, linkid, prop_val, val_cntp,
773*8118SVasumathi.Sundaram@Sun.COM 			    media, dld_flags, &perm_flags);
774*8118SVasumathi.Sundaram@Sun.COM 		}
775*8118SVasumathi.Sundaram@Sun.COM 
776*8118SVasumathi.Sundaram@Sun.COM 		*prop_val[0] = '\0';
777*8118SVasumathi.Sundaram@Sun.COM 		switch (perm_flags) {
778*8118SVasumathi.Sundaram@Sun.COM 			case MAC_PROP_PERM_READ:
779*8118SVasumathi.Sundaram@Sun.COM 				(void) strncpy(*prop_val, PERM_READ_ONLY,
780*8118SVasumathi.Sundaram@Sun.COM 				    DLADM_PROP_VAL_MAX);
781*8118SVasumathi.Sundaram@Sun.COM 				break;
782*8118SVasumathi.Sundaram@Sun.COM 			case MAC_PROP_PERM_RW:
783*8118SVasumathi.Sundaram@Sun.COM 				(void) strncpy(*prop_val, PERM_READ_WRITE,
784*8118SVasumathi.Sundaram@Sun.COM 				    DLADM_PROP_VAL_MAX);
785*8118SVasumathi.Sundaram@Sun.COM 				break;
786*8118SVasumathi.Sundaram@Sun.COM 		}
7875895Syz147064 		break;
7885895Syz147064 
7895895Syz147064 	case DLADM_PROP_VAL_DEFAULT:
7906768Sar224390 		/*
7916768Sar224390 		 * If defaults are not defined for the property,
7926768Sar224390 		 * pd_defval.vd_name should be null. If the driver
7936768Sar224390 		 * has to be contacted for the value, vd_name should
7946768Sar224390 		 * be the empty string (""). Otherwise, dladm will
7956768Sar224390 		 * just print whatever is in the table.
7966768Sar224390 		 */
7975895Syz147064 		if (pdp->pd_defval.vd_name == NULL) {
7985895Syz147064 			status = DLADM_STATUS_NOTSUP;
7995895Syz147064 			break;
8005895Syz147064 		}
8016512Ssowmini 
8026512Ssowmini 		if (strlen(pdp->pd_defval.vd_name) == 0) {
8036512Ssowmini 			status = pdp->pd_get(pdp, linkid, prop_val, val_cntp,
804*8118SVasumathi.Sundaram@Sun.COM 			    media, dld_flags, &perm_flags);
8056512Ssowmini 		} else {
8066512Ssowmini 			(void) strcpy(*prop_val, pdp->pd_defval.vd_name);
8076512Ssowmini 		}
8085895Syz147064 		*val_cntp = 1;
8095895Syz147064 		break;
8103448Sdh155122 
8115895Syz147064 	case DLADM_PROP_VAL_MODIFIABLE:
8125895Syz147064 		if (pdp->pd_getmod != NULL) {
8135903Ssowmini 			status = pdp->pd_getmod(pdp, linkid, prop_val,
814*8118SVasumathi.Sundaram@Sun.COM 			    val_cntp, media, dld_flags, &perm_flags);
8155895Syz147064 			break;
8165895Syz147064 		}
8175895Syz147064 		cnt = pdp->pd_noptval;
8185895Syz147064 		if (cnt == 0) {
8195895Syz147064 			status = DLADM_STATUS_NOTSUP;
8205895Syz147064 		} else if (cnt > *val_cntp) {
8215895Syz147064 			status = DLADM_STATUS_TOOSMALL;
8225895Syz147064 		} else {
8235895Syz147064 			for (i = 0; i < cnt; i++) {
8245895Syz147064 				(void) strcpy(prop_val[i],
8255895Syz147064 				    pdp->pd_optval[i].vd_name);
8265895Syz147064 			}
8275895Syz147064 			*val_cntp = cnt;
8285895Syz147064 		}
8295895Syz147064 		break;
8305895Syz147064 	case DLADM_PROP_VAL_PERSISTENT:
8315895Syz147064 		if (pdp->pd_flags & PD_TEMPONLY)
8325895Syz147064 			return (DLADM_STATUS_TEMPONLY);
8335895Syz147064 		status = i_dladm_get_linkprop_db(linkid, prop_name,
8345895Syz147064 		    prop_val, val_cntp);
8355895Syz147064 		break;
8365895Syz147064 	default:
8375895Syz147064 		status = DLADM_STATUS_BADARG;
8385895Syz147064 		break;
8393147Sxc151355 	}
8403448Sdh155122 
8415895Syz147064 	return (status);
8425895Syz147064 }
8435895Syz147064 
8445895Syz147064 /*ARGSUSED*/
8455895Syz147064 static int
8465895Syz147064 i_dladm_init_one_prop(datalink_id_t linkid, const char *prop_name, void *arg)
8475895Syz147064 {
8485895Syz147064 	char	*buf, **propvals;
8495895Syz147064 	uint_t	i, valcnt = DLADM_MAX_PROP_VALCNT;
8505895Syz147064 
8515895Syz147064 	if ((buf = malloc((sizeof (char *) + DLADM_PROP_VAL_MAX) *
8525895Syz147064 	    DLADM_MAX_PROP_VALCNT)) == NULL) {
8535895Syz147064 		return (DLADM_WALK_CONTINUE);
8545895Syz147064 	}
8555895Syz147064 
8565895Syz147064 	propvals = (char **)(void *)buf;
8575895Syz147064 	for (i = 0; i < valcnt; i++) {
8585895Syz147064 		propvals[i] = buf +
8595895Syz147064 		    sizeof (char *) * DLADM_MAX_PROP_VALCNT +
8605895Syz147064 		    i * DLADM_PROP_VAL_MAX;
8615895Syz147064 	}
8625895Syz147064 
8635895Syz147064 	if (dladm_get_linkprop(linkid, DLADM_PROP_VAL_PERSISTENT, prop_name,
8645895Syz147064 	    propvals, &valcnt) != DLADM_STATUS_OK) {
8655895Syz147064 		goto done;
8665895Syz147064 	}
8675895Syz147064 
8685895Syz147064 	(void) dladm_set_linkprop(linkid, prop_name, propvals, valcnt,
8695895Syz147064 	    DLADM_OPT_ACTIVE);
8705895Syz147064 
8715895Syz147064 done:
8725895Syz147064 	if (buf != NULL)
8735895Syz147064 		free(buf);
8745895Syz147064 
8755895Syz147064 	return (DLADM_WALK_CONTINUE);
8765895Syz147064 }
8775895Syz147064 
8785895Syz147064 /*ARGSUSED*/
8795895Syz147064 static int
8805895Syz147064 i_dladm_init_linkprop(datalink_id_t linkid, void *arg)
8815895Syz147064 {
8826916Sartem 	(void) dladm_init_linkprop(linkid, B_TRUE);
8835895Syz147064 	return (DLADM_WALK_CONTINUE);
8845895Syz147064 }
8855895Syz147064 
8865895Syz147064 dladm_status_t
8876916Sartem dladm_init_linkprop(datalink_id_t linkid, boolean_t any_media)
8885895Syz147064 {
8896916Sartem 	datalink_media_t	dmedia;
8906916Sartem 	uint32_t		media;
8916916Sartem 
8926916Sartem 	dmedia = any_media ? DATALINK_ANY_MEDIATYPE : DL_WIFI;
8936916Sartem 
8945895Syz147064 	if (linkid == DATALINK_ALL_LINKID) {
8955895Syz147064 		(void) dladm_walk_datalink_id(i_dladm_init_linkprop, NULL,
8966916Sartem 		    DATALINK_CLASS_ALL, dmedia, DLADM_OPT_PERSIST);
8976916Sartem 	} else if (any_media || ((dladm_datalink_id2info(linkid, NULL, NULL,
8986916Sartem 	    &media, NULL, 0) == DLADM_STATUS_OK) &&
8996916Sartem 	    DATALINK_MEDIA_ACCEPTED(dmedia, media))) {
9005895Syz147064 		(void) dladm_walk_linkprop(linkid, NULL, i_dladm_init_one_prop);
9013448Sdh155122 	}
9023448Sdh155122 	return (DLADM_STATUS_OK);
9033147Sxc151355 }
9043147Sxc151355 
9055903Ssowmini /* ARGSUSED */
9065895Syz147064 static dladm_status_t
9075903Ssowmini do_get_zone(struct prop_desc *pd, datalink_id_t linkid,
908*8118SVasumathi.Sundaram@Sun.COM     char **prop_val, uint_t *val_cnt, datalink_media_t media, uint_t flags,
909*8118SVasumathi.Sundaram@Sun.COM     uint_t *perm_flags)
9103147Sxc151355 {
9115895Syz147064 	char		zone_name[ZONENAME_MAX];
9125895Syz147064 	zoneid_t	zid;
9135895Syz147064 	dladm_status_t	status;
9147342SAruna.Ramakrishna@Sun.COM 	char		*cp;
9157342SAruna.Ramakrishna@Sun.COM 	dld_ioc_macprop_t	*dip;
9163147Sxc151355 
9176512Ssowmini 	if (flags != 0)
9186512Ssowmini 		return (DLADM_STATUS_NOTSUP);
9196512Ssowmini 
9207342SAruna.Ramakrishna@Sun.COM 	dip = i_dladm_get_public_prop(linkid, pd->pd_name, flags, &status);
9215895Syz147064 	if (status != DLADM_STATUS_OK)
9223448Sdh155122 		return (status);
9233448Sdh155122 
924*8118SVasumathi.Sundaram@Sun.COM 	*perm_flags = dip->pr_perm_flags;
9257342SAruna.Ramakrishna@Sun.COM 	cp = dip->pr_val;
9267342SAruna.Ramakrishna@Sun.COM 	(void) memcpy(&zid, cp, sizeof (zid));
9277342SAruna.Ramakrishna@Sun.COM 	free(dip);
9287342SAruna.Ramakrishna@Sun.COM 
9295895Syz147064 	*val_cnt = 1;
9305895Syz147064 	if (zid != GLOBAL_ZONEID) {
931*8118SVasumathi.Sundaram@Sun.COM 		if (getzonenamebyid(zid, zone_name, sizeof (zone_name)) < 0) {
932*8118SVasumathi.Sundaram@Sun.COM 			*perm_flags = 0;
9335895Syz147064 			return (dladm_errno2status(errno));
934*8118SVasumathi.Sundaram@Sun.COM 		}
9353147Sxc151355 
9365895Syz147064 		(void) strncpy(*prop_val, zone_name, DLADM_PROP_VAL_MAX);
9373147Sxc151355 	} else {
9385895Syz147064 		*prop_val[0] = '\0';
939*8118SVasumathi.Sundaram@Sun.COM 		*perm_flags = 0;
9403147Sxc151355 	}
9413147Sxc151355 
9423448Sdh155122 	return (DLADM_STATUS_OK);
9433448Sdh155122 }
9443448Sdh155122 
9453448Sdh155122 typedef int (*zone_get_devroot_t)(char *, char *, size_t);
9463448Sdh155122 
9473448Sdh155122 static int
9483448Sdh155122 i_dladm_get_zone_dev(char *zone_name, char *dev, size_t devlen)
9493448Sdh155122 {
9503448Sdh155122 	char			root[MAXPATHLEN];
9513448Sdh155122 	zone_get_devroot_t	real_zone_get_devroot;
9523448Sdh155122 	void			*dlhandle;
9533448Sdh155122 	void			*sym;
9543448Sdh155122 	int			ret;
9553448Sdh155122 
9563448Sdh155122 	if ((dlhandle = dlopen("libzonecfg.so.1", RTLD_LAZY)) == NULL)
9573448Sdh155122 		return (-1);
9583448Sdh155122 
9593448Sdh155122 	if ((sym = dlsym(dlhandle, "zone_get_devroot")) == NULL) {
9603448Sdh155122 		(void) dlclose(dlhandle);
9613448Sdh155122 		return (-1);
9623448Sdh155122 	}
9633448Sdh155122 
9643448Sdh155122 	real_zone_get_devroot = (zone_get_devroot_t)sym;
9653448Sdh155122 
9663448Sdh155122 	if ((ret = real_zone_get_devroot(zone_name, root, sizeof (root))) == 0)
9673448Sdh155122 		(void) snprintf(dev, devlen, "%s%s", root, "/dev");
9683448Sdh155122 	(void) dlclose(dlhandle);
9693448Sdh155122 	return (ret);
9703448Sdh155122 }
9713448Sdh155122 
9723448Sdh155122 static dladm_status_t
9735895Syz147064 i_dladm_update_deventry(zoneid_t zid, datalink_id_t linkid, boolean_t add)
9743448Sdh155122 {
9753448Sdh155122 	char		path[MAXPATHLEN];
9765895Syz147064 	char		name[MAXLINKNAMELEN];
9773448Sdh155122 	di_prof_t	prof = NULL;
9783448Sdh155122 	char		zone_name[ZONENAME_MAX];
9793448Sdh155122 	dladm_status_t	status;
9805895Syz147064 	int		ret;
9813448Sdh155122 
9823448Sdh155122 	if (getzonenamebyid(zid, zone_name, sizeof (zone_name)) < 0)
9833448Sdh155122 		return (dladm_errno2status(errno));
9843448Sdh155122 	if (i_dladm_get_zone_dev(zone_name, path, sizeof (path)) != 0)
9853448Sdh155122 		return (dladm_errno2status(errno));
9863448Sdh155122 	if (di_prof_init(path, &prof) != 0)
9873448Sdh155122 		return (dladm_errno2status(errno));
9883448Sdh155122 
9895895Syz147064 	status = dladm_linkid2legacyname(linkid, name, MAXLINKNAMELEN);
9905895Syz147064 	if (status != DLADM_STATUS_OK)
9915895Syz147064 		goto cleanup;
9925895Syz147064 
9935895Syz147064 	if (add)
9945895Syz147064 		ret = di_prof_add_dev(prof, name);
9955895Syz147064 	else
9965895Syz147064 		ret = di_prof_add_exclude(prof, name);
9975895Syz147064 
9985895Syz147064 	if (ret != 0) {
9993448Sdh155122 		status = dladm_errno2status(errno);
10003448Sdh155122 		goto cleanup;
10013448Sdh155122 	}
10023448Sdh155122 
10033448Sdh155122 	if (di_prof_commit(prof) != 0)
10043448Sdh155122 		status = dladm_errno2status(errno);
10053448Sdh155122 cleanup:
10063448Sdh155122 	if (prof)
10073448Sdh155122 		di_prof_fini(prof);
10083448Sdh155122 
10093448Sdh155122 	return (status);
10103448Sdh155122 }
10113448Sdh155122 
10125903Ssowmini /* ARGSUSED */
10133448Sdh155122 static dladm_status_t
10145960Ssowmini do_set_zone(prop_desc_t *pd, datalink_id_t linkid, val_desc_t *vdp,
10155960Ssowmini     uint_t val_cnt, uint_t flags, datalink_media_t media)
10163448Sdh155122 {
10177342SAruna.Ramakrishna@Sun.COM 	dladm_status_t	status = DLADM_STATUS_OK;
10183448Sdh155122 	zoneid_t	zid_old, zid_new;
10195895Syz147064 	char		link[MAXLINKNAMELEN];
10207342SAruna.Ramakrishna@Sun.COM 	char		*cp;
10217342SAruna.Ramakrishna@Sun.COM 	dld_ioc_macprop_t	*dip;
10227342SAruna.Ramakrishna@Sun.COM 	dld_ioc_zid_t		*dzp;
10233448Sdh155122 
10243448Sdh155122 	if (val_cnt != 1)
10253448Sdh155122 		return (DLADM_STATUS_BADVALCNT);
10263448Sdh155122 
10277342SAruna.Ramakrishna@Sun.COM 	dzp = (dld_ioc_zid_t *)vdp->vd_val;
10287342SAruna.Ramakrishna@Sun.COM 
10297342SAruna.Ramakrishna@Sun.COM 	/*
10307342SAruna.Ramakrishna@Sun.COM 	 * If diz_is_ppa_hack is set, then an implicit vlan must be created.
10317342SAruna.Ramakrishna@Sun.COM 	 * There is no old value to compare against, and vdp->vd_val is
10327342SAruna.Ramakrishna@Sun.COM 	 * already populated with the zoneid and linkname in the function
10337342SAruna.Ramakrishna@Sun.COM 	 * do_check_zone().
10347342SAruna.Ramakrishna@Sun.COM 	 */
10357342SAruna.Ramakrishna@Sun.COM 
10367342SAruna.Ramakrishna@Sun.COM 	if (dzp->diz_is_ppa_hack) {
10377342SAruna.Ramakrishna@Sun.COM 		zid_old = GLOBAL_ZONEID;
10387342SAruna.Ramakrishna@Sun.COM 	} else {
10397342SAruna.Ramakrishna@Sun.COM 		dip = i_dladm_get_public_prop(linkid, pd->pd_name,
10407342SAruna.Ramakrishna@Sun.COM 		    flags, &status);
10417342SAruna.Ramakrishna@Sun.COM 		if (status != DLADM_STATUS_OK)
10427342SAruna.Ramakrishna@Sun.COM 			return (status);
10437342SAruna.Ramakrishna@Sun.COM 
10447342SAruna.Ramakrishna@Sun.COM 		cp = dip->pr_val;
10457342SAruna.Ramakrishna@Sun.COM 		(void) memcpy(&zid_old, cp, sizeof (zid_old));
10467342SAruna.Ramakrishna@Sun.COM 		free(dip);
10477342SAruna.Ramakrishna@Sun.COM 	}
10487342SAruna.Ramakrishna@Sun.COM 
10497342SAruna.Ramakrishna@Sun.COM 	zid_new = dzp->diz_zid;
10507342SAruna.Ramakrishna@Sun.COM 	(void) strlcpy(link, dzp->diz_link, MAXLINKNAMELEN);
10513448Sdh155122 
10523448Sdh155122 	/* Do nothing if setting to current value */
10533448Sdh155122 	if (zid_new == zid_old)
10545895Syz147064 		return (status);
10555895Syz147064 
10565895Syz147064 	if (zid_new != GLOBAL_ZONEID) {
10575895Syz147064 		/*
10585895Syz147064 		 * If the new zoneid is the global zone, we could destroy
10595895Syz147064 		 * the link (in the case of an implicitly-created VLAN) as a
10607342SAruna.Ramakrishna@Sun.COM 		 * result of setting the zoneid. In that case, we defer the
10617342SAruna.Ramakrishna@Sun.COM 		 * operation to the end of this function to avoid recreating
10627342SAruna.Ramakrishna@Sun.COM 		 * the VLAN and getting a different linkid during the rollback
10637342SAruna.Ramakrishna@Sun.COM 		 * if other operation fails.
10645895Syz147064 		 *
10657342SAruna.Ramakrishna@Sun.COM 		 * Otherwise, this operation will hold a reference to the
10665895Syz147064 		 * link and prevent a link renaming, so we need to do it
10675895Syz147064 		 * before other operations.
10685895Syz147064 		 */
10697342SAruna.Ramakrishna@Sun.COM 		status = i_dladm_set_public_prop(pd, linkid, vdp, val_cnt,
10707342SAruna.Ramakrishna@Sun.COM 		    flags, media);
10715895Syz147064 		if (status != DLADM_STATUS_OK)
10725895Syz147064 			return (status);
10735895Syz147064 	}
10745895Syz147064 
10753448Sdh155122 	if (zid_old != GLOBAL_ZONEID) {
10765895Syz147064 		if (zone_remove_datalink(zid_old, link) != 0 &&
10773448Sdh155122 		    errno != ENXIO) {
10783448Sdh155122 			status = dladm_errno2status(errno);
10793448Sdh155122 			goto rollback1;
10803448Sdh155122 		}
10813448Sdh155122 
10825895Syz147064 		/*
10835895Syz147064 		 * It is okay to fail to update the /dev entry (some
10845895Syz147064 		 * vanity-named links do not have a /dev entry).
10855895Syz147064 		 */
10865895Syz147064 		(void) i_dladm_update_deventry(zid_old, linkid, B_FALSE);
10875895Syz147064 	}
10885895Syz147064 
10895895Syz147064 	if (zid_new != GLOBAL_ZONEID) {
10905895Syz147064 		if (zone_add_datalink(zid_new, link) != 0) {
10915895Syz147064 			status = dladm_errno2status(errno);
10925895Syz147064 			goto rollback2;
10935895Syz147064 		}
10945895Syz147064 
10957342SAruna.Ramakrishna@Sun.COM 		if (dzp->diz_is_ppa_hack) {
10967342SAruna.Ramakrishna@Sun.COM 			if ((status = dladm_name2info(link, &linkid, NULL, NULL,
10977342SAruna.Ramakrishna@Sun.COM 			    NULL)) != DLADM_STATUS_OK) {
10987342SAruna.Ramakrishna@Sun.COM 				return (status);
10997342SAruna.Ramakrishna@Sun.COM 			}
11007342SAruna.Ramakrishna@Sun.COM 		}
11017342SAruna.Ramakrishna@Sun.COM 
11025895Syz147064 		(void) i_dladm_update_deventry(zid_new, linkid, B_TRUE);
11035895Syz147064 	} else {
11047342SAruna.Ramakrishna@Sun.COM 		status = i_dladm_set_public_prop(pd, linkid, vdp, val_cnt,
11057342SAruna.Ramakrishna@Sun.COM 		    flags, media);
11063448Sdh155122 		if (status != DLADM_STATUS_OK)
11073448Sdh155122 			goto rollback2;
11083448Sdh155122 	}
11093448Sdh155122 
11103448Sdh155122 	return (DLADM_STATUS_OK);
11113448Sdh155122 
11123448Sdh155122 rollback2:
11133448Sdh155122 	if (zid_old != GLOBAL_ZONEID)
11145895Syz147064 		(void) i_dladm_update_deventry(zid_old, linkid, B_TRUE);
11155895Syz147064 	if (zid_old != GLOBAL_ZONEID)
11165895Syz147064 		(void) zone_add_datalink(zid_old, link);
11173448Sdh155122 rollback1:
11187342SAruna.Ramakrishna@Sun.COM 	if (zid_new != GLOBAL_ZONEID) {
11197342SAruna.Ramakrishna@Sun.COM 		dzp->diz_zid = zid_old;
11207342SAruna.Ramakrishna@Sun.COM 		(void) i_dladm_set_public_prop(pd, linkid, vdp, val_cnt,
11217342SAruna.Ramakrishna@Sun.COM 		    flags, media);
11227342SAruna.Ramakrishna@Sun.COM 	}
11237342SAruna.Ramakrishna@Sun.COM 
11243448Sdh155122 	return (status);
11253448Sdh155122 }
11263448Sdh155122 
11273448Sdh155122 /* ARGSUSED */
11283448Sdh155122 static dladm_status_t
11295903Ssowmini do_check_zone(struct prop_desc *pd, datalink_id_t linkid, char **prop_val,
11305960Ssowmini     uint_t val_cnt, val_desc_t *vdp, datalink_media_t media)
11313448Sdh155122 {
11327342SAruna.Ramakrishna@Sun.COM 	char		*zone_name;
11337342SAruna.Ramakrishna@Sun.COM 	char		linkname[MAXLINKNAMELEN];
11347342SAruna.Ramakrishna@Sun.COM 	zoneid_t	zoneid;
11357342SAruna.Ramakrishna@Sun.COM 	char		*cp;
11367342SAruna.Ramakrishna@Sun.COM 	dladm_status_t	status = DLADM_STATUS_OK;
11377342SAruna.Ramakrishna@Sun.COM 	boolean_t	is_ppa_hack = B_FALSE;
11387342SAruna.Ramakrishna@Sun.COM 	dld_ioc_zid_t	*dzp;
11393448Sdh155122 
11403448Sdh155122 	if (val_cnt != 1)
11413448Sdh155122 		return (DLADM_STATUS_BADVALCNT);
11423448Sdh155122 
11437342SAruna.Ramakrishna@Sun.COM 	dzp = malloc(sizeof (dld_ioc_zid_t));
11447342SAruna.Ramakrishna@Sun.COM 	if (dzp == NULL)
11457342SAruna.Ramakrishna@Sun.COM 		return (DLADM_STATUS_NOMEM);
11463448Sdh155122 
11477342SAruna.Ramakrishna@Sun.COM 	if (prop_val) {
11487342SAruna.Ramakrishna@Sun.COM 		/*
11497342SAruna.Ramakrishna@Sun.COM 		 * The prop_val contains zone_name{:linkname}. The linkname is
11507342SAruna.Ramakrishna@Sun.COM 		 * present only when the link is a ppa-hacked vlan.
11517342SAruna.Ramakrishna@Sun.COM 		 */
11527342SAruna.Ramakrishna@Sun.COM 		cp = strchr(*prop_val, ':');
11537342SAruna.Ramakrishna@Sun.COM 		if (cp) {
11547342SAruna.Ramakrishna@Sun.COM 			(void) strlcpy(linkname, cp + 1, MAXLINKNAMELEN);
11557342SAruna.Ramakrishna@Sun.COM 			*cp = '\0';
11567342SAruna.Ramakrishna@Sun.COM 			is_ppa_hack = B_TRUE;
11577342SAruna.Ramakrishna@Sun.COM 		} else {
11587342SAruna.Ramakrishna@Sun.COM 			status = dladm_datalink_id2info(linkid, NULL, NULL,
11597342SAruna.Ramakrishna@Sun.COM 			    NULL, linkname, MAXLINKNAMELEN);
11607342SAruna.Ramakrishna@Sun.COM 			if (status != DLADM_STATUS_OK) {
11617342SAruna.Ramakrishna@Sun.COM 				goto done;
11627342SAruna.Ramakrishna@Sun.COM 			}
11637342SAruna.Ramakrishna@Sun.COM 		}
11647342SAruna.Ramakrishna@Sun.COM 		zone_name = *prop_val;
11657342SAruna.Ramakrishna@Sun.COM 	} else {
11667342SAruna.Ramakrishna@Sun.COM 		zone_name = GLOBAL_ZONENAME;
11677342SAruna.Ramakrishna@Sun.COM 		if ((status = dladm_datalink_id2info(linkid, NULL, NULL, NULL,
11687342SAruna.Ramakrishna@Sun.COM 		    linkname, MAXLINKNAMELEN)) != DLADM_STATUS_OK) {
11697342SAruna.Ramakrishna@Sun.COM 			goto done;
11707342SAruna.Ramakrishna@Sun.COM 		}
11717342SAruna.Ramakrishna@Sun.COM 	}
11727342SAruna.Ramakrishna@Sun.COM 
11737342SAruna.Ramakrishna@Sun.COM 	if (strlen(linkname) > MAXLINKNAMELEN) {
11747342SAruna.Ramakrishna@Sun.COM 		status = DLADM_STATUS_BADVAL;
11757342SAruna.Ramakrishna@Sun.COM 		goto done;
11767342SAruna.Ramakrishna@Sun.COM 	}
11777342SAruna.Ramakrishna@Sun.COM 
11787342SAruna.Ramakrishna@Sun.COM 	if ((zoneid = getzoneidbyname(zone_name)) == -1) {
11797342SAruna.Ramakrishna@Sun.COM 		status = DLADM_STATUS_BADVAL;
11807342SAruna.Ramakrishna@Sun.COM 		goto done;
11817342SAruna.Ramakrishna@Sun.COM 	}
11827342SAruna.Ramakrishna@Sun.COM 
11837342SAruna.Ramakrishna@Sun.COM 	if (zoneid != GLOBAL_ZONEID) {
11843448Sdh155122 		ushort_t	flags;
11853448Sdh155122 
11867342SAruna.Ramakrishna@Sun.COM 		if (zone_getattr(zoneid, ZONE_ATTR_FLAGS, &flags,
11873448Sdh155122 		    sizeof (flags)) < 0) {
11887342SAruna.Ramakrishna@Sun.COM 			status = dladm_errno2status(errno);
11897342SAruna.Ramakrishna@Sun.COM 			goto done;
11903448Sdh155122 		}
11913448Sdh155122 
11923448Sdh155122 		if (!(flags & ZF_NET_EXCL)) {
11937342SAruna.Ramakrishna@Sun.COM 			status = DLADM_STATUS_BADVAL;
11947342SAruna.Ramakrishna@Sun.COM 			goto done;
11953448Sdh155122 		}
11963448Sdh155122 	}
11973448Sdh155122 
11987342SAruna.Ramakrishna@Sun.COM 	(void) memset(dzp, 0, sizeof (dld_ioc_zid_t));
11997342SAruna.Ramakrishna@Sun.COM 
12007342SAruna.Ramakrishna@Sun.COM 	dzp->diz_zid = zoneid;
12017342SAruna.Ramakrishna@Sun.COM 	(void) strlcpy(dzp->diz_link, linkname, MAXLINKNAMELEN);
12027342SAruna.Ramakrishna@Sun.COM 	dzp->diz_is_ppa_hack = is_ppa_hack;
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
12135903Ssowmini do_get_autopush(struct prop_desc *pd, datalink_id_t linkid,
1214*8118SVasumathi.Sundaram@Sun.COM     char **prop_val, uint_t *val_cnt, datalink_media_t media, uint_t flags,
1215*8118SVasumathi.Sundaram@Sun.COM     uint_t *perm_flags)
12165895Syz147064 {
12177342SAruna.Ramakrishna@Sun.COM 	struct		dlautopush dlap;
12187342SAruna.Ramakrishna@Sun.COM 	int		i, len;
12197342SAruna.Ramakrishna@Sun.COM 	dladm_status_t	status;
12207342SAruna.Ramakrishna@Sun.COM 	dld_ioc_macprop_t	*dip;
12215895Syz147064 
12226789Sam223141 	if (flags & MAC_PROP_DEFAULT)
12237776SSowmini.Varadhan@Sun.COM 		return (DLADM_STATUS_NOTDEFINED);
12246512Ssowmini 
12255895Syz147064 	*val_cnt = 1;
12267342SAruna.Ramakrishna@Sun.COM 	dip = i_dladm_get_public_prop(linkid, pd->pd_name, flags, &status);
12277342SAruna.Ramakrishna@Sun.COM 	if (dip == NULL) {
12285895Syz147064 		(*prop_val)[0] = '\0';
12295895Syz147064 		goto done;
12305895Syz147064 	}
12317342SAruna.Ramakrishna@Sun.COM 	(void) memcpy(&dlap, dip->pr_val, sizeof (dlap));
12325895Syz147064 
12337342SAruna.Ramakrishna@Sun.COM 	for (i = 0, len = 0; i < dlap.dap_npush; i++) {
12345895Syz147064 		if (i != 0) {
12355895Syz147064 			(void) snprintf(*prop_val + len,
12365895Syz147064 			    DLADM_PROP_VAL_MAX - len, "%c", AP_DELIMITER);
12375895Syz147064 			len += 1;
12385895Syz147064 		}
12395895Syz147064 		(void) snprintf(*prop_val + len, DLADM_PROP_VAL_MAX - len,
12407342SAruna.Ramakrishna@Sun.COM 		    "%s", dlap.dap_aplist[i]);
12417342SAruna.Ramakrishna@Sun.COM 		len += strlen(dlap.dap_aplist[i]);
12427342SAruna.Ramakrishna@Sun.COM 		if (dlap.dap_anchor - 1 == i) {
12435895Syz147064 			(void) snprintf(*prop_val + len,
12445895Syz147064 			    DLADM_PROP_VAL_MAX - len, "%c%s", AP_DELIMITER,
12455895Syz147064 			    AP_ANCHOR);
12465895Syz147064 			len += (strlen(AP_ANCHOR) + 1);
12475895Syz147064 		}
12485895Syz147064 	}
12495895Syz147064 
1250*8118SVasumathi.Sundaram@Sun.COM 	*perm_flags = dip->pr_perm_flags;
12517342SAruna.Ramakrishna@Sun.COM 	free(dip);
12525895Syz147064 done:
12535895Syz147064 	return (DLADM_STATUS_OK);
12545895Syz147064 }
12555895Syz147064 
12565895Syz147064 /*
12575895Syz147064  * Add the specified module to the dlautopush structure; returns a
12585895Syz147064  * DLADM_STATUS_* code.
12595895Syz147064  */
12605895Syz147064 dladm_status_t
12615895Syz147064 i_dladm_add_ap_module(const char *module, struct dlautopush *dlap)
12625895Syz147064 {
12635895Syz147064 	if ((strlen(module) == 0) || (strlen(module) > FMNAMESZ))
12645895Syz147064 		return (DLADM_STATUS_BADVAL);
12655895Syz147064 
12665895Syz147064 	if (strncasecmp(module, AP_ANCHOR, strlen(AP_ANCHOR)) == 0) {
12675895Syz147064 		/*
12685895Syz147064 		 * We don't allow multiple anchors, and the anchor must
12695895Syz147064 		 * be after at least one module.
12705895Syz147064 		 */
12715895Syz147064 		if (dlap->dap_anchor != 0)
12725895Syz147064 			return (DLADM_STATUS_BADVAL);
12735895Syz147064 		if (dlap->dap_npush == 0)
12745895Syz147064 			return (DLADM_STATUS_BADVAL);
12755895Syz147064 
12765895Syz147064 		dlap->dap_anchor = dlap->dap_npush;
12775895Syz147064 		return (DLADM_STATUS_OK);
12785895Syz147064 	}
12795895Syz147064 	if (dlap->dap_npush > MAXAPUSH)
12805895Syz147064 		return (DLADM_STATUS_BADVALCNT);
12815895Syz147064 
12825895Syz147064 	(void) strlcpy(dlap->dap_aplist[dlap->dap_npush++], module,
12835895Syz147064 	    FMNAMESZ + 1);
12845895Syz147064 
12855895Syz147064 	return (DLADM_STATUS_OK);
12865895Syz147064 }
12875895Syz147064 
12885895Syz147064 /*
12895895Syz147064  * Currently, both '.' and ' '(space) can be used as the delimiters between
12905895Syz147064  * autopush modules. The former is used in dladm set-linkprop, and the
12915895Syz147064  * latter is used in the autopush(1M) file.
12925895Syz147064  */
12935895Syz147064 /* ARGSUSED */
12945895Syz147064 static dladm_status_t
12955903Ssowmini do_check_autopush(struct prop_desc *pd, datalink_id_t linkid, char **prop_val,
12965960Ssowmini     uint_t val_cnt, val_desc_t *vdp, datalink_media_t media)
12975895Syz147064 {
12985895Syz147064 	char			*module;
12995895Syz147064 	struct dlautopush	*dlap;
13005895Syz147064 	dladm_status_t		status;
13015895Syz147064 	char			val[DLADM_PROP_VAL_MAX];
13025895Syz147064 	char			delimiters[4];
13035895Syz147064 
13045895Syz147064 	if (val_cnt != 1)
13055895Syz147064 		return (DLADM_STATUS_BADVALCNT);
13065895Syz147064 
13077342SAruna.Ramakrishna@Sun.COM 	if (prop_val != NULL) {
13087342SAruna.Ramakrishna@Sun.COM 		dlap = malloc(sizeof (struct dlautopush));
13097342SAruna.Ramakrishna@Sun.COM 		if (dlap == NULL)
13107342SAruna.Ramakrishna@Sun.COM 			return (DLADM_STATUS_NOMEM);
13113448Sdh155122 
13127342SAruna.Ramakrishna@Sun.COM 		(void) memset(dlap, 0, sizeof (struct dlautopush));
13137342SAruna.Ramakrishna@Sun.COM 		(void) snprintf(delimiters, 4, " %c\n", AP_DELIMITER);
13147342SAruna.Ramakrishna@Sun.COM 		bcopy(*prop_val, val, DLADM_PROP_VAL_MAX);
13157342SAruna.Ramakrishna@Sun.COM 		module = strtok(val, delimiters);
13167342SAruna.Ramakrishna@Sun.COM 		while (module != NULL) {
13177342SAruna.Ramakrishna@Sun.COM 			status = i_dladm_add_ap_module(module, dlap);
13187342SAruna.Ramakrishna@Sun.COM 			if (status != DLADM_STATUS_OK)
13197342SAruna.Ramakrishna@Sun.COM 				return (status);
13207342SAruna.Ramakrishna@Sun.COM 			module = strtok(NULL, delimiters);
13217342SAruna.Ramakrishna@Sun.COM 		}
13227342SAruna.Ramakrishna@Sun.COM 
13237342SAruna.Ramakrishna@Sun.COM 		vdp->vd_val = (uintptr_t)dlap;
13247342SAruna.Ramakrishna@Sun.COM 	} else {
13257342SAruna.Ramakrishna@Sun.COM 		vdp->vd_val = 0;
13265895Syz147064 	}
13273448Sdh155122 	return (DLADM_STATUS_OK);
13283448Sdh155122 }
13293448Sdh155122 
13307663SSowmini.Varadhan@Sun.COM #define	WLDP_BUFSIZE (MAX_BUF_LEN - WIFI_BUF_OFFSET)
13317663SSowmini.Varadhan@Sun.COM 
13325903Ssowmini /* ARGSUSED */
13333448Sdh155122 static dladm_status_t
13345903Ssowmini do_get_rate_common(struct prop_desc *pd, datalink_id_t linkid,
13355903Ssowmini     char **prop_val, uint_t *val_cnt, uint_t id)
13363448Sdh155122 {
13375895Syz147064 	wl_rates_t	*wrp;
13385895Syz147064 	uint_t		i;
13395895Syz147064 	dladm_status_t	status = DLADM_STATUS_OK;
13405895Syz147064 
13417663SSowmini.Varadhan@Sun.COM 	wrp = malloc(WLDP_BUFSIZE);
13427663SSowmini.Varadhan@Sun.COM 	if (wrp == NULL)
13437663SSowmini.Varadhan@Sun.COM 		return (DLADM_STATUS_NOMEM);
13445895Syz147064 
13457663SSowmini.Varadhan@Sun.COM 	status = i_dladm_wlan_param(linkid, wrp, id, WLDP_BUFSIZE, B_FALSE);
13465895Syz147064 	if (status != DLADM_STATUS_OK)
13475895Syz147064 		goto done;
13485895Syz147064 
13495895Syz147064 	if (wrp->wl_rates_num > *val_cnt) {
13505895Syz147064 		status = DLADM_STATUS_TOOSMALL;
13515895Syz147064 		goto done;
13525895Syz147064 	}
13535895Syz147064 
13545895Syz147064 	if (wrp->wl_rates_rates[0] == 0) {
13555895Syz147064 		prop_val[0][0] = '\0';
13565895Syz147064 		*val_cnt = 1;
13575895Syz147064 		goto done;
13585895Syz147064 	}
13595895Syz147064 
13605895Syz147064 	for (i = 0; i < wrp->wl_rates_num; i++) {
13615895Syz147064 		(void) snprintf(prop_val[i], DLADM_STRSIZE, "%.*f",
13625895Syz147064 		    wrp->wl_rates_rates[i] % 2,
13635895Syz147064 		    (float)wrp->wl_rates_rates[i] / 2);
13645895Syz147064 	}
13655895Syz147064 	*val_cnt = wrp->wl_rates_num;
13663448Sdh155122 
13675895Syz147064 done:
13687663SSowmini.Varadhan@Sun.COM 	free(wrp);
13695895Syz147064 	return (status);
13705895Syz147064 }
13715895Syz147064 
13725895Syz147064 static dladm_status_t
13735903Ssowmini do_get_rate_prop(struct prop_desc *pd, datalink_id_t linkid,
1374*8118SVasumathi.Sundaram@Sun.COM     char **prop_val, uint_t *val_cnt, datalink_media_t media, uint_t flags,
1375*8118SVasumathi.Sundaram@Sun.COM     uint_t *perm_flags)
13765895Syz147064 {
1377*8118SVasumathi.Sundaram@Sun.COM 	if (media != DL_WIFI) {
1378*8118SVasumathi.Sundaram@Sun.COM 		*perm_flags = MAC_PROP_PERM_READ;
13797342SAruna.Ramakrishna@Sun.COM 		return (i_dladm_speed_get(pd, linkid, prop_val,
13807342SAruna.Ramakrishna@Sun.COM 		    val_cnt, flags));
1381*8118SVasumathi.Sundaram@Sun.COM 	}
13825960Ssowmini 
1383*8118SVasumathi.Sundaram@Sun.COM 	*perm_flags = MAC_PROP_PERM_RW;
13845903Ssowmini 	return (do_get_rate_common(pd, linkid, prop_val, val_cnt,
13857663SSowmini.Varadhan@Sun.COM 	    MAC_PROP_WL_DESIRED_RATES));
13865895Syz147064 }
13875895Syz147064 
13886512Ssowmini /* ARGSUSED */
13895895Syz147064 static dladm_status_t
13905903Ssowmini do_get_rate_mod(struct prop_desc *pd, datalink_id_t linkid,
1391*8118SVasumathi.Sundaram@Sun.COM     char **prop_val, uint_t *val_cnt, datalink_media_t media, uint_t flags,
1392*8118SVasumathi.Sundaram@Sun.COM     uint_t *perm_flags)
13935895Syz147064 {
1394*8118SVasumathi.Sundaram@Sun.COM 	*perm_flags = MAC_PROP_PERM_READ;
1395*8118SVasumathi.Sundaram@Sun.COM 
13965960Ssowmini 	switch (media) {
13975960Ssowmini 	case DL_ETHER:
13986512Ssowmini 		/*
13996512Ssowmini 		 * Speed for ethernet links is unbounded. E.g., 802.11b
14006512Ssowmini 		 * links can have a speed of 5.5 Gbps.
14016512Ssowmini 		 */
14026512Ssowmini 		return (DLADM_STATUS_NOTSUP);
14035960Ssowmini 
14045960Ssowmini 	case DL_WIFI:
14055960Ssowmini 		return (do_get_rate_common(pd, linkid, prop_val, val_cnt,
14067663SSowmini.Varadhan@Sun.COM 		    MAC_PROP_WL_SUPPORTED_RATES));
14075960Ssowmini 	default:
14085960Ssowmini 		return (DLADM_STATUS_BADARG);
14095960Ssowmini 	}
14105895Syz147064 }
14115895Syz147064 
14125895Syz147064 static dladm_status_t
14135895Syz147064 do_set_rate(datalink_id_t linkid, dladm_wlan_rates_t *rates)
14145895Syz147064 {
14155895Syz147064 	int		i;
14165895Syz147064 	uint_t		len;
14175895Syz147064 	wl_rates_t	*wrp;
14185895Syz147064 	dladm_status_t	status = DLADM_STATUS_OK;
14195895Syz147064 
14207663SSowmini.Varadhan@Sun.COM 	wrp = malloc(WLDP_BUFSIZE);
14217663SSowmini.Varadhan@Sun.COM 	if (wrp == NULL)
14225895Syz147064 		return (DLADM_STATUS_NOMEM);
14235895Syz147064 
14247663SSowmini.Varadhan@Sun.COM 	bzero(wrp, WLDP_BUFSIZE);
14255895Syz147064 	for (i = 0; i < rates->wr_cnt; i++)
14265895Syz147064 		wrp->wl_rates_rates[i] = rates->wr_rates[i];
14275895Syz147064 	wrp->wl_rates_num = rates->wr_cnt;
14285895Syz147064 
14295895Syz147064 	len = offsetof(wl_rates_t, wl_rates_rates) +
14305895Syz147064 	    (rates->wr_cnt * sizeof (char)) + WIFI_BUF_OFFSET;
14317663SSowmini.Varadhan@Sun.COM 	status = i_dladm_wlan_param(linkid, wrp, MAC_PROP_WL_DESIRED_RATES,
14327663SSowmini.Varadhan@Sun.COM 	    len, B_TRUE);
14335895Syz147064 
14347663SSowmini.Varadhan@Sun.COM 	free(wrp);
14355895Syz147064 	return (status);
14365895Syz147064 }
14373448Sdh155122 
14385903Ssowmini /* ARGSUSED */
14395895Syz147064 static dladm_status_t
14405903Ssowmini do_set_rate_prop(prop_desc_t *pd, datalink_id_t linkid,
14415960Ssowmini     val_desc_t *vdp, uint_t val_cnt, uint_t flags, datalink_media_t media)
14425895Syz147064 {
14435895Syz147064 	dladm_wlan_rates_t	rates;
14445895Syz147064 	dladm_status_t		status;
14455895Syz147064 
14465960Ssowmini 	/*
14475960Ssowmini 	 * can currently set rate on WIFI links only.
14485960Ssowmini 	 */
14495960Ssowmini 	if (media != DL_WIFI)
14505960Ssowmini 		return (DLADM_STATUS_PROPRDONLY);
14515960Ssowmini 
14525895Syz147064 	if (val_cnt != 1)
14535895Syz147064 		return (DLADM_STATUS_BADVALCNT);
14545895Syz147064 
14555895Syz147064 	rates.wr_cnt = 1;
14565895Syz147064 	rates.wr_rates[0] = vdp[0].vd_val;
14575895Syz147064 
14585895Syz147064 	status = do_set_rate(linkid, &rates);
14595895Syz147064 
14605895Syz147064 done:
14615895Syz147064 	return (status);
14625895Syz147064 }
14633448Sdh155122 
14645895Syz147064 /* ARGSUSED */
14655895Syz147064 static dladm_status_t
14665903Ssowmini do_check_rate(struct prop_desc *pd, datalink_id_t linkid, char **prop_val,
14675960Ssowmini     uint_t val_cnt, val_desc_t *vdp, datalink_media_t media)
14685895Syz147064 {
14695895Syz147064 	int		i;
14705895Syz147064 	uint_t		modval_cnt = MAX_SUPPORT_RATES;
14715895Syz147064 	char		*buf, **modval;
14725895Syz147064 	dladm_status_t	status;
1473*8118SVasumathi.Sundaram@Sun.COM 	uint_t 		perm_flags;
14745895Syz147064 
14755895Syz147064 	if (val_cnt != 1)
14765895Syz147064 		return (DLADM_STATUS_BADVALCNT);
14775895Syz147064 
14785895Syz147064 	buf = malloc((sizeof (char *) + DLADM_STRSIZE) *
14795895Syz147064 	    MAX_SUPPORT_RATES);
14805895Syz147064 	if (buf == NULL) {
14815895Syz147064 		status = DLADM_STATUS_NOMEM;
14825895Syz147064 		goto done;
14835895Syz147064 	}
14843448Sdh155122 
14855895Syz147064 	modval = (char **)(void *)buf;
14865895Syz147064 	for (i = 0; i < MAX_SUPPORT_RATES; i++) {
14875895Syz147064 		modval[i] = buf + sizeof (char *) * MAX_SUPPORT_RATES +
14885895Syz147064 		    i * DLADM_STRSIZE;
14895895Syz147064 	}
14905895Syz147064 
1491*8118SVasumathi.Sundaram@Sun.COM 	status = do_get_rate_mod(NULL, linkid, modval, &modval_cnt, media,
1492*8118SVasumathi.Sundaram@Sun.COM 	    0, &perm_flags);
14935895Syz147064 	if (status != DLADM_STATUS_OK)
14945895Syz147064 		goto done;
14955895Syz147064 
14965895Syz147064 	for (i = 0; i < modval_cnt; i++) {
14975895Syz147064 		if (strcasecmp(*prop_val, modval[i]) == 0) {
14985903Ssowmini 			vdp->vd_val = (uintptr_t)(uint_t)
14995903Ssowmini 			    (atof(*prop_val) * 2);
15005895Syz147064 			status = DLADM_STATUS_OK;
15013448Sdh155122 			break;
15023448Sdh155122 		}
15035895Syz147064 	}
15045895Syz147064 	if (i == modval_cnt)
15055895Syz147064 		status = DLADM_STATUS_BADVAL;
15065895Syz147064 done:
15075895Syz147064 	free(buf);
15085895Syz147064 	return (status);
15095895Syz147064 }
15105895Syz147064 
15115895Syz147064 static dladm_status_t
15127663SSowmini.Varadhan@Sun.COM do_get_phyconf(datalink_id_t linkid, void *buf, int buflen)
15135895Syz147064 {
15147663SSowmini.Varadhan@Sun.COM 	return (i_dladm_wlan_param(linkid, buf, MAC_PROP_WL_PHY_CONFIG,
15157663SSowmini.Varadhan@Sun.COM 	    buflen, B_FALSE));
15165895Syz147064 }
15175895Syz147064 
15185903Ssowmini /* ARGSUSED */
15195895Syz147064 static dladm_status_t
15205903Ssowmini do_get_channel_prop(struct prop_desc *pd, datalink_id_t linkid,
1521*8118SVasumathi.Sundaram@Sun.COM     char **prop_val, uint_t *val_cnt, datalink_media_t media, uint_t flags,
1522*8118SVasumathi.Sundaram@Sun.COM     uint_t *perm_flags)
15235895Syz147064 {
15245895Syz147064 	uint32_t	channel;
15257663SSowmini.Varadhan@Sun.COM 	char		buf[WLDP_BUFSIZE];
15265895Syz147064 	dladm_status_t	status = DLADM_STATUS_OK;
15277663SSowmini.Varadhan@Sun.COM 	wl_phy_conf_t	wl_phy_conf;
15285895Syz147064 
1529*8118SVasumathi.Sundaram@Sun.COM 	*perm_flags = MAC_PROP_PERM_READ;
15307663SSowmini.Varadhan@Sun.COM 	if ((status = do_get_phyconf(linkid, buf, sizeof (buf)))
15317663SSowmini.Varadhan@Sun.COM 	    != DLADM_STATUS_OK)
15325895Syz147064 		goto done;
15335895Syz147064 
15347663SSowmini.Varadhan@Sun.COM 	(void) memcpy(&wl_phy_conf, buf, sizeof (wl_phy_conf));
15357663SSowmini.Varadhan@Sun.COM 	if (!i_dladm_wlan_convert_chan(&wl_phy_conf, &channel)) {
15365895Syz147064 		status = DLADM_STATUS_NOTFOUND;
15375895Syz147064 		goto done;
15385895Syz147064 	}
15395895Syz147064 
15405895Syz147064 	(void) snprintf(*prop_val, DLADM_STRSIZE, "%u", channel);
15415895Syz147064 	*val_cnt = 1;
15423448Sdh155122 
15435895Syz147064 done:
15445895Syz147064 	return (status);
15455895Syz147064 }
15465895Syz147064 
15475895Syz147064 static dladm_status_t
15487663SSowmini.Varadhan@Sun.COM do_get_powermode(datalink_id_t linkid, void *buf, int buflen)
15495895Syz147064 {
15507663SSowmini.Varadhan@Sun.COM 	return (i_dladm_wlan_param(linkid, buf, MAC_PROP_WL_POWER_MODE,
15517663SSowmini.Varadhan@Sun.COM 	    buflen, B_FALSE));
15525895Syz147064 }
15535895Syz147064 
15545903Ssowmini /* ARGSUSED */
15555895Syz147064 static dladm_status_t
15565903Ssowmini do_get_powermode_prop(struct prop_desc *pd, datalink_id_t linkid,
1557*8118SVasumathi.Sundaram@Sun.COM     char **prop_val, uint_t *val_cnt, datalink_media_t media, uint_t flags,
1558*8118SVasumathi.Sundaram@Sun.COM     uint_t *perm_flags)
15595895Syz147064 {
15607663SSowmini.Varadhan@Sun.COM 	wl_ps_mode_t	mode;
15615895Syz147064 	const char	*s;
15627663SSowmini.Varadhan@Sun.COM 	char		buf[WLDP_BUFSIZE];
15635895Syz147064 	dladm_status_t	status = DLADM_STATUS_OK;
15645895Syz147064 
15657663SSowmini.Varadhan@Sun.COM 	if ((status = do_get_powermode(linkid, buf, sizeof (buf)))
15667663SSowmini.Varadhan@Sun.COM 	    != DLADM_STATUS_OK)
15675895Syz147064 		goto done;
15685895Syz147064 
15697663SSowmini.Varadhan@Sun.COM 	(void) memcpy(&mode, buf, sizeof (mode));
15707663SSowmini.Varadhan@Sun.COM 	switch (mode.wl_ps_mode) {
15715895Syz147064 	case WL_PM_AM:
15725895Syz147064 		s = "off";
15735895Syz147064 		break;
15745895Syz147064 	case WL_PM_MPS:
15755895Syz147064 		s = "max";
15765895Syz147064 		break;
15775895Syz147064 	case WL_PM_FAST:
15785895Syz147064 		s = "fast";
15793448Sdh155122 		break;
15803448Sdh155122 	default:
15815895Syz147064 		status = DLADM_STATUS_NOTFOUND;
15825895Syz147064 		goto done;
15835895Syz147064 	}
15845895Syz147064 	(void) snprintf(*prop_val, DLADM_STRSIZE, "%s", s);
15855895Syz147064 	*val_cnt = 1;
15865895Syz147064 
15875895Syz147064 done:
1588*8118SVasumathi.Sundaram@Sun.COM 	if (status == DLADM_STATUS_OK)
1589*8118SVasumathi.Sundaram@Sun.COM 		*perm_flags = MAC_PROP_PERM_RW;
1590*8118SVasumathi.Sundaram@Sun.COM 	else
1591*8118SVasumathi.Sundaram@Sun.COM 		*perm_flags = 0;
15925895Syz147064 	return (status);
15935895Syz147064 }
15945895Syz147064 
15955895Syz147064 static dladm_status_t
15965895Syz147064 do_set_powermode(datalink_id_t linkid, dladm_wlan_powermode_t *pm)
15975895Syz147064 {
15985895Syz147064 	wl_ps_mode_t    ps_mode;
15995895Syz147064 
16005895Syz147064 	(void) memset(&ps_mode, 0xff, sizeof (ps_mode));
16015895Syz147064 
16025895Syz147064 	switch (*pm) {
16035895Syz147064 	case DLADM_WLAN_PM_OFF:
16045895Syz147064 		ps_mode.wl_ps_mode = WL_PM_AM;
16053448Sdh155122 		break;
16065895Syz147064 	case DLADM_WLAN_PM_MAX:
16075895Syz147064 		ps_mode.wl_ps_mode = WL_PM_MPS;
16085895Syz147064 		break;
16095895Syz147064 	case DLADM_WLAN_PM_FAST:
16105895Syz147064 		ps_mode.wl_ps_mode = WL_PM_FAST;
16115895Syz147064 		break;
16125895Syz147064 	default:
16135895Syz147064 		return (DLADM_STATUS_NOTSUP);
16143448Sdh155122 	}
16157663SSowmini.Varadhan@Sun.COM 	return (i_dladm_wlan_param(linkid, &ps_mode, MAC_PROP_WL_POWER_MODE,
16167663SSowmini.Varadhan@Sun.COM 	    sizeof (ps_mode), B_TRUE));
16175895Syz147064 }
16185895Syz147064 
16195895Syz147064 /* ARGSUSED */
16205895Syz147064 static dladm_status_t
16215903Ssowmini do_set_powermode_prop(prop_desc_t *pd, datalink_id_t linkid,
16225960Ssowmini     val_desc_t *vdp, uint_t val_cnt, uint_t flags, datalink_media_t media)
16235895Syz147064 {
16245895Syz147064 	dladm_wlan_powermode_t powermode = (dladm_wlan_powermode_t)vdp->vd_val;
16255895Syz147064 	dladm_status_t status;
16265895Syz147064 
16275895Syz147064 	if (val_cnt != 1)
16285895Syz147064 		return (DLADM_STATUS_BADVALCNT);
16295895Syz147064 
16305895Syz147064 	status = do_set_powermode(linkid, &powermode);
16313448Sdh155122 
16323448Sdh155122 	return (status);
16333448Sdh155122 }
16343448Sdh155122 
16353448Sdh155122 static dladm_status_t
16367663SSowmini.Varadhan@Sun.COM do_get_radio(datalink_id_t linkid, void *buf, int buflen)
16373448Sdh155122 {
16387663SSowmini.Varadhan@Sun.COM 	return (i_dladm_wlan_param(linkid, buf, MAC_PROP_WL_RADIO, buflen,
16397663SSowmini.Varadhan@Sun.COM 	    B_FALSE));
16405895Syz147064 }
16413448Sdh155122 
16425903Ssowmini /* ARGSUSED */
16435895Syz147064 static dladm_status_t
16445903Ssowmini do_get_radio_prop(struct prop_desc *pd, datalink_id_t linkid,
1645*8118SVasumathi.Sundaram@Sun.COM     char **prop_val, uint_t *val_cnt, datalink_media_t media, uint_t flags,
1646*8118SVasumathi.Sundaram@Sun.COM     uint_t *perm_flags)
16475895Syz147064 {
16485895Syz147064 	wl_radio_t	radio;
16495895Syz147064 	const char	*s;
16507663SSowmini.Varadhan@Sun.COM 	char		buf[WLDP_BUFSIZE];
16515895Syz147064 	dladm_status_t	status = DLADM_STATUS_OK;
16523448Sdh155122 
16537663SSowmini.Varadhan@Sun.COM 	if ((status = do_get_radio(linkid, buf, sizeof (buf)))
16547663SSowmini.Varadhan@Sun.COM 	    != DLADM_STATUS_OK)
16555895Syz147064 		goto done;
16563448Sdh155122 
16577663SSowmini.Varadhan@Sun.COM 	(void) memcpy(&radio, buf, sizeof (radio));
16585895Syz147064 	switch (radio) {
16595895Syz147064 	case B_TRUE:
16605895Syz147064 		s = "on";
16615895Syz147064 		break;
16625895Syz147064 	case B_FALSE:
16635895Syz147064 		s = "off";
16645895Syz147064 		break;
16655895Syz147064 	default:
16665895Syz147064 		status = DLADM_STATUS_NOTFOUND;
16675895Syz147064 		goto done;
16685895Syz147064 	}
16695895Syz147064 	(void) snprintf(*prop_val, DLADM_STRSIZE, "%s", s);
16705895Syz147064 	*val_cnt = 1;
16713448Sdh155122 
16725895Syz147064 done:
1673*8118SVasumathi.Sundaram@Sun.COM 	if (status == DLADM_STATUS_OK)
1674*8118SVasumathi.Sundaram@Sun.COM 		*perm_flags = MAC_PROP_PERM_RW;
1675*8118SVasumathi.Sundaram@Sun.COM 	else
1676*8118SVasumathi.Sundaram@Sun.COM 		*perm_flags = 0;
16773448Sdh155122 	return (status);
16783448Sdh155122 }
16793448Sdh155122 
16803448Sdh155122 static dladm_status_t
16815895Syz147064 do_set_radio(datalink_id_t linkid, dladm_wlan_radio_t *radio)
16823448Sdh155122 {
16835895Syz147064 	wl_radio_t r;
16843448Sdh155122 
16855895Syz147064 	switch (*radio) {
16865895Syz147064 	case DLADM_WLAN_RADIO_ON:
16875895Syz147064 		r = B_TRUE;
16885895Syz147064 		break;
16895895Syz147064 	case DLADM_WLAN_RADIO_OFF:
16905895Syz147064 		r = B_FALSE;
16915895Syz147064 		break;
16925895Syz147064 	default:
16935895Syz147064 		return (DLADM_STATUS_NOTSUP);
16945895Syz147064 	}
16957663SSowmini.Varadhan@Sun.COM 	return (i_dladm_wlan_param(linkid, &r, MAC_PROP_WL_RADIO,
16967663SSowmini.Varadhan@Sun.COM 	    sizeof (r), B_TRUE));
16975895Syz147064 }
16983448Sdh155122 
16995895Syz147064 /* ARGSUSED */
17005895Syz147064 static dladm_status_t
17015903Ssowmini do_set_radio_prop(prop_desc_t *pd, datalink_id_t linkid,
17025960Ssowmini     val_desc_t *vdp, uint_t val_cnt, uint_t fags, datalink_media_t media)
17035895Syz147064 {
17045895Syz147064 	dladm_wlan_radio_t radio = (dladm_wlan_radio_t)vdp->vd_val;
17055895Syz147064 	dladm_status_t status;
17063448Sdh155122 
17075895Syz147064 	if (val_cnt != 1)
17085895Syz147064 		return (DLADM_STATUS_BADVALCNT);
17095895Syz147064 
17105895Syz147064 	status = do_set_radio(linkid, &radio);
17113448Sdh155122 
17123448Sdh155122 	return (status);
17133448Sdh155122 }
17143448Sdh155122 
17155895Syz147064 static dladm_status_t
17165895Syz147064 i_dladm_set_linkprop_db(datalink_id_t linkid, const char *prop_name,
17175895Syz147064     char **prop_val, uint_t val_cnt)
17183448Sdh155122 {
17195895Syz147064 	char		buf[MAXLINELEN];
17205895Syz147064 	int		i;
17215895Syz147064 	dladm_conf_t	conf;
17225895Syz147064 	dladm_status_t	status;
17233448Sdh155122 
17245895Syz147064 	status = dladm_read_conf(linkid, &conf);
17255895Syz147064 	if (status != DLADM_STATUS_OK)
17265895Syz147064 		return (status);
17273448Sdh155122 
17285895Syz147064 	/*
17295895Syz147064 	 * reset case.
17305895Syz147064 	 */
17315895Syz147064 	if (val_cnt == 0) {
17325895Syz147064 		status = dladm_unset_conf_field(conf, prop_name);
17335895Syz147064 		if (status == DLADM_STATUS_OK)
17345895Syz147064 			status = dladm_write_conf(conf);
17355895Syz147064 		goto done;
17365895Syz147064 	}
17373448Sdh155122 
17385895Syz147064 	buf[0] = '\0';
17395895Syz147064 	for (i = 0; i < val_cnt; i++) {
17405895Syz147064 		(void) strlcat(buf, prop_val[i], MAXLINELEN);
17415895Syz147064 		if (i != val_cnt - 1)
17425895Syz147064 			(void) strlcat(buf, ",", MAXLINELEN);
17433448Sdh155122 	}
17443448Sdh155122 
17455895Syz147064 	status = dladm_set_conf_field(conf, prop_name, DLADM_TYPE_STR, buf);
17465895Syz147064 	if (status == DLADM_STATUS_OK)
17475895Syz147064 		status = dladm_write_conf(conf);
17485895Syz147064 
17495895Syz147064 done:
17505895Syz147064 	dladm_destroy_conf(conf);
17515895Syz147064 	return (status);
17523448Sdh155122 }
17535895Syz147064 
17545895Syz147064 static dladm_status_t
17555895Syz147064 i_dladm_get_linkprop_db(datalink_id_t linkid, const char *prop_name,
17565895Syz147064     char **prop_val, uint_t *val_cntp)
17575895Syz147064 {
17585895Syz147064 	char		buf[MAXLINELEN], *str;
17595895Syz147064 	uint_t		cnt = 0;
17605895Syz147064 	dladm_conf_t	conf;
17615895Syz147064 	dladm_status_t	status;
17625895Syz147064 
17635895Syz147064 	status = dladm_read_conf(linkid, &conf);
17645895Syz147064 	if (status != DLADM_STATUS_OK)
17655895Syz147064 		return (status);
17665895Syz147064 
17675895Syz147064 	status = dladm_get_conf_field(conf, prop_name, buf, MAXLINELEN);
17685895Syz147064 	if (status != DLADM_STATUS_OK)
17695895Syz147064 		goto done;
17705895Syz147064 
17715895Syz147064 	str = strtok(buf, ",");
17725895Syz147064 	while (str != NULL) {
17735895Syz147064 		if (cnt == *val_cntp) {
17745895Syz147064 			status = DLADM_STATUS_TOOSMALL;
17755895Syz147064 			goto done;
17765895Syz147064 		}
17775895Syz147064 		(void) strlcpy(prop_val[cnt++], str, DLADM_PROP_VAL_MAX);
17785895Syz147064 		str = strtok(NULL, ",");
17795895Syz147064 	}
17805895Syz147064 
17815895Syz147064 	*val_cntp = cnt;
17825895Syz147064 
17835895Syz147064 done:
17845895Syz147064 	dladm_destroy_conf(conf);
17855895Syz147064 	return (status);
17865895Syz147064 }
17875903Ssowmini 
17887663SSowmini.Varadhan@Sun.COM static link_attr_t *
17895903Ssowmini dladm_name2prop(const char *prop_name)
17905903Ssowmini {
17917663SSowmini.Varadhan@Sun.COM 	link_attr_t *p;
17925903Ssowmini 
17937663SSowmini.Varadhan@Sun.COM 	for (p = link_attr; p->pp_id != MAC_PROP_PRIVATE; p++) {
17945903Ssowmini 		if (strcmp(p->pp_name, prop_name) == 0)
17955903Ssowmini 			break;
17965903Ssowmini 	}
17975903Ssowmini 	return (p);
17985903Ssowmini }
17995903Ssowmini 
18007663SSowmini.Varadhan@Sun.COM static link_attr_t *
18017663SSowmini.Varadhan@Sun.COM dladm_id2prop(mac_prop_id_t propid)
18027663SSowmini.Varadhan@Sun.COM {
18037663SSowmini.Varadhan@Sun.COM 	link_attr_t *p;
18047663SSowmini.Varadhan@Sun.COM 
18057663SSowmini.Varadhan@Sun.COM 	for (p = link_attr; p->pp_id != MAC_PROP_PRIVATE; p++) {
18067663SSowmini.Varadhan@Sun.COM 		if (p->pp_id == propid)
18077663SSowmini.Varadhan@Sun.COM 			break;
18087663SSowmini.Varadhan@Sun.COM 	}
18097663SSowmini.Varadhan@Sun.COM 	return (p);
18107663SSowmini.Varadhan@Sun.COM }
18115903Ssowmini 
18126789Sam223141 static dld_ioc_macprop_t *
18137663SSowmini.Varadhan@Sun.COM i_dladm_buf_alloc_impl(size_t valsize, datalink_id_t linkid,
18147663SSowmini.Varadhan@Sun.COM     const char *prop_name, mac_prop_id_t propid, uint_t flags,
18157663SSowmini.Varadhan@Sun.COM     dladm_status_t *status)
18165903Ssowmini {
18175903Ssowmini 	int dsize;
18186789Sam223141 	dld_ioc_macprop_t *dip;
18195903Ssowmini 
18205903Ssowmini 	*status = DLADM_STATUS_OK;
18216789Sam223141 	dsize = MAC_PROP_BUFSIZE(valsize);
18225903Ssowmini 	dip = malloc(dsize);
18235903Ssowmini 	if (dip == NULL) {
18245903Ssowmini 		*status = DLADM_STATUS_NOMEM;
18255903Ssowmini 		return (NULL);
18265903Ssowmini 	}
18275903Ssowmini 	bzero(dip, dsize);
18285903Ssowmini 	dip->pr_valsize = valsize;
18296512Ssowmini 	(void) strlcpy(dip->pr_name, prop_name, sizeof (dip->pr_name));
18306789Sam223141 	dip->pr_version = MAC_PROP_VERSION;
18315960Ssowmini 	dip->pr_linkid = linkid;
18327663SSowmini.Varadhan@Sun.COM 	dip->pr_num = propid;
18336512Ssowmini 	dip->pr_flags = flags;
18345903Ssowmini 	return (dip);
18355903Ssowmini }
18365903Ssowmini 
18377663SSowmini.Varadhan@Sun.COM static dld_ioc_macprop_t *
18387663SSowmini.Varadhan@Sun.COM i_dladm_buf_alloc_by_name(size_t valsize, datalink_id_t linkid,
18397663SSowmini.Varadhan@Sun.COM     const char *prop_name, uint_t flags, dladm_status_t *status)
18407663SSowmini.Varadhan@Sun.COM {
18417663SSowmini.Varadhan@Sun.COM 	link_attr_t *p;
18427663SSowmini.Varadhan@Sun.COM 
18437663SSowmini.Varadhan@Sun.COM 	p = dladm_name2prop(prop_name);
18447663SSowmini.Varadhan@Sun.COM 	valsize = MAX(p->pp_valsize, valsize);
18457663SSowmini.Varadhan@Sun.COM 	return (i_dladm_buf_alloc_impl(valsize, linkid, prop_name, p->pp_id,
18467663SSowmini.Varadhan@Sun.COM 	    flags, status));
18477663SSowmini.Varadhan@Sun.COM }
18487663SSowmini.Varadhan@Sun.COM 
18497663SSowmini.Varadhan@Sun.COM static dld_ioc_macprop_t *
18507663SSowmini.Varadhan@Sun.COM i_dladm_buf_alloc_by_id(size_t valsize, datalink_id_t linkid,
18517663SSowmini.Varadhan@Sun.COM     mac_prop_id_t propid, uint_t flags, dladm_status_t *status)
18527663SSowmini.Varadhan@Sun.COM {
18537663SSowmini.Varadhan@Sun.COM 	link_attr_t *p;
18547663SSowmini.Varadhan@Sun.COM 
18557663SSowmini.Varadhan@Sun.COM 	p = dladm_id2prop(propid);
18567663SSowmini.Varadhan@Sun.COM 	valsize = MAX(p->pp_valsize, valsize);
18577663SSowmini.Varadhan@Sun.COM 	return (i_dladm_buf_alloc_impl(valsize, linkid, p->pp_name, propid,
18587663SSowmini.Varadhan@Sun.COM 	    flags, status));
18597663SSowmini.Varadhan@Sun.COM }
18607663SSowmini.Varadhan@Sun.COM 
18615903Ssowmini /* ARGSUSED */
18625903Ssowmini static dladm_status_t
18637342SAruna.Ramakrishna@Sun.COM i_dladm_set_public_prop(prop_desc_t *pd, datalink_id_t linkid,
18645960Ssowmini     val_desc_t *vdp, uint_t val_cnt, uint_t flags, datalink_media_t media)
18655903Ssowmini {
18666789Sam223141 	dld_ioc_macprop_t	*dip;
18675903Ssowmini 	dladm_status_t	status = DLADM_STATUS_OK;
18685903Ssowmini 	uint8_t		u8;
18695903Ssowmini 	uint16_t	u16;
18705903Ssowmini 	uint32_t	u32;
18715903Ssowmini 	void		*val;
18725903Ssowmini 
18737663SSowmini.Varadhan@Sun.COM 	dip = i_dladm_buf_alloc_by_name(0, linkid, pd->pd_name, 0, &status);
18745903Ssowmini 	if (dip == NULL)
18755903Ssowmini 		return (status);
18765903Ssowmini 
18775903Ssowmini 	if (pd->pd_flags & PD_CHECK_ALLOC)
18785903Ssowmini 		val = (void *)vdp->vd_val;
18795903Ssowmini 	else {
18805903Ssowmini 		/*
18815903Ssowmini 		 * Currently all 1/2/4-byte size properties are byte/word/int.
18825903Ssowmini 		 * No need (yet) to distinguish these from arrays of same size.
18835903Ssowmini 		 */
18845903Ssowmini 		switch (dip->pr_valsize) {
18855903Ssowmini 		case 1:
18865903Ssowmini 			u8 = vdp->vd_val;
18875903Ssowmini 			val = &u8;
18885903Ssowmini 			break;
18895903Ssowmini 		case 2:
18905903Ssowmini 			u16 = vdp->vd_val;
18915903Ssowmini 			val = &u16;
18925903Ssowmini 			break;
18935903Ssowmini 		case 4:
18945903Ssowmini 			u32 = vdp->vd_val;
18955903Ssowmini 			val = &u32;
18965903Ssowmini 			break;
18975903Ssowmini 		default:
18985903Ssowmini 			val = &vdp->vd_val;
18995903Ssowmini 			break;
19005903Ssowmini 		}
19015903Ssowmini 	}
19025903Ssowmini 
19037342SAruna.Ramakrishna@Sun.COM 	if (val != NULL)
19047342SAruna.Ramakrishna@Sun.COM 		(void) memcpy(dip->pr_val, val, dip->pr_valsize);
19057342SAruna.Ramakrishna@Sun.COM 	else
19067342SAruna.Ramakrishna@Sun.COM 		dip->pr_valsize = 0;
19077342SAruna.Ramakrishna@Sun.COM 
19087663SSowmini.Varadhan@Sun.COM 	status = i_dladm_macprop(dip, B_TRUE);
19097663SSowmini.Varadhan@Sun.COM 
19107663SSowmini.Varadhan@Sun.COM done:
19117663SSowmini.Varadhan@Sun.COM 	free(dip);
19127663SSowmini.Varadhan@Sun.COM 	return (status);
19137663SSowmini.Varadhan@Sun.COM }
19147663SSowmini.Varadhan@Sun.COM 
19157663SSowmini.Varadhan@Sun.COM dladm_status_t
19167663SSowmini.Varadhan@Sun.COM i_dladm_macprop(void *dip, boolean_t set)
19177663SSowmini.Varadhan@Sun.COM {
19187663SSowmini.Varadhan@Sun.COM 	int fd;
19197663SSowmini.Varadhan@Sun.COM 	dladm_status_t status = DLADM_STATUS_OK;
19207663SSowmini.Varadhan@Sun.COM 
19215903Ssowmini 	if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) {
19225903Ssowmini 		status = dladm_errno2status(errno);
19237663SSowmini.Varadhan@Sun.COM 		return (status);
19245903Ssowmini 	}
19257663SSowmini.Varadhan@Sun.COM 	if (ioctl(fd, (set ? DLDIOC_SETMACPROP : DLDIOC_GETMACPROP), dip))
19265903Ssowmini 		status = dladm_errno2status(errno);
19275903Ssowmini 
19285903Ssowmini 	(void) close(fd);
19295903Ssowmini 	return (status);
19305903Ssowmini }
19315903Ssowmini 
19326789Sam223141 static dld_ioc_macprop_t *
19337342SAruna.Ramakrishna@Sun.COM i_dladm_get_public_prop(datalink_id_t linkid, char *prop_name, uint_t flags,
19346512Ssowmini     dladm_status_t *status)
19355903Ssowmini {
19366789Sam223141 	dld_ioc_macprop_t *dip = NULL;
19376512Ssowmini 
19387663SSowmini.Varadhan@Sun.COM 	dip = i_dladm_buf_alloc_by_name(0, linkid, prop_name, flags, status);
19396512Ssowmini 	if (dip == NULL)
19406512Ssowmini 		return (NULL);
19415903Ssowmini 
19427663SSowmini.Varadhan@Sun.COM 	*status = i_dladm_macprop(dip, B_FALSE);
19436512Ssowmini 	if (*status != DLADM_STATUS_OK) {
19446512Ssowmini 		free(dip);
19456512Ssowmini 		return (NULL);
19466512Ssowmini 	}
19476512Ssowmini 	return (dip);
19485903Ssowmini }
19495903Ssowmini 
19505903Ssowmini /* ARGSUSED */
19515903Ssowmini static dladm_status_t
19527342SAruna.Ramakrishna@Sun.COM i_dladm_defmtu_check(struct prop_desc *pd, datalink_id_t linkid,
19537342SAruna.Ramakrishna@Sun.COM     char **prop_val, uint_t val_cnt, val_desc_t *v, datalink_media_t media)
19545903Ssowmini {
19555903Ssowmini 	if (val_cnt != 1)
19565903Ssowmini 		return (DLADM_STATUS_BADVAL);
19576512Ssowmini 	v->vd_val = atoi(prop_val[0]);
19585903Ssowmini 	return (DLADM_STATUS_OK);
19595903Ssowmini }
19605903Ssowmini 
19615903Ssowmini /* ARGSUSED */
19625903Ssowmini static dladm_status_t
19637342SAruna.Ramakrishna@Sun.COM i_dladm_duplex_get(struct prop_desc *pd, datalink_id_t linkid,
1964*8118SVasumathi.Sundaram@Sun.COM     char **prop_val, uint_t *val_cnt, datalink_media_t media, uint_t flags,
1965*8118SVasumathi.Sundaram@Sun.COM     uint_t *perm_flags)
19665903Ssowmini {
19675903Ssowmini 	link_duplex_t   link_duplex;
19685903Ssowmini 	dladm_status_t  status;
19695903Ssowmini 
19705903Ssowmini 	if ((status = dladm_get_single_mac_stat(linkid, "link_duplex",
19715903Ssowmini 	    KSTAT_DATA_UINT32, &link_duplex)) != 0)
19725903Ssowmini 		return (status);
19735903Ssowmini 
19745903Ssowmini 	switch (link_duplex) {
19755903Ssowmini 	case LINK_DUPLEX_FULL:
19765903Ssowmini 		(void) strcpy(*prop_val, "full");
19775903Ssowmini 		break;
19785903Ssowmini 	case LINK_DUPLEX_HALF:
19795903Ssowmini 		(void) strcpy(*prop_val, "half");
19805903Ssowmini 		break;
19815903Ssowmini 	default:
19825903Ssowmini 		(void) strcpy(*prop_val, "unknown");
19835903Ssowmini 		break;
19845903Ssowmini 	}
19855903Ssowmini 	*val_cnt = 1;
19865903Ssowmini 	return (DLADM_STATUS_OK);
19875903Ssowmini }
19885903Ssowmini 
19895903Ssowmini /* ARGSUSED */
19905903Ssowmini static dladm_status_t
19917342SAruna.Ramakrishna@Sun.COM i_dladm_speed_get(struct prop_desc *pd, datalink_id_t linkid,
19926512Ssowmini     char **prop_val, uint_t *val_cnt, uint_t flags)
19935903Ssowmini {
19945903Ssowmini 	uint64_t	ifspeed = 0;
19955903Ssowmini 	dladm_status_t status;
19965903Ssowmini 
19975903Ssowmini 	if ((status = dladm_get_single_mac_stat(linkid, "ifspeed",
19985903Ssowmini 	    KSTAT_DATA_UINT64, &ifspeed)) != 0)
19995903Ssowmini 		return (status);
20006512Ssowmini 
20015960Ssowmini 	if ((ifspeed % 1000000) != 0) {
20025960Ssowmini 		(void) snprintf(*prop_val, DLADM_PROP_VAL_MAX,
20035960Ssowmini 		    "%llf", ifspeed / (float)1000000); /* Mbps */
20045960Ssowmini 	} else {
20055960Ssowmini 		(void) snprintf(*prop_val, DLADM_PROP_VAL_MAX,
20065960Ssowmini 		    "%llu", ifspeed / 1000000); /* Mbps */
20075960Ssowmini 	}
20085903Ssowmini 	*val_cnt = 1;
20095903Ssowmini 	return (DLADM_STATUS_OK);
20105903Ssowmini }
20115903Ssowmini 
20125903Ssowmini /* ARGSUSED */
20135903Ssowmini static dladm_status_t
20147342SAruna.Ramakrishna@Sun.COM i_dladm_status_get(struct prop_desc *pd, datalink_id_t linkid,
2015*8118SVasumathi.Sundaram@Sun.COM     char **prop_val, uint_t *val_cnt, datalink_media_t media, uint_t flags,
2016*8118SVasumathi.Sundaram@Sun.COM     uint_t *perm_flags)
20175903Ssowmini {
20186512Ssowmini 	link_state_t	link_state;
20196512Ssowmini 	dladm_status_t	status;
20206512Ssowmini 	uchar_t 	*cp;
20216789Sam223141 	dld_ioc_macprop_t  *dip;
20225903Ssowmini 
20237342SAruna.Ramakrishna@Sun.COM 	dip = i_dladm_get_public_prop(linkid, pd->pd_name, flags, &status);
20246512Ssowmini 	if (status != DLADM_STATUS_OK)
20255903Ssowmini 		return (status);
20266512Ssowmini 	cp = (uchar_t *)dip->pr_val;
20276512Ssowmini 	(void) memcpy(&link_state, cp, sizeof (link_state));
20285903Ssowmini 
20295903Ssowmini 	switch (link_state) {
20305903Ssowmini 	case LINK_STATE_UP:
20315903Ssowmini 		(void) strcpy(*prop_val, "up");
20325903Ssowmini 		break;
20335903Ssowmini 	case LINK_STATE_DOWN:
20345903Ssowmini 		(void) strcpy(*prop_val, "down");
20355903Ssowmini 		break;
20365903Ssowmini 	default:
20375903Ssowmini 		(void) strcpy(*prop_val, "unknown");
20385903Ssowmini 		break;
20395903Ssowmini 	}
20405903Ssowmini 	*val_cnt = 1;
2041*8118SVasumathi.Sundaram@Sun.COM 	*perm_flags = dip->pr_perm_flags;
20426512Ssowmini 	free(dip);
20435903Ssowmini 	return (DLADM_STATUS_OK);
20445903Ssowmini }
20455903Ssowmini 
20465903Ssowmini /* ARGSUSED */
20475903Ssowmini static dladm_status_t
20487342SAruna.Ramakrishna@Sun.COM i_dladm_binary_get(struct prop_desc *pd, datalink_id_t linkid,
2049*8118SVasumathi.Sundaram@Sun.COM     char **prop_val, uint_t *val_cnt, datalink_media_t media, uint_t flags,
2050*8118SVasumathi.Sundaram@Sun.COM     uint_t *perm_flags)
20515903Ssowmini {
20526789Sam223141 	dld_ioc_macprop_t *dip;
20535903Ssowmini 	dladm_status_t status;
20545903Ssowmini 
20557342SAruna.Ramakrishna@Sun.COM 	dip = i_dladm_get_public_prop(linkid, pd->pd_name, flags, &status);
20566512Ssowmini 	if (dip == NULL)
20575903Ssowmini 		return (status);
20585903Ssowmini 	(void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "%x", dip->pr_val[0]);
2059*8118SVasumathi.Sundaram@Sun.COM 	*perm_flags = dip->pr_perm_flags;
20605903Ssowmini 	free(dip);
20615903Ssowmini 	*val_cnt = 1;
20625903Ssowmini 	return (DLADM_STATUS_OK);
20635903Ssowmini }
20645903Ssowmini 
20655960Ssowmini /* ARGSUSED */
20665903Ssowmini static dladm_status_t
20677342SAruna.Ramakrishna@Sun.COM i_dladm_uint32_get(struct prop_desc *pd, datalink_id_t linkid,
2068*8118SVasumathi.Sundaram@Sun.COM     char **prop_val, uint_t *val_cnt, datalink_media_t media, uint_t flags,
2069*8118SVasumathi.Sundaram@Sun.COM     uint_t *perm_flags)
20705903Ssowmini {
20716789Sam223141 	dld_ioc_macprop_t *dip;
20726512Ssowmini 	uint32_t v  = 0;
20735903Ssowmini 	uchar_t *cp;
20745903Ssowmini 	dladm_status_t status;
20755903Ssowmini 
20767342SAruna.Ramakrishna@Sun.COM 	dip = i_dladm_get_public_prop(linkid, pd->pd_name, flags, &status);
20776512Ssowmini 	if (dip == NULL)
20785903Ssowmini 		return (status);
20795903Ssowmini 	cp = (uchar_t *)dip->pr_val;
20805903Ssowmini 	(void) memcpy(&v, cp, sizeof (v));
20816512Ssowmini 	(void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "%ld", v);
2082*8118SVasumathi.Sundaram@Sun.COM 	*perm_flags = dip->pr_perm_flags;
20835903Ssowmini 	free(dip);
20845903Ssowmini 	*val_cnt = 1;
20855903Ssowmini 	return (DLADM_STATUS_OK);
20865903Ssowmini }
20875903Ssowmini 
20885960Ssowmini /* ARGSUSED */
20895903Ssowmini static dladm_status_t
20907342SAruna.Ramakrishna@Sun.COM i_dladm_flowctl_get(struct prop_desc *pd, datalink_id_t linkid,
2091*8118SVasumathi.Sundaram@Sun.COM     char **prop_val, uint_t *val_cnt, datalink_media_t media, uint_t flags,
2092*8118SVasumathi.Sundaram@Sun.COM     uint_t *perm_flags)
20935903Ssowmini {
20946789Sam223141 	dld_ioc_macprop_t *dip;
20955903Ssowmini 	link_flowctrl_t v;
20965903Ssowmini 	dladm_status_t status;
20975903Ssowmini 	uchar_t *cp;
20985903Ssowmini 
20997342SAruna.Ramakrishna@Sun.COM 	dip = i_dladm_get_public_prop(linkid, pd->pd_name, flags, &status);
21006512Ssowmini 	if (dip == NULL)
21015903Ssowmini 		return (status);
21025903Ssowmini 	cp = (uchar_t *)dip->pr_val;
21035903Ssowmini 	(void) memcpy(&v, cp, sizeof (v));
21045903Ssowmini 	switch (v) {
21055903Ssowmini 	case LINK_FLOWCTRL_NONE:
21065903Ssowmini 		(void) sprintf(*prop_val, "no");
21075903Ssowmini 		break;
21085903Ssowmini 	case LINK_FLOWCTRL_RX:
21095903Ssowmini 		(void) sprintf(*prop_val, "rx");
21105903Ssowmini 		break;
21115903Ssowmini 	case LINK_FLOWCTRL_TX:
21125903Ssowmini 		(void) sprintf(*prop_val, "tx");
21135903Ssowmini 		break;
21145903Ssowmini 	case LINK_FLOWCTRL_BI:
21155903Ssowmini 		(void) sprintf(*prop_val, "bi");
21165903Ssowmini 		break;
21175903Ssowmini 	}
2118*8118SVasumathi.Sundaram@Sun.COM 	*perm_flags = dip->pr_perm_flags;
21195903Ssowmini 	free(dip);
21205903Ssowmini 	*val_cnt = 1;
21215903Ssowmini 	return (DLADM_STATUS_OK);
21225903Ssowmini }
21235903Ssowmini 
21245903Ssowmini 
21255903Ssowmini /* ARGSUSED */
21265903Ssowmini static dladm_status_t
21277342SAruna.Ramakrishna@Sun.COM i_dladm_set_prop(datalink_id_t linkid, const char *prop_name,
21285903Ssowmini     char **prop_val, uint_t val_cnt, uint_t flags)
21295903Ssowmini {
21307663SSowmini.Varadhan@Sun.COM 	int		i, slen;
21317408SSebastien.Roy@Sun.COM 	int 		bufsize = 0;
21326789Sam223141 	dld_ioc_macprop_t *dip = NULL;
21335903Ssowmini 	uchar_t 	*dp;
21347663SSowmini.Varadhan@Sun.COM 	link_attr_t *p;
21356512Ssowmini 	dladm_status_t	status = DLADM_STATUS_OK;
21365903Ssowmini 
21375903Ssowmini 	if ((prop_name == NULL && prop_val != NULL) ||
21385903Ssowmini 	    (prop_val != NULL && val_cnt == 0))
21395903Ssowmini 		return (DLADM_STATUS_BADARG);
21405903Ssowmini 	p = dladm_name2prop(prop_name);
21416789Sam223141 	if (p->pp_id != MAC_PROP_PRIVATE)
21425903Ssowmini 		return (DLADM_STATUS_BADARG);
21435903Ssowmini 
21445903Ssowmini 	/*
21455903Ssowmini 	 * private properties: all parsing is done in the kernel.
21465903Ssowmini 	 * allocate a enough space for each property + its separator (',').
21475903Ssowmini 	 */
21485903Ssowmini 	for (i = 0; i < val_cnt; i++) {
21495903Ssowmini 		bufsize += strlen(prop_val[i]) + 1;
21505903Ssowmini 	}
21516512Ssowmini 
21526512Ssowmini 	if (prop_val == NULL) {
21536512Ssowmini 		/*
21546512Ssowmini 		 * getting default value. so use more buffer space.
21556512Ssowmini 		 */
21567663SSowmini.Varadhan@Sun.COM 		bufsize += DLADM_PROP_BUF_CHUNK;
21576512Ssowmini 	}
21586512Ssowmini 
21597663SSowmini.Varadhan@Sun.COM 	dip = i_dladm_buf_alloc_by_name(bufsize + 1, linkid, prop_name,
21606789Sam223141 	    (prop_val != NULL ? 0 : MAC_PROP_DEFAULT), &status);
21615903Ssowmini 	if (dip == NULL)
21625903Ssowmini 		return (status);
21635903Ssowmini 
21645903Ssowmini 	dp = (uchar_t *)dip->pr_val;
21655903Ssowmini 	slen = 0;
21667663SSowmini.Varadhan@Sun.COM 
21676512Ssowmini 	if (prop_val == NULL) {
21687663SSowmini.Varadhan@Sun.COM 		status = i_dladm_macprop(dip, B_FALSE);
21696512Ssowmini 	} else {
21706512Ssowmini 		for (i = 0; i < val_cnt; i++) {
21716512Ssowmini 			int plen = 0;
21725903Ssowmini 
21736512Ssowmini 			plen = strlen(prop_val[i]);
21746512Ssowmini 			bcopy(prop_val[i], dp, plen);
21756512Ssowmini 			slen += plen;
21766512Ssowmini 			/*
21776512Ssowmini 			 * add a "," separator and update dp.
21786512Ssowmini 			 */
21796512Ssowmini 			if (i != (val_cnt -1))
21806512Ssowmini 				dp[slen++] = ',';
21816512Ssowmini 			dp += (plen + 1);
21826512Ssowmini 		}
21837663SSowmini.Varadhan@Sun.COM 		status = i_dladm_macprop(dip, B_TRUE);
21845903Ssowmini 	}
21856512Ssowmini 
21865903Ssowmini 	free(dip);
21876512Ssowmini 	return (status);
21885903Ssowmini }
21895903Ssowmini 
21905903Ssowmini static dladm_status_t
21917342SAruna.Ramakrishna@Sun.COM i_dladm_get_prop(datalink_id_t linkid, const char *prop_name,
21926512Ssowmini     char **prop_val, uint_t *val_cnt, dladm_prop_type_t type, uint_t dld_flags)
21935903Ssowmini {
21947663SSowmini.Varadhan@Sun.COM 	dladm_status_t	status = DLADM_STATUS_OK;
21956789Sam223141 	dld_ioc_macprop_t *dip = NULL;
21967663SSowmini.Varadhan@Sun.COM 	link_attr_t *p;
21975903Ssowmini 	char tmp = '\0';
21985903Ssowmini 
21995903Ssowmini 	if ((prop_name == NULL && prop_val != NULL) ||
22005903Ssowmini 	    (prop_val != NULL && val_cnt == 0))
22015903Ssowmini 		return (DLADM_STATUS_BADARG);
22025903Ssowmini 
22035903Ssowmini 	p = dladm_name2prop(prop_name);
22046789Sam223141 	if (p->pp_id != MAC_PROP_PRIVATE)
22055903Ssowmini 		return (DLADM_STATUS_BADARG);
22065903Ssowmini 
22076512Ssowmini 	if (type == DLADM_PROP_VAL_MODIFIABLE) {
22085903Ssowmini 		*prop_val = &tmp;
22095903Ssowmini 		*val_cnt = 1;
22105903Ssowmini 		return (DLADM_STATUS_OK);
22115903Ssowmini 	}
22125903Ssowmini 
22135903Ssowmini 	/*
22145903Ssowmini 	 * private properties: all parsing is done in the kernel.
22155903Ssowmini 	 */
22167663SSowmini.Varadhan@Sun.COM 	dip = i_dladm_buf_alloc_by_name(DLADM_PROP_BUF_CHUNK, linkid, prop_name,
22177663SSowmini.Varadhan@Sun.COM 	    dld_flags, &status);
22185903Ssowmini 	if (dip == NULL)
22195903Ssowmini 		return (status);
22205903Ssowmini 
22217663SSowmini.Varadhan@Sun.COM 	if ((status = i_dladm_macprop(dip, B_FALSE)) == DLADM_STATUS_OK) {
2222*8118SVasumathi.Sundaram@Sun.COM 		if (type == DLADM_PROP_VAL_PERM) {
2223*8118SVasumathi.Sundaram@Sun.COM 			switch (dip->pr_perm_flags) {
2224*8118SVasumathi.Sundaram@Sun.COM 				case MAC_PROP_PERM_READ:
2225*8118SVasumathi.Sundaram@Sun.COM 					(void) strncpy(*prop_val,
2226*8118SVasumathi.Sundaram@Sun.COM 					    PERM_READ_ONLY, DLADM_PROP_VAL_MAX);
2227*8118SVasumathi.Sundaram@Sun.COM 					break;
2228*8118SVasumathi.Sundaram@Sun.COM 				case MAC_PROP_PERM_RW:
2229*8118SVasumathi.Sundaram@Sun.COM 					(void) strncpy(*prop_val,
2230*8118SVasumathi.Sundaram@Sun.COM 					    PERM_READ_WRITE,
2231*8118SVasumathi.Sundaram@Sun.COM 					    DLADM_PROP_VAL_MAX);
2232*8118SVasumathi.Sundaram@Sun.COM 					break;
2233*8118SVasumathi.Sundaram@Sun.COM 			}
2234*8118SVasumathi.Sundaram@Sun.COM 		} else {
2235*8118SVasumathi.Sundaram@Sun.COM 			(void) strncpy(*prop_val, dip->pr_val,
2236*8118SVasumathi.Sundaram@Sun.COM 			    DLADM_PROP_VAL_MAX);
2237*8118SVasumathi.Sundaram@Sun.COM 		}
22385903Ssowmini 		*val_cnt = 1;
22395903Ssowmini 	}
22406512Ssowmini 	free(dip);
22415903Ssowmini 	return (status);
22425903Ssowmini }
22436512Ssowmini 
22446512Ssowmini 
22456512Ssowmini static dladm_status_t
22466512Ssowmini i_dladm_getset_defval(prop_desc_t *pdp, datalink_id_t linkid,
22476512Ssowmini     datalink_media_t media, uint_t flags)
22486512Ssowmini {
22496512Ssowmini 	dladm_status_t status;
22506512Ssowmini 	char **prop_vals = NULL, *buf;
22516512Ssowmini 	size_t bufsize;
22526512Ssowmini 	uint_t cnt;
22536512Ssowmini 	int i;
2254*8118SVasumathi.Sundaram@Sun.COM 	uint_t perm_flags;
22556512Ssowmini 
22566512Ssowmini 	/*
22576512Ssowmini 	 * Allocate buffer needed for prop_vals array. We can have at most
22586512Ssowmini 	 * DLADM_MAX_PROP_VALCNT char *prop_vals[] entries, where
22596512Ssowmini 	 * each entry has max size DLADM_PROP_VAL_MAX
22606512Ssowmini 	 */
22616512Ssowmini 	bufsize =
22626512Ssowmini 	    (sizeof (char *) + DLADM_PROP_VAL_MAX) * DLADM_MAX_PROP_VALCNT;
22636512Ssowmini 	buf = malloc(bufsize);
22646512Ssowmini 	prop_vals = (char **)(void *)buf;
22656512Ssowmini 	for (i = 0; i < DLADM_MAX_PROP_VALCNT; i++) {
22666512Ssowmini 		prop_vals[i] = buf +
22676512Ssowmini 		    sizeof (char *) * DLADM_MAX_PROP_VALCNT +
22686512Ssowmini 		    i * DLADM_PROP_VAL_MAX;
22696512Ssowmini 	}
22706768Sar224390 
22716768Sar224390 	/*
22727342SAruna.Ramakrishna@Sun.COM 	 * For properties which have pdp->pd_defval.vd_name as a non-empty
22737342SAruna.Ramakrishna@Sun.COM 	 * string, the "" itself is used to reset the property (exceptions
22747342SAruna.Ramakrishna@Sun.COM 	 * are zone and autopush, which populate vdp->vd_val). So
22757342SAruna.Ramakrishna@Sun.COM 	 * libdladm can copy pdp->pd_defval over to the val_desc_t passed
22767342SAruna.Ramakrishna@Sun.COM 	 * down on the setprop using the global values in the table. For
22777342SAruna.Ramakrishna@Sun.COM 	 * other cases (vd_name is ""), doing reset-linkprop will cause
22787342SAruna.Ramakrishna@Sun.COM 	 * libdladm to do a getprop to find the default value and then do
22797342SAruna.Ramakrishna@Sun.COM 	 * a setprop to reset the value to default.
22806768Sar224390 	 */
22816789Sam223141 	status = pdp->pd_get(pdp, linkid, prop_vals, &cnt, media,
2282*8118SVasumathi.Sundaram@Sun.COM 	    MAC_PROP_DEFAULT, &perm_flags);
22836512Ssowmini 	if (status == DLADM_STATUS_OK) {
2284*8118SVasumathi.Sundaram@Sun.COM 		if (perm_flags == MAC_PROP_PERM_RW) {
2285*8118SVasumathi.Sundaram@Sun.COM 			status = i_dladm_set_single_prop(linkid, pdp->pd_class,
2286*8118SVasumathi.Sundaram@Sun.COM 			    media, pdp, prop_vals, cnt, flags);
2287*8118SVasumathi.Sundaram@Sun.COM 		}
2288*8118SVasumathi.Sundaram@Sun.COM 		else
2289*8118SVasumathi.Sundaram@Sun.COM 			status = DLADM_STATUS_NOTSUP;
22906512Ssowmini 	}
22916512Ssowmini 	free(buf);
22926512Ssowmini 	return (status);
22936512Ssowmini }
22947663SSowmini.Varadhan@Sun.COM 
22957663SSowmini.Varadhan@Sun.COM int
22967663SSowmini.Varadhan@Sun.COM macprop_to_wifi(mac_prop_id_t wl_prop)
22977663SSowmini.Varadhan@Sun.COM {
22987663SSowmini.Varadhan@Sun.COM 	switch (wl_prop) {
22997663SSowmini.Varadhan@Sun.COM 	case MAC_PROP_WL_ESSID:
23007663SSowmini.Varadhan@Sun.COM 		return (WL_ESSID);
23017663SSowmini.Varadhan@Sun.COM 	case MAC_PROP_WL_BSSID:
23027663SSowmini.Varadhan@Sun.COM 		return (WL_BSSID);
23037663SSowmini.Varadhan@Sun.COM 	case MAC_PROP_WL_BSSTYPE:
23047663SSowmini.Varadhan@Sun.COM 		return (WL_BSS_TYPE);
23057663SSowmini.Varadhan@Sun.COM 	case MAC_PROP_WL_LINKSTATUS:
23067663SSowmini.Varadhan@Sun.COM 		return (WL_LINKSTATUS);
23077663SSowmini.Varadhan@Sun.COM 	case MAC_PROP_WL_DESIRED_RATES:
23087663SSowmini.Varadhan@Sun.COM 		return (WL_DESIRED_RATES);
23097663SSowmini.Varadhan@Sun.COM 	case MAC_PROP_WL_SUPPORTED_RATES:
23107663SSowmini.Varadhan@Sun.COM 		return (WL_SUPPORTED_RATES);
23117663SSowmini.Varadhan@Sun.COM 	case MAC_PROP_WL_AUTH_MODE:
23127663SSowmini.Varadhan@Sun.COM 		return (WL_AUTH_MODE);
23137663SSowmini.Varadhan@Sun.COM 	case MAC_PROP_WL_ENCRYPTION:
23147663SSowmini.Varadhan@Sun.COM 		return (WL_ENCRYPTION);
23157663SSowmini.Varadhan@Sun.COM 	case MAC_PROP_WL_RSSI:
23167663SSowmini.Varadhan@Sun.COM 		return (WL_RSSI);
23177663SSowmini.Varadhan@Sun.COM 	case MAC_PROP_WL_PHY_CONFIG:
23187663SSowmini.Varadhan@Sun.COM 		return (WL_PHY_CONFIG);
23197663SSowmini.Varadhan@Sun.COM 	case MAC_PROP_WL_CAPABILITY:
23207663SSowmini.Varadhan@Sun.COM 		return (WL_CAPABILITY);
23217663SSowmini.Varadhan@Sun.COM 	case MAC_PROP_WL_WPA:
23227663SSowmini.Varadhan@Sun.COM 		return (WL_WPA);
23237663SSowmini.Varadhan@Sun.COM 	case MAC_PROP_WL_SCANRESULTS:
23247663SSowmini.Varadhan@Sun.COM 		return (WL_SCANRESULTS);
23257663SSowmini.Varadhan@Sun.COM 	case MAC_PROP_WL_POWER_MODE:
23267663SSowmini.Varadhan@Sun.COM 		return (WL_POWER_MODE);
23277663SSowmini.Varadhan@Sun.COM 	case MAC_PROP_WL_RADIO:
23287663SSowmini.Varadhan@Sun.COM 		return (WL_RADIO);
23297663SSowmini.Varadhan@Sun.COM 	case MAC_PROP_WL_ESS_LIST:
23307663SSowmini.Varadhan@Sun.COM 		return (WL_ESS_LIST);
23317663SSowmini.Varadhan@Sun.COM 	case MAC_PROP_WL_KEY_TAB:
23327663SSowmini.Varadhan@Sun.COM 		return (WL_WEP_KEY_TAB);
23337663SSowmini.Varadhan@Sun.COM 	case MAC_PROP_WL_CREATE_IBSS:
23347663SSowmini.Varadhan@Sun.COM 		return (WL_CREATE_IBSS);
23357663SSowmini.Varadhan@Sun.COM 	case MAC_PROP_WL_SETOPTIE:
23367663SSowmini.Varadhan@Sun.COM 		return (WL_SETOPTIE);
23377663SSowmini.Varadhan@Sun.COM 	case MAC_PROP_WL_DELKEY:
23387663SSowmini.Varadhan@Sun.COM 		return (WL_DELKEY);
23397663SSowmini.Varadhan@Sun.COM 	case MAC_PROP_WL_KEY:
23407663SSowmini.Varadhan@Sun.COM 		return (WL_KEY);
23417663SSowmini.Varadhan@Sun.COM 	case MAC_PROP_WL_MLME:
23427663SSowmini.Varadhan@Sun.COM 		return (WL_MLME);
23437663SSowmini.Varadhan@Sun.COM 	default:
23447663SSowmini.Varadhan@Sun.COM 		return (-1);
23457663SSowmini.Varadhan@Sun.COM 	}
23467663SSowmini.Varadhan@Sun.COM }
23477663SSowmini.Varadhan@Sun.COM 
23487663SSowmini.Varadhan@Sun.COM dladm_status_t
23497663SSowmini.Varadhan@Sun.COM i_dladm_wlan_param(datalink_id_t linkid, void *buf, mac_prop_id_t cmd,
23507663SSowmini.Varadhan@Sun.COM     size_t len, boolean_t set)
23517663SSowmini.Varadhan@Sun.COM {
23527663SSowmini.Varadhan@Sun.COM 	uint32_t		flags;
23537663SSowmini.Varadhan@Sun.COM 	dladm_status_t		status;
23547663SSowmini.Varadhan@Sun.COM 	uint32_t		media;
23557663SSowmini.Varadhan@Sun.COM 	dld_ioc_macprop_t	*dip;
23567663SSowmini.Varadhan@Sun.COM 	void			*dp;
23577663SSowmini.Varadhan@Sun.COM 
23587663SSowmini.Varadhan@Sun.COM 	if ((status = dladm_datalink_id2info(linkid, &flags, NULL, &media,
23597663SSowmini.Varadhan@Sun.COM 	    NULL, 0)) != DLADM_STATUS_OK) {
23607663SSowmini.Varadhan@Sun.COM 		return (status);
23617663SSowmini.Varadhan@Sun.COM 	}
23627663SSowmini.Varadhan@Sun.COM 
23637663SSowmini.Varadhan@Sun.COM 	if (media != DL_WIFI)
23647663SSowmini.Varadhan@Sun.COM 		return (DLADM_STATUS_BADARG);
23657663SSowmini.Varadhan@Sun.COM 
23667663SSowmini.Varadhan@Sun.COM 	if (!(flags & DLADM_OPT_ACTIVE))
23677663SSowmini.Varadhan@Sun.COM 		return (DLADM_STATUS_TEMPONLY);
23687663SSowmini.Varadhan@Sun.COM 
23697663SSowmini.Varadhan@Sun.COM 	if (len == (MAX_BUF_LEN - WIFI_BUF_OFFSET))
23707663SSowmini.Varadhan@Sun.COM 		len = MAX_BUF_LEN - sizeof (dld_ioc_macprop_t) - 1;
23717663SSowmini.Varadhan@Sun.COM 
23727663SSowmini.Varadhan@Sun.COM 	dip = i_dladm_buf_alloc_by_id(len, linkid, cmd, 0, &status);
23737663SSowmini.Varadhan@Sun.COM 	if (dip == NULL)
23747663SSowmini.Varadhan@Sun.COM 		return (DLADM_STATUS_NOMEM);
23757663SSowmini.Varadhan@Sun.COM 
23767663SSowmini.Varadhan@Sun.COM 	dp = (uchar_t *)dip->pr_val;
23777663SSowmini.Varadhan@Sun.COM 	if (set)
23787663SSowmini.Varadhan@Sun.COM 		(void) memcpy(dp, buf, len);
23797663SSowmini.Varadhan@Sun.COM 
23807663SSowmini.Varadhan@Sun.COM 	status = i_dladm_macprop(dip, set);
23817663SSowmini.Varadhan@Sun.COM 	if (status == DLADM_STATUS_NOTSUP) {
23827663SSowmini.Varadhan@Sun.COM 		if (set) {
23837663SSowmini.Varadhan@Sun.COM 			status = i_dladm_wlan_set_legacy_ioctl(linkid,
23847663SSowmini.Varadhan@Sun.COM 			    buf, len, macprop_to_wifi(cmd));
23857663SSowmini.Varadhan@Sun.COM 		} else {
23867663SSowmini.Varadhan@Sun.COM 			status = i_dladm_wlan_get_legacy_ioctl(linkid,
23877663SSowmini.Varadhan@Sun.COM 			    buf, len, macprop_to_wifi(cmd));
23887663SSowmini.Varadhan@Sun.COM 		}
23897663SSowmini.Varadhan@Sun.COM 	} else if (status == DLADM_STATUS_OK) {
23907663SSowmini.Varadhan@Sun.COM 		if (!set)
23917663SSowmini.Varadhan@Sun.COM 			(void) memcpy(buf, dp, len);
23927663SSowmini.Varadhan@Sun.COM 	}
23937663SSowmini.Varadhan@Sun.COM 
23947663SSowmini.Varadhan@Sun.COM 	free(dip);
23957663SSowmini.Varadhan@Sun.COM 	return (status);
23967663SSowmini.Varadhan@Sun.COM }
23977663SSowmini.Varadhan@Sun.COM 
23987663SSowmini.Varadhan@Sun.COM static dladm_status_t
23997663SSowmini.Varadhan@Sun.COM i_dladm_wlan_get_legacy_ioctl(datalink_id_t linkid, void *buf, uint_t buflen,
24007663SSowmini.Varadhan@Sun.COM     uint_t id)
24017663SSowmini.Varadhan@Sun.COM {
24027663SSowmini.Varadhan@Sun.COM 	wldp_t *gbuf;
24037663SSowmini.Varadhan@Sun.COM 	dladm_status_t status;
24047663SSowmini.Varadhan@Sun.COM 
24057663SSowmini.Varadhan@Sun.COM 	if ((gbuf = malloc(MAX_BUF_LEN)) == NULL)
24067663SSowmini.Varadhan@Sun.COM 		return (DLADM_STATUS_NOMEM);
24077663SSowmini.Varadhan@Sun.COM 
24087663SSowmini.Varadhan@Sun.COM 	(void) memset(gbuf, 0, MAX_BUF_LEN);
24097663SSowmini.Varadhan@Sun.COM 	status = i_dladm_wlan_legacy_ioctl(linkid, gbuf, id, MAX_BUF_LEN,
24107663SSowmini.Varadhan@Sun.COM 	    WLAN_GET_PARAM, sizeof (wldp_t));
24117663SSowmini.Varadhan@Sun.COM 	if (status == DLADM_STATUS_OK)
24127663SSowmini.Varadhan@Sun.COM 		(void) memcpy(buf, gbuf->wldp_buf, buflen);
24137663SSowmini.Varadhan@Sun.COM 
24147663SSowmini.Varadhan@Sun.COM 	free(gbuf);
24157663SSowmini.Varadhan@Sun.COM 	return (status);
24167663SSowmini.Varadhan@Sun.COM }
24177663SSowmini.Varadhan@Sun.COM 
24187663SSowmini.Varadhan@Sun.COM static dladm_status_t
24197663SSowmini.Varadhan@Sun.COM i_dladm_wlan_set_legacy_ioctl(datalink_id_t linkid,  void *buf, uint_t buflen,
24207663SSowmini.Varadhan@Sun.COM     uint_t id)
24217663SSowmini.Varadhan@Sun.COM {
24227663SSowmini.Varadhan@Sun.COM 	wldp_t *gbuf;
24237663SSowmini.Varadhan@Sun.COM 	dladm_status_t status = DLADM_STATUS_OK;
24247663SSowmini.Varadhan@Sun.COM 
24257663SSowmini.Varadhan@Sun.COM 	if ((gbuf = malloc(MAX_BUF_LEN)) == NULL)
24267663SSowmini.Varadhan@Sun.COM 		return (DLADM_STATUS_NOMEM);
24277663SSowmini.Varadhan@Sun.COM 
24287663SSowmini.Varadhan@Sun.COM 	(void) memset(gbuf, 0, MAX_BUF_LEN);
24297663SSowmini.Varadhan@Sun.COM 	(void) memcpy(gbuf->wldp_buf, buf, buflen);
24307663SSowmini.Varadhan@Sun.COM 	buflen += WIFI_BUF_OFFSET;
24317663SSowmini.Varadhan@Sun.COM 	status = i_dladm_wlan_legacy_ioctl(linkid, gbuf, id, buflen,
24327663SSowmini.Varadhan@Sun.COM 	    WLAN_SET_PARAM, buflen);
24337663SSowmini.Varadhan@Sun.COM 
24347663SSowmini.Varadhan@Sun.COM 	free(gbuf);
24357663SSowmini.Varadhan@Sun.COM 	return (status);
24367663SSowmini.Varadhan@Sun.COM }
2437