xref: /titanic_52/usr/src/lib/libdladm/common/linkprop.c (revision e7801d59e8ceda0cde8ebdfdddd7582ee2ea96ef)
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>
49*e7801d59Ssowmini #include <libdladm.h>
50*e7801d59Ssowmini #include <sys/param.h>
51*e7801d59Ssowmini #include <sys/dld.h>
52*e7801d59Ssowmini #include <inttypes.h>
53*e7801d59Ssowmini #include <sys/ethernet.h>
54f4b3ec61Sdh155122 
55d62bc4baSyz147064 /*
56d62bc4baSyz147064  * The linkprop get() callback.
57*e7801d59Ssowmini  * - 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  */
63*e7801d59Ssowmini struct prop_desc;
64*e7801d59Ssowmini 
65*e7801d59Ssowmini typedef dladm_status_t	pd_getf_t(struct prop_desc *pd,
66*e7801d59Ssowmini 			datalink_id_t, char **propstp, uint_t *cntp);
67f4b3ec61Sdh155122 
68d62bc4baSyz147064 /*
69d62bc4baSyz147064  * The linkprop set() callback.
70d62bc4baSyz147064  * - propval:	a val_desc_t array which keeps the property values to be set.
71d62bc4baSyz147064  * - cnt:	number of properties to be set.
72*e7801d59Ssowmini  * - flags: 	additional flags passed down the system call.
73*e7801d59Ssowmini  *
74*e7801d59Ssowmini  * pd_set takes val_desc_t given by pd_check(), translates it into
75*e7801d59Ssowmini  * a format suitable for kernel consumption. This may require allocation
76*e7801d59Ssowmini  * of ioctl buffers etc. pd_set() may call another common routine (used
77*e7801d59Ssowmini  * by all other pd_sets) which invokes the ioctl.
78d62bc4baSyz147064  */
79*e7801d59Ssowmini typedef dladm_status_t	pd_setf_t(struct prop_desc *, datalink_id_t,
80*e7801d59Ssowmini 			val_desc_t *propval, uint_t cnt, uint_t flags);
81f4b3ec61Sdh155122 
82f4b3ec61Sdh155122 
83d62bc4baSyz147064 /*
84d62bc4baSyz147064  * The linkprop check() callback.
85d62bc4baSyz147064  * - propstrp:	property string array which keeps the property to be checked.
86d62bc4baSyz147064  * - cnt:	number of properties.
87d62bc4baSyz147064  * - propval:	return value; the property values of the given property strings.
88*e7801d59Ssowmini  *
89*e7801d59Ssowmini  * pd_check checks that the input values are valid. It does so by
90*e7801d59Ssowmini  * iteraring through the pd_modval list for the property. If
91*e7801d59Ssowmini  * the modifiable values cannot be expressed as a list, a pd_check
92*e7801d59Ssowmini  * specific to this property can be used. If the input values are
93*e7801d59Ssowmini  * verified to be valid, pd_check allocates a val_desc_t and fills it
94*e7801d59Ssowmini  * with either a val_desc_t found on the pd_modval list or something
95*e7801d59Ssowmini  * generated on the fly.
96d62bc4baSyz147064  */
97*e7801d59Ssowmini typedef dladm_status_t	pd_checkf_t(struct prop_desc *pd,
98*e7801d59Ssowmini 			    datalink_id_t, char **propstrp,
99*e7801d59Ssowmini 			    uint_t cnt, val_desc_t *propval);
100f4b3ec61Sdh155122 
101*e7801d59Ssowmini typedef struct dld_public_prop_s {
102*e7801d59Ssowmini 	dld_prop_id_t	pp_id;
103*e7801d59Ssowmini 	size_t		pp_valsize;
104*e7801d59Ssowmini 	char		*pp_name;
105*e7801d59Ssowmini 	char		*pp_desc;
106*e7801d59Ssowmini } dld_public_prop_t;
107*e7801d59Ssowmini 
108*e7801d59Ssowmini static dld_ioc_prop_t *dld_buf_alloc(size_t, datalink_id_t, const char *,
109*e7801d59Ssowmini 					dladm_status_t *);
110*e7801d59Ssowmini static dladm_status_t dld_set_prop(datalink_id_t, const char *, char **,
111*e7801d59Ssowmini 					uint_t, uint_t);
112*e7801d59Ssowmini static dladm_status_t dld_get_prop(datalink_id_t, const char *, char **,
113*e7801d59Ssowmini 					uint_t *, dladm_prop_type_t);
114d62bc4baSyz147064 static pd_getf_t	do_get_zone, do_get_autopush, do_get_rate_mod,
115d62bc4baSyz147064 			do_get_rate_prop, do_get_channel_prop,
116*e7801d59Ssowmini 			do_get_powermode_prop, do_get_radio_prop,
117*e7801d59Ssowmini 			dld_duplex_get, dld_speed_get, dld_status_get,
118*e7801d59Ssowmini 			dld_binary_get, dld_uint64_get, dld_flowctl_get;
119d62bc4baSyz147064 static pd_setf_t	do_set_zone, do_set_autopush, do_set_rate_prop,
120*e7801d59Ssowmini 			do_set_powermode_prop, do_set_radio_prop,
121*e7801d59Ssowmini 			dld_set_public_prop;
122*e7801d59Ssowmini static pd_checkf_t	do_check_zone, do_check_autopush, do_check_rate,
123*e7801d59Ssowmini 			dld_defmtu_check;
124f4b3ec61Sdh155122 
125f4b3ec61Sdh155122 typedef struct prop_desc {
126d62bc4baSyz147064 	/*
127d62bc4baSyz147064 	 * link property name
128d62bc4baSyz147064 	 */
129f4b3ec61Sdh155122 	char			*pd_name;
130d62bc4baSyz147064 
131d62bc4baSyz147064 	/*
132d62bc4baSyz147064 	 * default property value, can be set to { "", NULL }
133d62bc4baSyz147064 	 */
134f4b3ec61Sdh155122 	val_desc_t		pd_defval;
135d62bc4baSyz147064 
136d62bc4baSyz147064 	/*
137d62bc4baSyz147064 	 * list of optional property values, can be NULL.
138d62bc4baSyz147064 	 *
139d62bc4baSyz147064 	 * This is set to non-NULL if there is a list of possible property
140d62bc4baSyz147064 	 * values.  pd_optval would point to the array of possible values.
141d62bc4baSyz147064 	 */
142d62bc4baSyz147064 	val_desc_t		*pd_optval;
143d62bc4baSyz147064 
144d62bc4baSyz147064 	/*
145d62bc4baSyz147064 	 * count of the above optional property values. 0 if pd_optval is NULL.
146d62bc4baSyz147064 	 */
147d62bc4baSyz147064 	uint_t			pd_noptval;
148d62bc4baSyz147064 
149d62bc4baSyz147064 	/*
150d62bc4baSyz147064 	 * callback to set link property;
151d62bc4baSyz147064 	 * set to NULL if this property is read-only
152d62bc4baSyz147064 	 */
153f4b3ec61Sdh155122 	pd_setf_t		*pd_set;
154d62bc4baSyz147064 
155d62bc4baSyz147064 	/*
156d62bc4baSyz147064 	 * callback to get modifiable link property
157d62bc4baSyz147064 	 */
158f4b3ec61Sdh155122 	pd_getf_t		*pd_getmod;
159d62bc4baSyz147064 
160d62bc4baSyz147064 	/*
161d62bc4baSyz147064 	 * callback to get current link property
162d62bc4baSyz147064 	 */
163f4b3ec61Sdh155122 	pd_getf_t		*pd_get;
164d62bc4baSyz147064 
165d62bc4baSyz147064 	/*
166d62bc4baSyz147064 	 * callback to validate link property value, set to NULL if pd_optval
167d62bc4baSyz147064 	 * is not NULL. In that case, validate the value by comparing it with
168d62bc4baSyz147064 	 * the pd_optval. Return a val_desc_t array pointer if the value is
169d62bc4baSyz147064 	 * valid.
170d62bc4baSyz147064 	 */
171f4b3ec61Sdh155122 	pd_checkf_t		*pd_check;
172d62bc4baSyz147064 
173d62bc4baSyz147064 	uint_t			pd_flags;
174*e7801d59Ssowmini #define	PD_TEMPONLY	0x1	/* property is temporary only */
175*e7801d59Ssowmini #define	PD_CHECK_ALLOC	0x2	/* alloc vd_val as part of pd_check */
176d62bc4baSyz147064 	/*
177d62bc4baSyz147064 	 * indicate link classes this property applies to.
178d62bc4baSyz147064 	 */
179d62bc4baSyz147064 	datalink_class_t	pd_class;
180d62bc4baSyz147064 
181d62bc4baSyz147064 	/*
182d62bc4baSyz147064 	 * indicate link media type this property applies to.
183d62bc4baSyz147064 	 */
184d62bc4baSyz147064 	datalink_media_t	pd_dmedia;
185f4b3ec61Sdh155122 } prop_desc_t;
186f4b3ec61Sdh155122 
187*e7801d59Ssowmini #define	DLD_PROPBUF_SIZE(v)	sizeof (dld_ioc_prop_t) + (v) - 1
188*e7801d59Ssowmini 
189*e7801d59Ssowmini 
190*e7801d59Ssowmini static dld_public_prop_t dld_prop[] = {
191*e7801d59Ssowmini 	{ DLD_PROP_DUPLEX,	sizeof (uint8_t),
192*e7801d59Ssowmini 	    "link_duplex",	"link duplex mode" },
193*e7801d59Ssowmini 
194*e7801d59Ssowmini 	{DLD_PROP_SPEED,	sizeof (uint8_t),
195*e7801d59Ssowmini 	    "ifspeed",		"link speed (Mbps)" },
196*e7801d59Ssowmini 
197*e7801d59Ssowmini 	{ DLD_PROP_STATUS,	sizeof (uint8_t),
198*e7801d59Ssowmini 	    "link_up",		"link up/down" },
199*e7801d59Ssowmini 
200*e7801d59Ssowmini 	{ DLD_PROP_AUTONEG,	sizeof (uint8_t),
201*e7801d59Ssowmini 	    "adv_autoneg_cap",	"Advertised auto-negotiation" },
202*e7801d59Ssowmini 
203*e7801d59Ssowmini 	{ DLD_PROP_DEFMTU,	sizeof (uint64_t),
204*e7801d59Ssowmini 	    "default_mtu",	"default frame mtu" },
205*e7801d59Ssowmini 
206*e7801d59Ssowmini 	{ DLD_PROP_FLOWCTRL,	sizeof (link_flowctrl_t),
207*e7801d59Ssowmini 	    "flowctrl",		"flowcontrol" },
208*e7801d59Ssowmini 
209*e7801d59Ssowmini 	{ DLD_PROP_ADV_1000FDX_CAP, sizeof (uint8_t),
210*e7801d59Ssowmini 	    "adv_1000fdx_cap",	"Adv 1000 Mbps fdx" },
211*e7801d59Ssowmini 
212*e7801d59Ssowmini 	{ DLD_PROP_EN_1000FDX_CAP, sizeof (uint8_t),
213*e7801d59Ssowmini 	    "en_1000fdx_cap",	"Enable 1000 Mbps fdx" },
214*e7801d59Ssowmini 
215*e7801d59Ssowmini 	{ DLD_PROP_ADV_1000HDX_CAP, sizeof (uint8_t),
216*e7801d59Ssowmini 	    "adv_1000hdx_cap", "Adv 1000 Mbps hdx" },
217*e7801d59Ssowmini 
218*e7801d59Ssowmini 	{ DLD_PROP_EN_1000HDX_CAP, sizeof (uint8_t),
219*e7801d59Ssowmini 	    "en_1000hdx_cap",	"Enable 1000 Mbps hdx" },
220*e7801d59Ssowmini 
221*e7801d59Ssowmini 	{ DLD_PROP_ADV_100FDX_CAP, sizeof (uint8_t),
222*e7801d59Ssowmini 	    "adv_100fdx_cap",	"Adv 100 Mbps fdx" },
223*e7801d59Ssowmini 
224*e7801d59Ssowmini 	{ DLD_PROP_EN_100FDX_CAP, sizeof (uint8_t),
225*e7801d59Ssowmini 	    "en_100fdx_cap",	"Enable 100 Mbps fdx" },
226*e7801d59Ssowmini 
227*e7801d59Ssowmini 	{ DLD_PROP_ADV_100HDX_CAP, sizeof (uint8_t),
228*e7801d59Ssowmini 	    "adv_100hdx_cap",	"Adv 100 Mbps hdx" },
229*e7801d59Ssowmini 
230*e7801d59Ssowmini 	{ DLD_PROP_EN_100HDX_CAP, sizeof (uint8_t),
231*e7801d59Ssowmini 	    "en_100hdx_cap",	"Enable 100 Mbps hdx" },
232*e7801d59Ssowmini 
233*e7801d59Ssowmini 	{ DLD_PROP_ADV_10FDX_CAP, sizeof (uint8_t),
234*e7801d59Ssowmini 	    "adv_10fdx_cap",	"Adv 10 Mbps fdx" },
235*e7801d59Ssowmini 
236*e7801d59Ssowmini 	{ DLD_PROP_EN_10FDX_CAP, sizeof (uint8_t),
237*e7801d59Ssowmini 	    "en_10fdx_cap",	"Enable 10 Mbps fdx" },
238*e7801d59Ssowmini 
239*e7801d59Ssowmini 	{ DLD_PROP_ADV_10HDX_CAP, sizeof (uint8_t),
240*e7801d59Ssowmini 	    "adv_10hdx_cap",	"Adv 10 Mbps hdx" },
241*e7801d59Ssowmini 
242*e7801d59Ssowmini 	{ DLD_PROP_EN_10HDX_CAP, sizeof (uint8_t),
243*e7801d59Ssowmini 	    "en_10hdx_cap",	"Enable 10 Mbps hdx" },
244*e7801d59Ssowmini 
245*e7801d59Ssowmini 	{ DLD_PROP_PRIVATE, 0,
246*e7801d59Ssowmini 	    "driver-private",	"" }
247*e7801d59Ssowmini };
248*e7801d59Ssowmini 
249*e7801d59Ssowmini static  val_desc_t	link_duplex_vals[] = {
250*e7801d59Ssowmini 	{ "half", 	LINK_DUPLEX_HALF	},
251*e7801d59Ssowmini 	{ "full", 	LINK_DUPLEX_HALF	}
252*e7801d59Ssowmini };
253*e7801d59Ssowmini static  val_desc_t	link_speed_vals[] = {
254*e7801d59Ssowmini 	{ "10",		10			},
255*e7801d59Ssowmini 	{ "100",	100			},
256*e7801d59Ssowmini 	{ "1000",	1000			}
257*e7801d59Ssowmini };
258*e7801d59Ssowmini static  val_desc_t	link_status_vals[] = {
259*e7801d59Ssowmini 	{ "up",		LINK_STATE_UP		},
260*e7801d59Ssowmini 	{ "down",	LINK_STATE_DOWN		}
261*e7801d59Ssowmini };
262*e7801d59Ssowmini static  val_desc_t	link_01_vals[] = {
263*e7801d59Ssowmini 	{ "1",		1			},
264*e7801d59Ssowmini 	{ "0",		0			}
265*e7801d59Ssowmini };
266*e7801d59Ssowmini static  val_desc_t	link_flow_vals[] = {
267*e7801d59Ssowmini 	{ "no",		LINK_FLOWCTRL_NONE	},
268*e7801d59Ssowmini 	{ "tx",		LINK_FLOWCTRL_TX	},
269*e7801d59Ssowmini 	{ "rx",		LINK_FLOWCTRL_RX	},
270*e7801d59Ssowmini 	{ "bi",		LINK_FLOWCTRL_BI	}
271*e7801d59Ssowmini };
272*e7801d59Ssowmini static  val_desc_t	macdefaultmtu_vals[] = {
273*e7801d59Ssowmini 	{ "68-9000",	NULL			}
274*e7801d59Ssowmini };
275*e7801d59Ssowmini 
276*e7801d59Ssowmini #define	VALCNT(vals)    (sizeof ((vals)) / sizeof (val_desc_t))
277*e7801d59Ssowmini 
278d62bc4baSyz147064 static val_desc_t	dladm_wlan_radio_vals[] = {
279d62bc4baSyz147064 	{ "on",		DLADM_WLAN_RADIO_ON	},
280d62bc4baSyz147064 	{ "off",	DLADM_WLAN_RADIO_OFF	}
281d62bc4baSyz147064 };
282d62bc4baSyz147064 
283d62bc4baSyz147064 static val_desc_t	dladm_wlan_powermode_vals[] = {
284d62bc4baSyz147064 	{ "off",	DLADM_WLAN_PM_OFF	},
285d62bc4baSyz147064 	{ "fast",	DLADM_WLAN_PM_FAST	},
286d62bc4baSyz147064 	{ "max",	DLADM_WLAN_PM_MAX	}
287d62bc4baSyz147064 };
288d62bc4baSyz147064 
289f4b3ec61Sdh155122 static prop_desc_t	prop_table[] = {
290d62bc4baSyz147064 
291*e7801d59Ssowmini 	{ "channel",	{ NULL, 0 },
292*e7801d59Ssowmini 	    NULL, 0, NULL, NULL,
293d62bc4baSyz147064 	    do_get_channel_prop, NULL, 0,
294d62bc4baSyz147064 	    DATALINK_CLASS_PHYS, DL_WIFI },
295d62bc4baSyz147064 
296d62bc4baSyz147064 	{ "powermode",	{ "off", DLADM_WLAN_PM_OFF },
297d62bc4baSyz147064 	    dladm_wlan_powermode_vals, VALCNT(dladm_wlan_powermode_vals),
298d62bc4baSyz147064 	    do_set_powermode_prop, NULL,
299d62bc4baSyz147064 	    do_get_powermode_prop, NULL, 0,
300d62bc4baSyz147064 	    DATALINK_CLASS_PHYS, DL_WIFI },
301d62bc4baSyz147064 
302d62bc4baSyz147064 	{ "radio",	{ "on", DLADM_WLAN_RADIO_ON },
303d62bc4baSyz147064 	    dladm_wlan_radio_vals, VALCNT(dladm_wlan_radio_vals),
304d62bc4baSyz147064 	    do_set_radio_prop, NULL,
305d62bc4baSyz147064 	    do_get_radio_prop, NULL, 0,
306d62bc4baSyz147064 	    DATALINK_CLASS_PHYS, DL_WIFI },
307d62bc4baSyz147064 
308d62bc4baSyz147064 	{ "speed",	{ "", 0 }, NULL, 0,
309d62bc4baSyz147064 	    do_set_rate_prop, do_get_rate_mod,
310d62bc4baSyz147064 	    do_get_rate_prop, do_check_rate, 0,
311d62bc4baSyz147064 	    DATALINK_CLASS_PHYS, DL_WIFI },
312d62bc4baSyz147064 
313d62bc4baSyz147064 	{ "autopush",	{ "", NULL }, NULL, 0,
314d62bc4baSyz147064 	    do_set_autopush, NULL,
315*e7801d59Ssowmini 	    do_get_autopush, do_check_autopush, PD_CHECK_ALLOC,
316d62bc4baSyz147064 	    DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
317d62bc4baSyz147064 
318d62bc4baSyz147064 	{ "zone",	{ "", NULL }, NULL, 0,
319f4b3ec61Sdh155122 	    do_set_zone, NULL,
320d62bc4baSyz147064 	    do_get_zone, do_check_zone, PD_TEMPONLY,
321*e7801d59Ssowmini 	    DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
322*e7801d59Ssowmini 
323*e7801d59Ssowmini 	{ "link_duplex", { "full", LINK_DUPLEX_FULL },
324*e7801d59Ssowmini 	    link_duplex_vals, VALCNT(link_duplex_vals),
325*e7801d59Ssowmini 	    NULL, NULL, dld_duplex_get, NULL,
326*e7801d59Ssowmini 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
327*e7801d59Ssowmini 
328*e7801d59Ssowmini 	{ "ifspeed", { "1000", 1000 },
329*e7801d59Ssowmini 	    link_speed_vals, VALCNT(link_speed_vals),
330*e7801d59Ssowmini 	    NULL, NULL, dld_speed_get, NULL,
331*e7801d59Ssowmini 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
332*e7801d59Ssowmini 
333*e7801d59Ssowmini 	{ "link_up", { "up", LINK_STATE_UP },
334*e7801d59Ssowmini 	    link_status_vals, VALCNT(link_status_vals),
335*e7801d59Ssowmini 	    NULL, NULL, dld_status_get, NULL,
336*e7801d59Ssowmini 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
337*e7801d59Ssowmini 
338*e7801d59Ssowmini 	{ "adv_autoneg_cap", { "1", 1 },
339*e7801d59Ssowmini 	    link_01_vals, VALCNT(link_01_vals),
340*e7801d59Ssowmini 	    dld_set_public_prop, NULL, dld_binary_get, NULL,
341*e7801d59Ssowmini 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
342*e7801d59Ssowmini 
343*e7801d59Ssowmini 	{ "default_mtu", { NULL, NULL },
344*e7801d59Ssowmini 	    macdefaultmtu_vals, VALCNT(macdefaultmtu_vals),
345*e7801d59Ssowmini 	    dld_set_public_prop, NULL, dld_uint64_get, dld_defmtu_check,
346*e7801d59Ssowmini 	    PD_CHECK_ALLOC, DATALINK_CLASS_PHYS, DL_ETHER },
347*e7801d59Ssowmini 
348*e7801d59Ssowmini 	{ "flowctrl", { "bi", LINK_FLOWCTRL_BI },
349*e7801d59Ssowmini 	    link_flow_vals, VALCNT(link_flow_vals),
350*e7801d59Ssowmini 	    dld_set_public_prop, NULL, dld_flowctl_get, NULL,
351*e7801d59Ssowmini 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
352*e7801d59Ssowmini 
353*e7801d59Ssowmini 	{ "adv_1000fdx_cap", { NULL, NULL },
354*e7801d59Ssowmini 	    link_01_vals, 0,
355*e7801d59Ssowmini 	    NULL, NULL, dld_binary_get, NULL,
356*e7801d59Ssowmini 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
357*e7801d59Ssowmini 
358*e7801d59Ssowmini 	{ "en_1000fdx_cap", { NULL, NULL },
359*e7801d59Ssowmini 	    link_01_vals, VALCNT(link_01_vals),
360*e7801d59Ssowmini 	    dld_set_public_prop, NULL, dld_binary_get, NULL,
361*e7801d59Ssowmini 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
362*e7801d59Ssowmini 
363*e7801d59Ssowmini 	{ "adv_1000hdx_cap", { NULL, NULL },
364*e7801d59Ssowmini 	    link_01_vals, VALCNT(link_01_vals),
365*e7801d59Ssowmini 	    NULL, NULL, dld_binary_get, NULL,
366*e7801d59Ssowmini 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
367*e7801d59Ssowmini 
368*e7801d59Ssowmini 	{ "en_1000hdx_cap", { NULL, NULL },
369*e7801d59Ssowmini 	    link_01_vals, VALCNT(link_01_vals),
370*e7801d59Ssowmini 	    dld_set_public_prop, NULL, dld_binary_get, NULL,
371*e7801d59Ssowmini 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
372*e7801d59Ssowmini 
373*e7801d59Ssowmini 	{ "adv_100fdx_cap", { NULL, NULL },
374*e7801d59Ssowmini 	    link_01_vals, VALCNT(link_01_vals),
375*e7801d59Ssowmini 	    NULL, NULL, dld_binary_get, NULL,
376*e7801d59Ssowmini 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
377*e7801d59Ssowmini 
378*e7801d59Ssowmini 	{ "en_100fdx_cap", { NULL, NULL },
379*e7801d59Ssowmini 	    link_01_vals, VALCNT(link_01_vals),
380*e7801d59Ssowmini 	    dld_set_public_prop, NULL, dld_binary_get, NULL,
381*e7801d59Ssowmini 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
382*e7801d59Ssowmini 
383*e7801d59Ssowmini 	{ "adv_100hdx_cap", { NULL, NULL },
384*e7801d59Ssowmini 	    link_01_vals, VALCNT(link_01_vals),
385*e7801d59Ssowmini 	    NULL, NULL, dld_binary_get, NULL,
386*e7801d59Ssowmini 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
387*e7801d59Ssowmini 
388*e7801d59Ssowmini 	{ "en_100hdx_cap", { NULL, NULL },
389*e7801d59Ssowmini 	    link_01_vals, VALCNT(link_01_vals),
390*e7801d59Ssowmini 	    dld_set_public_prop, NULL, dld_binary_get, NULL,
391*e7801d59Ssowmini 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
392*e7801d59Ssowmini 
393*e7801d59Ssowmini 	{ "adv_10fdx_cap", { NULL, NULL },
394*e7801d59Ssowmini 	    link_01_vals, VALCNT(link_01_vals),
395*e7801d59Ssowmini 	    NULL, NULL, dld_binary_get, NULL,
396*e7801d59Ssowmini 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
397*e7801d59Ssowmini 
398*e7801d59Ssowmini 	{ "en_10fdx_cap", { NULL, NULL },
399*e7801d59Ssowmini 	    link_01_vals, VALCNT(link_01_vals),
400*e7801d59Ssowmini 	    dld_set_public_prop, NULL, dld_binary_get, NULL,
401*e7801d59Ssowmini 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
402*e7801d59Ssowmini 
403*e7801d59Ssowmini 	{ "adv_10hdx_cap", { NULL, NULL },
404*e7801d59Ssowmini 	    link_01_vals, VALCNT(link_01_vals),
405*e7801d59Ssowmini 	    NULL, NULL, dld_binary_get, NULL,
406*e7801d59Ssowmini 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
407*e7801d59Ssowmini 
408*e7801d59Ssowmini 	{ "en_10hdx_cap", { NULL, NULL },
409*e7801d59Ssowmini 	    link_01_vals, VALCNT(link_01_vals),
410*e7801d59Ssowmini 	    dld_set_public_prop, NULL, dld_binary_get, NULL,
411*e7801d59Ssowmini 	    0, DATALINK_CLASS_PHYS, DL_ETHER }
412*e7801d59Ssowmini 
413f4b3ec61Sdh155122 };
414f4b3ec61Sdh155122 
415d62bc4baSyz147064 #define	DLADM_MAX_PROPS	(sizeof (prop_table) / sizeof (prop_desc_t))
4160ba2cbe9Sxc151355 
417d62bc4baSyz147064 static dladm_status_t	i_dladm_set_linkprop_db(datalink_id_t, const char *,
418d62bc4baSyz147064 			    char **, uint_t);
419d62bc4baSyz147064 static dladm_status_t	i_dladm_get_linkprop_db(datalink_id_t, const char *,
420d62bc4baSyz147064 			    char **, uint_t *);
421d62bc4baSyz147064 static dladm_status_t	i_dladm_set_single_prop(datalink_id_t, datalink_class_t,
422d62bc4baSyz147064 			    uint32_t, prop_desc_t *, char **, uint_t, uint_t);
423d62bc4baSyz147064 static dladm_status_t	i_dladm_set_linkprop(datalink_id_t, const char *,
424d62bc4baSyz147064 			    char **, uint_t, uint_t);
425d62bc4baSyz147064 
426d62bc4baSyz147064 /*
427d62bc4baSyz147064  * Unfortunately, MAX_SCAN_SUPPORT_RATES is too small to allow all
428d62bc4baSyz147064  * rates to be retrieved. However, we cannot increase it at this
429d62bc4baSyz147064  * time because it will break binary compatibility with unbundled
430d62bc4baSyz147064  * WiFi drivers and utilities. So for now we define an additional
431d62bc4baSyz147064  * constant, MAX_SUPPORT_RATES, to allow all rates to be retrieved.
432d62bc4baSyz147064  */
433d62bc4baSyz147064 #define	MAX_SUPPORT_RATES	64
434d62bc4baSyz147064 
435d62bc4baSyz147064 #define	AP_ANCHOR	"[anchor]"
436d62bc4baSyz147064 #define	AP_DELIMITER	'.'
437d62bc4baSyz147064 
438d62bc4baSyz147064 static dladm_status_t
439d62bc4baSyz147064 do_check_prop(prop_desc_t *pdp, char **prop_val, uint_t val_cnt,
440d62bc4baSyz147064     val_desc_t *vdp)
4410ba2cbe9Sxc151355 {
442d62bc4baSyz147064 	int		i, j;
4430ba2cbe9Sxc151355 	dladm_status_t	status = DLADM_STATUS_OK;
4440ba2cbe9Sxc151355 
445d62bc4baSyz147064 	for (j = 0; j < val_cnt; j++) {
446d62bc4baSyz147064 		for (i = 0; i < pdp->pd_noptval; i++) {
447d62bc4baSyz147064 			if (strcasecmp(*prop_val,
448d62bc4baSyz147064 			    pdp->pd_optval[i].vd_name) == 0) {
4490ba2cbe9Sxc151355 				break;
4500ba2cbe9Sxc151355 			}
4510ba2cbe9Sxc151355 		}
452d62bc4baSyz147064 		if (i == pdp->pd_noptval) {
453d62bc4baSyz147064 			status = DLADM_STATUS_BADVAL;
454d62bc4baSyz147064 			goto done;
455d62bc4baSyz147064 		}
456d62bc4baSyz147064 		(void) memcpy(vdp + j, &pdp->pd_optval[i], sizeof (val_desc_t));
4570ba2cbe9Sxc151355 	}
4580ba2cbe9Sxc151355 
459d62bc4baSyz147064 done:
460d62bc4baSyz147064 	return (status);
4610ba2cbe9Sxc151355 }
4620ba2cbe9Sxc151355 
4630ba2cbe9Sxc151355 static dladm_status_t
464d62bc4baSyz147064 i_dladm_set_single_prop(datalink_id_t linkid, datalink_class_t class,
465d62bc4baSyz147064     uint32_t media, prop_desc_t *pdp, char **prop_val, uint_t val_cnt,
466d62bc4baSyz147064     uint_t flags)
4670ba2cbe9Sxc151355 {
4680ba2cbe9Sxc151355 	dladm_status_t	status = DLADM_STATUS_OK;
469d62bc4baSyz147064 	val_desc_t	*vdp = NULL;
470d62bc4baSyz147064 	boolean_t	needfree = B_FALSE;
471d62bc4baSyz147064 	uint_t		cnt, i;
4720ba2cbe9Sxc151355 
473d62bc4baSyz147064 	if (!(pdp->pd_class & class))
474d62bc4baSyz147064 		return (DLADM_STATUS_BADARG);
4750ba2cbe9Sxc151355 
476d62bc4baSyz147064 	if (!DATALINK_MEDIA_ACCEPTED(pdp->pd_dmedia, media))
477d62bc4baSyz147064 		return (DLADM_STATUS_BADARG);
478d62bc4baSyz147064 
479d62bc4baSyz147064 	if ((flags & DLADM_OPT_PERSIST) && (pdp->pd_flags & PD_TEMPONLY))
480d62bc4baSyz147064 		return (DLADM_STATUS_TEMPONLY);
481d62bc4baSyz147064 
482d62bc4baSyz147064 	if (!(flags & DLADM_OPT_ACTIVE))
483d62bc4baSyz147064 		return (DLADM_STATUS_OK);
484d62bc4baSyz147064 
485d62bc4baSyz147064 	if (pdp->pd_set == NULL)
486d62bc4baSyz147064 		return (DLADM_STATUS_PROPRDONLY);
487d62bc4baSyz147064 
488*e7801d59Ssowmini 	if (pdp->pd_flags & PD_CHECK_ALLOC)
489*e7801d59Ssowmini 		needfree = B_TRUE;
490*e7801d59Ssowmini 	else
491*e7801d59Ssowmini 		needfree = B_FALSE;
492d62bc4baSyz147064 	if (prop_val != NULL) {
493d62bc4baSyz147064 		vdp = malloc(sizeof (val_desc_t) * val_cnt);
494d62bc4baSyz147064 		if (vdp == NULL)
495d62bc4baSyz147064 			return (DLADM_STATUS_NOMEM);
496d62bc4baSyz147064 
497*e7801d59Ssowmini 
498d62bc4baSyz147064 		if (pdp->pd_check != NULL) {
499*e7801d59Ssowmini 			status = pdp->pd_check(pdp, linkid, prop_val, val_cnt,
500*e7801d59Ssowmini 			    vdp);
501d62bc4baSyz147064 		} else if (pdp->pd_optval != NULL) {
502d62bc4baSyz147064 			status = do_check_prop(pdp, prop_val, val_cnt, vdp);
503d62bc4baSyz147064 		} else {
504d62bc4baSyz147064 			status = DLADM_STATUS_BADARG;
5050ba2cbe9Sxc151355 		}
5060ba2cbe9Sxc151355 
507d62bc4baSyz147064 		if (status != DLADM_STATUS_OK)
508d62bc4baSyz147064 			goto done;
509d62bc4baSyz147064 
510d62bc4baSyz147064 		cnt = val_cnt;
511d62bc4baSyz147064 	} else {
512d62bc4baSyz147064 		if (pdp->pd_defval.vd_name == NULL)
513d62bc4baSyz147064 			return (DLADM_STATUS_NOTSUP);
514d62bc4baSyz147064 
515d62bc4baSyz147064 		if ((vdp = malloc(sizeof (val_desc_t))) == NULL)
516d62bc4baSyz147064 			return (DLADM_STATUS_NOMEM);
517d62bc4baSyz147064 
518d62bc4baSyz147064 		(void) memcpy(vdp, &pdp->pd_defval, sizeof (val_desc_t));
519d62bc4baSyz147064 		cnt = 1;
520d62bc4baSyz147064 	}
521*e7801d59Ssowmini 	status = pdp->pd_set(pdp, linkid, vdp, cnt, flags);
522d62bc4baSyz147064 	if (needfree) {
523d62bc4baSyz147064 		for (i = 0; i < cnt; i++)
524*e7801d59Ssowmini 			free((void *)((val_desc_t *)vdp + i)->vd_val);
525d62bc4baSyz147064 	}
526d62bc4baSyz147064 done:
527d62bc4baSyz147064 	free(vdp);
528d62bc4baSyz147064 	return (status);
529d62bc4baSyz147064 }
530d62bc4baSyz147064 
531d62bc4baSyz147064 static dladm_status_t
532d62bc4baSyz147064 i_dladm_set_linkprop(datalink_id_t linkid, const char *prop_name,
533d62bc4baSyz147064     char **prop_val, uint_t val_cnt, uint_t flags)
534d62bc4baSyz147064 {
535d62bc4baSyz147064 	int			i;
536d62bc4baSyz147064 	boolean_t		found = B_FALSE;
537d62bc4baSyz147064 	datalink_class_t	class;
538d62bc4baSyz147064 	uint32_t		media;
539d62bc4baSyz147064 	dladm_status_t		status = DLADM_STATUS_OK;
540d62bc4baSyz147064 
541d62bc4baSyz147064 	status = dladm_datalink_id2info(linkid, NULL, &class, &media, NULL, 0);
542d62bc4baSyz147064 	if (status != DLADM_STATUS_OK)
5430ba2cbe9Sxc151355 		return (status);
5440ba2cbe9Sxc151355 
545d62bc4baSyz147064 	for (i = 0; i < DLADM_MAX_PROPS; i++) {
546d62bc4baSyz147064 		prop_desc_t	*pdp = &prop_table[i];
547d62bc4baSyz147064 		dladm_status_t	s;
5480ba2cbe9Sxc151355 
549d62bc4baSyz147064 		if (prop_name != NULL &&
550d62bc4baSyz147064 		    (strcasecmp(prop_name, pdp->pd_name) != 0))
551d62bc4baSyz147064 			continue;
552d62bc4baSyz147064 
553d62bc4baSyz147064 		found = B_TRUE;
554d62bc4baSyz147064 		s = i_dladm_set_single_prop(linkid, class, media, pdp, prop_val,
555d62bc4baSyz147064 		    val_cnt, flags);
556d62bc4baSyz147064 
557d62bc4baSyz147064 		if (prop_name != NULL) {
558d62bc4baSyz147064 			status = s;
559d62bc4baSyz147064 			break;
560d62bc4baSyz147064 		} else {
561d62bc4baSyz147064 			if (s != DLADM_STATUS_OK &&
562d62bc4baSyz147064 			    s != DLADM_STATUS_NOTSUP)
563d62bc4baSyz147064 				status = s;
564d62bc4baSyz147064 		}
565d62bc4baSyz147064 	}
566*e7801d59Ssowmini 	if (!found) {
567*e7801d59Ssowmini 		if (prop_name[0] == '_') {
568*e7801d59Ssowmini 			/* other private properties */
569*e7801d59Ssowmini 			status = dld_set_prop(linkid, prop_name, prop_val,
570*e7801d59Ssowmini 			    val_cnt, flags);
571*e7801d59Ssowmini 		} else  {
5720ba2cbe9Sxc151355 			status = DLADM_STATUS_NOTFOUND;
573*e7801d59Ssowmini 		}
574*e7801d59Ssowmini 	}
5750ba2cbe9Sxc151355 
5760ba2cbe9Sxc151355 	return (status);
5770ba2cbe9Sxc151355 }
5780ba2cbe9Sxc151355 
579d62bc4baSyz147064 /*
580d62bc4baSyz147064  * Set/reset link property for specific link
581d62bc4baSyz147064  */
582d62bc4baSyz147064 dladm_status_t
583d62bc4baSyz147064 dladm_set_linkprop(datalink_id_t linkid, const char *prop_name, char **prop_val,
584d62bc4baSyz147064     uint_t val_cnt, uint_t flags)
5850ba2cbe9Sxc151355 {
586d62bc4baSyz147064 	dladm_status_t	status = DLADM_STATUS_OK;
5870ba2cbe9Sxc151355 
588d62bc4baSyz147064 	if ((linkid == DATALINK_INVALID_LINKID) || (flags == 0) ||
589d62bc4baSyz147064 	    (prop_val == NULL && val_cnt > 0) ||
590d62bc4baSyz147064 	    (prop_val != NULL && val_cnt == 0) ||
591d62bc4baSyz147064 	    (prop_name == NULL && prop_val != NULL)) {
592d62bc4baSyz147064 		return (DLADM_STATUS_BADARG);
5930ba2cbe9Sxc151355 	}
5940ba2cbe9Sxc151355 
595d62bc4baSyz147064 	status = i_dladm_set_linkprop(linkid, prop_name, prop_val,
596d62bc4baSyz147064 	    val_cnt, flags);
597d62bc4baSyz147064 	if (status != DLADM_STATUS_OK)
598d62bc4baSyz147064 		return (status);
599d62bc4baSyz147064 
600d62bc4baSyz147064 	if (flags & DLADM_OPT_PERSIST) {
601d62bc4baSyz147064 		status = i_dladm_set_linkprop_db(linkid, prop_name,
602d62bc4baSyz147064 		    prop_val, val_cnt);
603d62bc4baSyz147064 	}
604d62bc4baSyz147064 	return (status);
605d62bc4baSyz147064 }
606d62bc4baSyz147064 
607d62bc4baSyz147064 /*
608d62bc4baSyz147064  * Walk link properties of the given specific link.
609d62bc4baSyz147064  */
610d62bc4baSyz147064 dladm_status_t
611d62bc4baSyz147064 dladm_walk_linkprop(datalink_id_t linkid, void *arg,
612d62bc4baSyz147064     int (*func)(datalink_id_t, const char *, void *))
6130ba2cbe9Sxc151355 {
614d62bc4baSyz147064 	dladm_status_t		status;
615d62bc4baSyz147064 	datalink_class_t	class;
616d62bc4baSyz147064 	uint_t			media;
617d62bc4baSyz147064 	int			i;
6180ba2cbe9Sxc151355 
619d62bc4baSyz147064 	if (linkid == DATALINK_INVALID_LINKID || func == NULL)
620d62bc4baSyz147064 		return (DLADM_STATUS_BADARG);
6210ba2cbe9Sxc151355 
622d62bc4baSyz147064 	status = dladm_datalink_id2info(linkid, NULL, &class, &media, NULL, 0);
623d62bc4baSyz147064 	if (status != DLADM_STATUS_OK)
624d62bc4baSyz147064 		return (status);
625d62bc4baSyz147064 
626d62bc4baSyz147064 	for (i = 0; i < DLADM_MAX_PROPS; i++) {
627d62bc4baSyz147064 		if (!(prop_table[i].pd_class & class))
628d62bc4baSyz147064 			continue;
629d62bc4baSyz147064 
630d62bc4baSyz147064 		if (!DATALINK_MEDIA_ACCEPTED(prop_table[i].pd_dmedia, media))
631d62bc4baSyz147064 			continue;
632d62bc4baSyz147064 
633d62bc4baSyz147064 		if (func(linkid, prop_table[i].pd_name, arg) ==
634d62bc4baSyz147064 		    DLADM_WALK_TERMINATE) {
635d62bc4baSyz147064 			break;
636d62bc4baSyz147064 		}
637d62bc4baSyz147064 	}
638d62bc4baSyz147064 
639d62bc4baSyz147064 	return (DLADM_STATUS_OK);
640d62bc4baSyz147064 }
641d62bc4baSyz147064 
642d62bc4baSyz147064 /*
643d62bc4baSyz147064  * Get linkprop of the given specific link.
644d62bc4baSyz147064  */
645d62bc4baSyz147064 dladm_status_t
646d62bc4baSyz147064 dladm_get_linkprop(datalink_id_t linkid, dladm_prop_type_t type,
647d62bc4baSyz147064     const char *prop_name, char **prop_val, uint_t *val_cntp)
648d62bc4baSyz147064 {
649d62bc4baSyz147064 	dladm_status_t		status = DLADM_STATUS_OK;
650d62bc4baSyz147064 	datalink_class_t	class;
651d62bc4baSyz147064 	uint_t			media;
652d62bc4baSyz147064 	prop_desc_t		*pdp;
653d62bc4baSyz147064 	uint_t			cnt;
654d62bc4baSyz147064 	int			i;
655d62bc4baSyz147064 
656d62bc4baSyz147064 	if (linkid == DATALINK_INVALID_LINKID || prop_name == NULL ||
657d62bc4baSyz147064 	    prop_val == NULL || val_cntp == NULL || *val_cntp == 0)
658d62bc4baSyz147064 		return (DLADM_STATUS_BADARG);
659d62bc4baSyz147064 
660d62bc4baSyz147064 	for (i = 0; i < DLADM_MAX_PROPS; i++)
661d62bc4baSyz147064 		if (strcasecmp(prop_name, prop_table[i].pd_name) == 0)
662d62bc4baSyz147064 			break;
663d62bc4baSyz147064 
664*e7801d59Ssowmini 	if (i == DLADM_MAX_PROPS) {
665*e7801d59Ssowmini 		if (prop_name[0] == '_') {
666*e7801d59Ssowmini 			/*
667*e7801d59Ssowmini 			 * private property.
668*e7801d59Ssowmini 			 */
669*e7801d59Ssowmini 			return (dld_get_prop(linkid, prop_name,
670*e7801d59Ssowmini 			    prop_val, val_cntp, type));
671*e7801d59Ssowmini 		} else {
672d62bc4baSyz147064 			return (DLADM_STATUS_NOTFOUND);
673*e7801d59Ssowmini 		}
674*e7801d59Ssowmini 	}
675d62bc4baSyz147064 
676d62bc4baSyz147064 	pdp = &prop_table[i];
677d62bc4baSyz147064 
678d62bc4baSyz147064 	status = dladm_datalink_id2info(linkid, NULL, &class, &media, NULL, 0);
679d62bc4baSyz147064 	if (status != DLADM_STATUS_OK)
680d62bc4baSyz147064 		return (status);
681d62bc4baSyz147064 
682d62bc4baSyz147064 	if (!(pdp->pd_class & class))
683d62bc4baSyz147064 		return (DLADM_STATUS_BADARG);
684d62bc4baSyz147064 
685d62bc4baSyz147064 	if (!DATALINK_MEDIA_ACCEPTED(pdp->pd_dmedia, media))
686d62bc4baSyz147064 		return (DLADM_STATUS_BADARG);
687d62bc4baSyz147064 
688d62bc4baSyz147064 	switch (type) {
689d62bc4baSyz147064 	case DLADM_PROP_VAL_CURRENT:
690*e7801d59Ssowmini 		status = pdp->pd_get(pdp, linkid, prop_val, val_cntp);
691d62bc4baSyz147064 		break;
692d62bc4baSyz147064 
693d62bc4baSyz147064 	case DLADM_PROP_VAL_DEFAULT:
694d62bc4baSyz147064 		if (pdp->pd_defval.vd_name == NULL) {
695d62bc4baSyz147064 			status = DLADM_STATUS_NOTSUP;
696d62bc4baSyz147064 			break;
697d62bc4baSyz147064 		}
698d62bc4baSyz147064 		(void) strcpy(*prop_val, pdp->pd_defval.vd_name);
699d62bc4baSyz147064 		*val_cntp = 1;
700d62bc4baSyz147064 		break;
701d62bc4baSyz147064 
702d62bc4baSyz147064 	case DLADM_PROP_VAL_MODIFIABLE:
703d62bc4baSyz147064 		if (pdp->pd_getmod != NULL) {
704*e7801d59Ssowmini 			status = pdp->pd_getmod(pdp, linkid, prop_val,
705*e7801d59Ssowmini 			    val_cntp);
706d62bc4baSyz147064 			break;
707d62bc4baSyz147064 		}
708d62bc4baSyz147064 		cnt = pdp->pd_noptval;
709d62bc4baSyz147064 		if (cnt == 0) {
710d62bc4baSyz147064 			status = DLADM_STATUS_NOTSUP;
711d62bc4baSyz147064 		} else if (cnt > *val_cntp) {
712d62bc4baSyz147064 			status = DLADM_STATUS_TOOSMALL;
713d62bc4baSyz147064 		} else {
714d62bc4baSyz147064 			for (i = 0; i < cnt; i++) {
715d62bc4baSyz147064 				(void) strcpy(prop_val[i],
716d62bc4baSyz147064 				    pdp->pd_optval[i].vd_name);
717d62bc4baSyz147064 			}
718d62bc4baSyz147064 			*val_cntp = cnt;
719d62bc4baSyz147064 		}
720d62bc4baSyz147064 		break;
721d62bc4baSyz147064 	case DLADM_PROP_VAL_PERSISTENT:
722d62bc4baSyz147064 		if (pdp->pd_flags & PD_TEMPONLY)
723d62bc4baSyz147064 			return (DLADM_STATUS_TEMPONLY);
724d62bc4baSyz147064 		status = i_dladm_get_linkprop_db(linkid, prop_name,
725d62bc4baSyz147064 		    prop_val, val_cntp);
726d62bc4baSyz147064 		break;
727d62bc4baSyz147064 	default:
728d62bc4baSyz147064 		status = DLADM_STATUS_BADARG;
729d62bc4baSyz147064 		break;
730d62bc4baSyz147064 	}
731d62bc4baSyz147064 
732d62bc4baSyz147064 	return (status);
733d62bc4baSyz147064 }
734d62bc4baSyz147064 
735d62bc4baSyz147064 /*ARGSUSED*/
736d62bc4baSyz147064 static int
737d62bc4baSyz147064 i_dladm_init_one_prop(datalink_id_t linkid, const char *prop_name, void *arg)
738d62bc4baSyz147064 {
739d62bc4baSyz147064 	char	*buf, **propvals;
740d62bc4baSyz147064 	uint_t	i, valcnt = DLADM_MAX_PROP_VALCNT;
741d62bc4baSyz147064 
742d62bc4baSyz147064 	if ((buf = malloc((sizeof (char *) + DLADM_PROP_VAL_MAX) *
743d62bc4baSyz147064 	    DLADM_MAX_PROP_VALCNT)) == NULL) {
744d62bc4baSyz147064 		return (DLADM_WALK_CONTINUE);
745d62bc4baSyz147064 	}
746d62bc4baSyz147064 
747d62bc4baSyz147064 	propvals = (char **)(void *)buf;
748d62bc4baSyz147064 	for (i = 0; i < valcnt; i++) {
749d62bc4baSyz147064 		propvals[i] = buf +
750d62bc4baSyz147064 		    sizeof (char *) * DLADM_MAX_PROP_VALCNT +
751d62bc4baSyz147064 		    i * DLADM_PROP_VAL_MAX;
752d62bc4baSyz147064 	}
753d62bc4baSyz147064 
754d62bc4baSyz147064 	if (dladm_get_linkprop(linkid, DLADM_PROP_VAL_PERSISTENT, prop_name,
755d62bc4baSyz147064 	    propvals, &valcnt) != DLADM_STATUS_OK) {
756d62bc4baSyz147064 		goto done;
757d62bc4baSyz147064 	}
758d62bc4baSyz147064 
759d62bc4baSyz147064 	(void) dladm_set_linkprop(linkid, prop_name, propvals, valcnt,
760d62bc4baSyz147064 	    DLADM_OPT_ACTIVE);
761d62bc4baSyz147064 
762d62bc4baSyz147064 done:
763d62bc4baSyz147064 	if (buf != NULL)
764d62bc4baSyz147064 		free(buf);
765d62bc4baSyz147064 
766d62bc4baSyz147064 	return (DLADM_WALK_CONTINUE);
767d62bc4baSyz147064 }
768d62bc4baSyz147064 
769d62bc4baSyz147064 /*ARGSUSED*/
770d62bc4baSyz147064 static int
771d62bc4baSyz147064 i_dladm_init_linkprop(datalink_id_t linkid, void *arg)
772d62bc4baSyz147064 {
773d62bc4baSyz147064 	(void) dladm_init_linkprop(linkid);
774d62bc4baSyz147064 	return (DLADM_WALK_CONTINUE);
7750ba2cbe9Sxc151355 }
7760ba2cbe9Sxc151355 
7770ba2cbe9Sxc151355 dladm_status_t
778d62bc4baSyz147064 dladm_init_linkprop(datalink_id_t linkid)
7790ba2cbe9Sxc151355 {
780d62bc4baSyz147064 	if (linkid == DATALINK_ALL_LINKID) {
781d62bc4baSyz147064 		(void) dladm_walk_datalink_id(i_dladm_init_linkprop, NULL,
782d62bc4baSyz147064 		    DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE,
783d62bc4baSyz147064 		    DLADM_OPT_PERSIST);
784d62bc4baSyz147064 	} else {
785d62bc4baSyz147064 		(void) dladm_walk_linkprop(linkid, NULL, i_dladm_init_one_prop);
786d62bc4baSyz147064 	}
787d62bc4baSyz147064 	return (DLADM_STATUS_OK);
7880ba2cbe9Sxc151355 }
789f4b3ec61Sdh155122 
790*e7801d59Ssowmini /* ARGSUSED */
791f4b3ec61Sdh155122 static dladm_status_t
792*e7801d59Ssowmini do_get_zone(struct prop_desc *pd, datalink_id_t linkid,
793*e7801d59Ssowmini     char **prop_val, uint_t *val_cnt)
794f4b3ec61Sdh155122 {
795d62bc4baSyz147064 	char		zone_name[ZONENAME_MAX];
796d62bc4baSyz147064 	zoneid_t	zid;
797d62bc4baSyz147064 	dladm_status_t	status;
798f4b3ec61Sdh155122 
799d62bc4baSyz147064 	status = dladm_getzid(linkid, &zid);
800d62bc4baSyz147064 	if (status != DLADM_STATUS_OK)
801d62bc4baSyz147064 		return (status);
802d62bc4baSyz147064 
803d62bc4baSyz147064 	*val_cnt = 1;
804d62bc4baSyz147064 	if (zid != GLOBAL_ZONEID) {
805d62bc4baSyz147064 		if (getzonenamebyid(zid, zone_name, sizeof (zone_name)) < 0)
806f4b3ec61Sdh155122 			return (dladm_errno2status(errno));
807f4b3ec61Sdh155122 
808d62bc4baSyz147064 		(void) strncpy(*prop_val, zone_name, DLADM_PROP_VAL_MAX);
80947a01978Sbw 	} else {
810d62bc4baSyz147064 		*prop_val[0] = '\0';
81147a01978Sbw 	}
812f4b3ec61Sdh155122 
813f4b3ec61Sdh155122 	return (DLADM_STATUS_OK);
814f4b3ec61Sdh155122 }
815f4b3ec61Sdh155122 
816f4b3ec61Sdh155122 typedef int (*zone_get_devroot_t)(char *, char *, size_t);
817f4b3ec61Sdh155122 
818f4b3ec61Sdh155122 static int
819f4b3ec61Sdh155122 i_dladm_get_zone_dev(char *zone_name, char *dev, size_t devlen)
820f4b3ec61Sdh155122 {
821f4b3ec61Sdh155122 	char			root[MAXPATHLEN];
822f4b3ec61Sdh155122 	zone_get_devroot_t	real_zone_get_devroot;
823f4b3ec61Sdh155122 	void			*dlhandle;
824f4b3ec61Sdh155122 	void			*sym;
825f4b3ec61Sdh155122 	int			ret;
826f4b3ec61Sdh155122 
827f4b3ec61Sdh155122 	if ((dlhandle = dlopen("libzonecfg.so.1", RTLD_LAZY)) == NULL)
828f4b3ec61Sdh155122 		return (-1);
829f4b3ec61Sdh155122 
830f4b3ec61Sdh155122 	if ((sym = dlsym(dlhandle, "zone_get_devroot")) == NULL) {
831f4b3ec61Sdh155122 		(void) dlclose(dlhandle);
832f4b3ec61Sdh155122 		return (-1);
833f4b3ec61Sdh155122 	}
834f4b3ec61Sdh155122 
835f4b3ec61Sdh155122 	real_zone_get_devroot = (zone_get_devroot_t)sym;
836f4b3ec61Sdh155122 
837f4b3ec61Sdh155122 	if ((ret = real_zone_get_devroot(zone_name, root, sizeof (root))) == 0)
838f4b3ec61Sdh155122 		(void) snprintf(dev, devlen, "%s%s", root, "/dev");
839f4b3ec61Sdh155122 	(void) dlclose(dlhandle);
840f4b3ec61Sdh155122 	return (ret);
841f4b3ec61Sdh155122 }
842f4b3ec61Sdh155122 
843f4b3ec61Sdh155122 static dladm_status_t
844d62bc4baSyz147064 i_dladm_update_deventry(zoneid_t zid, datalink_id_t linkid, boolean_t add)
845f4b3ec61Sdh155122 {
846f4b3ec61Sdh155122 	char		path[MAXPATHLEN];
847d62bc4baSyz147064 	char		name[MAXLINKNAMELEN];
848f4b3ec61Sdh155122 	di_prof_t	prof = NULL;
849f4b3ec61Sdh155122 	char		zone_name[ZONENAME_MAX];
850f4b3ec61Sdh155122 	dladm_status_t	status;
851d62bc4baSyz147064 	int		ret;
852f4b3ec61Sdh155122 
853f4b3ec61Sdh155122 	if (getzonenamebyid(zid, zone_name, sizeof (zone_name)) < 0)
854f4b3ec61Sdh155122 		return (dladm_errno2status(errno));
855f4b3ec61Sdh155122 	if (i_dladm_get_zone_dev(zone_name, path, sizeof (path)) != 0)
856f4b3ec61Sdh155122 		return (dladm_errno2status(errno));
857f4b3ec61Sdh155122 	if (di_prof_init(path, &prof) != 0)
858f4b3ec61Sdh155122 		return (dladm_errno2status(errno));
859f4b3ec61Sdh155122 
860d62bc4baSyz147064 	status = dladm_linkid2legacyname(linkid, name, MAXLINKNAMELEN);
861f4b3ec61Sdh155122 	if (status != DLADM_STATUS_OK)
862d62bc4baSyz147064 		goto cleanup;
863f4b3ec61Sdh155122 
864d62bc4baSyz147064 	if (add)
865d62bc4baSyz147064 		ret = di_prof_add_dev(prof, name);
866d62bc4baSyz147064 	else
867d62bc4baSyz147064 		ret = di_prof_add_exclude(prof, name);
868f4b3ec61Sdh155122 
869d62bc4baSyz147064 	if (ret != 0) {
870d62bc4baSyz147064 		status = dladm_errno2status(errno);
871d62bc4baSyz147064 		goto cleanup;
872f4b3ec61Sdh155122 	}
873f4b3ec61Sdh155122 
874d62bc4baSyz147064 	if (di_prof_commit(prof) != 0)
875d62bc4baSyz147064 		status = dladm_errno2status(errno);
876d62bc4baSyz147064 cleanup:
877d62bc4baSyz147064 	if (prof)
878d62bc4baSyz147064 		di_prof_fini(prof);
879d62bc4baSyz147064 
880d62bc4baSyz147064 	return (status);
881f4b3ec61Sdh155122 }
882f4b3ec61Sdh155122 
883*e7801d59Ssowmini /* ARGSUSED */
884f4b3ec61Sdh155122 static dladm_status_t
885*e7801d59Ssowmini do_set_zone(prop_desc_t *pd, datalink_id_t linkid,
886*e7801d59Ssowmini     val_desc_t *vdp, uint_t val_cnt, uint_t flags)
887f4b3ec61Sdh155122 {
888f4b3ec61Sdh155122 	dladm_status_t	status;
889f4b3ec61Sdh155122 	zoneid_t	zid_old, zid_new;
890d62bc4baSyz147064 	char		link[MAXLINKNAMELEN];
891f4b3ec61Sdh155122 
892f4b3ec61Sdh155122 	if (val_cnt != 1)
893f4b3ec61Sdh155122 		return (DLADM_STATUS_BADVALCNT);
894f4b3ec61Sdh155122 
895d62bc4baSyz147064 	status = dladm_getzid(linkid, &zid_old);
896f4b3ec61Sdh155122 	if (status != DLADM_STATUS_OK)
897f4b3ec61Sdh155122 		return (status);
898f4b3ec61Sdh155122 
899f4b3ec61Sdh155122 	/* Do nothing if setting to current value */
900d62bc4baSyz147064 	zid_new = vdp->vd_val;
901f4b3ec61Sdh155122 	if (zid_new == zid_old)
902f4b3ec61Sdh155122 		return (DLADM_STATUS_OK);
903f4b3ec61Sdh155122 
904d62bc4baSyz147064 	if ((status = dladm_datalink_id2info(linkid, NULL, NULL, NULL,
905d62bc4baSyz147064 	    link, MAXLINKNAMELEN)) != DLADM_STATUS_OK) {
906d62bc4baSyz147064 		return (status);
907d62bc4baSyz147064 	}
908f4b3ec61Sdh155122 
909d62bc4baSyz147064 	if (zid_new != GLOBAL_ZONEID) {
910d62bc4baSyz147064 		/*
911d62bc4baSyz147064 		 * If the new zoneid is the global zone, we could destroy
912d62bc4baSyz147064 		 * the link (in the case of an implicitly-created VLAN) as a
913d62bc4baSyz147064 		 * result of the dladm_setzid() operation. In that case,
914d62bc4baSyz147064 		 * we defer the operation to the end of this function to avoid
915d62bc4baSyz147064 		 * recreating the VLAN and getting a different linkid during
916d62bc4baSyz147064 		 * the rollback if other operation fails.
917d62bc4baSyz147064 		 *
918d62bc4baSyz147064 		 * Otherwise, dladm_setzid() will hold a reference to the
919d62bc4baSyz147064 		 * link and prevent a link renaming, so we need to do it
920d62bc4baSyz147064 		 * before other operations.
921d62bc4baSyz147064 		 */
922d62bc4baSyz147064 		status = dladm_setzid(link, zid_new);
923d62bc4baSyz147064 		if (status != DLADM_STATUS_OK)
924d62bc4baSyz147064 			return (status);
925d62bc4baSyz147064 	}
926d62bc4baSyz147064 
927d62bc4baSyz147064 	if (zid_old != GLOBAL_ZONEID) {
928d62bc4baSyz147064 		if (zone_remove_datalink(zid_old, link) != 0 &&
929f4b3ec61Sdh155122 		    errno != ENXIO) {
930f4b3ec61Sdh155122 			status = dladm_errno2status(errno);
931f4b3ec61Sdh155122 			goto rollback1;
932f4b3ec61Sdh155122 		}
933f4b3ec61Sdh155122 
934d62bc4baSyz147064 		/*
935d62bc4baSyz147064 		 * It is okay to fail to update the /dev entry (some
936d62bc4baSyz147064 		 * vanity-named links do not have a /dev entry).
937d62bc4baSyz147064 		 */
938d62bc4baSyz147064 		(void) i_dladm_update_deventry(zid_old, linkid, B_FALSE);
939d62bc4baSyz147064 	}
940d62bc4baSyz147064 
941d62bc4baSyz147064 	if (zid_new != GLOBAL_ZONEID) {
942d62bc4baSyz147064 		if (zone_add_datalink(zid_new, link) != 0) {
943d62bc4baSyz147064 			status = dladm_errno2status(errno);
944d62bc4baSyz147064 			goto rollback2;
945d62bc4baSyz147064 		}
946d62bc4baSyz147064 
947d62bc4baSyz147064 		(void) i_dladm_update_deventry(zid_new, linkid, B_TRUE);
948d62bc4baSyz147064 	} else {
949d62bc4baSyz147064 		status = dladm_setzid(link, zid_new);
950f4b3ec61Sdh155122 		if (status != DLADM_STATUS_OK)
951f4b3ec61Sdh155122 			goto rollback2;
952f4b3ec61Sdh155122 	}
953f4b3ec61Sdh155122 
954f4b3ec61Sdh155122 	return (DLADM_STATUS_OK);
955f4b3ec61Sdh155122 
956f4b3ec61Sdh155122 rollback2:
957f4b3ec61Sdh155122 	if (zid_old != GLOBAL_ZONEID)
958d62bc4baSyz147064 		(void) i_dladm_update_deventry(zid_old, linkid, B_TRUE);
959d62bc4baSyz147064 	if (zid_old != GLOBAL_ZONEID)
960d62bc4baSyz147064 		(void) zone_add_datalink(zid_old, link);
961f4b3ec61Sdh155122 rollback1:
962d62bc4baSyz147064 	if (zid_new != GLOBAL_ZONEID)
963d62bc4baSyz147064 		(void) dladm_setzid(link, zid_old);
964f4b3ec61Sdh155122 	return (status);
965f4b3ec61Sdh155122 }
966f4b3ec61Sdh155122 
967f4b3ec61Sdh155122 /* ARGSUSED */
968f4b3ec61Sdh155122 static dladm_status_t
969*e7801d59Ssowmini do_check_zone(struct prop_desc *pd, datalink_id_t linkid, char **prop_val,
970*e7801d59Ssowmini     uint_t val_cnt, val_desc_t *vdp)
971f4b3ec61Sdh155122 {
972f4b3ec61Sdh155122 	zoneid_t	zid;
973f4b3ec61Sdh155122 
974f4b3ec61Sdh155122 	if (val_cnt != 1)
975f4b3ec61Sdh155122 		return (DLADM_STATUS_BADVALCNT);
976f4b3ec61Sdh155122 
977f4b3ec61Sdh155122 	if ((zid = getzoneidbyname(*prop_val)) == -1)
978f4b3ec61Sdh155122 		return (DLADM_STATUS_BADVAL);
979f4b3ec61Sdh155122 
980f4b3ec61Sdh155122 	if (zid != GLOBAL_ZONEID) {
981f4b3ec61Sdh155122 		ushort_t	flags;
982f4b3ec61Sdh155122 
983f4b3ec61Sdh155122 		if (zone_getattr(zid, ZONE_ATTR_FLAGS, &flags,
984f4b3ec61Sdh155122 		    sizeof (flags)) < 0) {
985f4b3ec61Sdh155122 			return (dladm_errno2status(errno));
986f4b3ec61Sdh155122 		}
987f4b3ec61Sdh155122 
988f4b3ec61Sdh155122 		if (!(flags & ZF_NET_EXCL)) {
989f4b3ec61Sdh155122 			return (DLADM_STATUS_BADVAL);
990f4b3ec61Sdh155122 		}
991f4b3ec61Sdh155122 	}
992f4b3ec61Sdh155122 
993d62bc4baSyz147064 	vdp->vd_val = zid;
994f4b3ec61Sdh155122 	return (DLADM_STATUS_OK);
995f4b3ec61Sdh155122 }
996f4b3ec61Sdh155122 
997*e7801d59Ssowmini /* ARGSUSED */
998f4b3ec61Sdh155122 static dladm_status_t
999*e7801d59Ssowmini do_get_autopush(struct prop_desc *pd, datalink_id_t linkid,
1000*e7801d59Ssowmini     char **prop_val, uint_t *val_cnt)
1001d62bc4baSyz147064 {
1002d62bc4baSyz147064 	dld_ioc_ap_t	dia;
1003d62bc4baSyz147064 	int		fd, i, len;
1004d62bc4baSyz147064 
1005d62bc4baSyz147064 	if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0)
1006d62bc4baSyz147064 		return (dladm_errno2status(errno));
1007d62bc4baSyz147064 
1008d62bc4baSyz147064 	*val_cnt = 1;
1009d62bc4baSyz147064 	dia.dia_linkid = linkid;
1010d62bc4baSyz147064 	if (i_dladm_ioctl(fd, DLDIOC_GETAUTOPUSH, &dia, sizeof (dia)) < 0) {
1011d62bc4baSyz147064 		(*prop_val)[0] = '\0';
1012d62bc4baSyz147064 		goto done;
1013d62bc4baSyz147064 	}
1014d62bc4baSyz147064 
1015d62bc4baSyz147064 	for (i = 0, len = 0; i < dia.dia_npush; i++) {
1016d62bc4baSyz147064 		if (i != 0) {
1017d62bc4baSyz147064 			(void) snprintf(*prop_val + len,
1018d62bc4baSyz147064 			    DLADM_PROP_VAL_MAX - len, "%c", AP_DELIMITER);
1019d62bc4baSyz147064 			len += 1;
1020d62bc4baSyz147064 		}
1021d62bc4baSyz147064 		(void) snprintf(*prop_val + len, DLADM_PROP_VAL_MAX - len,
1022d62bc4baSyz147064 		    "%s", dia.dia_aplist[i]);
1023d62bc4baSyz147064 		len += strlen(dia.dia_aplist[i]);
1024d62bc4baSyz147064 		if (dia.dia_anchor - 1 == i) {
1025d62bc4baSyz147064 			(void) snprintf(*prop_val + len,
1026d62bc4baSyz147064 			    DLADM_PROP_VAL_MAX - len, "%c%s", AP_DELIMITER,
1027d62bc4baSyz147064 			    AP_ANCHOR);
1028d62bc4baSyz147064 			len += (strlen(AP_ANCHOR) + 1);
1029d62bc4baSyz147064 		}
1030d62bc4baSyz147064 	}
1031d62bc4baSyz147064 
1032d62bc4baSyz147064 done:
1033d62bc4baSyz147064 	(void) close(fd);
1034d62bc4baSyz147064 	return (DLADM_STATUS_OK);
1035d62bc4baSyz147064 }
1036d62bc4baSyz147064 
1037*e7801d59Ssowmini /* ARGSUSED */
1038d62bc4baSyz147064 static dladm_status_t
1039*e7801d59Ssowmini do_set_autopush(prop_desc_t *pd, datalink_id_t linkid,
1040*e7801d59Ssowmini     val_desc_t *vdp, uint_t val_cnt, uint_t flags)
1041d62bc4baSyz147064 {
1042d62bc4baSyz147064 	dld_ioc_ap_t		dia;
1043d62bc4baSyz147064 	struct dlautopush	*dlap = (struct dlautopush *)vdp->vd_val;
1044d62bc4baSyz147064 	dladm_status_t		status = DLADM_STATUS_OK;
1045d62bc4baSyz147064 	int			fd, i;
1046d62bc4baSyz147064 	int			ic_cmd;
1047d62bc4baSyz147064 
1048d62bc4baSyz147064 	if (val_cnt != 1)
1049d62bc4baSyz147064 		return (DLADM_STATUS_BADVALCNT);
1050d62bc4baSyz147064 
1051d62bc4baSyz147064 	if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0)
1052d62bc4baSyz147064 		return (dladm_errno2status(errno));
1053d62bc4baSyz147064 
1054d62bc4baSyz147064 	dia.dia_linkid = linkid;
1055d62bc4baSyz147064 	if (dlap != NULL) {
1056d62bc4baSyz147064 		dia.dia_anchor = dlap->dap_anchor;
1057d62bc4baSyz147064 		dia.dia_npush = dlap->dap_npush;
1058d62bc4baSyz147064 		for (i = 0; i < dia.dia_npush; i++) {
1059d62bc4baSyz147064 			(void) strlcpy(dia.dia_aplist[i], dlap->dap_aplist[i],
1060d62bc4baSyz147064 			    FMNAMESZ+1);
1061d62bc4baSyz147064 		}
1062d62bc4baSyz147064 		ic_cmd = DLDIOC_SETAUTOPUSH;
1063d62bc4baSyz147064 	} else {
1064d62bc4baSyz147064 		ic_cmd = DLDIOC_CLRAUTOPUSH;
1065d62bc4baSyz147064 	}
1066d62bc4baSyz147064 
1067d62bc4baSyz147064 	if (i_dladm_ioctl(fd, ic_cmd, &dia, sizeof (dia)) < 0)
1068d62bc4baSyz147064 		status = dladm_errno2status(errno);
1069d62bc4baSyz147064 
1070d62bc4baSyz147064 	(void) close(fd);
1071d62bc4baSyz147064 	return (status);
1072d62bc4baSyz147064 }
1073d62bc4baSyz147064 
1074d62bc4baSyz147064 /*
1075d62bc4baSyz147064  * Add the specified module to the dlautopush structure; returns a
1076d62bc4baSyz147064  * DLADM_STATUS_* code.
1077d62bc4baSyz147064  */
1078d62bc4baSyz147064 dladm_status_t
1079d62bc4baSyz147064 i_dladm_add_ap_module(const char *module, struct dlautopush *dlap)
1080d62bc4baSyz147064 {
1081d62bc4baSyz147064 	if ((strlen(module) == 0) || (strlen(module) > FMNAMESZ))
1082d62bc4baSyz147064 		return (DLADM_STATUS_BADVAL);
1083d62bc4baSyz147064 
1084d62bc4baSyz147064 	if (strncasecmp(module, AP_ANCHOR, strlen(AP_ANCHOR)) == 0) {
1085d62bc4baSyz147064 		/*
1086d62bc4baSyz147064 		 * We don't allow multiple anchors, and the anchor must
1087d62bc4baSyz147064 		 * be after at least one module.
1088d62bc4baSyz147064 		 */
1089d62bc4baSyz147064 		if (dlap->dap_anchor != 0)
1090d62bc4baSyz147064 			return (DLADM_STATUS_BADVAL);
1091d62bc4baSyz147064 		if (dlap->dap_npush == 0)
1092d62bc4baSyz147064 			return (DLADM_STATUS_BADVAL);
1093d62bc4baSyz147064 
1094d62bc4baSyz147064 		dlap->dap_anchor = dlap->dap_npush;
1095d62bc4baSyz147064 		return (DLADM_STATUS_OK);
1096d62bc4baSyz147064 	}
1097d62bc4baSyz147064 	if (dlap->dap_npush > MAXAPUSH)
1098d62bc4baSyz147064 		return (DLADM_STATUS_BADVALCNT);
1099d62bc4baSyz147064 
1100d62bc4baSyz147064 	(void) strlcpy(dlap->dap_aplist[dlap->dap_npush++], module,
1101d62bc4baSyz147064 	    FMNAMESZ + 1);
1102d62bc4baSyz147064 
1103d62bc4baSyz147064 	return (DLADM_STATUS_OK);
1104d62bc4baSyz147064 }
1105d62bc4baSyz147064 
1106d62bc4baSyz147064 /*
1107d62bc4baSyz147064  * Currently, both '.' and ' '(space) can be used as the delimiters between
1108d62bc4baSyz147064  * autopush modules. The former is used in dladm set-linkprop, and the
1109d62bc4baSyz147064  * latter is used in the autopush(1M) file.
1110d62bc4baSyz147064  */
1111d62bc4baSyz147064 /* ARGSUSED */
1112d62bc4baSyz147064 static dladm_status_t
1113*e7801d59Ssowmini do_check_autopush(struct prop_desc *pd, datalink_id_t linkid, char **prop_val,
1114*e7801d59Ssowmini     uint_t val_cnt, val_desc_t *vdp)
1115d62bc4baSyz147064 {
1116d62bc4baSyz147064 	char			*module;
1117d62bc4baSyz147064 	struct dlautopush	*dlap;
1118d62bc4baSyz147064 	dladm_status_t		status;
1119d62bc4baSyz147064 	char			val[DLADM_PROP_VAL_MAX];
1120d62bc4baSyz147064 	char			delimiters[4];
1121d62bc4baSyz147064 
1122d62bc4baSyz147064 	if (val_cnt != 1)
1123d62bc4baSyz147064 		return (DLADM_STATUS_BADVALCNT);
1124d62bc4baSyz147064 
1125d62bc4baSyz147064 	dlap = malloc(sizeof (struct dlautopush));
1126d62bc4baSyz147064 	if (dlap == NULL)
1127d62bc4baSyz147064 		return (DLADM_STATUS_NOMEM);
1128d62bc4baSyz147064 
1129d62bc4baSyz147064 	(void) memset(dlap, 0, sizeof (struct dlautopush));
1130d62bc4baSyz147064 	(void) snprintf(delimiters, 4, " %c\n", AP_DELIMITER);
1131d62bc4baSyz147064 	bcopy(*prop_val, val, DLADM_PROP_VAL_MAX);
1132d62bc4baSyz147064 	module = strtok(val, delimiters);
1133d62bc4baSyz147064 	while (module != NULL) {
1134d62bc4baSyz147064 		status = i_dladm_add_ap_module(module, dlap);
1135d62bc4baSyz147064 		if (status != DLADM_STATUS_OK)
1136d62bc4baSyz147064 			return (status);
1137d62bc4baSyz147064 		module = strtok(NULL, delimiters);
1138d62bc4baSyz147064 	}
1139d62bc4baSyz147064 
1140d62bc4baSyz147064 	vdp->vd_val = (uintptr_t)dlap;
1141d62bc4baSyz147064 	return (DLADM_STATUS_OK);
1142d62bc4baSyz147064 }
1143d62bc4baSyz147064 
1144*e7801d59Ssowmini /* ARGSUSED */
1145d62bc4baSyz147064 static dladm_status_t
1146*e7801d59Ssowmini do_get_rate_common(struct prop_desc *pd, datalink_id_t linkid,
1147*e7801d59Ssowmini     char **prop_val, uint_t *val_cnt, uint_t id)
1148d62bc4baSyz147064 {
1149d62bc4baSyz147064 	wl_rates_t	*wrp;
1150d62bc4baSyz147064 	uint_t		i;
1151d62bc4baSyz147064 	wldp_t		*gbuf = NULL;
1152d62bc4baSyz147064 	dladm_status_t	status = DLADM_STATUS_OK;
1153d62bc4baSyz147064 
1154d62bc4baSyz147064 	if ((gbuf = malloc(MAX_BUF_LEN)) == NULL) {
1155d62bc4baSyz147064 		status = DLADM_STATUS_NOMEM;
1156d62bc4baSyz147064 		goto done;
1157d62bc4baSyz147064 	}
1158d62bc4baSyz147064 
1159d62bc4baSyz147064 	status = i_dladm_wlan_get_ioctl(linkid, gbuf, id);
1160d62bc4baSyz147064 	if (status != DLADM_STATUS_OK)
1161d62bc4baSyz147064 		goto done;
1162d62bc4baSyz147064 
1163d62bc4baSyz147064 	wrp = (wl_rates_t *)gbuf->wldp_buf;
1164d62bc4baSyz147064 	if (wrp->wl_rates_num > *val_cnt) {
1165d62bc4baSyz147064 		status = DLADM_STATUS_TOOSMALL;
1166d62bc4baSyz147064 		goto done;
1167d62bc4baSyz147064 	}
1168d62bc4baSyz147064 
1169d62bc4baSyz147064 	if (wrp->wl_rates_rates[0] == 0) {
1170d62bc4baSyz147064 		prop_val[0][0] = '\0';
1171d62bc4baSyz147064 		*val_cnt = 1;
1172d62bc4baSyz147064 		goto done;
1173d62bc4baSyz147064 	}
1174d62bc4baSyz147064 
1175d62bc4baSyz147064 	for (i = 0; i < wrp->wl_rates_num; i++) {
1176d62bc4baSyz147064 		(void) snprintf(prop_val[i], DLADM_STRSIZE, "%.*f",
1177d62bc4baSyz147064 		    wrp->wl_rates_rates[i] % 2,
1178d62bc4baSyz147064 		    (float)wrp->wl_rates_rates[i] / 2);
1179d62bc4baSyz147064 	}
1180d62bc4baSyz147064 	*val_cnt = wrp->wl_rates_num;
1181d62bc4baSyz147064 
1182d62bc4baSyz147064 done:
1183d62bc4baSyz147064 	free(gbuf);
1184d62bc4baSyz147064 	return (status);
1185d62bc4baSyz147064 }
1186d62bc4baSyz147064 
1187d62bc4baSyz147064 static dladm_status_t
1188*e7801d59Ssowmini do_get_rate_prop(struct prop_desc *pd, datalink_id_t linkid,
1189*e7801d59Ssowmini     char **prop_val, uint_t *val_cnt)
1190d62bc4baSyz147064 {
1191*e7801d59Ssowmini 	return (do_get_rate_common(pd, linkid, prop_val, val_cnt,
1192d62bc4baSyz147064 	    WL_DESIRED_RATES));
1193d62bc4baSyz147064 }
1194d62bc4baSyz147064 
1195d62bc4baSyz147064 static dladm_status_t
1196*e7801d59Ssowmini do_get_rate_mod(struct prop_desc *pd, datalink_id_t linkid,
1197*e7801d59Ssowmini     char **prop_val, uint_t *val_cnt)
1198d62bc4baSyz147064 {
1199*e7801d59Ssowmini 	return (do_get_rate_common(pd, linkid, prop_val, val_cnt,
1200d62bc4baSyz147064 	    WL_SUPPORTED_RATES));
1201d62bc4baSyz147064 }
1202d62bc4baSyz147064 
1203d62bc4baSyz147064 static dladm_status_t
1204d62bc4baSyz147064 do_set_rate(datalink_id_t linkid, dladm_wlan_rates_t *rates)
1205f4b3ec61Sdh155122 {
1206f4b3ec61Sdh155122 	int		i;
1207d62bc4baSyz147064 	uint_t		len;
1208d62bc4baSyz147064 	wldp_t		*gbuf;
1209d62bc4baSyz147064 	wl_rates_t	*wrp;
1210d62bc4baSyz147064 	dladm_status_t	status = DLADM_STATUS_OK;
1211d62bc4baSyz147064 
1212d62bc4baSyz147064 	if ((gbuf = malloc(MAX_BUF_LEN)) == NULL)
1213d62bc4baSyz147064 		return (DLADM_STATUS_NOMEM);
1214d62bc4baSyz147064 
1215d62bc4baSyz147064 	(void) memset(gbuf, 0, MAX_BUF_LEN);
1216d62bc4baSyz147064 
1217d62bc4baSyz147064 	wrp = (wl_rates_t *)gbuf->wldp_buf;
1218d62bc4baSyz147064 	for (i = 0; i < rates->wr_cnt; i++)
1219d62bc4baSyz147064 		wrp->wl_rates_rates[i] = rates->wr_rates[i];
1220d62bc4baSyz147064 	wrp->wl_rates_num = rates->wr_cnt;
1221d62bc4baSyz147064 
1222d62bc4baSyz147064 	len = offsetof(wl_rates_t, wl_rates_rates) +
1223d62bc4baSyz147064 	    (rates->wr_cnt * sizeof (char)) + WIFI_BUF_OFFSET;
1224d62bc4baSyz147064 	status = i_dladm_wlan_ioctl(linkid, gbuf, WL_DESIRED_RATES, len,
1225d62bc4baSyz147064 	    WLAN_SET_PARAM, len);
1226d62bc4baSyz147064 
1227d62bc4baSyz147064 	free(gbuf);
1228d62bc4baSyz147064 	return (status);
1229d62bc4baSyz147064 }
1230d62bc4baSyz147064 
1231*e7801d59Ssowmini /* ARGSUSED */
1232d62bc4baSyz147064 static dladm_status_t
1233*e7801d59Ssowmini do_set_rate_prop(prop_desc_t *pd, datalink_id_t linkid,
1234*e7801d59Ssowmini     val_desc_t *vdp, uint_t val_cnt, uint_t flags)
1235d62bc4baSyz147064 {
1236d62bc4baSyz147064 	dladm_wlan_rates_t	rates;
1237f4b3ec61Sdh155122 	dladm_status_t		status;
1238f4b3ec61Sdh155122 
1239d62bc4baSyz147064 	if (val_cnt != 1)
1240d62bc4baSyz147064 		return (DLADM_STATUS_BADVALCNT);
1241f4b3ec61Sdh155122 
1242d62bc4baSyz147064 	rates.wr_cnt = 1;
1243d62bc4baSyz147064 	rates.wr_rates[0] = vdp[0].vd_val;
1244f4b3ec61Sdh155122 
1245d62bc4baSyz147064 	status = do_set_rate(linkid, &rates);
1246f4b3ec61Sdh155122 
1247d62bc4baSyz147064 done:
1248d62bc4baSyz147064 	return (status);
1249d62bc4baSyz147064 }
1250d62bc4baSyz147064 
1251d62bc4baSyz147064 /* ARGSUSED */
1252d62bc4baSyz147064 static dladm_status_t
1253*e7801d59Ssowmini do_check_rate(struct prop_desc *pd, datalink_id_t linkid, char **prop_val,
1254*e7801d59Ssowmini     uint_t val_cnt, val_desc_t *vdp)
1255d62bc4baSyz147064 {
1256d62bc4baSyz147064 	int		i;
1257d62bc4baSyz147064 	uint_t		modval_cnt = MAX_SUPPORT_RATES;
1258d62bc4baSyz147064 	char		*buf, **modval;
1259d62bc4baSyz147064 	dladm_status_t	status;
1260d62bc4baSyz147064 
1261d62bc4baSyz147064 	if (val_cnt != 1)
1262d62bc4baSyz147064 		return (DLADM_STATUS_BADVALCNT);
1263d62bc4baSyz147064 
1264d62bc4baSyz147064 	buf = malloc((sizeof (char *) + DLADM_STRSIZE) *
1265d62bc4baSyz147064 	    MAX_SUPPORT_RATES);
1266d62bc4baSyz147064 	if (buf == NULL) {
1267d62bc4baSyz147064 		status = DLADM_STATUS_NOMEM;
1268d62bc4baSyz147064 		goto done;
1269d62bc4baSyz147064 	}
1270d62bc4baSyz147064 
1271d62bc4baSyz147064 	modval = (char **)(void *)buf;
1272d62bc4baSyz147064 	for (i = 0; i < MAX_SUPPORT_RATES; i++) {
1273d62bc4baSyz147064 		modval[i] = buf + sizeof (char *) * MAX_SUPPORT_RATES +
1274d62bc4baSyz147064 		    i * DLADM_STRSIZE;
1275d62bc4baSyz147064 	}
1276d62bc4baSyz147064 
1277*e7801d59Ssowmini 	status = do_get_rate_mod(NULL, linkid, modval, &modval_cnt);
1278d62bc4baSyz147064 	if (status != DLADM_STATUS_OK)
1279d62bc4baSyz147064 		goto done;
1280d62bc4baSyz147064 
1281d62bc4baSyz147064 	for (i = 0; i < modval_cnt; i++) {
1282d62bc4baSyz147064 		if (strcasecmp(*prop_val, modval[i]) == 0) {
1283*e7801d59Ssowmini 			vdp->vd_val = (uintptr_t)(uint_t)
1284*e7801d59Ssowmini 			    (atof(*prop_val) * 2);
1285f4b3ec61Sdh155122 			status = DLADM_STATUS_OK;
1286f4b3ec61Sdh155122 			break;
1287f4b3ec61Sdh155122 		}
1288d62bc4baSyz147064 	}
1289d62bc4baSyz147064 	if (i == modval_cnt)
1290d62bc4baSyz147064 		status = DLADM_STATUS_BADVAL;
1291d62bc4baSyz147064 done:
1292d62bc4baSyz147064 	free(buf);
1293d62bc4baSyz147064 	return (status);
1294d62bc4baSyz147064 }
1295f4b3ec61Sdh155122 
1296d62bc4baSyz147064 static dladm_status_t
1297d62bc4baSyz147064 do_get_phyconf(datalink_id_t linkid, wldp_t *gbuf)
1298d62bc4baSyz147064 {
1299d62bc4baSyz147064 	return (i_dladm_wlan_get_ioctl(linkid, gbuf, WL_PHY_CONFIG));
1300d62bc4baSyz147064 }
1301d62bc4baSyz147064 
1302*e7801d59Ssowmini /* ARGSUSED */
1303d62bc4baSyz147064 static dladm_status_t
1304*e7801d59Ssowmini do_get_channel_prop(struct prop_desc *pd, datalink_id_t linkid,
1305*e7801d59Ssowmini     char **prop_val, uint_t *val_cnt)
1306d62bc4baSyz147064 {
1307d62bc4baSyz147064 	uint32_t	channel;
1308d62bc4baSyz147064 	wldp_t		*gbuf;
1309d62bc4baSyz147064 	dladm_status_t	status = DLADM_STATUS_OK;
1310d62bc4baSyz147064 
1311d62bc4baSyz147064 	if ((gbuf = malloc(MAX_BUF_LEN)) == NULL)
1312d62bc4baSyz147064 		return (DLADM_STATUS_NOMEM);
1313d62bc4baSyz147064 
1314d62bc4baSyz147064 	if ((status = do_get_phyconf(linkid, gbuf)) != DLADM_STATUS_OK)
1315d62bc4baSyz147064 		goto done;
1316d62bc4baSyz147064 
1317d62bc4baSyz147064 	if (!i_dladm_wlan_convert_chan((wl_phy_conf_t *)gbuf->wldp_buf,
1318d62bc4baSyz147064 	    &channel)) {
1319d62bc4baSyz147064 		status = DLADM_STATUS_NOTFOUND;
1320d62bc4baSyz147064 		goto done;
1321d62bc4baSyz147064 	}
1322d62bc4baSyz147064 
1323d62bc4baSyz147064 	(void) snprintf(*prop_val, DLADM_STRSIZE, "%u", channel);
1324d62bc4baSyz147064 	*val_cnt = 1;
1325d62bc4baSyz147064 
1326d62bc4baSyz147064 done:
1327d62bc4baSyz147064 	free(gbuf);
1328d62bc4baSyz147064 	return (status);
1329d62bc4baSyz147064 }
1330d62bc4baSyz147064 
1331d62bc4baSyz147064 static dladm_status_t
1332d62bc4baSyz147064 do_get_powermode(datalink_id_t linkid, wldp_t *gbuf)
1333d62bc4baSyz147064 {
1334d62bc4baSyz147064 	return (i_dladm_wlan_get_ioctl(linkid, gbuf, WL_POWER_MODE));
1335d62bc4baSyz147064 }
1336d62bc4baSyz147064 
1337*e7801d59Ssowmini /* ARGSUSED */
1338d62bc4baSyz147064 static dladm_status_t
1339*e7801d59Ssowmini do_get_powermode_prop(struct prop_desc *pd, datalink_id_t linkid,
1340*e7801d59Ssowmini     char **prop_val, uint_t *val_cnt)
1341d62bc4baSyz147064 {
1342d62bc4baSyz147064 	wl_ps_mode_t	*mode;
1343d62bc4baSyz147064 	const char	*s;
1344d62bc4baSyz147064 	wldp_t		*gbuf;
1345d62bc4baSyz147064 	dladm_status_t	status = DLADM_STATUS_OK;
1346d62bc4baSyz147064 
1347d62bc4baSyz147064 	if ((gbuf = malloc(MAX_BUF_LEN)) == NULL)
1348d62bc4baSyz147064 		return (DLADM_STATUS_NOMEM);
1349d62bc4baSyz147064 
1350d62bc4baSyz147064 	if ((status = do_get_powermode(linkid, gbuf)) != DLADM_STATUS_OK)
1351d62bc4baSyz147064 		goto done;
1352d62bc4baSyz147064 
1353d62bc4baSyz147064 	mode = (wl_ps_mode_t *)(gbuf->wldp_buf);
1354d62bc4baSyz147064 	switch (mode->wl_ps_mode) {
1355d62bc4baSyz147064 	case WL_PM_AM:
1356d62bc4baSyz147064 		s = "off";
1357f4b3ec61Sdh155122 		break;
1358d62bc4baSyz147064 	case WL_PM_MPS:
1359d62bc4baSyz147064 		s = "max";
1360d62bc4baSyz147064 		break;
1361d62bc4baSyz147064 	case WL_PM_FAST:
1362d62bc4baSyz147064 		s = "fast";
1363f4b3ec61Sdh155122 		break;
1364f4b3ec61Sdh155122 	default:
1365d62bc4baSyz147064 		status = DLADM_STATUS_NOTFOUND;
1366d62bc4baSyz147064 		goto done;
1367f4b3ec61Sdh155122 	}
1368d62bc4baSyz147064 	(void) snprintf(*prop_val, DLADM_STRSIZE, "%s", s);
1369d62bc4baSyz147064 	*val_cnt = 1;
1370d62bc4baSyz147064 
1371d62bc4baSyz147064 done:
1372d62bc4baSyz147064 	free(gbuf);
1373d62bc4baSyz147064 	return (status);
1374d62bc4baSyz147064 }
1375d62bc4baSyz147064 
1376d62bc4baSyz147064 static dladm_status_t
1377d62bc4baSyz147064 do_set_powermode(datalink_id_t linkid, dladm_wlan_powermode_t *pm)
1378d62bc4baSyz147064 {
1379d62bc4baSyz147064 	wl_ps_mode_t    ps_mode;
1380d62bc4baSyz147064 
1381d62bc4baSyz147064 	(void) memset(&ps_mode, 0xff, sizeof (ps_mode));
1382d62bc4baSyz147064 
1383d62bc4baSyz147064 	switch (*pm) {
1384d62bc4baSyz147064 	case DLADM_WLAN_PM_OFF:
1385d62bc4baSyz147064 		ps_mode.wl_ps_mode = WL_PM_AM;
1386d62bc4baSyz147064 		break;
1387d62bc4baSyz147064 	case DLADM_WLAN_PM_MAX:
1388d62bc4baSyz147064 		ps_mode.wl_ps_mode = WL_PM_MPS;
1389d62bc4baSyz147064 		break;
1390d62bc4baSyz147064 	case DLADM_WLAN_PM_FAST:
1391d62bc4baSyz147064 		ps_mode.wl_ps_mode = WL_PM_FAST;
1392d62bc4baSyz147064 		break;
1393d62bc4baSyz147064 	default:
1394d62bc4baSyz147064 		return (DLADM_STATUS_NOTSUP);
1395d62bc4baSyz147064 	}
1396d62bc4baSyz147064 	return (i_dladm_wlan_set_ioctl(linkid, WL_POWER_MODE, &ps_mode,
1397d62bc4baSyz147064 	    sizeof (ps_mode)));
1398d62bc4baSyz147064 }
1399d62bc4baSyz147064 
1400d62bc4baSyz147064 /* ARGSUSED */
1401d62bc4baSyz147064 static dladm_status_t
1402*e7801d59Ssowmini do_set_powermode_prop(prop_desc_t *pd, datalink_id_t linkid,
1403*e7801d59Ssowmini     val_desc_t *vdp, uint_t val_cnt, uint_t flags)
1404d62bc4baSyz147064 {
1405d62bc4baSyz147064 	dladm_wlan_powermode_t powermode = (dladm_wlan_powermode_t)vdp->vd_val;
1406d62bc4baSyz147064 	dladm_status_t status;
1407d62bc4baSyz147064 
1408d62bc4baSyz147064 	if (val_cnt != 1)
1409d62bc4baSyz147064 		return (DLADM_STATUS_BADVALCNT);
1410d62bc4baSyz147064 
1411d62bc4baSyz147064 	status = do_set_powermode(linkid, &powermode);
1412f4b3ec61Sdh155122 
1413f4b3ec61Sdh155122 	return (status);
1414f4b3ec61Sdh155122 }
1415f4b3ec61Sdh155122 
1416f4b3ec61Sdh155122 static dladm_status_t
1417d62bc4baSyz147064 do_get_radio(datalink_id_t linkid, wldp_t *gbuf)
1418f4b3ec61Sdh155122 {
1419d62bc4baSyz147064 	return (i_dladm_wlan_get_ioctl(linkid, gbuf, WL_RADIO));
1420d62bc4baSyz147064 }
1421d62bc4baSyz147064 
1422*e7801d59Ssowmini /* ARGSUSED */
1423d62bc4baSyz147064 static dladm_status_t
1424*e7801d59Ssowmini do_get_radio_prop(struct prop_desc *pd, datalink_id_t linkid,
1425*e7801d59Ssowmini     char **prop_val, uint_t *val_cnt)
1426d62bc4baSyz147064 {
1427d62bc4baSyz147064 	wl_radio_t	radio;
1428d62bc4baSyz147064 	const char	*s;
1429d62bc4baSyz147064 	wldp_t		*gbuf;
1430d62bc4baSyz147064 	dladm_status_t	status = DLADM_STATUS_OK;
1431d62bc4baSyz147064 
1432d62bc4baSyz147064 	if ((gbuf = malloc(MAX_BUF_LEN)) == NULL)
1433d62bc4baSyz147064 		return (DLADM_STATUS_NOMEM);
1434d62bc4baSyz147064 
1435d62bc4baSyz147064 	if ((status = do_get_radio(linkid, gbuf)) != DLADM_STATUS_OK)
1436d62bc4baSyz147064 		goto done;
1437d62bc4baSyz147064 
1438d62bc4baSyz147064 	radio = *(wl_radio_t *)(gbuf->wldp_buf);
1439d62bc4baSyz147064 	switch (radio) {
1440d62bc4baSyz147064 	case B_TRUE:
1441d62bc4baSyz147064 		s = "on";
1442d62bc4baSyz147064 		break;
1443d62bc4baSyz147064 	case B_FALSE:
1444d62bc4baSyz147064 		s = "off";
1445d62bc4baSyz147064 		break;
1446d62bc4baSyz147064 	default:
1447d62bc4baSyz147064 		status = DLADM_STATUS_NOTFOUND;
1448d62bc4baSyz147064 		goto done;
1449d62bc4baSyz147064 	}
1450d62bc4baSyz147064 	(void) snprintf(*prop_val, DLADM_STRSIZE, "%s", s);
1451d62bc4baSyz147064 	*val_cnt = 1;
1452d62bc4baSyz147064 
1453d62bc4baSyz147064 done:
1454d62bc4baSyz147064 	free(gbuf);
1455d62bc4baSyz147064 	return (status);
1456d62bc4baSyz147064 }
1457d62bc4baSyz147064 
1458d62bc4baSyz147064 static dladm_status_t
1459d62bc4baSyz147064 do_set_radio(datalink_id_t linkid, dladm_wlan_radio_t *radio)
1460d62bc4baSyz147064 {
1461d62bc4baSyz147064 	wl_radio_t r;
1462d62bc4baSyz147064 
1463d62bc4baSyz147064 	switch (*radio) {
1464d62bc4baSyz147064 	case DLADM_WLAN_RADIO_ON:
1465d62bc4baSyz147064 		r = B_TRUE;
1466d62bc4baSyz147064 		break;
1467d62bc4baSyz147064 	case DLADM_WLAN_RADIO_OFF:
1468d62bc4baSyz147064 		r = B_FALSE;
1469d62bc4baSyz147064 		break;
1470d62bc4baSyz147064 	default:
1471d62bc4baSyz147064 		return (DLADM_STATUS_NOTSUP);
1472d62bc4baSyz147064 	}
1473d62bc4baSyz147064 	return (i_dladm_wlan_set_ioctl(linkid, WL_RADIO, &r, sizeof (r)));
1474d62bc4baSyz147064 }
1475d62bc4baSyz147064 
1476d62bc4baSyz147064 /* ARGSUSED */
1477d62bc4baSyz147064 static dladm_status_t
1478*e7801d59Ssowmini do_set_radio_prop(prop_desc_t *pd, datalink_id_t linkid,
1479*e7801d59Ssowmini     val_desc_t *vdp, uint_t val_cnt, uint_t fags)
1480d62bc4baSyz147064 {
1481d62bc4baSyz147064 	dladm_wlan_radio_t radio = (dladm_wlan_radio_t)vdp->vd_val;
1482f4b3ec61Sdh155122 	dladm_status_t status;
1483f4b3ec61Sdh155122 
1484d62bc4baSyz147064 	if (val_cnt != 1)
1485d62bc4baSyz147064 		return (DLADM_STATUS_BADVALCNT);
1486f4b3ec61Sdh155122 
1487d62bc4baSyz147064 	status = do_set_radio(linkid, &radio);
1488f4b3ec61Sdh155122 
1489d62bc4baSyz147064 	return (status);
1490d62bc4baSyz147064 }
1491f4b3ec61Sdh155122 
1492d62bc4baSyz147064 static dladm_status_t
1493d62bc4baSyz147064 i_dladm_set_linkprop_db(datalink_id_t linkid, const char *prop_name,
1494d62bc4baSyz147064     char **prop_val, uint_t val_cnt)
1495d62bc4baSyz147064 {
1496d62bc4baSyz147064 	char		buf[MAXLINELEN];
1497d62bc4baSyz147064 	int		i;
1498d62bc4baSyz147064 	dladm_conf_t	conf;
1499d62bc4baSyz147064 	dladm_status_t	status;
1500d62bc4baSyz147064 
1501d62bc4baSyz147064 	status = dladm_read_conf(linkid, &conf);
1502f4b3ec61Sdh155122 	if (status != DLADM_STATUS_OK)
1503f4b3ec61Sdh155122 		return (status);
1504f4b3ec61Sdh155122 
1505d62bc4baSyz147064 	/*
1506d62bc4baSyz147064 	 * reset case.
1507d62bc4baSyz147064 	 */
1508d62bc4baSyz147064 	if (val_cnt == 0) {
1509d62bc4baSyz147064 		status = dladm_unset_conf_field(conf, prop_name);
1510d62bc4baSyz147064 		if (status == DLADM_STATUS_OK)
1511d62bc4baSyz147064 			status = dladm_write_conf(conf);
1512d62bc4baSyz147064 		goto done;
1513f4b3ec61Sdh155122 	}
1514f4b3ec61Sdh155122 
1515d62bc4baSyz147064 	buf[0] = '\0';
1516d62bc4baSyz147064 	for (i = 0; i < val_cnt; i++) {
1517d62bc4baSyz147064 		(void) strlcat(buf, prop_val[i], MAXLINELEN);
1518d62bc4baSyz147064 		if (i != val_cnt - 1)
1519d62bc4baSyz147064 			(void) strlcat(buf, ",", MAXLINELEN);
1520d62bc4baSyz147064 	}
1521f4b3ec61Sdh155122 
1522d62bc4baSyz147064 	status = dladm_set_conf_field(conf, prop_name, DLADM_TYPE_STR, buf);
1523d62bc4baSyz147064 	if (status == DLADM_STATUS_OK)
1524d62bc4baSyz147064 		status = dladm_write_conf(conf);
1525d62bc4baSyz147064 
1526d62bc4baSyz147064 done:
1527d62bc4baSyz147064 	dladm_destroy_conf(conf);
1528f4b3ec61Sdh155122 	return (status);
1529f4b3ec61Sdh155122 }
1530f4b3ec61Sdh155122 
1531f4b3ec61Sdh155122 static dladm_status_t
1532d62bc4baSyz147064 i_dladm_get_linkprop_db(datalink_id_t linkid, const char *prop_name,
1533d62bc4baSyz147064     char **prop_val, uint_t *val_cntp)
1534f4b3ec61Sdh155122 {
1535d62bc4baSyz147064 	char		buf[MAXLINELEN], *str;
1536d62bc4baSyz147064 	uint_t		cnt = 0;
1537d62bc4baSyz147064 	dladm_conf_t	conf;
1538d62bc4baSyz147064 	dladm_status_t	status;
1539f4b3ec61Sdh155122 
1540d62bc4baSyz147064 	status = dladm_read_conf(linkid, &conf);
1541d62bc4baSyz147064 	if (status != DLADM_STATUS_OK)
1542f4b3ec61Sdh155122 		return (status);
1543d62bc4baSyz147064 
1544d62bc4baSyz147064 	status = dladm_get_conf_field(conf, prop_name, buf, MAXLINELEN);
1545d62bc4baSyz147064 	if (status != DLADM_STATUS_OK)
1546d62bc4baSyz147064 		goto done;
1547d62bc4baSyz147064 
1548d62bc4baSyz147064 	str = strtok(buf, ",");
1549d62bc4baSyz147064 	while (str != NULL) {
1550d62bc4baSyz147064 		if (cnt == *val_cntp) {
1551d62bc4baSyz147064 			status = DLADM_STATUS_TOOSMALL;
1552d62bc4baSyz147064 			goto done;
1553d62bc4baSyz147064 		}
1554d62bc4baSyz147064 		(void) strlcpy(prop_val[cnt++], str, DLADM_PROP_VAL_MAX);
1555d62bc4baSyz147064 		str = strtok(NULL, ",");
1556f4b3ec61Sdh155122 	}
1557f4b3ec61Sdh155122 
1558d62bc4baSyz147064 	*val_cntp = cnt;
1559f4b3ec61Sdh155122 
1560d62bc4baSyz147064 done:
1561d62bc4baSyz147064 	dladm_destroy_conf(conf);
1562d62bc4baSyz147064 	return (status);
1563f4b3ec61Sdh155122 }
1564*e7801d59Ssowmini 
1565*e7801d59Ssowmini static dld_public_prop_t *
1566*e7801d59Ssowmini dladm_name2prop(const char *prop_name)
1567*e7801d59Ssowmini {
1568*e7801d59Ssowmini 	dld_public_prop_t *p;
1569*e7801d59Ssowmini 
1570*e7801d59Ssowmini 	for (p = dld_prop; p->pp_id != DLD_PROP_PRIVATE; p++) {
1571*e7801d59Ssowmini 		if (strcmp(p->pp_name, prop_name) == 0)
1572*e7801d59Ssowmini 			break;
1573*e7801d59Ssowmini 	}
1574*e7801d59Ssowmini 	return (p);
1575*e7801d59Ssowmini }
1576*e7801d59Ssowmini 
1577*e7801d59Ssowmini 
1578*e7801d59Ssowmini static dld_ioc_prop_t *
1579*e7801d59Ssowmini dld_buf_alloc(size_t valsize, datalink_id_t linkid, const char *prop_name,
1580*e7801d59Ssowmini     dladm_status_t *status)
1581*e7801d59Ssowmini {
1582*e7801d59Ssowmini 	int dsize;
1583*e7801d59Ssowmini 	dld_ioc_prop_t *dip;
1584*e7801d59Ssowmini 	dld_public_prop_t *p;
1585*e7801d59Ssowmini 	char link[DLPI_LINKNAME_MAX];
1586*e7801d59Ssowmini 	uint32_t flags;
1587*e7801d59Ssowmini 
1588*e7801d59Ssowmini 	*status = DLADM_STATUS_OK;
1589*e7801d59Ssowmini 	p = dladm_name2prop(prop_name);
1590*e7801d59Ssowmini 	if (p->pp_id != DLD_PROP_PRIVATE)
1591*e7801d59Ssowmini 		valsize = p->pp_valsize;
1592*e7801d59Ssowmini 
1593*e7801d59Ssowmini 	dsize = DLD_PROPBUF_SIZE(valsize);
1594*e7801d59Ssowmini 	dip = malloc(dsize);
1595*e7801d59Ssowmini 	if (dip == NULL) {
1596*e7801d59Ssowmini 		*status = DLADM_STATUS_NOMEM;
1597*e7801d59Ssowmini 		return (NULL);
1598*e7801d59Ssowmini 	}
1599*e7801d59Ssowmini 	bzero(dip, dsize);
1600*e7801d59Ssowmini 	dip->pr_valsize = valsize;
1601*e7801d59Ssowmini 	(void) strlcpy(dip->pr_name, prop_name, DLD_LINKPROP_NAME_MAX);
1602*e7801d59Ssowmini 	dip->pr_version = DLD_PROP_VERSION;
1603*e7801d59Ssowmini 
1604*e7801d59Ssowmini 	if ((*status = dladm_datalink_id2info(linkid, &flags, NULL, NULL,
1605*e7801d59Ssowmini 	    (char *)link, DLPI_LINKNAME_MAX)) != DLADM_STATUS_OK) {
1606*e7801d59Ssowmini 		free(dip);
1607*e7801d59Ssowmini 		return (NULL);
1608*e7801d59Ssowmini 	}
1609*e7801d59Ssowmini 
1610*e7801d59Ssowmini 	if (!(flags & DLADM_OPT_ACTIVE)) {
1611*e7801d59Ssowmini 		free(dip);
1612*e7801d59Ssowmini 		*status = DLADM_STATUS_TEMPONLY;
1613*e7801d59Ssowmini 		return (NULL);
1614*e7801d59Ssowmini 	}
1615*e7801d59Ssowmini 	(void) strlcpy(dip->pr_linkname, link, IFNAMSIZ);
1616*e7801d59Ssowmini 	dip->pr_num = p->pp_id;
1617*e7801d59Ssowmini 	return (dip);
1618*e7801d59Ssowmini }
1619*e7801d59Ssowmini 
1620*e7801d59Ssowmini /* ARGSUSED */
1621*e7801d59Ssowmini static dladm_status_t
1622*e7801d59Ssowmini dld_set_public_prop(prop_desc_t *pd, datalink_id_t linkid,
1623*e7801d59Ssowmini     val_desc_t *vdp, uint_t val_cnt, uint_t flags)
1624*e7801d59Ssowmini {
1625*e7801d59Ssowmini 	dld_ioc_prop_t	*dip;
1626*e7801d59Ssowmini 	int		fd, dsize;
1627*e7801d59Ssowmini 	dladm_status_t	status = DLADM_STATUS_OK;
1628*e7801d59Ssowmini 	uint8_t		u8;
1629*e7801d59Ssowmini 	uint16_t	u16;
1630*e7801d59Ssowmini 	uint32_t	u32;
1631*e7801d59Ssowmini 	void		*val;
1632*e7801d59Ssowmini 
1633*e7801d59Ssowmini 	dip = dld_buf_alloc(0, linkid, pd->pd_name, &status);
1634*e7801d59Ssowmini 	if (dip == NULL)
1635*e7801d59Ssowmini 		return (status);
1636*e7801d59Ssowmini 
1637*e7801d59Ssowmini 	if (pd->pd_flags & PD_CHECK_ALLOC)
1638*e7801d59Ssowmini 		val = (void *)vdp->vd_val;
1639*e7801d59Ssowmini 	else {
1640*e7801d59Ssowmini 		/*
1641*e7801d59Ssowmini 		 * Currently all 1/2/4-byte size properties are byte/word/int.
1642*e7801d59Ssowmini 		 * No need (yet) to distinguish these from arrays of same size.
1643*e7801d59Ssowmini 		 */
1644*e7801d59Ssowmini 		switch (dip->pr_valsize) {
1645*e7801d59Ssowmini 		case 1:
1646*e7801d59Ssowmini 			u8 = vdp->vd_val;
1647*e7801d59Ssowmini 			val = &u8;
1648*e7801d59Ssowmini 			break;
1649*e7801d59Ssowmini 		case 2:
1650*e7801d59Ssowmini 			u16 = vdp->vd_val;
1651*e7801d59Ssowmini 			val = &u16;
1652*e7801d59Ssowmini 			break;
1653*e7801d59Ssowmini 		case 4:
1654*e7801d59Ssowmini 			u32 = vdp->vd_val;
1655*e7801d59Ssowmini 			val = &u32;
1656*e7801d59Ssowmini 			break;
1657*e7801d59Ssowmini 		default:
1658*e7801d59Ssowmini 			val = &vdp->vd_val;
1659*e7801d59Ssowmini 			break;
1660*e7801d59Ssowmini 		}
1661*e7801d59Ssowmini 	}
1662*e7801d59Ssowmini 
1663*e7801d59Ssowmini 	(void) memcpy(dip->pr_val, val, dip->pr_valsize);
1664*e7801d59Ssowmini 	dsize = DLD_PROPBUF_SIZE(dip->pr_valsize);
1665*e7801d59Ssowmini 	if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) {
1666*e7801d59Ssowmini 		status = dladm_errno2status(errno);
1667*e7801d59Ssowmini 		goto done;
1668*e7801d59Ssowmini 	}
1669*e7801d59Ssowmini 	if (i_dladm_ioctl(fd, DLDIOCSETPROP, dip, dsize) < 0)
1670*e7801d59Ssowmini 		status = dladm_errno2status(errno);
1671*e7801d59Ssowmini 
1672*e7801d59Ssowmini 	(void) close(fd);
1673*e7801d59Ssowmini done:
1674*e7801d59Ssowmini 	return (status);
1675*e7801d59Ssowmini }
1676*e7801d59Ssowmini 
1677*e7801d59Ssowmini static dladm_status_t
1678*e7801d59Ssowmini dld_get_public_prop(dld_ioc_prop_t *dip)
1679*e7801d59Ssowmini {
1680*e7801d59Ssowmini 	int fd, dsize;
1681*e7801d59Ssowmini 	dladm_status_t status = DLADM_STATUS_OK;
1682*e7801d59Ssowmini 
1683*e7801d59Ssowmini 	dsize = DLD_PROPBUF_SIZE(dip->pr_valsize);
1684*e7801d59Ssowmini 
1685*e7801d59Ssowmini 	if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) {
1686*e7801d59Ssowmini 		status = dladm_errno2status(errno);
1687*e7801d59Ssowmini 		goto done;
1688*e7801d59Ssowmini 	}
1689*e7801d59Ssowmini 	if (i_dladm_ioctl(fd, DLDIOCGETPROP, dip, dsize) < 0) {
1690*e7801d59Ssowmini 		status = dladm_errno2status(errno);
1691*e7801d59Ssowmini 	}
1692*e7801d59Ssowmini done:
1693*e7801d59Ssowmini 	return (status);
1694*e7801d59Ssowmini }
1695*e7801d59Ssowmini 
1696*e7801d59Ssowmini 
1697*e7801d59Ssowmini /* ARGSUSED */
1698*e7801d59Ssowmini static dladm_status_t
1699*e7801d59Ssowmini dld_defmtu_check(struct prop_desc *pd, datalink_id_t linkid, char **prop_val,
1700*e7801d59Ssowmini     uint_t val_cnt, val_desc_t *v)
1701*e7801d59Ssowmini {
1702*e7801d59Ssowmini 	uint64_t mtu;
1703*e7801d59Ssowmini 
1704*e7801d59Ssowmini 	if (val_cnt != 1)
1705*e7801d59Ssowmini 		return (DLADM_STATUS_BADVAL);
1706*e7801d59Ssowmini 	mtu = atoll(prop_val[0]);
1707*e7801d59Ssowmini 	v->vd_val = (uintptr_t)malloc(sizeof (uint64_t));
1708*e7801d59Ssowmini 	if ((void *)v->vd_val == NULL)
1709*e7801d59Ssowmini 		return (DLADM_STATUS_NOMEM);
1710*e7801d59Ssowmini 	bcopy(&mtu, (void *)v->vd_val, sizeof (mtu));
1711*e7801d59Ssowmini 	return (DLADM_STATUS_OK);
1712*e7801d59Ssowmini }
1713*e7801d59Ssowmini 
1714*e7801d59Ssowmini /* ARGSUSED */
1715*e7801d59Ssowmini static dladm_status_t
1716*e7801d59Ssowmini dld_duplex_get(struct prop_desc *pd, datalink_id_t linkid,
1717*e7801d59Ssowmini     char **prop_val, uint_t *val_cnt)
1718*e7801d59Ssowmini {
1719*e7801d59Ssowmini 	link_duplex_t   link_duplex;
1720*e7801d59Ssowmini 	dladm_status_t  status;
1721*e7801d59Ssowmini 
1722*e7801d59Ssowmini 	if ((status = dladm_get_single_mac_stat(linkid, "link_duplex",
1723*e7801d59Ssowmini 	    KSTAT_DATA_UINT32, &link_duplex)) != 0)
1724*e7801d59Ssowmini 		return (status);
1725*e7801d59Ssowmini 
1726*e7801d59Ssowmini 	switch (link_duplex) {
1727*e7801d59Ssowmini 	case LINK_DUPLEX_FULL:
1728*e7801d59Ssowmini 		(void) strcpy(*prop_val, "full");
1729*e7801d59Ssowmini 		break;
1730*e7801d59Ssowmini 	case LINK_DUPLEX_HALF:
1731*e7801d59Ssowmini 		(void) strcpy(*prop_val, "half");
1732*e7801d59Ssowmini 		break;
1733*e7801d59Ssowmini 	default:
1734*e7801d59Ssowmini 		(void) strcpy(*prop_val, "unknown");
1735*e7801d59Ssowmini 		break;
1736*e7801d59Ssowmini 	}
1737*e7801d59Ssowmini 	*val_cnt = 1;
1738*e7801d59Ssowmini 	return (DLADM_STATUS_OK);
1739*e7801d59Ssowmini }
1740*e7801d59Ssowmini 
1741*e7801d59Ssowmini /* ARGSUSED */
1742*e7801d59Ssowmini static dladm_status_t
1743*e7801d59Ssowmini dld_speed_get(struct prop_desc *pd, datalink_id_t linkid,
1744*e7801d59Ssowmini     char **prop_val, uint_t *val_cnt)
1745*e7801d59Ssowmini {
1746*e7801d59Ssowmini 	uint64_t	ifspeed = 0;
1747*e7801d59Ssowmini 	dladm_status_t status;
1748*e7801d59Ssowmini 
1749*e7801d59Ssowmini 	if ((status = dladm_get_single_mac_stat(linkid, "ifspeed",
1750*e7801d59Ssowmini 	    KSTAT_DATA_UINT64, &ifspeed)) != 0)
1751*e7801d59Ssowmini 		return (status);
1752*e7801d59Ssowmini 
1753*e7801d59Ssowmini 	(void) snprintf(*prop_val, DLADM_PROP_VAL_MAX,
1754*e7801d59Ssowmini 	    "%llu", ifspeed / 1000000); /* Mbps */
1755*e7801d59Ssowmini 	*val_cnt = 1;
1756*e7801d59Ssowmini 	return (DLADM_STATUS_OK);
1757*e7801d59Ssowmini }
1758*e7801d59Ssowmini 
1759*e7801d59Ssowmini /* ARGSUSED */
1760*e7801d59Ssowmini static dladm_status_t
1761*e7801d59Ssowmini dld_status_get(struct prop_desc *pd, datalink_id_t linkid,
1762*e7801d59Ssowmini     char **prop_val, uint_t *val_cnt)
1763*e7801d59Ssowmini {
1764*e7801d59Ssowmini 	link_state_t   link_state;
1765*e7801d59Ssowmini 	dladm_status_t status;
1766*e7801d59Ssowmini 
1767*e7801d59Ssowmini 	if ((status = dladm_get_single_mac_stat(linkid, "link_state",
1768*e7801d59Ssowmini 	    KSTAT_DATA_UINT32, &link_state)) != 0)
1769*e7801d59Ssowmini 		return (status);
1770*e7801d59Ssowmini 
1771*e7801d59Ssowmini 	switch (link_state) {
1772*e7801d59Ssowmini 	case LINK_STATE_UP:
1773*e7801d59Ssowmini 		(void) strcpy(*prop_val, "up");
1774*e7801d59Ssowmini 		break;
1775*e7801d59Ssowmini 	case LINK_STATE_DOWN:
1776*e7801d59Ssowmini 		(void) strcpy(*prop_val, "down");
1777*e7801d59Ssowmini 		break;
1778*e7801d59Ssowmini 	default:
1779*e7801d59Ssowmini 		(void) strcpy(*prop_val, "unknown");
1780*e7801d59Ssowmini 		break;
1781*e7801d59Ssowmini 	}
1782*e7801d59Ssowmini 	*val_cnt = 1;
1783*e7801d59Ssowmini 	return (DLADM_STATUS_OK);
1784*e7801d59Ssowmini }
1785*e7801d59Ssowmini 
1786*e7801d59Ssowmini /* ARGSUSED */
1787*e7801d59Ssowmini static dladm_status_t
1788*e7801d59Ssowmini dld_binary_get(struct prop_desc *pd, datalink_id_t linkid,
1789*e7801d59Ssowmini     char **prop_val, uint_t *val_cnt)
1790*e7801d59Ssowmini {
1791*e7801d59Ssowmini 	dld_ioc_prop_t *dip;
1792*e7801d59Ssowmini 	dladm_status_t status;
1793*e7801d59Ssowmini 
1794*e7801d59Ssowmini 	if ((dip = dld_buf_alloc(0, linkid, pd->pd_name, &status)) == NULL)
1795*e7801d59Ssowmini 		return (status);
1796*e7801d59Ssowmini 	if ((status = dld_get_public_prop(dip)) != DLADM_STATUS_OK) {
1797*e7801d59Ssowmini 		free(dip);
1798*e7801d59Ssowmini 		return (status);
1799*e7801d59Ssowmini 	}
1800*e7801d59Ssowmini 	(void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "%x", dip->pr_val[0]);
1801*e7801d59Ssowmini 	free(dip);
1802*e7801d59Ssowmini 	*val_cnt = 1;
1803*e7801d59Ssowmini 	return (DLADM_STATUS_OK);
1804*e7801d59Ssowmini }
1805*e7801d59Ssowmini 
1806*e7801d59Ssowmini static dladm_status_t
1807*e7801d59Ssowmini dld_uint64_get(struct prop_desc *pd, datalink_id_t linkid,
1808*e7801d59Ssowmini     char **prop_val, uint_t *val_cnt)
1809*e7801d59Ssowmini {
1810*e7801d59Ssowmini 	dld_ioc_prop_t *dip;
1811*e7801d59Ssowmini 	uint64_t v  = 0;
1812*e7801d59Ssowmini 	uchar_t *cp;
1813*e7801d59Ssowmini 	dladm_status_t status;
1814*e7801d59Ssowmini 
1815*e7801d59Ssowmini 	if ((dip = dld_buf_alloc(0, linkid, pd->pd_name, &status)) == NULL)
1816*e7801d59Ssowmini 		return (status);
1817*e7801d59Ssowmini 	if ((status = dld_get_public_prop(dip)) != DLADM_STATUS_OK) {
1818*e7801d59Ssowmini 		free(dip);
1819*e7801d59Ssowmini 		return (status);
1820*e7801d59Ssowmini 	}
1821*e7801d59Ssowmini 	cp = (uchar_t *)dip->pr_val;
1822*e7801d59Ssowmini 	(void) memcpy(&v, cp, sizeof (v));
1823*e7801d59Ssowmini 	(void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "%" PRIu64, v);
1824*e7801d59Ssowmini 	free(dip);
1825*e7801d59Ssowmini 	*val_cnt = 1;
1826*e7801d59Ssowmini 	return (DLADM_STATUS_OK);
1827*e7801d59Ssowmini }
1828*e7801d59Ssowmini 
1829*e7801d59Ssowmini static dladm_status_t
1830*e7801d59Ssowmini dld_flowctl_get(struct prop_desc *pd, datalink_id_t linkid,
1831*e7801d59Ssowmini     char **prop_val, uint_t *val_cnt)
1832*e7801d59Ssowmini {
1833*e7801d59Ssowmini 	dld_ioc_prop_t *dip;
1834*e7801d59Ssowmini 	link_flowctrl_t v;
1835*e7801d59Ssowmini 	dladm_status_t status;
1836*e7801d59Ssowmini 	uchar_t *cp;
1837*e7801d59Ssowmini 
1838*e7801d59Ssowmini 	if ((dip = dld_buf_alloc(0, linkid, pd->pd_name, &status)) == NULL)
1839*e7801d59Ssowmini 		return (status);
1840*e7801d59Ssowmini 
1841*e7801d59Ssowmini 	if ((status = dld_get_public_prop(dip)) != DLADM_STATUS_OK) {
1842*e7801d59Ssowmini 		free(dip);
1843*e7801d59Ssowmini 		return (status);
1844*e7801d59Ssowmini 	}
1845*e7801d59Ssowmini 	cp = (uchar_t *)dip->pr_val;
1846*e7801d59Ssowmini 	(void) memcpy(&v, cp, sizeof (v));
1847*e7801d59Ssowmini 	switch (v) {
1848*e7801d59Ssowmini 	case LINK_FLOWCTRL_NONE:
1849*e7801d59Ssowmini 		(void) sprintf(*prop_val, "no");
1850*e7801d59Ssowmini 		break;
1851*e7801d59Ssowmini 	case LINK_FLOWCTRL_RX:
1852*e7801d59Ssowmini 		(void) sprintf(*prop_val, "rx");
1853*e7801d59Ssowmini 		break;
1854*e7801d59Ssowmini 	case LINK_FLOWCTRL_TX:
1855*e7801d59Ssowmini 		(void) sprintf(*prop_val, "tx");
1856*e7801d59Ssowmini 		break;
1857*e7801d59Ssowmini 	case LINK_FLOWCTRL_BI:
1858*e7801d59Ssowmini 		(void) sprintf(*prop_val, "bi");
1859*e7801d59Ssowmini 		break;
1860*e7801d59Ssowmini 	}
1861*e7801d59Ssowmini 	free(dip);
1862*e7801d59Ssowmini 	*val_cnt = 1;
1863*e7801d59Ssowmini 	return (DLADM_STATUS_OK);
1864*e7801d59Ssowmini }
1865*e7801d59Ssowmini 
1866*e7801d59Ssowmini 
1867*e7801d59Ssowmini /* ARGSUSED */
1868*e7801d59Ssowmini static dladm_status_t
1869*e7801d59Ssowmini dld_set_prop(datalink_id_t linkid, const char *prop_name,
1870*e7801d59Ssowmini     char **prop_val, uint_t val_cnt, uint_t flags)
1871*e7801d59Ssowmini {
1872*e7801d59Ssowmini 	int		fd, i, slen;
1873*e7801d59Ssowmini 	int 		bufsize = 0, dsize;
1874*e7801d59Ssowmini 	dld_ioc_prop_t *dip = NULL;
1875*e7801d59Ssowmini 	uchar_t 	*dp;
1876*e7801d59Ssowmini 	dld_public_prop_t *p;
1877*e7801d59Ssowmini 	dladm_status_t	status;
1878*e7801d59Ssowmini 
1879*e7801d59Ssowmini 	if ((prop_name == NULL && prop_val != NULL) ||
1880*e7801d59Ssowmini 	    (prop_val != NULL && val_cnt == 0))
1881*e7801d59Ssowmini 		return (DLADM_STATUS_BADARG);
1882*e7801d59Ssowmini 	p = dladm_name2prop(prop_name);
1883*e7801d59Ssowmini 	if (p->pp_id != DLD_PROP_PRIVATE)
1884*e7801d59Ssowmini 		return (DLADM_STATUS_BADARG);
1885*e7801d59Ssowmini 
1886*e7801d59Ssowmini 	/*
1887*e7801d59Ssowmini 	 * private properties: all parsing is done in the kernel.
1888*e7801d59Ssowmini 	 * allocate a enough space for each property + its separator (',').
1889*e7801d59Ssowmini 	 */
1890*e7801d59Ssowmini 	for (i = 0; i < val_cnt; i++) {
1891*e7801d59Ssowmini 		bufsize += strlen(prop_val[i]) + 1;
1892*e7801d59Ssowmini 	}
1893*e7801d59Ssowmini 	dip = dld_buf_alloc(bufsize + 1, linkid, prop_name, &status);
1894*e7801d59Ssowmini 	if (dip == NULL)
1895*e7801d59Ssowmini 		return (status);
1896*e7801d59Ssowmini 
1897*e7801d59Ssowmini 	dp = (uchar_t *)dip->pr_val;
1898*e7801d59Ssowmini 	dsize = sizeof (dld_ioc_prop_t) + bufsize;
1899*e7801d59Ssowmini 	slen = 0;
1900*e7801d59Ssowmini 	for (i = 0; i < val_cnt; i++) {
1901*e7801d59Ssowmini 		int plen = 0;
1902*e7801d59Ssowmini 
1903*e7801d59Ssowmini 		plen = strlen(prop_val[i]);
1904*e7801d59Ssowmini 		bcopy(prop_val[i], dp, plen);
1905*e7801d59Ssowmini 		slen += plen;
1906*e7801d59Ssowmini 		/*
1907*e7801d59Ssowmini 		 * add a "," separator and update dp.
1908*e7801d59Ssowmini 		 */
1909*e7801d59Ssowmini 		if (i != (val_cnt -1))
1910*e7801d59Ssowmini 			dp[slen++] = ',';
1911*e7801d59Ssowmini 		dp += (plen + 1);
1912*e7801d59Ssowmini 	}
1913*e7801d59Ssowmini 	if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) {
1914*e7801d59Ssowmini 		free(dip);
1915*e7801d59Ssowmini 		return (dladm_errno2status(errno));
1916*e7801d59Ssowmini 	}
1917*e7801d59Ssowmini 	if ((status = i_dladm_ioctl(fd, DLDIOCSETPROP, dip, dsize)) < 0) {
1918*e7801d59Ssowmini 		free(dip);
1919*e7801d59Ssowmini 		return (status);
1920*e7801d59Ssowmini 	}
1921*e7801d59Ssowmini 	free(dip);
1922*e7801d59Ssowmini 	(void) close(fd);
1923*e7801d59Ssowmini 	return (DLADM_STATUS_OK);
1924*e7801d59Ssowmini }
1925*e7801d59Ssowmini 
1926*e7801d59Ssowmini static dladm_status_t
1927*e7801d59Ssowmini dld_get_prop(datalink_id_t linkid, const char *prop_name,
1928*e7801d59Ssowmini     char **prop_val, uint_t *val_cnt, dladm_prop_type_t type)
1929*e7801d59Ssowmini {
1930*e7801d59Ssowmini 	int		fd;
1931*e7801d59Ssowmini 	dladm_status_t  status = DLADM_STATUS_OK;
1932*e7801d59Ssowmini 	uint_t 		dsize;
1933*e7801d59Ssowmini 	dld_ioc_prop_t *dip = NULL;
1934*e7801d59Ssowmini 	dld_public_prop_t *p;
1935*e7801d59Ssowmini 	char tmp = '\0';
1936*e7801d59Ssowmini 
1937*e7801d59Ssowmini 	if ((prop_name == NULL && prop_val != NULL) ||
1938*e7801d59Ssowmini 	    (prop_val != NULL && val_cnt == 0))
1939*e7801d59Ssowmini 		return (DLADM_STATUS_BADARG);
1940*e7801d59Ssowmini 
1941*e7801d59Ssowmini 	p = dladm_name2prop(prop_name);
1942*e7801d59Ssowmini 	if (p->pp_id != DLD_PROP_PRIVATE)
1943*e7801d59Ssowmini 		return (DLADM_STATUS_BADARG);
1944*e7801d59Ssowmini 
1945*e7801d59Ssowmini 	if (type == DLADM_PROP_VAL_DEFAULT ||
1946*e7801d59Ssowmini 	    type == DLADM_PROP_VAL_MODIFIABLE) {
1947*e7801d59Ssowmini 		*prop_val = &tmp;
1948*e7801d59Ssowmini 		*val_cnt = 1;
1949*e7801d59Ssowmini 		return (DLADM_STATUS_OK);
1950*e7801d59Ssowmini 	}
1951*e7801d59Ssowmini 
1952*e7801d59Ssowmini 	/*
1953*e7801d59Ssowmini 	 * private properties: all parsing is done in the kernel.
1954*e7801d59Ssowmini 	 */
1955*e7801d59Ssowmini 	dip = dld_buf_alloc(1024, linkid, prop_name, &status);
1956*e7801d59Ssowmini 	if (dip == NULL)
1957*e7801d59Ssowmini 		return (status);
1958*e7801d59Ssowmini 	dsize = DLD_PROPBUF_SIZE(dip->pr_valsize);
1959*e7801d59Ssowmini 
1960*e7801d59Ssowmini 	if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0)
1961*e7801d59Ssowmini 		return (DLADM_STATUS_BADARG);
1962*e7801d59Ssowmini 
1963*e7801d59Ssowmini 	if ((status = i_dladm_ioctl(fd, DLDIOCGETPROP, dip, dsize)) < 0) {
1964*e7801d59Ssowmini 		status = dladm_errno2status(errno);
1965*e7801d59Ssowmini 	} else {
1966*e7801d59Ssowmini 		(void) strncpy(*prop_val, dip->pr_val, DLADM_PROP_VAL_MAX);
1967*e7801d59Ssowmini 		*val_cnt = 1;
1968*e7801d59Ssowmini 	}
1969*e7801d59Ssowmini 	return (status);
1970*e7801d59Ssowmini }
1971