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 #pragma ident	"%Z%%M%	%I%	%E% SMI"
273147Sxc151355 
283147Sxc151355 #include <stdlib.h>
293147Sxc151355 #include <strings.h>
303147Sxc151355 #include <errno.h>
313147Sxc151355 #include <ctype.h>
325895Syz147064 #include <stddef.h>
333448Sdh155122 #include <sys/types.h>
343147Sxc151355 #include <sys/stat.h>
353448Sdh155122 #include <sys/dld.h>
363448Sdh155122 #include <sys/zone.h>
373448Sdh155122 #include <fcntl.h>
383448Sdh155122 #include <unistd.h>
393448Sdh155122 #include <libdevinfo.h>
403448Sdh155122 #include <zone.h>
413871Syz147064 #include <libdllink.h>
423147Sxc151355 #include <libdladm_impl.h>
435895Syz147064 #include <libdlwlan_impl.h>
443871Syz147064 #include <libdlwlan.h>
455895Syz147064 #include <libdlvlan.h>
463448Sdh155122 #include <dlfcn.h>
473448Sdh155122 #include <link.h>
485895Syz147064 #include <inet/wifi_ioctl.h>
49*5903Ssowmini #include <libdladm.h>
50*5903Ssowmini #include <sys/param.h>
51*5903Ssowmini #include <sys/dld.h>
52*5903Ssowmini #include <inttypes.h>
53*5903Ssowmini #include <sys/ethernet.h>
543448Sdh155122 
555895Syz147064 /*
565895Syz147064  * The linkprop get() callback.
57*5903Ssowmini  * - pd: 	pointer to the struct prop_desc
585895Syz147064  * - propstrp:	a property string array to keep the returned property.
595895Syz147064  *		Caller allocated.
605895Syz147064  * - cntp:	number of returned properties.
615895Syz147064  *		Caller also uses it to indicate how many it expects.
625895Syz147064  */
63*5903Ssowmini struct prop_desc;
64*5903Ssowmini 
65*5903Ssowmini typedef dladm_status_t	pd_getf_t(struct prop_desc *pd,
66*5903Ssowmini 			datalink_id_t, char **propstp, uint_t *cntp);
675895Syz147064 
685895Syz147064 /*
695895Syz147064  * The linkprop set() callback.
705895Syz147064  * - propval:	a val_desc_t array which keeps the property values to be set.
715895Syz147064  * - cnt:	number of properties to be set.
72*5903Ssowmini  * - flags: 	additional flags passed down the system call.
73*5903Ssowmini  *
74*5903Ssowmini  * pd_set takes val_desc_t given by pd_check(), translates it into
75*5903Ssowmini  * a format suitable for kernel consumption. This may require allocation
76*5903Ssowmini  * of ioctl buffers etc. pd_set() may call another common routine (used
77*5903Ssowmini  * by all other pd_sets) which invokes the ioctl.
785895Syz147064  */
79*5903Ssowmini typedef dladm_status_t	pd_setf_t(struct prop_desc *, datalink_id_t,
80*5903Ssowmini 			val_desc_t *propval, uint_t cnt, uint_t flags);
813448Sdh155122 
823448Sdh155122 
835895Syz147064 /*
845895Syz147064  * The linkprop check() callback.
855895Syz147064  * - propstrp:	property string array which keeps the property to be checked.
865895Syz147064  * - cnt:	number of properties.
875895Syz147064  * - propval:	return value; the property values of the given property strings.
88*5903Ssowmini  *
89*5903Ssowmini  * pd_check checks that the input values are valid. It does so by
90*5903Ssowmini  * iteraring through the pd_modval list for the property. If
91*5903Ssowmini  * the modifiable values cannot be expressed as a list, a pd_check
92*5903Ssowmini  * specific to this property can be used. If the input values are
93*5903Ssowmini  * verified to be valid, pd_check allocates a val_desc_t and fills it
94*5903Ssowmini  * with either a val_desc_t found on the pd_modval list or something
95*5903Ssowmini  * generated on the fly.
965895Syz147064  */
97*5903Ssowmini typedef dladm_status_t	pd_checkf_t(struct prop_desc *pd,
98*5903Ssowmini 			    datalink_id_t, char **propstrp,
99*5903Ssowmini 			    uint_t cnt, val_desc_t *propval);
1003448Sdh155122 
101*5903Ssowmini typedef struct dld_public_prop_s {
102*5903Ssowmini 	dld_prop_id_t	pp_id;
103*5903Ssowmini 	size_t		pp_valsize;
104*5903Ssowmini 	char		*pp_name;
105*5903Ssowmini 	char		*pp_desc;
106*5903Ssowmini } dld_public_prop_t;
107*5903Ssowmini 
108*5903Ssowmini static dld_ioc_prop_t *dld_buf_alloc(size_t, datalink_id_t, const char *,
109*5903Ssowmini 					dladm_status_t *);
110*5903Ssowmini static dladm_status_t dld_set_prop(datalink_id_t, const char *, char **,
111*5903Ssowmini 					uint_t, uint_t);
112*5903Ssowmini static dladm_status_t dld_get_prop(datalink_id_t, const char *, char **,
113*5903Ssowmini 					uint_t *, dladm_prop_type_t);
1145895Syz147064 static pd_getf_t	do_get_zone, do_get_autopush, do_get_rate_mod,
1155895Syz147064 			do_get_rate_prop, do_get_channel_prop,
116*5903Ssowmini 			do_get_powermode_prop, do_get_radio_prop,
117*5903Ssowmini 			dld_duplex_get, dld_speed_get, dld_status_get,
118*5903Ssowmini 			dld_binary_get, dld_uint64_get, dld_flowctl_get;
1195895Syz147064 static pd_setf_t	do_set_zone, do_set_autopush, do_set_rate_prop,
120*5903Ssowmini 			do_set_powermode_prop, do_set_radio_prop,
121*5903Ssowmini 			dld_set_public_prop;
122*5903Ssowmini static pd_checkf_t	do_check_zone, do_check_autopush, do_check_rate,
123*5903Ssowmini 			dld_defmtu_check;
1243448Sdh155122 
1253448Sdh155122 typedef struct prop_desc {
1265895Syz147064 	/*
1275895Syz147064 	 * link property name
1285895Syz147064 	 */
1295895Syz147064 	char			*pd_name;
1305895Syz147064 
1315895Syz147064 	/*
1325895Syz147064 	 * default property value, can be set to { "", NULL }
1335895Syz147064 	 */
1345895Syz147064 	val_desc_t		pd_defval;
1355895Syz147064 
1365895Syz147064 	/*
1375895Syz147064 	 * list of optional property values, can be NULL.
1385895Syz147064 	 *
1395895Syz147064 	 * This is set to non-NULL if there is a list of possible property
1405895Syz147064 	 * values.  pd_optval would point to the array of possible values.
1415895Syz147064 	 */
1425895Syz147064 	val_desc_t		*pd_optval;
1435895Syz147064 
1445895Syz147064 	/*
1455895Syz147064 	 * count of the above optional property values. 0 if pd_optval is NULL.
1465895Syz147064 	 */
1475895Syz147064 	uint_t			pd_noptval;
1485895Syz147064 
1495895Syz147064 	/*
1505895Syz147064 	 * callback to set link property;
1515895Syz147064 	 * set to NULL if this property is read-only
1525895Syz147064 	 */
1535895Syz147064 	pd_setf_t		*pd_set;
1545895Syz147064 
1555895Syz147064 	/*
1565895Syz147064 	 * callback to get modifiable link property
1575895Syz147064 	 */
1585895Syz147064 	pd_getf_t		*pd_getmod;
1595895Syz147064 
1605895Syz147064 	/*
1615895Syz147064 	 * callback to get current link property
1625895Syz147064 	 */
1635895Syz147064 	pd_getf_t		*pd_get;
1645895Syz147064 
1655895Syz147064 	/*
1665895Syz147064 	 * callback to validate link property value, set to NULL if pd_optval
1675895Syz147064 	 * is not NULL. In that case, validate the value by comparing it with
1685895Syz147064 	 * the pd_optval. Return a val_desc_t array pointer if the value is
1695895Syz147064 	 * valid.
1705895Syz147064 	 */
1715895Syz147064 	pd_checkf_t		*pd_check;
1725895Syz147064 
1735895Syz147064 	uint_t			pd_flags;
174*5903Ssowmini #define	PD_TEMPONLY	0x1	/* property is temporary only */
175*5903Ssowmini #define	PD_CHECK_ALLOC	0x2	/* alloc vd_val as part of pd_check */
1765895Syz147064 	/*
1775895Syz147064 	 * indicate link classes this property applies to.
1785895Syz147064 	 */
1795895Syz147064 	datalink_class_t	pd_class;
1805895Syz147064 
1815895Syz147064 	/*
1825895Syz147064 	 * indicate link media type this property applies to.
1835895Syz147064 	 */
1845895Syz147064 	datalink_media_t	pd_dmedia;
1853448Sdh155122 } prop_desc_t;
1863448Sdh155122 
187*5903Ssowmini #define	DLD_PROPBUF_SIZE(v)	sizeof (dld_ioc_prop_t) + (v) - 1
188*5903Ssowmini 
189*5903Ssowmini 
190*5903Ssowmini static dld_public_prop_t dld_prop[] = {
191*5903Ssowmini 	{ DLD_PROP_DUPLEX,	sizeof (uint8_t),
192*5903Ssowmini 	    "link_duplex",	"link duplex mode" },
193*5903Ssowmini 
194*5903Ssowmini 	{DLD_PROP_SPEED,	sizeof (uint8_t),
195*5903Ssowmini 	    "ifspeed",		"link speed (Mbps)" },
196*5903Ssowmini 
197*5903Ssowmini 	{ DLD_PROP_STATUS,	sizeof (uint8_t),
198*5903Ssowmini 	    "link_up",		"link up/down" },
199*5903Ssowmini 
200*5903Ssowmini 	{ DLD_PROP_AUTONEG,	sizeof (uint8_t),
201*5903Ssowmini 	    "adv_autoneg_cap",	"Advertised auto-negotiation" },
202*5903Ssowmini 
203*5903Ssowmini 	{ DLD_PROP_DEFMTU,	sizeof (uint64_t),
204*5903Ssowmini 	    "default_mtu",	"default frame mtu" },
205*5903Ssowmini 
206*5903Ssowmini 	{ DLD_PROP_FLOWCTRL,	sizeof (link_flowctrl_t),
207*5903Ssowmini 	    "flowctrl",		"flowcontrol" },
208*5903Ssowmini 
209*5903Ssowmini 	{ DLD_PROP_ADV_1000FDX_CAP, sizeof (uint8_t),
210*5903Ssowmini 	    "adv_1000fdx_cap",	"Adv 1000 Mbps fdx" },
211*5903Ssowmini 
212*5903Ssowmini 	{ DLD_PROP_EN_1000FDX_CAP, sizeof (uint8_t),
213*5903Ssowmini 	    "en_1000fdx_cap",	"Enable 1000 Mbps fdx" },
214*5903Ssowmini 
215*5903Ssowmini 	{ DLD_PROP_ADV_1000HDX_CAP, sizeof (uint8_t),
216*5903Ssowmini 	    "adv_1000hdx_cap", "Adv 1000 Mbps hdx" },
217*5903Ssowmini 
218*5903Ssowmini 	{ DLD_PROP_EN_1000HDX_CAP, sizeof (uint8_t),
219*5903Ssowmini 	    "en_1000hdx_cap",	"Enable 1000 Mbps hdx" },
220*5903Ssowmini 
221*5903Ssowmini 	{ DLD_PROP_ADV_100FDX_CAP, sizeof (uint8_t),
222*5903Ssowmini 	    "adv_100fdx_cap",	"Adv 100 Mbps fdx" },
223*5903Ssowmini 
224*5903Ssowmini 	{ DLD_PROP_EN_100FDX_CAP, sizeof (uint8_t),
225*5903Ssowmini 	    "en_100fdx_cap",	"Enable 100 Mbps fdx" },
226*5903Ssowmini 
227*5903Ssowmini 	{ DLD_PROP_ADV_100HDX_CAP, sizeof (uint8_t),
228*5903Ssowmini 	    "adv_100hdx_cap",	"Adv 100 Mbps hdx" },
229*5903Ssowmini 
230*5903Ssowmini 	{ DLD_PROP_EN_100HDX_CAP, sizeof (uint8_t),
231*5903Ssowmini 	    "en_100hdx_cap",	"Enable 100 Mbps hdx" },
232*5903Ssowmini 
233*5903Ssowmini 	{ DLD_PROP_ADV_10FDX_CAP, sizeof (uint8_t),
234*5903Ssowmini 	    "adv_10fdx_cap",	"Adv 10 Mbps fdx" },
235*5903Ssowmini 
236*5903Ssowmini 	{ DLD_PROP_EN_10FDX_CAP, sizeof (uint8_t),
237*5903Ssowmini 	    "en_10fdx_cap",	"Enable 10 Mbps fdx" },
238*5903Ssowmini 
239*5903Ssowmini 	{ DLD_PROP_ADV_10HDX_CAP, sizeof (uint8_t),
240*5903Ssowmini 	    "adv_10hdx_cap",	"Adv 10 Mbps hdx" },
241*5903Ssowmini 
242*5903Ssowmini 	{ DLD_PROP_EN_10HDX_CAP, sizeof (uint8_t),
243*5903Ssowmini 	    "en_10hdx_cap",	"Enable 10 Mbps hdx" },
244*5903Ssowmini 
245*5903Ssowmini 	{ DLD_PROP_PRIVATE, 0,
246*5903Ssowmini 	    "driver-private",	"" }
247*5903Ssowmini };
248*5903Ssowmini 
249*5903Ssowmini static  val_desc_t	link_duplex_vals[] = {
250*5903Ssowmini 	{ "half", 	LINK_DUPLEX_HALF	},
251*5903Ssowmini 	{ "full", 	LINK_DUPLEX_HALF	}
252*5903Ssowmini };
253*5903Ssowmini static  val_desc_t	link_speed_vals[] = {
254*5903Ssowmini 	{ "10",		10			},
255*5903Ssowmini 	{ "100",	100			},
256*5903Ssowmini 	{ "1000",	1000			}
257*5903Ssowmini };
258*5903Ssowmini static  val_desc_t	link_status_vals[] = {
259*5903Ssowmini 	{ "up",		LINK_STATE_UP		},
260*5903Ssowmini 	{ "down",	LINK_STATE_DOWN		}
261*5903Ssowmini };
262*5903Ssowmini static  val_desc_t	link_01_vals[] = {
263*5903Ssowmini 	{ "1",		1			},
264*5903Ssowmini 	{ "0",		0			}
265*5903Ssowmini };
266*5903Ssowmini static  val_desc_t	link_flow_vals[] = {
267*5903Ssowmini 	{ "no",		LINK_FLOWCTRL_NONE	},
268*5903Ssowmini 	{ "tx",		LINK_FLOWCTRL_TX	},
269*5903Ssowmini 	{ "rx",		LINK_FLOWCTRL_RX	},
270*5903Ssowmini 	{ "bi",		LINK_FLOWCTRL_BI	}
271*5903Ssowmini };
272*5903Ssowmini static  val_desc_t	macdefaultmtu_vals[] = {
273*5903Ssowmini 	{ "68-9000",	NULL			}
274*5903Ssowmini };
275*5903Ssowmini 
276*5903Ssowmini #define	VALCNT(vals)    (sizeof ((vals)) / sizeof (val_desc_t))
277*5903Ssowmini 
2785895Syz147064 static val_desc_t	dladm_wlan_radio_vals[] = {
2795895Syz147064 	{ "on",		DLADM_WLAN_RADIO_ON	},
2805895Syz147064 	{ "off",	DLADM_WLAN_RADIO_OFF	}
2815895Syz147064 };
2825895Syz147064 
2835895Syz147064 static val_desc_t	dladm_wlan_powermode_vals[] = {
2845895Syz147064 	{ "off",	DLADM_WLAN_PM_OFF	},
2855895Syz147064 	{ "fast",	DLADM_WLAN_PM_FAST	},
2865895Syz147064 	{ "max",	DLADM_WLAN_PM_MAX	}
2875895Syz147064 };
2885895Syz147064 
2893448Sdh155122 static prop_desc_t	prop_table[] = {
2905895Syz147064 
291*5903Ssowmini 	{ "channel",	{ NULL, 0 },
292*5903Ssowmini 	    NULL, 0, NULL, NULL,
2935895Syz147064 	    do_get_channel_prop, NULL, 0,
294*5903Ssowmini 	    DATALINK_CLASS_PHYS, DL_WIFI },
2955895Syz147064 
2965895Syz147064 	{ "powermode",	{ "off", DLADM_WLAN_PM_OFF },
2975895Syz147064 	    dladm_wlan_powermode_vals, VALCNT(dladm_wlan_powermode_vals),
2985895Syz147064 	    do_set_powermode_prop, NULL,
2995895Syz147064 	    do_get_powermode_prop, NULL, 0,
300*5903Ssowmini 	    DATALINK_CLASS_PHYS, DL_WIFI },
3015895Syz147064 
3025895Syz147064 	{ "radio",	{ "on", DLADM_WLAN_RADIO_ON },
3035895Syz147064 	    dladm_wlan_radio_vals, VALCNT(dladm_wlan_radio_vals),
3045895Syz147064 	    do_set_radio_prop, NULL,
3055895Syz147064 	    do_get_radio_prop, NULL, 0,
306*5903Ssowmini 	    DATALINK_CLASS_PHYS, DL_WIFI },
3075895Syz147064 
3085895Syz147064 	{ "speed",	{ "", 0 }, NULL, 0,
3095895Syz147064 	    do_set_rate_prop, do_get_rate_mod,
3105895Syz147064 	    do_get_rate_prop, do_check_rate, 0,
311*5903Ssowmini 	    DATALINK_CLASS_PHYS, DL_WIFI },
3125895Syz147064 
3135895Syz147064 	{ "autopush",	{ "", NULL }, NULL, 0,
3145895Syz147064 	    do_set_autopush, NULL,
315*5903Ssowmini 	    do_get_autopush, do_check_autopush, PD_CHECK_ALLOC,
316*5903Ssowmini 	    DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
3175895Syz147064 
3185895Syz147064 	{ "zone",	{ "", NULL }, NULL, 0,
3193448Sdh155122 	    do_set_zone, NULL,
3205895Syz147064 	    do_get_zone, do_check_zone, PD_TEMPONLY,
321*5903Ssowmini 	    DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
322*5903Ssowmini 
323*5903Ssowmini 	{ "link_duplex", { "full", LINK_DUPLEX_FULL },
324*5903Ssowmini 	    link_duplex_vals, VALCNT(link_duplex_vals),
325*5903Ssowmini 	    NULL, NULL, dld_duplex_get, NULL,
326*5903Ssowmini 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
327*5903Ssowmini 
328*5903Ssowmini 	{ "ifspeed", { "1000", 1000 },
329*5903Ssowmini 	    link_speed_vals, VALCNT(link_speed_vals),
330*5903Ssowmini 	    NULL, NULL, dld_speed_get, NULL,
331*5903Ssowmini 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
332*5903Ssowmini 
333*5903Ssowmini 	{ "link_up", { "up", LINK_STATE_UP },
334*5903Ssowmini 	    link_status_vals, VALCNT(link_status_vals),
335*5903Ssowmini 	    NULL, NULL, dld_status_get, NULL,
336*5903Ssowmini 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
337*5903Ssowmini 
338*5903Ssowmini 	{ "adv_autoneg_cap", { "1", 1 },
339*5903Ssowmini 	    link_01_vals, VALCNT(link_01_vals),
340*5903Ssowmini 	    dld_set_public_prop, NULL, dld_binary_get, NULL,
341*5903Ssowmini 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
342*5903Ssowmini 
343*5903Ssowmini 	{ "default_mtu", { NULL, NULL },
344*5903Ssowmini 	    macdefaultmtu_vals, VALCNT(macdefaultmtu_vals),
345*5903Ssowmini 	    dld_set_public_prop, NULL, dld_uint64_get, dld_defmtu_check,
346*5903Ssowmini 	    PD_CHECK_ALLOC, DATALINK_CLASS_PHYS, DL_ETHER },
347*5903Ssowmini 
348*5903Ssowmini 	{ "flowctrl", { "bi", LINK_FLOWCTRL_BI },
349*5903Ssowmini 	    link_flow_vals, VALCNT(link_flow_vals),
350*5903Ssowmini 	    dld_set_public_prop, NULL, dld_flowctl_get, NULL,
351*5903Ssowmini 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
352*5903Ssowmini 
353*5903Ssowmini 	{ "adv_1000fdx_cap", { NULL, NULL },
354*5903Ssowmini 	    link_01_vals, 0,
355*5903Ssowmini 	    NULL, NULL, dld_binary_get, NULL,
356*5903Ssowmini 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
357*5903Ssowmini 
358*5903Ssowmini 	{ "en_1000fdx_cap", { NULL, NULL },
359*5903Ssowmini 	    link_01_vals, VALCNT(link_01_vals),
360*5903Ssowmini 	    dld_set_public_prop, NULL, dld_binary_get, NULL,
361*5903Ssowmini 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
362*5903Ssowmini 
363*5903Ssowmini 	{ "adv_1000hdx_cap", { NULL, NULL },
364*5903Ssowmini 	    link_01_vals, VALCNT(link_01_vals),
365*5903Ssowmini 	    NULL, NULL, dld_binary_get, NULL,
366*5903Ssowmini 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
367*5903Ssowmini 
368*5903Ssowmini 	{ "en_1000hdx_cap", { NULL, NULL },
369*5903Ssowmini 	    link_01_vals, VALCNT(link_01_vals),
370*5903Ssowmini 	    dld_set_public_prop, NULL, dld_binary_get, NULL,
371*5903Ssowmini 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
372*5903Ssowmini 
373*5903Ssowmini 	{ "adv_100fdx_cap", { NULL, NULL },
374*5903Ssowmini 	    link_01_vals, VALCNT(link_01_vals),
375*5903Ssowmini 	    NULL, NULL, dld_binary_get, NULL,
376*5903Ssowmini 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
377*5903Ssowmini 
378*5903Ssowmini 	{ "en_100fdx_cap", { NULL, NULL },
379*5903Ssowmini 	    link_01_vals, VALCNT(link_01_vals),
380*5903Ssowmini 	    dld_set_public_prop, NULL, dld_binary_get, NULL,
381*5903Ssowmini 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
382*5903Ssowmini 
383*5903Ssowmini 	{ "adv_100hdx_cap", { NULL, NULL },
384*5903Ssowmini 	    link_01_vals, VALCNT(link_01_vals),
385*5903Ssowmini 	    NULL, NULL, dld_binary_get, NULL,
386*5903Ssowmini 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
387*5903Ssowmini 
388*5903Ssowmini 	{ "en_100hdx_cap", { NULL, NULL },
389*5903Ssowmini 	    link_01_vals, VALCNT(link_01_vals),
390*5903Ssowmini 	    dld_set_public_prop, NULL, dld_binary_get, NULL,
391*5903Ssowmini 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
392*5903Ssowmini 
393*5903Ssowmini 	{ "adv_10fdx_cap", { NULL, NULL },
394*5903Ssowmini 	    link_01_vals, VALCNT(link_01_vals),
395*5903Ssowmini 	    NULL, NULL, dld_binary_get, NULL,
396*5903Ssowmini 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
397*5903Ssowmini 
398*5903Ssowmini 	{ "en_10fdx_cap", { NULL, NULL },
399*5903Ssowmini 	    link_01_vals, VALCNT(link_01_vals),
400*5903Ssowmini 	    dld_set_public_prop, NULL, dld_binary_get, NULL,
401*5903Ssowmini 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
402*5903Ssowmini 
403*5903Ssowmini 	{ "adv_10hdx_cap", { NULL, NULL },
404*5903Ssowmini 	    link_01_vals, VALCNT(link_01_vals),
405*5903Ssowmini 	    NULL, NULL, dld_binary_get, NULL,
406*5903Ssowmini 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
407*5903Ssowmini 
408*5903Ssowmini 	{ "en_10hdx_cap", { NULL, NULL },
409*5903Ssowmini 	    link_01_vals, VALCNT(link_01_vals),
410*5903Ssowmini 	    dld_set_public_prop, NULL, dld_binary_get, NULL,
411*5903Ssowmini 	    0, DATALINK_CLASS_PHYS, DL_ETHER }
412*5903Ssowmini 
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);
4255895Syz147064 
4265895Syz147064 /*
4275895Syz147064  * Unfortunately, MAX_SCAN_SUPPORT_RATES is too small to allow all
4285895Syz147064  * rates to be retrieved. However, we cannot increase it at this
4295895Syz147064  * time because it will break binary compatibility with unbundled
4305895Syz147064  * WiFi drivers and utilities. So for now we define an additional
4315895Syz147064  * constant, MAX_SUPPORT_RATES, to allow all rates to be retrieved.
4325895Syz147064  */
4335895Syz147064 #define	MAX_SUPPORT_RATES	64
4345895Syz147064 
4355895Syz147064 #define	AP_ANCHOR	"[anchor]"
4365895Syz147064 #define	AP_DELIMITER	'.'
4375895Syz147064 
4385895Syz147064 static dladm_status_t
4395895Syz147064 do_check_prop(prop_desc_t *pdp, char **prop_val, uint_t val_cnt,
4405895Syz147064     val_desc_t *vdp)
4415895Syz147064 {
4425895Syz147064 	int		i, j;
4435895Syz147064 	dladm_status_t	status = DLADM_STATUS_OK;
4443147Sxc151355 
4455895Syz147064 	for (j = 0; j < val_cnt; j++) {
4465895Syz147064 		for (i = 0; i < pdp->pd_noptval; i++) {
4475895Syz147064 			if (strcasecmp(*prop_val,
4485895Syz147064 			    pdp->pd_optval[i].vd_name) == 0) {
4495895Syz147064 				break;
4505895Syz147064 			}
4515895Syz147064 		}
4525895Syz147064 		if (i == pdp->pd_noptval) {
4535895Syz147064 			status = DLADM_STATUS_BADVAL;
4545895Syz147064 			goto done;
4555895Syz147064 		}
4565895Syz147064 		(void) memcpy(vdp + j, &pdp->pd_optval[i], sizeof (val_desc_t));
4575895Syz147064 	}
4585895Syz147064 
4595895Syz147064 done:
4605895Syz147064 	return (status);
4615895Syz147064 }
4625895Syz147064 
4635895Syz147064 static dladm_status_t
4645895Syz147064 i_dladm_set_single_prop(datalink_id_t linkid, datalink_class_t class,
4655895Syz147064     uint32_t media, prop_desc_t *pdp, char **prop_val, uint_t val_cnt,
4665895Syz147064     uint_t flags)
4673147Sxc151355 {
4685895Syz147064 	dladm_status_t	status = DLADM_STATUS_OK;
4695895Syz147064 	val_desc_t	*vdp = NULL;
4705895Syz147064 	boolean_t	needfree = B_FALSE;
4715895Syz147064 	uint_t		cnt, i;
4723147Sxc151355 
4735895Syz147064 	if (!(pdp->pd_class & class))
4745895Syz147064 		return (DLADM_STATUS_BADARG);
4755895Syz147064 
4765895Syz147064 	if (!DATALINK_MEDIA_ACCEPTED(pdp->pd_dmedia, media))
4773147Sxc151355 		return (DLADM_STATUS_BADARG);
4783147Sxc151355 
4795895Syz147064 	if ((flags & DLADM_OPT_PERSIST) && (pdp->pd_flags & PD_TEMPONLY))
4805895Syz147064 		return (DLADM_STATUS_TEMPONLY);
4815895Syz147064 
4825895Syz147064 	if (!(flags & DLADM_OPT_ACTIVE))
4835895Syz147064 		return (DLADM_STATUS_OK);
4845895Syz147064 
4855895Syz147064 	if (pdp->pd_set == NULL)
4865895Syz147064 		return (DLADM_STATUS_PROPRDONLY);
4873448Sdh155122 
488*5903Ssowmini 	if (pdp->pd_flags & PD_CHECK_ALLOC)
489*5903Ssowmini 		needfree = B_TRUE;
490*5903Ssowmini 	else
491*5903Ssowmini 		needfree = B_FALSE;
4925895Syz147064 	if (prop_val != NULL) {
4935895Syz147064 		vdp = malloc(sizeof (val_desc_t) * val_cnt);
4945895Syz147064 		if (vdp == NULL)
4955895Syz147064 			return (DLADM_STATUS_NOMEM);
4965895Syz147064 
497*5903Ssowmini 
4985895Syz147064 		if (pdp->pd_check != NULL) {
499*5903Ssowmini 			status = pdp->pd_check(pdp, linkid, prop_val, val_cnt,
500*5903Ssowmini 			    vdp);
5015895Syz147064 		} else if (pdp->pd_optval != NULL) {
5025895Syz147064 			status = do_check_prop(pdp, prop_val, val_cnt, vdp);
5035895Syz147064 		} else {
5043448Sdh155122 			status = DLADM_STATUS_BADARG;
5053147Sxc151355 		}
5065895Syz147064 
5073147Sxc151355 		if (status != DLADM_STATUS_OK)
5085895Syz147064 			goto done;
5095895Syz147064 
5105895Syz147064 		cnt = val_cnt;
5115895Syz147064 	} else {
5125895Syz147064 		if (pdp->pd_defval.vd_name == NULL)
5135895Syz147064 			return (DLADM_STATUS_NOTSUP);
5145895Syz147064 
5155895Syz147064 		if ((vdp = malloc(sizeof (val_desc_t))) == NULL)
5165895Syz147064 			return (DLADM_STATUS_NOMEM);
5175895Syz147064 
5185895Syz147064 		(void) memcpy(vdp, &pdp->pd_defval, sizeof (val_desc_t));
5195895Syz147064 		cnt = 1;
5205895Syz147064 	}
521*5903Ssowmini 	status = pdp->pd_set(pdp, linkid, vdp, cnt, flags);
5225895Syz147064 	if (needfree) {
5235895Syz147064 		for (i = 0; i < cnt; i++)
524*5903Ssowmini 			free((void *)((val_desc_t *)vdp + i)->vd_val);
5253147Sxc151355 	}
5265895Syz147064 done:
5275895Syz147064 	free(vdp);
5285895Syz147064 	return (status);
5295895Syz147064 }
5305895Syz147064 
5315895Syz147064 static dladm_status_t
5325895Syz147064 i_dladm_set_linkprop(datalink_id_t linkid, const char *prop_name,
5335895Syz147064     char **prop_val, uint_t val_cnt, uint_t flags)
5345895Syz147064 {
5355895Syz147064 	int			i;
5365895Syz147064 	boolean_t		found = B_FALSE;
5375895Syz147064 	datalink_class_t	class;
5385895Syz147064 	uint32_t		media;
5395895Syz147064 	dladm_status_t		status = DLADM_STATUS_OK;
5405895Syz147064 
5415895Syz147064 	status = dladm_datalink_id2info(linkid, NULL, &class, &media, NULL, 0);
5425895Syz147064 	if (status != DLADM_STATUS_OK)
5435895Syz147064 		return (status);
5445895Syz147064 
5455895Syz147064 	for (i = 0; i < DLADM_MAX_PROPS; i++) {
5465895Syz147064 		prop_desc_t	*pdp = &prop_table[i];
5475895Syz147064 		dladm_status_t	s;
5485895Syz147064 
5495895Syz147064 		if (prop_name != NULL &&
5505895Syz147064 		    (strcasecmp(prop_name, pdp->pd_name) != 0))
5515895Syz147064 			continue;
5525895Syz147064 
5535895Syz147064 		found = B_TRUE;
5545895Syz147064 		s = i_dladm_set_single_prop(linkid, class, media, pdp, prop_val,
5555895Syz147064 		    val_cnt, flags);
5563448Sdh155122 
5575895Syz147064 		if (prop_name != NULL) {
5585895Syz147064 			status = s;
5595895Syz147064 			break;
5605895Syz147064 		} else {
5615895Syz147064 			if (s != DLADM_STATUS_OK &&
5625895Syz147064 			    s != DLADM_STATUS_NOTSUP)
5635895Syz147064 				status = s;
5645895Syz147064 		}
5655895Syz147064 	}
566*5903Ssowmini 	if (!found) {
567*5903Ssowmini 		if (prop_name[0] == '_') {
568*5903Ssowmini 			/* other private properties */
569*5903Ssowmini 			status = dld_set_prop(linkid, prop_name, prop_val,
570*5903Ssowmini 			    val_cnt, flags);
571*5903Ssowmini 		} else  {
572*5903Ssowmini 			status = DLADM_STATUS_NOTFOUND;
573*5903Ssowmini 		}
574*5903Ssowmini 	}
5755895Syz147064 
5765895Syz147064 	return (status);
5775895Syz147064 }
5785895Syz147064 
5795895Syz147064 /*
5805895Syz147064  * Set/reset link property for specific link
5815895Syz147064  */
5825895Syz147064 dladm_status_t
5835895Syz147064 dladm_set_linkprop(datalink_id_t linkid, const char *prop_name, char **prop_val,
5845895Syz147064     uint_t val_cnt, uint_t flags)
5855895Syz147064 {
5865895Syz147064 	dladm_status_t	status = DLADM_STATUS_OK;
5875895Syz147064 
5885895Syz147064 	if ((linkid == DATALINK_INVALID_LINKID) || (flags == 0) ||
5895895Syz147064 	    (prop_val == NULL && val_cnt > 0) ||
5905895Syz147064 	    (prop_val != NULL && val_cnt == 0) ||
5915895Syz147064 	    (prop_name == NULL && prop_val != NULL)) {
5925895Syz147064 		return (DLADM_STATUS_BADARG);
5935895Syz147064 	}
5945895Syz147064 
5955895Syz147064 	status = i_dladm_set_linkprop(linkid, prop_name, prop_val,
5965895Syz147064 	    val_cnt, flags);
5975895Syz147064 	if (status != DLADM_STATUS_OK)
5985895Syz147064 		return (status);
5995895Syz147064 
6005895Syz147064 	if (flags & DLADM_OPT_PERSIST) {
6015895Syz147064 		status = i_dladm_set_linkprop_db(linkid, prop_name,
6023147Sxc151355 		    prop_val, val_cnt);
6033147Sxc151355 	}
6043147Sxc151355 	return (status);
6053147Sxc151355 }
6063147Sxc151355 
6075895Syz147064 /*
6085895Syz147064  * Walk link properties of the given specific link.
6095895Syz147064  */
6103147Sxc151355 dladm_status_t
6115895Syz147064 dladm_walk_linkprop(datalink_id_t linkid, void *arg,
6125895Syz147064     int (*func)(datalink_id_t, const char *, void *))
6133147Sxc151355 {
6145895Syz147064 	dladm_status_t		status;
6155895Syz147064 	datalink_class_t	class;
6165895Syz147064 	uint_t			media;
6175895Syz147064 	int			i;
6185895Syz147064 
6195895Syz147064 	if (linkid == DATALINK_INVALID_LINKID || func == NULL)
6205895Syz147064 		return (DLADM_STATUS_BADARG);
6215895Syz147064 
6225895Syz147064 	status = dladm_datalink_id2info(linkid, NULL, &class, &media, NULL, 0);
6235895Syz147064 	if (status != DLADM_STATUS_OK)
6245895Syz147064 		return (status);
6255895Syz147064 
6265895Syz147064 	for (i = 0; i < DLADM_MAX_PROPS; i++) {
6275895Syz147064 		if (!(prop_table[i].pd_class & class))
6285895Syz147064 			continue;
6295895Syz147064 
6305895Syz147064 		if (!DATALINK_MEDIA_ACCEPTED(prop_table[i].pd_dmedia, media))
6315895Syz147064 			continue;
6325895Syz147064 
6335895Syz147064 		if (func(linkid, prop_table[i].pd_name, arg) ==
6345895Syz147064 		    DLADM_WALK_TERMINATE) {
6355895Syz147064 			break;
6365895Syz147064 		}
6375895Syz147064 	}
6385895Syz147064 
6395895Syz147064 	return (DLADM_STATUS_OK);
6405895Syz147064 }
6413448Sdh155122 
6425895Syz147064 /*
6435895Syz147064  * Get linkprop of the given specific link.
6445895Syz147064  */
6455895Syz147064 dladm_status_t
6465895Syz147064 dladm_get_linkprop(datalink_id_t linkid, dladm_prop_type_t type,
6475895Syz147064     const char *prop_name, char **prop_val, uint_t *val_cntp)
6485895Syz147064 {
6495895Syz147064 	dladm_status_t		status = DLADM_STATUS_OK;
6505895Syz147064 	datalink_class_t	class;
6515895Syz147064 	uint_t			media;
6525895Syz147064 	prop_desc_t		*pdp;
6535895Syz147064 	uint_t			cnt;
6545895Syz147064 	int			i;
6555895Syz147064 
6565895Syz147064 	if (linkid == DATALINK_INVALID_LINKID || prop_name == NULL ||
6575895Syz147064 	    prop_val == NULL || val_cntp == NULL || *val_cntp == 0)
6585895Syz147064 		return (DLADM_STATUS_BADARG);
6595895Syz147064 
6605895Syz147064 	for (i = 0; i < DLADM_MAX_PROPS; i++)
6615895Syz147064 		if (strcasecmp(prop_name, prop_table[i].pd_name) == 0)
6625895Syz147064 			break;
6635895Syz147064 
664*5903Ssowmini 	if (i == DLADM_MAX_PROPS) {
665*5903Ssowmini 		if (prop_name[0] == '_') {
666*5903Ssowmini 			/*
667*5903Ssowmini 			 * private property.
668*5903Ssowmini 			 */
669*5903Ssowmini 			return (dld_get_prop(linkid, prop_name,
670*5903Ssowmini 			    prop_val, val_cntp, type));
671*5903Ssowmini 		} else {
672*5903Ssowmini 			return (DLADM_STATUS_NOTFOUND);
673*5903Ssowmini 		}
674*5903Ssowmini 	}
6755895Syz147064 
6765895Syz147064 	pdp = &prop_table[i];
6775895Syz147064 
6785895Syz147064 	status = dladm_datalink_id2info(linkid, NULL, &class, &media, NULL, 0);
6795895Syz147064 	if (status != DLADM_STATUS_OK)
6805895Syz147064 		return (status);
6815895Syz147064 
6825895Syz147064 	if (!(pdp->pd_class & class))
6835895Syz147064 		return (DLADM_STATUS_BADARG);
6845895Syz147064 
6855895Syz147064 	if (!DATALINK_MEDIA_ACCEPTED(pdp->pd_dmedia, media))
6863147Sxc151355 		return (DLADM_STATUS_BADARG);
6873147Sxc151355 
6885895Syz147064 	switch (type) {
6895895Syz147064 	case DLADM_PROP_VAL_CURRENT:
690*5903Ssowmini 		status = pdp->pd_get(pdp, linkid, prop_val, val_cntp);
6915895Syz147064 		break;
6925895Syz147064 
6935895Syz147064 	case DLADM_PROP_VAL_DEFAULT:
6945895Syz147064 		if (pdp->pd_defval.vd_name == NULL) {
6955895Syz147064 			status = DLADM_STATUS_NOTSUP;
6965895Syz147064 			break;
6975895Syz147064 		}
6985895Syz147064 		(void) strcpy(*prop_val, pdp->pd_defval.vd_name);
6995895Syz147064 		*val_cntp = 1;
7005895Syz147064 		break;
7013448Sdh155122 
7025895Syz147064 	case DLADM_PROP_VAL_MODIFIABLE:
7035895Syz147064 		if (pdp->pd_getmod != NULL) {
704*5903Ssowmini 			status = pdp->pd_getmod(pdp, linkid, prop_val,
705*5903Ssowmini 			    val_cntp);
7065895Syz147064 			break;
7075895Syz147064 		}
7085895Syz147064 		cnt = pdp->pd_noptval;
7095895Syz147064 		if (cnt == 0) {
7105895Syz147064 			status = DLADM_STATUS_NOTSUP;
7115895Syz147064 		} else if (cnt > *val_cntp) {
7125895Syz147064 			status = DLADM_STATUS_TOOSMALL;
7135895Syz147064 		} else {
7145895Syz147064 			for (i = 0; i < cnt; i++) {
7155895Syz147064 				(void) strcpy(prop_val[i],
7165895Syz147064 				    pdp->pd_optval[i].vd_name);
7175895Syz147064 			}
7185895Syz147064 			*val_cntp = cnt;
7195895Syz147064 		}
7205895Syz147064 		break;
7215895Syz147064 	case DLADM_PROP_VAL_PERSISTENT:
7225895Syz147064 		if (pdp->pd_flags & PD_TEMPONLY)
7235895Syz147064 			return (DLADM_STATUS_TEMPONLY);
7245895Syz147064 		status = i_dladm_get_linkprop_db(linkid, prop_name,
7255895Syz147064 		    prop_val, val_cntp);
7265895Syz147064 		break;
7275895Syz147064 	default:
7285895Syz147064 		status = DLADM_STATUS_BADARG;
7295895Syz147064 		break;
7303147Sxc151355 	}
7313448Sdh155122 
7325895Syz147064 	return (status);
7335895Syz147064 }
7345895Syz147064 
7355895Syz147064 /*ARGSUSED*/
7365895Syz147064 static int
7375895Syz147064 i_dladm_init_one_prop(datalink_id_t linkid, const char *prop_name, void *arg)
7385895Syz147064 {
7395895Syz147064 	char	*buf, **propvals;
7405895Syz147064 	uint_t	i, valcnt = DLADM_MAX_PROP_VALCNT;
7415895Syz147064 
7425895Syz147064 	if ((buf = malloc((sizeof (char *) + DLADM_PROP_VAL_MAX) *
7435895Syz147064 	    DLADM_MAX_PROP_VALCNT)) == NULL) {
7445895Syz147064 		return (DLADM_WALK_CONTINUE);
7455895Syz147064 	}
7465895Syz147064 
7475895Syz147064 	propvals = (char **)(void *)buf;
7485895Syz147064 	for (i = 0; i < valcnt; i++) {
7495895Syz147064 		propvals[i] = buf +
7505895Syz147064 		    sizeof (char *) * DLADM_MAX_PROP_VALCNT +
7515895Syz147064 		    i * DLADM_PROP_VAL_MAX;
7525895Syz147064 	}
7535895Syz147064 
7545895Syz147064 	if (dladm_get_linkprop(linkid, DLADM_PROP_VAL_PERSISTENT, prop_name,
7555895Syz147064 	    propvals, &valcnt) != DLADM_STATUS_OK) {
7565895Syz147064 		goto done;
7575895Syz147064 	}
7585895Syz147064 
7595895Syz147064 	(void) dladm_set_linkprop(linkid, prop_name, propvals, valcnt,
7605895Syz147064 	    DLADM_OPT_ACTIVE);
7615895Syz147064 
7625895Syz147064 done:
7635895Syz147064 	if (buf != NULL)
7645895Syz147064 		free(buf);
7655895Syz147064 
7665895Syz147064 	return (DLADM_WALK_CONTINUE);
7675895Syz147064 }
7685895Syz147064 
7695895Syz147064 /*ARGSUSED*/
7705895Syz147064 static int
7715895Syz147064 i_dladm_init_linkprop(datalink_id_t linkid, void *arg)
7725895Syz147064 {
7735895Syz147064 	(void) dladm_init_linkprop(linkid);
7745895Syz147064 	return (DLADM_WALK_CONTINUE);
7755895Syz147064 }
7765895Syz147064 
7775895Syz147064 dladm_status_t
7785895Syz147064 dladm_init_linkprop(datalink_id_t linkid)
7795895Syz147064 {
7805895Syz147064 	if (linkid == DATALINK_ALL_LINKID) {
7815895Syz147064 		(void) dladm_walk_datalink_id(i_dladm_init_linkprop, NULL,
7825895Syz147064 		    DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE,
7835895Syz147064 		    DLADM_OPT_PERSIST);
7845895Syz147064 	} else {
7855895Syz147064 		(void) dladm_walk_linkprop(linkid, NULL, i_dladm_init_one_prop);
7863448Sdh155122 	}
7873448Sdh155122 	return (DLADM_STATUS_OK);
7883147Sxc151355 }
7893147Sxc151355 
790*5903Ssowmini /* ARGSUSED */
7915895Syz147064 static dladm_status_t
792*5903Ssowmini do_get_zone(struct prop_desc *pd, datalink_id_t linkid,
793*5903Ssowmini     char **prop_val, uint_t *val_cnt)
7943147Sxc151355 {
7955895Syz147064 	char		zone_name[ZONENAME_MAX];
7965895Syz147064 	zoneid_t	zid;
7975895Syz147064 	dladm_status_t	status;
7983147Sxc151355 
7995895Syz147064 	status = dladm_getzid(linkid, &zid);
8005895Syz147064 	if (status != DLADM_STATUS_OK)
8013448Sdh155122 		return (status);
8023448Sdh155122 
8035895Syz147064 	*val_cnt = 1;
8045895Syz147064 	if (zid != GLOBAL_ZONEID) {
8055895Syz147064 		if (getzonenamebyid(zid, zone_name, sizeof (zone_name)) < 0)
8065895Syz147064 			return (dladm_errno2status(errno));
8073147Sxc151355 
8085895Syz147064 		(void) strncpy(*prop_val, zone_name, DLADM_PROP_VAL_MAX);
8093147Sxc151355 	} else {
8105895Syz147064 		*prop_val[0] = '\0';
8113147Sxc151355 	}
8123147Sxc151355 
8133448Sdh155122 	return (DLADM_STATUS_OK);
8143448Sdh155122 }
8153448Sdh155122 
8163448Sdh155122 typedef int (*zone_get_devroot_t)(char *, char *, size_t);
8173448Sdh155122 
8183448Sdh155122 static int
8193448Sdh155122 i_dladm_get_zone_dev(char *zone_name, char *dev, size_t devlen)
8203448Sdh155122 {
8213448Sdh155122 	char			root[MAXPATHLEN];
8223448Sdh155122 	zone_get_devroot_t	real_zone_get_devroot;
8233448Sdh155122 	void			*dlhandle;
8243448Sdh155122 	void			*sym;
8253448Sdh155122 	int			ret;
8263448Sdh155122 
8273448Sdh155122 	if ((dlhandle = dlopen("libzonecfg.so.1", RTLD_LAZY)) == NULL)
8283448Sdh155122 		return (-1);
8293448Sdh155122 
8303448Sdh155122 	if ((sym = dlsym(dlhandle, "zone_get_devroot")) == NULL) {
8313448Sdh155122 		(void) dlclose(dlhandle);
8323448Sdh155122 		return (-1);
8333448Sdh155122 	}
8343448Sdh155122 
8353448Sdh155122 	real_zone_get_devroot = (zone_get_devroot_t)sym;
8363448Sdh155122 
8373448Sdh155122 	if ((ret = real_zone_get_devroot(zone_name, root, sizeof (root))) == 0)
8383448Sdh155122 		(void) snprintf(dev, devlen, "%s%s", root, "/dev");
8393448Sdh155122 	(void) dlclose(dlhandle);
8403448Sdh155122 	return (ret);
8413448Sdh155122 }
8423448Sdh155122 
8433448Sdh155122 static dladm_status_t
8445895Syz147064 i_dladm_update_deventry(zoneid_t zid, datalink_id_t linkid, boolean_t add)
8453448Sdh155122 {
8463448Sdh155122 	char		path[MAXPATHLEN];
8475895Syz147064 	char		name[MAXLINKNAMELEN];
8483448Sdh155122 	di_prof_t	prof = NULL;
8493448Sdh155122 	char		zone_name[ZONENAME_MAX];
8503448Sdh155122 	dladm_status_t	status;
8515895Syz147064 	int		ret;
8523448Sdh155122 
8533448Sdh155122 	if (getzonenamebyid(zid, zone_name, sizeof (zone_name)) < 0)
8543448Sdh155122 		return (dladm_errno2status(errno));
8553448Sdh155122 	if (i_dladm_get_zone_dev(zone_name, path, sizeof (path)) != 0)
8563448Sdh155122 		return (dladm_errno2status(errno));
8573448Sdh155122 	if (di_prof_init(path, &prof) != 0)
8583448Sdh155122 		return (dladm_errno2status(errno));
8593448Sdh155122 
8605895Syz147064 	status = dladm_linkid2legacyname(linkid, name, MAXLINKNAMELEN);
8615895Syz147064 	if (status != DLADM_STATUS_OK)
8625895Syz147064 		goto cleanup;
8635895Syz147064 
8645895Syz147064 	if (add)
8655895Syz147064 		ret = di_prof_add_dev(prof, name);
8665895Syz147064 	else
8675895Syz147064 		ret = di_prof_add_exclude(prof, name);
8685895Syz147064 
8695895Syz147064 	if (ret != 0) {
8703448Sdh155122 		status = dladm_errno2status(errno);
8713448Sdh155122 		goto cleanup;
8723448Sdh155122 	}
8733448Sdh155122 
8743448Sdh155122 	if (di_prof_commit(prof) != 0)
8753448Sdh155122 		status = dladm_errno2status(errno);
8763448Sdh155122 cleanup:
8773448Sdh155122 	if (prof)
8783448Sdh155122 		di_prof_fini(prof);
8793448Sdh155122 
8803448Sdh155122 	return (status);
8813448Sdh155122 }
8823448Sdh155122 
883*5903Ssowmini /* ARGSUSED */
8843448Sdh155122 static dladm_status_t
885*5903Ssowmini do_set_zone(prop_desc_t *pd, datalink_id_t linkid,
886*5903Ssowmini     val_desc_t *vdp, uint_t val_cnt, uint_t flags)
8873448Sdh155122 {
8883448Sdh155122 	dladm_status_t	status;
8893448Sdh155122 	zoneid_t	zid_old, zid_new;
8905895Syz147064 	char		link[MAXLINKNAMELEN];
8913448Sdh155122 
8923448Sdh155122 	if (val_cnt != 1)
8933448Sdh155122 		return (DLADM_STATUS_BADVALCNT);
8943448Sdh155122 
8955895Syz147064 	status = dladm_getzid(linkid, &zid_old);
8963448Sdh155122 	if (status != DLADM_STATUS_OK)
8973448Sdh155122 		return (status);
8983448Sdh155122 
8993448Sdh155122 	/* Do nothing if setting to current value */
9005895Syz147064 	zid_new = vdp->vd_val;
9013448Sdh155122 	if (zid_new == zid_old)
9023448Sdh155122 		return (DLADM_STATUS_OK);
9033448Sdh155122 
9045895Syz147064 	if ((status = dladm_datalink_id2info(linkid, NULL, NULL, NULL,
9055895Syz147064 	    link, MAXLINKNAMELEN)) != DLADM_STATUS_OK) {
9065895Syz147064 		return (status);
9075895Syz147064 	}
9085895Syz147064 
9095895Syz147064 	if (zid_new != GLOBAL_ZONEID) {
9105895Syz147064 		/*
9115895Syz147064 		 * If the new zoneid is the global zone, we could destroy
9125895Syz147064 		 * the link (in the case of an implicitly-created VLAN) as a
9135895Syz147064 		 * result of the dladm_setzid() operation. In that case,
9145895Syz147064 		 * we defer the operation to the end of this function to avoid
9155895Syz147064 		 * recreating the VLAN and getting a different linkid during
9165895Syz147064 		 * the rollback if other operation fails.
9175895Syz147064 		 *
9185895Syz147064 		 * Otherwise, dladm_setzid() will hold a reference to the
9195895Syz147064 		 * link and prevent a link renaming, so we need to do it
9205895Syz147064 		 * before other operations.
9215895Syz147064 		 */
9225895Syz147064 		status = dladm_setzid(link, zid_new);
9235895Syz147064 		if (status != DLADM_STATUS_OK)
9245895Syz147064 			return (status);
9255895Syz147064 	}
9265895Syz147064 
9273448Sdh155122 	if (zid_old != GLOBAL_ZONEID) {
9285895Syz147064 		if (zone_remove_datalink(zid_old, link) != 0 &&
9293448Sdh155122 		    errno != ENXIO) {
9303448Sdh155122 			status = dladm_errno2status(errno);
9313448Sdh155122 			goto rollback1;
9323448Sdh155122 		}
9333448Sdh155122 
9345895Syz147064 		/*
9355895Syz147064 		 * It is okay to fail to update the /dev entry (some
9365895Syz147064 		 * vanity-named links do not have a /dev entry).
9375895Syz147064 		 */
9385895Syz147064 		(void) i_dladm_update_deventry(zid_old, linkid, B_FALSE);
9395895Syz147064 	}
9405895Syz147064 
9415895Syz147064 	if (zid_new != GLOBAL_ZONEID) {
9425895Syz147064 		if (zone_add_datalink(zid_new, link) != 0) {
9435895Syz147064 			status = dladm_errno2status(errno);
9445895Syz147064 			goto rollback2;
9455895Syz147064 		}
9465895Syz147064 
9475895Syz147064 		(void) i_dladm_update_deventry(zid_new, linkid, B_TRUE);
9485895Syz147064 	} else {
9495895Syz147064 		status = dladm_setzid(link, zid_new);
9503448Sdh155122 		if (status != DLADM_STATUS_OK)
9513448Sdh155122 			goto rollback2;
9523448Sdh155122 	}
9533448Sdh155122 
9543448Sdh155122 	return (DLADM_STATUS_OK);
9553448Sdh155122 
9563448Sdh155122 rollback2:
9573448Sdh155122 	if (zid_old != GLOBAL_ZONEID)
9585895Syz147064 		(void) i_dladm_update_deventry(zid_old, linkid, B_TRUE);
9595895Syz147064 	if (zid_old != GLOBAL_ZONEID)
9605895Syz147064 		(void) zone_add_datalink(zid_old, link);
9613448Sdh155122 rollback1:
9625895Syz147064 	if (zid_new != GLOBAL_ZONEID)
9635895Syz147064 		(void) dladm_setzid(link, zid_old);
9643448Sdh155122 	return (status);
9653448Sdh155122 }
9663448Sdh155122 
9673448Sdh155122 /* ARGSUSED */
9683448Sdh155122 static dladm_status_t
969*5903Ssowmini do_check_zone(struct prop_desc *pd, datalink_id_t linkid, char **prop_val,
970*5903Ssowmini     uint_t val_cnt, val_desc_t *vdp)
9713448Sdh155122 {
9725895Syz147064 	zoneid_t	zid;
9733448Sdh155122 
9743448Sdh155122 	if (val_cnt != 1)
9753448Sdh155122 		return (DLADM_STATUS_BADVALCNT);
9763448Sdh155122 
9773448Sdh155122 	if ((zid = getzoneidbyname(*prop_val)) == -1)
9783448Sdh155122 		return (DLADM_STATUS_BADVAL);
9793448Sdh155122 
9803448Sdh155122 	if (zid != GLOBAL_ZONEID) {
9813448Sdh155122 		ushort_t	flags;
9823448Sdh155122 
9833448Sdh155122 		if (zone_getattr(zid, ZONE_ATTR_FLAGS, &flags,
9843448Sdh155122 		    sizeof (flags)) < 0) {
9853448Sdh155122 			return (dladm_errno2status(errno));
9863448Sdh155122 		}
9873448Sdh155122 
9883448Sdh155122 		if (!(flags & ZF_NET_EXCL)) {
9893448Sdh155122 			return (DLADM_STATUS_BADVAL);
9903448Sdh155122 		}
9913448Sdh155122 	}
9923448Sdh155122 
9935895Syz147064 	vdp->vd_val = zid;
9945895Syz147064 	return (DLADM_STATUS_OK);
9955895Syz147064 }
9965895Syz147064 
997*5903Ssowmini /* ARGSUSED */
9985895Syz147064 static dladm_status_t
999*5903Ssowmini do_get_autopush(struct prop_desc *pd, datalink_id_t linkid,
1000*5903Ssowmini     char **prop_val, uint_t *val_cnt)
10015895Syz147064 {
10025895Syz147064 	dld_ioc_ap_t	dia;
10035895Syz147064 	int		fd, i, len;
10045895Syz147064 
10055895Syz147064 	if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0)
10065895Syz147064 		return (dladm_errno2status(errno));
10075895Syz147064 
10085895Syz147064 	*val_cnt = 1;
10095895Syz147064 	dia.dia_linkid = linkid;
10105895Syz147064 	if (i_dladm_ioctl(fd, DLDIOC_GETAUTOPUSH, &dia, sizeof (dia)) < 0) {
10115895Syz147064 		(*prop_val)[0] = '\0';
10125895Syz147064 		goto done;
10135895Syz147064 	}
10145895Syz147064 
10155895Syz147064 	for (i = 0, len = 0; i < dia.dia_npush; i++) {
10165895Syz147064 		if (i != 0) {
10175895Syz147064 			(void) snprintf(*prop_val + len,
10185895Syz147064 			    DLADM_PROP_VAL_MAX - len, "%c", AP_DELIMITER);
10195895Syz147064 			len += 1;
10205895Syz147064 		}
10215895Syz147064 		(void) snprintf(*prop_val + len, DLADM_PROP_VAL_MAX - len,
10225895Syz147064 		    "%s", dia.dia_aplist[i]);
10235895Syz147064 		len += strlen(dia.dia_aplist[i]);
10245895Syz147064 		if (dia.dia_anchor - 1 == i) {
10255895Syz147064 			(void) snprintf(*prop_val + len,
10265895Syz147064 			    DLADM_PROP_VAL_MAX - len, "%c%s", AP_DELIMITER,
10275895Syz147064 			    AP_ANCHOR);
10285895Syz147064 			len += (strlen(AP_ANCHOR) + 1);
10295895Syz147064 		}
10305895Syz147064 	}
10315895Syz147064 
10325895Syz147064 done:
10335895Syz147064 	(void) close(fd);
10345895Syz147064 	return (DLADM_STATUS_OK);
10355895Syz147064 }
10365895Syz147064 
1037*5903Ssowmini /* ARGSUSED */
10385895Syz147064 static dladm_status_t
1039*5903Ssowmini do_set_autopush(prop_desc_t *pd, datalink_id_t linkid,
1040*5903Ssowmini     val_desc_t *vdp, uint_t val_cnt, uint_t flags)
10415895Syz147064 {
10425895Syz147064 	dld_ioc_ap_t		dia;
10435895Syz147064 	struct dlautopush	*dlap = (struct dlautopush *)vdp->vd_val;
10445895Syz147064 	dladm_status_t		status = DLADM_STATUS_OK;
10455895Syz147064 	int			fd, i;
10465895Syz147064 	int			ic_cmd;
10475895Syz147064 
10485895Syz147064 	if (val_cnt != 1)
10495895Syz147064 		return (DLADM_STATUS_BADVALCNT);
10505895Syz147064 
10515895Syz147064 	if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0)
10525895Syz147064 		return (dladm_errno2status(errno));
10535895Syz147064 
10545895Syz147064 	dia.dia_linkid = linkid;
10555895Syz147064 	if (dlap != NULL) {
10565895Syz147064 		dia.dia_anchor = dlap->dap_anchor;
10575895Syz147064 		dia.dia_npush = dlap->dap_npush;
10585895Syz147064 		for (i = 0; i < dia.dia_npush; i++) {
10595895Syz147064 			(void) strlcpy(dia.dia_aplist[i], dlap->dap_aplist[i],
10605895Syz147064 			    FMNAMESZ+1);
10615895Syz147064 		}
10625895Syz147064 		ic_cmd = DLDIOC_SETAUTOPUSH;
10635895Syz147064 	} else {
10645895Syz147064 		ic_cmd = DLDIOC_CLRAUTOPUSH;
10655895Syz147064 	}
10665895Syz147064 
10675895Syz147064 	if (i_dladm_ioctl(fd, ic_cmd, &dia, sizeof (dia)) < 0)
10685895Syz147064 		status = dladm_errno2status(errno);
10695895Syz147064 
10705895Syz147064 	(void) close(fd);
10715895Syz147064 	return (status);
10725895Syz147064 }
10735895Syz147064 
10745895Syz147064 /*
10755895Syz147064  * Add the specified module to the dlautopush structure; returns a
10765895Syz147064  * DLADM_STATUS_* code.
10775895Syz147064  */
10785895Syz147064 dladm_status_t
10795895Syz147064 i_dladm_add_ap_module(const char *module, struct dlautopush *dlap)
10805895Syz147064 {
10815895Syz147064 	if ((strlen(module) == 0) || (strlen(module) > FMNAMESZ))
10825895Syz147064 		return (DLADM_STATUS_BADVAL);
10835895Syz147064 
10845895Syz147064 	if (strncasecmp(module, AP_ANCHOR, strlen(AP_ANCHOR)) == 0) {
10855895Syz147064 		/*
10865895Syz147064 		 * We don't allow multiple anchors, and the anchor must
10875895Syz147064 		 * be after at least one module.
10885895Syz147064 		 */
10895895Syz147064 		if (dlap->dap_anchor != 0)
10905895Syz147064 			return (DLADM_STATUS_BADVAL);
10915895Syz147064 		if (dlap->dap_npush == 0)
10925895Syz147064 			return (DLADM_STATUS_BADVAL);
10935895Syz147064 
10945895Syz147064 		dlap->dap_anchor = dlap->dap_npush;
10955895Syz147064 		return (DLADM_STATUS_OK);
10965895Syz147064 	}
10975895Syz147064 	if (dlap->dap_npush > MAXAPUSH)
10985895Syz147064 		return (DLADM_STATUS_BADVALCNT);
10995895Syz147064 
11005895Syz147064 	(void) strlcpy(dlap->dap_aplist[dlap->dap_npush++], module,
11015895Syz147064 	    FMNAMESZ + 1);
11025895Syz147064 
11035895Syz147064 	return (DLADM_STATUS_OK);
11045895Syz147064 }
11055895Syz147064 
11065895Syz147064 /*
11075895Syz147064  * Currently, both '.' and ' '(space) can be used as the delimiters between
11085895Syz147064  * autopush modules. The former is used in dladm set-linkprop, and the
11095895Syz147064  * latter is used in the autopush(1M) file.
11105895Syz147064  */
11115895Syz147064 /* ARGSUSED */
11125895Syz147064 static dladm_status_t
1113*5903Ssowmini do_check_autopush(struct prop_desc *pd, datalink_id_t linkid, char **prop_val,
1114*5903Ssowmini     uint_t val_cnt, val_desc_t *vdp)
11155895Syz147064 {
11165895Syz147064 	char			*module;
11175895Syz147064 	struct dlautopush	*dlap;
11185895Syz147064 	dladm_status_t		status;
11195895Syz147064 	char			val[DLADM_PROP_VAL_MAX];
11205895Syz147064 	char			delimiters[4];
11215895Syz147064 
11225895Syz147064 	if (val_cnt != 1)
11235895Syz147064 		return (DLADM_STATUS_BADVALCNT);
11245895Syz147064 
11255895Syz147064 	dlap = malloc(sizeof (struct dlautopush));
11265895Syz147064 	if (dlap == NULL)
11273448Sdh155122 		return (DLADM_STATUS_NOMEM);
11283448Sdh155122 
11295895Syz147064 	(void) memset(dlap, 0, sizeof (struct dlautopush));
11305895Syz147064 	(void) snprintf(delimiters, 4, " %c\n", AP_DELIMITER);
11315895Syz147064 	bcopy(*prop_val, val, DLADM_PROP_VAL_MAX);
11325895Syz147064 	module = strtok(val, delimiters);
11335895Syz147064 	while (module != NULL) {
11345895Syz147064 		status = i_dladm_add_ap_module(module, dlap);
11355895Syz147064 		if (status != DLADM_STATUS_OK)
11365895Syz147064 			return (status);
11375895Syz147064 		module = strtok(NULL, delimiters);
11385895Syz147064 	}
11395895Syz147064 
11405895Syz147064 	vdp->vd_val = (uintptr_t)dlap;
11413448Sdh155122 	return (DLADM_STATUS_OK);
11423448Sdh155122 }
11433448Sdh155122 
1144*5903Ssowmini /* ARGSUSED */
11453448Sdh155122 static dladm_status_t
1146*5903Ssowmini do_get_rate_common(struct prop_desc *pd, datalink_id_t linkid,
1147*5903Ssowmini     char **prop_val, uint_t *val_cnt, uint_t id)
11483448Sdh155122 {
11495895Syz147064 	wl_rates_t	*wrp;
11505895Syz147064 	uint_t		i;
11515895Syz147064 	wldp_t		*gbuf = NULL;
11525895Syz147064 	dladm_status_t	status = DLADM_STATUS_OK;
11535895Syz147064 
11545895Syz147064 	if ((gbuf = malloc(MAX_BUF_LEN)) == NULL) {
11555895Syz147064 		status = DLADM_STATUS_NOMEM;
11565895Syz147064 		goto done;
11575895Syz147064 	}
11585895Syz147064 
11595895Syz147064 	status = i_dladm_wlan_get_ioctl(linkid, gbuf, id);
11605895Syz147064 	if (status != DLADM_STATUS_OK)
11615895Syz147064 		goto done;
11625895Syz147064 
11635895Syz147064 	wrp = (wl_rates_t *)gbuf->wldp_buf;
11645895Syz147064 	if (wrp->wl_rates_num > *val_cnt) {
11655895Syz147064 		status = DLADM_STATUS_TOOSMALL;
11665895Syz147064 		goto done;
11675895Syz147064 	}
11685895Syz147064 
11695895Syz147064 	if (wrp->wl_rates_rates[0] == 0) {
11705895Syz147064 		prop_val[0][0] = '\0';
11715895Syz147064 		*val_cnt = 1;
11725895Syz147064 		goto done;
11735895Syz147064 	}
11745895Syz147064 
11755895Syz147064 	for (i = 0; i < wrp->wl_rates_num; i++) {
11765895Syz147064 		(void) snprintf(prop_val[i], DLADM_STRSIZE, "%.*f",
11775895Syz147064 		    wrp->wl_rates_rates[i] % 2,
11785895Syz147064 		    (float)wrp->wl_rates_rates[i] / 2);
11795895Syz147064 	}
11805895Syz147064 	*val_cnt = wrp->wl_rates_num;
11813448Sdh155122 
11825895Syz147064 done:
11835895Syz147064 	free(gbuf);
11845895Syz147064 	return (status);
11855895Syz147064 }
11865895Syz147064 
11875895Syz147064 static dladm_status_t
1188*5903Ssowmini do_get_rate_prop(struct prop_desc *pd, datalink_id_t linkid,
1189*5903Ssowmini     char **prop_val, uint_t *val_cnt)
11905895Syz147064 {
1191*5903Ssowmini 	return (do_get_rate_common(pd, linkid, prop_val, val_cnt,
11925895Syz147064 	    WL_DESIRED_RATES));
11935895Syz147064 }
11945895Syz147064 
11955895Syz147064 static dladm_status_t
1196*5903Ssowmini do_get_rate_mod(struct prop_desc *pd, datalink_id_t linkid,
1197*5903Ssowmini     char **prop_val, uint_t *val_cnt)
11985895Syz147064 {
1199*5903Ssowmini 	return (do_get_rate_common(pd, linkid, prop_val, val_cnt,
12005895Syz147064 	    WL_SUPPORTED_RATES));
12015895Syz147064 }
12025895Syz147064 
12035895Syz147064 static dladm_status_t
12045895Syz147064 do_set_rate(datalink_id_t linkid, dladm_wlan_rates_t *rates)
12055895Syz147064 {
12065895Syz147064 	int		i;
12075895Syz147064 	uint_t		len;
12085895Syz147064 	wldp_t		*gbuf;
12095895Syz147064 	wl_rates_t	*wrp;
12105895Syz147064 	dladm_status_t	status = DLADM_STATUS_OK;
12115895Syz147064 
12125895Syz147064 	if ((gbuf = malloc(MAX_BUF_LEN)) == NULL)
12135895Syz147064 		return (DLADM_STATUS_NOMEM);
12145895Syz147064 
12155895Syz147064 	(void) memset(gbuf, 0, MAX_BUF_LEN);
12163448Sdh155122 
12175895Syz147064 	wrp = (wl_rates_t *)gbuf->wldp_buf;
12185895Syz147064 	for (i = 0; i < rates->wr_cnt; i++)
12195895Syz147064 		wrp->wl_rates_rates[i] = rates->wr_rates[i];
12205895Syz147064 	wrp->wl_rates_num = rates->wr_cnt;
12215895Syz147064 
12225895Syz147064 	len = offsetof(wl_rates_t, wl_rates_rates) +
12235895Syz147064 	    (rates->wr_cnt * sizeof (char)) + WIFI_BUF_OFFSET;
12245895Syz147064 	status = i_dladm_wlan_ioctl(linkid, gbuf, WL_DESIRED_RATES, len,
12255895Syz147064 	    WLAN_SET_PARAM, len);
12265895Syz147064 
12275895Syz147064 	free(gbuf);
12285895Syz147064 	return (status);
12295895Syz147064 }
12303448Sdh155122 
1231*5903Ssowmini /* ARGSUSED */
12325895Syz147064 static dladm_status_t
1233*5903Ssowmini do_set_rate_prop(prop_desc_t *pd, datalink_id_t linkid,
1234*5903Ssowmini     val_desc_t *vdp, uint_t val_cnt, uint_t flags)
12355895Syz147064 {
12365895Syz147064 	dladm_wlan_rates_t	rates;
12375895Syz147064 	dladm_status_t		status;
12385895Syz147064 
12395895Syz147064 	if (val_cnt != 1)
12405895Syz147064 		return (DLADM_STATUS_BADVALCNT);
12415895Syz147064 
12425895Syz147064 	rates.wr_cnt = 1;
12435895Syz147064 	rates.wr_rates[0] = vdp[0].vd_val;
12445895Syz147064 
12455895Syz147064 	status = do_set_rate(linkid, &rates);
12465895Syz147064 
12475895Syz147064 done:
12485895Syz147064 	return (status);
12495895Syz147064 }
12503448Sdh155122 
12515895Syz147064 /* ARGSUSED */
12525895Syz147064 static dladm_status_t
1253*5903Ssowmini do_check_rate(struct prop_desc *pd, datalink_id_t linkid, char **prop_val,
1254*5903Ssowmini     uint_t val_cnt, val_desc_t *vdp)
12555895Syz147064 {
12565895Syz147064 	int		i;
12575895Syz147064 	uint_t		modval_cnt = MAX_SUPPORT_RATES;
12585895Syz147064 	char		*buf, **modval;
12595895Syz147064 	dladm_status_t	status;
12605895Syz147064 
12615895Syz147064 	if (val_cnt != 1)
12625895Syz147064 		return (DLADM_STATUS_BADVALCNT);
12635895Syz147064 
12645895Syz147064 	buf = malloc((sizeof (char *) + DLADM_STRSIZE) *
12655895Syz147064 	    MAX_SUPPORT_RATES);
12665895Syz147064 	if (buf == NULL) {
12675895Syz147064 		status = DLADM_STATUS_NOMEM;
12685895Syz147064 		goto done;
12695895Syz147064 	}
12703448Sdh155122 
12715895Syz147064 	modval = (char **)(void *)buf;
12725895Syz147064 	for (i = 0; i < MAX_SUPPORT_RATES; i++) {
12735895Syz147064 		modval[i] = buf + sizeof (char *) * MAX_SUPPORT_RATES +
12745895Syz147064 		    i * DLADM_STRSIZE;
12755895Syz147064 	}
12765895Syz147064 
1277*5903Ssowmini 	status = do_get_rate_mod(NULL, linkid, modval, &modval_cnt);
12785895Syz147064 	if (status != DLADM_STATUS_OK)
12795895Syz147064 		goto done;
12805895Syz147064 
12815895Syz147064 	for (i = 0; i < modval_cnt; i++) {
12825895Syz147064 		if (strcasecmp(*prop_val, modval[i]) == 0) {
1283*5903Ssowmini 			vdp->vd_val = (uintptr_t)(uint_t)
1284*5903Ssowmini 			    (atof(*prop_val) * 2);
12855895Syz147064 			status = DLADM_STATUS_OK;
12863448Sdh155122 			break;
12873448Sdh155122 		}
12885895Syz147064 	}
12895895Syz147064 	if (i == modval_cnt)
12905895Syz147064 		status = DLADM_STATUS_BADVAL;
12915895Syz147064 done:
12925895Syz147064 	free(buf);
12935895Syz147064 	return (status);
12945895Syz147064 }
12955895Syz147064 
12965895Syz147064 static dladm_status_t
12975895Syz147064 do_get_phyconf(datalink_id_t linkid, wldp_t *gbuf)
12985895Syz147064 {
12995895Syz147064 	return (i_dladm_wlan_get_ioctl(linkid, gbuf, WL_PHY_CONFIG));
13005895Syz147064 }
13015895Syz147064 
1302*5903Ssowmini /* ARGSUSED */
13035895Syz147064 static dladm_status_t
1304*5903Ssowmini do_get_channel_prop(struct prop_desc *pd, datalink_id_t linkid,
1305*5903Ssowmini     char **prop_val, uint_t *val_cnt)
13065895Syz147064 {
13075895Syz147064 	uint32_t	channel;
13085895Syz147064 	wldp_t		*gbuf;
13095895Syz147064 	dladm_status_t	status = DLADM_STATUS_OK;
13105895Syz147064 
13115895Syz147064 	if ((gbuf = malloc(MAX_BUF_LEN)) == NULL)
13125895Syz147064 		return (DLADM_STATUS_NOMEM);
13135895Syz147064 
13145895Syz147064 	if ((status = do_get_phyconf(linkid, gbuf)) != DLADM_STATUS_OK)
13155895Syz147064 		goto done;
13165895Syz147064 
13175895Syz147064 	if (!i_dladm_wlan_convert_chan((wl_phy_conf_t *)gbuf->wldp_buf,
13185895Syz147064 	    &channel)) {
13195895Syz147064 		status = DLADM_STATUS_NOTFOUND;
13205895Syz147064 		goto done;
13215895Syz147064 	}
13225895Syz147064 
13235895Syz147064 	(void) snprintf(*prop_val, DLADM_STRSIZE, "%u", channel);
13245895Syz147064 	*val_cnt = 1;
13253448Sdh155122 
13265895Syz147064 done:
13275895Syz147064 	free(gbuf);
13285895Syz147064 	return (status);
13295895Syz147064 }
13305895Syz147064 
13315895Syz147064 static dladm_status_t
13325895Syz147064 do_get_powermode(datalink_id_t linkid, wldp_t *gbuf)
13335895Syz147064 {
13345895Syz147064 	return (i_dladm_wlan_get_ioctl(linkid, gbuf, WL_POWER_MODE));
13355895Syz147064 }
13365895Syz147064 
1337*5903Ssowmini /* ARGSUSED */
13385895Syz147064 static dladm_status_t
1339*5903Ssowmini do_get_powermode_prop(struct prop_desc *pd, datalink_id_t linkid,
1340*5903Ssowmini     char **prop_val, uint_t *val_cnt)
13415895Syz147064 {
13425895Syz147064 	wl_ps_mode_t	*mode;
13435895Syz147064 	const char	*s;
13445895Syz147064 	wldp_t		*gbuf;
13455895Syz147064 	dladm_status_t	status = DLADM_STATUS_OK;
13465895Syz147064 
13475895Syz147064 	if ((gbuf = malloc(MAX_BUF_LEN)) == NULL)
13485895Syz147064 		return (DLADM_STATUS_NOMEM);
13495895Syz147064 
13505895Syz147064 	if ((status = do_get_powermode(linkid, gbuf)) != DLADM_STATUS_OK)
13515895Syz147064 		goto done;
13525895Syz147064 
13535895Syz147064 	mode = (wl_ps_mode_t *)(gbuf->wldp_buf);
13545895Syz147064 	switch (mode->wl_ps_mode) {
13555895Syz147064 	case WL_PM_AM:
13565895Syz147064 		s = "off";
13575895Syz147064 		break;
13585895Syz147064 	case WL_PM_MPS:
13595895Syz147064 		s = "max";
13605895Syz147064 		break;
13615895Syz147064 	case WL_PM_FAST:
13625895Syz147064 		s = "fast";
13633448Sdh155122 		break;
13643448Sdh155122 	default:
13655895Syz147064 		status = DLADM_STATUS_NOTFOUND;
13665895Syz147064 		goto done;
13675895Syz147064 	}
13685895Syz147064 	(void) snprintf(*prop_val, DLADM_STRSIZE, "%s", s);
13695895Syz147064 	*val_cnt = 1;
13705895Syz147064 
13715895Syz147064 done:
13725895Syz147064 	free(gbuf);
13735895Syz147064 	return (status);
13745895Syz147064 }
13755895Syz147064 
13765895Syz147064 static dladm_status_t
13775895Syz147064 do_set_powermode(datalink_id_t linkid, dladm_wlan_powermode_t *pm)
13785895Syz147064 {
13795895Syz147064 	wl_ps_mode_t    ps_mode;
13805895Syz147064 
13815895Syz147064 	(void) memset(&ps_mode, 0xff, sizeof (ps_mode));
13825895Syz147064 
13835895Syz147064 	switch (*pm) {
13845895Syz147064 	case DLADM_WLAN_PM_OFF:
13855895Syz147064 		ps_mode.wl_ps_mode = WL_PM_AM;
13863448Sdh155122 		break;
13875895Syz147064 	case DLADM_WLAN_PM_MAX:
13885895Syz147064 		ps_mode.wl_ps_mode = WL_PM_MPS;
13895895Syz147064 		break;
13905895Syz147064 	case DLADM_WLAN_PM_FAST:
13915895Syz147064 		ps_mode.wl_ps_mode = WL_PM_FAST;
13925895Syz147064 		break;
13935895Syz147064 	default:
13945895Syz147064 		return (DLADM_STATUS_NOTSUP);
13953448Sdh155122 	}
13965895Syz147064 	return (i_dladm_wlan_set_ioctl(linkid, WL_POWER_MODE, &ps_mode,
13975895Syz147064 	    sizeof (ps_mode)));
13985895Syz147064 }
13995895Syz147064 
14005895Syz147064 /* ARGSUSED */
14015895Syz147064 static dladm_status_t
1402*5903Ssowmini do_set_powermode_prop(prop_desc_t *pd, datalink_id_t linkid,
1403*5903Ssowmini     val_desc_t *vdp, uint_t val_cnt, uint_t flags)
14045895Syz147064 {
14055895Syz147064 	dladm_wlan_powermode_t powermode = (dladm_wlan_powermode_t)vdp->vd_val;
14065895Syz147064 	dladm_status_t status;
14075895Syz147064 
14085895Syz147064 	if (val_cnt != 1)
14095895Syz147064 		return (DLADM_STATUS_BADVALCNT);
14105895Syz147064 
14115895Syz147064 	status = do_set_powermode(linkid, &powermode);
14123448Sdh155122 
14133448Sdh155122 	return (status);
14143448Sdh155122 }
14153448Sdh155122 
14163448Sdh155122 static dladm_status_t
14175895Syz147064 do_get_radio(datalink_id_t linkid, wldp_t *gbuf)
14183448Sdh155122 {
14195895Syz147064 	return (i_dladm_wlan_get_ioctl(linkid, gbuf, WL_RADIO));
14205895Syz147064 }
14213448Sdh155122 
1422*5903Ssowmini /* ARGSUSED */
14235895Syz147064 static dladm_status_t
1424*5903Ssowmini do_get_radio_prop(struct prop_desc *pd, datalink_id_t linkid,
1425*5903Ssowmini     char **prop_val, uint_t *val_cnt)
14265895Syz147064 {
14275895Syz147064 	wl_radio_t	radio;
14285895Syz147064 	const char	*s;
14295895Syz147064 	wldp_t		*gbuf;
14305895Syz147064 	dladm_status_t	status = DLADM_STATUS_OK;
14313448Sdh155122 
14325895Syz147064 	if ((gbuf = malloc(MAX_BUF_LEN)) == NULL)
14335895Syz147064 		return (DLADM_STATUS_NOMEM);
14343448Sdh155122 
14355895Syz147064 	if ((status = do_get_radio(linkid, gbuf)) != DLADM_STATUS_OK)
14365895Syz147064 		goto done;
14373448Sdh155122 
14385895Syz147064 	radio = *(wl_radio_t *)(gbuf->wldp_buf);
14395895Syz147064 	switch (radio) {
14405895Syz147064 	case B_TRUE:
14415895Syz147064 		s = "on";
14425895Syz147064 		break;
14435895Syz147064 	case B_FALSE:
14445895Syz147064 		s = "off";
14455895Syz147064 		break;
14465895Syz147064 	default:
14475895Syz147064 		status = DLADM_STATUS_NOTFOUND;
14485895Syz147064 		goto done;
14495895Syz147064 	}
14505895Syz147064 	(void) snprintf(*prop_val, DLADM_STRSIZE, "%s", s);
14515895Syz147064 	*val_cnt = 1;
14523448Sdh155122 
14535895Syz147064 done:
14545895Syz147064 	free(gbuf);
14553448Sdh155122 	return (status);
14563448Sdh155122 }
14573448Sdh155122 
14583448Sdh155122 static dladm_status_t
14595895Syz147064 do_set_radio(datalink_id_t linkid, dladm_wlan_radio_t *radio)
14603448Sdh155122 {
14615895Syz147064 	wl_radio_t r;
14623448Sdh155122 
14635895Syz147064 	switch (*radio) {
14645895Syz147064 	case DLADM_WLAN_RADIO_ON:
14655895Syz147064 		r = B_TRUE;
14665895Syz147064 		break;
14675895Syz147064 	case DLADM_WLAN_RADIO_OFF:
14685895Syz147064 		r = B_FALSE;
14695895Syz147064 		break;
14705895Syz147064 	default:
14715895Syz147064 		return (DLADM_STATUS_NOTSUP);
14725895Syz147064 	}
14735895Syz147064 	return (i_dladm_wlan_set_ioctl(linkid, WL_RADIO, &r, sizeof (r)));
14745895Syz147064 }
14753448Sdh155122 
14765895Syz147064 /* ARGSUSED */
14775895Syz147064 static dladm_status_t
1478*5903Ssowmini do_set_radio_prop(prop_desc_t *pd, datalink_id_t linkid,
1479*5903Ssowmini     val_desc_t *vdp, uint_t val_cnt, uint_t fags)
14805895Syz147064 {
14815895Syz147064 	dladm_wlan_radio_t radio = (dladm_wlan_radio_t)vdp->vd_val;
14825895Syz147064 	dladm_status_t status;
14833448Sdh155122 
14845895Syz147064 	if (val_cnt != 1)
14855895Syz147064 		return (DLADM_STATUS_BADVALCNT);
14865895Syz147064 
14875895Syz147064 	status = do_set_radio(linkid, &radio);
14883448Sdh155122 
14893448Sdh155122 	return (status);
14903448Sdh155122 }
14913448Sdh155122 
14925895Syz147064 static dladm_status_t
14935895Syz147064 i_dladm_set_linkprop_db(datalink_id_t linkid, const char *prop_name,
14945895Syz147064     char **prop_val, uint_t val_cnt)
14953448Sdh155122 {
14965895Syz147064 	char		buf[MAXLINELEN];
14975895Syz147064 	int		i;
14985895Syz147064 	dladm_conf_t	conf;
14995895Syz147064 	dladm_status_t	status;
15003448Sdh155122 
15015895Syz147064 	status = dladm_read_conf(linkid, &conf);
15025895Syz147064 	if (status != DLADM_STATUS_OK)
15035895Syz147064 		return (status);
15043448Sdh155122 
15055895Syz147064 	/*
15065895Syz147064 	 * reset case.
15075895Syz147064 	 */
15085895Syz147064 	if (val_cnt == 0) {
15095895Syz147064 		status = dladm_unset_conf_field(conf, prop_name);
15105895Syz147064 		if (status == DLADM_STATUS_OK)
15115895Syz147064 			status = dladm_write_conf(conf);
15125895Syz147064 		goto done;
15135895Syz147064 	}
15143448Sdh155122 
15155895Syz147064 	buf[0] = '\0';
15165895Syz147064 	for (i = 0; i < val_cnt; i++) {
15175895Syz147064 		(void) strlcat(buf, prop_val[i], MAXLINELEN);
15185895Syz147064 		if (i != val_cnt - 1)
15195895Syz147064 			(void) strlcat(buf, ",", MAXLINELEN);
15203448Sdh155122 	}
15213448Sdh155122 
15225895Syz147064 	status = dladm_set_conf_field(conf, prop_name, DLADM_TYPE_STR, buf);
15235895Syz147064 	if (status == DLADM_STATUS_OK)
15245895Syz147064 		status = dladm_write_conf(conf);
15255895Syz147064 
15265895Syz147064 done:
15275895Syz147064 	dladm_destroy_conf(conf);
15285895Syz147064 	return (status);
15293448Sdh155122 }
15305895Syz147064 
15315895Syz147064 static dladm_status_t
15325895Syz147064 i_dladm_get_linkprop_db(datalink_id_t linkid, const char *prop_name,
15335895Syz147064     char **prop_val, uint_t *val_cntp)
15345895Syz147064 {
15355895Syz147064 	char		buf[MAXLINELEN], *str;
15365895Syz147064 	uint_t		cnt = 0;
15375895Syz147064 	dladm_conf_t	conf;
15385895Syz147064 	dladm_status_t	status;
15395895Syz147064 
15405895Syz147064 	status = dladm_read_conf(linkid, &conf);
15415895Syz147064 	if (status != DLADM_STATUS_OK)
15425895Syz147064 		return (status);
15435895Syz147064 
15445895Syz147064 	status = dladm_get_conf_field(conf, prop_name, buf, MAXLINELEN);
15455895Syz147064 	if (status != DLADM_STATUS_OK)
15465895Syz147064 		goto done;
15475895Syz147064 
15485895Syz147064 	str = strtok(buf, ",");
15495895Syz147064 	while (str != NULL) {
15505895Syz147064 		if (cnt == *val_cntp) {
15515895Syz147064 			status = DLADM_STATUS_TOOSMALL;
15525895Syz147064 			goto done;
15535895Syz147064 		}
15545895Syz147064 		(void) strlcpy(prop_val[cnt++], str, DLADM_PROP_VAL_MAX);
15555895Syz147064 		str = strtok(NULL, ",");
15565895Syz147064 	}
15575895Syz147064 
15585895Syz147064 	*val_cntp = cnt;
15595895Syz147064 
15605895Syz147064 done:
15615895Syz147064 	dladm_destroy_conf(conf);
15625895Syz147064 	return (status);
15635895Syz147064 }
1564*5903Ssowmini 
1565*5903Ssowmini static dld_public_prop_t *
1566*5903Ssowmini dladm_name2prop(const char *prop_name)
1567*5903Ssowmini {
1568*5903Ssowmini 	dld_public_prop_t *p;
1569*5903Ssowmini 
1570*5903Ssowmini 	for (p = dld_prop; p->pp_id != DLD_PROP_PRIVATE; p++) {
1571*5903Ssowmini 		if (strcmp(p->pp_name, prop_name) == 0)
1572*5903Ssowmini 			break;
1573*5903Ssowmini 	}
1574*5903Ssowmini 	return (p);
1575*5903Ssowmini }
1576*5903Ssowmini 
1577*5903Ssowmini 
1578*5903Ssowmini static dld_ioc_prop_t *
1579*5903Ssowmini dld_buf_alloc(size_t valsize, datalink_id_t linkid, const char *prop_name,
1580*5903Ssowmini     dladm_status_t *status)
1581*5903Ssowmini {
1582*5903Ssowmini 	int dsize;
1583*5903Ssowmini 	dld_ioc_prop_t *dip;
1584*5903Ssowmini 	dld_public_prop_t *p;
1585*5903Ssowmini 	char link[DLPI_LINKNAME_MAX];
1586*5903Ssowmini 	uint32_t flags;
1587*5903Ssowmini 
1588*5903Ssowmini 	*status = DLADM_STATUS_OK;
1589*5903Ssowmini 	p = dladm_name2prop(prop_name);
1590*5903Ssowmini 	if (p->pp_id != DLD_PROP_PRIVATE)
1591*5903Ssowmini 		valsize = p->pp_valsize;
1592*5903Ssowmini 
1593*5903Ssowmini 	dsize = DLD_PROPBUF_SIZE(valsize);
1594*5903Ssowmini 	dip = malloc(dsize);
1595*5903Ssowmini 	if (dip == NULL) {
1596*5903Ssowmini 		*status = DLADM_STATUS_NOMEM;
1597*5903Ssowmini 		return (NULL);
1598*5903Ssowmini 	}
1599*5903Ssowmini 	bzero(dip, dsize);
1600*5903Ssowmini 	dip->pr_valsize = valsize;
1601*5903Ssowmini 	(void) strlcpy(dip->pr_name, prop_name, DLD_LINKPROP_NAME_MAX);
1602*5903Ssowmini 	dip->pr_version = DLD_PROP_VERSION;
1603*5903Ssowmini 
1604*5903Ssowmini 	if ((*status = dladm_datalink_id2info(linkid, &flags, NULL, NULL,
1605*5903Ssowmini 	    (char *)link, DLPI_LINKNAME_MAX)) != DLADM_STATUS_OK) {
1606*5903Ssowmini 		free(dip);
1607*5903Ssowmini 		return (NULL);
1608*5903Ssowmini 	}
1609*5903Ssowmini 
1610*5903Ssowmini 	if (!(flags & DLADM_OPT_ACTIVE)) {
1611*5903Ssowmini 		free(dip);
1612*5903Ssowmini 		*status = DLADM_STATUS_TEMPONLY;
1613*5903Ssowmini 		return (NULL);
1614*5903Ssowmini 	}
1615*5903Ssowmini 	(void) strlcpy(dip->pr_linkname, link, IFNAMSIZ);
1616*5903Ssowmini 	dip->pr_num = p->pp_id;
1617*5903Ssowmini 	return (dip);
1618*5903Ssowmini }
1619*5903Ssowmini 
1620*5903Ssowmini /* ARGSUSED */
1621*5903Ssowmini static dladm_status_t
1622*5903Ssowmini dld_set_public_prop(prop_desc_t *pd, datalink_id_t linkid,
1623*5903Ssowmini     val_desc_t *vdp, uint_t val_cnt, uint_t flags)
1624*5903Ssowmini {
1625*5903Ssowmini 	dld_ioc_prop_t	*dip;
1626*5903Ssowmini 	int		fd, dsize;
1627*5903Ssowmini 	dladm_status_t	status = DLADM_STATUS_OK;
1628*5903Ssowmini 	uint8_t		u8;
1629*5903Ssowmini 	uint16_t	u16;
1630*5903Ssowmini 	uint32_t	u32;
1631*5903Ssowmini 	void		*val;
1632*5903Ssowmini 
1633*5903Ssowmini 	dip = dld_buf_alloc(0, linkid, pd->pd_name, &status);
1634*5903Ssowmini 	if (dip == NULL)
1635*5903Ssowmini 		return (status);
1636*5903Ssowmini 
1637*5903Ssowmini 	if (pd->pd_flags & PD_CHECK_ALLOC)
1638*5903Ssowmini 		val = (void *)vdp->vd_val;
1639*5903Ssowmini 	else {
1640*5903Ssowmini 		/*
1641*5903Ssowmini 		 * Currently all 1/2/4-byte size properties are byte/word/int.
1642*5903Ssowmini 		 * No need (yet) to distinguish these from arrays of same size.
1643*5903Ssowmini 		 */
1644*5903Ssowmini 		switch (dip->pr_valsize) {
1645*5903Ssowmini 		case 1:
1646*5903Ssowmini 			u8 = vdp->vd_val;
1647*5903Ssowmini 			val = &u8;
1648*5903Ssowmini 			break;
1649*5903Ssowmini 		case 2:
1650*5903Ssowmini 			u16 = vdp->vd_val;
1651*5903Ssowmini 			val = &u16;
1652*5903Ssowmini 			break;
1653*5903Ssowmini 		case 4:
1654*5903Ssowmini 			u32 = vdp->vd_val;
1655*5903Ssowmini 			val = &u32;
1656*5903Ssowmini 			break;
1657*5903Ssowmini 		default:
1658*5903Ssowmini 			val = &vdp->vd_val;
1659*5903Ssowmini 			break;
1660*5903Ssowmini 		}
1661*5903Ssowmini 	}
1662*5903Ssowmini 
1663*5903Ssowmini 	(void) memcpy(dip->pr_val, val, dip->pr_valsize);
1664*5903Ssowmini 	dsize = DLD_PROPBUF_SIZE(dip->pr_valsize);
1665*5903Ssowmini 	if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) {
1666*5903Ssowmini 		status = dladm_errno2status(errno);
1667*5903Ssowmini 		goto done;
1668*5903Ssowmini 	}
1669*5903Ssowmini 	if (i_dladm_ioctl(fd, DLDIOCSETPROP, dip, dsize) < 0)
1670*5903Ssowmini 		status = dladm_errno2status(errno);
1671*5903Ssowmini 
1672*5903Ssowmini 	(void) close(fd);
1673*5903Ssowmini done:
1674*5903Ssowmini 	return (status);
1675*5903Ssowmini }
1676*5903Ssowmini 
1677*5903Ssowmini static dladm_status_t
1678*5903Ssowmini dld_get_public_prop(dld_ioc_prop_t *dip)
1679*5903Ssowmini {
1680*5903Ssowmini 	int fd, dsize;
1681*5903Ssowmini 	dladm_status_t status = DLADM_STATUS_OK;
1682*5903Ssowmini 
1683*5903Ssowmini 	dsize = DLD_PROPBUF_SIZE(dip->pr_valsize);
1684*5903Ssowmini 
1685*5903Ssowmini 	if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) {
1686*5903Ssowmini 		status = dladm_errno2status(errno);
1687*5903Ssowmini 		goto done;
1688*5903Ssowmini 	}
1689*5903Ssowmini 	if (i_dladm_ioctl(fd, DLDIOCGETPROP, dip, dsize) < 0) {
1690*5903Ssowmini 		status = dladm_errno2status(errno);
1691*5903Ssowmini 	}
1692*5903Ssowmini done:
1693*5903Ssowmini 	return (status);
1694*5903Ssowmini }
1695*5903Ssowmini 
1696*5903Ssowmini 
1697*5903Ssowmini /* ARGSUSED */
1698*5903Ssowmini static dladm_status_t
1699*5903Ssowmini dld_defmtu_check(struct prop_desc *pd, datalink_id_t linkid, char **prop_val,
1700*5903Ssowmini     uint_t val_cnt, val_desc_t *v)
1701*5903Ssowmini {
1702*5903Ssowmini 	uint64_t mtu;
1703*5903Ssowmini 
1704*5903Ssowmini 	if (val_cnt != 1)
1705*5903Ssowmini 		return (DLADM_STATUS_BADVAL);
1706*5903Ssowmini 	mtu = atoll(prop_val[0]);
1707*5903Ssowmini 	v->vd_val = (uintptr_t)malloc(sizeof (uint64_t));
1708*5903Ssowmini 	if ((void *)v->vd_val == NULL)
1709*5903Ssowmini 		return (DLADM_STATUS_NOMEM);
1710*5903Ssowmini 	bcopy(&mtu, (void *)v->vd_val, sizeof (mtu));
1711*5903Ssowmini 	return (DLADM_STATUS_OK);
1712*5903Ssowmini }
1713*5903Ssowmini 
1714*5903Ssowmini /* ARGSUSED */
1715*5903Ssowmini static dladm_status_t
1716*5903Ssowmini dld_duplex_get(struct prop_desc *pd, datalink_id_t linkid,
1717*5903Ssowmini     char **prop_val, uint_t *val_cnt)
1718*5903Ssowmini {
1719*5903Ssowmini 	link_duplex_t   link_duplex;
1720*5903Ssowmini 	dladm_status_t  status;
1721*5903Ssowmini 
1722*5903Ssowmini 	if ((status = dladm_get_single_mac_stat(linkid, "link_duplex",
1723*5903Ssowmini 	    KSTAT_DATA_UINT32, &link_duplex)) != 0)
1724*5903Ssowmini 		return (status);
1725*5903Ssowmini 
1726*5903Ssowmini 	switch (link_duplex) {
1727*5903Ssowmini 	case LINK_DUPLEX_FULL:
1728*5903Ssowmini 		(void) strcpy(*prop_val, "full");
1729*5903Ssowmini 		break;
1730*5903Ssowmini 	case LINK_DUPLEX_HALF:
1731*5903Ssowmini 		(void) strcpy(*prop_val, "half");
1732*5903Ssowmini 		break;
1733*5903Ssowmini 	default:
1734*5903Ssowmini 		(void) strcpy(*prop_val, "unknown");
1735*5903Ssowmini 		break;
1736*5903Ssowmini 	}
1737*5903Ssowmini 	*val_cnt = 1;
1738*5903Ssowmini 	return (DLADM_STATUS_OK);
1739*5903Ssowmini }
1740*5903Ssowmini 
1741*5903Ssowmini /* ARGSUSED */
1742*5903Ssowmini static dladm_status_t
1743*5903Ssowmini dld_speed_get(struct prop_desc *pd, datalink_id_t linkid,
1744*5903Ssowmini     char **prop_val, uint_t *val_cnt)
1745*5903Ssowmini {
1746*5903Ssowmini 	uint64_t	ifspeed = 0;
1747*5903Ssowmini 	dladm_status_t status;
1748*5903Ssowmini 
1749*5903Ssowmini 	if ((status = dladm_get_single_mac_stat(linkid, "ifspeed",
1750*5903Ssowmini 	    KSTAT_DATA_UINT64, &ifspeed)) != 0)
1751*5903Ssowmini 		return (status);
1752*5903Ssowmini 
1753*5903Ssowmini 	(void) snprintf(*prop_val, DLADM_PROP_VAL_MAX,
1754*5903Ssowmini 	    "%llu", ifspeed / 1000000); /* Mbps */
1755*5903Ssowmini 	*val_cnt = 1;
1756*5903Ssowmini 	return (DLADM_STATUS_OK);
1757*5903Ssowmini }
1758*5903Ssowmini 
1759*5903Ssowmini /* ARGSUSED */
1760*5903Ssowmini static dladm_status_t
1761*5903Ssowmini dld_status_get(struct prop_desc *pd, datalink_id_t linkid,
1762*5903Ssowmini     char **prop_val, uint_t *val_cnt)
1763*5903Ssowmini {
1764*5903Ssowmini 	link_state_t   link_state;
1765*5903Ssowmini 	dladm_status_t status;
1766*5903Ssowmini 
1767*5903Ssowmini 	if ((status = dladm_get_single_mac_stat(linkid, "link_state",
1768*5903Ssowmini 	    KSTAT_DATA_UINT32, &link_state)) != 0)
1769*5903Ssowmini 		return (status);
1770*5903Ssowmini 
1771*5903Ssowmini 	switch (link_state) {
1772*5903Ssowmini 	case LINK_STATE_UP:
1773*5903Ssowmini 		(void) strcpy(*prop_val, "up");
1774*5903Ssowmini 		break;
1775*5903Ssowmini 	case LINK_STATE_DOWN:
1776*5903Ssowmini 		(void) strcpy(*prop_val, "down");
1777*5903Ssowmini 		break;
1778*5903Ssowmini 	default:
1779*5903Ssowmini 		(void) strcpy(*prop_val, "unknown");
1780*5903Ssowmini 		break;
1781*5903Ssowmini 	}
1782*5903Ssowmini 	*val_cnt = 1;
1783*5903Ssowmini 	return (DLADM_STATUS_OK);
1784*5903Ssowmini }
1785*5903Ssowmini 
1786*5903Ssowmini /* ARGSUSED */
1787*5903Ssowmini static dladm_status_t
1788*5903Ssowmini dld_binary_get(struct prop_desc *pd, datalink_id_t linkid,
1789*5903Ssowmini     char **prop_val, uint_t *val_cnt)
1790*5903Ssowmini {
1791*5903Ssowmini 	dld_ioc_prop_t *dip;
1792*5903Ssowmini 	dladm_status_t status;
1793*5903Ssowmini 
1794*5903Ssowmini 	if ((dip = dld_buf_alloc(0, linkid, pd->pd_name, &status)) == NULL)
1795*5903Ssowmini 		return (status);
1796*5903Ssowmini 	if ((status = dld_get_public_prop(dip)) != DLADM_STATUS_OK) {
1797*5903Ssowmini 		free(dip);
1798*5903Ssowmini 		return (status);
1799*5903Ssowmini 	}
1800*5903Ssowmini 	(void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "%x", dip->pr_val[0]);
1801*5903Ssowmini 	free(dip);
1802*5903Ssowmini 	*val_cnt = 1;
1803*5903Ssowmini 	return (DLADM_STATUS_OK);
1804*5903Ssowmini }
1805*5903Ssowmini 
1806*5903Ssowmini static dladm_status_t
1807*5903Ssowmini dld_uint64_get(struct prop_desc *pd, datalink_id_t linkid,
1808*5903Ssowmini     char **prop_val, uint_t *val_cnt)
1809*5903Ssowmini {
1810*5903Ssowmini 	dld_ioc_prop_t *dip;
1811*5903Ssowmini 	uint64_t v  = 0;
1812*5903Ssowmini 	uchar_t *cp;
1813*5903Ssowmini 	dladm_status_t status;
1814*5903Ssowmini 
1815*5903Ssowmini 	if ((dip = dld_buf_alloc(0, linkid, pd->pd_name, &status)) == NULL)
1816*5903Ssowmini 		return (status);
1817*5903Ssowmini 	if ((status = dld_get_public_prop(dip)) != DLADM_STATUS_OK) {
1818*5903Ssowmini 		free(dip);
1819*5903Ssowmini 		return (status);
1820*5903Ssowmini 	}
1821*5903Ssowmini 	cp = (uchar_t *)dip->pr_val;
1822*5903Ssowmini 	(void) memcpy(&v, cp, sizeof (v));
1823*5903Ssowmini 	(void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "%" PRIu64, v);
1824*5903Ssowmini 	free(dip);
1825*5903Ssowmini 	*val_cnt = 1;
1826*5903Ssowmini 	return (DLADM_STATUS_OK);
1827*5903Ssowmini }
1828*5903Ssowmini 
1829*5903Ssowmini static dladm_status_t
1830*5903Ssowmini dld_flowctl_get(struct prop_desc *pd, datalink_id_t linkid,
1831*5903Ssowmini     char **prop_val, uint_t *val_cnt)
1832*5903Ssowmini {
1833*5903Ssowmini 	dld_ioc_prop_t *dip;
1834*5903Ssowmini 	link_flowctrl_t v;
1835*5903Ssowmini 	dladm_status_t status;
1836*5903Ssowmini 	uchar_t *cp;
1837*5903Ssowmini 
1838*5903Ssowmini 	if ((dip = dld_buf_alloc(0, linkid, pd->pd_name, &status)) == NULL)
1839*5903Ssowmini 		return (status);
1840*5903Ssowmini 
1841*5903Ssowmini 	if ((status = dld_get_public_prop(dip)) != DLADM_STATUS_OK) {
1842*5903Ssowmini 		free(dip);
1843*5903Ssowmini 		return (status);
1844*5903Ssowmini 	}
1845*5903Ssowmini 	cp = (uchar_t *)dip->pr_val;
1846*5903Ssowmini 	(void) memcpy(&v, cp, sizeof (v));
1847*5903Ssowmini 	switch (v) {
1848*5903Ssowmini 	case LINK_FLOWCTRL_NONE:
1849*5903Ssowmini 		(void) sprintf(*prop_val, "no");
1850*5903Ssowmini 		break;
1851*5903Ssowmini 	case LINK_FLOWCTRL_RX:
1852*5903Ssowmini 		(void) sprintf(*prop_val, "rx");
1853*5903Ssowmini 		break;
1854*5903Ssowmini 	case LINK_FLOWCTRL_TX:
1855*5903Ssowmini 		(void) sprintf(*prop_val, "tx");
1856*5903Ssowmini 		break;
1857*5903Ssowmini 	case LINK_FLOWCTRL_BI:
1858*5903Ssowmini 		(void) sprintf(*prop_val, "bi");
1859*5903Ssowmini 		break;
1860*5903Ssowmini 	}
1861*5903Ssowmini 	free(dip);
1862*5903Ssowmini 	*val_cnt = 1;
1863*5903Ssowmini 	return (DLADM_STATUS_OK);
1864*5903Ssowmini }
1865*5903Ssowmini 
1866*5903Ssowmini 
1867*5903Ssowmini /* ARGSUSED */
1868*5903Ssowmini static dladm_status_t
1869*5903Ssowmini dld_set_prop(datalink_id_t linkid, const char *prop_name,
1870*5903Ssowmini     char **prop_val, uint_t val_cnt, uint_t flags)
1871*5903Ssowmini {
1872*5903Ssowmini 	int		fd, i, slen;
1873*5903Ssowmini 	int 		bufsize = 0, dsize;
1874*5903Ssowmini 	dld_ioc_prop_t *dip = NULL;
1875*5903Ssowmini 	uchar_t 	*dp;
1876*5903Ssowmini 	dld_public_prop_t *p;
1877*5903Ssowmini 	dladm_status_t	status;
1878*5903Ssowmini 
1879*5903Ssowmini 	if ((prop_name == NULL && prop_val != NULL) ||
1880*5903Ssowmini 	    (prop_val != NULL && val_cnt == 0))
1881*5903Ssowmini 		return (DLADM_STATUS_BADARG);
1882*5903Ssowmini 	p = dladm_name2prop(prop_name);
1883*5903Ssowmini 	if (p->pp_id != DLD_PROP_PRIVATE)
1884*5903Ssowmini 		return (DLADM_STATUS_BADARG);
1885*5903Ssowmini 
1886*5903Ssowmini 	/*
1887*5903Ssowmini 	 * private properties: all parsing is done in the kernel.
1888*5903Ssowmini 	 * allocate a enough space for each property + its separator (',').
1889*5903Ssowmini 	 */
1890*5903Ssowmini 	for (i = 0; i < val_cnt; i++) {
1891*5903Ssowmini 		bufsize += strlen(prop_val[i]) + 1;
1892*5903Ssowmini 	}
1893*5903Ssowmini 	dip = dld_buf_alloc(bufsize + 1, linkid, prop_name, &status);
1894*5903Ssowmini 	if (dip == NULL)
1895*5903Ssowmini 		return (status);
1896*5903Ssowmini 
1897*5903Ssowmini 	dp = (uchar_t *)dip->pr_val;
1898*5903Ssowmini 	dsize = sizeof (dld_ioc_prop_t) + bufsize;
1899*5903Ssowmini 	slen = 0;
1900*5903Ssowmini 	for (i = 0; i < val_cnt; i++) {
1901*5903Ssowmini 		int plen = 0;
1902*5903Ssowmini 
1903*5903Ssowmini 		plen = strlen(prop_val[i]);
1904*5903Ssowmini 		bcopy(prop_val[i], dp, plen);
1905*5903Ssowmini 		slen += plen;
1906*5903Ssowmini 		/*
1907*5903Ssowmini 		 * add a "," separator and update dp.
1908*5903Ssowmini 		 */
1909*5903Ssowmini 		if (i != (val_cnt -1))
1910*5903Ssowmini 			dp[slen++] = ',';
1911*5903Ssowmini 		dp += (plen + 1);
1912*5903Ssowmini 	}
1913*5903Ssowmini 	if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) {
1914*5903Ssowmini 		free(dip);
1915*5903Ssowmini 		return (dladm_errno2status(errno));
1916*5903Ssowmini 	}
1917*5903Ssowmini 	if ((status = i_dladm_ioctl(fd, DLDIOCSETPROP, dip, dsize)) < 0) {
1918*5903Ssowmini 		free(dip);
1919*5903Ssowmini 		return (status);
1920*5903Ssowmini 	}
1921*5903Ssowmini 	free(dip);
1922*5903Ssowmini 	(void) close(fd);
1923*5903Ssowmini 	return (DLADM_STATUS_OK);
1924*5903Ssowmini }
1925*5903Ssowmini 
1926*5903Ssowmini static dladm_status_t
1927*5903Ssowmini dld_get_prop(datalink_id_t linkid, const char *prop_name,
1928*5903Ssowmini     char **prop_val, uint_t *val_cnt, dladm_prop_type_t type)
1929*5903Ssowmini {
1930*5903Ssowmini 	int		fd;
1931*5903Ssowmini 	dladm_status_t  status = DLADM_STATUS_OK;
1932*5903Ssowmini 	uint_t 		dsize;
1933*5903Ssowmini 	dld_ioc_prop_t *dip = NULL;
1934*5903Ssowmini 	dld_public_prop_t *p;
1935*5903Ssowmini 	char tmp = '\0';
1936*5903Ssowmini 
1937*5903Ssowmini 	if ((prop_name == NULL && prop_val != NULL) ||
1938*5903Ssowmini 	    (prop_val != NULL && val_cnt == 0))
1939*5903Ssowmini 		return (DLADM_STATUS_BADARG);
1940*5903Ssowmini 
1941*5903Ssowmini 	p = dladm_name2prop(prop_name);
1942*5903Ssowmini 	if (p->pp_id != DLD_PROP_PRIVATE)
1943*5903Ssowmini 		return (DLADM_STATUS_BADARG);
1944*5903Ssowmini 
1945*5903Ssowmini 	if (type == DLADM_PROP_VAL_DEFAULT ||
1946*5903Ssowmini 	    type == DLADM_PROP_VAL_MODIFIABLE) {
1947*5903Ssowmini 		*prop_val = &tmp;
1948*5903Ssowmini 		*val_cnt = 1;
1949*5903Ssowmini 		return (DLADM_STATUS_OK);
1950*5903Ssowmini 	}
1951*5903Ssowmini 
1952*5903Ssowmini 	/*
1953*5903Ssowmini 	 * private properties: all parsing is done in the kernel.
1954*5903Ssowmini 	 */
1955*5903Ssowmini 	dip = dld_buf_alloc(1024, linkid, prop_name, &status);
1956*5903Ssowmini 	if (dip == NULL)
1957*5903Ssowmini 		return (status);
1958*5903Ssowmini 	dsize = DLD_PROPBUF_SIZE(dip->pr_valsize);
1959*5903Ssowmini 
1960*5903Ssowmini 	if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0)
1961*5903Ssowmini 		return (DLADM_STATUS_BADARG);
1962*5903Ssowmini 
1963*5903Ssowmini 	if ((status = i_dladm_ioctl(fd, DLDIOCGETPROP, dip, dsize)) < 0) {
1964*5903Ssowmini 		status = dladm_errno2status(errno);
1965*5903Ssowmini 	} else {
1966*5903Ssowmini 		(void) strncpy(*prop_val, dip->pr_val, DLADM_PROP_VAL_MAX);
1967*5903Ssowmini 		*val_cnt = 1;
1968*5903Ssowmini 	}
1969*5903Ssowmini 	return (status);
1970*5903Ssowmini }
1971