xref: /titanic_53/usr/src/lib/libdladm/common/linkprop.c (revision d62bc4badc1c1f1549c961cfb8b420e650e1272b)
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 /*
22*d62bc4baSyz147064  * 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>
32*d62bc4baSyz147064 #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>
43*d62bc4baSyz147064 #include <libdlwlan_impl.h>
44f595a68aSyz147064 #include <libdlwlan.h>
45*d62bc4baSyz147064 #include <libdlvlan.h>
46f4b3ec61Sdh155122 #include <dlfcn.h>
47f4b3ec61Sdh155122 #include <link.h>
48*d62bc4baSyz147064 #include <inet/wifi_ioctl.h>
49f4b3ec61Sdh155122 
50*d62bc4baSyz147064 /*
51*d62bc4baSyz147064  * The linkprop get() callback.
52*d62bc4baSyz147064  * - propstrp:	a property string array to keep the returned property.
53*d62bc4baSyz147064  *		Caller allocated.
54*d62bc4baSyz147064  * - cntp:	number of returned properties.
55*d62bc4baSyz147064  *		Caller also uses it to indicate how many it expects.
56*d62bc4baSyz147064  */
57*d62bc4baSyz147064 typedef dladm_status_t	pd_getf_t(datalink_id_t, char **propstp, uint_t *cntp);
58f4b3ec61Sdh155122 
59*d62bc4baSyz147064 /*
60*d62bc4baSyz147064  * The linkprop set() callback.
61*d62bc4baSyz147064  * - propval:	a val_desc_t array which keeps the property values to be set.
62*d62bc4baSyz147064  * - cnt:	number of properties to be set.
63*d62bc4baSyz147064  */
64*d62bc4baSyz147064 typedef dladm_status_t	pd_setf_t(datalink_id_t, val_desc_t *propval,
65*d62bc4baSyz147064 			    uint_t cnt);
66f4b3ec61Sdh155122 
67*d62bc4baSyz147064 #define	PD_TEMPONLY	0x1
68f4b3ec61Sdh155122 
69*d62bc4baSyz147064 /*
70*d62bc4baSyz147064  * The linkprop check() callback.
71*d62bc4baSyz147064  * - propstrp:	property string array which keeps the property to be checked.
72*d62bc4baSyz147064  * - cnt:	number of properties.
73*d62bc4baSyz147064  * - propval:	return value; the property values of the given property strings.
74*d62bc4baSyz147064  * - dofree:	indicates whether the caller needs to free propvalp->vd_val.
75*d62bc4baSyz147064  */
76*d62bc4baSyz147064 typedef dladm_status_t	pd_checkf_t(datalink_id_t, char **propstrp,
77*d62bc4baSyz147064 			    uint_t cnt, val_desc_t *propval, boolean_t *dofree);
78f4b3ec61Sdh155122 
79*d62bc4baSyz147064 static pd_getf_t	do_get_zone, do_get_autopush, do_get_rate_mod,
80*d62bc4baSyz147064 			do_get_rate_prop, do_get_channel_prop,
81*d62bc4baSyz147064 			do_get_powermode_prop, do_get_radio_prop;
82*d62bc4baSyz147064 static pd_setf_t	do_set_zone, do_set_autopush, do_set_rate_prop,
83*d62bc4baSyz147064 			do_set_powermode_prop, do_set_radio_prop;
84*d62bc4baSyz147064 static pd_checkf_t	do_check_zone, do_check_autopush, do_check_rate;
85f4b3ec61Sdh155122 
86f4b3ec61Sdh155122 typedef struct prop_desc {
87*d62bc4baSyz147064 	/*
88*d62bc4baSyz147064 	 * link property name
89*d62bc4baSyz147064 	 */
90f4b3ec61Sdh155122 	char			*pd_name;
91*d62bc4baSyz147064 
92*d62bc4baSyz147064 	/*
93*d62bc4baSyz147064 	 * default property value, can be set to { "", NULL }
94*d62bc4baSyz147064 	 */
95f4b3ec61Sdh155122 	val_desc_t		pd_defval;
96*d62bc4baSyz147064 
97*d62bc4baSyz147064 	/*
98*d62bc4baSyz147064 	 * list of optional property values, can be NULL.
99*d62bc4baSyz147064 	 *
100*d62bc4baSyz147064 	 * This is set to non-NULL if there is a list of possible property
101*d62bc4baSyz147064 	 * values.  pd_optval would point to the array of possible values.
102*d62bc4baSyz147064 	 */
103*d62bc4baSyz147064 	val_desc_t		*pd_optval;
104*d62bc4baSyz147064 
105*d62bc4baSyz147064 	/*
106*d62bc4baSyz147064 	 * count of the above optional property values. 0 if pd_optval is NULL.
107*d62bc4baSyz147064 	 */
108*d62bc4baSyz147064 	uint_t			pd_noptval;
109*d62bc4baSyz147064 
110*d62bc4baSyz147064 	/*
111*d62bc4baSyz147064 	 * callback to set link property;
112*d62bc4baSyz147064 	 * set to NULL if this property is read-only
113*d62bc4baSyz147064 	 */
114f4b3ec61Sdh155122 	pd_setf_t		*pd_set;
115*d62bc4baSyz147064 
116*d62bc4baSyz147064 	/*
117*d62bc4baSyz147064 	 * callback to get modifiable link property
118*d62bc4baSyz147064 	 */
119f4b3ec61Sdh155122 	pd_getf_t		*pd_getmod;
120*d62bc4baSyz147064 
121*d62bc4baSyz147064 	/*
122*d62bc4baSyz147064 	 * callback to get current link property
123*d62bc4baSyz147064 	 */
124f4b3ec61Sdh155122 	pd_getf_t		*pd_get;
125*d62bc4baSyz147064 
126*d62bc4baSyz147064 	/*
127*d62bc4baSyz147064 	 * callback to validate link property value, set to NULL if pd_optval
128*d62bc4baSyz147064 	 * is not NULL. In that case, validate the value by comparing it with
129*d62bc4baSyz147064 	 * the pd_optval. Return a val_desc_t array pointer if the value is
130*d62bc4baSyz147064 	 * valid.
131*d62bc4baSyz147064 	 */
132f4b3ec61Sdh155122 	pd_checkf_t		*pd_check;
133*d62bc4baSyz147064 
134*d62bc4baSyz147064 	/*
135*d62bc4baSyz147064 	 * currently only PD_TEMPONLY is valid, which indicates the property
136*d62bc4baSyz147064 	 * is temporary only.
137*d62bc4baSyz147064 	 */
138*d62bc4baSyz147064 	uint_t			pd_flags;
139*d62bc4baSyz147064 
140*d62bc4baSyz147064 	/*
141*d62bc4baSyz147064 	 * indicate link classes this property applies to.
142*d62bc4baSyz147064 	 */
143*d62bc4baSyz147064 	datalink_class_t	pd_class;
144*d62bc4baSyz147064 
145*d62bc4baSyz147064 	/*
146*d62bc4baSyz147064 	 * indicate link media type this property applies to.
147*d62bc4baSyz147064 	 */
148*d62bc4baSyz147064 	datalink_media_t	pd_dmedia;
149f4b3ec61Sdh155122 } prop_desc_t;
150f4b3ec61Sdh155122 
151*d62bc4baSyz147064 static val_desc_t	dladm_wlan_radio_vals[] = {
152*d62bc4baSyz147064 	{ "on",		DLADM_WLAN_RADIO_ON	},
153*d62bc4baSyz147064 	{ "off",	DLADM_WLAN_RADIO_OFF	}
154*d62bc4baSyz147064 };
155*d62bc4baSyz147064 
156*d62bc4baSyz147064 static val_desc_t	dladm_wlan_powermode_vals[] = {
157*d62bc4baSyz147064 	{ "off",	DLADM_WLAN_PM_OFF	},
158*d62bc4baSyz147064 	{ "fast",	DLADM_WLAN_PM_FAST	},
159*d62bc4baSyz147064 	{ "max",	DLADM_WLAN_PM_MAX	}
160*d62bc4baSyz147064 };
161*d62bc4baSyz147064 
162f4b3ec61Sdh155122 static prop_desc_t	prop_table[] = {
163*d62bc4baSyz147064 
164*d62bc4baSyz147064 	{ "channel",	{ NULL, 0 }, NULL, 0, NULL, NULL,
165*d62bc4baSyz147064 	    do_get_channel_prop, NULL, 0,
166*d62bc4baSyz147064 	    DATALINK_CLASS_PHYS, DL_WIFI},
167*d62bc4baSyz147064 
168*d62bc4baSyz147064 	{ "powermode",	{ "off", DLADM_WLAN_PM_OFF },
169*d62bc4baSyz147064 	    dladm_wlan_powermode_vals, VALCNT(dladm_wlan_powermode_vals),
170*d62bc4baSyz147064 	    do_set_powermode_prop, NULL,
171*d62bc4baSyz147064 	    do_get_powermode_prop, NULL, 0,
172*d62bc4baSyz147064 	    DATALINK_CLASS_PHYS, DL_WIFI},
173*d62bc4baSyz147064 
174*d62bc4baSyz147064 	{ "radio",	{ "on", DLADM_WLAN_RADIO_ON },
175*d62bc4baSyz147064 	    dladm_wlan_radio_vals, VALCNT(dladm_wlan_radio_vals),
176*d62bc4baSyz147064 	    do_set_radio_prop, NULL,
177*d62bc4baSyz147064 	    do_get_radio_prop, NULL, 0,
178*d62bc4baSyz147064 	    DATALINK_CLASS_PHYS, DL_WIFI},
179*d62bc4baSyz147064 
180*d62bc4baSyz147064 	{ "speed",	{ "", 0 }, NULL, 0,
181*d62bc4baSyz147064 	    do_set_rate_prop, do_get_rate_mod,
182*d62bc4baSyz147064 	    do_get_rate_prop, do_check_rate, 0,
183*d62bc4baSyz147064 	    DATALINK_CLASS_PHYS, DL_WIFI},
184*d62bc4baSyz147064 
185*d62bc4baSyz147064 	{ "autopush",	{ "", NULL }, NULL, 0,
186*d62bc4baSyz147064 	    do_set_autopush, NULL,
187*d62bc4baSyz147064 	    do_get_autopush, do_check_autopush, 0,
188*d62bc4baSyz147064 	    DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE},
189*d62bc4baSyz147064 
190*d62bc4baSyz147064 	{ "zone",	{ "", NULL }, NULL, 0,
191f4b3ec61Sdh155122 	    do_set_zone, NULL,
192*d62bc4baSyz147064 	    do_get_zone, do_check_zone, PD_TEMPONLY,
193*d62bc4baSyz147064 	    DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE}
194f4b3ec61Sdh155122 };
195f4b3ec61Sdh155122 
196*d62bc4baSyz147064 #define	DLADM_MAX_PROPS	(sizeof (prop_table) / sizeof (prop_desc_t))
1970ba2cbe9Sxc151355 
198*d62bc4baSyz147064 static dladm_status_t	i_dladm_set_linkprop_db(datalink_id_t, const char *,
199*d62bc4baSyz147064 			    char **, uint_t);
200*d62bc4baSyz147064 static dladm_status_t	i_dladm_get_linkprop_db(datalink_id_t, const char *,
201*d62bc4baSyz147064 			    char **, uint_t *);
202*d62bc4baSyz147064 static dladm_status_t	i_dladm_set_single_prop(datalink_id_t, datalink_class_t,
203*d62bc4baSyz147064 			    uint32_t, prop_desc_t *, char **, uint_t, uint_t);
204*d62bc4baSyz147064 static dladm_status_t	i_dladm_set_linkprop(datalink_id_t, const char *,
205*d62bc4baSyz147064 			    char **, uint_t, uint_t);
206*d62bc4baSyz147064 
207*d62bc4baSyz147064 /*
208*d62bc4baSyz147064  * Unfortunately, MAX_SCAN_SUPPORT_RATES is too small to allow all
209*d62bc4baSyz147064  * rates to be retrieved. However, we cannot increase it at this
210*d62bc4baSyz147064  * time because it will break binary compatibility with unbundled
211*d62bc4baSyz147064  * WiFi drivers and utilities. So for now we define an additional
212*d62bc4baSyz147064  * constant, MAX_SUPPORT_RATES, to allow all rates to be retrieved.
213*d62bc4baSyz147064  */
214*d62bc4baSyz147064 #define	MAX_SUPPORT_RATES	64
215*d62bc4baSyz147064 
216*d62bc4baSyz147064 #define	AP_ANCHOR	"[anchor]"
217*d62bc4baSyz147064 #define	AP_DELIMITER	'.'
218*d62bc4baSyz147064 
219*d62bc4baSyz147064 static dladm_status_t
220*d62bc4baSyz147064 do_check_prop(prop_desc_t *pdp, char **prop_val, uint_t val_cnt,
221*d62bc4baSyz147064     val_desc_t *vdp)
2220ba2cbe9Sxc151355 {
223*d62bc4baSyz147064 	int		i, j;
2240ba2cbe9Sxc151355 	dladm_status_t	status = DLADM_STATUS_OK;
2250ba2cbe9Sxc151355 
226*d62bc4baSyz147064 	for (j = 0; j < val_cnt; j++) {
227*d62bc4baSyz147064 		for (i = 0; i < pdp->pd_noptval; i++) {
228*d62bc4baSyz147064 			if (strcasecmp(*prop_val,
229*d62bc4baSyz147064 			    pdp->pd_optval[i].vd_name) == 0) {
2300ba2cbe9Sxc151355 				break;
2310ba2cbe9Sxc151355 			}
2320ba2cbe9Sxc151355 		}
233*d62bc4baSyz147064 		if (i == pdp->pd_noptval) {
234*d62bc4baSyz147064 			status = DLADM_STATUS_BADVAL;
235*d62bc4baSyz147064 			goto done;
236*d62bc4baSyz147064 		}
237*d62bc4baSyz147064 		(void) memcpy(vdp + j, &pdp->pd_optval[i], sizeof (val_desc_t));
2380ba2cbe9Sxc151355 	}
2390ba2cbe9Sxc151355 
240*d62bc4baSyz147064 done:
241*d62bc4baSyz147064 	return (status);
2420ba2cbe9Sxc151355 }
2430ba2cbe9Sxc151355 
2440ba2cbe9Sxc151355 static dladm_status_t
245*d62bc4baSyz147064 i_dladm_set_single_prop(datalink_id_t linkid, datalink_class_t class,
246*d62bc4baSyz147064     uint32_t media, prop_desc_t *pdp, char **prop_val, uint_t val_cnt,
247*d62bc4baSyz147064     uint_t flags)
2480ba2cbe9Sxc151355 {
2490ba2cbe9Sxc151355 	dladm_status_t	status = DLADM_STATUS_OK;
250*d62bc4baSyz147064 	val_desc_t	*vdp = NULL;
251*d62bc4baSyz147064 	boolean_t	needfree = B_FALSE;
252*d62bc4baSyz147064 	uint_t		cnt, i;
2530ba2cbe9Sxc151355 
254*d62bc4baSyz147064 	if (!(pdp->pd_class & class))
255*d62bc4baSyz147064 		return (DLADM_STATUS_BADARG);
2560ba2cbe9Sxc151355 
257*d62bc4baSyz147064 	if (!DATALINK_MEDIA_ACCEPTED(pdp->pd_dmedia, media))
258*d62bc4baSyz147064 		return (DLADM_STATUS_BADARG);
259*d62bc4baSyz147064 
260*d62bc4baSyz147064 	if ((flags & DLADM_OPT_PERSIST) && (pdp->pd_flags & PD_TEMPONLY))
261*d62bc4baSyz147064 		return (DLADM_STATUS_TEMPONLY);
262*d62bc4baSyz147064 
263*d62bc4baSyz147064 	if (!(flags & DLADM_OPT_ACTIVE))
264*d62bc4baSyz147064 		return (DLADM_STATUS_OK);
265*d62bc4baSyz147064 
266*d62bc4baSyz147064 	if (pdp->pd_set == NULL)
267*d62bc4baSyz147064 		return (DLADM_STATUS_PROPRDONLY);
268*d62bc4baSyz147064 
269*d62bc4baSyz147064 	if (prop_val != NULL) {
270*d62bc4baSyz147064 		vdp = malloc(sizeof (val_desc_t) * val_cnt);
271*d62bc4baSyz147064 		if (vdp == NULL)
272*d62bc4baSyz147064 			return (DLADM_STATUS_NOMEM);
273*d62bc4baSyz147064 
274*d62bc4baSyz147064 		if (pdp->pd_check != NULL) {
275*d62bc4baSyz147064 			status = pdp->pd_check(linkid, prop_val, val_cnt, vdp,
276*d62bc4baSyz147064 			    &needfree);
277*d62bc4baSyz147064 		} else if (pdp->pd_optval != NULL) {
278*d62bc4baSyz147064 			status = do_check_prop(pdp, prop_val, val_cnt, vdp);
279*d62bc4baSyz147064 		} else {
280*d62bc4baSyz147064 			status = DLADM_STATUS_BADARG;
2810ba2cbe9Sxc151355 		}
2820ba2cbe9Sxc151355 
283*d62bc4baSyz147064 		if (status != DLADM_STATUS_OK)
284*d62bc4baSyz147064 			goto done;
285*d62bc4baSyz147064 
286*d62bc4baSyz147064 		cnt = val_cnt;
287*d62bc4baSyz147064 	} else {
288*d62bc4baSyz147064 		if (pdp->pd_defval.vd_name == NULL)
289*d62bc4baSyz147064 			return (DLADM_STATUS_NOTSUP);
290*d62bc4baSyz147064 
291*d62bc4baSyz147064 		if ((vdp = malloc(sizeof (val_desc_t))) == NULL)
292*d62bc4baSyz147064 			return (DLADM_STATUS_NOMEM);
293*d62bc4baSyz147064 
294*d62bc4baSyz147064 		(void) memcpy(vdp, &pdp->pd_defval, sizeof (val_desc_t));
295*d62bc4baSyz147064 		cnt = 1;
296*d62bc4baSyz147064 	}
297*d62bc4baSyz147064 	status = pdp->pd_set(linkid, vdp, cnt);
298*d62bc4baSyz147064 	if (needfree) {
299*d62bc4baSyz147064 		for (i = 0; i < cnt; i++)
300*d62bc4baSyz147064 			free((void *)(((val_desc_t *)vdp + i)->vd_val));
301*d62bc4baSyz147064 	}
302*d62bc4baSyz147064 done:
303*d62bc4baSyz147064 	free(vdp);
304*d62bc4baSyz147064 	return (status);
305*d62bc4baSyz147064 }
306*d62bc4baSyz147064 
307*d62bc4baSyz147064 static dladm_status_t
308*d62bc4baSyz147064 i_dladm_set_linkprop(datalink_id_t linkid, const char *prop_name,
309*d62bc4baSyz147064     char **prop_val, uint_t val_cnt, uint_t flags)
310*d62bc4baSyz147064 {
311*d62bc4baSyz147064 	int			i;
312*d62bc4baSyz147064 	boolean_t		found = B_FALSE;
313*d62bc4baSyz147064 	datalink_class_t	class;
314*d62bc4baSyz147064 	uint32_t		media;
315*d62bc4baSyz147064 	dladm_status_t		status = DLADM_STATUS_OK;
316*d62bc4baSyz147064 
317*d62bc4baSyz147064 	status = dladm_datalink_id2info(linkid, NULL, &class, &media, NULL, 0);
318*d62bc4baSyz147064 	if (status != DLADM_STATUS_OK)
3190ba2cbe9Sxc151355 		return (status);
3200ba2cbe9Sxc151355 
321*d62bc4baSyz147064 	for (i = 0; i < DLADM_MAX_PROPS; i++) {
322*d62bc4baSyz147064 		prop_desc_t	*pdp = &prop_table[i];
323*d62bc4baSyz147064 		dladm_status_t	s;
3240ba2cbe9Sxc151355 
325*d62bc4baSyz147064 		if (prop_name != NULL &&
326*d62bc4baSyz147064 		    (strcasecmp(prop_name, pdp->pd_name) != 0))
327*d62bc4baSyz147064 			continue;
328*d62bc4baSyz147064 
329*d62bc4baSyz147064 		found = B_TRUE;
330*d62bc4baSyz147064 		s = i_dladm_set_single_prop(linkid, class, media, pdp, prop_val,
331*d62bc4baSyz147064 		    val_cnt, flags);
332*d62bc4baSyz147064 
333*d62bc4baSyz147064 		if (prop_name != NULL) {
334*d62bc4baSyz147064 			status = s;
335*d62bc4baSyz147064 			break;
336*d62bc4baSyz147064 		} else {
337*d62bc4baSyz147064 			if (s != DLADM_STATUS_OK &&
338*d62bc4baSyz147064 			    s != DLADM_STATUS_NOTSUP)
339*d62bc4baSyz147064 				status = s;
340*d62bc4baSyz147064 		}
341*d62bc4baSyz147064 	}
342*d62bc4baSyz147064 	if (!found)
3430ba2cbe9Sxc151355 		status = DLADM_STATUS_NOTFOUND;
3440ba2cbe9Sxc151355 
3450ba2cbe9Sxc151355 	return (status);
3460ba2cbe9Sxc151355 }
3470ba2cbe9Sxc151355 
348*d62bc4baSyz147064 /*
349*d62bc4baSyz147064  * Set/reset link property for specific link
350*d62bc4baSyz147064  */
351*d62bc4baSyz147064 dladm_status_t
352*d62bc4baSyz147064 dladm_set_linkprop(datalink_id_t linkid, const char *prop_name, char **prop_val,
353*d62bc4baSyz147064     uint_t val_cnt, uint_t flags)
3540ba2cbe9Sxc151355 {
355*d62bc4baSyz147064 	dladm_status_t	status = DLADM_STATUS_OK;
3560ba2cbe9Sxc151355 
357*d62bc4baSyz147064 	if ((linkid == DATALINK_INVALID_LINKID) || (flags == 0) ||
358*d62bc4baSyz147064 	    (prop_val == NULL && val_cnt > 0) ||
359*d62bc4baSyz147064 	    (prop_val != NULL && val_cnt == 0) ||
360*d62bc4baSyz147064 	    (prop_name == NULL && prop_val != NULL)) {
361*d62bc4baSyz147064 		return (DLADM_STATUS_BADARG);
3620ba2cbe9Sxc151355 	}
3630ba2cbe9Sxc151355 
364*d62bc4baSyz147064 	status = i_dladm_set_linkprop(linkid, prop_name, prop_val,
365*d62bc4baSyz147064 	    val_cnt, flags);
366*d62bc4baSyz147064 	if (status != DLADM_STATUS_OK)
367*d62bc4baSyz147064 		return (status);
368*d62bc4baSyz147064 
369*d62bc4baSyz147064 	if (flags & DLADM_OPT_PERSIST) {
370*d62bc4baSyz147064 		status = i_dladm_set_linkprop_db(linkid, prop_name,
371*d62bc4baSyz147064 		    prop_val, val_cnt);
372*d62bc4baSyz147064 	}
373*d62bc4baSyz147064 	return (status);
374*d62bc4baSyz147064 }
375*d62bc4baSyz147064 
376*d62bc4baSyz147064 /*
377*d62bc4baSyz147064  * Walk link properties of the given specific link.
378*d62bc4baSyz147064  */
379*d62bc4baSyz147064 dladm_status_t
380*d62bc4baSyz147064 dladm_walk_linkprop(datalink_id_t linkid, void *arg,
381*d62bc4baSyz147064     int (*func)(datalink_id_t, const char *, void *))
3820ba2cbe9Sxc151355 {
383*d62bc4baSyz147064 	dladm_status_t		status;
384*d62bc4baSyz147064 	datalink_class_t	class;
385*d62bc4baSyz147064 	uint_t			media;
386*d62bc4baSyz147064 	int			i;
3870ba2cbe9Sxc151355 
388*d62bc4baSyz147064 	if (linkid == DATALINK_INVALID_LINKID || func == NULL)
389*d62bc4baSyz147064 		return (DLADM_STATUS_BADARG);
3900ba2cbe9Sxc151355 
391*d62bc4baSyz147064 	status = dladm_datalink_id2info(linkid, NULL, &class, &media, NULL, 0);
392*d62bc4baSyz147064 	if (status != DLADM_STATUS_OK)
393*d62bc4baSyz147064 		return (status);
394*d62bc4baSyz147064 
395*d62bc4baSyz147064 	for (i = 0; i < DLADM_MAX_PROPS; i++) {
396*d62bc4baSyz147064 		if (!(prop_table[i].pd_class & class))
397*d62bc4baSyz147064 			continue;
398*d62bc4baSyz147064 
399*d62bc4baSyz147064 		if (!DATALINK_MEDIA_ACCEPTED(prop_table[i].pd_dmedia, media))
400*d62bc4baSyz147064 			continue;
401*d62bc4baSyz147064 
402*d62bc4baSyz147064 		if (func(linkid, prop_table[i].pd_name, arg) ==
403*d62bc4baSyz147064 		    DLADM_WALK_TERMINATE) {
404*d62bc4baSyz147064 			break;
405*d62bc4baSyz147064 		}
406*d62bc4baSyz147064 	}
407*d62bc4baSyz147064 
408*d62bc4baSyz147064 	return (DLADM_STATUS_OK);
409*d62bc4baSyz147064 }
410*d62bc4baSyz147064 
411*d62bc4baSyz147064 /*
412*d62bc4baSyz147064  * Get linkprop of the given specific link.
413*d62bc4baSyz147064  */
414*d62bc4baSyz147064 dladm_status_t
415*d62bc4baSyz147064 dladm_get_linkprop(datalink_id_t linkid, dladm_prop_type_t type,
416*d62bc4baSyz147064     const char *prop_name, char **prop_val, uint_t *val_cntp)
417*d62bc4baSyz147064 {
418*d62bc4baSyz147064 	dladm_status_t		status = DLADM_STATUS_OK;
419*d62bc4baSyz147064 	datalink_class_t	class;
420*d62bc4baSyz147064 	uint_t			media;
421*d62bc4baSyz147064 	prop_desc_t		*pdp;
422*d62bc4baSyz147064 	uint_t			cnt;
423*d62bc4baSyz147064 	int			i;
424*d62bc4baSyz147064 
425*d62bc4baSyz147064 	if (linkid == DATALINK_INVALID_LINKID || prop_name == NULL ||
426*d62bc4baSyz147064 	    prop_val == NULL || val_cntp == NULL || *val_cntp == 0)
427*d62bc4baSyz147064 		return (DLADM_STATUS_BADARG);
428*d62bc4baSyz147064 
429*d62bc4baSyz147064 	for (i = 0; i < DLADM_MAX_PROPS; i++)
430*d62bc4baSyz147064 		if (strcasecmp(prop_name, prop_table[i].pd_name) == 0)
431*d62bc4baSyz147064 			break;
432*d62bc4baSyz147064 
433*d62bc4baSyz147064 	if (i == DLADM_MAX_PROPS)
434*d62bc4baSyz147064 		return (DLADM_STATUS_NOTFOUND);
435*d62bc4baSyz147064 
436*d62bc4baSyz147064 	pdp = &prop_table[i];
437*d62bc4baSyz147064 
438*d62bc4baSyz147064 	status = dladm_datalink_id2info(linkid, NULL, &class, &media, NULL, 0);
439*d62bc4baSyz147064 	if (status != DLADM_STATUS_OK)
440*d62bc4baSyz147064 		return (status);
441*d62bc4baSyz147064 
442*d62bc4baSyz147064 	if (!(pdp->pd_class & class))
443*d62bc4baSyz147064 		return (DLADM_STATUS_BADARG);
444*d62bc4baSyz147064 
445*d62bc4baSyz147064 	if (!DATALINK_MEDIA_ACCEPTED(pdp->pd_dmedia, media))
446*d62bc4baSyz147064 		return (DLADM_STATUS_BADARG);
447*d62bc4baSyz147064 
448*d62bc4baSyz147064 	switch (type) {
449*d62bc4baSyz147064 	case DLADM_PROP_VAL_CURRENT:
450*d62bc4baSyz147064 		status = pdp->pd_get(linkid, prop_val, val_cntp);
451*d62bc4baSyz147064 		break;
452*d62bc4baSyz147064 
453*d62bc4baSyz147064 	case DLADM_PROP_VAL_DEFAULT:
454*d62bc4baSyz147064 		if (pdp->pd_defval.vd_name == NULL) {
455*d62bc4baSyz147064 			status = DLADM_STATUS_NOTSUP;
456*d62bc4baSyz147064 			break;
457*d62bc4baSyz147064 		}
458*d62bc4baSyz147064 		(void) strcpy(*prop_val, pdp->pd_defval.vd_name);
459*d62bc4baSyz147064 		*val_cntp = 1;
460*d62bc4baSyz147064 		break;
461*d62bc4baSyz147064 
462*d62bc4baSyz147064 	case DLADM_PROP_VAL_MODIFIABLE:
463*d62bc4baSyz147064 		if (pdp->pd_getmod != NULL) {
464*d62bc4baSyz147064 			status = pdp->pd_getmod(linkid, prop_val, val_cntp);
465*d62bc4baSyz147064 			break;
466*d62bc4baSyz147064 		}
467*d62bc4baSyz147064 		cnt = pdp->pd_noptval;
468*d62bc4baSyz147064 		if (cnt == 0) {
469*d62bc4baSyz147064 			status = DLADM_STATUS_NOTSUP;
470*d62bc4baSyz147064 		} else if (cnt > *val_cntp) {
471*d62bc4baSyz147064 			status = DLADM_STATUS_TOOSMALL;
472*d62bc4baSyz147064 		} else {
473*d62bc4baSyz147064 			for (i = 0; i < cnt; i++) {
474*d62bc4baSyz147064 				(void) strcpy(prop_val[i],
475*d62bc4baSyz147064 				    pdp->pd_optval[i].vd_name);
476*d62bc4baSyz147064 			}
477*d62bc4baSyz147064 			*val_cntp = cnt;
478*d62bc4baSyz147064 		}
479*d62bc4baSyz147064 		break;
480*d62bc4baSyz147064 	case DLADM_PROP_VAL_PERSISTENT:
481*d62bc4baSyz147064 		if (pdp->pd_flags & PD_TEMPONLY)
482*d62bc4baSyz147064 			return (DLADM_STATUS_TEMPONLY);
483*d62bc4baSyz147064 		status = i_dladm_get_linkprop_db(linkid, prop_name,
484*d62bc4baSyz147064 		    prop_val, val_cntp);
485*d62bc4baSyz147064 		break;
486*d62bc4baSyz147064 	default:
487*d62bc4baSyz147064 		status = DLADM_STATUS_BADARG;
488*d62bc4baSyz147064 		break;
489*d62bc4baSyz147064 	}
490*d62bc4baSyz147064 
491*d62bc4baSyz147064 	return (status);
492*d62bc4baSyz147064 }
493*d62bc4baSyz147064 
494*d62bc4baSyz147064 /*ARGSUSED*/
495*d62bc4baSyz147064 static int
496*d62bc4baSyz147064 i_dladm_init_one_prop(datalink_id_t linkid, const char *prop_name, void *arg)
497*d62bc4baSyz147064 {
498*d62bc4baSyz147064 	char	*buf, **propvals;
499*d62bc4baSyz147064 	uint_t	i, valcnt = DLADM_MAX_PROP_VALCNT;
500*d62bc4baSyz147064 
501*d62bc4baSyz147064 	if ((buf = malloc((sizeof (char *) + DLADM_PROP_VAL_MAX) *
502*d62bc4baSyz147064 	    DLADM_MAX_PROP_VALCNT)) == NULL) {
503*d62bc4baSyz147064 		return (DLADM_WALK_CONTINUE);
504*d62bc4baSyz147064 	}
505*d62bc4baSyz147064 
506*d62bc4baSyz147064 	propvals = (char **)(void *)buf;
507*d62bc4baSyz147064 	for (i = 0; i < valcnt; i++) {
508*d62bc4baSyz147064 		propvals[i] = buf +
509*d62bc4baSyz147064 		    sizeof (char *) * DLADM_MAX_PROP_VALCNT +
510*d62bc4baSyz147064 		    i * DLADM_PROP_VAL_MAX;
511*d62bc4baSyz147064 	}
512*d62bc4baSyz147064 
513*d62bc4baSyz147064 	if (dladm_get_linkprop(linkid, DLADM_PROP_VAL_PERSISTENT, prop_name,
514*d62bc4baSyz147064 	    propvals, &valcnt) != DLADM_STATUS_OK) {
515*d62bc4baSyz147064 		goto done;
516*d62bc4baSyz147064 	}
517*d62bc4baSyz147064 
518*d62bc4baSyz147064 	(void) dladm_set_linkprop(linkid, prop_name, propvals, valcnt,
519*d62bc4baSyz147064 	    DLADM_OPT_ACTIVE);
520*d62bc4baSyz147064 
521*d62bc4baSyz147064 done:
522*d62bc4baSyz147064 	if (buf != NULL)
523*d62bc4baSyz147064 		free(buf);
524*d62bc4baSyz147064 
525*d62bc4baSyz147064 	return (DLADM_WALK_CONTINUE);
526*d62bc4baSyz147064 }
527*d62bc4baSyz147064 
528*d62bc4baSyz147064 /*ARGSUSED*/
529*d62bc4baSyz147064 static int
530*d62bc4baSyz147064 i_dladm_init_linkprop(datalink_id_t linkid, void *arg)
531*d62bc4baSyz147064 {
532*d62bc4baSyz147064 	(void) dladm_init_linkprop(linkid);
533*d62bc4baSyz147064 	return (DLADM_WALK_CONTINUE);
5340ba2cbe9Sxc151355 }
5350ba2cbe9Sxc151355 
5360ba2cbe9Sxc151355 dladm_status_t
537*d62bc4baSyz147064 dladm_init_linkprop(datalink_id_t linkid)
5380ba2cbe9Sxc151355 {
539*d62bc4baSyz147064 	if (linkid == DATALINK_ALL_LINKID) {
540*d62bc4baSyz147064 		(void) dladm_walk_datalink_id(i_dladm_init_linkprop, NULL,
541*d62bc4baSyz147064 		    DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE,
542*d62bc4baSyz147064 		    DLADM_OPT_PERSIST);
543*d62bc4baSyz147064 	} else {
544*d62bc4baSyz147064 		(void) dladm_walk_linkprop(linkid, NULL, i_dladm_init_one_prop);
545*d62bc4baSyz147064 	}
546*d62bc4baSyz147064 	return (DLADM_STATUS_OK);
5470ba2cbe9Sxc151355 }
548f4b3ec61Sdh155122 
549f4b3ec61Sdh155122 static dladm_status_t
550*d62bc4baSyz147064 do_get_zone(datalink_id_t linkid, char **prop_val, uint_t *val_cnt)
551f4b3ec61Sdh155122 {
552*d62bc4baSyz147064 	char		zone_name[ZONENAME_MAX];
553*d62bc4baSyz147064 	zoneid_t	zid;
554*d62bc4baSyz147064 	dladm_status_t	status;
555f4b3ec61Sdh155122 
556*d62bc4baSyz147064 	status = dladm_getzid(linkid, &zid);
557*d62bc4baSyz147064 	if (status != DLADM_STATUS_OK)
558*d62bc4baSyz147064 		return (status);
559*d62bc4baSyz147064 
560*d62bc4baSyz147064 	*val_cnt = 1;
561*d62bc4baSyz147064 	if (zid != GLOBAL_ZONEID) {
562*d62bc4baSyz147064 		if (getzonenamebyid(zid, zone_name, sizeof (zone_name)) < 0)
563f4b3ec61Sdh155122 			return (dladm_errno2status(errno));
564f4b3ec61Sdh155122 
565*d62bc4baSyz147064 		(void) strncpy(*prop_val, zone_name, DLADM_PROP_VAL_MAX);
56647a01978Sbw 	} else {
567*d62bc4baSyz147064 		*prop_val[0] = '\0';
56847a01978Sbw 	}
569f4b3ec61Sdh155122 
570f4b3ec61Sdh155122 	return (DLADM_STATUS_OK);
571f4b3ec61Sdh155122 }
572f4b3ec61Sdh155122 
573f4b3ec61Sdh155122 typedef int (*zone_get_devroot_t)(char *, char *, size_t);
574f4b3ec61Sdh155122 
575f4b3ec61Sdh155122 static int
576f4b3ec61Sdh155122 i_dladm_get_zone_dev(char *zone_name, char *dev, size_t devlen)
577f4b3ec61Sdh155122 {
578f4b3ec61Sdh155122 	char			root[MAXPATHLEN];
579f4b3ec61Sdh155122 	zone_get_devroot_t	real_zone_get_devroot;
580f4b3ec61Sdh155122 	void			*dlhandle;
581f4b3ec61Sdh155122 	void			*sym;
582f4b3ec61Sdh155122 	int			ret;
583f4b3ec61Sdh155122 
584f4b3ec61Sdh155122 	if ((dlhandle = dlopen("libzonecfg.so.1", RTLD_LAZY)) == NULL)
585f4b3ec61Sdh155122 		return (-1);
586f4b3ec61Sdh155122 
587f4b3ec61Sdh155122 	if ((sym = dlsym(dlhandle, "zone_get_devroot")) == NULL) {
588f4b3ec61Sdh155122 		(void) dlclose(dlhandle);
589f4b3ec61Sdh155122 		return (-1);
590f4b3ec61Sdh155122 	}
591f4b3ec61Sdh155122 
592f4b3ec61Sdh155122 	real_zone_get_devroot = (zone_get_devroot_t)sym;
593f4b3ec61Sdh155122 
594f4b3ec61Sdh155122 	if ((ret = real_zone_get_devroot(zone_name, root, sizeof (root))) == 0)
595f4b3ec61Sdh155122 		(void) snprintf(dev, devlen, "%s%s", root, "/dev");
596f4b3ec61Sdh155122 	(void) dlclose(dlhandle);
597f4b3ec61Sdh155122 	return (ret);
598f4b3ec61Sdh155122 }
599f4b3ec61Sdh155122 
600f4b3ec61Sdh155122 static dladm_status_t
601*d62bc4baSyz147064 i_dladm_update_deventry(zoneid_t zid, datalink_id_t linkid, boolean_t add)
602f4b3ec61Sdh155122 {
603f4b3ec61Sdh155122 	char		path[MAXPATHLEN];
604*d62bc4baSyz147064 	char		name[MAXLINKNAMELEN];
605f4b3ec61Sdh155122 	di_prof_t	prof = NULL;
606f4b3ec61Sdh155122 	char		zone_name[ZONENAME_MAX];
607f4b3ec61Sdh155122 	dladm_status_t	status;
608*d62bc4baSyz147064 	int		ret;
609f4b3ec61Sdh155122 
610f4b3ec61Sdh155122 	if (getzonenamebyid(zid, zone_name, sizeof (zone_name)) < 0)
611f4b3ec61Sdh155122 		return (dladm_errno2status(errno));
612f4b3ec61Sdh155122 	if (i_dladm_get_zone_dev(zone_name, path, sizeof (path)) != 0)
613f4b3ec61Sdh155122 		return (dladm_errno2status(errno));
614f4b3ec61Sdh155122 	if (di_prof_init(path, &prof) != 0)
615f4b3ec61Sdh155122 		return (dladm_errno2status(errno));
616f4b3ec61Sdh155122 
617*d62bc4baSyz147064 	status = dladm_linkid2legacyname(linkid, name, MAXLINKNAMELEN);
618f4b3ec61Sdh155122 	if (status != DLADM_STATUS_OK)
619*d62bc4baSyz147064 		goto cleanup;
620f4b3ec61Sdh155122 
621*d62bc4baSyz147064 	if (add)
622*d62bc4baSyz147064 		ret = di_prof_add_dev(prof, name);
623*d62bc4baSyz147064 	else
624*d62bc4baSyz147064 		ret = di_prof_add_exclude(prof, name);
625f4b3ec61Sdh155122 
626*d62bc4baSyz147064 	if (ret != 0) {
627*d62bc4baSyz147064 		status = dladm_errno2status(errno);
628*d62bc4baSyz147064 		goto cleanup;
629f4b3ec61Sdh155122 	}
630f4b3ec61Sdh155122 
631*d62bc4baSyz147064 	if (di_prof_commit(prof) != 0)
632*d62bc4baSyz147064 		status = dladm_errno2status(errno);
633*d62bc4baSyz147064 cleanup:
634*d62bc4baSyz147064 	if (prof)
635*d62bc4baSyz147064 		di_prof_fini(prof);
636*d62bc4baSyz147064 
637*d62bc4baSyz147064 	return (status);
638f4b3ec61Sdh155122 }
639f4b3ec61Sdh155122 
640f4b3ec61Sdh155122 static dladm_status_t
641*d62bc4baSyz147064 do_set_zone(datalink_id_t linkid, val_desc_t *vdp, uint_t val_cnt)
642f4b3ec61Sdh155122 {
643f4b3ec61Sdh155122 	dladm_status_t	status;
644f4b3ec61Sdh155122 	zoneid_t	zid_old, zid_new;
645*d62bc4baSyz147064 	char		link[MAXLINKNAMELEN];
646f4b3ec61Sdh155122 
647f4b3ec61Sdh155122 	if (val_cnt != 1)
648f4b3ec61Sdh155122 		return (DLADM_STATUS_BADVALCNT);
649f4b3ec61Sdh155122 
650*d62bc4baSyz147064 	status = dladm_getzid(linkid, &zid_old);
651f4b3ec61Sdh155122 	if (status != DLADM_STATUS_OK)
652f4b3ec61Sdh155122 		return (status);
653f4b3ec61Sdh155122 
654f4b3ec61Sdh155122 	/* Do nothing if setting to current value */
655*d62bc4baSyz147064 	zid_new = vdp->vd_val;
656f4b3ec61Sdh155122 	if (zid_new == zid_old)
657f4b3ec61Sdh155122 		return (DLADM_STATUS_OK);
658f4b3ec61Sdh155122 
659*d62bc4baSyz147064 	if ((status = dladm_datalink_id2info(linkid, NULL, NULL, NULL,
660*d62bc4baSyz147064 	    link, MAXLINKNAMELEN)) != DLADM_STATUS_OK) {
661*d62bc4baSyz147064 		return (status);
662*d62bc4baSyz147064 	}
663f4b3ec61Sdh155122 
664*d62bc4baSyz147064 	if (zid_new != GLOBAL_ZONEID) {
665*d62bc4baSyz147064 		/*
666*d62bc4baSyz147064 		 * If the new zoneid is the global zone, we could destroy
667*d62bc4baSyz147064 		 * the link (in the case of an implicitly-created VLAN) as a
668*d62bc4baSyz147064 		 * result of the dladm_setzid() operation. In that case,
669*d62bc4baSyz147064 		 * we defer the operation to the end of this function to avoid
670*d62bc4baSyz147064 		 * recreating the VLAN and getting a different linkid during
671*d62bc4baSyz147064 		 * the rollback if other operation fails.
672*d62bc4baSyz147064 		 *
673*d62bc4baSyz147064 		 * Otherwise, dladm_setzid() will hold a reference to the
674*d62bc4baSyz147064 		 * link and prevent a link renaming, so we need to do it
675*d62bc4baSyz147064 		 * before other operations.
676*d62bc4baSyz147064 		 */
677*d62bc4baSyz147064 		status = dladm_setzid(link, zid_new);
678*d62bc4baSyz147064 		if (status != DLADM_STATUS_OK)
679*d62bc4baSyz147064 			return (status);
680*d62bc4baSyz147064 	}
681*d62bc4baSyz147064 
682*d62bc4baSyz147064 	if (zid_old != GLOBAL_ZONEID) {
683*d62bc4baSyz147064 		if (zone_remove_datalink(zid_old, link) != 0 &&
684f4b3ec61Sdh155122 		    errno != ENXIO) {
685f4b3ec61Sdh155122 			status = dladm_errno2status(errno);
686f4b3ec61Sdh155122 			goto rollback1;
687f4b3ec61Sdh155122 		}
688f4b3ec61Sdh155122 
689*d62bc4baSyz147064 		/*
690*d62bc4baSyz147064 		 * It is okay to fail to update the /dev entry (some
691*d62bc4baSyz147064 		 * vanity-named links do not have a /dev entry).
692*d62bc4baSyz147064 		 */
693*d62bc4baSyz147064 		(void) i_dladm_update_deventry(zid_old, linkid, B_FALSE);
694*d62bc4baSyz147064 	}
695*d62bc4baSyz147064 
696*d62bc4baSyz147064 	if (zid_new != GLOBAL_ZONEID) {
697*d62bc4baSyz147064 		if (zone_add_datalink(zid_new, link) != 0) {
698*d62bc4baSyz147064 			status = dladm_errno2status(errno);
699*d62bc4baSyz147064 			goto rollback2;
700*d62bc4baSyz147064 		}
701*d62bc4baSyz147064 
702*d62bc4baSyz147064 		(void) i_dladm_update_deventry(zid_new, linkid, B_TRUE);
703*d62bc4baSyz147064 	} else {
704*d62bc4baSyz147064 		status = dladm_setzid(link, zid_new);
705f4b3ec61Sdh155122 		if (status != DLADM_STATUS_OK)
706f4b3ec61Sdh155122 			goto rollback2;
707f4b3ec61Sdh155122 	}
708f4b3ec61Sdh155122 
709f4b3ec61Sdh155122 	return (DLADM_STATUS_OK);
710f4b3ec61Sdh155122 
711f4b3ec61Sdh155122 rollback2:
712f4b3ec61Sdh155122 	if (zid_old != GLOBAL_ZONEID)
713*d62bc4baSyz147064 		(void) i_dladm_update_deventry(zid_old, linkid, B_TRUE);
714*d62bc4baSyz147064 	if (zid_old != GLOBAL_ZONEID)
715*d62bc4baSyz147064 		(void) zone_add_datalink(zid_old, link);
716f4b3ec61Sdh155122 rollback1:
717*d62bc4baSyz147064 	if (zid_new != GLOBAL_ZONEID)
718*d62bc4baSyz147064 		(void) dladm_setzid(link, zid_old);
719f4b3ec61Sdh155122 	return (status);
720f4b3ec61Sdh155122 }
721f4b3ec61Sdh155122 
722f4b3ec61Sdh155122 /* ARGSUSED */
723f4b3ec61Sdh155122 static dladm_status_t
724*d62bc4baSyz147064 do_check_zone(datalink_id_t linkid, char **prop_val, uint_t val_cnt,
725*d62bc4baSyz147064     val_desc_t *vdp, boolean_t *needfreep)
726f4b3ec61Sdh155122 {
727f4b3ec61Sdh155122 	zoneid_t	zid;
728f4b3ec61Sdh155122 
729f4b3ec61Sdh155122 	if (val_cnt != 1)
730f4b3ec61Sdh155122 		return (DLADM_STATUS_BADVALCNT);
731f4b3ec61Sdh155122 
732f4b3ec61Sdh155122 	if ((zid = getzoneidbyname(*prop_val)) == -1)
733f4b3ec61Sdh155122 		return (DLADM_STATUS_BADVAL);
734f4b3ec61Sdh155122 
735f4b3ec61Sdh155122 	if (zid != GLOBAL_ZONEID) {
736f4b3ec61Sdh155122 		ushort_t	flags;
737f4b3ec61Sdh155122 
738f4b3ec61Sdh155122 		if (zone_getattr(zid, ZONE_ATTR_FLAGS, &flags,
739f4b3ec61Sdh155122 		    sizeof (flags)) < 0) {
740f4b3ec61Sdh155122 			return (dladm_errno2status(errno));
741f4b3ec61Sdh155122 		}
742f4b3ec61Sdh155122 
743f4b3ec61Sdh155122 		if (!(flags & ZF_NET_EXCL)) {
744f4b3ec61Sdh155122 			return (DLADM_STATUS_BADVAL);
745f4b3ec61Sdh155122 		}
746f4b3ec61Sdh155122 	}
747f4b3ec61Sdh155122 
748*d62bc4baSyz147064 	vdp->vd_val = zid;
749*d62bc4baSyz147064 	*needfreep = B_FALSE;
750f4b3ec61Sdh155122 	return (DLADM_STATUS_OK);
751f4b3ec61Sdh155122 }
752f4b3ec61Sdh155122 
753f4b3ec61Sdh155122 static dladm_status_t
754*d62bc4baSyz147064 do_get_autopush(datalink_id_t linkid, char **prop_val, uint_t *val_cnt)
755*d62bc4baSyz147064 {
756*d62bc4baSyz147064 	dld_ioc_ap_t	dia;
757*d62bc4baSyz147064 	int		fd, i, len;
758*d62bc4baSyz147064 
759*d62bc4baSyz147064 	if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0)
760*d62bc4baSyz147064 		return (dladm_errno2status(errno));
761*d62bc4baSyz147064 
762*d62bc4baSyz147064 	*val_cnt = 1;
763*d62bc4baSyz147064 	dia.dia_linkid = linkid;
764*d62bc4baSyz147064 	if (i_dladm_ioctl(fd, DLDIOC_GETAUTOPUSH, &dia, sizeof (dia)) < 0) {
765*d62bc4baSyz147064 		(*prop_val)[0] = '\0';
766*d62bc4baSyz147064 		goto done;
767*d62bc4baSyz147064 	}
768*d62bc4baSyz147064 
769*d62bc4baSyz147064 	for (i = 0, len = 0; i < dia.dia_npush; i++) {
770*d62bc4baSyz147064 		if (i != 0) {
771*d62bc4baSyz147064 			(void) snprintf(*prop_val + len,
772*d62bc4baSyz147064 			    DLADM_PROP_VAL_MAX - len, "%c", AP_DELIMITER);
773*d62bc4baSyz147064 			len += 1;
774*d62bc4baSyz147064 		}
775*d62bc4baSyz147064 		(void) snprintf(*prop_val + len, DLADM_PROP_VAL_MAX - len,
776*d62bc4baSyz147064 		    "%s", dia.dia_aplist[i]);
777*d62bc4baSyz147064 		len += strlen(dia.dia_aplist[i]);
778*d62bc4baSyz147064 		if (dia.dia_anchor - 1 == i) {
779*d62bc4baSyz147064 			(void) snprintf(*prop_val + len,
780*d62bc4baSyz147064 			    DLADM_PROP_VAL_MAX - len, "%c%s", AP_DELIMITER,
781*d62bc4baSyz147064 			    AP_ANCHOR);
782*d62bc4baSyz147064 			len += (strlen(AP_ANCHOR) + 1);
783*d62bc4baSyz147064 		}
784*d62bc4baSyz147064 	}
785*d62bc4baSyz147064 
786*d62bc4baSyz147064 done:
787*d62bc4baSyz147064 	(void) close(fd);
788*d62bc4baSyz147064 	return (DLADM_STATUS_OK);
789*d62bc4baSyz147064 }
790*d62bc4baSyz147064 
791*d62bc4baSyz147064 static dladm_status_t
792*d62bc4baSyz147064 do_set_autopush(datalink_id_t linkid, val_desc_t *vdp, uint_t val_cnt)
793*d62bc4baSyz147064 {
794*d62bc4baSyz147064 	dld_ioc_ap_t		dia;
795*d62bc4baSyz147064 	struct dlautopush	*dlap = (struct dlautopush *)vdp->vd_val;
796*d62bc4baSyz147064 	dladm_status_t		status = DLADM_STATUS_OK;
797*d62bc4baSyz147064 	int			fd, i;
798*d62bc4baSyz147064 	int			ic_cmd;
799*d62bc4baSyz147064 
800*d62bc4baSyz147064 	if (val_cnt != 1)
801*d62bc4baSyz147064 		return (DLADM_STATUS_BADVALCNT);
802*d62bc4baSyz147064 
803*d62bc4baSyz147064 	if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0)
804*d62bc4baSyz147064 		return (dladm_errno2status(errno));
805*d62bc4baSyz147064 
806*d62bc4baSyz147064 	dia.dia_linkid = linkid;
807*d62bc4baSyz147064 	if (dlap != NULL) {
808*d62bc4baSyz147064 		dia.dia_anchor = dlap->dap_anchor;
809*d62bc4baSyz147064 		dia.dia_npush = dlap->dap_npush;
810*d62bc4baSyz147064 		for (i = 0; i < dia.dia_npush; i++) {
811*d62bc4baSyz147064 			(void) strlcpy(dia.dia_aplist[i], dlap->dap_aplist[i],
812*d62bc4baSyz147064 			    FMNAMESZ+1);
813*d62bc4baSyz147064 		}
814*d62bc4baSyz147064 		ic_cmd = DLDIOC_SETAUTOPUSH;
815*d62bc4baSyz147064 	} else {
816*d62bc4baSyz147064 		ic_cmd = DLDIOC_CLRAUTOPUSH;
817*d62bc4baSyz147064 	}
818*d62bc4baSyz147064 
819*d62bc4baSyz147064 	if (i_dladm_ioctl(fd, ic_cmd, &dia, sizeof (dia)) < 0)
820*d62bc4baSyz147064 		status = dladm_errno2status(errno);
821*d62bc4baSyz147064 
822*d62bc4baSyz147064 	(void) close(fd);
823*d62bc4baSyz147064 	return (status);
824*d62bc4baSyz147064 }
825*d62bc4baSyz147064 
826*d62bc4baSyz147064 /*
827*d62bc4baSyz147064  * Add the specified module to the dlautopush structure; returns a
828*d62bc4baSyz147064  * DLADM_STATUS_* code.
829*d62bc4baSyz147064  */
830*d62bc4baSyz147064 dladm_status_t
831*d62bc4baSyz147064 i_dladm_add_ap_module(const char *module, struct dlautopush *dlap)
832*d62bc4baSyz147064 {
833*d62bc4baSyz147064 	if ((strlen(module) == 0) || (strlen(module) > FMNAMESZ))
834*d62bc4baSyz147064 		return (DLADM_STATUS_BADVAL);
835*d62bc4baSyz147064 
836*d62bc4baSyz147064 	if (strncasecmp(module, AP_ANCHOR, strlen(AP_ANCHOR)) == 0) {
837*d62bc4baSyz147064 		/*
838*d62bc4baSyz147064 		 * We don't allow multiple anchors, and the anchor must
839*d62bc4baSyz147064 		 * be after at least one module.
840*d62bc4baSyz147064 		 */
841*d62bc4baSyz147064 		if (dlap->dap_anchor != 0)
842*d62bc4baSyz147064 			return (DLADM_STATUS_BADVAL);
843*d62bc4baSyz147064 		if (dlap->dap_npush == 0)
844*d62bc4baSyz147064 			return (DLADM_STATUS_BADVAL);
845*d62bc4baSyz147064 
846*d62bc4baSyz147064 		dlap->dap_anchor = dlap->dap_npush;
847*d62bc4baSyz147064 		return (DLADM_STATUS_OK);
848*d62bc4baSyz147064 	}
849*d62bc4baSyz147064 	if (dlap->dap_npush > MAXAPUSH)
850*d62bc4baSyz147064 		return (DLADM_STATUS_BADVALCNT);
851*d62bc4baSyz147064 
852*d62bc4baSyz147064 	(void) strlcpy(dlap->dap_aplist[dlap->dap_npush++], module,
853*d62bc4baSyz147064 	    FMNAMESZ + 1);
854*d62bc4baSyz147064 
855*d62bc4baSyz147064 	return (DLADM_STATUS_OK);
856*d62bc4baSyz147064 }
857*d62bc4baSyz147064 
858*d62bc4baSyz147064 /*
859*d62bc4baSyz147064  * Currently, both '.' and ' '(space) can be used as the delimiters between
860*d62bc4baSyz147064  * autopush modules. The former is used in dladm set-linkprop, and the
861*d62bc4baSyz147064  * latter is used in the autopush(1M) file.
862*d62bc4baSyz147064  */
863*d62bc4baSyz147064 /* ARGSUSED */
864*d62bc4baSyz147064 static dladm_status_t
865*d62bc4baSyz147064 do_check_autopush(datalink_id_t linkid, char **prop_val, uint_t val_cnt,
866*d62bc4baSyz147064     val_desc_t *vdp, boolean_t *needfreep)
867*d62bc4baSyz147064 {
868*d62bc4baSyz147064 	char			*module;
869*d62bc4baSyz147064 	struct dlautopush	*dlap;
870*d62bc4baSyz147064 	dladm_status_t		status;
871*d62bc4baSyz147064 	char			val[DLADM_PROP_VAL_MAX];
872*d62bc4baSyz147064 	char			delimiters[4];
873*d62bc4baSyz147064 
874*d62bc4baSyz147064 	if (val_cnt != 1)
875*d62bc4baSyz147064 		return (DLADM_STATUS_BADVALCNT);
876*d62bc4baSyz147064 
877*d62bc4baSyz147064 	dlap = malloc(sizeof (struct dlautopush));
878*d62bc4baSyz147064 	if (dlap == NULL)
879*d62bc4baSyz147064 		return (DLADM_STATUS_NOMEM);
880*d62bc4baSyz147064 
881*d62bc4baSyz147064 	(void) memset(dlap, 0, sizeof (struct dlautopush));
882*d62bc4baSyz147064 	(void) snprintf(delimiters, 4, " %c\n", AP_DELIMITER);
883*d62bc4baSyz147064 	bcopy(*prop_val, val, DLADM_PROP_VAL_MAX);
884*d62bc4baSyz147064 	module = strtok(val, delimiters);
885*d62bc4baSyz147064 	while (module != NULL) {
886*d62bc4baSyz147064 		status = i_dladm_add_ap_module(module, dlap);
887*d62bc4baSyz147064 		if (status != DLADM_STATUS_OK)
888*d62bc4baSyz147064 			return (status);
889*d62bc4baSyz147064 		module = strtok(NULL, delimiters);
890*d62bc4baSyz147064 	}
891*d62bc4baSyz147064 
892*d62bc4baSyz147064 	vdp->vd_val = (uintptr_t)dlap;
893*d62bc4baSyz147064 	*needfreep = B_TRUE;
894*d62bc4baSyz147064 	return (DLADM_STATUS_OK);
895*d62bc4baSyz147064 }
896*d62bc4baSyz147064 
897*d62bc4baSyz147064 static dladm_status_t
898*d62bc4baSyz147064 do_get_rate_common(datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
899*d62bc4baSyz147064     uint_t id)
900*d62bc4baSyz147064 {
901*d62bc4baSyz147064 	wl_rates_t	*wrp;
902*d62bc4baSyz147064 	uint_t		i;
903*d62bc4baSyz147064 	wldp_t		*gbuf = NULL;
904*d62bc4baSyz147064 	dladm_status_t	status = DLADM_STATUS_OK;
905*d62bc4baSyz147064 
906*d62bc4baSyz147064 	if ((gbuf = malloc(MAX_BUF_LEN)) == NULL) {
907*d62bc4baSyz147064 		status = DLADM_STATUS_NOMEM;
908*d62bc4baSyz147064 		goto done;
909*d62bc4baSyz147064 	}
910*d62bc4baSyz147064 
911*d62bc4baSyz147064 	status = i_dladm_wlan_get_ioctl(linkid, gbuf, id);
912*d62bc4baSyz147064 	if (status != DLADM_STATUS_OK)
913*d62bc4baSyz147064 		goto done;
914*d62bc4baSyz147064 
915*d62bc4baSyz147064 	wrp = (wl_rates_t *)gbuf->wldp_buf;
916*d62bc4baSyz147064 	if (wrp->wl_rates_num > *val_cnt) {
917*d62bc4baSyz147064 		status = DLADM_STATUS_TOOSMALL;
918*d62bc4baSyz147064 		goto done;
919*d62bc4baSyz147064 	}
920*d62bc4baSyz147064 
921*d62bc4baSyz147064 	if (wrp->wl_rates_rates[0] == 0) {
922*d62bc4baSyz147064 		prop_val[0][0] = '\0';
923*d62bc4baSyz147064 		*val_cnt = 1;
924*d62bc4baSyz147064 		goto done;
925*d62bc4baSyz147064 	}
926*d62bc4baSyz147064 
927*d62bc4baSyz147064 	for (i = 0; i < wrp->wl_rates_num; i++) {
928*d62bc4baSyz147064 		(void) snprintf(prop_val[i], DLADM_STRSIZE, "%.*f",
929*d62bc4baSyz147064 		    wrp->wl_rates_rates[i] % 2,
930*d62bc4baSyz147064 		    (float)wrp->wl_rates_rates[i] / 2);
931*d62bc4baSyz147064 	}
932*d62bc4baSyz147064 	*val_cnt = wrp->wl_rates_num;
933*d62bc4baSyz147064 
934*d62bc4baSyz147064 done:
935*d62bc4baSyz147064 	free(gbuf);
936*d62bc4baSyz147064 	return (status);
937*d62bc4baSyz147064 }
938*d62bc4baSyz147064 
939*d62bc4baSyz147064 static dladm_status_t
940*d62bc4baSyz147064 do_get_rate_prop(datalink_id_t linkid, char **prop_val, uint_t *val_cnt)
941*d62bc4baSyz147064 {
942*d62bc4baSyz147064 	return (do_get_rate_common(linkid, prop_val, val_cnt,
943*d62bc4baSyz147064 	    WL_DESIRED_RATES));
944*d62bc4baSyz147064 }
945*d62bc4baSyz147064 
946*d62bc4baSyz147064 static dladm_status_t
947*d62bc4baSyz147064 do_get_rate_mod(datalink_id_t linkid, char **prop_val, uint_t *val_cnt)
948*d62bc4baSyz147064 {
949*d62bc4baSyz147064 	return (do_get_rate_common(linkid, prop_val, val_cnt,
950*d62bc4baSyz147064 	    WL_SUPPORTED_RATES));
951*d62bc4baSyz147064 }
952*d62bc4baSyz147064 
953*d62bc4baSyz147064 static dladm_status_t
954*d62bc4baSyz147064 do_set_rate(datalink_id_t linkid, dladm_wlan_rates_t *rates)
955f4b3ec61Sdh155122 {
956f4b3ec61Sdh155122 	int		i;
957*d62bc4baSyz147064 	uint_t		len;
958*d62bc4baSyz147064 	wldp_t		*gbuf;
959*d62bc4baSyz147064 	wl_rates_t	*wrp;
960*d62bc4baSyz147064 	dladm_status_t	status = DLADM_STATUS_OK;
961*d62bc4baSyz147064 
962*d62bc4baSyz147064 	if ((gbuf = malloc(MAX_BUF_LEN)) == NULL)
963*d62bc4baSyz147064 		return (DLADM_STATUS_NOMEM);
964*d62bc4baSyz147064 
965*d62bc4baSyz147064 	(void) memset(gbuf, 0, MAX_BUF_LEN);
966*d62bc4baSyz147064 
967*d62bc4baSyz147064 	wrp = (wl_rates_t *)gbuf->wldp_buf;
968*d62bc4baSyz147064 	for (i = 0; i < rates->wr_cnt; i++)
969*d62bc4baSyz147064 		wrp->wl_rates_rates[i] = rates->wr_rates[i];
970*d62bc4baSyz147064 	wrp->wl_rates_num = rates->wr_cnt;
971*d62bc4baSyz147064 
972*d62bc4baSyz147064 	len = offsetof(wl_rates_t, wl_rates_rates) +
973*d62bc4baSyz147064 	    (rates->wr_cnt * sizeof (char)) + WIFI_BUF_OFFSET;
974*d62bc4baSyz147064 	status = i_dladm_wlan_ioctl(linkid, gbuf, WL_DESIRED_RATES, len,
975*d62bc4baSyz147064 	    WLAN_SET_PARAM, len);
976*d62bc4baSyz147064 
977*d62bc4baSyz147064 	free(gbuf);
978*d62bc4baSyz147064 	return (status);
979*d62bc4baSyz147064 }
980*d62bc4baSyz147064 
981*d62bc4baSyz147064 static dladm_status_t
982*d62bc4baSyz147064 do_set_rate_prop(datalink_id_t linkid, val_desc_t *vdp, uint_t val_cnt)
983*d62bc4baSyz147064 {
984*d62bc4baSyz147064 	dladm_wlan_rates_t	rates;
985f4b3ec61Sdh155122 	dladm_status_t		status;
986f4b3ec61Sdh155122 
987*d62bc4baSyz147064 	if (val_cnt != 1)
988*d62bc4baSyz147064 		return (DLADM_STATUS_BADVALCNT);
989f4b3ec61Sdh155122 
990*d62bc4baSyz147064 	rates.wr_cnt = 1;
991*d62bc4baSyz147064 	rates.wr_rates[0] = vdp[0].vd_val;
992f4b3ec61Sdh155122 
993*d62bc4baSyz147064 	status = do_set_rate(linkid, &rates);
994f4b3ec61Sdh155122 
995*d62bc4baSyz147064 done:
996*d62bc4baSyz147064 	return (status);
997*d62bc4baSyz147064 }
998*d62bc4baSyz147064 
999*d62bc4baSyz147064 /* ARGSUSED */
1000*d62bc4baSyz147064 static dladm_status_t
1001*d62bc4baSyz147064 do_check_rate(datalink_id_t linkid, char **prop_val, uint_t val_cnt,
1002*d62bc4baSyz147064     val_desc_t *vdp, boolean_t *needfreep)
1003*d62bc4baSyz147064 {
1004*d62bc4baSyz147064 	int		i;
1005*d62bc4baSyz147064 	uint_t		modval_cnt = MAX_SUPPORT_RATES;
1006*d62bc4baSyz147064 	char		*buf, **modval;
1007*d62bc4baSyz147064 	dladm_status_t	status;
1008*d62bc4baSyz147064 
1009*d62bc4baSyz147064 	if (val_cnt != 1)
1010*d62bc4baSyz147064 		return (DLADM_STATUS_BADVALCNT);
1011*d62bc4baSyz147064 
1012*d62bc4baSyz147064 	buf = malloc((sizeof (char *) + DLADM_STRSIZE) *
1013*d62bc4baSyz147064 	    MAX_SUPPORT_RATES);
1014*d62bc4baSyz147064 	if (buf == NULL) {
1015*d62bc4baSyz147064 		status = DLADM_STATUS_NOMEM;
1016*d62bc4baSyz147064 		goto done;
1017*d62bc4baSyz147064 	}
1018*d62bc4baSyz147064 
1019*d62bc4baSyz147064 	modval = (char **)(void *)buf;
1020*d62bc4baSyz147064 	for (i = 0; i < MAX_SUPPORT_RATES; i++) {
1021*d62bc4baSyz147064 		modval[i] = buf + sizeof (char *) * MAX_SUPPORT_RATES +
1022*d62bc4baSyz147064 		    i * DLADM_STRSIZE;
1023*d62bc4baSyz147064 	}
1024*d62bc4baSyz147064 
1025*d62bc4baSyz147064 	status = do_get_rate_mod(linkid, modval, &modval_cnt);
1026*d62bc4baSyz147064 	if (status != DLADM_STATUS_OK)
1027*d62bc4baSyz147064 		goto done;
1028*d62bc4baSyz147064 
1029*d62bc4baSyz147064 	for (i = 0; i < modval_cnt; i++) {
1030*d62bc4baSyz147064 		if (strcasecmp(*prop_val, modval[i]) == 0) {
1031*d62bc4baSyz147064 			vdp->vd_val = (uint_t)(atof(*prop_val) * 2);
1032f4b3ec61Sdh155122 			status = DLADM_STATUS_OK;
1033f4b3ec61Sdh155122 
1034*d62bc4baSyz147064 			/*
1035*d62bc4baSyz147064 			 * Does not need the caller to free the vdp->vd_val
1036*d62bc4baSyz147064 			 */
1037*d62bc4baSyz147064 			*needfreep = B_FALSE;
1038f4b3ec61Sdh155122 			break;
1039f4b3ec61Sdh155122 		}
1040*d62bc4baSyz147064 	}
1041*d62bc4baSyz147064 	if (i == modval_cnt)
1042*d62bc4baSyz147064 		status = DLADM_STATUS_BADVAL;
1043*d62bc4baSyz147064 done:
1044*d62bc4baSyz147064 	free(buf);
1045*d62bc4baSyz147064 	return (status);
1046*d62bc4baSyz147064 }
1047f4b3ec61Sdh155122 
1048*d62bc4baSyz147064 static dladm_status_t
1049*d62bc4baSyz147064 do_get_phyconf(datalink_id_t linkid, wldp_t *gbuf)
1050*d62bc4baSyz147064 {
1051*d62bc4baSyz147064 	return (i_dladm_wlan_get_ioctl(linkid, gbuf, WL_PHY_CONFIG));
1052*d62bc4baSyz147064 }
1053*d62bc4baSyz147064 
1054*d62bc4baSyz147064 static dladm_status_t
1055*d62bc4baSyz147064 do_get_channel_prop(datalink_id_t linkid, char **prop_val, uint_t *val_cnt)
1056*d62bc4baSyz147064 {
1057*d62bc4baSyz147064 	uint32_t	channel;
1058*d62bc4baSyz147064 	wldp_t		*gbuf;
1059*d62bc4baSyz147064 	dladm_status_t	status = DLADM_STATUS_OK;
1060*d62bc4baSyz147064 
1061*d62bc4baSyz147064 	if ((gbuf = malloc(MAX_BUF_LEN)) == NULL)
1062*d62bc4baSyz147064 		return (DLADM_STATUS_NOMEM);
1063*d62bc4baSyz147064 
1064*d62bc4baSyz147064 	if ((status = do_get_phyconf(linkid, gbuf)) != DLADM_STATUS_OK)
1065*d62bc4baSyz147064 		goto done;
1066*d62bc4baSyz147064 
1067*d62bc4baSyz147064 	if (!i_dladm_wlan_convert_chan((wl_phy_conf_t *)gbuf->wldp_buf,
1068*d62bc4baSyz147064 	    &channel)) {
1069*d62bc4baSyz147064 		status = DLADM_STATUS_NOTFOUND;
1070*d62bc4baSyz147064 		goto done;
1071*d62bc4baSyz147064 	}
1072*d62bc4baSyz147064 
1073*d62bc4baSyz147064 	(void) snprintf(*prop_val, DLADM_STRSIZE, "%u", channel);
1074*d62bc4baSyz147064 	*val_cnt = 1;
1075*d62bc4baSyz147064 
1076*d62bc4baSyz147064 done:
1077*d62bc4baSyz147064 	free(gbuf);
1078*d62bc4baSyz147064 	return (status);
1079*d62bc4baSyz147064 }
1080*d62bc4baSyz147064 
1081*d62bc4baSyz147064 static dladm_status_t
1082*d62bc4baSyz147064 do_get_powermode(datalink_id_t linkid, wldp_t *gbuf)
1083*d62bc4baSyz147064 {
1084*d62bc4baSyz147064 	return (i_dladm_wlan_get_ioctl(linkid, gbuf, WL_POWER_MODE));
1085*d62bc4baSyz147064 }
1086*d62bc4baSyz147064 
1087*d62bc4baSyz147064 static dladm_status_t
1088*d62bc4baSyz147064 do_get_powermode_prop(datalink_id_t linkid, char **prop_val, uint_t *val_cnt)
1089*d62bc4baSyz147064 {
1090*d62bc4baSyz147064 	wl_ps_mode_t	*mode;
1091*d62bc4baSyz147064 	const char	*s;
1092*d62bc4baSyz147064 	wldp_t		*gbuf;
1093*d62bc4baSyz147064 	dladm_status_t	status = DLADM_STATUS_OK;
1094*d62bc4baSyz147064 
1095*d62bc4baSyz147064 	if ((gbuf = malloc(MAX_BUF_LEN)) == NULL)
1096*d62bc4baSyz147064 		return (DLADM_STATUS_NOMEM);
1097*d62bc4baSyz147064 
1098*d62bc4baSyz147064 	if ((status = do_get_powermode(linkid, gbuf)) != DLADM_STATUS_OK)
1099*d62bc4baSyz147064 		goto done;
1100*d62bc4baSyz147064 
1101*d62bc4baSyz147064 	mode = (wl_ps_mode_t *)(gbuf->wldp_buf);
1102*d62bc4baSyz147064 	switch (mode->wl_ps_mode) {
1103*d62bc4baSyz147064 	case WL_PM_AM:
1104*d62bc4baSyz147064 		s = "off";
1105f4b3ec61Sdh155122 		break;
1106*d62bc4baSyz147064 	case WL_PM_MPS:
1107*d62bc4baSyz147064 		s = "max";
1108*d62bc4baSyz147064 		break;
1109*d62bc4baSyz147064 	case WL_PM_FAST:
1110*d62bc4baSyz147064 		s = "fast";
1111f4b3ec61Sdh155122 		break;
1112f4b3ec61Sdh155122 	default:
1113*d62bc4baSyz147064 		status = DLADM_STATUS_NOTFOUND;
1114*d62bc4baSyz147064 		goto done;
1115f4b3ec61Sdh155122 	}
1116*d62bc4baSyz147064 	(void) snprintf(*prop_val, DLADM_STRSIZE, "%s", s);
1117*d62bc4baSyz147064 	*val_cnt = 1;
1118*d62bc4baSyz147064 
1119*d62bc4baSyz147064 done:
1120*d62bc4baSyz147064 	free(gbuf);
1121*d62bc4baSyz147064 	return (status);
1122*d62bc4baSyz147064 }
1123*d62bc4baSyz147064 
1124*d62bc4baSyz147064 static dladm_status_t
1125*d62bc4baSyz147064 do_set_powermode(datalink_id_t linkid, dladm_wlan_powermode_t *pm)
1126*d62bc4baSyz147064 {
1127*d62bc4baSyz147064 	wl_ps_mode_t    ps_mode;
1128*d62bc4baSyz147064 
1129*d62bc4baSyz147064 	(void) memset(&ps_mode, 0xff, sizeof (ps_mode));
1130*d62bc4baSyz147064 
1131*d62bc4baSyz147064 	switch (*pm) {
1132*d62bc4baSyz147064 	case DLADM_WLAN_PM_OFF:
1133*d62bc4baSyz147064 		ps_mode.wl_ps_mode = WL_PM_AM;
1134*d62bc4baSyz147064 		break;
1135*d62bc4baSyz147064 	case DLADM_WLAN_PM_MAX:
1136*d62bc4baSyz147064 		ps_mode.wl_ps_mode = WL_PM_MPS;
1137*d62bc4baSyz147064 		break;
1138*d62bc4baSyz147064 	case DLADM_WLAN_PM_FAST:
1139*d62bc4baSyz147064 		ps_mode.wl_ps_mode = WL_PM_FAST;
1140*d62bc4baSyz147064 		break;
1141*d62bc4baSyz147064 	default:
1142*d62bc4baSyz147064 		return (DLADM_STATUS_NOTSUP);
1143*d62bc4baSyz147064 	}
1144*d62bc4baSyz147064 	return (i_dladm_wlan_set_ioctl(linkid, WL_POWER_MODE, &ps_mode,
1145*d62bc4baSyz147064 	    sizeof (ps_mode)));
1146*d62bc4baSyz147064 }
1147*d62bc4baSyz147064 
1148*d62bc4baSyz147064 /* ARGSUSED */
1149*d62bc4baSyz147064 static dladm_status_t
1150*d62bc4baSyz147064 do_set_powermode_prop(datalink_id_t linkid, val_desc_t *vdp, uint_t val_cnt)
1151*d62bc4baSyz147064 {
1152*d62bc4baSyz147064 	dladm_wlan_powermode_t powermode = (dladm_wlan_powermode_t)vdp->vd_val;
1153*d62bc4baSyz147064 	dladm_status_t status;
1154*d62bc4baSyz147064 
1155*d62bc4baSyz147064 	if (val_cnt != 1)
1156*d62bc4baSyz147064 		return (DLADM_STATUS_BADVALCNT);
1157*d62bc4baSyz147064 
1158*d62bc4baSyz147064 	status = do_set_powermode(linkid, &powermode);
1159f4b3ec61Sdh155122 
1160f4b3ec61Sdh155122 	return (status);
1161f4b3ec61Sdh155122 }
1162f4b3ec61Sdh155122 
1163f4b3ec61Sdh155122 static dladm_status_t
1164*d62bc4baSyz147064 do_get_radio(datalink_id_t linkid, wldp_t *gbuf)
1165f4b3ec61Sdh155122 {
1166*d62bc4baSyz147064 	return (i_dladm_wlan_get_ioctl(linkid, gbuf, WL_RADIO));
1167*d62bc4baSyz147064 }
1168*d62bc4baSyz147064 
1169*d62bc4baSyz147064 static dladm_status_t
1170*d62bc4baSyz147064 do_get_radio_prop(datalink_id_t linkid, char **prop_val, uint_t *val_cnt)
1171*d62bc4baSyz147064 {
1172*d62bc4baSyz147064 	wl_radio_t	radio;
1173*d62bc4baSyz147064 	const char	*s;
1174*d62bc4baSyz147064 	wldp_t		*gbuf;
1175*d62bc4baSyz147064 	dladm_status_t	status = DLADM_STATUS_OK;
1176*d62bc4baSyz147064 
1177*d62bc4baSyz147064 	if ((gbuf = malloc(MAX_BUF_LEN)) == NULL)
1178*d62bc4baSyz147064 		return (DLADM_STATUS_NOMEM);
1179*d62bc4baSyz147064 
1180*d62bc4baSyz147064 	if ((status = do_get_radio(linkid, gbuf)) != DLADM_STATUS_OK)
1181*d62bc4baSyz147064 		goto done;
1182*d62bc4baSyz147064 
1183*d62bc4baSyz147064 	radio = *(wl_radio_t *)(gbuf->wldp_buf);
1184*d62bc4baSyz147064 	switch (radio) {
1185*d62bc4baSyz147064 	case B_TRUE:
1186*d62bc4baSyz147064 		s = "on";
1187*d62bc4baSyz147064 		break;
1188*d62bc4baSyz147064 	case B_FALSE:
1189*d62bc4baSyz147064 		s = "off";
1190*d62bc4baSyz147064 		break;
1191*d62bc4baSyz147064 	default:
1192*d62bc4baSyz147064 		status = DLADM_STATUS_NOTFOUND;
1193*d62bc4baSyz147064 		goto done;
1194*d62bc4baSyz147064 	}
1195*d62bc4baSyz147064 	(void) snprintf(*prop_val, DLADM_STRSIZE, "%s", s);
1196*d62bc4baSyz147064 	*val_cnt = 1;
1197*d62bc4baSyz147064 
1198*d62bc4baSyz147064 done:
1199*d62bc4baSyz147064 	free(gbuf);
1200*d62bc4baSyz147064 	return (status);
1201*d62bc4baSyz147064 }
1202*d62bc4baSyz147064 
1203*d62bc4baSyz147064 static dladm_status_t
1204*d62bc4baSyz147064 do_set_radio(datalink_id_t linkid, dladm_wlan_radio_t *radio)
1205*d62bc4baSyz147064 {
1206*d62bc4baSyz147064 	wl_radio_t r;
1207*d62bc4baSyz147064 
1208*d62bc4baSyz147064 	switch (*radio) {
1209*d62bc4baSyz147064 	case DLADM_WLAN_RADIO_ON:
1210*d62bc4baSyz147064 		r = B_TRUE;
1211*d62bc4baSyz147064 		break;
1212*d62bc4baSyz147064 	case DLADM_WLAN_RADIO_OFF:
1213*d62bc4baSyz147064 		r = B_FALSE;
1214*d62bc4baSyz147064 		break;
1215*d62bc4baSyz147064 	default:
1216*d62bc4baSyz147064 		return (DLADM_STATUS_NOTSUP);
1217*d62bc4baSyz147064 	}
1218*d62bc4baSyz147064 	return (i_dladm_wlan_set_ioctl(linkid, WL_RADIO, &r, sizeof (r)));
1219*d62bc4baSyz147064 }
1220*d62bc4baSyz147064 
1221*d62bc4baSyz147064 /* ARGSUSED */
1222*d62bc4baSyz147064 static dladm_status_t
1223*d62bc4baSyz147064 do_set_radio_prop(datalink_id_t linkid, val_desc_t *vdp, uint_t val_cnt)
1224*d62bc4baSyz147064 {
1225*d62bc4baSyz147064 	dladm_wlan_radio_t radio = (dladm_wlan_radio_t)vdp->vd_val;
1226f4b3ec61Sdh155122 	dladm_status_t status;
1227f4b3ec61Sdh155122 
1228*d62bc4baSyz147064 	if (val_cnt != 1)
1229*d62bc4baSyz147064 		return (DLADM_STATUS_BADVALCNT);
1230f4b3ec61Sdh155122 
1231*d62bc4baSyz147064 	status = do_set_radio(linkid, &radio);
1232f4b3ec61Sdh155122 
1233*d62bc4baSyz147064 	return (status);
1234*d62bc4baSyz147064 }
1235f4b3ec61Sdh155122 
1236*d62bc4baSyz147064 static dladm_status_t
1237*d62bc4baSyz147064 i_dladm_set_linkprop_db(datalink_id_t linkid, const char *prop_name,
1238*d62bc4baSyz147064     char **prop_val, uint_t val_cnt)
1239*d62bc4baSyz147064 {
1240*d62bc4baSyz147064 	char		buf[MAXLINELEN];
1241*d62bc4baSyz147064 	int		i;
1242*d62bc4baSyz147064 	dladm_conf_t	conf;
1243*d62bc4baSyz147064 	dladm_status_t	status;
1244*d62bc4baSyz147064 
1245*d62bc4baSyz147064 	status = dladm_read_conf(linkid, &conf);
1246f4b3ec61Sdh155122 	if (status != DLADM_STATUS_OK)
1247f4b3ec61Sdh155122 		return (status);
1248f4b3ec61Sdh155122 
1249*d62bc4baSyz147064 	/*
1250*d62bc4baSyz147064 	 * reset case.
1251*d62bc4baSyz147064 	 */
1252*d62bc4baSyz147064 	if (val_cnt == 0) {
1253*d62bc4baSyz147064 		status = dladm_unset_conf_field(conf, prop_name);
1254*d62bc4baSyz147064 		if (status == DLADM_STATUS_OK)
1255*d62bc4baSyz147064 			status = dladm_write_conf(conf);
1256*d62bc4baSyz147064 		goto done;
1257f4b3ec61Sdh155122 	}
1258f4b3ec61Sdh155122 
1259*d62bc4baSyz147064 	buf[0] = '\0';
1260*d62bc4baSyz147064 	for (i = 0; i < val_cnt; i++) {
1261*d62bc4baSyz147064 		(void) strlcat(buf, prop_val[i], MAXLINELEN);
1262*d62bc4baSyz147064 		if (i != val_cnt - 1)
1263*d62bc4baSyz147064 			(void) strlcat(buf, ",", MAXLINELEN);
1264*d62bc4baSyz147064 	}
1265f4b3ec61Sdh155122 
1266*d62bc4baSyz147064 	status = dladm_set_conf_field(conf, prop_name, DLADM_TYPE_STR, buf);
1267*d62bc4baSyz147064 	if (status == DLADM_STATUS_OK)
1268*d62bc4baSyz147064 		status = dladm_write_conf(conf);
1269*d62bc4baSyz147064 
1270*d62bc4baSyz147064 done:
1271*d62bc4baSyz147064 	dladm_destroy_conf(conf);
1272f4b3ec61Sdh155122 	return (status);
1273f4b3ec61Sdh155122 }
1274f4b3ec61Sdh155122 
1275f4b3ec61Sdh155122 static dladm_status_t
1276*d62bc4baSyz147064 i_dladm_get_linkprop_db(datalink_id_t linkid, const char *prop_name,
1277*d62bc4baSyz147064     char **prop_val, uint_t *val_cntp)
1278f4b3ec61Sdh155122 {
1279*d62bc4baSyz147064 	char		buf[MAXLINELEN], *str;
1280*d62bc4baSyz147064 	uint_t		cnt = 0;
1281*d62bc4baSyz147064 	dladm_conf_t	conf;
1282*d62bc4baSyz147064 	dladm_status_t	status;
1283f4b3ec61Sdh155122 
1284*d62bc4baSyz147064 	status = dladm_read_conf(linkid, &conf);
1285*d62bc4baSyz147064 	if (status != DLADM_STATUS_OK)
1286f4b3ec61Sdh155122 		return (status);
1287*d62bc4baSyz147064 
1288*d62bc4baSyz147064 	status = dladm_get_conf_field(conf, prop_name, buf, MAXLINELEN);
1289*d62bc4baSyz147064 	if (status != DLADM_STATUS_OK)
1290*d62bc4baSyz147064 		goto done;
1291*d62bc4baSyz147064 
1292*d62bc4baSyz147064 	str = strtok(buf, ",");
1293*d62bc4baSyz147064 	while (str != NULL) {
1294*d62bc4baSyz147064 		if (cnt == *val_cntp) {
1295*d62bc4baSyz147064 			status = DLADM_STATUS_TOOSMALL;
1296*d62bc4baSyz147064 			goto done;
1297*d62bc4baSyz147064 		}
1298*d62bc4baSyz147064 		(void) strlcpy(prop_val[cnt++], str, DLADM_PROP_VAL_MAX);
1299*d62bc4baSyz147064 		str = strtok(NULL, ",");
1300f4b3ec61Sdh155122 	}
1301f4b3ec61Sdh155122 
1302*d62bc4baSyz147064 	*val_cntp = cnt;
1303f4b3ec61Sdh155122 
1304*d62bc4baSyz147064 done:
1305*d62bc4baSyz147064 	dladm_destroy_conf(conf);
1306*d62bc4baSyz147064 	return (status);
1307f4b3ec61Sdh155122 }
1308