xref: /titanic_44/usr/src/lib/libdladm/common/linkprop.c (revision 13a55820e952b584554bc6b9d4e9303052a2cf29)
10ba2cbe9Sxc151355 /*
20ba2cbe9Sxc151355  * CDDL HEADER START
30ba2cbe9Sxc151355  *
40ba2cbe9Sxc151355  * The contents of this file are subject to the terms of the
50ba2cbe9Sxc151355  * Common Development and Distribution License (the "License").
60ba2cbe9Sxc151355  * You may not use this file except in compliance with the License.
70ba2cbe9Sxc151355  *
80ba2cbe9Sxc151355  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90ba2cbe9Sxc151355  * or http://www.opensolaris.org/os/licensing.
100ba2cbe9Sxc151355  * See the License for the specific language governing permissions
110ba2cbe9Sxc151355  * and limitations under the License.
120ba2cbe9Sxc151355  *
130ba2cbe9Sxc151355  * When distributing Covered Code, include this CDDL HEADER in each
140ba2cbe9Sxc151355  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150ba2cbe9Sxc151355  * If applicable, add the following below this CDDL HEADER, with the
160ba2cbe9Sxc151355  * fields enclosed by brackets "[]" replaced with your own identifying
170ba2cbe9Sxc151355  * information: Portions Copyright [yyyy] [name of copyright owner]
180ba2cbe9Sxc151355  *
190ba2cbe9Sxc151355  * CDDL HEADER END
200ba2cbe9Sxc151355  */
210ba2cbe9Sxc151355 /*
22d62bc4baSyz147064  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
230ba2cbe9Sxc151355  * Use is subject to license terms.
240ba2cbe9Sxc151355  */
250ba2cbe9Sxc151355 
260ba2cbe9Sxc151355 #pragma ident	"%Z%%M%	%I%	%E% SMI"
270ba2cbe9Sxc151355 
280ba2cbe9Sxc151355 #include <stdlib.h>
290ba2cbe9Sxc151355 #include <strings.h>
300ba2cbe9Sxc151355 #include <errno.h>
310ba2cbe9Sxc151355 #include <ctype.h>
32d62bc4baSyz147064 #include <stddef.h>
33f4b3ec61Sdh155122 #include <sys/types.h>
340ba2cbe9Sxc151355 #include <sys/stat.h>
35f4b3ec61Sdh155122 #include <sys/dld.h>
36f4b3ec61Sdh155122 #include <sys/zone.h>
37f4b3ec61Sdh155122 #include <fcntl.h>
38f4b3ec61Sdh155122 #include <unistd.h>
39f4b3ec61Sdh155122 #include <libdevinfo.h>
40f4b3ec61Sdh155122 #include <zone.h>
41f595a68aSyz147064 #include <libdllink.h>
420ba2cbe9Sxc151355 #include <libdladm_impl.h>
43d62bc4baSyz147064 #include <libdlwlan_impl.h>
44f595a68aSyz147064 #include <libdlwlan.h>
45d62bc4baSyz147064 #include <libdlvlan.h>
46f4b3ec61Sdh155122 #include <dlfcn.h>
47f4b3ec61Sdh155122 #include <link.h>
48d62bc4baSyz147064 #include <inet/wifi_ioctl.h>
49e7801d59Ssowmini #include <libdladm.h>
50e7801d59Ssowmini #include <sys/param.h>
51e7801d59Ssowmini #include <sys/dld.h>
52e7801d59Ssowmini #include <inttypes.h>
53e7801d59Ssowmini #include <sys/ethernet.h>
54f4b3ec61Sdh155122 
55d62bc4baSyz147064 /*
56d62bc4baSyz147064  * The linkprop get() callback.
57e7801d59Ssowmini  * - pd: 	pointer to the struct prop_desc
58d62bc4baSyz147064  * - propstrp:	a property string array to keep the returned property.
59d62bc4baSyz147064  *		Caller allocated.
60d62bc4baSyz147064  * - cntp:	number of returned properties.
61d62bc4baSyz147064  *		Caller also uses it to indicate how many it expects.
62d62bc4baSyz147064  */
63e7801d59Ssowmini struct prop_desc;
64e7801d59Ssowmini 
65e7801d59Ssowmini typedef dladm_status_t	pd_getf_t(struct prop_desc *pd,
666b9e797cSsowmini 			datalink_id_t, char **propstp, uint_t *cntp,
674045d941Ssowmini 			datalink_media_t, uint_t);
68f4b3ec61Sdh155122 
69d62bc4baSyz147064 /*
70d62bc4baSyz147064  * The linkprop set() callback.
71d62bc4baSyz147064  * - propval:	a val_desc_t array which keeps the property values to be set.
72d62bc4baSyz147064  * - cnt:	number of properties to be set.
73e7801d59Ssowmini  * - flags: 	additional flags passed down the system call.
74e7801d59Ssowmini  *
75e7801d59Ssowmini  * pd_set takes val_desc_t given by pd_check(), translates it into
76e7801d59Ssowmini  * a format suitable for kernel consumption. This may require allocation
77e7801d59Ssowmini  * of ioctl buffers etc. pd_set() may call another common routine (used
78e7801d59Ssowmini  * by all other pd_sets) which invokes the ioctl.
79d62bc4baSyz147064  */
80e7801d59Ssowmini typedef dladm_status_t	pd_setf_t(struct prop_desc *, datalink_id_t,
816b9e797cSsowmini 			val_desc_t *propval, uint_t cnt, uint_t flags,
826b9e797cSsowmini 			datalink_media_t);
83f4b3ec61Sdh155122 
84f4b3ec61Sdh155122 
85d62bc4baSyz147064 /*
86d62bc4baSyz147064  * The linkprop check() callback.
87d62bc4baSyz147064  * - propstrp:	property string array which keeps the property to be checked.
88d62bc4baSyz147064  * - cnt:	number of properties.
89d62bc4baSyz147064  * - propval:	return value; the property values of the given property strings.
90e7801d59Ssowmini  *
91e7801d59Ssowmini  * pd_check checks that the input values are valid. It does so by
92e7801d59Ssowmini  * iteraring through the pd_modval list for the property. If
93e7801d59Ssowmini  * the modifiable values cannot be expressed as a list, a pd_check
94e7801d59Ssowmini  * specific to this property can be used. If the input values are
95e7801d59Ssowmini  * verified to be valid, pd_check allocates a val_desc_t and fills it
96e7801d59Ssowmini  * with either a val_desc_t found on the pd_modval list or something
97e7801d59Ssowmini  * generated on the fly.
98d62bc4baSyz147064  */
99e7801d59Ssowmini typedef dladm_status_t	pd_checkf_t(struct prop_desc *pd,
100e7801d59Ssowmini 			    datalink_id_t, char **propstrp,
1016b9e797cSsowmini 			    uint_t cnt, val_desc_t *propval,
1026b9e797cSsowmini 			    datalink_media_t);
103f4b3ec61Sdh155122 
104e7801d59Ssowmini typedef struct dld_public_prop_s {
105e7801d59Ssowmini 	dld_prop_id_t	pp_id;
106e7801d59Ssowmini 	size_t		pp_valsize;
107e7801d59Ssowmini 	char		*pp_name;
108e7801d59Ssowmini 	char		*pp_desc;
109e7801d59Ssowmini } dld_public_prop_t;
110e7801d59Ssowmini 
111e7801d59Ssowmini static dld_ioc_prop_t *dld_buf_alloc(size_t, datalink_id_t, const char *,
1124045d941Ssowmini 					uint_t, dladm_status_t *);
113e7801d59Ssowmini static dladm_status_t dld_set_prop(datalink_id_t, const char *, char **,
114e7801d59Ssowmini 					uint_t, uint_t);
115e7801d59Ssowmini static dladm_status_t dld_get_prop(datalink_id_t, const char *, char **,
1164045d941Ssowmini 					uint_t *, dladm_prop_type_t, uint_t);
117d62bc4baSyz147064 static pd_getf_t	do_get_zone, do_get_autopush, do_get_rate_mod,
118d62bc4baSyz147064 			do_get_rate_prop, do_get_channel_prop,
119e7801d59Ssowmini 			do_get_powermode_prop, do_get_radio_prop,
1206b9e797cSsowmini 			dld_duplex_get, dld_status_get,
1214045d941Ssowmini 			dld_binary_get, dld_uint32_get, dld_flowctl_get;
122d62bc4baSyz147064 static pd_setf_t	do_set_zone, do_set_autopush, do_set_rate_prop,
123e7801d59Ssowmini 			do_set_powermode_prop, do_set_radio_prop,
124e7801d59Ssowmini 			dld_set_public_prop;
125e7801d59Ssowmini static pd_checkf_t	do_check_zone, do_check_autopush, do_check_rate,
126e7801d59Ssowmini 			dld_defmtu_check;
127f4b3ec61Sdh155122 
1286b9e797cSsowmini static dladm_status_t	dld_speed_get(struct prop_desc *, datalink_id_t,
1294045d941Ssowmini 			char **, uint_t *, uint_t);
1306b9e797cSsowmini 
131f4b3ec61Sdh155122 typedef struct prop_desc {
132d62bc4baSyz147064 	/*
133d62bc4baSyz147064 	 * link property name
134d62bc4baSyz147064 	 */
135f4b3ec61Sdh155122 	char			*pd_name;
136d62bc4baSyz147064 
137d62bc4baSyz147064 	/*
138d62bc4baSyz147064 	 * default property value, can be set to { "", NULL }
139d62bc4baSyz147064 	 */
140f4b3ec61Sdh155122 	val_desc_t		pd_defval;
141d62bc4baSyz147064 
142d62bc4baSyz147064 	/*
143d62bc4baSyz147064 	 * list of optional property values, can be NULL.
144d62bc4baSyz147064 	 *
145d62bc4baSyz147064 	 * This is set to non-NULL if there is a list of possible property
146d62bc4baSyz147064 	 * values.  pd_optval would point to the array of possible values.
147d62bc4baSyz147064 	 */
148d62bc4baSyz147064 	val_desc_t		*pd_optval;
149d62bc4baSyz147064 
150d62bc4baSyz147064 	/*
151d62bc4baSyz147064 	 * count of the above optional property values. 0 if pd_optval is NULL.
152d62bc4baSyz147064 	 */
153d62bc4baSyz147064 	uint_t			pd_noptval;
154d62bc4baSyz147064 
155d62bc4baSyz147064 	/*
156d62bc4baSyz147064 	 * callback to set link property;
157d62bc4baSyz147064 	 * set to NULL if this property is read-only
158d62bc4baSyz147064 	 */
159f4b3ec61Sdh155122 	pd_setf_t		*pd_set;
160d62bc4baSyz147064 
161d62bc4baSyz147064 	/*
162d62bc4baSyz147064 	 * callback to get modifiable link property
163d62bc4baSyz147064 	 */
164f4b3ec61Sdh155122 	pd_getf_t		*pd_getmod;
165d62bc4baSyz147064 
166d62bc4baSyz147064 	/*
167d62bc4baSyz147064 	 * callback to get current link property
168d62bc4baSyz147064 	 */
169f4b3ec61Sdh155122 	pd_getf_t		*pd_get;
170d62bc4baSyz147064 
171d62bc4baSyz147064 	/*
172d62bc4baSyz147064 	 * callback to validate link property value, set to NULL if pd_optval
173d62bc4baSyz147064 	 * is not NULL. In that case, validate the value by comparing it with
174d62bc4baSyz147064 	 * the pd_optval. Return a val_desc_t array pointer if the value is
175d62bc4baSyz147064 	 * valid.
176d62bc4baSyz147064 	 */
177f4b3ec61Sdh155122 	pd_checkf_t		*pd_check;
178d62bc4baSyz147064 
179d62bc4baSyz147064 	uint_t			pd_flags;
180e7801d59Ssowmini #define	PD_TEMPONLY	0x1	/* property is temporary only */
181e7801d59Ssowmini #define	PD_CHECK_ALLOC	0x2	/* alloc vd_val as part of pd_check */
1824045d941Ssowmini #define	PD_EMPTY_RESET	0x4	/* Use "" to reset the link property */
183d62bc4baSyz147064 	/*
184d62bc4baSyz147064 	 * indicate link classes this property applies to.
185d62bc4baSyz147064 	 */
186d62bc4baSyz147064 	datalink_class_t	pd_class;
187d62bc4baSyz147064 
188d62bc4baSyz147064 	/*
189d62bc4baSyz147064 	 * indicate link media type this property applies to.
190d62bc4baSyz147064 	 */
191d62bc4baSyz147064 	datalink_media_t	pd_dmedia;
192f4b3ec61Sdh155122 } prop_desc_t;
193f4b3ec61Sdh155122 
194e7801d59Ssowmini #define	DLD_PROPBUF_SIZE(v)	sizeof (dld_ioc_prop_t) + (v) - 1
195e7801d59Ssowmini 
196e7801d59Ssowmini 
197e7801d59Ssowmini static dld_public_prop_t dld_prop[] = {
1984045d941Ssowmini 	{ DLD_PROP_DUPLEX,	sizeof (link_duplex_t),
1996b9e797cSsowmini 	    "duplex",		"link duplex mode" },
200e7801d59Ssowmini 
2016b9e797cSsowmini 	{DLD_PROP_SPEED,	sizeof (uint64_t),
2026b9e797cSsowmini 	    "speed",		"link speed (bps)" },
203e7801d59Ssowmini 
2044045d941Ssowmini 	{ DLD_PROP_STATUS,	sizeof (link_state_t),
2056b9e797cSsowmini 	    "state",		"link up/down" },
206e7801d59Ssowmini 
207e7801d59Ssowmini 	{ DLD_PROP_AUTONEG,	sizeof (uint8_t),
208e7801d59Ssowmini 	    "adv_autoneg_cap",	"Advertised auto-negotiation" },
209e7801d59Ssowmini 
2104045d941Ssowmini 	{ DLD_PROP_MTU,		sizeof (uint32_t),
2116b9e797cSsowmini 	    "mtu",		"current link mtu" },
212e7801d59Ssowmini 
213e7801d59Ssowmini 	{ DLD_PROP_FLOWCTRL,	sizeof (link_flowctrl_t),
214e7801d59Ssowmini 	    "flowctrl",		"flowcontrol" },
215e7801d59Ssowmini 
216e7801d59Ssowmini 	{ DLD_PROP_ADV_1000FDX_CAP, sizeof (uint8_t),
217e7801d59Ssowmini 	    "adv_1000fdx_cap",	"Adv 1000 Mbps fdx" },
218e7801d59Ssowmini 
219e7801d59Ssowmini 	{ DLD_PROP_EN_1000FDX_CAP, sizeof (uint8_t),
220e7801d59Ssowmini 	    "en_1000fdx_cap",	"Enable 1000 Mbps fdx" },
221e7801d59Ssowmini 
222e7801d59Ssowmini 	{ DLD_PROP_ADV_1000HDX_CAP, sizeof (uint8_t),
223e7801d59Ssowmini 	    "adv_1000hdx_cap", "Adv 1000 Mbps hdx" },
224e7801d59Ssowmini 
225e7801d59Ssowmini 	{ DLD_PROP_EN_1000HDX_CAP, sizeof (uint8_t),
226e7801d59Ssowmini 	    "en_1000hdx_cap",	"Enable 1000 Mbps hdx" },
227e7801d59Ssowmini 
228e7801d59Ssowmini 	{ DLD_PROP_ADV_100FDX_CAP, sizeof (uint8_t),
229e7801d59Ssowmini 	    "adv_100fdx_cap",	"Adv 100 Mbps fdx" },
230e7801d59Ssowmini 
231e7801d59Ssowmini 	{ DLD_PROP_EN_100FDX_CAP, sizeof (uint8_t),
232e7801d59Ssowmini 	    "en_100fdx_cap",	"Enable 100 Mbps fdx" },
233e7801d59Ssowmini 
234e7801d59Ssowmini 	{ DLD_PROP_ADV_100HDX_CAP, sizeof (uint8_t),
235e7801d59Ssowmini 	    "adv_100hdx_cap",	"Adv 100 Mbps hdx" },
236e7801d59Ssowmini 
237e7801d59Ssowmini 	{ DLD_PROP_EN_100HDX_CAP, sizeof (uint8_t),
238e7801d59Ssowmini 	    "en_100hdx_cap",	"Enable 100 Mbps hdx" },
239e7801d59Ssowmini 
240e7801d59Ssowmini 	{ DLD_PROP_ADV_10FDX_CAP, sizeof (uint8_t),
241e7801d59Ssowmini 	    "adv_10fdx_cap",	"Adv 10 Mbps fdx" },
242e7801d59Ssowmini 
243e7801d59Ssowmini 	{ DLD_PROP_EN_10FDX_CAP, sizeof (uint8_t),
244e7801d59Ssowmini 	    "en_10fdx_cap",	"Enable 10 Mbps fdx" },
245e7801d59Ssowmini 
246e7801d59Ssowmini 	{ DLD_PROP_ADV_10HDX_CAP, sizeof (uint8_t),
247e7801d59Ssowmini 	    "adv_10hdx_cap",	"Adv 10 Mbps hdx" },
248e7801d59Ssowmini 
249e7801d59Ssowmini 	{ DLD_PROP_EN_10HDX_CAP, sizeof (uint8_t),
250e7801d59Ssowmini 	    "en_10hdx_cap",	"Enable 10 Mbps hdx" },
251e7801d59Ssowmini 
252e7801d59Ssowmini 	{ DLD_PROP_PRIVATE, 0,
253e7801d59Ssowmini 	    "driver-private",	"" }
254e7801d59Ssowmini };
255e7801d59Ssowmini 
256e7801d59Ssowmini static  val_desc_t	link_duplex_vals[] = {
257e7801d59Ssowmini 	{ "half", 	LINK_DUPLEX_HALF	},
258e7801d59Ssowmini 	{ "full", 	LINK_DUPLEX_HALF	}
259e7801d59Ssowmini };
260e7801d59Ssowmini static  val_desc_t	link_status_vals[] = {
261e7801d59Ssowmini 	{ "up",		LINK_STATE_UP		},
262e7801d59Ssowmini 	{ "down",	LINK_STATE_DOWN		}
263e7801d59Ssowmini };
264e7801d59Ssowmini static  val_desc_t	link_01_vals[] = {
265e7801d59Ssowmini 	{ "1",		1			},
266e7801d59Ssowmini 	{ "0",		0			}
267e7801d59Ssowmini };
268e7801d59Ssowmini static  val_desc_t	link_flow_vals[] = {
269e7801d59Ssowmini 	{ "no",		LINK_FLOWCTRL_NONE	},
270e7801d59Ssowmini 	{ "tx",		LINK_FLOWCTRL_TX	},
271e7801d59Ssowmini 	{ "rx",		LINK_FLOWCTRL_RX	},
272e7801d59Ssowmini 	{ "bi",		LINK_FLOWCTRL_BI	}
273e7801d59Ssowmini };
274e7801d59Ssowmini 
275e7801d59Ssowmini #define	VALCNT(vals)    (sizeof ((vals)) / sizeof (val_desc_t))
276e7801d59Ssowmini 
277d62bc4baSyz147064 static val_desc_t	dladm_wlan_radio_vals[] = {
278d62bc4baSyz147064 	{ "on",		DLADM_WLAN_RADIO_ON	},
279d62bc4baSyz147064 	{ "off",	DLADM_WLAN_RADIO_OFF	}
280d62bc4baSyz147064 };
281d62bc4baSyz147064 
282d62bc4baSyz147064 static val_desc_t	dladm_wlan_powermode_vals[] = {
283d62bc4baSyz147064 	{ "off",	DLADM_WLAN_PM_OFF	},
284d62bc4baSyz147064 	{ "fast",	DLADM_WLAN_PM_FAST	},
285d62bc4baSyz147064 	{ "max",	DLADM_WLAN_PM_MAX	}
286d62bc4baSyz147064 };
287d62bc4baSyz147064 
288f4b3ec61Sdh155122 static prop_desc_t	prop_table[] = {
289d62bc4baSyz147064 
290e7801d59Ssowmini 	{ "channel",	{ NULL, 0 },
291e7801d59Ssowmini 	    NULL, 0, NULL, NULL,
292d62bc4baSyz147064 	    do_get_channel_prop, NULL, 0,
293d62bc4baSyz147064 	    DATALINK_CLASS_PHYS, DL_WIFI },
294d62bc4baSyz147064 
295d62bc4baSyz147064 	{ "powermode",	{ "off", DLADM_WLAN_PM_OFF },
296d62bc4baSyz147064 	    dladm_wlan_powermode_vals, VALCNT(dladm_wlan_powermode_vals),
297d62bc4baSyz147064 	    do_set_powermode_prop, NULL,
298d62bc4baSyz147064 	    do_get_powermode_prop, NULL, 0,
299d62bc4baSyz147064 	    DATALINK_CLASS_PHYS, DL_WIFI },
300d62bc4baSyz147064 
301d62bc4baSyz147064 	{ "radio",	{ "on", DLADM_WLAN_RADIO_ON },
302d62bc4baSyz147064 	    dladm_wlan_radio_vals, VALCNT(dladm_wlan_radio_vals),
303d62bc4baSyz147064 	    do_set_radio_prop, NULL,
304d62bc4baSyz147064 	    do_get_radio_prop, NULL, 0,
305d62bc4baSyz147064 	    DATALINK_CLASS_PHYS, DL_WIFI },
306d62bc4baSyz147064 
307d62bc4baSyz147064 	{ "speed",	{ "", 0 }, NULL, 0,
308d62bc4baSyz147064 	    do_set_rate_prop, do_get_rate_mod,
309d62bc4baSyz147064 	    do_get_rate_prop, do_check_rate, 0,
3106b9e797cSsowmini 	    DATALINK_CLASS_PHYS, DATALINK_ANY_MEDIATYPE },
311d62bc4baSyz147064 
3124045d941Ssowmini 	{ "autopush",	{ "", 0 }, NULL, 0,
313d62bc4baSyz147064 	    do_set_autopush, NULL,
3144045d941Ssowmini 	    do_get_autopush, do_check_autopush, PD_CHECK_ALLOC|PD_EMPTY_RESET,
315d62bc4baSyz147064 	    DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
316d62bc4baSyz147064 
3174045d941Ssowmini 	{ "zone",	{ "", 0 }, NULL, 0,
318f4b3ec61Sdh155122 	    do_set_zone, NULL,
3194045d941Ssowmini 	    do_get_zone, do_check_zone, PD_TEMPONLY|PD_EMPTY_RESET,
320e7801d59Ssowmini 	    DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
321e7801d59Ssowmini 
3224045d941Ssowmini 	{ "duplex", { "", 0 },
323e7801d59Ssowmini 	    link_duplex_vals, VALCNT(link_duplex_vals),
324e7801d59Ssowmini 	    NULL, NULL, dld_duplex_get, NULL,
325e7801d59Ssowmini 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
326e7801d59Ssowmini 
3276b9e797cSsowmini 	{ "state", { "up", LINK_STATE_UP },
328e7801d59Ssowmini 	    link_status_vals, VALCNT(link_status_vals),
329e7801d59Ssowmini 	    NULL, NULL, dld_status_get, NULL,
3304045d941Ssowmini 	    0, DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
331e7801d59Ssowmini 
332e7801d59Ssowmini 	{ "adv_autoneg_cap", { "1", 1 },
333e7801d59Ssowmini 	    link_01_vals, VALCNT(link_01_vals),
334e7801d59Ssowmini 	    dld_set_public_prop, NULL, dld_binary_get, NULL,
335e7801d59Ssowmini 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
336e7801d59Ssowmini 
3374045d941Ssowmini 	{ "mtu", { "", 0 }, NULL, 0,
3384045d941Ssowmini 	    dld_set_public_prop, NULL, dld_uint32_get,
3394045d941Ssowmini 	    dld_defmtu_check, 0, DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
340e7801d59Ssowmini 
3414045d941Ssowmini 	{ "flowctrl", { "", 0 },
342e7801d59Ssowmini 	    link_flow_vals, VALCNT(link_flow_vals),
343e7801d59Ssowmini 	    dld_set_public_prop, NULL, dld_flowctl_get, NULL,
344e7801d59Ssowmini 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
345e7801d59Ssowmini 
3464045d941Ssowmini 	{ "adv_1000fdx_cap", { "", 0 },
3474045d941Ssowmini 	    link_01_vals, VALCNT(link_01_vals),
348e7801d59Ssowmini 	    NULL, NULL, dld_binary_get, NULL,
349e7801d59Ssowmini 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
350e7801d59Ssowmini 
3514045d941Ssowmini 	{ "en_1000fdx_cap", { "", 0 },
352e7801d59Ssowmini 	    link_01_vals, VALCNT(link_01_vals),
353e7801d59Ssowmini 	    dld_set_public_prop, NULL, dld_binary_get, NULL,
354e7801d59Ssowmini 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
355e7801d59Ssowmini 
3564045d941Ssowmini 	{ "adv_1000hdx_cap", { "", 0 },
357e7801d59Ssowmini 	    link_01_vals, VALCNT(link_01_vals),
358e7801d59Ssowmini 	    NULL, NULL, dld_binary_get, NULL,
359e7801d59Ssowmini 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
360e7801d59Ssowmini 
3614045d941Ssowmini 	{ "en_1000hdx_cap", { "", 0 },
362e7801d59Ssowmini 	    link_01_vals, VALCNT(link_01_vals),
363e7801d59Ssowmini 	    dld_set_public_prop, NULL, dld_binary_get, NULL,
364e7801d59Ssowmini 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
365e7801d59Ssowmini 
3664045d941Ssowmini 	{ "adv_100fdx_cap", { "", 0 },
367e7801d59Ssowmini 	    link_01_vals, VALCNT(link_01_vals),
368e7801d59Ssowmini 	    NULL, NULL, dld_binary_get, NULL,
369e7801d59Ssowmini 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
370e7801d59Ssowmini 
3714045d941Ssowmini 	{ "en_100fdx_cap", { "", 0 },
372e7801d59Ssowmini 	    link_01_vals, VALCNT(link_01_vals),
373e7801d59Ssowmini 	    dld_set_public_prop, NULL, dld_binary_get, NULL,
374e7801d59Ssowmini 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
375e7801d59Ssowmini 
3764045d941Ssowmini 	{ "adv_100hdx_cap", { "", 0 },
377e7801d59Ssowmini 	    link_01_vals, VALCNT(link_01_vals),
378e7801d59Ssowmini 	    NULL, NULL, dld_binary_get, NULL,
379e7801d59Ssowmini 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
380e7801d59Ssowmini 
3814045d941Ssowmini 	{ "en_100hdx_cap", { "", 0 },
382e7801d59Ssowmini 	    link_01_vals, VALCNT(link_01_vals),
383e7801d59Ssowmini 	    dld_set_public_prop, NULL, dld_binary_get, NULL,
384e7801d59Ssowmini 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
385e7801d59Ssowmini 
3864045d941Ssowmini 	{ "adv_10fdx_cap", { "", 0 },
387e7801d59Ssowmini 	    link_01_vals, VALCNT(link_01_vals),
388e7801d59Ssowmini 	    NULL, NULL, dld_binary_get, NULL,
389e7801d59Ssowmini 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
390e7801d59Ssowmini 
3914045d941Ssowmini 	{ "en_10fdx_cap", { "", 0 },
392e7801d59Ssowmini 	    link_01_vals, VALCNT(link_01_vals),
393e7801d59Ssowmini 	    dld_set_public_prop, NULL, dld_binary_get, NULL,
394e7801d59Ssowmini 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
395e7801d59Ssowmini 
3964045d941Ssowmini 	{ "adv_10hdx_cap", { "", 0 },
397e7801d59Ssowmini 	    link_01_vals, VALCNT(link_01_vals),
398e7801d59Ssowmini 	    NULL, NULL, dld_binary_get, NULL,
399e7801d59Ssowmini 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
400e7801d59Ssowmini 
4014045d941Ssowmini 	{ "en_10hdx_cap", { "", 0 },
402e7801d59Ssowmini 	    link_01_vals, VALCNT(link_01_vals),
403e7801d59Ssowmini 	    dld_set_public_prop, NULL, dld_binary_get, NULL,
404e7801d59Ssowmini 	    0, DATALINK_CLASS_PHYS, DL_ETHER }
405e7801d59Ssowmini 
406f4b3ec61Sdh155122 };
407f4b3ec61Sdh155122 
408d62bc4baSyz147064 #define	DLADM_MAX_PROPS	(sizeof (prop_table) / sizeof (prop_desc_t))
4090ba2cbe9Sxc151355 
410d62bc4baSyz147064 static dladm_status_t	i_dladm_set_linkprop_db(datalink_id_t, const char *,
411d62bc4baSyz147064 			    char **, uint_t);
412d62bc4baSyz147064 static dladm_status_t	i_dladm_get_linkprop_db(datalink_id_t, const char *,
413d62bc4baSyz147064 			    char **, uint_t *);
414d62bc4baSyz147064 static dladm_status_t	i_dladm_set_single_prop(datalink_id_t, datalink_class_t,
415d62bc4baSyz147064 			    uint32_t, prop_desc_t *, char **, uint_t, uint_t);
416d62bc4baSyz147064 static dladm_status_t	i_dladm_set_linkprop(datalink_id_t, const char *,
417d62bc4baSyz147064 			    char **, uint_t, uint_t);
4184045d941Ssowmini static dladm_status_t	i_dladm_getset_defval(prop_desc_t *, datalink_id_t,
4194045d941Ssowmini 			    datalink_media_t, uint_t);
420d62bc4baSyz147064 /*
421d62bc4baSyz147064  * Unfortunately, MAX_SCAN_SUPPORT_RATES is too small to allow all
422d62bc4baSyz147064  * rates to be retrieved. However, we cannot increase it at this
423d62bc4baSyz147064  * time because it will break binary compatibility with unbundled
424d62bc4baSyz147064  * WiFi drivers and utilities. So for now we define an additional
425d62bc4baSyz147064  * constant, MAX_SUPPORT_RATES, to allow all rates to be retrieved.
426d62bc4baSyz147064  */
427d62bc4baSyz147064 #define	MAX_SUPPORT_RATES	64
428d62bc4baSyz147064 
429d62bc4baSyz147064 #define	AP_ANCHOR	"[anchor]"
430d62bc4baSyz147064 #define	AP_DELIMITER	'.'
431d62bc4baSyz147064 
432d62bc4baSyz147064 static dladm_status_t
433d62bc4baSyz147064 do_check_prop(prop_desc_t *pdp, char **prop_val, uint_t val_cnt,
434d62bc4baSyz147064     val_desc_t *vdp)
4350ba2cbe9Sxc151355 {
436d62bc4baSyz147064 	int		i, j;
4370ba2cbe9Sxc151355 	dladm_status_t	status = DLADM_STATUS_OK;
4380ba2cbe9Sxc151355 
439d62bc4baSyz147064 	for (j = 0; j < val_cnt; j++) {
440d62bc4baSyz147064 		for (i = 0; i < pdp->pd_noptval; i++) {
441d62bc4baSyz147064 			if (strcasecmp(*prop_val,
442d62bc4baSyz147064 			    pdp->pd_optval[i].vd_name) == 0) {
4430ba2cbe9Sxc151355 				break;
4440ba2cbe9Sxc151355 			}
4450ba2cbe9Sxc151355 		}
446d62bc4baSyz147064 		if (i == pdp->pd_noptval) {
447d62bc4baSyz147064 			status = DLADM_STATUS_BADVAL;
448d62bc4baSyz147064 			goto done;
449d62bc4baSyz147064 		}
450d62bc4baSyz147064 		(void) memcpy(vdp + j, &pdp->pd_optval[i], sizeof (val_desc_t));
4510ba2cbe9Sxc151355 	}
4520ba2cbe9Sxc151355 
453d62bc4baSyz147064 done:
454d62bc4baSyz147064 	return (status);
4550ba2cbe9Sxc151355 }
4560ba2cbe9Sxc151355 
4570ba2cbe9Sxc151355 static dladm_status_t
458d62bc4baSyz147064 i_dladm_set_single_prop(datalink_id_t linkid, datalink_class_t class,
459d62bc4baSyz147064     uint32_t media, prop_desc_t *pdp, char **prop_val, uint_t val_cnt,
460d62bc4baSyz147064     uint_t flags)
4610ba2cbe9Sxc151355 {
4620ba2cbe9Sxc151355 	dladm_status_t	status = DLADM_STATUS_OK;
463d62bc4baSyz147064 	val_desc_t	*vdp = NULL;
464d62bc4baSyz147064 	boolean_t	needfree = B_FALSE;
465d62bc4baSyz147064 	uint_t		cnt, i;
4660ba2cbe9Sxc151355 
467d62bc4baSyz147064 	if (!(pdp->pd_class & class))
468d62bc4baSyz147064 		return (DLADM_STATUS_BADARG);
4690ba2cbe9Sxc151355 
470d62bc4baSyz147064 	if (!DATALINK_MEDIA_ACCEPTED(pdp->pd_dmedia, media))
471d62bc4baSyz147064 		return (DLADM_STATUS_BADARG);
472d62bc4baSyz147064 
473d62bc4baSyz147064 	if ((flags & DLADM_OPT_PERSIST) && (pdp->pd_flags & PD_TEMPONLY))
474d62bc4baSyz147064 		return (DLADM_STATUS_TEMPONLY);
475d62bc4baSyz147064 
476d62bc4baSyz147064 	if (!(flags & DLADM_OPT_ACTIVE))
477d62bc4baSyz147064 		return (DLADM_STATUS_OK);
478d62bc4baSyz147064 
479d62bc4baSyz147064 	if (pdp->pd_set == NULL)
480d62bc4baSyz147064 		return (DLADM_STATUS_PROPRDONLY);
481d62bc4baSyz147064 
482e7801d59Ssowmini 	if (pdp->pd_flags & PD_CHECK_ALLOC)
483e7801d59Ssowmini 		needfree = B_TRUE;
484e7801d59Ssowmini 	else
485e7801d59Ssowmini 		needfree = B_FALSE;
486d62bc4baSyz147064 	if (prop_val != NULL) {
487d62bc4baSyz147064 		vdp = malloc(sizeof (val_desc_t) * val_cnt);
488d62bc4baSyz147064 		if (vdp == NULL)
489d62bc4baSyz147064 			return (DLADM_STATUS_NOMEM);
490d62bc4baSyz147064 
491e7801d59Ssowmini 
492d62bc4baSyz147064 		if (pdp->pd_check != NULL) {
493e7801d59Ssowmini 			status = pdp->pd_check(pdp, linkid, prop_val, val_cnt,
4946b9e797cSsowmini 			    vdp, media);
495d62bc4baSyz147064 		} else if (pdp->pd_optval != NULL) {
496d62bc4baSyz147064 			status = do_check_prop(pdp, prop_val, val_cnt, vdp);
497d62bc4baSyz147064 		} else {
498d62bc4baSyz147064 			status = DLADM_STATUS_BADARG;
4990ba2cbe9Sxc151355 		}
5000ba2cbe9Sxc151355 
501d62bc4baSyz147064 		if (status != DLADM_STATUS_OK)
502d62bc4baSyz147064 			goto done;
503d62bc4baSyz147064 
504d62bc4baSyz147064 		cnt = val_cnt;
505d62bc4baSyz147064 	} else {
506d62bc4baSyz147064 		if (pdp->pd_defval.vd_name == NULL)
507d62bc4baSyz147064 			return (DLADM_STATUS_NOTSUP);
508d62bc4baSyz147064 
5094045d941Ssowmini 		if ((pdp->pd_flags & PD_EMPTY_RESET) != 0 ||
5104045d941Ssowmini 		    strlen(pdp->pd_defval.vd_name) > 0) {
511d62bc4baSyz147064 			if ((vdp = malloc(sizeof (val_desc_t))) == NULL)
512d62bc4baSyz147064 				return (DLADM_STATUS_NOMEM);
5134045d941Ssowmini 			(void) memcpy(vdp, &pdp->pd_defval,
5144045d941Ssowmini 			    sizeof (val_desc_t));
5154045d941Ssowmini 		} else {
5164045d941Ssowmini 			status = i_dladm_getset_defval(pdp, linkid,
5174045d941Ssowmini 			    media, flags);
5184045d941Ssowmini 			return (status);
5194045d941Ssowmini 		}
520d62bc4baSyz147064 		cnt = 1;
521d62bc4baSyz147064 	}
5226b9e797cSsowmini 	status = pdp->pd_set(pdp, linkid, vdp, cnt, flags, media);
523d62bc4baSyz147064 	if (needfree) {
524d62bc4baSyz147064 		for (i = 0; i < cnt; i++)
525e7801d59Ssowmini 			free((void *)((val_desc_t *)vdp + i)->vd_val);
526d62bc4baSyz147064 	}
527d62bc4baSyz147064 done:
528d62bc4baSyz147064 	free(vdp);
529d62bc4baSyz147064 	return (status);
530d62bc4baSyz147064 }
531d62bc4baSyz147064 
532d62bc4baSyz147064 static dladm_status_t
533d62bc4baSyz147064 i_dladm_set_linkprop(datalink_id_t linkid, const char *prop_name,
534d62bc4baSyz147064     char **prop_val, uint_t val_cnt, uint_t flags)
535d62bc4baSyz147064 {
536d62bc4baSyz147064 	int			i;
537d62bc4baSyz147064 	boolean_t		found = B_FALSE;
538d62bc4baSyz147064 	datalink_class_t	class;
539d62bc4baSyz147064 	uint32_t		media;
540d62bc4baSyz147064 	dladm_status_t		status = DLADM_STATUS_OK;
541d62bc4baSyz147064 
542d62bc4baSyz147064 	status = dladm_datalink_id2info(linkid, NULL, &class, &media, NULL, 0);
543d62bc4baSyz147064 	if (status != DLADM_STATUS_OK)
5440ba2cbe9Sxc151355 		return (status);
5450ba2cbe9Sxc151355 
546d62bc4baSyz147064 	for (i = 0; i < DLADM_MAX_PROPS; i++) {
547d62bc4baSyz147064 		prop_desc_t	*pdp = &prop_table[i];
548d62bc4baSyz147064 		dladm_status_t	s;
5490ba2cbe9Sxc151355 
550d62bc4baSyz147064 		if (prop_name != NULL &&
551d62bc4baSyz147064 		    (strcasecmp(prop_name, pdp->pd_name) != 0))
552d62bc4baSyz147064 			continue;
553d62bc4baSyz147064 
554d62bc4baSyz147064 		found = B_TRUE;
555d62bc4baSyz147064 		s = i_dladm_set_single_prop(linkid, class, media, pdp, prop_val,
556d62bc4baSyz147064 		    val_cnt, flags);
557d62bc4baSyz147064 
558d62bc4baSyz147064 		if (prop_name != NULL) {
559d62bc4baSyz147064 			status = s;
560d62bc4baSyz147064 			break;
561d62bc4baSyz147064 		} else {
562d62bc4baSyz147064 			if (s != DLADM_STATUS_OK &&
563d62bc4baSyz147064 			    s != DLADM_STATUS_NOTSUP)
564d62bc4baSyz147064 				status = s;
565d62bc4baSyz147064 		}
566d62bc4baSyz147064 	}
567e7801d59Ssowmini 	if (!found) {
568e7801d59Ssowmini 		if (prop_name[0] == '_') {
569e7801d59Ssowmini 			/* other private properties */
570e7801d59Ssowmini 			status = dld_set_prop(linkid, prop_name, prop_val,
571e7801d59Ssowmini 			    val_cnt, flags);
572e7801d59Ssowmini 		} else  {
5730ba2cbe9Sxc151355 			status = DLADM_STATUS_NOTFOUND;
574e7801d59Ssowmini 		}
575e7801d59Ssowmini 	}
5760ba2cbe9Sxc151355 
5770ba2cbe9Sxc151355 	return (status);
5780ba2cbe9Sxc151355 }
5790ba2cbe9Sxc151355 
580d62bc4baSyz147064 /*
581d62bc4baSyz147064  * Set/reset link property for specific link
582d62bc4baSyz147064  */
583d62bc4baSyz147064 dladm_status_t
584d62bc4baSyz147064 dladm_set_linkprop(datalink_id_t linkid, const char *prop_name, char **prop_val,
585d62bc4baSyz147064     uint_t val_cnt, uint_t flags)
5860ba2cbe9Sxc151355 {
587d62bc4baSyz147064 	dladm_status_t	status = DLADM_STATUS_OK;
5880ba2cbe9Sxc151355 
589d62bc4baSyz147064 	if ((linkid == DATALINK_INVALID_LINKID) || (flags == 0) ||
590d62bc4baSyz147064 	    (prop_val == NULL && val_cnt > 0) ||
591d62bc4baSyz147064 	    (prop_val != NULL && val_cnt == 0) ||
592d62bc4baSyz147064 	    (prop_name == NULL && prop_val != NULL)) {
593d62bc4baSyz147064 		return (DLADM_STATUS_BADARG);
5940ba2cbe9Sxc151355 	}
5950ba2cbe9Sxc151355 
596d62bc4baSyz147064 	status = i_dladm_set_linkprop(linkid, prop_name, prop_val,
597d62bc4baSyz147064 	    val_cnt, flags);
598d62bc4baSyz147064 	if (status != DLADM_STATUS_OK)
599d62bc4baSyz147064 		return (status);
600d62bc4baSyz147064 
601d62bc4baSyz147064 	if (flags & DLADM_OPT_PERSIST) {
602d62bc4baSyz147064 		status = i_dladm_set_linkprop_db(linkid, prop_name,
603d62bc4baSyz147064 		    prop_val, val_cnt);
604d62bc4baSyz147064 	}
605d62bc4baSyz147064 	return (status);
606d62bc4baSyz147064 }
607d62bc4baSyz147064 
608d62bc4baSyz147064 /*
609d62bc4baSyz147064  * Walk link properties of the given specific link.
610d62bc4baSyz147064  */
611d62bc4baSyz147064 dladm_status_t
612d62bc4baSyz147064 dladm_walk_linkprop(datalink_id_t linkid, void *arg,
613d62bc4baSyz147064     int (*func)(datalink_id_t, const char *, void *))
6140ba2cbe9Sxc151355 {
615d62bc4baSyz147064 	dladm_status_t		status;
616d62bc4baSyz147064 	datalink_class_t	class;
617d62bc4baSyz147064 	uint_t			media;
618d62bc4baSyz147064 	int			i;
6190ba2cbe9Sxc151355 
620d62bc4baSyz147064 	if (linkid == DATALINK_INVALID_LINKID || func == NULL)
621d62bc4baSyz147064 		return (DLADM_STATUS_BADARG);
6220ba2cbe9Sxc151355 
623d62bc4baSyz147064 	status = dladm_datalink_id2info(linkid, NULL, &class, &media, NULL, 0);
624d62bc4baSyz147064 	if (status != DLADM_STATUS_OK)
625d62bc4baSyz147064 		return (status);
626d62bc4baSyz147064 
627d62bc4baSyz147064 	for (i = 0; i < DLADM_MAX_PROPS; i++) {
628d62bc4baSyz147064 		if (!(prop_table[i].pd_class & class))
629d62bc4baSyz147064 			continue;
630d62bc4baSyz147064 
631d62bc4baSyz147064 		if (!DATALINK_MEDIA_ACCEPTED(prop_table[i].pd_dmedia, media))
632d62bc4baSyz147064 			continue;
633d62bc4baSyz147064 
634d62bc4baSyz147064 		if (func(linkid, prop_table[i].pd_name, arg) ==
635d62bc4baSyz147064 		    DLADM_WALK_TERMINATE) {
636d62bc4baSyz147064 			break;
637d62bc4baSyz147064 		}
638d62bc4baSyz147064 	}
639d62bc4baSyz147064 
640d62bc4baSyz147064 	return (DLADM_STATUS_OK);
641d62bc4baSyz147064 }
642d62bc4baSyz147064 
643d62bc4baSyz147064 /*
644d62bc4baSyz147064  * Get linkprop of the given specific link.
645d62bc4baSyz147064  */
646d62bc4baSyz147064 dladm_status_t
647d62bc4baSyz147064 dladm_get_linkprop(datalink_id_t linkid, dladm_prop_type_t type,
648d62bc4baSyz147064     const char *prop_name, char **prop_val, uint_t *val_cntp)
649d62bc4baSyz147064 {
650d62bc4baSyz147064 	dladm_status_t		status = DLADM_STATUS_OK;
651d62bc4baSyz147064 	datalink_class_t	class;
652d62bc4baSyz147064 	uint_t			media;
653d62bc4baSyz147064 	prop_desc_t		*pdp;
6544045d941Ssowmini 	uint_t			cnt, dld_flags = 0;
655d62bc4baSyz147064 	int			i;
656d62bc4baSyz147064 
6574045d941Ssowmini 	if (type == DLADM_PROP_VAL_DEFAULT)
6584045d941Ssowmini 		dld_flags = DLD_DEFAULT;
6594045d941Ssowmini 
660d62bc4baSyz147064 	if (linkid == DATALINK_INVALID_LINKID || prop_name == NULL ||
661d62bc4baSyz147064 	    prop_val == NULL || val_cntp == NULL || *val_cntp == 0)
662d62bc4baSyz147064 		return (DLADM_STATUS_BADARG);
663d62bc4baSyz147064 
664d62bc4baSyz147064 	for (i = 0; i < DLADM_MAX_PROPS; i++)
665d62bc4baSyz147064 		if (strcasecmp(prop_name, prop_table[i].pd_name) == 0)
666d62bc4baSyz147064 			break;
667d62bc4baSyz147064 
668e7801d59Ssowmini 	if (i == DLADM_MAX_PROPS) {
669e7801d59Ssowmini 		if (prop_name[0] == '_') {
670e7801d59Ssowmini 			/*
671e7801d59Ssowmini 			 * private property.
672e7801d59Ssowmini 			 */
673e7801d59Ssowmini 			return (dld_get_prop(linkid, prop_name,
6744045d941Ssowmini 			    prop_val, val_cntp, type, dld_flags));
675e7801d59Ssowmini 		} else {
676d62bc4baSyz147064 			return (DLADM_STATUS_NOTFOUND);
677e7801d59Ssowmini 		}
678e7801d59Ssowmini 	}
679d62bc4baSyz147064 
680d62bc4baSyz147064 	pdp = &prop_table[i];
681d62bc4baSyz147064 
682d62bc4baSyz147064 	status = dladm_datalink_id2info(linkid, NULL, &class, &media, NULL, 0);
683d62bc4baSyz147064 	if (status != DLADM_STATUS_OK)
684d62bc4baSyz147064 		return (status);
685d62bc4baSyz147064 
686d62bc4baSyz147064 	if (!(pdp->pd_class & class))
687d62bc4baSyz147064 		return (DLADM_STATUS_BADARG);
688d62bc4baSyz147064 
689d62bc4baSyz147064 	if (!DATALINK_MEDIA_ACCEPTED(pdp->pd_dmedia, media))
690d62bc4baSyz147064 		return (DLADM_STATUS_BADARG);
691d62bc4baSyz147064 
692d62bc4baSyz147064 	switch (type) {
693d62bc4baSyz147064 	case DLADM_PROP_VAL_CURRENT:
6944045d941Ssowmini 		status = pdp->pd_get(pdp, linkid, prop_val, val_cntp, media,
6954045d941Ssowmini 		    dld_flags);
696d62bc4baSyz147064 		break;
697d62bc4baSyz147064 
698d62bc4baSyz147064 	case DLADM_PROP_VAL_DEFAULT:
699*13a55820Sar224390 		/*
700*13a55820Sar224390 		 * If defaults are not defined for the property,
701*13a55820Sar224390 		 * pd_defval.vd_name should be null. If the driver
702*13a55820Sar224390 		 * has to be contacted for the value, vd_name should
703*13a55820Sar224390 		 * be the empty string (""). Otherwise, dladm will
704*13a55820Sar224390 		 * just print whatever is in the table.
705*13a55820Sar224390 		 */
706d62bc4baSyz147064 		if (pdp->pd_defval.vd_name == NULL) {
707d62bc4baSyz147064 			status = DLADM_STATUS_NOTSUP;
708d62bc4baSyz147064 			break;
709d62bc4baSyz147064 		}
7104045d941Ssowmini 
7114045d941Ssowmini 		if (strlen(pdp->pd_defval.vd_name) == 0) {
7124045d941Ssowmini 			status = pdp->pd_get(pdp, linkid, prop_val, val_cntp,
7134045d941Ssowmini 			    media, dld_flags);
7144045d941Ssowmini 		} else {
715d62bc4baSyz147064 			(void) strcpy(*prop_val, pdp->pd_defval.vd_name);
7164045d941Ssowmini 		}
717d62bc4baSyz147064 		*val_cntp = 1;
718d62bc4baSyz147064 		break;
719d62bc4baSyz147064 
720d62bc4baSyz147064 	case DLADM_PROP_VAL_MODIFIABLE:
721d62bc4baSyz147064 		if (pdp->pd_getmod != NULL) {
722e7801d59Ssowmini 			status = pdp->pd_getmod(pdp, linkid, prop_val,
7234045d941Ssowmini 			    val_cntp, media, dld_flags);
724d62bc4baSyz147064 			break;
725d62bc4baSyz147064 		}
726d62bc4baSyz147064 		cnt = pdp->pd_noptval;
727d62bc4baSyz147064 		if (cnt == 0) {
728d62bc4baSyz147064 			status = DLADM_STATUS_NOTSUP;
729d62bc4baSyz147064 		} else if (cnt > *val_cntp) {
730d62bc4baSyz147064 			status = DLADM_STATUS_TOOSMALL;
731d62bc4baSyz147064 		} else {
732d62bc4baSyz147064 			for (i = 0; i < cnt; i++) {
733d62bc4baSyz147064 				(void) strcpy(prop_val[i],
734d62bc4baSyz147064 				    pdp->pd_optval[i].vd_name);
735d62bc4baSyz147064 			}
736d62bc4baSyz147064 			*val_cntp = cnt;
737d62bc4baSyz147064 		}
738d62bc4baSyz147064 		break;
739d62bc4baSyz147064 	case DLADM_PROP_VAL_PERSISTENT:
740d62bc4baSyz147064 		if (pdp->pd_flags & PD_TEMPONLY)
741d62bc4baSyz147064 			return (DLADM_STATUS_TEMPONLY);
742d62bc4baSyz147064 		status = i_dladm_get_linkprop_db(linkid, prop_name,
743d62bc4baSyz147064 		    prop_val, val_cntp);
744d62bc4baSyz147064 		break;
745d62bc4baSyz147064 	default:
746d62bc4baSyz147064 		status = DLADM_STATUS_BADARG;
747d62bc4baSyz147064 		break;
748d62bc4baSyz147064 	}
749d62bc4baSyz147064 
750d62bc4baSyz147064 	return (status);
751d62bc4baSyz147064 }
752d62bc4baSyz147064 
753d62bc4baSyz147064 /*ARGSUSED*/
754d62bc4baSyz147064 static int
755d62bc4baSyz147064 i_dladm_init_one_prop(datalink_id_t linkid, const char *prop_name, void *arg)
756d62bc4baSyz147064 {
757d62bc4baSyz147064 	char	*buf, **propvals;
758d62bc4baSyz147064 	uint_t	i, valcnt = DLADM_MAX_PROP_VALCNT;
759d62bc4baSyz147064 
760d62bc4baSyz147064 	if ((buf = malloc((sizeof (char *) + DLADM_PROP_VAL_MAX) *
761d62bc4baSyz147064 	    DLADM_MAX_PROP_VALCNT)) == NULL) {
762d62bc4baSyz147064 		return (DLADM_WALK_CONTINUE);
763d62bc4baSyz147064 	}
764d62bc4baSyz147064 
765d62bc4baSyz147064 	propvals = (char **)(void *)buf;
766d62bc4baSyz147064 	for (i = 0; i < valcnt; i++) {
767d62bc4baSyz147064 		propvals[i] = buf +
768d62bc4baSyz147064 		    sizeof (char *) * DLADM_MAX_PROP_VALCNT +
769d62bc4baSyz147064 		    i * DLADM_PROP_VAL_MAX;
770d62bc4baSyz147064 	}
771d62bc4baSyz147064 
772d62bc4baSyz147064 	if (dladm_get_linkprop(linkid, DLADM_PROP_VAL_PERSISTENT, prop_name,
773d62bc4baSyz147064 	    propvals, &valcnt) != DLADM_STATUS_OK) {
774d62bc4baSyz147064 		goto done;
775d62bc4baSyz147064 	}
776d62bc4baSyz147064 
777d62bc4baSyz147064 	(void) dladm_set_linkprop(linkid, prop_name, propvals, valcnt,
778d62bc4baSyz147064 	    DLADM_OPT_ACTIVE);
779d62bc4baSyz147064 
780d62bc4baSyz147064 done:
781d62bc4baSyz147064 	if (buf != NULL)
782d62bc4baSyz147064 		free(buf);
783d62bc4baSyz147064 
784d62bc4baSyz147064 	return (DLADM_WALK_CONTINUE);
785d62bc4baSyz147064 }
786d62bc4baSyz147064 
787d62bc4baSyz147064 /*ARGSUSED*/
788d62bc4baSyz147064 static int
789d62bc4baSyz147064 i_dladm_init_linkprop(datalink_id_t linkid, void *arg)
790d62bc4baSyz147064 {
791d62bc4baSyz147064 	(void) dladm_init_linkprop(linkid);
792d62bc4baSyz147064 	return (DLADM_WALK_CONTINUE);
7930ba2cbe9Sxc151355 }
7940ba2cbe9Sxc151355 
7950ba2cbe9Sxc151355 dladm_status_t
796d62bc4baSyz147064 dladm_init_linkprop(datalink_id_t linkid)
7970ba2cbe9Sxc151355 {
798d62bc4baSyz147064 	if (linkid == DATALINK_ALL_LINKID) {
799d62bc4baSyz147064 		(void) dladm_walk_datalink_id(i_dladm_init_linkprop, NULL,
800d62bc4baSyz147064 		    DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE,
801d62bc4baSyz147064 		    DLADM_OPT_PERSIST);
802d62bc4baSyz147064 	} else {
803d62bc4baSyz147064 		(void) dladm_walk_linkprop(linkid, NULL, i_dladm_init_one_prop);
804d62bc4baSyz147064 	}
805d62bc4baSyz147064 	return (DLADM_STATUS_OK);
8060ba2cbe9Sxc151355 }
807f4b3ec61Sdh155122 
808e7801d59Ssowmini /* ARGSUSED */
809f4b3ec61Sdh155122 static dladm_status_t
810e7801d59Ssowmini do_get_zone(struct prop_desc *pd, datalink_id_t linkid,
8114045d941Ssowmini     char **prop_val, uint_t *val_cnt, datalink_media_t media, uint_t flags)
812f4b3ec61Sdh155122 {
813d62bc4baSyz147064 	char		zone_name[ZONENAME_MAX];
814d62bc4baSyz147064 	zoneid_t	zid;
815d62bc4baSyz147064 	dladm_status_t	status;
816f4b3ec61Sdh155122 
8174045d941Ssowmini 	if (flags != 0)
8184045d941Ssowmini 		return (DLADM_STATUS_NOTSUP);
8194045d941Ssowmini 
820d62bc4baSyz147064 	status = dladm_getzid(linkid, &zid);
821d62bc4baSyz147064 	if (status != DLADM_STATUS_OK)
822d62bc4baSyz147064 		return (status);
823d62bc4baSyz147064 
824d62bc4baSyz147064 	*val_cnt = 1;
825d62bc4baSyz147064 	if (zid != GLOBAL_ZONEID) {
826d62bc4baSyz147064 		if (getzonenamebyid(zid, zone_name, sizeof (zone_name)) < 0)
827f4b3ec61Sdh155122 			return (dladm_errno2status(errno));
828f4b3ec61Sdh155122 
829d62bc4baSyz147064 		(void) strncpy(*prop_val, zone_name, DLADM_PROP_VAL_MAX);
83047a01978Sbw 	} else {
831d62bc4baSyz147064 		*prop_val[0] = '\0';
83247a01978Sbw 	}
833f4b3ec61Sdh155122 
834f4b3ec61Sdh155122 	return (DLADM_STATUS_OK);
835f4b3ec61Sdh155122 }
836f4b3ec61Sdh155122 
837f4b3ec61Sdh155122 typedef int (*zone_get_devroot_t)(char *, char *, size_t);
838f4b3ec61Sdh155122 
839f4b3ec61Sdh155122 static int
840f4b3ec61Sdh155122 i_dladm_get_zone_dev(char *zone_name, char *dev, size_t devlen)
841f4b3ec61Sdh155122 {
842f4b3ec61Sdh155122 	char			root[MAXPATHLEN];
843f4b3ec61Sdh155122 	zone_get_devroot_t	real_zone_get_devroot;
844f4b3ec61Sdh155122 	void			*dlhandle;
845f4b3ec61Sdh155122 	void			*sym;
846f4b3ec61Sdh155122 	int			ret;
847f4b3ec61Sdh155122 
848f4b3ec61Sdh155122 	if ((dlhandle = dlopen("libzonecfg.so.1", RTLD_LAZY)) == NULL)
849f4b3ec61Sdh155122 		return (-1);
850f4b3ec61Sdh155122 
851f4b3ec61Sdh155122 	if ((sym = dlsym(dlhandle, "zone_get_devroot")) == NULL) {
852f4b3ec61Sdh155122 		(void) dlclose(dlhandle);
853f4b3ec61Sdh155122 		return (-1);
854f4b3ec61Sdh155122 	}
855f4b3ec61Sdh155122 
856f4b3ec61Sdh155122 	real_zone_get_devroot = (zone_get_devroot_t)sym;
857f4b3ec61Sdh155122 
858f4b3ec61Sdh155122 	if ((ret = real_zone_get_devroot(zone_name, root, sizeof (root))) == 0)
859f4b3ec61Sdh155122 		(void) snprintf(dev, devlen, "%s%s", root, "/dev");
860f4b3ec61Sdh155122 	(void) dlclose(dlhandle);
861f4b3ec61Sdh155122 	return (ret);
862f4b3ec61Sdh155122 }
863f4b3ec61Sdh155122 
864f4b3ec61Sdh155122 static dladm_status_t
865d62bc4baSyz147064 i_dladm_update_deventry(zoneid_t zid, datalink_id_t linkid, boolean_t add)
866f4b3ec61Sdh155122 {
867f4b3ec61Sdh155122 	char		path[MAXPATHLEN];
868d62bc4baSyz147064 	char		name[MAXLINKNAMELEN];
869f4b3ec61Sdh155122 	di_prof_t	prof = NULL;
870f4b3ec61Sdh155122 	char		zone_name[ZONENAME_MAX];
871f4b3ec61Sdh155122 	dladm_status_t	status;
872d62bc4baSyz147064 	int		ret;
873f4b3ec61Sdh155122 
874f4b3ec61Sdh155122 	if (getzonenamebyid(zid, zone_name, sizeof (zone_name)) < 0)
875f4b3ec61Sdh155122 		return (dladm_errno2status(errno));
876f4b3ec61Sdh155122 	if (i_dladm_get_zone_dev(zone_name, path, sizeof (path)) != 0)
877f4b3ec61Sdh155122 		return (dladm_errno2status(errno));
878f4b3ec61Sdh155122 	if (di_prof_init(path, &prof) != 0)
879f4b3ec61Sdh155122 		return (dladm_errno2status(errno));
880f4b3ec61Sdh155122 
881d62bc4baSyz147064 	status = dladm_linkid2legacyname(linkid, name, MAXLINKNAMELEN);
882f4b3ec61Sdh155122 	if (status != DLADM_STATUS_OK)
883d62bc4baSyz147064 		goto cleanup;
884f4b3ec61Sdh155122 
885d62bc4baSyz147064 	if (add)
886d62bc4baSyz147064 		ret = di_prof_add_dev(prof, name);
887d62bc4baSyz147064 	else
888d62bc4baSyz147064 		ret = di_prof_add_exclude(prof, name);
889f4b3ec61Sdh155122 
890d62bc4baSyz147064 	if (ret != 0) {
891d62bc4baSyz147064 		status = dladm_errno2status(errno);
892d62bc4baSyz147064 		goto cleanup;
893f4b3ec61Sdh155122 	}
894f4b3ec61Sdh155122 
895d62bc4baSyz147064 	if (di_prof_commit(prof) != 0)
896d62bc4baSyz147064 		status = dladm_errno2status(errno);
897d62bc4baSyz147064 cleanup:
898d62bc4baSyz147064 	if (prof)
899d62bc4baSyz147064 		di_prof_fini(prof);
900d62bc4baSyz147064 
901d62bc4baSyz147064 	return (status);
902f4b3ec61Sdh155122 }
903f4b3ec61Sdh155122 
904e7801d59Ssowmini /* ARGSUSED */
905f4b3ec61Sdh155122 static dladm_status_t
9066b9e797cSsowmini do_set_zone(prop_desc_t *pd, datalink_id_t linkid, val_desc_t *vdp,
9076b9e797cSsowmini     uint_t val_cnt, uint_t flags, datalink_media_t media)
908f4b3ec61Sdh155122 {
909f4b3ec61Sdh155122 	dladm_status_t	status;
910f4b3ec61Sdh155122 	zoneid_t	zid_old, zid_new;
911d62bc4baSyz147064 	char		link[MAXLINKNAMELEN];
912f4b3ec61Sdh155122 
913f4b3ec61Sdh155122 	if (val_cnt != 1)
914f4b3ec61Sdh155122 		return (DLADM_STATUS_BADVALCNT);
915f4b3ec61Sdh155122 
916d62bc4baSyz147064 	status = dladm_getzid(linkid, &zid_old);
917f4b3ec61Sdh155122 	if (status != DLADM_STATUS_OK)
918f4b3ec61Sdh155122 		return (status);
919f4b3ec61Sdh155122 
920f4b3ec61Sdh155122 	/* Do nothing if setting to current value */
921d62bc4baSyz147064 	zid_new = vdp->vd_val;
922f4b3ec61Sdh155122 	if (zid_new == zid_old)
923f4b3ec61Sdh155122 		return (DLADM_STATUS_OK);
924f4b3ec61Sdh155122 
925d62bc4baSyz147064 	if ((status = dladm_datalink_id2info(linkid, NULL, NULL, NULL,
926d62bc4baSyz147064 	    link, MAXLINKNAMELEN)) != DLADM_STATUS_OK) {
927d62bc4baSyz147064 		return (status);
928d62bc4baSyz147064 	}
929f4b3ec61Sdh155122 
930d62bc4baSyz147064 	if (zid_new != GLOBAL_ZONEID) {
931d62bc4baSyz147064 		/*
932d62bc4baSyz147064 		 * If the new zoneid is the global zone, we could destroy
933d62bc4baSyz147064 		 * the link (in the case of an implicitly-created VLAN) as a
934d62bc4baSyz147064 		 * result of the dladm_setzid() operation. In that case,
935d62bc4baSyz147064 		 * we defer the operation to the end of this function to avoid
936d62bc4baSyz147064 		 * recreating the VLAN and getting a different linkid during
937d62bc4baSyz147064 		 * the rollback if other operation fails.
938d62bc4baSyz147064 		 *
939d62bc4baSyz147064 		 * Otherwise, dladm_setzid() will hold a reference to the
940d62bc4baSyz147064 		 * link and prevent a link renaming, so we need to do it
941d62bc4baSyz147064 		 * before other operations.
942d62bc4baSyz147064 		 */
943d62bc4baSyz147064 		status = dladm_setzid(link, zid_new);
944d62bc4baSyz147064 		if (status != DLADM_STATUS_OK)
945d62bc4baSyz147064 			return (status);
946d62bc4baSyz147064 	}
947d62bc4baSyz147064 
948d62bc4baSyz147064 	if (zid_old != GLOBAL_ZONEID) {
949d62bc4baSyz147064 		if (zone_remove_datalink(zid_old, link) != 0 &&
950f4b3ec61Sdh155122 		    errno != ENXIO) {
951f4b3ec61Sdh155122 			status = dladm_errno2status(errno);
952f4b3ec61Sdh155122 			goto rollback1;
953f4b3ec61Sdh155122 		}
954f4b3ec61Sdh155122 
955d62bc4baSyz147064 		/*
956d62bc4baSyz147064 		 * It is okay to fail to update the /dev entry (some
957d62bc4baSyz147064 		 * vanity-named links do not have a /dev entry).
958d62bc4baSyz147064 		 */
959d62bc4baSyz147064 		(void) i_dladm_update_deventry(zid_old, linkid, B_FALSE);
960d62bc4baSyz147064 	}
961d62bc4baSyz147064 
962d62bc4baSyz147064 	if (zid_new != GLOBAL_ZONEID) {
963d62bc4baSyz147064 		if (zone_add_datalink(zid_new, link) != 0) {
964d62bc4baSyz147064 			status = dladm_errno2status(errno);
965d62bc4baSyz147064 			goto rollback2;
966d62bc4baSyz147064 		}
967d62bc4baSyz147064 
968d62bc4baSyz147064 		(void) i_dladm_update_deventry(zid_new, linkid, B_TRUE);
969d62bc4baSyz147064 	} else {
970d62bc4baSyz147064 		status = dladm_setzid(link, zid_new);
971f4b3ec61Sdh155122 		if (status != DLADM_STATUS_OK)
972f4b3ec61Sdh155122 			goto rollback2;
973f4b3ec61Sdh155122 	}
974f4b3ec61Sdh155122 
975f4b3ec61Sdh155122 	return (DLADM_STATUS_OK);
976f4b3ec61Sdh155122 
977f4b3ec61Sdh155122 rollback2:
978f4b3ec61Sdh155122 	if (zid_old != GLOBAL_ZONEID)
979d62bc4baSyz147064 		(void) i_dladm_update_deventry(zid_old, linkid, B_TRUE);
980d62bc4baSyz147064 	if (zid_old != GLOBAL_ZONEID)
981d62bc4baSyz147064 		(void) zone_add_datalink(zid_old, link);
982f4b3ec61Sdh155122 rollback1:
983d62bc4baSyz147064 	if (zid_new != GLOBAL_ZONEID)
984d62bc4baSyz147064 		(void) dladm_setzid(link, zid_old);
985f4b3ec61Sdh155122 	return (status);
986f4b3ec61Sdh155122 }
987f4b3ec61Sdh155122 
988f4b3ec61Sdh155122 /* ARGSUSED */
989f4b3ec61Sdh155122 static dladm_status_t
990e7801d59Ssowmini do_check_zone(struct prop_desc *pd, datalink_id_t linkid, char **prop_val,
9916b9e797cSsowmini     uint_t val_cnt, val_desc_t *vdp, datalink_media_t media)
992f4b3ec61Sdh155122 {
993f4b3ec61Sdh155122 	zoneid_t	zid;
994f4b3ec61Sdh155122 
995f4b3ec61Sdh155122 	if (val_cnt != 1)
996f4b3ec61Sdh155122 		return (DLADM_STATUS_BADVALCNT);
997f4b3ec61Sdh155122 
998f4b3ec61Sdh155122 	if ((zid = getzoneidbyname(*prop_val)) == -1)
999f4b3ec61Sdh155122 		return (DLADM_STATUS_BADVAL);
1000f4b3ec61Sdh155122 
1001f4b3ec61Sdh155122 	if (zid != GLOBAL_ZONEID) {
1002f4b3ec61Sdh155122 		ushort_t	flags;
1003f4b3ec61Sdh155122 
1004f4b3ec61Sdh155122 		if (zone_getattr(zid, ZONE_ATTR_FLAGS, &flags,
1005f4b3ec61Sdh155122 		    sizeof (flags)) < 0) {
1006f4b3ec61Sdh155122 			return (dladm_errno2status(errno));
1007f4b3ec61Sdh155122 		}
1008f4b3ec61Sdh155122 
1009f4b3ec61Sdh155122 		if (!(flags & ZF_NET_EXCL)) {
1010f4b3ec61Sdh155122 			return (DLADM_STATUS_BADVAL);
1011f4b3ec61Sdh155122 		}
1012f4b3ec61Sdh155122 	}
1013f4b3ec61Sdh155122 
1014d62bc4baSyz147064 	vdp->vd_val = zid;
1015f4b3ec61Sdh155122 	return (DLADM_STATUS_OK);
1016f4b3ec61Sdh155122 }
1017f4b3ec61Sdh155122 
1018e7801d59Ssowmini /* ARGSUSED */
1019f4b3ec61Sdh155122 static dladm_status_t
1020e7801d59Ssowmini do_get_autopush(struct prop_desc *pd, datalink_id_t linkid,
10214045d941Ssowmini     char **prop_val, uint_t *val_cnt, datalink_media_t media, uint_t flags)
1022d62bc4baSyz147064 {
1023d62bc4baSyz147064 	dld_ioc_ap_t	dia;
1024d62bc4baSyz147064 	int		fd, i, len;
1025d62bc4baSyz147064 
10264045d941Ssowmini 	if (flags & DLD_DEFAULT)
10274045d941Ssowmini 		return (DLADM_STATUS_NOTSUP);
10284045d941Ssowmini 
1029d62bc4baSyz147064 	if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0)
1030d62bc4baSyz147064 		return (dladm_errno2status(errno));
1031d62bc4baSyz147064 
1032d62bc4baSyz147064 	*val_cnt = 1;
1033d62bc4baSyz147064 	dia.dia_linkid = linkid;
1034d62bc4baSyz147064 	if (i_dladm_ioctl(fd, DLDIOC_GETAUTOPUSH, &dia, sizeof (dia)) < 0) {
1035d62bc4baSyz147064 		(*prop_val)[0] = '\0';
1036d62bc4baSyz147064 		goto done;
1037d62bc4baSyz147064 	}
1038d62bc4baSyz147064 
1039d62bc4baSyz147064 	for (i = 0, len = 0; i < dia.dia_npush; i++) {
1040d62bc4baSyz147064 		if (i != 0) {
1041d62bc4baSyz147064 			(void) snprintf(*prop_val + len,
1042d62bc4baSyz147064 			    DLADM_PROP_VAL_MAX - len, "%c", AP_DELIMITER);
1043d62bc4baSyz147064 			len += 1;
1044d62bc4baSyz147064 		}
1045d62bc4baSyz147064 		(void) snprintf(*prop_val + len, DLADM_PROP_VAL_MAX - len,
1046d62bc4baSyz147064 		    "%s", dia.dia_aplist[i]);
1047d62bc4baSyz147064 		len += strlen(dia.dia_aplist[i]);
1048d62bc4baSyz147064 		if (dia.dia_anchor - 1 == i) {
1049d62bc4baSyz147064 			(void) snprintf(*prop_val + len,
1050d62bc4baSyz147064 			    DLADM_PROP_VAL_MAX - len, "%c%s", AP_DELIMITER,
1051d62bc4baSyz147064 			    AP_ANCHOR);
1052d62bc4baSyz147064 			len += (strlen(AP_ANCHOR) + 1);
1053d62bc4baSyz147064 		}
1054d62bc4baSyz147064 	}
1055d62bc4baSyz147064 
1056d62bc4baSyz147064 done:
1057d62bc4baSyz147064 	(void) close(fd);
1058d62bc4baSyz147064 	return (DLADM_STATUS_OK);
1059d62bc4baSyz147064 }
1060d62bc4baSyz147064 
1061e7801d59Ssowmini /* ARGSUSED */
1062d62bc4baSyz147064 static dladm_status_t
10636b9e797cSsowmini do_set_autopush(prop_desc_t *pd, datalink_id_t linkid, val_desc_t *vdp,
10646b9e797cSsowmini     uint_t val_cnt, uint_t flags, datalink_media_t media)
1065d62bc4baSyz147064 {
1066d62bc4baSyz147064 	dld_ioc_ap_t		dia;
1067d62bc4baSyz147064 	struct dlautopush	*dlap = (struct dlautopush *)vdp->vd_val;
1068d62bc4baSyz147064 	dladm_status_t		status = DLADM_STATUS_OK;
1069d62bc4baSyz147064 	int			fd, i;
1070d62bc4baSyz147064 	int			ic_cmd;
1071d62bc4baSyz147064 
1072d62bc4baSyz147064 	if (val_cnt != 1)
1073d62bc4baSyz147064 		return (DLADM_STATUS_BADVALCNT);
1074d62bc4baSyz147064 
1075d62bc4baSyz147064 	if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0)
1076d62bc4baSyz147064 		return (dladm_errno2status(errno));
1077d62bc4baSyz147064 
1078d62bc4baSyz147064 	dia.dia_linkid = linkid;
1079d62bc4baSyz147064 	if (dlap != NULL) {
1080d62bc4baSyz147064 		dia.dia_anchor = dlap->dap_anchor;
1081d62bc4baSyz147064 		dia.dia_npush = dlap->dap_npush;
1082d62bc4baSyz147064 		for (i = 0; i < dia.dia_npush; i++) {
1083d62bc4baSyz147064 			(void) strlcpy(dia.dia_aplist[i], dlap->dap_aplist[i],
1084d62bc4baSyz147064 			    FMNAMESZ+1);
1085d62bc4baSyz147064 		}
1086d62bc4baSyz147064 		ic_cmd = DLDIOC_SETAUTOPUSH;
1087d62bc4baSyz147064 	} else {
1088d62bc4baSyz147064 		ic_cmd = DLDIOC_CLRAUTOPUSH;
1089d62bc4baSyz147064 	}
1090d62bc4baSyz147064 
1091d62bc4baSyz147064 	if (i_dladm_ioctl(fd, ic_cmd, &dia, sizeof (dia)) < 0)
1092d62bc4baSyz147064 		status = dladm_errno2status(errno);
1093d62bc4baSyz147064 
1094d62bc4baSyz147064 	(void) close(fd);
1095d62bc4baSyz147064 	return (status);
1096d62bc4baSyz147064 }
1097d62bc4baSyz147064 
1098d62bc4baSyz147064 /*
1099d62bc4baSyz147064  * Add the specified module to the dlautopush structure; returns a
1100d62bc4baSyz147064  * DLADM_STATUS_* code.
1101d62bc4baSyz147064  */
1102d62bc4baSyz147064 dladm_status_t
1103d62bc4baSyz147064 i_dladm_add_ap_module(const char *module, struct dlautopush *dlap)
1104d62bc4baSyz147064 {
1105d62bc4baSyz147064 	if ((strlen(module) == 0) || (strlen(module) > FMNAMESZ))
1106d62bc4baSyz147064 		return (DLADM_STATUS_BADVAL);
1107d62bc4baSyz147064 
1108d62bc4baSyz147064 	if (strncasecmp(module, AP_ANCHOR, strlen(AP_ANCHOR)) == 0) {
1109d62bc4baSyz147064 		/*
1110d62bc4baSyz147064 		 * We don't allow multiple anchors, and the anchor must
1111d62bc4baSyz147064 		 * be after at least one module.
1112d62bc4baSyz147064 		 */
1113d62bc4baSyz147064 		if (dlap->dap_anchor != 0)
1114d62bc4baSyz147064 			return (DLADM_STATUS_BADVAL);
1115d62bc4baSyz147064 		if (dlap->dap_npush == 0)
1116d62bc4baSyz147064 			return (DLADM_STATUS_BADVAL);
1117d62bc4baSyz147064 
1118d62bc4baSyz147064 		dlap->dap_anchor = dlap->dap_npush;
1119d62bc4baSyz147064 		return (DLADM_STATUS_OK);
1120d62bc4baSyz147064 	}
1121d62bc4baSyz147064 	if (dlap->dap_npush > MAXAPUSH)
1122d62bc4baSyz147064 		return (DLADM_STATUS_BADVALCNT);
1123d62bc4baSyz147064 
1124d62bc4baSyz147064 	(void) strlcpy(dlap->dap_aplist[dlap->dap_npush++], module,
1125d62bc4baSyz147064 	    FMNAMESZ + 1);
1126d62bc4baSyz147064 
1127d62bc4baSyz147064 	return (DLADM_STATUS_OK);
1128d62bc4baSyz147064 }
1129d62bc4baSyz147064 
1130d62bc4baSyz147064 /*
1131d62bc4baSyz147064  * Currently, both '.' and ' '(space) can be used as the delimiters between
1132d62bc4baSyz147064  * autopush modules. The former is used in dladm set-linkprop, and the
1133d62bc4baSyz147064  * latter is used in the autopush(1M) file.
1134d62bc4baSyz147064  */
1135d62bc4baSyz147064 /* ARGSUSED */
1136d62bc4baSyz147064 static dladm_status_t
1137e7801d59Ssowmini do_check_autopush(struct prop_desc *pd, datalink_id_t linkid, char **prop_val,
11386b9e797cSsowmini     uint_t val_cnt, val_desc_t *vdp, datalink_media_t media)
1139d62bc4baSyz147064 {
1140d62bc4baSyz147064 	char			*module;
1141d62bc4baSyz147064 	struct dlautopush	*dlap;
1142d62bc4baSyz147064 	dladm_status_t		status;
1143d62bc4baSyz147064 	char			val[DLADM_PROP_VAL_MAX];
1144d62bc4baSyz147064 	char			delimiters[4];
1145d62bc4baSyz147064 
1146d62bc4baSyz147064 	if (val_cnt != 1)
1147d62bc4baSyz147064 		return (DLADM_STATUS_BADVALCNT);
1148d62bc4baSyz147064 
1149d62bc4baSyz147064 	dlap = malloc(sizeof (struct dlautopush));
1150d62bc4baSyz147064 	if (dlap == NULL)
1151d62bc4baSyz147064 		return (DLADM_STATUS_NOMEM);
1152d62bc4baSyz147064 
1153d62bc4baSyz147064 	(void) memset(dlap, 0, sizeof (struct dlautopush));
1154d62bc4baSyz147064 	(void) snprintf(delimiters, 4, " %c\n", AP_DELIMITER);
1155d62bc4baSyz147064 	bcopy(*prop_val, val, DLADM_PROP_VAL_MAX);
1156d62bc4baSyz147064 	module = strtok(val, delimiters);
1157d62bc4baSyz147064 	while (module != NULL) {
1158d62bc4baSyz147064 		status = i_dladm_add_ap_module(module, dlap);
1159d62bc4baSyz147064 		if (status != DLADM_STATUS_OK)
1160d62bc4baSyz147064 			return (status);
1161d62bc4baSyz147064 		module = strtok(NULL, delimiters);
1162d62bc4baSyz147064 	}
1163d62bc4baSyz147064 
1164d62bc4baSyz147064 	vdp->vd_val = (uintptr_t)dlap;
1165d62bc4baSyz147064 	return (DLADM_STATUS_OK);
1166d62bc4baSyz147064 }
1167d62bc4baSyz147064 
1168e7801d59Ssowmini /* ARGSUSED */
1169d62bc4baSyz147064 static dladm_status_t
1170e7801d59Ssowmini do_get_rate_common(struct prop_desc *pd, datalink_id_t linkid,
1171e7801d59Ssowmini     char **prop_val, uint_t *val_cnt, uint_t id)
1172d62bc4baSyz147064 {
1173d62bc4baSyz147064 	wl_rates_t	*wrp;
1174d62bc4baSyz147064 	uint_t		i;
1175d62bc4baSyz147064 	wldp_t		*gbuf = NULL;
1176d62bc4baSyz147064 	dladm_status_t	status = DLADM_STATUS_OK;
1177d62bc4baSyz147064 
1178d62bc4baSyz147064 	if ((gbuf = malloc(MAX_BUF_LEN)) == NULL) {
1179d62bc4baSyz147064 		status = DLADM_STATUS_NOMEM;
1180d62bc4baSyz147064 		goto done;
1181d62bc4baSyz147064 	}
1182d62bc4baSyz147064 
1183d62bc4baSyz147064 	status = i_dladm_wlan_get_ioctl(linkid, gbuf, id);
1184d62bc4baSyz147064 	if (status != DLADM_STATUS_OK)
1185d62bc4baSyz147064 		goto done;
1186d62bc4baSyz147064 
1187d62bc4baSyz147064 	wrp = (wl_rates_t *)gbuf->wldp_buf;
1188d62bc4baSyz147064 	if (wrp->wl_rates_num > *val_cnt) {
1189d62bc4baSyz147064 		status = DLADM_STATUS_TOOSMALL;
1190d62bc4baSyz147064 		goto done;
1191d62bc4baSyz147064 	}
1192d62bc4baSyz147064 
1193d62bc4baSyz147064 	if (wrp->wl_rates_rates[0] == 0) {
1194d62bc4baSyz147064 		prop_val[0][0] = '\0';
1195d62bc4baSyz147064 		*val_cnt = 1;
1196d62bc4baSyz147064 		goto done;
1197d62bc4baSyz147064 	}
1198d62bc4baSyz147064 
1199d62bc4baSyz147064 	for (i = 0; i < wrp->wl_rates_num; i++) {
1200d62bc4baSyz147064 		(void) snprintf(prop_val[i], DLADM_STRSIZE, "%.*f",
1201d62bc4baSyz147064 		    wrp->wl_rates_rates[i] % 2,
1202d62bc4baSyz147064 		    (float)wrp->wl_rates_rates[i] / 2);
1203d62bc4baSyz147064 	}
1204d62bc4baSyz147064 	*val_cnt = wrp->wl_rates_num;
1205d62bc4baSyz147064 
1206d62bc4baSyz147064 done:
1207d62bc4baSyz147064 	free(gbuf);
1208d62bc4baSyz147064 	return (status);
1209d62bc4baSyz147064 }
1210d62bc4baSyz147064 
1211d62bc4baSyz147064 static dladm_status_t
1212e7801d59Ssowmini do_get_rate_prop(struct prop_desc *pd, datalink_id_t linkid,
12134045d941Ssowmini     char **prop_val, uint_t *val_cnt, datalink_media_t media, uint_t flags)
1214d62bc4baSyz147064 {
12156b9e797cSsowmini 	if (media != DL_WIFI)
12164045d941Ssowmini 		return (dld_speed_get(pd, linkid, prop_val, val_cnt, flags));
12176b9e797cSsowmini 
1218e7801d59Ssowmini 	return (do_get_rate_common(pd, linkid, prop_val, val_cnt,
1219d62bc4baSyz147064 	    WL_DESIRED_RATES));
1220d62bc4baSyz147064 }
1221d62bc4baSyz147064 
12224045d941Ssowmini /* ARGSUSED */
1223d62bc4baSyz147064 static dladm_status_t
1224e7801d59Ssowmini do_get_rate_mod(struct prop_desc *pd, datalink_id_t linkid,
12254045d941Ssowmini     char **prop_val, uint_t *val_cnt, datalink_media_t media, uint_t flags)
1226d62bc4baSyz147064 {
12276b9e797cSsowmini 	switch (media) {
12286b9e797cSsowmini 	case DL_ETHER:
12294045d941Ssowmini 		/*
12304045d941Ssowmini 		 * Speed for ethernet links is unbounded. E.g., 802.11b
12314045d941Ssowmini 		 * links can have a speed of 5.5 Gbps.
12324045d941Ssowmini 		 */
12334045d941Ssowmini 		return (DLADM_STATUS_NOTSUP);
12346b9e797cSsowmini 
12356b9e797cSsowmini 	case DL_WIFI:
1236e7801d59Ssowmini 		return (do_get_rate_common(pd, linkid, prop_val, val_cnt,
1237d62bc4baSyz147064 		    WL_SUPPORTED_RATES));
12386b9e797cSsowmini 	default:
12396b9e797cSsowmini 		return (DLADM_STATUS_BADARG);
12406b9e797cSsowmini 	}
1241d62bc4baSyz147064 }
1242d62bc4baSyz147064 
1243d62bc4baSyz147064 static dladm_status_t
1244d62bc4baSyz147064 do_set_rate(datalink_id_t linkid, dladm_wlan_rates_t *rates)
1245f4b3ec61Sdh155122 {
1246f4b3ec61Sdh155122 	int		i;
1247d62bc4baSyz147064 	uint_t		len;
1248d62bc4baSyz147064 	wldp_t		*gbuf;
1249d62bc4baSyz147064 	wl_rates_t	*wrp;
1250d62bc4baSyz147064 	dladm_status_t	status = DLADM_STATUS_OK;
1251d62bc4baSyz147064 
1252d62bc4baSyz147064 	if ((gbuf = malloc(MAX_BUF_LEN)) == NULL)
1253d62bc4baSyz147064 		return (DLADM_STATUS_NOMEM);
1254d62bc4baSyz147064 
1255d62bc4baSyz147064 	(void) memset(gbuf, 0, MAX_BUF_LEN);
1256d62bc4baSyz147064 
1257d62bc4baSyz147064 	wrp = (wl_rates_t *)gbuf->wldp_buf;
1258d62bc4baSyz147064 	for (i = 0; i < rates->wr_cnt; i++)
1259d62bc4baSyz147064 		wrp->wl_rates_rates[i] = rates->wr_rates[i];
1260d62bc4baSyz147064 	wrp->wl_rates_num = rates->wr_cnt;
1261d62bc4baSyz147064 
1262d62bc4baSyz147064 	len = offsetof(wl_rates_t, wl_rates_rates) +
1263d62bc4baSyz147064 	    (rates->wr_cnt * sizeof (char)) + WIFI_BUF_OFFSET;
1264d62bc4baSyz147064 	status = i_dladm_wlan_ioctl(linkid, gbuf, WL_DESIRED_RATES, len,
1265d62bc4baSyz147064 	    WLAN_SET_PARAM, len);
1266d62bc4baSyz147064 
1267d62bc4baSyz147064 	free(gbuf);
1268d62bc4baSyz147064 	return (status);
1269d62bc4baSyz147064 }
1270d62bc4baSyz147064 
1271e7801d59Ssowmini /* ARGSUSED */
1272d62bc4baSyz147064 static dladm_status_t
1273e7801d59Ssowmini do_set_rate_prop(prop_desc_t *pd, datalink_id_t linkid,
12746b9e797cSsowmini     val_desc_t *vdp, uint_t val_cnt, uint_t flags, datalink_media_t media)
1275d62bc4baSyz147064 {
1276d62bc4baSyz147064 	dladm_wlan_rates_t	rates;
1277f4b3ec61Sdh155122 	dladm_status_t		status;
1278f4b3ec61Sdh155122 
12796b9e797cSsowmini 	/*
12806b9e797cSsowmini 	 * can currently set rate on WIFI links only.
12816b9e797cSsowmini 	 */
12826b9e797cSsowmini 	if (media != DL_WIFI)
12836b9e797cSsowmini 		return (DLADM_STATUS_PROPRDONLY);
12846b9e797cSsowmini 
1285d62bc4baSyz147064 	if (val_cnt != 1)
1286d62bc4baSyz147064 		return (DLADM_STATUS_BADVALCNT);
1287f4b3ec61Sdh155122 
1288d62bc4baSyz147064 	rates.wr_cnt = 1;
1289d62bc4baSyz147064 	rates.wr_rates[0] = vdp[0].vd_val;
1290f4b3ec61Sdh155122 
1291d62bc4baSyz147064 	status = do_set_rate(linkid, &rates);
1292f4b3ec61Sdh155122 
1293d62bc4baSyz147064 done:
1294d62bc4baSyz147064 	return (status);
1295d62bc4baSyz147064 }
1296d62bc4baSyz147064 
1297d62bc4baSyz147064 /* ARGSUSED */
1298d62bc4baSyz147064 static dladm_status_t
1299e7801d59Ssowmini do_check_rate(struct prop_desc *pd, datalink_id_t linkid, char **prop_val,
13006b9e797cSsowmini     uint_t val_cnt, val_desc_t *vdp, datalink_media_t media)
1301d62bc4baSyz147064 {
1302d62bc4baSyz147064 	int		i;
1303d62bc4baSyz147064 	uint_t		modval_cnt = MAX_SUPPORT_RATES;
1304d62bc4baSyz147064 	char		*buf, **modval;
1305d62bc4baSyz147064 	dladm_status_t	status;
1306d62bc4baSyz147064 
1307d62bc4baSyz147064 	if (val_cnt != 1)
1308d62bc4baSyz147064 		return (DLADM_STATUS_BADVALCNT);
1309d62bc4baSyz147064 
1310d62bc4baSyz147064 	buf = malloc((sizeof (char *) + DLADM_STRSIZE) *
1311d62bc4baSyz147064 	    MAX_SUPPORT_RATES);
1312d62bc4baSyz147064 	if (buf == NULL) {
1313d62bc4baSyz147064 		status = DLADM_STATUS_NOMEM;
1314d62bc4baSyz147064 		goto done;
1315d62bc4baSyz147064 	}
1316d62bc4baSyz147064 
1317d62bc4baSyz147064 	modval = (char **)(void *)buf;
1318d62bc4baSyz147064 	for (i = 0; i < MAX_SUPPORT_RATES; i++) {
1319d62bc4baSyz147064 		modval[i] = buf + sizeof (char *) * MAX_SUPPORT_RATES +
1320d62bc4baSyz147064 		    i * DLADM_STRSIZE;
1321d62bc4baSyz147064 	}
1322d62bc4baSyz147064 
13234045d941Ssowmini 	status = do_get_rate_mod(NULL, linkid, modval, &modval_cnt, media, 0);
1324d62bc4baSyz147064 	if (status != DLADM_STATUS_OK)
1325d62bc4baSyz147064 		goto done;
1326d62bc4baSyz147064 
1327d62bc4baSyz147064 	for (i = 0; i < modval_cnt; i++) {
1328d62bc4baSyz147064 		if (strcasecmp(*prop_val, modval[i]) == 0) {
1329e7801d59Ssowmini 			vdp->vd_val = (uintptr_t)(uint_t)
1330e7801d59Ssowmini 			    (atof(*prop_val) * 2);
1331f4b3ec61Sdh155122 			status = DLADM_STATUS_OK;
1332f4b3ec61Sdh155122 			break;
1333f4b3ec61Sdh155122 		}
1334d62bc4baSyz147064 	}
1335d62bc4baSyz147064 	if (i == modval_cnt)
1336d62bc4baSyz147064 		status = DLADM_STATUS_BADVAL;
1337d62bc4baSyz147064 done:
1338d62bc4baSyz147064 	free(buf);
1339d62bc4baSyz147064 	return (status);
1340d62bc4baSyz147064 }
1341f4b3ec61Sdh155122 
1342d62bc4baSyz147064 static dladm_status_t
1343d62bc4baSyz147064 do_get_phyconf(datalink_id_t linkid, wldp_t *gbuf)
1344d62bc4baSyz147064 {
1345d62bc4baSyz147064 	return (i_dladm_wlan_get_ioctl(linkid, gbuf, WL_PHY_CONFIG));
1346d62bc4baSyz147064 }
1347d62bc4baSyz147064 
1348e7801d59Ssowmini /* ARGSUSED */
1349d62bc4baSyz147064 static dladm_status_t
1350e7801d59Ssowmini do_get_channel_prop(struct prop_desc *pd, datalink_id_t linkid,
13514045d941Ssowmini     char **prop_val, uint_t *val_cnt, datalink_media_t media, uint_t flags)
1352d62bc4baSyz147064 {
1353d62bc4baSyz147064 	uint32_t	channel;
1354d62bc4baSyz147064 	wldp_t		*gbuf;
1355d62bc4baSyz147064 	dladm_status_t	status = DLADM_STATUS_OK;
1356d62bc4baSyz147064 
1357d62bc4baSyz147064 	if ((gbuf = malloc(MAX_BUF_LEN)) == NULL)
1358d62bc4baSyz147064 		return (DLADM_STATUS_NOMEM);
1359d62bc4baSyz147064 
1360d62bc4baSyz147064 	if ((status = do_get_phyconf(linkid, gbuf)) != DLADM_STATUS_OK)
1361d62bc4baSyz147064 		goto done;
1362d62bc4baSyz147064 
1363d62bc4baSyz147064 	if (!i_dladm_wlan_convert_chan((wl_phy_conf_t *)gbuf->wldp_buf,
1364d62bc4baSyz147064 	    &channel)) {
1365d62bc4baSyz147064 		status = DLADM_STATUS_NOTFOUND;
1366d62bc4baSyz147064 		goto done;
1367d62bc4baSyz147064 	}
1368d62bc4baSyz147064 
1369d62bc4baSyz147064 	(void) snprintf(*prop_val, DLADM_STRSIZE, "%u", channel);
1370d62bc4baSyz147064 	*val_cnt = 1;
1371d62bc4baSyz147064 
1372d62bc4baSyz147064 done:
1373d62bc4baSyz147064 	free(gbuf);
1374d62bc4baSyz147064 	return (status);
1375d62bc4baSyz147064 }
1376d62bc4baSyz147064 
1377d62bc4baSyz147064 static dladm_status_t
1378d62bc4baSyz147064 do_get_powermode(datalink_id_t linkid, wldp_t *gbuf)
1379d62bc4baSyz147064 {
1380d62bc4baSyz147064 	return (i_dladm_wlan_get_ioctl(linkid, gbuf, WL_POWER_MODE));
1381d62bc4baSyz147064 }
1382d62bc4baSyz147064 
1383e7801d59Ssowmini /* ARGSUSED */
1384d62bc4baSyz147064 static dladm_status_t
1385e7801d59Ssowmini do_get_powermode_prop(struct prop_desc *pd, datalink_id_t linkid,
13864045d941Ssowmini     char **prop_val, uint_t *val_cnt, datalink_media_t media, uint_t flags)
1387d62bc4baSyz147064 {
1388d62bc4baSyz147064 	wl_ps_mode_t	*mode;
1389d62bc4baSyz147064 	const char	*s;
1390d62bc4baSyz147064 	wldp_t		*gbuf;
1391d62bc4baSyz147064 	dladm_status_t	status = DLADM_STATUS_OK;
1392d62bc4baSyz147064 
1393d62bc4baSyz147064 	if ((gbuf = malloc(MAX_BUF_LEN)) == NULL)
1394d62bc4baSyz147064 		return (DLADM_STATUS_NOMEM);
1395d62bc4baSyz147064 
1396d62bc4baSyz147064 	if ((status = do_get_powermode(linkid, gbuf)) != DLADM_STATUS_OK)
1397d62bc4baSyz147064 		goto done;
1398d62bc4baSyz147064 
1399d62bc4baSyz147064 	mode = (wl_ps_mode_t *)(gbuf->wldp_buf);
1400d62bc4baSyz147064 	switch (mode->wl_ps_mode) {
1401d62bc4baSyz147064 	case WL_PM_AM:
1402d62bc4baSyz147064 		s = "off";
1403f4b3ec61Sdh155122 		break;
1404d62bc4baSyz147064 	case WL_PM_MPS:
1405d62bc4baSyz147064 		s = "max";
1406d62bc4baSyz147064 		break;
1407d62bc4baSyz147064 	case WL_PM_FAST:
1408d62bc4baSyz147064 		s = "fast";
1409f4b3ec61Sdh155122 		break;
1410f4b3ec61Sdh155122 	default:
1411d62bc4baSyz147064 		status = DLADM_STATUS_NOTFOUND;
1412d62bc4baSyz147064 		goto done;
1413f4b3ec61Sdh155122 	}
1414d62bc4baSyz147064 	(void) snprintf(*prop_val, DLADM_STRSIZE, "%s", s);
1415d62bc4baSyz147064 	*val_cnt = 1;
1416d62bc4baSyz147064 
1417d62bc4baSyz147064 done:
1418d62bc4baSyz147064 	free(gbuf);
1419d62bc4baSyz147064 	return (status);
1420d62bc4baSyz147064 }
1421d62bc4baSyz147064 
1422d62bc4baSyz147064 static dladm_status_t
1423d62bc4baSyz147064 do_set_powermode(datalink_id_t linkid, dladm_wlan_powermode_t *pm)
1424d62bc4baSyz147064 {
1425d62bc4baSyz147064 	wl_ps_mode_t    ps_mode;
1426d62bc4baSyz147064 
1427d62bc4baSyz147064 	(void) memset(&ps_mode, 0xff, sizeof (ps_mode));
1428d62bc4baSyz147064 
1429d62bc4baSyz147064 	switch (*pm) {
1430d62bc4baSyz147064 	case DLADM_WLAN_PM_OFF:
1431d62bc4baSyz147064 		ps_mode.wl_ps_mode = WL_PM_AM;
1432d62bc4baSyz147064 		break;
1433d62bc4baSyz147064 	case DLADM_WLAN_PM_MAX:
1434d62bc4baSyz147064 		ps_mode.wl_ps_mode = WL_PM_MPS;
1435d62bc4baSyz147064 		break;
1436d62bc4baSyz147064 	case DLADM_WLAN_PM_FAST:
1437d62bc4baSyz147064 		ps_mode.wl_ps_mode = WL_PM_FAST;
1438d62bc4baSyz147064 		break;
1439d62bc4baSyz147064 	default:
1440d62bc4baSyz147064 		return (DLADM_STATUS_NOTSUP);
1441d62bc4baSyz147064 	}
1442d62bc4baSyz147064 	return (i_dladm_wlan_set_ioctl(linkid, WL_POWER_MODE, &ps_mode,
1443d62bc4baSyz147064 	    sizeof (ps_mode)));
1444d62bc4baSyz147064 }
1445d62bc4baSyz147064 
1446d62bc4baSyz147064 /* ARGSUSED */
1447d62bc4baSyz147064 static dladm_status_t
1448e7801d59Ssowmini do_set_powermode_prop(prop_desc_t *pd, datalink_id_t linkid,
14496b9e797cSsowmini     val_desc_t *vdp, uint_t val_cnt, uint_t flags, datalink_media_t media)
1450d62bc4baSyz147064 {
1451d62bc4baSyz147064 	dladm_wlan_powermode_t powermode = (dladm_wlan_powermode_t)vdp->vd_val;
1452d62bc4baSyz147064 	dladm_status_t status;
1453d62bc4baSyz147064 
1454d62bc4baSyz147064 	if (val_cnt != 1)
1455d62bc4baSyz147064 		return (DLADM_STATUS_BADVALCNT);
1456d62bc4baSyz147064 
1457d62bc4baSyz147064 	status = do_set_powermode(linkid, &powermode);
1458f4b3ec61Sdh155122 
1459f4b3ec61Sdh155122 	return (status);
1460f4b3ec61Sdh155122 }
1461f4b3ec61Sdh155122 
1462f4b3ec61Sdh155122 static dladm_status_t
1463d62bc4baSyz147064 do_get_radio(datalink_id_t linkid, wldp_t *gbuf)
1464f4b3ec61Sdh155122 {
1465d62bc4baSyz147064 	return (i_dladm_wlan_get_ioctl(linkid, gbuf, WL_RADIO));
1466d62bc4baSyz147064 }
1467d62bc4baSyz147064 
1468e7801d59Ssowmini /* ARGSUSED */
1469d62bc4baSyz147064 static dladm_status_t
1470e7801d59Ssowmini do_get_radio_prop(struct prop_desc *pd, datalink_id_t linkid,
14714045d941Ssowmini     char **prop_val, uint_t *val_cnt, datalink_media_t media, uint_t flags)
1472d62bc4baSyz147064 {
1473d62bc4baSyz147064 	wl_radio_t	radio;
1474d62bc4baSyz147064 	const char	*s;
1475d62bc4baSyz147064 	wldp_t		*gbuf;
1476d62bc4baSyz147064 	dladm_status_t	status = DLADM_STATUS_OK;
1477d62bc4baSyz147064 
1478d62bc4baSyz147064 	if ((gbuf = malloc(MAX_BUF_LEN)) == NULL)
1479d62bc4baSyz147064 		return (DLADM_STATUS_NOMEM);
1480d62bc4baSyz147064 
1481d62bc4baSyz147064 	if ((status = do_get_radio(linkid, gbuf)) != DLADM_STATUS_OK)
1482d62bc4baSyz147064 		goto done;
1483d62bc4baSyz147064 
1484d62bc4baSyz147064 	radio = *(wl_radio_t *)(gbuf->wldp_buf);
1485d62bc4baSyz147064 	switch (radio) {
1486d62bc4baSyz147064 	case B_TRUE:
1487d62bc4baSyz147064 		s = "on";
1488d62bc4baSyz147064 		break;
1489d62bc4baSyz147064 	case B_FALSE:
1490d62bc4baSyz147064 		s = "off";
1491d62bc4baSyz147064 		break;
1492d62bc4baSyz147064 	default:
1493d62bc4baSyz147064 		status = DLADM_STATUS_NOTFOUND;
1494d62bc4baSyz147064 		goto done;
1495d62bc4baSyz147064 	}
1496d62bc4baSyz147064 	(void) snprintf(*prop_val, DLADM_STRSIZE, "%s", s);
1497d62bc4baSyz147064 	*val_cnt = 1;
1498d62bc4baSyz147064 
1499d62bc4baSyz147064 done:
1500d62bc4baSyz147064 	free(gbuf);
1501d62bc4baSyz147064 	return (status);
1502d62bc4baSyz147064 }
1503d62bc4baSyz147064 
1504d62bc4baSyz147064 static dladm_status_t
1505d62bc4baSyz147064 do_set_radio(datalink_id_t linkid, dladm_wlan_radio_t *radio)
1506d62bc4baSyz147064 {
1507d62bc4baSyz147064 	wl_radio_t r;
1508d62bc4baSyz147064 
1509d62bc4baSyz147064 	switch (*radio) {
1510d62bc4baSyz147064 	case DLADM_WLAN_RADIO_ON:
1511d62bc4baSyz147064 		r = B_TRUE;
1512d62bc4baSyz147064 		break;
1513d62bc4baSyz147064 	case DLADM_WLAN_RADIO_OFF:
1514d62bc4baSyz147064 		r = B_FALSE;
1515d62bc4baSyz147064 		break;
1516d62bc4baSyz147064 	default:
1517d62bc4baSyz147064 		return (DLADM_STATUS_NOTSUP);
1518d62bc4baSyz147064 	}
1519d62bc4baSyz147064 	return (i_dladm_wlan_set_ioctl(linkid, WL_RADIO, &r, sizeof (r)));
1520d62bc4baSyz147064 }
1521d62bc4baSyz147064 
1522d62bc4baSyz147064 /* ARGSUSED */
1523d62bc4baSyz147064 static dladm_status_t
1524e7801d59Ssowmini do_set_radio_prop(prop_desc_t *pd, datalink_id_t linkid,
15256b9e797cSsowmini     val_desc_t *vdp, uint_t val_cnt, uint_t fags, datalink_media_t media)
1526d62bc4baSyz147064 {
1527d62bc4baSyz147064 	dladm_wlan_radio_t radio = (dladm_wlan_radio_t)vdp->vd_val;
1528f4b3ec61Sdh155122 	dladm_status_t status;
1529f4b3ec61Sdh155122 
1530d62bc4baSyz147064 	if (val_cnt != 1)
1531d62bc4baSyz147064 		return (DLADM_STATUS_BADVALCNT);
1532f4b3ec61Sdh155122 
1533d62bc4baSyz147064 	status = do_set_radio(linkid, &radio);
1534f4b3ec61Sdh155122 
1535d62bc4baSyz147064 	return (status);
1536d62bc4baSyz147064 }
1537f4b3ec61Sdh155122 
1538d62bc4baSyz147064 static dladm_status_t
1539d62bc4baSyz147064 i_dladm_set_linkprop_db(datalink_id_t linkid, const char *prop_name,
1540d62bc4baSyz147064     char **prop_val, uint_t val_cnt)
1541d62bc4baSyz147064 {
1542d62bc4baSyz147064 	char		buf[MAXLINELEN];
1543d62bc4baSyz147064 	int		i;
1544d62bc4baSyz147064 	dladm_conf_t	conf;
1545d62bc4baSyz147064 	dladm_status_t	status;
1546d62bc4baSyz147064 
1547d62bc4baSyz147064 	status = dladm_read_conf(linkid, &conf);
1548f4b3ec61Sdh155122 	if (status != DLADM_STATUS_OK)
1549f4b3ec61Sdh155122 		return (status);
1550f4b3ec61Sdh155122 
1551d62bc4baSyz147064 	/*
1552d62bc4baSyz147064 	 * reset case.
1553d62bc4baSyz147064 	 */
1554d62bc4baSyz147064 	if (val_cnt == 0) {
1555d62bc4baSyz147064 		status = dladm_unset_conf_field(conf, prop_name);
1556d62bc4baSyz147064 		if (status == DLADM_STATUS_OK)
1557d62bc4baSyz147064 			status = dladm_write_conf(conf);
1558d62bc4baSyz147064 		goto done;
1559f4b3ec61Sdh155122 	}
1560f4b3ec61Sdh155122 
1561d62bc4baSyz147064 	buf[0] = '\0';
1562d62bc4baSyz147064 	for (i = 0; i < val_cnt; i++) {
1563d62bc4baSyz147064 		(void) strlcat(buf, prop_val[i], MAXLINELEN);
1564d62bc4baSyz147064 		if (i != val_cnt - 1)
1565d62bc4baSyz147064 			(void) strlcat(buf, ",", MAXLINELEN);
1566d62bc4baSyz147064 	}
1567f4b3ec61Sdh155122 
1568d62bc4baSyz147064 	status = dladm_set_conf_field(conf, prop_name, DLADM_TYPE_STR, buf);
1569d62bc4baSyz147064 	if (status == DLADM_STATUS_OK)
1570d62bc4baSyz147064 		status = dladm_write_conf(conf);
1571d62bc4baSyz147064 
1572d62bc4baSyz147064 done:
1573d62bc4baSyz147064 	dladm_destroy_conf(conf);
1574f4b3ec61Sdh155122 	return (status);
1575f4b3ec61Sdh155122 }
1576f4b3ec61Sdh155122 
1577f4b3ec61Sdh155122 static dladm_status_t
1578d62bc4baSyz147064 i_dladm_get_linkprop_db(datalink_id_t linkid, const char *prop_name,
1579d62bc4baSyz147064     char **prop_val, uint_t *val_cntp)
1580f4b3ec61Sdh155122 {
1581d62bc4baSyz147064 	char		buf[MAXLINELEN], *str;
1582d62bc4baSyz147064 	uint_t		cnt = 0;
1583d62bc4baSyz147064 	dladm_conf_t	conf;
1584d62bc4baSyz147064 	dladm_status_t	status;
1585f4b3ec61Sdh155122 
1586d62bc4baSyz147064 	status = dladm_read_conf(linkid, &conf);
1587d62bc4baSyz147064 	if (status != DLADM_STATUS_OK)
1588f4b3ec61Sdh155122 		return (status);
1589d62bc4baSyz147064 
1590d62bc4baSyz147064 	status = dladm_get_conf_field(conf, prop_name, buf, MAXLINELEN);
1591d62bc4baSyz147064 	if (status != DLADM_STATUS_OK)
1592d62bc4baSyz147064 		goto done;
1593d62bc4baSyz147064 
1594d62bc4baSyz147064 	str = strtok(buf, ",");
1595d62bc4baSyz147064 	while (str != NULL) {
1596d62bc4baSyz147064 		if (cnt == *val_cntp) {
1597d62bc4baSyz147064 			status = DLADM_STATUS_TOOSMALL;
1598d62bc4baSyz147064 			goto done;
1599d62bc4baSyz147064 		}
1600d62bc4baSyz147064 		(void) strlcpy(prop_val[cnt++], str, DLADM_PROP_VAL_MAX);
1601d62bc4baSyz147064 		str = strtok(NULL, ",");
1602f4b3ec61Sdh155122 	}
1603f4b3ec61Sdh155122 
1604d62bc4baSyz147064 	*val_cntp = cnt;
1605f4b3ec61Sdh155122 
1606d62bc4baSyz147064 done:
1607d62bc4baSyz147064 	dladm_destroy_conf(conf);
1608d62bc4baSyz147064 	return (status);
1609f4b3ec61Sdh155122 }
1610e7801d59Ssowmini 
1611e7801d59Ssowmini static dld_public_prop_t *
1612e7801d59Ssowmini dladm_name2prop(const char *prop_name)
1613e7801d59Ssowmini {
1614e7801d59Ssowmini 	dld_public_prop_t *p;
1615e7801d59Ssowmini 
1616e7801d59Ssowmini 	for (p = dld_prop; p->pp_id != DLD_PROP_PRIVATE; p++) {
1617e7801d59Ssowmini 		if (strcmp(p->pp_name, prop_name) == 0)
1618e7801d59Ssowmini 			break;
1619e7801d59Ssowmini 	}
1620e7801d59Ssowmini 	return (p);
1621e7801d59Ssowmini }
1622e7801d59Ssowmini 
1623e7801d59Ssowmini 
1624e7801d59Ssowmini static dld_ioc_prop_t *
1625e7801d59Ssowmini dld_buf_alloc(size_t valsize, datalink_id_t linkid, const char *prop_name,
16264045d941Ssowmini     uint_t flags, dladm_status_t *status)
1627e7801d59Ssowmini {
1628e7801d59Ssowmini 	int dsize;
1629e7801d59Ssowmini 	dld_ioc_prop_t *dip;
1630e7801d59Ssowmini 	dld_public_prop_t *p;
1631e7801d59Ssowmini 
1632e7801d59Ssowmini 	*status = DLADM_STATUS_OK;
1633e7801d59Ssowmini 	p = dladm_name2prop(prop_name);
1634e7801d59Ssowmini 	if (p->pp_id != DLD_PROP_PRIVATE)
1635e7801d59Ssowmini 		valsize = p->pp_valsize;
1636e7801d59Ssowmini 
1637e7801d59Ssowmini 	dsize = DLD_PROPBUF_SIZE(valsize);
1638e7801d59Ssowmini 	dip = malloc(dsize);
1639e7801d59Ssowmini 	if (dip == NULL) {
1640e7801d59Ssowmini 		*status = DLADM_STATUS_NOMEM;
1641e7801d59Ssowmini 		return (NULL);
1642e7801d59Ssowmini 	}
1643e7801d59Ssowmini 	bzero(dip, dsize);
1644e7801d59Ssowmini 	dip->pr_valsize = valsize;
16454045d941Ssowmini 	(void) strlcpy(dip->pr_name, prop_name, sizeof (dip->pr_name));
1646e7801d59Ssowmini 	dip->pr_version = DLD_PROP_VERSION;
16476b9e797cSsowmini 	dip->pr_linkid = linkid;
1648e7801d59Ssowmini 	dip->pr_num = p->pp_id;
16494045d941Ssowmini 	dip->pr_flags = flags;
1650e7801d59Ssowmini 	return (dip);
1651e7801d59Ssowmini }
1652e7801d59Ssowmini 
1653e7801d59Ssowmini /* ARGSUSED */
1654e7801d59Ssowmini static dladm_status_t
1655e7801d59Ssowmini dld_set_public_prop(prop_desc_t *pd, datalink_id_t linkid,
16566b9e797cSsowmini     val_desc_t *vdp, uint_t val_cnt, uint_t flags, datalink_media_t media)
1657e7801d59Ssowmini {
1658e7801d59Ssowmini 	dld_ioc_prop_t	*dip;
1659e7801d59Ssowmini 	int		fd, dsize;
1660e7801d59Ssowmini 	dladm_status_t	status = DLADM_STATUS_OK;
1661e7801d59Ssowmini 	uint8_t		u8;
1662e7801d59Ssowmini 	uint16_t	u16;
1663e7801d59Ssowmini 	uint32_t	u32;
1664e7801d59Ssowmini 	void		*val;
1665e7801d59Ssowmini 
16664045d941Ssowmini 	dip = dld_buf_alloc(0, linkid, pd->pd_name, 0, &status);
1667e7801d59Ssowmini 	if (dip == NULL)
1668e7801d59Ssowmini 		return (status);
1669e7801d59Ssowmini 
1670e7801d59Ssowmini 	if (pd->pd_flags & PD_CHECK_ALLOC)
1671e7801d59Ssowmini 		val = (void *)vdp->vd_val;
1672e7801d59Ssowmini 	else {
1673e7801d59Ssowmini 		/*
1674e7801d59Ssowmini 		 * Currently all 1/2/4-byte size properties are byte/word/int.
1675e7801d59Ssowmini 		 * No need (yet) to distinguish these from arrays of same size.
1676e7801d59Ssowmini 		 */
1677e7801d59Ssowmini 		switch (dip->pr_valsize) {
1678e7801d59Ssowmini 		case 1:
1679e7801d59Ssowmini 			u8 = vdp->vd_val;
1680e7801d59Ssowmini 			val = &u8;
1681e7801d59Ssowmini 			break;
1682e7801d59Ssowmini 		case 2:
1683e7801d59Ssowmini 			u16 = vdp->vd_val;
1684e7801d59Ssowmini 			val = &u16;
1685e7801d59Ssowmini 			break;
1686e7801d59Ssowmini 		case 4:
1687e7801d59Ssowmini 			u32 = vdp->vd_val;
1688e7801d59Ssowmini 			val = &u32;
1689e7801d59Ssowmini 			break;
1690e7801d59Ssowmini 		default:
1691e7801d59Ssowmini 			val = &vdp->vd_val;
1692e7801d59Ssowmini 			break;
1693e7801d59Ssowmini 		}
1694e7801d59Ssowmini 	}
1695e7801d59Ssowmini 
1696e7801d59Ssowmini 	(void) memcpy(dip->pr_val, val, dip->pr_valsize);
1697e7801d59Ssowmini 	dsize = DLD_PROPBUF_SIZE(dip->pr_valsize);
1698e7801d59Ssowmini 	if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) {
1699e7801d59Ssowmini 		status = dladm_errno2status(errno);
1700e7801d59Ssowmini 		goto done;
1701e7801d59Ssowmini 	}
1702e7801d59Ssowmini 	if (i_dladm_ioctl(fd, DLDIOCSETPROP, dip, dsize) < 0)
1703e7801d59Ssowmini 		status = dladm_errno2status(errno);
1704e7801d59Ssowmini 
1705e7801d59Ssowmini 	(void) close(fd);
1706e7801d59Ssowmini done:
17074045d941Ssowmini 	free(dip);
1708e7801d59Ssowmini 	return (status);
1709e7801d59Ssowmini }
1710e7801d59Ssowmini 
17114045d941Ssowmini static dld_ioc_prop_t *
17124045d941Ssowmini dld_get_public_prop(datalink_id_t linkid, char *prop_name, uint_t flags,
17134045d941Ssowmini     dladm_status_t *status)
1714e7801d59Ssowmini {
1715e7801d59Ssowmini 	int fd, dsize;
17164045d941Ssowmini 	dld_ioc_prop_t *dip = NULL;
17174045d941Ssowmini 
17184045d941Ssowmini 	*status = DLADM_STATUS_OK;
17194045d941Ssowmini 
17204045d941Ssowmini 	dip = dld_buf_alloc(0, linkid, prop_name, flags, status);
17214045d941Ssowmini 	if (dip == NULL)
17224045d941Ssowmini 		return (NULL);
1723e7801d59Ssowmini 
1724e7801d59Ssowmini 	dsize = DLD_PROPBUF_SIZE(dip->pr_valsize);
1725e7801d59Ssowmini 
1726e7801d59Ssowmini 	if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) {
17274045d941Ssowmini 		*status = dladm_errno2status(errno);
1728e7801d59Ssowmini 		goto done;
1729e7801d59Ssowmini 	}
1730e7801d59Ssowmini 	if (i_dladm_ioctl(fd, DLDIOCGETPROP, dip, dsize) < 0) {
17314045d941Ssowmini 		*status = dladm_errno2status(errno);
1732e7801d59Ssowmini 	}
17334045d941Ssowmini 
17344045d941Ssowmini 	(void) close(fd);
1735e7801d59Ssowmini done:
17364045d941Ssowmini 	if (*status != DLADM_STATUS_OK) {
17374045d941Ssowmini 		free(dip);
17384045d941Ssowmini 		return (NULL);
17394045d941Ssowmini 	}
17404045d941Ssowmini 	return (dip);
1741e7801d59Ssowmini }
1742e7801d59Ssowmini 
1743e7801d59Ssowmini /* ARGSUSED */
1744e7801d59Ssowmini static dladm_status_t
1745e7801d59Ssowmini dld_defmtu_check(struct prop_desc *pd, datalink_id_t linkid, char **prop_val,
17466b9e797cSsowmini     uint_t val_cnt, val_desc_t *v, datalink_media_t media)
1747e7801d59Ssowmini {
1748e7801d59Ssowmini 	if (val_cnt != 1)
1749e7801d59Ssowmini 		return (DLADM_STATUS_BADVAL);
17504045d941Ssowmini 	v->vd_val = atoi(prop_val[0]);
1751e7801d59Ssowmini 	return (DLADM_STATUS_OK);
1752e7801d59Ssowmini }
1753e7801d59Ssowmini 
1754e7801d59Ssowmini /* ARGSUSED */
1755e7801d59Ssowmini static dladm_status_t
1756e7801d59Ssowmini dld_duplex_get(struct prop_desc *pd, datalink_id_t linkid,
17574045d941Ssowmini     char **prop_val, uint_t *val_cnt, datalink_media_t media, uint_t flags)
1758e7801d59Ssowmini {
1759e7801d59Ssowmini 	link_duplex_t   link_duplex;
1760e7801d59Ssowmini 	dladm_status_t  status;
1761e7801d59Ssowmini 
17624045d941Ssowmini 	if (flags & DLD_DEFAULT)
17634045d941Ssowmini 		return (DLADM_STATUS_NOTSUP);
17644045d941Ssowmini 
1765e7801d59Ssowmini 	if ((status = dladm_get_single_mac_stat(linkid, "link_duplex",
1766e7801d59Ssowmini 	    KSTAT_DATA_UINT32, &link_duplex)) != 0)
1767e7801d59Ssowmini 		return (status);
1768e7801d59Ssowmini 
1769e7801d59Ssowmini 	switch (link_duplex) {
1770e7801d59Ssowmini 	case LINK_DUPLEX_FULL:
1771e7801d59Ssowmini 		(void) strcpy(*prop_val, "full");
1772e7801d59Ssowmini 		break;
1773e7801d59Ssowmini 	case LINK_DUPLEX_HALF:
1774e7801d59Ssowmini 		(void) strcpy(*prop_val, "half");
1775e7801d59Ssowmini 		break;
1776e7801d59Ssowmini 	default:
1777e7801d59Ssowmini 		(void) strcpy(*prop_val, "unknown");
1778e7801d59Ssowmini 		break;
1779e7801d59Ssowmini 	}
1780e7801d59Ssowmini 	*val_cnt = 1;
1781e7801d59Ssowmini 	return (DLADM_STATUS_OK);
1782e7801d59Ssowmini }
1783e7801d59Ssowmini 
1784e7801d59Ssowmini /* ARGSUSED */
1785e7801d59Ssowmini static dladm_status_t
1786e7801d59Ssowmini dld_speed_get(struct prop_desc *pd, datalink_id_t linkid,
17874045d941Ssowmini     char **prop_val, uint_t *val_cnt, uint_t flags)
1788e7801d59Ssowmini {
1789e7801d59Ssowmini 	uint64_t	ifspeed = 0;
1790e7801d59Ssowmini 	dladm_status_t status;
1791e7801d59Ssowmini 
17924045d941Ssowmini 	if (flags & DLD_DEFAULT)
17934045d941Ssowmini 		return (DLADM_STATUS_NOTSUP);
17944045d941Ssowmini 
1795e7801d59Ssowmini 	if ((status = dladm_get_single_mac_stat(linkid, "ifspeed",
1796e7801d59Ssowmini 	    KSTAT_DATA_UINT64, &ifspeed)) != 0)
1797e7801d59Ssowmini 		return (status);
17984045d941Ssowmini 
17996b9e797cSsowmini 	if ((ifspeed % 1000000) != 0) {
18006b9e797cSsowmini 		(void) snprintf(*prop_val, DLADM_PROP_VAL_MAX,
18016b9e797cSsowmini 		    "%llf", ifspeed / (float)1000000); /* Mbps */
18026b9e797cSsowmini 	} else {
1803e7801d59Ssowmini 		(void) snprintf(*prop_val, DLADM_PROP_VAL_MAX,
1804e7801d59Ssowmini 		    "%llu", ifspeed / 1000000); /* Mbps */
18056b9e797cSsowmini 	}
1806e7801d59Ssowmini 	*val_cnt = 1;
1807e7801d59Ssowmini 	return (DLADM_STATUS_OK);
1808e7801d59Ssowmini }
1809e7801d59Ssowmini 
1810e7801d59Ssowmini /* ARGSUSED */
1811e7801d59Ssowmini static dladm_status_t
1812e7801d59Ssowmini dld_status_get(struct prop_desc *pd, datalink_id_t linkid,
18134045d941Ssowmini     char **prop_val, uint_t *val_cnt, datalink_media_t media, uint_t flags)
1814e7801d59Ssowmini {
1815e7801d59Ssowmini 	link_state_t	link_state;
1816e7801d59Ssowmini 	dladm_status_t	status;
18174045d941Ssowmini 	uchar_t 	*cp;
18184045d941Ssowmini 	dld_ioc_prop_t  *dip;
1819e7801d59Ssowmini 
18204045d941Ssowmini 	if (flags & DLD_DEFAULT)
18214045d941Ssowmini 		return (DLADM_STATUS_NOTSUP);
18224045d941Ssowmini 	dip = dld_get_public_prop(linkid, pd->pd_name, flags, &status);
18234045d941Ssowmini 	if (status != DLADM_STATUS_OK)
1824e7801d59Ssowmini 		return (status);
18254045d941Ssowmini 	cp = (uchar_t *)dip->pr_val;
18264045d941Ssowmini 	(void) memcpy(&link_state, cp, sizeof (link_state));
1827e7801d59Ssowmini 
1828e7801d59Ssowmini 	switch (link_state) {
1829e7801d59Ssowmini 	case LINK_STATE_UP:
1830e7801d59Ssowmini 		(void) strcpy(*prop_val, "up");
1831e7801d59Ssowmini 		break;
1832e7801d59Ssowmini 	case LINK_STATE_DOWN:
1833e7801d59Ssowmini 		(void) strcpy(*prop_val, "down");
1834e7801d59Ssowmini 		break;
1835e7801d59Ssowmini 	default:
1836e7801d59Ssowmini 		(void) strcpy(*prop_val, "unknown");
1837e7801d59Ssowmini 		break;
1838e7801d59Ssowmini 	}
1839e7801d59Ssowmini 	*val_cnt = 1;
18404045d941Ssowmini 	free(dip);
1841e7801d59Ssowmini 	return (DLADM_STATUS_OK);
1842e7801d59Ssowmini }
1843e7801d59Ssowmini 
1844e7801d59Ssowmini /* ARGSUSED */
1845e7801d59Ssowmini static dladm_status_t
1846e7801d59Ssowmini dld_binary_get(struct prop_desc *pd, datalink_id_t linkid,
18474045d941Ssowmini     char **prop_val, uint_t *val_cnt, datalink_media_t media, uint_t flags)
1848e7801d59Ssowmini {
1849e7801d59Ssowmini 	dld_ioc_prop_t *dip;
1850e7801d59Ssowmini 	dladm_status_t status;
1851e7801d59Ssowmini 
18524045d941Ssowmini 	dip = dld_get_public_prop(linkid, pd->pd_name, flags, &status);
18534045d941Ssowmini 	if (dip == NULL)
1854e7801d59Ssowmini 		return (status);
1855e7801d59Ssowmini 	(void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "%x", dip->pr_val[0]);
1856e7801d59Ssowmini 	free(dip);
1857e7801d59Ssowmini 	*val_cnt = 1;
1858e7801d59Ssowmini 	return (DLADM_STATUS_OK);
1859e7801d59Ssowmini }
1860e7801d59Ssowmini 
18616b9e797cSsowmini /* ARGSUSED */
1862e7801d59Ssowmini static dladm_status_t
18634045d941Ssowmini dld_uint32_get(struct prop_desc *pd, datalink_id_t linkid,
18644045d941Ssowmini     char **prop_val, uint_t *val_cnt, datalink_media_t media, uint_t flags)
1865e7801d59Ssowmini {
1866e7801d59Ssowmini 	dld_ioc_prop_t *dip;
18674045d941Ssowmini 	uint32_t v  = 0;
1868e7801d59Ssowmini 	uchar_t *cp;
1869e7801d59Ssowmini 	dladm_status_t status;
1870e7801d59Ssowmini 
18714045d941Ssowmini 	dip = dld_get_public_prop(linkid, pd->pd_name, flags, &status);
18724045d941Ssowmini 	if (dip == NULL)
1873e7801d59Ssowmini 		return (status);
1874e7801d59Ssowmini 	cp = (uchar_t *)dip->pr_val;
1875e7801d59Ssowmini 	(void) memcpy(&v, cp, sizeof (v));
18764045d941Ssowmini 	(void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "%ld", v);
1877e7801d59Ssowmini 	free(dip);
1878e7801d59Ssowmini 	*val_cnt = 1;
1879e7801d59Ssowmini 	return (DLADM_STATUS_OK);
1880e7801d59Ssowmini }
1881e7801d59Ssowmini 
18826b9e797cSsowmini /* ARGSUSED */
1883e7801d59Ssowmini static dladm_status_t
1884e7801d59Ssowmini dld_flowctl_get(struct prop_desc *pd, datalink_id_t linkid,
18854045d941Ssowmini     char **prop_val, uint_t *val_cnt, datalink_media_t media, uint_t flags)
1886e7801d59Ssowmini {
1887e7801d59Ssowmini 	dld_ioc_prop_t *dip;
1888e7801d59Ssowmini 	link_flowctrl_t v;
1889e7801d59Ssowmini 	dladm_status_t status;
1890e7801d59Ssowmini 	uchar_t *cp;
1891e7801d59Ssowmini 
18924045d941Ssowmini 	dip = dld_get_public_prop(linkid, pd->pd_name, flags, &status);
18934045d941Ssowmini 	if (dip == NULL)
1894e7801d59Ssowmini 		return (status);
1895e7801d59Ssowmini 	cp = (uchar_t *)dip->pr_val;
1896e7801d59Ssowmini 	(void) memcpy(&v, cp, sizeof (v));
1897e7801d59Ssowmini 	switch (v) {
1898e7801d59Ssowmini 	case LINK_FLOWCTRL_NONE:
1899e7801d59Ssowmini 		(void) sprintf(*prop_val, "no");
1900e7801d59Ssowmini 		break;
1901e7801d59Ssowmini 	case LINK_FLOWCTRL_RX:
1902e7801d59Ssowmini 		(void) sprintf(*prop_val, "rx");
1903e7801d59Ssowmini 		break;
1904e7801d59Ssowmini 	case LINK_FLOWCTRL_TX:
1905e7801d59Ssowmini 		(void) sprintf(*prop_val, "tx");
1906e7801d59Ssowmini 		break;
1907e7801d59Ssowmini 	case LINK_FLOWCTRL_BI:
1908e7801d59Ssowmini 		(void) sprintf(*prop_val, "bi");
1909e7801d59Ssowmini 		break;
1910e7801d59Ssowmini 	}
1911e7801d59Ssowmini 	free(dip);
1912e7801d59Ssowmini 	*val_cnt = 1;
1913e7801d59Ssowmini 	return (DLADM_STATUS_OK);
1914e7801d59Ssowmini }
1915e7801d59Ssowmini 
1916e7801d59Ssowmini 
1917e7801d59Ssowmini /* ARGSUSED */
1918e7801d59Ssowmini static dladm_status_t
1919e7801d59Ssowmini dld_set_prop(datalink_id_t linkid, const char *prop_name,
1920e7801d59Ssowmini     char **prop_val, uint_t val_cnt, uint_t flags)
1921e7801d59Ssowmini {
1922e7801d59Ssowmini 	int		fd, i, slen;
1923e7801d59Ssowmini 	int 		bufsize = 0, dsize;
1924e7801d59Ssowmini 	dld_ioc_prop_t *dip = NULL;
1925e7801d59Ssowmini 	uchar_t 	*dp;
1926e7801d59Ssowmini 	dld_public_prop_t *p;
19274045d941Ssowmini 	dladm_status_t	status = DLADM_STATUS_OK;
1928e7801d59Ssowmini 
1929e7801d59Ssowmini 	if ((prop_name == NULL && prop_val != NULL) ||
1930e7801d59Ssowmini 	    (prop_val != NULL && val_cnt == 0))
1931e7801d59Ssowmini 		return (DLADM_STATUS_BADARG);
1932e7801d59Ssowmini 	p = dladm_name2prop(prop_name);
1933e7801d59Ssowmini 	if (p->pp_id != DLD_PROP_PRIVATE)
1934e7801d59Ssowmini 		return (DLADM_STATUS_BADARG);
1935e7801d59Ssowmini 
1936e7801d59Ssowmini 	/*
1937e7801d59Ssowmini 	 * private properties: all parsing is done in the kernel.
1938e7801d59Ssowmini 	 * allocate a enough space for each property + its separator (',').
1939e7801d59Ssowmini 	 */
1940e7801d59Ssowmini 	for (i = 0; i < val_cnt; i++) {
1941e7801d59Ssowmini 		bufsize += strlen(prop_val[i]) + 1;
1942e7801d59Ssowmini 	}
19434045d941Ssowmini 
19444045d941Ssowmini 	if (prop_val == NULL) {
19454045d941Ssowmini 		/*
19464045d941Ssowmini 		 * getting default value. so use more buffer space.
19474045d941Ssowmini 		 */
19484045d941Ssowmini 		bufsize += 1024;
19494045d941Ssowmini 	}
19504045d941Ssowmini 
19514045d941Ssowmini 	dip = dld_buf_alloc(bufsize + 1, linkid, prop_name,
19524045d941Ssowmini 	    (prop_val != NULL ? 0 : DLD_DEFAULT), &status);
1953e7801d59Ssowmini 	if (dip == NULL)
1954e7801d59Ssowmini 		return (status);
1955e7801d59Ssowmini 
1956e7801d59Ssowmini 	dp = (uchar_t *)dip->pr_val;
1957e7801d59Ssowmini 	dsize = sizeof (dld_ioc_prop_t) + bufsize;
1958e7801d59Ssowmini 	slen = 0;
19594045d941Ssowmini 	if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) {
19604045d941Ssowmini 		status = dladm_errno2status(errno);
19614045d941Ssowmini 		goto done;
19624045d941Ssowmini 	}
19634045d941Ssowmini 	if (prop_val == NULL) {
19644045d941Ssowmini 		if (i_dladm_ioctl(fd, DLDIOCGETPROP, dip, dsize) < 0) {
19654045d941Ssowmini 			status = dladm_errno2status(errno);
19664045d941Ssowmini 			goto done;
19674045d941Ssowmini 		}
19684045d941Ssowmini 	} else {
1969e7801d59Ssowmini 		for (i = 0; i < val_cnt; i++) {
1970e7801d59Ssowmini 			int plen = 0;
1971e7801d59Ssowmini 
1972e7801d59Ssowmini 			plen = strlen(prop_val[i]);
1973e7801d59Ssowmini 			bcopy(prop_val[i], dp, plen);
1974e7801d59Ssowmini 			slen += plen;
1975e7801d59Ssowmini 			/*
1976e7801d59Ssowmini 			 * add a "," separator and update dp.
1977e7801d59Ssowmini 			 */
1978e7801d59Ssowmini 			if (i != (val_cnt -1))
1979e7801d59Ssowmini 				dp[slen++] = ',';
1980e7801d59Ssowmini 			dp += (plen + 1);
1981e7801d59Ssowmini 		}
1982e7801d59Ssowmini 	}
19834045d941Ssowmini 	if (i_dladm_ioctl(fd, DLDIOCSETPROP, dip, dsize) < 0) {
19844045d941Ssowmini 		status = dladm_errno2status(errno);
19854045d941Ssowmini 	}
19864045d941Ssowmini 
19874045d941Ssowmini done:
19884045d941Ssowmini 	if (fd > 0)
19894045d941Ssowmini 		(void) close(fd);
1990e7801d59Ssowmini 	free(dip);
1991e7801d59Ssowmini 	return (status);
1992e7801d59Ssowmini }
1993e7801d59Ssowmini 
1994e7801d59Ssowmini static dladm_status_t
1995e7801d59Ssowmini dld_get_prop(datalink_id_t linkid, const char *prop_name,
19964045d941Ssowmini     char **prop_val, uint_t *val_cnt, dladm_prop_type_t type, uint_t dld_flags)
1997e7801d59Ssowmini {
1998e7801d59Ssowmini 	int		fd;
1999e7801d59Ssowmini 	dladm_status_t  status = DLADM_STATUS_OK;
2000e7801d59Ssowmini 	uint_t 		dsize;
2001e7801d59Ssowmini 	dld_ioc_prop_t *dip = NULL;
2002e7801d59Ssowmini 	dld_public_prop_t *p;
2003e7801d59Ssowmini 	char tmp = '\0';
2004e7801d59Ssowmini 
2005e7801d59Ssowmini 	if ((prop_name == NULL && prop_val != NULL) ||
2006e7801d59Ssowmini 	    (prop_val != NULL && val_cnt == 0))
2007e7801d59Ssowmini 		return (DLADM_STATUS_BADARG);
2008e7801d59Ssowmini 
2009e7801d59Ssowmini 	p = dladm_name2prop(prop_name);
2010e7801d59Ssowmini 	if (p->pp_id != DLD_PROP_PRIVATE)
2011e7801d59Ssowmini 		return (DLADM_STATUS_BADARG);
2012e7801d59Ssowmini 
20134045d941Ssowmini 	if (type == DLADM_PROP_VAL_MODIFIABLE) {
2014e7801d59Ssowmini 		*prop_val = &tmp;
2015e7801d59Ssowmini 		*val_cnt = 1;
2016e7801d59Ssowmini 		return (DLADM_STATUS_OK);
2017e7801d59Ssowmini 	}
2018e7801d59Ssowmini 
2019e7801d59Ssowmini 	/*
2020e7801d59Ssowmini 	 * private properties: all parsing is done in the kernel.
2021e7801d59Ssowmini 	 */
20224045d941Ssowmini 	dip = dld_buf_alloc(1024, linkid, prop_name, dld_flags, &status);
2023e7801d59Ssowmini 	if (dip == NULL)
2024e7801d59Ssowmini 		return (status);
2025e7801d59Ssowmini 	dsize = DLD_PROPBUF_SIZE(dip->pr_valsize);
2026e7801d59Ssowmini 
20274045d941Ssowmini 	if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) {
20284045d941Ssowmini 		free(dip);
2029e7801d59Ssowmini 		return (DLADM_STATUS_BADARG);
20304045d941Ssowmini 	}
2031e7801d59Ssowmini 
2032e7801d59Ssowmini 	if ((status = i_dladm_ioctl(fd, DLDIOCGETPROP, dip, dsize)) < 0) {
2033e7801d59Ssowmini 		status = dladm_errno2status(errno);
2034e7801d59Ssowmini 	} else {
2035e7801d59Ssowmini 		(void) strncpy(*prop_val, dip->pr_val, DLADM_PROP_VAL_MAX);
2036e7801d59Ssowmini 		*val_cnt = 1;
2037e7801d59Ssowmini 	}
20384045d941Ssowmini 
20394045d941Ssowmini 	(void) close(fd);
20404045d941Ssowmini 	free(dip);
20414045d941Ssowmini 	return (status);
20424045d941Ssowmini }
20434045d941Ssowmini 
20444045d941Ssowmini 
20454045d941Ssowmini static dladm_status_t
20464045d941Ssowmini i_dladm_getset_defval(prop_desc_t *pdp, datalink_id_t linkid,
20474045d941Ssowmini     datalink_media_t media, uint_t flags)
20484045d941Ssowmini {
20494045d941Ssowmini 	dladm_status_t status;
20504045d941Ssowmini 	char **prop_vals = NULL, *buf;
20514045d941Ssowmini 	size_t bufsize;
20524045d941Ssowmini 	uint_t cnt;
20534045d941Ssowmini 	int i;
20544045d941Ssowmini 
20554045d941Ssowmini 	/*
20564045d941Ssowmini 	 * Allocate buffer needed for prop_vals array. We can have at most
20574045d941Ssowmini 	 * DLADM_MAX_PROP_VALCNT char *prop_vals[] entries, where
20584045d941Ssowmini 	 * each entry has max size DLADM_PROP_VAL_MAX
20594045d941Ssowmini 	 */
20604045d941Ssowmini 	bufsize =
20614045d941Ssowmini 	    (sizeof (char *) + DLADM_PROP_VAL_MAX) * DLADM_MAX_PROP_VALCNT;
20624045d941Ssowmini 	buf = malloc(bufsize);
20634045d941Ssowmini 	prop_vals = (char **)(void *)buf;
20644045d941Ssowmini 	for (i = 0; i < DLADM_MAX_PROP_VALCNT; i++) {
20654045d941Ssowmini 		prop_vals[i] = buf +
20664045d941Ssowmini 		    sizeof (char *) * DLADM_MAX_PROP_VALCNT +
20674045d941Ssowmini 		    i * DLADM_PROP_VAL_MAX;
20684045d941Ssowmini 	}
2069*13a55820Sar224390 
2070*13a55820Sar224390 	/*
2071*13a55820Sar224390 	 * PD_EMPTY_RESET is used for properties like zone where the
2072*13a55820Sar224390 	 * "" itself is used to reset the property. So libdladm can
2073*13a55820Sar224390 	 * copy pdp->pd_defval over to the val_desc_t passed down on
2074*13a55820Sar224390 	 * the setprop using the global values in the table. For other
2075*13a55820Sar224390 	 * cases (PD_EMPTY_RESET is not set, vd_name is ""), doing
2076*13a55820Sar224390 	 * reset-linkprop will cause libdladm to do a getprop to find
2077*13a55820Sar224390 	 * the default value and then do a setprop to reset the value
2078*13a55820Sar224390 	 * to default.
2079*13a55820Sar224390 	 */
20804045d941Ssowmini 	status = pdp->pd_get(pdp, linkid, prop_vals, &cnt, media, DLD_DEFAULT);
20814045d941Ssowmini 	if (status == DLADM_STATUS_OK) {
20824045d941Ssowmini 		status = i_dladm_set_single_prop(linkid, pdp->pd_class,
20834045d941Ssowmini 		    media, pdp, prop_vals, cnt, flags);
20844045d941Ssowmini 	}
20854045d941Ssowmini 	free(buf);
2086e7801d59Ssowmini 	return (status);
2087e7801d59Ssowmini }
2088