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>
513448Sdh155122 
525895Syz147064 /*
535895Syz147064  * The linkprop get() callback.
545903Ssowmini  * - pd: 	pointer to the struct prop_desc
555895Syz147064  * - propstrp:	a property string array to keep the returned property.
565895Syz147064  *		Caller allocated.
575895Syz147064  * - cntp:	number of returned properties.
585895Syz147064  *		Caller also uses it to indicate how many it expects.
595895Syz147064  */
605903Ssowmini struct prop_desc;
615903Ssowmini 
625903Ssowmini typedef dladm_status_t	pd_getf_t(struct prop_desc *pd,
635960Ssowmini 			datalink_id_t, char **propstp, uint_t *cntp,
646512Ssowmini 			datalink_media_t, uint_t);
655895Syz147064 
665895Syz147064 /*
675895Syz147064  * The linkprop set() callback.
685895Syz147064  * - propval:	a val_desc_t array which keeps the property values to be set.
695895Syz147064  * - cnt:	number of properties to be set.
705903Ssowmini  * - flags: 	additional flags passed down the system call.
715903Ssowmini  *
725903Ssowmini  * pd_set takes val_desc_t given by pd_check(), translates it into
735903Ssowmini  * a format suitable for kernel consumption. This may require allocation
745903Ssowmini  * of ioctl buffers etc. pd_set() may call another common routine (used
755903Ssowmini  * by all other pd_sets) which invokes the ioctl.
765895Syz147064  */
775903Ssowmini typedef dladm_status_t	pd_setf_t(struct prop_desc *, datalink_id_t,
785960Ssowmini 			val_desc_t *propval, uint_t cnt, uint_t flags,
795960Ssowmini 			datalink_media_t);
803448Sdh155122 
813448Sdh155122 
825895Syz147064 /*
835895Syz147064  * The linkprop check() callback.
845895Syz147064  * - propstrp:	property string array which keeps the property to be checked.
855895Syz147064  * - cnt:	number of properties.
865895Syz147064  * - propval:	return value; the property values of the given property strings.
875903Ssowmini  *
885903Ssowmini  * pd_check checks that the input values are valid. It does so by
895903Ssowmini  * iteraring through the pd_modval list for the property. If
905903Ssowmini  * the modifiable values cannot be expressed as a list, a pd_check
915903Ssowmini  * specific to this property can be used. If the input values are
925903Ssowmini  * verified to be valid, pd_check allocates a val_desc_t and fills it
935903Ssowmini  * with either a val_desc_t found on the pd_modval list or something
945903Ssowmini  * generated on the fly.
955895Syz147064  */
965903Ssowmini typedef dladm_status_t	pd_checkf_t(struct prop_desc *pd,
975903Ssowmini 			    datalink_id_t, char **propstrp,
985960Ssowmini 			    uint_t cnt, val_desc_t *propval,
995960Ssowmini 			    datalink_media_t);
1003448Sdh155122 
101*7342SAruna.Ramakrishna@Sun.COM typedef struct dladm_public_prop_s {
1026789Sam223141 	mac_prop_id_t	pp_id;
1035903Ssowmini 	size_t		pp_valsize;
1045903Ssowmini 	char		*pp_name;
1055903Ssowmini 	char		*pp_desc;
106*7342SAruna.Ramakrishna@Sun.COM } dladm_public_prop_t;
1075903Ssowmini 
108*7342SAruna.Ramakrishna@Sun.COM static dld_ioc_macprop_t *i_dladm_buf_alloc(size_t, datalink_id_t, const char *,
1096512Ssowmini 					uint_t, dladm_status_t *);
110*7342SAruna.Ramakrishna@Sun.COM static dladm_status_t i_dladm_set_prop(datalink_id_t, const char *, char **,
1115903Ssowmini 					uint_t, uint_t);
112*7342SAruna.Ramakrishna@Sun.COM static dladm_status_t i_dladm_get_prop(datalink_id_t, const char *, char **,
1136512Ssowmini 					uint_t *, dladm_prop_type_t, uint_t);
114*7342SAruna.Ramakrishna@Sun.COM static dladm_public_prop_t *dladm_name2prop(const char *);
115*7342SAruna.Ramakrishna@Sun.COM static dld_ioc_macprop_t *i_dladm_get_public_prop(datalink_id_t, char *, uint_t,
116*7342SAruna.Ramakrishna@Sun.COM 					dladm_status_t *);
1175895Syz147064 static pd_getf_t	do_get_zone, do_get_autopush, do_get_rate_mod,
1185895Syz147064 			do_get_rate_prop, do_get_channel_prop,
1195903Ssowmini 			do_get_powermode_prop, do_get_radio_prop,
120*7342SAruna.Ramakrishna@Sun.COM 			i_dladm_duplex_get, i_dladm_status_get,
121*7342SAruna.Ramakrishna@Sun.COM 			i_dladm_binary_get, i_dladm_uint32_get,
122*7342SAruna.Ramakrishna@Sun.COM 			i_dladm_flowctl_get;
123*7342SAruna.Ramakrishna@Sun.COM static pd_setf_t	do_set_zone, do_set_rate_prop,
1245903Ssowmini 			do_set_powermode_prop, do_set_radio_prop,
125*7342SAruna.Ramakrishna@Sun.COM 			i_dladm_set_public_prop;
1265903Ssowmini static pd_checkf_t	do_check_zone, do_check_autopush, do_check_rate,
127*7342SAruna.Ramakrishna@Sun.COM 			i_dladm_defmtu_check;
1283448Sdh155122 
129*7342SAruna.Ramakrishna@Sun.COM static dladm_status_t	i_dladm_speed_get(struct prop_desc *, datalink_id_t,
1306512Ssowmini 			char **, uint_t *, uint_t);
1315960Ssowmini 
1323448Sdh155122 typedef struct prop_desc {
1335895Syz147064 	/*
1345895Syz147064 	 * link property name
1355895Syz147064 	 */
1365895Syz147064 	char			*pd_name;
1375895Syz147064 
1385895Syz147064 	/*
1395895Syz147064 	 * default property value, can be set to { "", NULL }
1405895Syz147064 	 */
1415895Syz147064 	val_desc_t		pd_defval;
1425895Syz147064 
1435895Syz147064 	/*
1445895Syz147064 	 * list of optional property values, can be NULL.
1455895Syz147064 	 *
1465895Syz147064 	 * This is set to non-NULL if there is a list of possible property
1475895Syz147064 	 * values.  pd_optval would point to the array of possible values.
1485895Syz147064 	 */
1495895Syz147064 	val_desc_t		*pd_optval;
1505895Syz147064 
1515895Syz147064 	/*
1525895Syz147064 	 * count of the above optional property values. 0 if pd_optval is NULL.
1535895Syz147064 	 */
1545895Syz147064 	uint_t			pd_noptval;
1555895Syz147064 
1565895Syz147064 	/*
1575895Syz147064 	 * callback to set link property;
1585895Syz147064 	 * set to NULL if this property is read-only
1595895Syz147064 	 */
1605895Syz147064 	pd_setf_t		*pd_set;
1615895Syz147064 
1625895Syz147064 	/*
1635895Syz147064 	 * callback to get modifiable link property
1645895Syz147064 	 */
1655895Syz147064 	pd_getf_t		*pd_getmod;
1665895Syz147064 
1675895Syz147064 	/*
1685895Syz147064 	 * callback to get current link property
1695895Syz147064 	 */
1705895Syz147064 	pd_getf_t		*pd_get;
1715895Syz147064 
1725895Syz147064 	/*
1735895Syz147064 	 * callback to validate link property value, set to NULL if pd_optval
1745895Syz147064 	 * is not NULL. In that case, validate the value by comparing it with
1755895Syz147064 	 * the pd_optval. Return a val_desc_t array pointer if the value is
1765895Syz147064 	 * valid.
1775895Syz147064 	 */
1785895Syz147064 	pd_checkf_t		*pd_check;
1795895Syz147064 
1805895Syz147064 	uint_t			pd_flags;
1815903Ssowmini #define	PD_TEMPONLY	0x1	/* property is temporary only */
1825903Ssowmini #define	PD_CHECK_ALLOC	0x2	/* alloc vd_val as part of pd_check */
1835895Syz147064 	/*
1845895Syz147064 	 * indicate link classes this property applies to.
1855895Syz147064 	 */
1865895Syz147064 	datalink_class_t	pd_class;
1875895Syz147064 
1885895Syz147064 	/*
1895895Syz147064 	 * indicate link media type this property applies to.
1905895Syz147064 	 */
1915895Syz147064 	datalink_media_t	pd_dmedia;
1923448Sdh155122 } prop_desc_t;
1933448Sdh155122 
1946789Sam223141 #define	MAC_PROP_BUFSIZE(v)	sizeof (dld_ioc_macprop_t) + (v) - 1
1955903Ssowmini 
1965903Ssowmini 
197*7342SAruna.Ramakrishna@Sun.COM static dladm_public_prop_t dladm_prop[] = {
1986789Sam223141 	{ MAC_PROP_DUPLEX,	sizeof (link_duplex_t),
1995960Ssowmini 	    "duplex",		"link duplex mode" },
2005903Ssowmini 
2016789Sam223141 	{MAC_PROP_SPEED,	sizeof (uint64_t),
2025960Ssowmini 	    "speed",		"link speed (bps)" },
2035903Ssowmini 
2046789Sam223141 	{ MAC_PROP_STATUS,	sizeof (link_state_t),
2055960Ssowmini 	    "state",		"link up/down" },
2065903Ssowmini 
2076789Sam223141 	{ MAC_PROP_AUTONEG,	sizeof (uint8_t),
2085903Ssowmini 	    "adv_autoneg_cap",	"Advertised auto-negotiation" },
2095903Ssowmini 
2106789Sam223141 	{ MAC_PROP_MTU,		sizeof (uint32_t),
2115960Ssowmini 	    "mtu",		"current link mtu" },
2125903Ssowmini 
2136789Sam223141 	{ MAC_PROP_FLOWCTRL,	sizeof (link_flowctrl_t),
2145903Ssowmini 	    "flowctrl",		"flowcontrol" },
2155903Ssowmini 
216*7342SAruna.Ramakrishna@Sun.COM 	{ MAC_PROP_ZONE,	sizeof (dld_ioc_zid_t),
217*7342SAruna.Ramakrishna@Sun.COM 	    "zone",		"non-global zones" },
218*7342SAruna.Ramakrishna@Sun.COM 
219*7342SAruna.Ramakrishna@Sun.COM 	{ MAC_PROP_AUTOPUSH,	sizeof (struct dlautopush),
220*7342SAruna.Ramakrishna@Sun.COM 	    "autopush",		"autopush modules" },
221*7342SAruna.Ramakrishna@Sun.COM 
2226789Sam223141 	{ MAC_PROP_ADV_1000FDX_CAP, sizeof (uint8_t),
2235903Ssowmini 	    "adv_1000fdx_cap",	"Adv 1000 Mbps fdx" },
2245903Ssowmini 
2256789Sam223141 	{ MAC_PROP_EN_1000FDX_CAP, sizeof (uint8_t),
2265903Ssowmini 	    "en_1000fdx_cap",	"Enable 1000 Mbps fdx" },
2275903Ssowmini 
2286789Sam223141 	{ MAC_PROP_ADV_1000HDX_CAP, sizeof (uint8_t),
2295903Ssowmini 	    "adv_1000hdx_cap", "Adv 1000 Mbps hdx" },
2305903Ssowmini 
2316789Sam223141 	{ MAC_PROP_EN_1000HDX_CAP, sizeof (uint8_t),
2325903Ssowmini 	    "en_1000hdx_cap",	"Enable 1000 Mbps hdx" },
2335903Ssowmini 
2346789Sam223141 	{ MAC_PROP_ADV_100FDX_CAP, sizeof (uint8_t),
2355903Ssowmini 	    "adv_100fdx_cap",	"Adv 100 Mbps fdx" },
2365903Ssowmini 
2376789Sam223141 	{ MAC_PROP_EN_100FDX_CAP, sizeof (uint8_t),
2385903Ssowmini 	    "en_100fdx_cap",	"Enable 100 Mbps fdx" },
2395903Ssowmini 
2406789Sam223141 	{ MAC_PROP_ADV_100HDX_CAP, sizeof (uint8_t),
2415903Ssowmini 	    "adv_100hdx_cap",	"Adv 100 Mbps hdx" },
2425903Ssowmini 
2436789Sam223141 	{ MAC_PROP_EN_100HDX_CAP, sizeof (uint8_t),
2445903Ssowmini 	    "en_100hdx_cap",	"Enable 100 Mbps hdx" },
2455903Ssowmini 
2466789Sam223141 	{ MAC_PROP_ADV_10FDX_CAP, sizeof (uint8_t),
2475903Ssowmini 	    "adv_10fdx_cap",	"Adv 10 Mbps fdx" },
2485903Ssowmini 
2496789Sam223141 	{ MAC_PROP_EN_10FDX_CAP, sizeof (uint8_t),
2505903Ssowmini 	    "en_10fdx_cap",	"Enable 10 Mbps fdx" },
2515903Ssowmini 
2526789Sam223141 	{ MAC_PROP_ADV_10HDX_CAP, sizeof (uint8_t),
2535903Ssowmini 	    "adv_10hdx_cap",	"Adv 10 Mbps hdx" },
2545903Ssowmini 
2556789Sam223141 	{ MAC_PROP_EN_10HDX_CAP, sizeof (uint8_t),
2565903Ssowmini 	    "en_10hdx_cap",	"Enable 10 Mbps hdx" },
2575903Ssowmini 
2586789Sam223141 	{ MAC_PROP_PRIVATE, 0,
2595903Ssowmini 	    "driver-private",	"" }
2605903Ssowmini };
2615903Ssowmini 
2625903Ssowmini static  val_desc_t	link_duplex_vals[] = {
2635903Ssowmini 	{ "half", 	LINK_DUPLEX_HALF	},
2645903Ssowmini 	{ "full", 	LINK_DUPLEX_HALF	}
2655903Ssowmini };
2665903Ssowmini static  val_desc_t	link_status_vals[] = {
2675903Ssowmini 	{ "up",		LINK_STATE_UP		},
2685903Ssowmini 	{ "down",	LINK_STATE_DOWN		}
2695903Ssowmini };
2705903Ssowmini static  val_desc_t	link_01_vals[] = {
2715903Ssowmini 	{ "1",		1			},
2725903Ssowmini 	{ "0",		0			}
2735903Ssowmini };
2745903Ssowmini static  val_desc_t	link_flow_vals[] = {
2755903Ssowmini 	{ "no",		LINK_FLOWCTRL_NONE	},
2765903Ssowmini 	{ "tx",		LINK_FLOWCTRL_TX	},
2775903Ssowmini 	{ "rx",		LINK_FLOWCTRL_RX	},
2785903Ssowmini 	{ "bi",		LINK_FLOWCTRL_BI	}
2795903Ssowmini };
2805903Ssowmini 
2815903Ssowmini #define	VALCNT(vals)    (sizeof ((vals)) / sizeof (val_desc_t))
2825903Ssowmini 
2835895Syz147064 static val_desc_t	dladm_wlan_radio_vals[] = {
2845895Syz147064 	{ "on",		DLADM_WLAN_RADIO_ON	},
2855895Syz147064 	{ "off",	DLADM_WLAN_RADIO_OFF	}
2865895Syz147064 };
2875895Syz147064 
2885895Syz147064 static val_desc_t	dladm_wlan_powermode_vals[] = {
2895895Syz147064 	{ "off",	DLADM_WLAN_PM_OFF	},
2905895Syz147064 	{ "fast",	DLADM_WLAN_PM_FAST	},
2915895Syz147064 	{ "max",	DLADM_WLAN_PM_MAX	}
2925895Syz147064 };
2935895Syz147064 
2943448Sdh155122 static prop_desc_t	prop_table[] = {
2955895Syz147064 
2965903Ssowmini 	{ "channel",	{ NULL, 0 },
2975903Ssowmini 	    NULL, 0, NULL, NULL,
2985895Syz147064 	    do_get_channel_prop, NULL, 0,
2995903Ssowmini 	    DATALINK_CLASS_PHYS, DL_WIFI },
3005895Syz147064 
3015895Syz147064 	{ "powermode",	{ "off", DLADM_WLAN_PM_OFF },
3025895Syz147064 	    dladm_wlan_powermode_vals, VALCNT(dladm_wlan_powermode_vals),
3035895Syz147064 	    do_set_powermode_prop, NULL,
3045895Syz147064 	    do_get_powermode_prop, NULL, 0,
3055903Ssowmini 	    DATALINK_CLASS_PHYS, DL_WIFI },
3065895Syz147064 
3075895Syz147064 	{ "radio",	{ "on", DLADM_WLAN_RADIO_ON },
3085895Syz147064 	    dladm_wlan_radio_vals, VALCNT(dladm_wlan_radio_vals),
3095895Syz147064 	    do_set_radio_prop, NULL,
3105895Syz147064 	    do_get_radio_prop, NULL, 0,
3115903Ssowmini 	    DATALINK_CLASS_PHYS, DL_WIFI },
3125895Syz147064 
3135895Syz147064 	{ "speed",	{ "", 0 }, NULL, 0,
3145895Syz147064 	    do_set_rate_prop, do_get_rate_mod,
3155895Syz147064 	    do_get_rate_prop, do_check_rate, 0,
3165960Ssowmini 	    DATALINK_CLASS_PHYS, DATALINK_ANY_MEDIATYPE },
3175895Syz147064 
3186512Ssowmini 	{ "autopush",	{ "", 0 }, NULL, 0,
319*7342SAruna.Ramakrishna@Sun.COM 	    i_dladm_set_public_prop, NULL,
320*7342SAruna.Ramakrishna@Sun.COM 	    do_get_autopush, do_check_autopush, PD_CHECK_ALLOC,
3215903Ssowmini 	    DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
3225895Syz147064 
3236512Ssowmini 	{ "zone",	{ "", 0 }, NULL, 0,
3243448Sdh155122 	    do_set_zone, NULL,
325*7342SAruna.Ramakrishna@Sun.COM 	    do_get_zone, do_check_zone, PD_TEMPONLY|PD_CHECK_ALLOC,
3265903Ssowmini 	    DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
3275903Ssowmini 
3286512Ssowmini 	{ "duplex", { "", 0 },
3295903Ssowmini 	    link_duplex_vals, VALCNT(link_duplex_vals),
330*7342SAruna.Ramakrishna@Sun.COM 	    NULL, NULL, i_dladm_duplex_get, NULL,
3315903Ssowmini 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
3325903Ssowmini 
3335960Ssowmini 	{ "state", { "up", LINK_STATE_UP },
3345903Ssowmini 	    link_status_vals, VALCNT(link_status_vals),
335*7342SAruna.Ramakrishna@Sun.COM 	    NULL, NULL, i_dladm_status_get, NULL,
3366512Ssowmini 	    0, DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
3375903Ssowmini 
3385903Ssowmini 	{ "adv_autoneg_cap", { "1", 1 },
3395903Ssowmini 	    link_01_vals, VALCNT(link_01_vals),
340*7342SAruna.Ramakrishna@Sun.COM 	    i_dladm_set_public_prop, NULL, i_dladm_binary_get, NULL,
3415903Ssowmini 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
3425903Ssowmini 
3436512Ssowmini 	{ "mtu", { "", 0 }, NULL, 0,
344*7342SAruna.Ramakrishna@Sun.COM 	    i_dladm_set_public_prop, NULL, i_dladm_uint32_get,
345*7342SAruna.Ramakrishna@Sun.COM 	    i_dladm_defmtu_check, 0, DATALINK_CLASS_ALL,
346*7342SAruna.Ramakrishna@Sun.COM 	    DATALINK_ANY_MEDIATYPE },
3475903Ssowmini 
3486512Ssowmini 	{ "flowctrl", { "", 0 },
3495903Ssowmini 	    link_flow_vals, VALCNT(link_flow_vals),
350*7342SAruna.Ramakrishna@Sun.COM 	    i_dladm_set_public_prop, NULL, i_dladm_flowctl_get, NULL,
3515903Ssowmini 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
3525903Ssowmini 
3536512Ssowmini 	{ "adv_1000fdx_cap", { "", 0 },
3546512Ssowmini 	    link_01_vals, VALCNT(link_01_vals),
355*7342SAruna.Ramakrishna@Sun.COM 	    NULL, NULL, i_dladm_binary_get, NULL,
3565903Ssowmini 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
3575903Ssowmini 
3586512Ssowmini 	{ "en_1000fdx_cap", { "", 0 },
3595903Ssowmini 	    link_01_vals, VALCNT(link_01_vals),
360*7342SAruna.Ramakrishna@Sun.COM 	    i_dladm_set_public_prop, NULL, i_dladm_binary_get, NULL,
3615903Ssowmini 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
3625903Ssowmini 
3636512Ssowmini 	{ "adv_1000hdx_cap", { "", 0 },
3645903Ssowmini 	    link_01_vals, VALCNT(link_01_vals),
365*7342SAruna.Ramakrishna@Sun.COM 	    NULL, NULL, i_dladm_binary_get, NULL,
3665903Ssowmini 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
3675903Ssowmini 
3686512Ssowmini 	{ "en_1000hdx_cap", { "", 0 },
3695903Ssowmini 	    link_01_vals, VALCNT(link_01_vals),
370*7342SAruna.Ramakrishna@Sun.COM 	    i_dladm_set_public_prop, NULL, i_dladm_binary_get, NULL,
3715903Ssowmini 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
3725903Ssowmini 
3736512Ssowmini 	{ "adv_100fdx_cap", { "", 0 },
3745903Ssowmini 	    link_01_vals, VALCNT(link_01_vals),
375*7342SAruna.Ramakrishna@Sun.COM 	    NULL, NULL, i_dladm_binary_get, NULL,
3765903Ssowmini 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
3775903Ssowmini 
3786512Ssowmini 	{ "en_100fdx_cap", { "", 0 },
3795903Ssowmini 	    link_01_vals, VALCNT(link_01_vals),
380*7342SAruna.Ramakrishna@Sun.COM 	    i_dladm_set_public_prop, NULL, i_dladm_binary_get, NULL,
3815903Ssowmini 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
3825903Ssowmini 
3836512Ssowmini 	{ "adv_100hdx_cap", { "", 0 },
3845903Ssowmini 	    link_01_vals, VALCNT(link_01_vals),
385*7342SAruna.Ramakrishna@Sun.COM 	    NULL, NULL, i_dladm_binary_get, NULL,
3865903Ssowmini 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
3875903Ssowmini 
3886512Ssowmini 	{ "en_100hdx_cap", { "", 0 },
3895903Ssowmini 	    link_01_vals, VALCNT(link_01_vals),
390*7342SAruna.Ramakrishna@Sun.COM 	    i_dladm_set_public_prop, NULL, i_dladm_binary_get, NULL,
3915903Ssowmini 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
3925903Ssowmini 
3936512Ssowmini 	{ "adv_10fdx_cap", { "", 0 },
3945903Ssowmini 	    link_01_vals, VALCNT(link_01_vals),
395*7342SAruna.Ramakrishna@Sun.COM 	    NULL, NULL, i_dladm_binary_get, NULL,
3965903Ssowmini 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
3975903Ssowmini 
3986512Ssowmini 	{ "en_10fdx_cap", { "", 0 },
3995903Ssowmini 	    link_01_vals, VALCNT(link_01_vals),
400*7342SAruna.Ramakrishna@Sun.COM 	    i_dladm_set_public_prop, NULL, i_dladm_binary_get, NULL,
4015903Ssowmini 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
4025903Ssowmini 
4036512Ssowmini 	{ "adv_10hdx_cap", { "", 0 },
4045903Ssowmini 	    link_01_vals, VALCNT(link_01_vals),
405*7342SAruna.Ramakrishna@Sun.COM 	    NULL, NULL, i_dladm_binary_get, NULL,
4065903Ssowmini 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
4075903Ssowmini 
4086512Ssowmini 	{ "en_10hdx_cap", { "", 0 },
4095903Ssowmini 	    link_01_vals, VALCNT(link_01_vals),
410*7342SAruna.Ramakrishna@Sun.COM 	    i_dladm_set_public_prop, NULL, i_dladm_binary_get, NULL,
4115903Ssowmini 	    0, DATALINK_CLASS_PHYS, DL_ETHER }
4125903Ssowmini 
4133448Sdh155122 };
4143448Sdh155122 
4155895Syz147064 #define	DLADM_MAX_PROPS	(sizeof (prop_table) / sizeof (prop_desc_t))
4165895Syz147064 
4175895Syz147064 static dladm_status_t	i_dladm_set_linkprop_db(datalink_id_t, const char *,
4185895Syz147064 			    char **, uint_t);
4195895Syz147064 static dladm_status_t	i_dladm_get_linkprop_db(datalink_id_t, const char *,
4205895Syz147064 			    char **, uint_t *);
4215895Syz147064 static dladm_status_t	i_dladm_set_single_prop(datalink_id_t, datalink_class_t,
4225895Syz147064 			    uint32_t, prop_desc_t *, char **, uint_t, uint_t);
4235895Syz147064 static dladm_status_t	i_dladm_set_linkprop(datalink_id_t, const char *,
4245895Syz147064 			    char **, uint_t, uint_t);
4256512Ssowmini static dladm_status_t	i_dladm_getset_defval(prop_desc_t *, datalink_id_t,
4266512Ssowmini 			    datalink_media_t, uint_t);
4275895Syz147064 /*
4285895Syz147064  * Unfortunately, MAX_SCAN_SUPPORT_RATES is too small to allow all
4295895Syz147064  * rates to be retrieved. However, we cannot increase it at this
4305895Syz147064  * time because it will break binary compatibility with unbundled
4315895Syz147064  * WiFi drivers and utilities. So for now we define an additional
4325895Syz147064  * constant, MAX_SUPPORT_RATES, to allow all rates to be retrieved.
4335895Syz147064  */
4345895Syz147064 #define	MAX_SUPPORT_RATES	64
4355895Syz147064 
4365895Syz147064 #define	AP_ANCHOR	"[anchor]"
4375895Syz147064 #define	AP_DELIMITER	'.'
4385895Syz147064 
4395895Syz147064 static dladm_status_t
4405895Syz147064 do_check_prop(prop_desc_t *pdp, char **prop_val, uint_t val_cnt,
4415895Syz147064     val_desc_t *vdp)
4425895Syz147064 {
4435895Syz147064 	int		i, j;
4445895Syz147064 	dladm_status_t	status = DLADM_STATUS_OK;
4453147Sxc151355 
4465895Syz147064 	for (j = 0; j < val_cnt; j++) {
4475895Syz147064 		for (i = 0; i < pdp->pd_noptval; i++) {
4485895Syz147064 			if (strcasecmp(*prop_val,
4495895Syz147064 			    pdp->pd_optval[i].vd_name) == 0) {
4505895Syz147064 				break;
4515895Syz147064 			}
4525895Syz147064 		}
4535895Syz147064 		if (i == pdp->pd_noptval) {
4545895Syz147064 			status = DLADM_STATUS_BADVAL;
4555895Syz147064 			goto done;
4565895Syz147064 		}
4575895Syz147064 		(void) memcpy(vdp + j, &pdp->pd_optval[i], sizeof (val_desc_t));
4585895Syz147064 	}
4595895Syz147064 
4605895Syz147064 done:
4615895Syz147064 	return (status);
4625895Syz147064 }
4635895Syz147064 
4645895Syz147064 static dladm_status_t
4655895Syz147064 i_dladm_set_single_prop(datalink_id_t linkid, datalink_class_t class,
4665895Syz147064     uint32_t media, prop_desc_t *pdp, char **prop_val, uint_t val_cnt,
4675895Syz147064     uint_t flags)
4683147Sxc151355 {
4695895Syz147064 	dladm_status_t	status = DLADM_STATUS_OK;
4705895Syz147064 	val_desc_t	*vdp = NULL;
4715895Syz147064 	boolean_t	needfree = B_FALSE;
4725895Syz147064 	uint_t		cnt, i;
4733147Sxc151355 
4745895Syz147064 	if (!(pdp->pd_class & class))
4755895Syz147064 		return (DLADM_STATUS_BADARG);
4765895Syz147064 
4775895Syz147064 	if (!DATALINK_MEDIA_ACCEPTED(pdp->pd_dmedia, media))
4783147Sxc151355 		return (DLADM_STATUS_BADARG);
4793147Sxc151355 
4805895Syz147064 	if ((flags & DLADM_OPT_PERSIST) && (pdp->pd_flags & PD_TEMPONLY))
4815895Syz147064 		return (DLADM_STATUS_TEMPONLY);
4825895Syz147064 
4835895Syz147064 	if (!(flags & DLADM_OPT_ACTIVE))
4845895Syz147064 		return (DLADM_STATUS_OK);
4855895Syz147064 
4865895Syz147064 	if (pdp->pd_set == NULL)
4875895Syz147064 		return (DLADM_STATUS_PROPRDONLY);
4883448Sdh155122 
4895903Ssowmini 	if (pdp->pd_flags & PD_CHECK_ALLOC)
4905903Ssowmini 		needfree = B_TRUE;
4915903Ssowmini 	else
4925903Ssowmini 		needfree = B_FALSE;
4935895Syz147064 	if (prop_val != NULL) {
4945895Syz147064 		vdp = malloc(sizeof (val_desc_t) * val_cnt);
4955895Syz147064 		if (vdp == NULL)
4965895Syz147064 			return (DLADM_STATUS_NOMEM);
4975895Syz147064 
4985903Ssowmini 
4995895Syz147064 		if (pdp->pd_check != NULL) {
5005903Ssowmini 			status = pdp->pd_check(pdp, linkid, prop_val, val_cnt,
5015960Ssowmini 			    vdp, media);
5025895Syz147064 		} else if (pdp->pd_optval != NULL) {
5035895Syz147064 			status = do_check_prop(pdp, prop_val, val_cnt, vdp);
5045895Syz147064 		} else {
5053448Sdh155122 			status = DLADM_STATUS_BADARG;
5063147Sxc151355 		}
5075895Syz147064 
5083147Sxc151355 		if (status != DLADM_STATUS_OK)
5095895Syz147064 			goto done;
5105895Syz147064 
5115895Syz147064 		cnt = val_cnt;
5125895Syz147064 	} else {
5135895Syz147064 		if (pdp->pd_defval.vd_name == NULL)
5145895Syz147064 			return (DLADM_STATUS_NOTSUP);
5155895Syz147064 
516*7342SAruna.Ramakrishna@Sun.COM 		cnt = 1;
517*7342SAruna.Ramakrishna@Sun.COM 		if ((pdp->pd_flags & PD_CHECK_ALLOC) != 0 ||
5186512Ssowmini 		    strlen(pdp->pd_defval.vd_name) > 0) {
5196512Ssowmini 			if ((vdp = malloc(sizeof (val_desc_t))) == NULL)
5206512Ssowmini 				return (DLADM_STATUS_NOMEM);
521*7342SAruna.Ramakrishna@Sun.COM 
522*7342SAruna.Ramakrishna@Sun.COM 			if (pdp->pd_check != NULL) {
523*7342SAruna.Ramakrishna@Sun.COM 				status = pdp->pd_check(pdp, linkid, prop_val,
524*7342SAruna.Ramakrishna@Sun.COM 				    cnt, vdp, media);
525*7342SAruna.Ramakrishna@Sun.COM 				if (status != DLADM_STATUS_OK)
526*7342SAruna.Ramakrishna@Sun.COM 					goto done;
527*7342SAruna.Ramakrishna@Sun.COM 			} else {
528*7342SAruna.Ramakrishna@Sun.COM 				(void) memcpy(vdp, &pdp->pd_defval,
529*7342SAruna.Ramakrishna@Sun.COM 				    sizeof (val_desc_t));
530*7342SAruna.Ramakrishna@Sun.COM 			}
5316512Ssowmini 		} else {
5326512Ssowmini 			status = i_dladm_getset_defval(pdp, linkid,
5336512Ssowmini 			    media, flags);
5346512Ssowmini 			return (status);
5356512Ssowmini 		}
5365895Syz147064 	}
5375960Ssowmini 	status = pdp->pd_set(pdp, linkid, vdp, cnt, flags, media);
5385895Syz147064 	if (needfree) {
5395895Syz147064 		for (i = 0; i < cnt; i++)
5405903Ssowmini 			free((void *)((val_desc_t *)vdp + i)->vd_val);
5413147Sxc151355 	}
5425895Syz147064 done:
5435895Syz147064 	free(vdp);
5445895Syz147064 	return (status);
5455895Syz147064 }
5465895Syz147064 
5475895Syz147064 static dladm_status_t
5485895Syz147064 i_dladm_set_linkprop(datalink_id_t linkid, const char *prop_name,
5495895Syz147064     char **prop_val, uint_t val_cnt, uint_t flags)
5505895Syz147064 {
5515895Syz147064 	int			i;
5525895Syz147064 	boolean_t		found = B_FALSE;
5535895Syz147064 	datalink_class_t	class;
5545895Syz147064 	uint32_t		media;
5555895Syz147064 	dladm_status_t		status = DLADM_STATUS_OK;
5565895Syz147064 
5575895Syz147064 	status = dladm_datalink_id2info(linkid, NULL, &class, &media, NULL, 0);
5585895Syz147064 	if (status != DLADM_STATUS_OK)
5595895Syz147064 		return (status);
5605895Syz147064 
5615895Syz147064 	for (i = 0; i < DLADM_MAX_PROPS; i++) {
5625895Syz147064 		prop_desc_t	*pdp = &prop_table[i];
5635895Syz147064 		dladm_status_t	s;
5645895Syz147064 
5655895Syz147064 		if (prop_name != NULL &&
5665895Syz147064 		    (strcasecmp(prop_name, pdp->pd_name) != 0))
5675895Syz147064 			continue;
5685895Syz147064 
5695895Syz147064 		found = B_TRUE;
5705895Syz147064 		s = i_dladm_set_single_prop(linkid, class, media, pdp, prop_val,
5715895Syz147064 		    val_cnt, flags);
5723448Sdh155122 
5735895Syz147064 		if (prop_name != NULL) {
5745895Syz147064 			status = s;
5755895Syz147064 			break;
5765895Syz147064 		} else {
5775895Syz147064 			if (s != DLADM_STATUS_OK &&
5785895Syz147064 			    s != DLADM_STATUS_NOTSUP)
5795895Syz147064 				status = s;
5805895Syz147064 		}
5815895Syz147064 	}
5825903Ssowmini 	if (!found) {
5835903Ssowmini 		if (prop_name[0] == '_') {
5845903Ssowmini 			/* other private properties */
585*7342SAruna.Ramakrishna@Sun.COM 			status = i_dladm_set_prop(linkid, prop_name, prop_val,
5865903Ssowmini 			    val_cnt, flags);
5875903Ssowmini 		} else  {
5885903Ssowmini 			status = DLADM_STATUS_NOTFOUND;
5895903Ssowmini 		}
5905903Ssowmini 	}
5915895Syz147064 
5925895Syz147064 	return (status);
5935895Syz147064 }
5945895Syz147064 
5955895Syz147064 /*
5965895Syz147064  * Set/reset link property for specific link
5975895Syz147064  */
5985895Syz147064 dladm_status_t
5995895Syz147064 dladm_set_linkprop(datalink_id_t linkid, const char *prop_name, char **prop_val,
6005895Syz147064     uint_t val_cnt, uint_t flags)
6015895Syz147064 {
6025895Syz147064 	dladm_status_t	status = DLADM_STATUS_OK;
6035895Syz147064 
6045895Syz147064 	if ((linkid == DATALINK_INVALID_LINKID) || (flags == 0) ||
6055895Syz147064 	    (prop_val == NULL && val_cnt > 0) ||
6065895Syz147064 	    (prop_val != NULL && val_cnt == 0) ||
6075895Syz147064 	    (prop_name == NULL && prop_val != NULL)) {
6085895Syz147064 		return (DLADM_STATUS_BADARG);
6095895Syz147064 	}
6105895Syz147064 
6115895Syz147064 	status = i_dladm_set_linkprop(linkid, prop_name, prop_val,
6125895Syz147064 	    val_cnt, flags);
6135895Syz147064 	if (status != DLADM_STATUS_OK)
6145895Syz147064 		return (status);
6155895Syz147064 
6165895Syz147064 	if (flags & DLADM_OPT_PERSIST) {
6175895Syz147064 		status = i_dladm_set_linkprop_db(linkid, prop_name,
6183147Sxc151355 		    prop_val, val_cnt);
6193147Sxc151355 	}
6203147Sxc151355 	return (status);
6213147Sxc151355 }
6223147Sxc151355 
6235895Syz147064 /*
6245895Syz147064  * Walk link properties of the given specific link.
6255895Syz147064  */
6263147Sxc151355 dladm_status_t
6275895Syz147064 dladm_walk_linkprop(datalink_id_t linkid, void *arg,
6285895Syz147064     int (*func)(datalink_id_t, const char *, void *))
6293147Sxc151355 {
6305895Syz147064 	dladm_status_t		status;
6315895Syz147064 	datalink_class_t	class;
6325895Syz147064 	uint_t			media;
6335895Syz147064 	int			i;
6345895Syz147064 
6355895Syz147064 	if (linkid == DATALINK_INVALID_LINKID || func == NULL)
6365895Syz147064 		return (DLADM_STATUS_BADARG);
6375895Syz147064 
6385895Syz147064 	status = dladm_datalink_id2info(linkid, NULL, &class, &media, NULL, 0);
6395895Syz147064 	if (status != DLADM_STATUS_OK)
6405895Syz147064 		return (status);
6415895Syz147064 
6425895Syz147064 	for (i = 0; i < DLADM_MAX_PROPS; i++) {
6435895Syz147064 		if (!(prop_table[i].pd_class & class))
6445895Syz147064 			continue;
6455895Syz147064 
6465895Syz147064 		if (!DATALINK_MEDIA_ACCEPTED(prop_table[i].pd_dmedia, media))
6475895Syz147064 			continue;
6485895Syz147064 
6495895Syz147064 		if (func(linkid, prop_table[i].pd_name, arg) ==
6505895Syz147064 		    DLADM_WALK_TERMINATE) {
6515895Syz147064 			break;
6525895Syz147064 		}
6535895Syz147064 	}
6545895Syz147064 
6555895Syz147064 	return (DLADM_STATUS_OK);
6565895Syz147064 }
6573448Sdh155122 
6585895Syz147064 /*
6595895Syz147064  * Get linkprop of the given specific link.
6605895Syz147064  */
6615895Syz147064 dladm_status_t
6625895Syz147064 dladm_get_linkprop(datalink_id_t linkid, dladm_prop_type_t type,
6635895Syz147064     const char *prop_name, char **prop_val, uint_t *val_cntp)
6645895Syz147064 {
6655895Syz147064 	dladm_status_t		status = DLADM_STATUS_OK;
6665895Syz147064 	datalink_class_t	class;
6675895Syz147064 	uint_t			media;
6685895Syz147064 	prop_desc_t		*pdp;
6696512Ssowmini 	uint_t			cnt, dld_flags = 0;
6705895Syz147064 	int			i;
6715895Syz147064 
6726512Ssowmini 	if (type == DLADM_PROP_VAL_DEFAULT)
6736789Sam223141 		dld_flags = MAC_PROP_DEFAULT;
6746512Ssowmini 
6755895Syz147064 	if (linkid == DATALINK_INVALID_LINKID || prop_name == NULL ||
6765895Syz147064 	    prop_val == NULL || val_cntp == NULL || *val_cntp == 0)
6775895Syz147064 		return (DLADM_STATUS_BADARG);
6785895Syz147064 
6795895Syz147064 	for (i = 0; i < DLADM_MAX_PROPS; i++)
6805895Syz147064 		if (strcasecmp(prop_name, prop_table[i].pd_name) == 0)
6815895Syz147064 			break;
6825895Syz147064 
6835903Ssowmini 	if (i == DLADM_MAX_PROPS) {
6845903Ssowmini 		if (prop_name[0] == '_') {
6855903Ssowmini 			/*
6865903Ssowmini 			 * private property.
6875903Ssowmini 			 */
688*7342SAruna.Ramakrishna@Sun.COM 			return (i_dladm_get_prop(linkid, prop_name,
6896512Ssowmini 			    prop_val, val_cntp, type, dld_flags));
6905903Ssowmini 		} else {
6915903Ssowmini 			return (DLADM_STATUS_NOTFOUND);
6925903Ssowmini 		}
6935903Ssowmini 	}
6945895Syz147064 
6955895Syz147064 	pdp = &prop_table[i];
6965895Syz147064 
6975895Syz147064 	status = dladm_datalink_id2info(linkid, NULL, &class, &media, NULL, 0);
6985895Syz147064 	if (status != DLADM_STATUS_OK)
6995895Syz147064 		return (status);
7005895Syz147064 
7015895Syz147064 	if (!(pdp->pd_class & class))
7025895Syz147064 		return (DLADM_STATUS_BADARG);
7035895Syz147064 
7045895Syz147064 	if (!DATALINK_MEDIA_ACCEPTED(pdp->pd_dmedia, media))
7053147Sxc151355 		return (DLADM_STATUS_BADARG);
7063147Sxc151355 
7075895Syz147064 	switch (type) {
7085895Syz147064 	case DLADM_PROP_VAL_CURRENT:
7096512Ssowmini 		status = pdp->pd_get(pdp, linkid, prop_val, val_cntp, media,
7106512Ssowmini 		    dld_flags);
7115895Syz147064 		break;
7125895Syz147064 
7135895Syz147064 	case DLADM_PROP_VAL_DEFAULT:
7146768Sar224390 		/*
7156768Sar224390 		 * If defaults are not defined for the property,
7166768Sar224390 		 * pd_defval.vd_name should be null. If the driver
7176768Sar224390 		 * has to be contacted for the value, vd_name should
7186768Sar224390 		 * be the empty string (""). Otherwise, dladm will
7196768Sar224390 		 * just print whatever is in the table.
7206768Sar224390 		 */
7215895Syz147064 		if (pdp->pd_defval.vd_name == NULL) {
7225895Syz147064 			status = DLADM_STATUS_NOTSUP;
7235895Syz147064 			break;
7245895Syz147064 		}
7256512Ssowmini 
7266512Ssowmini 		if (strlen(pdp->pd_defval.vd_name) == 0) {
7276512Ssowmini 			status = pdp->pd_get(pdp, linkid, prop_val, val_cntp,
7286512Ssowmini 			    media, dld_flags);
7296512Ssowmini 		} else {
7306512Ssowmini 			(void) strcpy(*prop_val, pdp->pd_defval.vd_name);
7316512Ssowmini 		}
7325895Syz147064 		*val_cntp = 1;
7335895Syz147064 		break;
7343448Sdh155122 
7355895Syz147064 	case DLADM_PROP_VAL_MODIFIABLE:
7365895Syz147064 		if (pdp->pd_getmod != NULL) {
7375903Ssowmini 			status = pdp->pd_getmod(pdp, linkid, prop_val,
7386512Ssowmini 			    val_cntp, media, dld_flags);
7395895Syz147064 			break;
7405895Syz147064 		}
7415895Syz147064 		cnt = pdp->pd_noptval;
7425895Syz147064 		if (cnt == 0) {
7435895Syz147064 			status = DLADM_STATUS_NOTSUP;
7445895Syz147064 		} else if (cnt > *val_cntp) {
7455895Syz147064 			status = DLADM_STATUS_TOOSMALL;
7465895Syz147064 		} else {
7475895Syz147064 			for (i = 0; i < cnt; i++) {
7485895Syz147064 				(void) strcpy(prop_val[i],
7495895Syz147064 				    pdp->pd_optval[i].vd_name);
7505895Syz147064 			}
7515895Syz147064 			*val_cntp = cnt;
7525895Syz147064 		}
7535895Syz147064 		break;
7545895Syz147064 	case DLADM_PROP_VAL_PERSISTENT:
7555895Syz147064 		if (pdp->pd_flags & PD_TEMPONLY)
7565895Syz147064 			return (DLADM_STATUS_TEMPONLY);
7575895Syz147064 		status = i_dladm_get_linkprop_db(linkid, prop_name,
7585895Syz147064 		    prop_val, val_cntp);
7595895Syz147064 		break;
7605895Syz147064 	default:
7615895Syz147064 		status = DLADM_STATUS_BADARG;
7625895Syz147064 		break;
7633147Sxc151355 	}
7643448Sdh155122 
7655895Syz147064 	return (status);
7665895Syz147064 }
7675895Syz147064 
7685895Syz147064 /*ARGSUSED*/
7695895Syz147064 static int
7705895Syz147064 i_dladm_init_one_prop(datalink_id_t linkid, const char *prop_name, void *arg)
7715895Syz147064 {
7725895Syz147064 	char	*buf, **propvals;
7735895Syz147064 	uint_t	i, valcnt = DLADM_MAX_PROP_VALCNT;
7745895Syz147064 
7755895Syz147064 	if ((buf = malloc((sizeof (char *) + DLADM_PROP_VAL_MAX) *
7765895Syz147064 	    DLADM_MAX_PROP_VALCNT)) == NULL) {
7775895Syz147064 		return (DLADM_WALK_CONTINUE);
7785895Syz147064 	}
7795895Syz147064 
7805895Syz147064 	propvals = (char **)(void *)buf;
7815895Syz147064 	for (i = 0; i < valcnt; i++) {
7825895Syz147064 		propvals[i] = buf +
7835895Syz147064 		    sizeof (char *) * DLADM_MAX_PROP_VALCNT +
7845895Syz147064 		    i * DLADM_PROP_VAL_MAX;
7855895Syz147064 	}
7865895Syz147064 
7875895Syz147064 	if (dladm_get_linkprop(linkid, DLADM_PROP_VAL_PERSISTENT, prop_name,
7885895Syz147064 	    propvals, &valcnt) != DLADM_STATUS_OK) {
7895895Syz147064 		goto done;
7905895Syz147064 	}
7915895Syz147064 
7925895Syz147064 	(void) dladm_set_linkprop(linkid, prop_name, propvals, valcnt,
7935895Syz147064 	    DLADM_OPT_ACTIVE);
7945895Syz147064 
7955895Syz147064 done:
7965895Syz147064 	if (buf != NULL)
7975895Syz147064 		free(buf);
7985895Syz147064 
7995895Syz147064 	return (DLADM_WALK_CONTINUE);
8005895Syz147064 }
8015895Syz147064 
8025895Syz147064 /*ARGSUSED*/
8035895Syz147064 static int
8045895Syz147064 i_dladm_init_linkprop(datalink_id_t linkid, void *arg)
8055895Syz147064 {
8066916Sartem 	(void) dladm_init_linkprop(linkid, B_TRUE);
8075895Syz147064 	return (DLADM_WALK_CONTINUE);
8085895Syz147064 }
8095895Syz147064 
8105895Syz147064 dladm_status_t
8116916Sartem dladm_init_linkprop(datalink_id_t linkid, boolean_t any_media)
8125895Syz147064 {
8136916Sartem 	datalink_media_t	dmedia;
8146916Sartem 	uint32_t		media;
8156916Sartem 
8166916Sartem 	dmedia = any_media ? DATALINK_ANY_MEDIATYPE : DL_WIFI;
8176916Sartem 
8185895Syz147064 	if (linkid == DATALINK_ALL_LINKID) {
8195895Syz147064 		(void) dladm_walk_datalink_id(i_dladm_init_linkprop, NULL,
8206916Sartem 		    DATALINK_CLASS_ALL, dmedia, DLADM_OPT_PERSIST);
8216916Sartem 	} else if (any_media || ((dladm_datalink_id2info(linkid, NULL, NULL,
8226916Sartem 	    &media, NULL, 0) == DLADM_STATUS_OK) &&
8236916Sartem 	    DATALINK_MEDIA_ACCEPTED(dmedia, media))) {
8245895Syz147064 		(void) dladm_walk_linkprop(linkid, NULL, i_dladm_init_one_prop);
8253448Sdh155122 	}
8263448Sdh155122 	return (DLADM_STATUS_OK);
8273147Sxc151355 }
8283147Sxc151355 
8295903Ssowmini /* ARGSUSED */
8305895Syz147064 static dladm_status_t
8315903Ssowmini do_get_zone(struct prop_desc *pd, datalink_id_t linkid,
8326512Ssowmini     char **prop_val, uint_t *val_cnt, datalink_media_t media, uint_t flags)
8333147Sxc151355 {
8345895Syz147064 	char		zone_name[ZONENAME_MAX];
8355895Syz147064 	zoneid_t	zid;
8365895Syz147064 	dladm_status_t	status;
837*7342SAruna.Ramakrishna@Sun.COM 	char		*cp;
838*7342SAruna.Ramakrishna@Sun.COM 	dld_ioc_macprop_t	*dip;
8393147Sxc151355 
8406512Ssowmini 	if (flags != 0)
8416512Ssowmini 		return (DLADM_STATUS_NOTSUP);
8426512Ssowmini 
843*7342SAruna.Ramakrishna@Sun.COM 	dip = i_dladm_get_public_prop(linkid, pd->pd_name, flags, &status);
8445895Syz147064 	if (status != DLADM_STATUS_OK)
8453448Sdh155122 		return (status);
8463448Sdh155122 
847*7342SAruna.Ramakrishna@Sun.COM 	cp = dip->pr_val;
848*7342SAruna.Ramakrishna@Sun.COM 	(void) memcpy(&zid, cp, sizeof (zid));
849*7342SAruna.Ramakrishna@Sun.COM 	free(dip);
850*7342SAruna.Ramakrishna@Sun.COM 
8515895Syz147064 	*val_cnt = 1;
8525895Syz147064 	if (zid != GLOBAL_ZONEID) {
8535895Syz147064 		if (getzonenamebyid(zid, zone_name, sizeof (zone_name)) < 0)
8545895Syz147064 			return (dladm_errno2status(errno));
8553147Sxc151355 
8565895Syz147064 		(void) strncpy(*prop_val, zone_name, DLADM_PROP_VAL_MAX);
8573147Sxc151355 	} else {
8585895Syz147064 		*prop_val[0] = '\0';
8593147Sxc151355 	}
8603147Sxc151355 
8613448Sdh155122 	return (DLADM_STATUS_OK);
8623448Sdh155122 }
8633448Sdh155122 
8643448Sdh155122 typedef int (*zone_get_devroot_t)(char *, char *, size_t);
8653448Sdh155122 
8663448Sdh155122 static int
8673448Sdh155122 i_dladm_get_zone_dev(char *zone_name, char *dev, size_t devlen)
8683448Sdh155122 {
8693448Sdh155122 	char			root[MAXPATHLEN];
8703448Sdh155122 	zone_get_devroot_t	real_zone_get_devroot;
8713448Sdh155122 	void			*dlhandle;
8723448Sdh155122 	void			*sym;
8733448Sdh155122 	int			ret;
8743448Sdh155122 
8753448Sdh155122 	if ((dlhandle = dlopen("libzonecfg.so.1", RTLD_LAZY)) == NULL)
8763448Sdh155122 		return (-1);
8773448Sdh155122 
8783448Sdh155122 	if ((sym = dlsym(dlhandle, "zone_get_devroot")) == NULL) {
8793448Sdh155122 		(void) dlclose(dlhandle);
8803448Sdh155122 		return (-1);
8813448Sdh155122 	}
8823448Sdh155122 
8833448Sdh155122 	real_zone_get_devroot = (zone_get_devroot_t)sym;
8843448Sdh155122 
8853448Sdh155122 	if ((ret = real_zone_get_devroot(zone_name, root, sizeof (root))) == 0)
8863448Sdh155122 		(void) snprintf(dev, devlen, "%s%s", root, "/dev");
8873448Sdh155122 	(void) dlclose(dlhandle);
8883448Sdh155122 	return (ret);
8893448Sdh155122 }
8903448Sdh155122 
8913448Sdh155122 static dladm_status_t
8925895Syz147064 i_dladm_update_deventry(zoneid_t zid, datalink_id_t linkid, boolean_t add)
8933448Sdh155122 {
8943448Sdh155122 	char		path[MAXPATHLEN];
8955895Syz147064 	char		name[MAXLINKNAMELEN];
8963448Sdh155122 	di_prof_t	prof = NULL;
8973448Sdh155122 	char		zone_name[ZONENAME_MAX];
8983448Sdh155122 	dladm_status_t	status;
8995895Syz147064 	int		ret;
9003448Sdh155122 
9013448Sdh155122 	if (getzonenamebyid(zid, zone_name, sizeof (zone_name)) < 0)
9023448Sdh155122 		return (dladm_errno2status(errno));
9033448Sdh155122 	if (i_dladm_get_zone_dev(zone_name, path, sizeof (path)) != 0)
9043448Sdh155122 		return (dladm_errno2status(errno));
9053448Sdh155122 	if (di_prof_init(path, &prof) != 0)
9063448Sdh155122 		return (dladm_errno2status(errno));
9073448Sdh155122 
9085895Syz147064 	status = dladm_linkid2legacyname(linkid, name, MAXLINKNAMELEN);
9095895Syz147064 	if (status != DLADM_STATUS_OK)
9105895Syz147064 		goto cleanup;
9115895Syz147064 
9125895Syz147064 	if (add)
9135895Syz147064 		ret = di_prof_add_dev(prof, name);
9145895Syz147064 	else
9155895Syz147064 		ret = di_prof_add_exclude(prof, name);
9165895Syz147064 
9175895Syz147064 	if (ret != 0) {
9183448Sdh155122 		status = dladm_errno2status(errno);
9193448Sdh155122 		goto cleanup;
9203448Sdh155122 	}
9213448Sdh155122 
9223448Sdh155122 	if (di_prof_commit(prof) != 0)
9233448Sdh155122 		status = dladm_errno2status(errno);
9243448Sdh155122 cleanup:
9253448Sdh155122 	if (prof)
9263448Sdh155122 		di_prof_fini(prof);
9273448Sdh155122 
9283448Sdh155122 	return (status);
9293448Sdh155122 }
9303448Sdh155122 
9315903Ssowmini /* ARGSUSED */
9323448Sdh155122 static dladm_status_t
9335960Ssowmini do_set_zone(prop_desc_t *pd, datalink_id_t linkid, val_desc_t *vdp,
9345960Ssowmini     uint_t val_cnt, uint_t flags, datalink_media_t media)
9353448Sdh155122 {
936*7342SAruna.Ramakrishna@Sun.COM 	dladm_status_t	status = DLADM_STATUS_OK;
9373448Sdh155122 	zoneid_t	zid_old, zid_new;
9385895Syz147064 	char		link[MAXLINKNAMELEN];
939*7342SAruna.Ramakrishna@Sun.COM 	char		*cp;
940*7342SAruna.Ramakrishna@Sun.COM 	dld_ioc_macprop_t	*dip;
941*7342SAruna.Ramakrishna@Sun.COM 	dld_ioc_zid_t		*dzp;
9423448Sdh155122 
9433448Sdh155122 	if (val_cnt != 1)
9443448Sdh155122 		return (DLADM_STATUS_BADVALCNT);
9453448Sdh155122 
946*7342SAruna.Ramakrishna@Sun.COM 	dzp = (dld_ioc_zid_t *)vdp->vd_val;
947*7342SAruna.Ramakrishna@Sun.COM 
948*7342SAruna.Ramakrishna@Sun.COM 	/*
949*7342SAruna.Ramakrishna@Sun.COM 	 * If diz_is_ppa_hack is set, then an implicit vlan must be created.
950*7342SAruna.Ramakrishna@Sun.COM 	 * There is no old value to compare against, and vdp->vd_val is
951*7342SAruna.Ramakrishna@Sun.COM 	 * already populated with the zoneid and linkname in the function
952*7342SAruna.Ramakrishna@Sun.COM 	 * do_check_zone().
953*7342SAruna.Ramakrishna@Sun.COM 	 */
954*7342SAruna.Ramakrishna@Sun.COM 
955*7342SAruna.Ramakrishna@Sun.COM 	if (dzp->diz_is_ppa_hack) {
956*7342SAruna.Ramakrishna@Sun.COM 		zid_old = GLOBAL_ZONEID;
957*7342SAruna.Ramakrishna@Sun.COM 	} else {
958*7342SAruna.Ramakrishna@Sun.COM 		dip = i_dladm_get_public_prop(linkid, pd->pd_name,
959*7342SAruna.Ramakrishna@Sun.COM 		    flags, &status);
960*7342SAruna.Ramakrishna@Sun.COM 		if (status != DLADM_STATUS_OK)
961*7342SAruna.Ramakrishna@Sun.COM 			return (status);
962*7342SAruna.Ramakrishna@Sun.COM 
963*7342SAruna.Ramakrishna@Sun.COM 		cp = dip->pr_val;
964*7342SAruna.Ramakrishna@Sun.COM 		(void) memcpy(&zid_old, cp, sizeof (zid_old));
965*7342SAruna.Ramakrishna@Sun.COM 		free(dip);
966*7342SAruna.Ramakrishna@Sun.COM 	}
967*7342SAruna.Ramakrishna@Sun.COM 
968*7342SAruna.Ramakrishna@Sun.COM 	zid_new = dzp->diz_zid;
969*7342SAruna.Ramakrishna@Sun.COM 	(void) strlcpy(link, dzp->diz_link, MAXLINKNAMELEN);
9703448Sdh155122 
9713448Sdh155122 	/* Do nothing if setting to current value */
9723448Sdh155122 	if (zid_new == zid_old)
9735895Syz147064 		return (status);
9745895Syz147064 
9755895Syz147064 	if (zid_new != GLOBAL_ZONEID) {
9765895Syz147064 		/*
9775895Syz147064 		 * If the new zoneid is the global zone, we could destroy
9785895Syz147064 		 * the link (in the case of an implicitly-created VLAN) as a
979*7342SAruna.Ramakrishna@Sun.COM 		 * result of setting the zoneid. In that case, we defer the
980*7342SAruna.Ramakrishna@Sun.COM 		 * operation to the end of this function to avoid recreating
981*7342SAruna.Ramakrishna@Sun.COM 		 * the VLAN and getting a different linkid during the rollback
982*7342SAruna.Ramakrishna@Sun.COM 		 * if other operation fails.
9835895Syz147064 		 *
984*7342SAruna.Ramakrishna@Sun.COM 		 * Otherwise, this operation will hold a reference to the
9855895Syz147064 		 * link and prevent a link renaming, so we need to do it
9865895Syz147064 		 * before other operations.
9875895Syz147064 		 */
988*7342SAruna.Ramakrishna@Sun.COM 		status = i_dladm_set_public_prop(pd, linkid, vdp, val_cnt,
989*7342SAruna.Ramakrishna@Sun.COM 		    flags, media);
9905895Syz147064 		if (status != DLADM_STATUS_OK)
9915895Syz147064 			return (status);
9925895Syz147064 	}
9935895Syz147064 
9943448Sdh155122 	if (zid_old != GLOBAL_ZONEID) {
9955895Syz147064 		if (zone_remove_datalink(zid_old, link) != 0 &&
9963448Sdh155122 		    errno != ENXIO) {
9973448Sdh155122 			status = dladm_errno2status(errno);
9983448Sdh155122 			goto rollback1;
9993448Sdh155122 		}
10003448Sdh155122 
10015895Syz147064 		/*
10025895Syz147064 		 * It is okay to fail to update the /dev entry (some
10035895Syz147064 		 * vanity-named links do not have a /dev entry).
10045895Syz147064 		 */
10055895Syz147064 		(void) i_dladm_update_deventry(zid_old, linkid, B_FALSE);
10065895Syz147064 	}
10075895Syz147064 
10085895Syz147064 	if (zid_new != GLOBAL_ZONEID) {
10095895Syz147064 		if (zone_add_datalink(zid_new, link) != 0) {
10105895Syz147064 			status = dladm_errno2status(errno);
10115895Syz147064 			goto rollback2;
10125895Syz147064 		}
10135895Syz147064 
1014*7342SAruna.Ramakrishna@Sun.COM 		if (dzp->diz_is_ppa_hack) {
1015*7342SAruna.Ramakrishna@Sun.COM 			if ((status = dladm_name2info(link, &linkid, NULL, NULL,
1016*7342SAruna.Ramakrishna@Sun.COM 			    NULL)) != DLADM_STATUS_OK) {
1017*7342SAruna.Ramakrishna@Sun.COM 				return (status);
1018*7342SAruna.Ramakrishna@Sun.COM 			}
1019*7342SAruna.Ramakrishna@Sun.COM 		}
1020*7342SAruna.Ramakrishna@Sun.COM 
10215895Syz147064 		(void) i_dladm_update_deventry(zid_new, linkid, B_TRUE);
10225895Syz147064 	} else {
1023*7342SAruna.Ramakrishna@Sun.COM 		status = i_dladm_set_public_prop(pd, linkid, vdp, val_cnt,
1024*7342SAruna.Ramakrishna@Sun.COM 		    flags, media);
10253448Sdh155122 		if (status != DLADM_STATUS_OK)
10263448Sdh155122 			goto rollback2;
10273448Sdh155122 	}
10283448Sdh155122 
10293448Sdh155122 	return (DLADM_STATUS_OK);
10303448Sdh155122 
10313448Sdh155122 rollback2:
10323448Sdh155122 	if (zid_old != GLOBAL_ZONEID)
10335895Syz147064 		(void) i_dladm_update_deventry(zid_old, linkid, B_TRUE);
10345895Syz147064 	if (zid_old != GLOBAL_ZONEID)
10355895Syz147064 		(void) zone_add_datalink(zid_old, link);
10363448Sdh155122 rollback1:
1037*7342SAruna.Ramakrishna@Sun.COM 	if (zid_new != GLOBAL_ZONEID) {
1038*7342SAruna.Ramakrishna@Sun.COM 		dzp->diz_zid = zid_old;
1039*7342SAruna.Ramakrishna@Sun.COM 		(void) i_dladm_set_public_prop(pd, linkid, vdp, val_cnt,
1040*7342SAruna.Ramakrishna@Sun.COM 		    flags, media);
1041*7342SAruna.Ramakrishna@Sun.COM 	}
1042*7342SAruna.Ramakrishna@Sun.COM 
10433448Sdh155122 	return (status);
10443448Sdh155122 }
10453448Sdh155122 
10463448Sdh155122 /* ARGSUSED */
10473448Sdh155122 static dladm_status_t
10485903Ssowmini do_check_zone(struct prop_desc *pd, datalink_id_t linkid, char **prop_val,
10495960Ssowmini     uint_t val_cnt, val_desc_t *vdp, datalink_media_t media)
10503448Sdh155122 {
1051*7342SAruna.Ramakrishna@Sun.COM 	char		*zone_name;
1052*7342SAruna.Ramakrishna@Sun.COM 	char		linkname[MAXLINKNAMELEN];
1053*7342SAruna.Ramakrishna@Sun.COM 	zoneid_t	zoneid;
1054*7342SAruna.Ramakrishna@Sun.COM 	char		*cp;
1055*7342SAruna.Ramakrishna@Sun.COM 	dladm_status_t	status = DLADM_STATUS_OK;
1056*7342SAruna.Ramakrishna@Sun.COM 	boolean_t	is_ppa_hack = B_FALSE;
1057*7342SAruna.Ramakrishna@Sun.COM 	dld_ioc_zid_t	*dzp;
10583448Sdh155122 
10593448Sdh155122 	if (val_cnt != 1)
10603448Sdh155122 		return (DLADM_STATUS_BADVALCNT);
10613448Sdh155122 
1062*7342SAruna.Ramakrishna@Sun.COM 	dzp = malloc(sizeof (dld_ioc_zid_t));
1063*7342SAruna.Ramakrishna@Sun.COM 	if (dzp == NULL)
1064*7342SAruna.Ramakrishna@Sun.COM 		return (DLADM_STATUS_NOMEM);
10653448Sdh155122 
1066*7342SAruna.Ramakrishna@Sun.COM 	if (prop_val) {
1067*7342SAruna.Ramakrishna@Sun.COM 		/*
1068*7342SAruna.Ramakrishna@Sun.COM 		 * The prop_val contains zone_name{:linkname}. The linkname is
1069*7342SAruna.Ramakrishna@Sun.COM 		 * present only when the link is a ppa-hacked vlan.
1070*7342SAruna.Ramakrishna@Sun.COM 		 */
1071*7342SAruna.Ramakrishna@Sun.COM 		cp = strchr(*prop_val, ':');
1072*7342SAruna.Ramakrishna@Sun.COM 		if (cp) {
1073*7342SAruna.Ramakrishna@Sun.COM 			(void) strlcpy(linkname, cp + 1, MAXLINKNAMELEN);
1074*7342SAruna.Ramakrishna@Sun.COM 			*cp = '\0';
1075*7342SAruna.Ramakrishna@Sun.COM 			is_ppa_hack = B_TRUE;
1076*7342SAruna.Ramakrishna@Sun.COM 		} else {
1077*7342SAruna.Ramakrishna@Sun.COM 			status = dladm_datalink_id2info(linkid, NULL, NULL,
1078*7342SAruna.Ramakrishna@Sun.COM 			    NULL, linkname, MAXLINKNAMELEN);
1079*7342SAruna.Ramakrishna@Sun.COM 			if (status != DLADM_STATUS_OK) {
1080*7342SAruna.Ramakrishna@Sun.COM 				goto done;
1081*7342SAruna.Ramakrishna@Sun.COM 			}
1082*7342SAruna.Ramakrishna@Sun.COM 		}
1083*7342SAruna.Ramakrishna@Sun.COM 		zone_name = *prop_val;
1084*7342SAruna.Ramakrishna@Sun.COM 	} else {
1085*7342SAruna.Ramakrishna@Sun.COM 		zone_name = GLOBAL_ZONENAME;
1086*7342SAruna.Ramakrishna@Sun.COM 		if ((status = dladm_datalink_id2info(linkid, NULL, NULL, NULL,
1087*7342SAruna.Ramakrishna@Sun.COM 		    linkname, MAXLINKNAMELEN)) != DLADM_STATUS_OK) {
1088*7342SAruna.Ramakrishna@Sun.COM 			goto done;
1089*7342SAruna.Ramakrishna@Sun.COM 		}
1090*7342SAruna.Ramakrishna@Sun.COM 	}
1091*7342SAruna.Ramakrishna@Sun.COM 
1092*7342SAruna.Ramakrishna@Sun.COM 	if (strlen(linkname) > MAXLINKNAMELEN) {
1093*7342SAruna.Ramakrishna@Sun.COM 		status = DLADM_STATUS_BADVAL;
1094*7342SAruna.Ramakrishna@Sun.COM 		goto done;
1095*7342SAruna.Ramakrishna@Sun.COM 	}
1096*7342SAruna.Ramakrishna@Sun.COM 
1097*7342SAruna.Ramakrishna@Sun.COM 	if ((zoneid = getzoneidbyname(zone_name)) == -1) {
1098*7342SAruna.Ramakrishna@Sun.COM 		status = DLADM_STATUS_BADVAL;
1099*7342SAruna.Ramakrishna@Sun.COM 		goto done;
1100*7342SAruna.Ramakrishna@Sun.COM 	}
1101*7342SAruna.Ramakrishna@Sun.COM 
1102*7342SAruna.Ramakrishna@Sun.COM 	if (zoneid != GLOBAL_ZONEID) {
11033448Sdh155122 		ushort_t	flags;
11043448Sdh155122 
1105*7342SAruna.Ramakrishna@Sun.COM 		if (zone_getattr(zoneid, ZONE_ATTR_FLAGS, &flags,
11063448Sdh155122 		    sizeof (flags)) < 0) {
1107*7342SAruna.Ramakrishna@Sun.COM 			status = dladm_errno2status(errno);
1108*7342SAruna.Ramakrishna@Sun.COM 			goto done;
11093448Sdh155122 		}
11103448Sdh155122 
11113448Sdh155122 		if (!(flags & ZF_NET_EXCL)) {
1112*7342SAruna.Ramakrishna@Sun.COM 			status = DLADM_STATUS_BADVAL;
1113*7342SAruna.Ramakrishna@Sun.COM 			goto done;
11143448Sdh155122 		}
11153448Sdh155122 	}
11163448Sdh155122 
1117*7342SAruna.Ramakrishna@Sun.COM 	(void) memset(dzp, 0, sizeof (dld_ioc_zid_t));
1118*7342SAruna.Ramakrishna@Sun.COM 
1119*7342SAruna.Ramakrishna@Sun.COM 	dzp->diz_zid = zoneid;
1120*7342SAruna.Ramakrishna@Sun.COM 	(void) strlcpy(dzp->diz_link, linkname, MAXLINKNAMELEN);
1121*7342SAruna.Ramakrishna@Sun.COM 	dzp->diz_is_ppa_hack = is_ppa_hack;
1122*7342SAruna.Ramakrishna@Sun.COM 
1123*7342SAruna.Ramakrishna@Sun.COM 	vdp->vd_val = (uintptr_t)dzp;
11245895Syz147064 	return (DLADM_STATUS_OK);
1125*7342SAruna.Ramakrishna@Sun.COM done:
1126*7342SAruna.Ramakrishna@Sun.COM 	free(dzp);
1127*7342SAruna.Ramakrishna@Sun.COM 	return (status);
11285895Syz147064 }
11295895Syz147064 
11305903Ssowmini /* ARGSUSED */
11315895Syz147064 static dladm_status_t
11325903Ssowmini do_get_autopush(struct prop_desc *pd, datalink_id_t linkid,
11336512Ssowmini     char **prop_val, uint_t *val_cnt, datalink_media_t media, uint_t flags)
11345895Syz147064 {
1135*7342SAruna.Ramakrishna@Sun.COM 	struct		dlautopush dlap;
1136*7342SAruna.Ramakrishna@Sun.COM 	int		i, len;
1137*7342SAruna.Ramakrishna@Sun.COM 	dladm_status_t	status;
1138*7342SAruna.Ramakrishna@Sun.COM 	dld_ioc_macprop_t	*dip;
11395895Syz147064 
11406789Sam223141 	if (flags & MAC_PROP_DEFAULT)
11416512Ssowmini 		return (DLADM_STATUS_NOTSUP);
11426512Ssowmini 
11435895Syz147064 	*val_cnt = 1;
1144*7342SAruna.Ramakrishna@Sun.COM 	dip = i_dladm_get_public_prop(linkid, pd->pd_name, flags, &status);
1145*7342SAruna.Ramakrishna@Sun.COM 	if (dip == NULL) {
11465895Syz147064 		(*prop_val)[0] = '\0';
11475895Syz147064 		goto done;
11485895Syz147064 	}
1149*7342SAruna.Ramakrishna@Sun.COM 	(void) memcpy(&dlap, dip->pr_val, sizeof (dlap));
11505895Syz147064 
1151*7342SAruna.Ramakrishna@Sun.COM 	for (i = 0, len = 0; i < dlap.dap_npush; i++) {
11525895Syz147064 		if (i != 0) {
11535895Syz147064 			(void) snprintf(*prop_val + len,
11545895Syz147064 			    DLADM_PROP_VAL_MAX - len, "%c", AP_DELIMITER);
11555895Syz147064 			len += 1;
11565895Syz147064 		}
11575895Syz147064 		(void) snprintf(*prop_val + len, DLADM_PROP_VAL_MAX - len,
1158*7342SAruna.Ramakrishna@Sun.COM 		    "%s", dlap.dap_aplist[i]);
1159*7342SAruna.Ramakrishna@Sun.COM 		len += strlen(dlap.dap_aplist[i]);
1160*7342SAruna.Ramakrishna@Sun.COM 		if (dlap.dap_anchor - 1 == i) {
11615895Syz147064 			(void) snprintf(*prop_val + len,
11625895Syz147064 			    DLADM_PROP_VAL_MAX - len, "%c%s", AP_DELIMITER,
11635895Syz147064 			    AP_ANCHOR);
11645895Syz147064 			len += (strlen(AP_ANCHOR) + 1);
11655895Syz147064 		}
11665895Syz147064 	}
11675895Syz147064 
1168*7342SAruna.Ramakrishna@Sun.COM 	free(dip);
11695895Syz147064 done:
11705895Syz147064 	return (DLADM_STATUS_OK);
11715895Syz147064 }
11725895Syz147064 
11735895Syz147064 /*
11745895Syz147064  * Add the specified module to the dlautopush structure; returns a
11755895Syz147064  * DLADM_STATUS_* code.
11765895Syz147064  */
11775895Syz147064 dladm_status_t
11785895Syz147064 i_dladm_add_ap_module(const char *module, struct dlautopush *dlap)
11795895Syz147064 {
11805895Syz147064 	if ((strlen(module) == 0) || (strlen(module) > FMNAMESZ))
11815895Syz147064 		return (DLADM_STATUS_BADVAL);
11825895Syz147064 
11835895Syz147064 	if (strncasecmp(module, AP_ANCHOR, strlen(AP_ANCHOR)) == 0) {
11845895Syz147064 		/*
11855895Syz147064 		 * We don't allow multiple anchors, and the anchor must
11865895Syz147064 		 * be after at least one module.
11875895Syz147064 		 */
11885895Syz147064 		if (dlap->dap_anchor != 0)
11895895Syz147064 			return (DLADM_STATUS_BADVAL);
11905895Syz147064 		if (dlap->dap_npush == 0)
11915895Syz147064 			return (DLADM_STATUS_BADVAL);
11925895Syz147064 
11935895Syz147064 		dlap->dap_anchor = dlap->dap_npush;
11945895Syz147064 		return (DLADM_STATUS_OK);
11955895Syz147064 	}
11965895Syz147064 	if (dlap->dap_npush > MAXAPUSH)
11975895Syz147064 		return (DLADM_STATUS_BADVALCNT);
11985895Syz147064 
11995895Syz147064 	(void) strlcpy(dlap->dap_aplist[dlap->dap_npush++], module,
12005895Syz147064 	    FMNAMESZ + 1);
12015895Syz147064 
12025895Syz147064 	return (DLADM_STATUS_OK);
12035895Syz147064 }
12045895Syz147064 
12055895Syz147064 /*
12065895Syz147064  * Currently, both '.' and ' '(space) can be used as the delimiters between
12075895Syz147064  * autopush modules. The former is used in dladm set-linkprop, and the
12085895Syz147064  * latter is used in the autopush(1M) file.
12095895Syz147064  */
12105895Syz147064 /* ARGSUSED */
12115895Syz147064 static dladm_status_t
12125903Ssowmini do_check_autopush(struct prop_desc *pd, datalink_id_t linkid, char **prop_val,
12135960Ssowmini     uint_t val_cnt, val_desc_t *vdp, datalink_media_t media)
12145895Syz147064 {
12155895Syz147064 	char			*module;
12165895Syz147064 	struct dlautopush	*dlap;
12175895Syz147064 	dladm_status_t		status;
12185895Syz147064 	char			val[DLADM_PROP_VAL_MAX];
12195895Syz147064 	char			delimiters[4];
12205895Syz147064 
12215895Syz147064 	if (val_cnt != 1)
12225895Syz147064 		return (DLADM_STATUS_BADVALCNT);
12235895Syz147064 
1224*7342SAruna.Ramakrishna@Sun.COM 	if (prop_val != NULL) {
1225*7342SAruna.Ramakrishna@Sun.COM 		dlap = malloc(sizeof (struct dlautopush));
1226*7342SAruna.Ramakrishna@Sun.COM 		if (dlap == NULL)
1227*7342SAruna.Ramakrishna@Sun.COM 			return (DLADM_STATUS_NOMEM);
12283448Sdh155122 
1229*7342SAruna.Ramakrishna@Sun.COM 		(void) memset(dlap, 0, sizeof (struct dlautopush));
1230*7342SAruna.Ramakrishna@Sun.COM 		(void) snprintf(delimiters, 4, " %c\n", AP_DELIMITER);
1231*7342SAruna.Ramakrishna@Sun.COM 		bcopy(*prop_val, val, DLADM_PROP_VAL_MAX);
1232*7342SAruna.Ramakrishna@Sun.COM 		module = strtok(val, delimiters);
1233*7342SAruna.Ramakrishna@Sun.COM 		while (module != NULL) {
1234*7342SAruna.Ramakrishna@Sun.COM 			status = i_dladm_add_ap_module(module, dlap);
1235*7342SAruna.Ramakrishna@Sun.COM 			if (status != DLADM_STATUS_OK)
1236*7342SAruna.Ramakrishna@Sun.COM 				return (status);
1237*7342SAruna.Ramakrishna@Sun.COM 			module = strtok(NULL, delimiters);
1238*7342SAruna.Ramakrishna@Sun.COM 		}
1239*7342SAruna.Ramakrishna@Sun.COM 
1240*7342SAruna.Ramakrishna@Sun.COM 		vdp->vd_val = (uintptr_t)dlap;
1241*7342SAruna.Ramakrishna@Sun.COM 	} else {
1242*7342SAruna.Ramakrishna@Sun.COM 		vdp->vd_val = 0;
12435895Syz147064 	}
12443448Sdh155122 	return (DLADM_STATUS_OK);
12453448Sdh155122 }
12463448Sdh155122 
12475903Ssowmini /* ARGSUSED */
12483448Sdh155122 static dladm_status_t
12495903Ssowmini do_get_rate_common(struct prop_desc *pd, datalink_id_t linkid,
12505903Ssowmini     char **prop_val, uint_t *val_cnt, uint_t id)
12513448Sdh155122 {
12525895Syz147064 	wl_rates_t	*wrp;
12535895Syz147064 	uint_t		i;
12545895Syz147064 	wldp_t		*gbuf = NULL;
12555895Syz147064 	dladm_status_t	status = DLADM_STATUS_OK;
12565895Syz147064 
12575895Syz147064 	if ((gbuf = malloc(MAX_BUF_LEN)) == NULL) {
12585895Syz147064 		status = DLADM_STATUS_NOMEM;
12595895Syz147064 		goto done;
12605895Syz147064 	}
12615895Syz147064 
12625895Syz147064 	status = i_dladm_wlan_get_ioctl(linkid, gbuf, id);
12635895Syz147064 	if (status != DLADM_STATUS_OK)
12645895Syz147064 		goto done;
12655895Syz147064 
12665895Syz147064 	wrp = (wl_rates_t *)gbuf->wldp_buf;
12675895Syz147064 	if (wrp->wl_rates_num > *val_cnt) {
12685895Syz147064 		status = DLADM_STATUS_TOOSMALL;
12695895Syz147064 		goto done;
12705895Syz147064 	}
12715895Syz147064 
12725895Syz147064 	if (wrp->wl_rates_rates[0] == 0) {
12735895Syz147064 		prop_val[0][0] = '\0';
12745895Syz147064 		*val_cnt = 1;
12755895Syz147064 		goto done;
12765895Syz147064 	}
12775895Syz147064 
12785895Syz147064 	for (i = 0; i < wrp->wl_rates_num; i++) {
12795895Syz147064 		(void) snprintf(prop_val[i], DLADM_STRSIZE, "%.*f",
12805895Syz147064 		    wrp->wl_rates_rates[i] % 2,
12815895Syz147064 		    (float)wrp->wl_rates_rates[i] / 2);
12825895Syz147064 	}
12835895Syz147064 	*val_cnt = wrp->wl_rates_num;
12843448Sdh155122 
12855895Syz147064 done:
12865895Syz147064 	free(gbuf);
12875895Syz147064 	return (status);
12885895Syz147064 }
12895895Syz147064 
12905895Syz147064 static dladm_status_t
12915903Ssowmini do_get_rate_prop(struct prop_desc *pd, datalink_id_t linkid,
12926512Ssowmini     char **prop_val, uint_t *val_cnt, datalink_media_t media, uint_t flags)
12935895Syz147064 {
12945960Ssowmini 	if (media != DL_WIFI)
1295*7342SAruna.Ramakrishna@Sun.COM 		return (i_dladm_speed_get(pd, linkid, prop_val,
1296*7342SAruna.Ramakrishna@Sun.COM 		    val_cnt, flags));
12975960Ssowmini 
12985903Ssowmini 	return (do_get_rate_common(pd, linkid, prop_val, val_cnt,
12995895Syz147064 	    WL_DESIRED_RATES));
13005895Syz147064 }
13015895Syz147064 
13026512Ssowmini /* ARGSUSED */
13035895Syz147064 static dladm_status_t
13045903Ssowmini do_get_rate_mod(struct prop_desc *pd, datalink_id_t linkid,
13056512Ssowmini     char **prop_val, uint_t *val_cnt, datalink_media_t media, uint_t flags)
13065895Syz147064 {
13075960Ssowmini 	switch (media) {
13085960Ssowmini 	case DL_ETHER:
13096512Ssowmini 		/*
13106512Ssowmini 		 * Speed for ethernet links is unbounded. E.g., 802.11b
13116512Ssowmini 		 * links can have a speed of 5.5 Gbps.
13126512Ssowmini 		 */
13136512Ssowmini 		return (DLADM_STATUS_NOTSUP);
13145960Ssowmini 
13155960Ssowmini 	case DL_WIFI:
13165960Ssowmini 		return (do_get_rate_common(pd, linkid, prop_val, val_cnt,
13175960Ssowmini 		    WL_SUPPORTED_RATES));
13185960Ssowmini 	default:
13195960Ssowmini 		return (DLADM_STATUS_BADARG);
13205960Ssowmini 	}
13215895Syz147064 }
13225895Syz147064 
13235895Syz147064 static dladm_status_t
13245895Syz147064 do_set_rate(datalink_id_t linkid, dladm_wlan_rates_t *rates)
13255895Syz147064 {
13265895Syz147064 	int		i;
13275895Syz147064 	uint_t		len;
13285895Syz147064 	wldp_t		*gbuf;
13295895Syz147064 	wl_rates_t	*wrp;
13305895Syz147064 	dladm_status_t	status = DLADM_STATUS_OK;
13315895Syz147064 
13325895Syz147064 	if ((gbuf = malloc(MAX_BUF_LEN)) == NULL)
13335895Syz147064 		return (DLADM_STATUS_NOMEM);
13345895Syz147064 
13355895Syz147064 	(void) memset(gbuf, 0, MAX_BUF_LEN);
13363448Sdh155122 
13375895Syz147064 	wrp = (wl_rates_t *)gbuf->wldp_buf;
13385895Syz147064 	for (i = 0; i < rates->wr_cnt; i++)
13395895Syz147064 		wrp->wl_rates_rates[i] = rates->wr_rates[i];
13405895Syz147064 	wrp->wl_rates_num = rates->wr_cnt;
13415895Syz147064 
13425895Syz147064 	len = offsetof(wl_rates_t, wl_rates_rates) +
13435895Syz147064 	    (rates->wr_cnt * sizeof (char)) + WIFI_BUF_OFFSET;
13445895Syz147064 	status = i_dladm_wlan_ioctl(linkid, gbuf, WL_DESIRED_RATES, len,
13455895Syz147064 	    WLAN_SET_PARAM, len);
13465895Syz147064 
13475895Syz147064 	free(gbuf);
13485895Syz147064 	return (status);
13495895Syz147064 }
13503448Sdh155122 
13515903Ssowmini /* ARGSUSED */
13525895Syz147064 static dladm_status_t
13535903Ssowmini do_set_rate_prop(prop_desc_t *pd, datalink_id_t linkid,
13545960Ssowmini     val_desc_t *vdp, uint_t val_cnt, uint_t flags, datalink_media_t media)
13555895Syz147064 {
13565895Syz147064 	dladm_wlan_rates_t	rates;
13575895Syz147064 	dladm_status_t		status;
13585895Syz147064 
13595960Ssowmini 	/*
13605960Ssowmini 	 * can currently set rate on WIFI links only.
13615960Ssowmini 	 */
13625960Ssowmini 	if (media != DL_WIFI)
13635960Ssowmini 		return (DLADM_STATUS_PROPRDONLY);
13645960Ssowmini 
13655895Syz147064 	if (val_cnt != 1)
13665895Syz147064 		return (DLADM_STATUS_BADVALCNT);
13675895Syz147064 
13685895Syz147064 	rates.wr_cnt = 1;
13695895Syz147064 	rates.wr_rates[0] = vdp[0].vd_val;
13705895Syz147064 
13715895Syz147064 	status = do_set_rate(linkid, &rates);
13725895Syz147064 
13735895Syz147064 done:
13745895Syz147064 	return (status);
13755895Syz147064 }
13763448Sdh155122 
13775895Syz147064 /* ARGSUSED */
13785895Syz147064 static dladm_status_t
13795903Ssowmini do_check_rate(struct prop_desc *pd, datalink_id_t linkid, char **prop_val,
13805960Ssowmini     uint_t val_cnt, val_desc_t *vdp, datalink_media_t media)
13815895Syz147064 {
13825895Syz147064 	int		i;
13835895Syz147064 	uint_t		modval_cnt = MAX_SUPPORT_RATES;
13845895Syz147064 	char		*buf, **modval;
13855895Syz147064 	dladm_status_t	status;
13865895Syz147064 
13875895Syz147064 	if (val_cnt != 1)
13885895Syz147064 		return (DLADM_STATUS_BADVALCNT);
13895895Syz147064 
13905895Syz147064 	buf = malloc((sizeof (char *) + DLADM_STRSIZE) *
13915895Syz147064 	    MAX_SUPPORT_RATES);
13925895Syz147064 	if (buf == NULL) {
13935895Syz147064 		status = DLADM_STATUS_NOMEM;
13945895Syz147064 		goto done;
13955895Syz147064 	}
13963448Sdh155122 
13975895Syz147064 	modval = (char **)(void *)buf;
13985895Syz147064 	for (i = 0; i < MAX_SUPPORT_RATES; i++) {
13995895Syz147064 		modval[i] = buf + sizeof (char *) * MAX_SUPPORT_RATES +
14005895Syz147064 		    i * DLADM_STRSIZE;
14015895Syz147064 	}
14025895Syz147064 
14036512Ssowmini 	status = do_get_rate_mod(NULL, linkid, modval, &modval_cnt, media, 0);
14045895Syz147064 	if (status != DLADM_STATUS_OK)
14055895Syz147064 		goto done;
14065895Syz147064 
14075895Syz147064 	for (i = 0; i < modval_cnt; i++) {
14085895Syz147064 		if (strcasecmp(*prop_val, modval[i]) == 0) {
14095903Ssowmini 			vdp->vd_val = (uintptr_t)(uint_t)
14105903Ssowmini 			    (atof(*prop_val) * 2);
14115895Syz147064 			status = DLADM_STATUS_OK;
14123448Sdh155122 			break;
14133448Sdh155122 		}
14145895Syz147064 	}
14155895Syz147064 	if (i == modval_cnt)
14165895Syz147064 		status = DLADM_STATUS_BADVAL;
14175895Syz147064 done:
14185895Syz147064 	free(buf);
14195895Syz147064 	return (status);
14205895Syz147064 }
14215895Syz147064 
14225895Syz147064 static dladm_status_t
14235895Syz147064 do_get_phyconf(datalink_id_t linkid, wldp_t *gbuf)
14245895Syz147064 {
14255895Syz147064 	return (i_dladm_wlan_get_ioctl(linkid, gbuf, WL_PHY_CONFIG));
14265895Syz147064 }
14275895Syz147064 
14285903Ssowmini /* ARGSUSED */
14295895Syz147064 static dladm_status_t
14305903Ssowmini do_get_channel_prop(struct prop_desc *pd, datalink_id_t linkid,
14316512Ssowmini     char **prop_val, uint_t *val_cnt, datalink_media_t media, uint_t flags)
14325895Syz147064 {
14335895Syz147064 	uint32_t	channel;
14345895Syz147064 	wldp_t		*gbuf;
14355895Syz147064 	dladm_status_t	status = DLADM_STATUS_OK;
14365895Syz147064 
14375895Syz147064 	if ((gbuf = malloc(MAX_BUF_LEN)) == NULL)
14385895Syz147064 		return (DLADM_STATUS_NOMEM);
14395895Syz147064 
14405895Syz147064 	if ((status = do_get_phyconf(linkid, gbuf)) != DLADM_STATUS_OK)
14415895Syz147064 		goto done;
14425895Syz147064 
14435895Syz147064 	if (!i_dladm_wlan_convert_chan((wl_phy_conf_t *)gbuf->wldp_buf,
14445895Syz147064 	    &channel)) {
14455895Syz147064 		status = DLADM_STATUS_NOTFOUND;
14465895Syz147064 		goto done;
14475895Syz147064 	}
14485895Syz147064 
14495895Syz147064 	(void) snprintf(*prop_val, DLADM_STRSIZE, "%u", channel);
14505895Syz147064 	*val_cnt = 1;
14513448Sdh155122 
14525895Syz147064 done:
14535895Syz147064 	free(gbuf);
14545895Syz147064 	return (status);
14555895Syz147064 }
14565895Syz147064 
14575895Syz147064 static dladm_status_t
14585895Syz147064 do_get_powermode(datalink_id_t linkid, wldp_t *gbuf)
14595895Syz147064 {
14605895Syz147064 	return (i_dladm_wlan_get_ioctl(linkid, gbuf, WL_POWER_MODE));
14615895Syz147064 }
14625895Syz147064 
14635903Ssowmini /* ARGSUSED */
14645895Syz147064 static dladm_status_t
14655903Ssowmini do_get_powermode_prop(struct prop_desc *pd, datalink_id_t linkid,
14666512Ssowmini     char **prop_val, uint_t *val_cnt, datalink_media_t media, uint_t flags)
14675895Syz147064 {
14685895Syz147064 	wl_ps_mode_t	*mode;
14695895Syz147064 	const char	*s;
14705895Syz147064 	wldp_t		*gbuf;
14715895Syz147064 	dladm_status_t	status = DLADM_STATUS_OK;
14725895Syz147064 
14735895Syz147064 	if ((gbuf = malloc(MAX_BUF_LEN)) == NULL)
14745895Syz147064 		return (DLADM_STATUS_NOMEM);
14755895Syz147064 
14765895Syz147064 	if ((status = do_get_powermode(linkid, gbuf)) != DLADM_STATUS_OK)
14775895Syz147064 		goto done;
14785895Syz147064 
14795895Syz147064 	mode = (wl_ps_mode_t *)(gbuf->wldp_buf);
14805895Syz147064 	switch (mode->wl_ps_mode) {
14815895Syz147064 	case WL_PM_AM:
14825895Syz147064 		s = "off";
14835895Syz147064 		break;
14845895Syz147064 	case WL_PM_MPS:
14855895Syz147064 		s = "max";
14865895Syz147064 		break;
14875895Syz147064 	case WL_PM_FAST:
14885895Syz147064 		s = "fast";
14893448Sdh155122 		break;
14903448Sdh155122 	default:
14915895Syz147064 		status = DLADM_STATUS_NOTFOUND;
14925895Syz147064 		goto done;
14935895Syz147064 	}
14945895Syz147064 	(void) snprintf(*prop_val, DLADM_STRSIZE, "%s", s);
14955895Syz147064 	*val_cnt = 1;
14965895Syz147064 
14975895Syz147064 done:
14985895Syz147064 	free(gbuf);
14995895Syz147064 	return (status);
15005895Syz147064 }
15015895Syz147064 
15025895Syz147064 static dladm_status_t
15035895Syz147064 do_set_powermode(datalink_id_t linkid, dladm_wlan_powermode_t *pm)
15045895Syz147064 {
15055895Syz147064 	wl_ps_mode_t    ps_mode;
15065895Syz147064 
15075895Syz147064 	(void) memset(&ps_mode, 0xff, sizeof (ps_mode));
15085895Syz147064 
15095895Syz147064 	switch (*pm) {
15105895Syz147064 	case DLADM_WLAN_PM_OFF:
15115895Syz147064 		ps_mode.wl_ps_mode = WL_PM_AM;
15123448Sdh155122 		break;
15135895Syz147064 	case DLADM_WLAN_PM_MAX:
15145895Syz147064 		ps_mode.wl_ps_mode = WL_PM_MPS;
15155895Syz147064 		break;
15165895Syz147064 	case DLADM_WLAN_PM_FAST:
15175895Syz147064 		ps_mode.wl_ps_mode = WL_PM_FAST;
15185895Syz147064 		break;
15195895Syz147064 	default:
15205895Syz147064 		return (DLADM_STATUS_NOTSUP);
15213448Sdh155122 	}
15225895Syz147064 	return (i_dladm_wlan_set_ioctl(linkid, WL_POWER_MODE, &ps_mode,
15235895Syz147064 	    sizeof (ps_mode)));
15245895Syz147064 }
15255895Syz147064 
15265895Syz147064 /* ARGSUSED */
15275895Syz147064 static dladm_status_t
15285903Ssowmini do_set_powermode_prop(prop_desc_t *pd, datalink_id_t linkid,
15295960Ssowmini     val_desc_t *vdp, uint_t val_cnt, uint_t flags, datalink_media_t media)
15305895Syz147064 {
15315895Syz147064 	dladm_wlan_powermode_t powermode = (dladm_wlan_powermode_t)vdp->vd_val;
15325895Syz147064 	dladm_status_t status;
15335895Syz147064 
15345895Syz147064 	if (val_cnt != 1)
15355895Syz147064 		return (DLADM_STATUS_BADVALCNT);
15365895Syz147064 
15375895Syz147064 	status = do_set_powermode(linkid, &powermode);
15383448Sdh155122 
15393448Sdh155122 	return (status);
15403448Sdh155122 }
15413448Sdh155122 
15423448Sdh155122 static dladm_status_t
15435895Syz147064 do_get_radio(datalink_id_t linkid, wldp_t *gbuf)
15443448Sdh155122 {
15455895Syz147064 	return (i_dladm_wlan_get_ioctl(linkid, gbuf, WL_RADIO));
15465895Syz147064 }
15473448Sdh155122 
15485903Ssowmini /* ARGSUSED */
15495895Syz147064 static dladm_status_t
15505903Ssowmini do_get_radio_prop(struct prop_desc *pd, datalink_id_t linkid,
15516512Ssowmini     char **prop_val, uint_t *val_cnt, datalink_media_t media, uint_t flags)
15525895Syz147064 {
15535895Syz147064 	wl_radio_t	radio;
15545895Syz147064 	const char	*s;
15555895Syz147064 	wldp_t		*gbuf;
15565895Syz147064 	dladm_status_t	status = DLADM_STATUS_OK;
15573448Sdh155122 
15585895Syz147064 	if ((gbuf = malloc(MAX_BUF_LEN)) == NULL)
15595895Syz147064 		return (DLADM_STATUS_NOMEM);
15603448Sdh155122 
15615895Syz147064 	if ((status = do_get_radio(linkid, gbuf)) != DLADM_STATUS_OK)
15625895Syz147064 		goto done;
15633448Sdh155122 
15645895Syz147064 	radio = *(wl_radio_t *)(gbuf->wldp_buf);
15655895Syz147064 	switch (radio) {
15665895Syz147064 	case B_TRUE:
15675895Syz147064 		s = "on";
15685895Syz147064 		break;
15695895Syz147064 	case B_FALSE:
15705895Syz147064 		s = "off";
15715895Syz147064 		break;
15725895Syz147064 	default:
15735895Syz147064 		status = DLADM_STATUS_NOTFOUND;
15745895Syz147064 		goto done;
15755895Syz147064 	}
15765895Syz147064 	(void) snprintf(*prop_val, DLADM_STRSIZE, "%s", s);
15775895Syz147064 	*val_cnt = 1;
15783448Sdh155122 
15795895Syz147064 done:
15805895Syz147064 	free(gbuf);
15813448Sdh155122 	return (status);
15823448Sdh155122 }
15833448Sdh155122 
15843448Sdh155122 static dladm_status_t
15855895Syz147064 do_set_radio(datalink_id_t linkid, dladm_wlan_radio_t *radio)
15863448Sdh155122 {
15875895Syz147064 	wl_radio_t r;
15883448Sdh155122 
15895895Syz147064 	switch (*radio) {
15905895Syz147064 	case DLADM_WLAN_RADIO_ON:
15915895Syz147064 		r = B_TRUE;
15925895Syz147064 		break;
15935895Syz147064 	case DLADM_WLAN_RADIO_OFF:
15945895Syz147064 		r = B_FALSE;
15955895Syz147064 		break;
15965895Syz147064 	default:
15975895Syz147064 		return (DLADM_STATUS_NOTSUP);
15985895Syz147064 	}
15995895Syz147064 	return (i_dladm_wlan_set_ioctl(linkid, WL_RADIO, &r, sizeof (r)));
16005895Syz147064 }
16013448Sdh155122 
16025895Syz147064 /* ARGSUSED */
16035895Syz147064 static dladm_status_t
16045903Ssowmini do_set_radio_prop(prop_desc_t *pd, datalink_id_t linkid,
16055960Ssowmini     val_desc_t *vdp, uint_t val_cnt, uint_t fags, datalink_media_t media)
16065895Syz147064 {
16075895Syz147064 	dladm_wlan_radio_t radio = (dladm_wlan_radio_t)vdp->vd_val;
16085895Syz147064 	dladm_status_t status;
16093448Sdh155122 
16105895Syz147064 	if (val_cnt != 1)
16115895Syz147064 		return (DLADM_STATUS_BADVALCNT);
16125895Syz147064 
16135895Syz147064 	status = do_set_radio(linkid, &radio);
16143448Sdh155122 
16153448Sdh155122 	return (status);
16163448Sdh155122 }
16173448Sdh155122 
16185895Syz147064 static dladm_status_t
16195895Syz147064 i_dladm_set_linkprop_db(datalink_id_t linkid, const char *prop_name,
16205895Syz147064     char **prop_val, uint_t val_cnt)
16213448Sdh155122 {
16225895Syz147064 	char		buf[MAXLINELEN];
16235895Syz147064 	int		i;
16245895Syz147064 	dladm_conf_t	conf;
16255895Syz147064 	dladm_status_t	status;
16263448Sdh155122 
16275895Syz147064 	status = dladm_read_conf(linkid, &conf);
16285895Syz147064 	if (status != DLADM_STATUS_OK)
16295895Syz147064 		return (status);
16303448Sdh155122 
16315895Syz147064 	/*
16325895Syz147064 	 * reset case.
16335895Syz147064 	 */
16345895Syz147064 	if (val_cnt == 0) {
16355895Syz147064 		status = dladm_unset_conf_field(conf, prop_name);
16365895Syz147064 		if (status == DLADM_STATUS_OK)
16375895Syz147064 			status = dladm_write_conf(conf);
16385895Syz147064 		goto done;
16395895Syz147064 	}
16403448Sdh155122 
16415895Syz147064 	buf[0] = '\0';
16425895Syz147064 	for (i = 0; i < val_cnt; i++) {
16435895Syz147064 		(void) strlcat(buf, prop_val[i], MAXLINELEN);
16445895Syz147064 		if (i != val_cnt - 1)
16455895Syz147064 			(void) strlcat(buf, ",", MAXLINELEN);
16463448Sdh155122 	}
16473448Sdh155122 
16485895Syz147064 	status = dladm_set_conf_field(conf, prop_name, DLADM_TYPE_STR, buf);
16495895Syz147064 	if (status == DLADM_STATUS_OK)
16505895Syz147064 		status = dladm_write_conf(conf);
16515895Syz147064 
16525895Syz147064 done:
16535895Syz147064 	dladm_destroy_conf(conf);
16545895Syz147064 	return (status);
16553448Sdh155122 }
16565895Syz147064 
16575895Syz147064 static dladm_status_t
16585895Syz147064 i_dladm_get_linkprop_db(datalink_id_t linkid, const char *prop_name,
16595895Syz147064     char **prop_val, uint_t *val_cntp)
16605895Syz147064 {
16615895Syz147064 	char		buf[MAXLINELEN], *str;
16625895Syz147064 	uint_t		cnt = 0;
16635895Syz147064 	dladm_conf_t	conf;
16645895Syz147064 	dladm_status_t	status;
16655895Syz147064 
16665895Syz147064 	status = dladm_read_conf(linkid, &conf);
16675895Syz147064 	if (status != DLADM_STATUS_OK)
16685895Syz147064 		return (status);
16695895Syz147064 
16705895Syz147064 	status = dladm_get_conf_field(conf, prop_name, buf, MAXLINELEN);
16715895Syz147064 	if (status != DLADM_STATUS_OK)
16725895Syz147064 		goto done;
16735895Syz147064 
16745895Syz147064 	str = strtok(buf, ",");
16755895Syz147064 	while (str != NULL) {
16765895Syz147064 		if (cnt == *val_cntp) {
16775895Syz147064 			status = DLADM_STATUS_TOOSMALL;
16785895Syz147064 			goto done;
16795895Syz147064 		}
16805895Syz147064 		(void) strlcpy(prop_val[cnt++], str, DLADM_PROP_VAL_MAX);
16815895Syz147064 		str = strtok(NULL, ",");
16825895Syz147064 	}
16835895Syz147064 
16845895Syz147064 	*val_cntp = cnt;
16855895Syz147064 
16865895Syz147064 done:
16875895Syz147064 	dladm_destroy_conf(conf);
16885895Syz147064 	return (status);
16895895Syz147064 }
16905903Ssowmini 
1691*7342SAruna.Ramakrishna@Sun.COM static dladm_public_prop_t *
16925903Ssowmini dladm_name2prop(const char *prop_name)
16935903Ssowmini {
1694*7342SAruna.Ramakrishna@Sun.COM 	dladm_public_prop_t *p;
16955903Ssowmini 
1696*7342SAruna.Ramakrishna@Sun.COM 	for (p = dladm_prop; p->pp_id != MAC_PROP_PRIVATE; p++) {
16975903Ssowmini 		if (strcmp(p->pp_name, prop_name) == 0)
16985903Ssowmini 			break;
16995903Ssowmini 	}
17005903Ssowmini 	return (p);
17015903Ssowmini }
17025903Ssowmini 
17035903Ssowmini 
17046789Sam223141 static dld_ioc_macprop_t *
1705*7342SAruna.Ramakrishna@Sun.COM i_dladm_buf_alloc(size_t valsize, datalink_id_t linkid, const char *prop_name,
17066512Ssowmini     uint_t flags, dladm_status_t *status)
17075903Ssowmini {
17085903Ssowmini 	int dsize;
17096789Sam223141 	dld_ioc_macprop_t *dip;
1710*7342SAruna.Ramakrishna@Sun.COM 	dladm_public_prop_t *p;
17115903Ssowmini 
17125903Ssowmini 	*status = DLADM_STATUS_OK;
17135903Ssowmini 	p = dladm_name2prop(prop_name);
17146789Sam223141 	if (p->pp_id != MAC_PROP_PRIVATE)
17155903Ssowmini 		valsize = p->pp_valsize;
17165903Ssowmini 
17176789Sam223141 	dsize = MAC_PROP_BUFSIZE(valsize);
17185903Ssowmini 	dip = malloc(dsize);
17195903Ssowmini 	if (dip == NULL) {
17205903Ssowmini 		*status = DLADM_STATUS_NOMEM;
17215903Ssowmini 		return (NULL);
17225903Ssowmini 	}
17235903Ssowmini 	bzero(dip, dsize);
17245903Ssowmini 	dip->pr_valsize = valsize;
17256512Ssowmini 	(void) strlcpy(dip->pr_name, prop_name, sizeof (dip->pr_name));
17266789Sam223141 	dip->pr_version = MAC_PROP_VERSION;
17275960Ssowmini 	dip->pr_linkid = linkid;
17285903Ssowmini 	dip->pr_num = p->pp_id;
17296512Ssowmini 	dip->pr_flags = flags;
17305903Ssowmini 	return (dip);
17315903Ssowmini }
17325903Ssowmini 
17335903Ssowmini /* ARGSUSED */
17345903Ssowmini static dladm_status_t
1735*7342SAruna.Ramakrishna@Sun.COM i_dladm_set_public_prop(prop_desc_t *pd, datalink_id_t linkid,
17365960Ssowmini     val_desc_t *vdp, uint_t val_cnt, uint_t flags, datalink_media_t media)
17375903Ssowmini {
17386789Sam223141 	dld_ioc_macprop_t	*dip;
17395903Ssowmini 	int		fd, dsize;
17405903Ssowmini 	dladm_status_t	status = DLADM_STATUS_OK;
17415903Ssowmini 	uint8_t		u8;
17425903Ssowmini 	uint16_t	u16;
17435903Ssowmini 	uint32_t	u32;
17445903Ssowmini 	void		*val;
17455903Ssowmini 
1746*7342SAruna.Ramakrishna@Sun.COM 	dip = i_dladm_buf_alloc(0, linkid, pd->pd_name, 0, &status);
17475903Ssowmini 	if (dip == NULL)
17485903Ssowmini 		return (status);
17495903Ssowmini 
17505903Ssowmini 	if (pd->pd_flags & PD_CHECK_ALLOC)
17515903Ssowmini 		val = (void *)vdp->vd_val;
17525903Ssowmini 	else {
17535903Ssowmini 		/*
17545903Ssowmini 		 * Currently all 1/2/4-byte size properties are byte/word/int.
17555903Ssowmini 		 * No need (yet) to distinguish these from arrays of same size.
17565903Ssowmini 		 */
17575903Ssowmini 		switch (dip->pr_valsize) {
17585903Ssowmini 		case 1:
17595903Ssowmini 			u8 = vdp->vd_val;
17605903Ssowmini 			val = &u8;
17615903Ssowmini 			break;
17625903Ssowmini 		case 2:
17635903Ssowmini 			u16 = vdp->vd_val;
17645903Ssowmini 			val = &u16;
17655903Ssowmini 			break;
17665903Ssowmini 		case 4:
17675903Ssowmini 			u32 = vdp->vd_val;
17685903Ssowmini 			val = &u32;
17695903Ssowmini 			break;
17705903Ssowmini 		default:
17715903Ssowmini 			val = &vdp->vd_val;
17725903Ssowmini 			break;
17735903Ssowmini 		}
17745903Ssowmini 	}
17755903Ssowmini 
1776*7342SAruna.Ramakrishna@Sun.COM 	if (val != NULL)
1777*7342SAruna.Ramakrishna@Sun.COM 		(void) memcpy(dip->pr_val, val, dip->pr_valsize);
1778*7342SAruna.Ramakrishna@Sun.COM 	else
1779*7342SAruna.Ramakrishna@Sun.COM 		dip->pr_valsize = 0;
1780*7342SAruna.Ramakrishna@Sun.COM 
17816789Sam223141 	dsize = MAC_PROP_BUFSIZE(dip->pr_valsize);
17825903Ssowmini 	if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) {
17835903Ssowmini 		status = dladm_errno2status(errno);
17845903Ssowmini 		goto done;
17855903Ssowmini 	}
17866789Sam223141 	if (i_dladm_ioctl(fd, DLDIOC_SETMACPROP, dip, dsize) < 0)
17875903Ssowmini 		status = dladm_errno2status(errno);
17885903Ssowmini 
17895903Ssowmini 	(void) close(fd);
17905903Ssowmini done:
17916512Ssowmini 	free(dip);
17925903Ssowmini 	return (status);
17935903Ssowmini }
17945903Ssowmini 
17956789Sam223141 static dld_ioc_macprop_t *
1796*7342SAruna.Ramakrishna@Sun.COM i_dladm_get_public_prop(datalink_id_t linkid, char *prop_name, uint_t flags,
17976512Ssowmini     dladm_status_t *status)
17985903Ssowmini {
17995903Ssowmini 	int fd, dsize;
18006789Sam223141 	dld_ioc_macprop_t *dip = NULL;
18016512Ssowmini 
18026512Ssowmini 	*status = DLADM_STATUS_OK;
18036512Ssowmini 
1804*7342SAruna.Ramakrishna@Sun.COM 	dip = i_dladm_buf_alloc(0, linkid, prop_name, flags, status);
18056512Ssowmini 	if (dip == NULL)
18066512Ssowmini 		return (NULL);
18075903Ssowmini 
18086789Sam223141 	dsize = MAC_PROP_BUFSIZE(dip->pr_valsize);
18095903Ssowmini 
18105903Ssowmini 	if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) {
18116512Ssowmini 		*status = dladm_errno2status(errno);
18125903Ssowmini 		goto done;
18135903Ssowmini 	}
18146789Sam223141 	if (i_dladm_ioctl(fd, DLDIOC_GETMACPROP, dip, dsize) < 0) {
18156512Ssowmini 		*status = dladm_errno2status(errno);
18165903Ssowmini 	}
18176512Ssowmini 
18186512Ssowmini 	(void) close(fd);
18195903Ssowmini done:
18206512Ssowmini 	if (*status != DLADM_STATUS_OK) {
18216512Ssowmini 		free(dip);
18226512Ssowmini 		return (NULL);
18236512Ssowmini 	}
18246512Ssowmini 	return (dip);
18255903Ssowmini }
18265903Ssowmini 
18275903Ssowmini /* ARGSUSED */
18285903Ssowmini static dladm_status_t
1829*7342SAruna.Ramakrishna@Sun.COM i_dladm_defmtu_check(struct prop_desc *pd, datalink_id_t linkid,
1830*7342SAruna.Ramakrishna@Sun.COM     char **prop_val, uint_t val_cnt, val_desc_t *v, datalink_media_t media)
18315903Ssowmini {
18325903Ssowmini 	if (val_cnt != 1)
18335903Ssowmini 		return (DLADM_STATUS_BADVAL);
18346512Ssowmini 	v->vd_val = atoi(prop_val[0]);
18355903Ssowmini 	return (DLADM_STATUS_OK);
18365903Ssowmini }
18375903Ssowmini 
18385903Ssowmini /* ARGSUSED */
18395903Ssowmini static dladm_status_t
1840*7342SAruna.Ramakrishna@Sun.COM i_dladm_duplex_get(struct prop_desc *pd, datalink_id_t linkid,
18416512Ssowmini     char **prop_val, uint_t *val_cnt, datalink_media_t media, uint_t flags)
18425903Ssowmini {
18435903Ssowmini 	link_duplex_t   link_duplex;
18445903Ssowmini 	dladm_status_t  status;
18455903Ssowmini 
18466789Sam223141 	if (flags & MAC_PROP_DEFAULT)
18476512Ssowmini 		return (DLADM_STATUS_NOTSUP);
18486512Ssowmini 
18495903Ssowmini 	if ((status = dladm_get_single_mac_stat(linkid, "link_duplex",
18505903Ssowmini 	    KSTAT_DATA_UINT32, &link_duplex)) != 0)
18515903Ssowmini 		return (status);
18525903Ssowmini 
18535903Ssowmini 	switch (link_duplex) {
18545903Ssowmini 	case LINK_DUPLEX_FULL:
18555903Ssowmini 		(void) strcpy(*prop_val, "full");
18565903Ssowmini 		break;
18575903Ssowmini 	case LINK_DUPLEX_HALF:
18585903Ssowmini 		(void) strcpy(*prop_val, "half");
18595903Ssowmini 		break;
18605903Ssowmini 	default:
18615903Ssowmini 		(void) strcpy(*prop_val, "unknown");
18625903Ssowmini 		break;
18635903Ssowmini 	}
18645903Ssowmini 	*val_cnt = 1;
18655903Ssowmini 	return (DLADM_STATUS_OK);
18665903Ssowmini }
18675903Ssowmini 
18685903Ssowmini /* ARGSUSED */
18695903Ssowmini static dladm_status_t
1870*7342SAruna.Ramakrishna@Sun.COM i_dladm_speed_get(struct prop_desc *pd, datalink_id_t linkid,
18716512Ssowmini     char **prop_val, uint_t *val_cnt, uint_t flags)
18725903Ssowmini {
18735903Ssowmini 	uint64_t	ifspeed = 0;
18745903Ssowmini 	dladm_status_t status;
18755903Ssowmini 
18766789Sam223141 	if (flags & MAC_PROP_DEFAULT)
18776512Ssowmini 		return (DLADM_STATUS_NOTSUP);
18786512Ssowmini 
18795903Ssowmini 	if ((status = dladm_get_single_mac_stat(linkid, "ifspeed",
18805903Ssowmini 	    KSTAT_DATA_UINT64, &ifspeed)) != 0)
18815903Ssowmini 		return (status);
18826512Ssowmini 
18835960Ssowmini 	if ((ifspeed % 1000000) != 0) {
18845960Ssowmini 		(void) snprintf(*prop_val, DLADM_PROP_VAL_MAX,
18855960Ssowmini 		    "%llf", ifspeed / (float)1000000); /* Mbps */
18865960Ssowmini 	} else {
18875960Ssowmini 		(void) snprintf(*prop_val, DLADM_PROP_VAL_MAX,
18885960Ssowmini 		    "%llu", ifspeed / 1000000); /* Mbps */
18895960Ssowmini 	}
18905903Ssowmini 	*val_cnt = 1;
18915903Ssowmini 	return (DLADM_STATUS_OK);
18925903Ssowmini }
18935903Ssowmini 
18945903Ssowmini /* ARGSUSED */
18955903Ssowmini static dladm_status_t
1896*7342SAruna.Ramakrishna@Sun.COM i_dladm_status_get(struct prop_desc *pd, datalink_id_t linkid,
18976512Ssowmini     char **prop_val, uint_t *val_cnt, datalink_media_t media, uint_t flags)
18985903Ssowmini {
18996512Ssowmini 	link_state_t	link_state;
19006512Ssowmini 	dladm_status_t	status;
19016512Ssowmini 	uchar_t 	*cp;
19026789Sam223141 	dld_ioc_macprop_t  *dip;
19035903Ssowmini 
19046789Sam223141 	if (flags & MAC_PROP_DEFAULT)
19056512Ssowmini 		return (DLADM_STATUS_NOTSUP);
1906*7342SAruna.Ramakrishna@Sun.COM 	dip = i_dladm_get_public_prop(linkid, pd->pd_name, flags, &status);
19076512Ssowmini 	if (status != DLADM_STATUS_OK)
19085903Ssowmini 		return (status);
19096512Ssowmini 	cp = (uchar_t *)dip->pr_val;
19106512Ssowmini 	(void) memcpy(&link_state, cp, sizeof (link_state));
19115903Ssowmini 
19125903Ssowmini 	switch (link_state) {
19135903Ssowmini 	case LINK_STATE_UP:
19145903Ssowmini 		(void) strcpy(*prop_val, "up");
19155903Ssowmini 		break;
19165903Ssowmini 	case LINK_STATE_DOWN:
19175903Ssowmini 		(void) strcpy(*prop_val, "down");
19185903Ssowmini 		break;
19195903Ssowmini 	default:
19205903Ssowmini 		(void) strcpy(*prop_val, "unknown");
19215903Ssowmini 		break;
19225903Ssowmini 	}
19235903Ssowmini 	*val_cnt = 1;
19246512Ssowmini 	free(dip);
19255903Ssowmini 	return (DLADM_STATUS_OK);
19265903Ssowmini }
19275903Ssowmini 
19285903Ssowmini /* ARGSUSED */
19295903Ssowmini static dladm_status_t
1930*7342SAruna.Ramakrishna@Sun.COM i_dladm_binary_get(struct prop_desc *pd, datalink_id_t linkid,
19316512Ssowmini     char **prop_val, uint_t *val_cnt, datalink_media_t media, uint_t flags)
19325903Ssowmini {
19336789Sam223141 	dld_ioc_macprop_t *dip;
19345903Ssowmini 	dladm_status_t status;
19355903Ssowmini 
1936*7342SAruna.Ramakrishna@Sun.COM 	dip = i_dladm_get_public_prop(linkid, pd->pd_name, flags, &status);
19376512Ssowmini 	if (dip == NULL)
19385903Ssowmini 		return (status);
19395903Ssowmini 	(void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "%x", dip->pr_val[0]);
19405903Ssowmini 	free(dip);
19415903Ssowmini 	*val_cnt = 1;
19425903Ssowmini 	return (DLADM_STATUS_OK);
19435903Ssowmini }
19445903Ssowmini 
19455960Ssowmini /* ARGSUSED */
19465903Ssowmini static dladm_status_t
1947*7342SAruna.Ramakrishna@Sun.COM i_dladm_uint32_get(struct prop_desc *pd, datalink_id_t linkid,
19486512Ssowmini     char **prop_val, uint_t *val_cnt, datalink_media_t media, uint_t flags)
19495903Ssowmini {
19506789Sam223141 	dld_ioc_macprop_t *dip;
19516512Ssowmini 	uint32_t v  = 0;
19525903Ssowmini 	uchar_t *cp;
19535903Ssowmini 	dladm_status_t status;
19545903Ssowmini 
1955*7342SAruna.Ramakrishna@Sun.COM 	dip = i_dladm_get_public_prop(linkid, pd->pd_name, flags, &status);
19566512Ssowmini 	if (dip == NULL)
19575903Ssowmini 		return (status);
19585903Ssowmini 	cp = (uchar_t *)dip->pr_val;
19595903Ssowmini 	(void) memcpy(&v, cp, sizeof (v));
19606512Ssowmini 	(void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "%ld", v);
19615903Ssowmini 	free(dip);
19625903Ssowmini 	*val_cnt = 1;
19635903Ssowmini 	return (DLADM_STATUS_OK);
19645903Ssowmini }
19655903Ssowmini 
19665960Ssowmini /* ARGSUSED */
19675903Ssowmini static dladm_status_t
1968*7342SAruna.Ramakrishna@Sun.COM i_dladm_flowctl_get(struct prop_desc *pd, datalink_id_t linkid,
19696512Ssowmini     char **prop_val, uint_t *val_cnt, datalink_media_t media, uint_t flags)
19705903Ssowmini {
19716789Sam223141 	dld_ioc_macprop_t *dip;
19725903Ssowmini 	link_flowctrl_t v;
19735903Ssowmini 	dladm_status_t status;
19745903Ssowmini 	uchar_t *cp;
19755903Ssowmini 
1976*7342SAruna.Ramakrishna@Sun.COM 	dip = i_dladm_get_public_prop(linkid, pd->pd_name, flags, &status);
19776512Ssowmini 	if (dip == NULL)
19785903Ssowmini 		return (status);
19795903Ssowmini 	cp = (uchar_t *)dip->pr_val;
19805903Ssowmini 	(void) memcpy(&v, cp, sizeof (v));
19815903Ssowmini 	switch (v) {
19825903Ssowmini 	case LINK_FLOWCTRL_NONE:
19835903Ssowmini 		(void) sprintf(*prop_val, "no");
19845903Ssowmini 		break;
19855903Ssowmini 	case LINK_FLOWCTRL_RX:
19865903Ssowmini 		(void) sprintf(*prop_val, "rx");
19875903Ssowmini 		break;
19885903Ssowmini 	case LINK_FLOWCTRL_TX:
19895903Ssowmini 		(void) sprintf(*prop_val, "tx");
19905903Ssowmini 		break;
19915903Ssowmini 	case LINK_FLOWCTRL_BI:
19925903Ssowmini 		(void) sprintf(*prop_val, "bi");
19935903Ssowmini 		break;
19945903Ssowmini 	}
19955903Ssowmini 	free(dip);
19965903Ssowmini 	*val_cnt = 1;
19975903Ssowmini 	return (DLADM_STATUS_OK);
19985903Ssowmini }
19995903Ssowmini 
20005903Ssowmini 
20015903Ssowmini /* ARGSUSED */
20025903Ssowmini static dladm_status_t
2003*7342SAruna.Ramakrishna@Sun.COM i_dladm_set_prop(datalink_id_t linkid, const char *prop_name,
20045903Ssowmini     char **prop_val, uint_t val_cnt, uint_t flags)
20055903Ssowmini {
20065903Ssowmini 	int		fd, i, slen;
20075903Ssowmini 	int 		bufsize = 0, dsize;
20086789Sam223141 	dld_ioc_macprop_t *dip = NULL;
20095903Ssowmini 	uchar_t 	*dp;
2010*7342SAruna.Ramakrishna@Sun.COM 	dladm_public_prop_t *p;
20116512Ssowmini 	dladm_status_t	status = DLADM_STATUS_OK;
20125903Ssowmini 
20135903Ssowmini 	if ((prop_name == NULL && prop_val != NULL) ||
20145903Ssowmini 	    (prop_val != NULL && val_cnt == 0))
20155903Ssowmini 		return (DLADM_STATUS_BADARG);
20165903Ssowmini 	p = dladm_name2prop(prop_name);
20176789Sam223141 	if (p->pp_id != MAC_PROP_PRIVATE)
20185903Ssowmini 		return (DLADM_STATUS_BADARG);
20195903Ssowmini 
20205903Ssowmini 	/*
20215903Ssowmini 	 * private properties: all parsing is done in the kernel.
20225903Ssowmini 	 * allocate a enough space for each property + its separator (',').
20235903Ssowmini 	 */
20245903Ssowmini 	for (i = 0; i < val_cnt; i++) {
20255903Ssowmini 		bufsize += strlen(prop_val[i]) + 1;
20265903Ssowmini 	}
20276512Ssowmini 
20286512Ssowmini 	if (prop_val == NULL) {
20296512Ssowmini 		/*
20306512Ssowmini 		 * getting default value. so use more buffer space.
20316512Ssowmini 		 */
20326512Ssowmini 		bufsize += 1024;
20336512Ssowmini 	}
20346512Ssowmini 
2035*7342SAruna.Ramakrishna@Sun.COM 	dip = i_dladm_buf_alloc(bufsize + 1, linkid, prop_name,
20366789Sam223141 	    (prop_val != NULL ? 0 : MAC_PROP_DEFAULT), &status);
20375903Ssowmini 	if (dip == NULL)
20385903Ssowmini 		return (status);
20395903Ssowmini 
20405903Ssowmini 	dp = (uchar_t *)dip->pr_val;
20416789Sam223141 	dsize = sizeof (dld_ioc_macprop_t) + bufsize;
20425903Ssowmini 	slen = 0;
20436512Ssowmini 	if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) {
20446512Ssowmini 		status = dladm_errno2status(errno);
20456512Ssowmini 		goto done;
20466512Ssowmini 	}
20476512Ssowmini 	if (prop_val == NULL) {
20486789Sam223141 		if (i_dladm_ioctl(fd, DLDIOC_GETMACPROP, dip, dsize) < 0) {
20496512Ssowmini 			status = dladm_errno2status(errno);
20506512Ssowmini 			goto done;
20516512Ssowmini 		}
20526512Ssowmini 	} else {
20536512Ssowmini 		for (i = 0; i < val_cnt; i++) {
20546512Ssowmini 			int plen = 0;
20555903Ssowmini 
20566512Ssowmini 			plen = strlen(prop_val[i]);
20576512Ssowmini 			bcopy(prop_val[i], dp, plen);
20586512Ssowmini 			slen += plen;
20596512Ssowmini 			/*
20606512Ssowmini 			 * add a "," separator and update dp.
20616512Ssowmini 			 */
20626512Ssowmini 			if (i != (val_cnt -1))
20636512Ssowmini 				dp[slen++] = ',';
20646512Ssowmini 			dp += (plen + 1);
20656512Ssowmini 		}
20665903Ssowmini 	}
20676789Sam223141 	if (i_dladm_ioctl(fd, DLDIOC_SETMACPROP, dip, dsize) < 0) {
20686512Ssowmini 		status = dladm_errno2status(errno);
20695903Ssowmini 	}
20706512Ssowmini 
20716512Ssowmini done:
20726512Ssowmini 	if (fd > 0)
20736512Ssowmini 		(void) close(fd);
20745903Ssowmini 	free(dip);
20756512Ssowmini 	return (status);
20765903Ssowmini }
20775903Ssowmini 
20785903Ssowmini static dladm_status_t
2079*7342SAruna.Ramakrishna@Sun.COM i_dladm_get_prop(datalink_id_t linkid, const char *prop_name,
20806512Ssowmini     char **prop_val, uint_t *val_cnt, dladm_prop_type_t type, uint_t dld_flags)
20815903Ssowmini {
20825903Ssowmini 	int		fd;
20835903Ssowmini 	dladm_status_t  status = DLADM_STATUS_OK;
20845903Ssowmini 	uint_t 		dsize;
20856789Sam223141 	dld_ioc_macprop_t *dip = NULL;
2086*7342SAruna.Ramakrishna@Sun.COM 	dladm_public_prop_t *p;
20875903Ssowmini 	char tmp = '\0';
20885903Ssowmini 
20895903Ssowmini 	if ((prop_name == NULL && prop_val != NULL) ||
20905903Ssowmini 	    (prop_val != NULL && val_cnt == 0))
20915903Ssowmini 		return (DLADM_STATUS_BADARG);
20925903Ssowmini 
20935903Ssowmini 	p = dladm_name2prop(prop_name);
20946789Sam223141 	if (p->pp_id != MAC_PROP_PRIVATE)
20955903Ssowmini 		return (DLADM_STATUS_BADARG);
20965903Ssowmini 
20976512Ssowmini 	if (type == DLADM_PROP_VAL_MODIFIABLE) {
20985903Ssowmini 		*prop_val = &tmp;
20995903Ssowmini 		*val_cnt = 1;
21005903Ssowmini 		return (DLADM_STATUS_OK);
21015903Ssowmini 	}
21025903Ssowmini 
21035903Ssowmini 	/*
21045903Ssowmini 	 * private properties: all parsing is done in the kernel.
21055903Ssowmini 	 */
2106*7342SAruna.Ramakrishna@Sun.COM 	dip = i_dladm_buf_alloc(1024, linkid, prop_name, dld_flags, &status);
21075903Ssowmini 	if (dip == NULL)
21085903Ssowmini 		return (status);
21096789Sam223141 	dsize = MAC_PROP_BUFSIZE(dip->pr_valsize);
21105903Ssowmini 
21116512Ssowmini 	if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) {
21126512Ssowmini 		free(dip);
21135903Ssowmini 		return (DLADM_STATUS_BADARG);
21146512Ssowmini 	}
21155903Ssowmini 
21166789Sam223141 	if ((status = i_dladm_ioctl(fd, DLDIOC_GETMACPROP, dip, dsize)) < 0) {
21175903Ssowmini 		status = dladm_errno2status(errno);
21185903Ssowmini 	} else {
21195903Ssowmini 		(void) strncpy(*prop_val, dip->pr_val, DLADM_PROP_VAL_MAX);
21205903Ssowmini 		*val_cnt = 1;
21215903Ssowmini 	}
21226512Ssowmini 
21236512Ssowmini 	(void) close(fd);
21246512Ssowmini 	free(dip);
21255903Ssowmini 	return (status);
21265903Ssowmini }
21276512Ssowmini 
21286512Ssowmini 
21296512Ssowmini static dladm_status_t
21306512Ssowmini i_dladm_getset_defval(prop_desc_t *pdp, datalink_id_t linkid,
21316512Ssowmini     datalink_media_t media, uint_t flags)
21326512Ssowmini {
21336512Ssowmini 	dladm_status_t status;
21346512Ssowmini 	char **prop_vals = NULL, *buf;
21356512Ssowmini 	size_t bufsize;
21366512Ssowmini 	uint_t cnt;
21376512Ssowmini 	int i;
21386512Ssowmini 
21396512Ssowmini 	/*
21406512Ssowmini 	 * Allocate buffer needed for prop_vals array. We can have at most
21416512Ssowmini 	 * DLADM_MAX_PROP_VALCNT char *prop_vals[] entries, where
21426512Ssowmini 	 * each entry has max size DLADM_PROP_VAL_MAX
21436512Ssowmini 	 */
21446512Ssowmini 	bufsize =
21456512Ssowmini 	    (sizeof (char *) + DLADM_PROP_VAL_MAX) * DLADM_MAX_PROP_VALCNT;
21466512Ssowmini 	buf = malloc(bufsize);
21476512Ssowmini 	prop_vals = (char **)(void *)buf;
21486512Ssowmini 	for (i = 0; i < DLADM_MAX_PROP_VALCNT; i++) {
21496512Ssowmini 		prop_vals[i] = buf +
21506512Ssowmini 		    sizeof (char *) * DLADM_MAX_PROP_VALCNT +
21516512Ssowmini 		    i * DLADM_PROP_VAL_MAX;
21526512Ssowmini 	}
21536768Sar224390 
21546768Sar224390 	/*
2155*7342SAruna.Ramakrishna@Sun.COM 	 * For properties which have pdp->pd_defval.vd_name as a non-empty
2156*7342SAruna.Ramakrishna@Sun.COM 	 * string, the "" itself is used to reset the property (exceptions
2157*7342SAruna.Ramakrishna@Sun.COM 	 * are zone and autopush, which populate vdp->vd_val). So
2158*7342SAruna.Ramakrishna@Sun.COM 	 * libdladm can copy pdp->pd_defval over to the val_desc_t passed
2159*7342SAruna.Ramakrishna@Sun.COM 	 * down on the setprop using the global values in the table. For
2160*7342SAruna.Ramakrishna@Sun.COM 	 * other cases (vd_name is ""), doing reset-linkprop will cause
2161*7342SAruna.Ramakrishna@Sun.COM 	 * libdladm to do a getprop to find the default value and then do
2162*7342SAruna.Ramakrishna@Sun.COM 	 * a setprop to reset the value to default.
21636768Sar224390 	 */
21646789Sam223141 	status = pdp->pd_get(pdp, linkid, prop_vals, &cnt, media,
21656789Sam223141 	    MAC_PROP_DEFAULT);
21666512Ssowmini 	if (status == DLADM_STATUS_OK) {
21676512Ssowmini 		status = i_dladm_set_single_prop(linkid, pdp->pd_class,
21686512Ssowmini 		    media, pdp, prop_vals, cnt, flags);
21696512Ssowmini 	}
21706512Ssowmini 	free(buf);
21716512Ssowmini 	return (status);
21726512Ssowmini }
2173