13147Sxc151355 /*
23147Sxc151355  * CDDL HEADER START
33147Sxc151355  *
43147Sxc151355  * The contents of this file are subject to the terms of the
53147Sxc151355  * Common Development and Distribution License (the "License").
63147Sxc151355  * You may not use this file except in compliance with the License.
73147Sxc151355  *
83147Sxc151355  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
93147Sxc151355  * or http://www.opensolaris.org/os/licensing.
103147Sxc151355  * See the License for the specific language governing permissions
113147Sxc151355  * and limitations under the License.
123147Sxc151355  *
133147Sxc151355  * When distributing Covered Code, include this CDDL HEADER in each
143147Sxc151355  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
153147Sxc151355  * If applicable, add the following below this CDDL HEADER, with the
163147Sxc151355  * fields enclosed by brackets "[]" replaced with your own identifying
173147Sxc151355  * information: Portions Copyright [yyyy] [name of copyright owner]
183147Sxc151355  *
193147Sxc151355  * CDDL HEADER END
203147Sxc151355  */
213147Sxc151355 /*
22*5895Syz147064  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
233147Sxc151355  * Use is subject to license terms.
243147Sxc151355  */
253147Sxc151355 
263147Sxc151355 #pragma ident	"%Z%%M%	%I%	%E% SMI"
273147Sxc151355 
283147Sxc151355 #include <stdlib.h>
293147Sxc151355 #include <strings.h>
303147Sxc151355 #include <errno.h>
313147Sxc151355 #include <ctype.h>
32*5895Syz147064 #include <stddef.h>
333448Sdh155122 #include <sys/types.h>
343147Sxc151355 #include <sys/stat.h>
353448Sdh155122 #include <sys/dld.h>
363448Sdh155122 #include <sys/zone.h>
373448Sdh155122 #include <fcntl.h>
383448Sdh155122 #include <unistd.h>
393448Sdh155122 #include <libdevinfo.h>
403448Sdh155122 #include <zone.h>
413871Syz147064 #include <libdllink.h>
423147Sxc151355 #include <libdladm_impl.h>
43*5895Syz147064 #include <libdlwlan_impl.h>
443871Syz147064 #include <libdlwlan.h>
45*5895Syz147064 #include <libdlvlan.h>
463448Sdh155122 #include <dlfcn.h>
473448Sdh155122 #include <link.h>
48*5895Syz147064 #include <inet/wifi_ioctl.h>
493448Sdh155122 
50*5895Syz147064 /*
51*5895Syz147064  * The linkprop get() callback.
52*5895Syz147064  * - propstrp:	a property string array to keep the returned property.
53*5895Syz147064  *		Caller allocated.
54*5895Syz147064  * - cntp:	number of returned properties.
55*5895Syz147064  *		Caller also uses it to indicate how many it expects.
56*5895Syz147064  */
57*5895Syz147064 typedef dladm_status_t	pd_getf_t(datalink_id_t, char **propstp, uint_t *cntp);
58*5895Syz147064 
59*5895Syz147064 /*
60*5895Syz147064  * The linkprop set() callback.
61*5895Syz147064  * - propval:	a val_desc_t array which keeps the property values to be set.
62*5895Syz147064  * - cnt:	number of properties to be set.
63*5895Syz147064  */
64*5895Syz147064 typedef dladm_status_t	pd_setf_t(datalink_id_t, val_desc_t *propval,
65*5895Syz147064 			    uint_t cnt);
663448Sdh155122 
67*5895Syz147064 #define	PD_TEMPONLY	0x1
683448Sdh155122 
69*5895Syz147064 /*
70*5895Syz147064  * The linkprop check() callback.
71*5895Syz147064  * - propstrp:	property string array which keeps the property to be checked.
72*5895Syz147064  * - cnt:	number of properties.
73*5895Syz147064  * - propval:	return value; the property values of the given property strings.
74*5895Syz147064  * - dofree:	indicates whether the caller needs to free propvalp->vd_val.
75*5895Syz147064  */
76*5895Syz147064 typedef dladm_status_t	pd_checkf_t(datalink_id_t, char **propstrp,
77*5895Syz147064 			    uint_t cnt, val_desc_t *propval, boolean_t *dofree);
783448Sdh155122 
79*5895Syz147064 static pd_getf_t	do_get_zone, do_get_autopush, do_get_rate_mod,
80*5895Syz147064 			do_get_rate_prop, do_get_channel_prop,
81*5895Syz147064 			do_get_powermode_prop, do_get_radio_prop;
82*5895Syz147064 static pd_setf_t	do_set_zone, do_set_autopush, do_set_rate_prop,
83*5895Syz147064 			do_set_powermode_prop, do_set_radio_prop;
84*5895Syz147064 static pd_checkf_t	do_check_zone, do_check_autopush, do_check_rate;
853448Sdh155122 
863448Sdh155122 typedef struct prop_desc {
87*5895Syz147064 	/*
88*5895Syz147064 	 * link property name
89*5895Syz147064 	 */
90*5895Syz147064 	char			*pd_name;
91*5895Syz147064 
92*5895Syz147064 	/*
93*5895Syz147064 	 * default property value, can be set to { "", NULL }
94*5895Syz147064 	 */
95*5895Syz147064 	val_desc_t		pd_defval;
96*5895Syz147064 
97*5895Syz147064 	/*
98*5895Syz147064 	 * list of optional property values, can be NULL.
99*5895Syz147064 	 *
100*5895Syz147064 	 * This is set to non-NULL if there is a list of possible property
101*5895Syz147064 	 * values.  pd_optval would point to the array of possible values.
102*5895Syz147064 	 */
103*5895Syz147064 	val_desc_t		*pd_optval;
104*5895Syz147064 
105*5895Syz147064 	/*
106*5895Syz147064 	 * count of the above optional property values. 0 if pd_optval is NULL.
107*5895Syz147064 	 */
108*5895Syz147064 	uint_t			pd_noptval;
109*5895Syz147064 
110*5895Syz147064 	/*
111*5895Syz147064 	 * callback to set link property;
112*5895Syz147064 	 * set to NULL if this property is read-only
113*5895Syz147064 	 */
114*5895Syz147064 	pd_setf_t		*pd_set;
115*5895Syz147064 
116*5895Syz147064 	/*
117*5895Syz147064 	 * callback to get modifiable link property
118*5895Syz147064 	 */
119*5895Syz147064 	pd_getf_t		*pd_getmod;
120*5895Syz147064 
121*5895Syz147064 	/*
122*5895Syz147064 	 * callback to get current link property
123*5895Syz147064 	 */
124*5895Syz147064 	pd_getf_t		*pd_get;
125*5895Syz147064 
126*5895Syz147064 	/*
127*5895Syz147064 	 * callback to validate link property value, set to NULL if pd_optval
128*5895Syz147064 	 * is not NULL. In that case, validate the value by comparing it with
129*5895Syz147064 	 * the pd_optval. Return a val_desc_t array pointer if the value is
130*5895Syz147064 	 * valid.
131*5895Syz147064 	 */
132*5895Syz147064 	pd_checkf_t		*pd_check;
133*5895Syz147064 
134*5895Syz147064 	/*
135*5895Syz147064 	 * currently only PD_TEMPONLY is valid, which indicates the property
136*5895Syz147064 	 * is temporary only.
137*5895Syz147064 	 */
138*5895Syz147064 	uint_t			pd_flags;
139*5895Syz147064 
140*5895Syz147064 	/*
141*5895Syz147064 	 * indicate link classes this property applies to.
142*5895Syz147064 	 */
143*5895Syz147064 	datalink_class_t	pd_class;
144*5895Syz147064 
145*5895Syz147064 	/*
146*5895Syz147064 	 * indicate link media type this property applies to.
147*5895Syz147064 	 */
148*5895Syz147064 	datalink_media_t	pd_dmedia;
1493448Sdh155122 } prop_desc_t;
1503448Sdh155122 
151*5895Syz147064 static val_desc_t	dladm_wlan_radio_vals[] = {
152*5895Syz147064 	{ "on",		DLADM_WLAN_RADIO_ON	},
153*5895Syz147064 	{ "off",	DLADM_WLAN_RADIO_OFF	}
154*5895Syz147064 };
155*5895Syz147064 
156*5895Syz147064 static val_desc_t	dladm_wlan_powermode_vals[] = {
157*5895Syz147064 	{ "off",	DLADM_WLAN_PM_OFF	},
158*5895Syz147064 	{ "fast",	DLADM_WLAN_PM_FAST	},
159*5895Syz147064 	{ "max",	DLADM_WLAN_PM_MAX	}
160*5895Syz147064 };
161*5895Syz147064 
1623448Sdh155122 static prop_desc_t	prop_table[] = {
163*5895Syz147064 
164*5895Syz147064 	{ "channel",	{ NULL, 0 }, NULL, 0, NULL, NULL,
165*5895Syz147064 	    do_get_channel_prop, NULL, 0,
166*5895Syz147064 	    DATALINK_CLASS_PHYS, DL_WIFI},
167*5895Syz147064 
168*5895Syz147064 	{ "powermode",	{ "off", DLADM_WLAN_PM_OFF },
169*5895Syz147064 	    dladm_wlan_powermode_vals, VALCNT(dladm_wlan_powermode_vals),
170*5895Syz147064 	    do_set_powermode_prop, NULL,
171*5895Syz147064 	    do_get_powermode_prop, NULL, 0,
172*5895Syz147064 	    DATALINK_CLASS_PHYS, DL_WIFI},
173*5895Syz147064 
174*5895Syz147064 	{ "radio",	{ "on", DLADM_WLAN_RADIO_ON },
175*5895Syz147064 	    dladm_wlan_radio_vals, VALCNT(dladm_wlan_radio_vals),
176*5895Syz147064 	    do_set_radio_prop, NULL,
177*5895Syz147064 	    do_get_radio_prop, NULL, 0,
178*5895Syz147064 	    DATALINK_CLASS_PHYS, DL_WIFI},
179*5895Syz147064 
180*5895Syz147064 	{ "speed",	{ "", 0 }, NULL, 0,
181*5895Syz147064 	    do_set_rate_prop, do_get_rate_mod,
182*5895Syz147064 	    do_get_rate_prop, do_check_rate, 0,
183*5895Syz147064 	    DATALINK_CLASS_PHYS, DL_WIFI},
184*5895Syz147064 
185*5895Syz147064 	{ "autopush",	{ "", NULL }, NULL, 0,
186*5895Syz147064 	    do_set_autopush, NULL,
187*5895Syz147064 	    do_get_autopush, do_check_autopush, 0,
188*5895Syz147064 	    DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE},
189*5895Syz147064 
190*5895Syz147064 	{ "zone",	{ "", NULL }, NULL, 0,
1913448Sdh155122 	    do_set_zone, NULL,
192*5895Syz147064 	    do_get_zone, do_check_zone, PD_TEMPONLY,
193*5895Syz147064 	    DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE}
1943448Sdh155122 };
1953448Sdh155122 
196*5895Syz147064 #define	DLADM_MAX_PROPS	(sizeof (prop_table) / sizeof (prop_desc_t))
197*5895Syz147064 
198*5895Syz147064 static dladm_status_t	i_dladm_set_linkprop_db(datalink_id_t, const char *,
199*5895Syz147064 			    char **, uint_t);
200*5895Syz147064 static dladm_status_t	i_dladm_get_linkprop_db(datalink_id_t, const char *,
201*5895Syz147064 			    char **, uint_t *);
202*5895Syz147064 static dladm_status_t	i_dladm_set_single_prop(datalink_id_t, datalink_class_t,
203*5895Syz147064 			    uint32_t, prop_desc_t *, char **, uint_t, uint_t);
204*5895Syz147064 static dladm_status_t	i_dladm_set_linkprop(datalink_id_t, const char *,
205*5895Syz147064 			    char **, uint_t, uint_t);
206*5895Syz147064 
207*5895Syz147064 /*
208*5895Syz147064  * Unfortunately, MAX_SCAN_SUPPORT_RATES is too small to allow all
209*5895Syz147064  * rates to be retrieved. However, we cannot increase it at this
210*5895Syz147064  * time because it will break binary compatibility with unbundled
211*5895Syz147064  * WiFi drivers and utilities. So for now we define an additional
212*5895Syz147064  * constant, MAX_SUPPORT_RATES, to allow all rates to be retrieved.
213*5895Syz147064  */
214*5895Syz147064 #define	MAX_SUPPORT_RATES	64
215*5895Syz147064 
216*5895Syz147064 #define	AP_ANCHOR	"[anchor]"
217*5895Syz147064 #define	AP_DELIMITER	'.'
218*5895Syz147064 
219*5895Syz147064 static dladm_status_t
220*5895Syz147064 do_check_prop(prop_desc_t *pdp, char **prop_val, uint_t val_cnt,
221*5895Syz147064     val_desc_t *vdp)
222*5895Syz147064 {
223*5895Syz147064 	int		i, j;
224*5895Syz147064 	dladm_status_t	status = DLADM_STATUS_OK;
2253147Sxc151355 
226*5895Syz147064 	for (j = 0; j < val_cnt; j++) {
227*5895Syz147064 		for (i = 0; i < pdp->pd_noptval; i++) {
228*5895Syz147064 			if (strcasecmp(*prop_val,
229*5895Syz147064 			    pdp->pd_optval[i].vd_name) == 0) {
230*5895Syz147064 				break;
231*5895Syz147064 			}
232*5895Syz147064 		}
233*5895Syz147064 		if (i == pdp->pd_noptval) {
234*5895Syz147064 			status = DLADM_STATUS_BADVAL;
235*5895Syz147064 			goto done;
236*5895Syz147064 		}
237*5895Syz147064 		(void) memcpy(vdp + j, &pdp->pd_optval[i], sizeof (val_desc_t));
238*5895Syz147064 	}
239*5895Syz147064 
240*5895Syz147064 done:
241*5895Syz147064 	return (status);
242*5895Syz147064 }
243*5895Syz147064 
244*5895Syz147064 static dladm_status_t
245*5895Syz147064 i_dladm_set_single_prop(datalink_id_t linkid, datalink_class_t class,
246*5895Syz147064     uint32_t media, prop_desc_t *pdp, char **prop_val, uint_t val_cnt,
247*5895Syz147064     uint_t flags)
2483147Sxc151355 {
249*5895Syz147064 	dladm_status_t	status = DLADM_STATUS_OK;
250*5895Syz147064 	val_desc_t	*vdp = NULL;
251*5895Syz147064 	boolean_t	needfree = B_FALSE;
252*5895Syz147064 	uint_t		cnt, i;
2533147Sxc151355 
254*5895Syz147064 	if (!(pdp->pd_class & class))
255*5895Syz147064 		return (DLADM_STATUS_BADARG);
256*5895Syz147064 
257*5895Syz147064 	if (!DATALINK_MEDIA_ACCEPTED(pdp->pd_dmedia, media))
2583147Sxc151355 		return (DLADM_STATUS_BADARG);
2593147Sxc151355 
260*5895Syz147064 	if ((flags & DLADM_OPT_PERSIST) && (pdp->pd_flags & PD_TEMPONLY))
261*5895Syz147064 		return (DLADM_STATUS_TEMPONLY);
262*5895Syz147064 
263*5895Syz147064 	if (!(flags & DLADM_OPT_ACTIVE))
264*5895Syz147064 		return (DLADM_STATUS_OK);
265*5895Syz147064 
266*5895Syz147064 	if (pdp->pd_set == NULL)
267*5895Syz147064 		return (DLADM_STATUS_PROPRDONLY);
2683448Sdh155122 
269*5895Syz147064 	if (prop_val != NULL) {
270*5895Syz147064 		vdp = malloc(sizeof (val_desc_t) * val_cnt);
271*5895Syz147064 		if (vdp == NULL)
272*5895Syz147064 			return (DLADM_STATUS_NOMEM);
273*5895Syz147064 
274*5895Syz147064 		if (pdp->pd_check != NULL) {
275*5895Syz147064 			status = pdp->pd_check(linkid, prop_val, val_cnt, vdp,
276*5895Syz147064 			    &needfree);
277*5895Syz147064 		} else if (pdp->pd_optval != NULL) {
278*5895Syz147064 			status = do_check_prop(pdp, prop_val, val_cnt, vdp);
279*5895Syz147064 		} else {
2803448Sdh155122 			status = DLADM_STATUS_BADARG;
2813147Sxc151355 		}
282*5895Syz147064 
2833147Sxc151355 		if (status != DLADM_STATUS_OK)
284*5895Syz147064 			goto done;
285*5895Syz147064 
286*5895Syz147064 		cnt = val_cnt;
287*5895Syz147064 	} else {
288*5895Syz147064 		if (pdp->pd_defval.vd_name == NULL)
289*5895Syz147064 			return (DLADM_STATUS_NOTSUP);
290*5895Syz147064 
291*5895Syz147064 		if ((vdp = malloc(sizeof (val_desc_t))) == NULL)
292*5895Syz147064 			return (DLADM_STATUS_NOMEM);
293*5895Syz147064 
294*5895Syz147064 		(void) memcpy(vdp, &pdp->pd_defval, sizeof (val_desc_t));
295*5895Syz147064 		cnt = 1;
296*5895Syz147064 	}
297*5895Syz147064 	status = pdp->pd_set(linkid, vdp, cnt);
298*5895Syz147064 	if (needfree) {
299*5895Syz147064 		for (i = 0; i < cnt; i++)
300*5895Syz147064 			free((void *)(((val_desc_t *)vdp + i)->vd_val));
3013147Sxc151355 	}
302*5895Syz147064 done:
303*5895Syz147064 	free(vdp);
304*5895Syz147064 	return (status);
305*5895Syz147064 }
306*5895Syz147064 
307*5895Syz147064 static dladm_status_t
308*5895Syz147064 i_dladm_set_linkprop(datalink_id_t linkid, const char *prop_name,
309*5895Syz147064     char **prop_val, uint_t val_cnt, uint_t flags)
310*5895Syz147064 {
311*5895Syz147064 	int			i;
312*5895Syz147064 	boolean_t		found = B_FALSE;
313*5895Syz147064 	datalink_class_t	class;
314*5895Syz147064 	uint32_t		media;
315*5895Syz147064 	dladm_status_t		status = DLADM_STATUS_OK;
316*5895Syz147064 
317*5895Syz147064 	status = dladm_datalink_id2info(linkid, NULL, &class, &media, NULL, 0);
318*5895Syz147064 	if (status != DLADM_STATUS_OK)
319*5895Syz147064 		return (status);
320*5895Syz147064 
321*5895Syz147064 	for (i = 0; i < DLADM_MAX_PROPS; i++) {
322*5895Syz147064 		prop_desc_t	*pdp = &prop_table[i];
323*5895Syz147064 		dladm_status_t	s;
324*5895Syz147064 
325*5895Syz147064 		if (prop_name != NULL &&
326*5895Syz147064 		    (strcasecmp(prop_name, pdp->pd_name) != 0))
327*5895Syz147064 			continue;
328*5895Syz147064 
329*5895Syz147064 		found = B_TRUE;
330*5895Syz147064 		s = i_dladm_set_single_prop(linkid, class, media, pdp, prop_val,
331*5895Syz147064 		    val_cnt, flags);
3323448Sdh155122 
333*5895Syz147064 		if (prop_name != NULL) {
334*5895Syz147064 			status = s;
335*5895Syz147064 			break;
336*5895Syz147064 		} else {
337*5895Syz147064 			if (s != DLADM_STATUS_OK &&
338*5895Syz147064 			    s != DLADM_STATUS_NOTSUP)
339*5895Syz147064 				status = s;
340*5895Syz147064 		}
341*5895Syz147064 	}
342*5895Syz147064 	if (!found)
343*5895Syz147064 		status = DLADM_STATUS_NOTFOUND;
344*5895Syz147064 
345*5895Syz147064 	return (status);
346*5895Syz147064 }
347*5895Syz147064 
348*5895Syz147064 /*
349*5895Syz147064  * Set/reset link property for specific link
350*5895Syz147064  */
351*5895Syz147064 dladm_status_t
352*5895Syz147064 dladm_set_linkprop(datalink_id_t linkid, const char *prop_name, char **prop_val,
353*5895Syz147064     uint_t val_cnt, uint_t flags)
354*5895Syz147064 {
355*5895Syz147064 	dladm_status_t	status = DLADM_STATUS_OK;
356*5895Syz147064 
357*5895Syz147064 	if ((linkid == DATALINK_INVALID_LINKID) || (flags == 0) ||
358*5895Syz147064 	    (prop_val == NULL && val_cnt > 0) ||
359*5895Syz147064 	    (prop_val != NULL && val_cnt == 0) ||
360*5895Syz147064 	    (prop_name == NULL && prop_val != NULL)) {
361*5895Syz147064 		return (DLADM_STATUS_BADARG);
362*5895Syz147064 	}
363*5895Syz147064 
364*5895Syz147064 	status = i_dladm_set_linkprop(linkid, prop_name, prop_val,
365*5895Syz147064 	    val_cnt, flags);
366*5895Syz147064 	if (status != DLADM_STATUS_OK)
367*5895Syz147064 		return (status);
368*5895Syz147064 
369*5895Syz147064 	if (flags & DLADM_OPT_PERSIST) {
370*5895Syz147064 		status = i_dladm_set_linkprop_db(linkid, prop_name,
3713147Sxc151355 		    prop_val, val_cnt);
3723147Sxc151355 	}
3733147Sxc151355 	return (status);
3743147Sxc151355 }
3753147Sxc151355 
376*5895Syz147064 /*
377*5895Syz147064  * Walk link properties of the given specific link.
378*5895Syz147064  */
3793147Sxc151355 dladm_status_t
380*5895Syz147064 dladm_walk_linkprop(datalink_id_t linkid, void *arg,
381*5895Syz147064     int (*func)(datalink_id_t, const char *, void *))
3823147Sxc151355 {
383*5895Syz147064 	dladm_status_t		status;
384*5895Syz147064 	datalink_class_t	class;
385*5895Syz147064 	uint_t			media;
386*5895Syz147064 	int			i;
387*5895Syz147064 
388*5895Syz147064 	if (linkid == DATALINK_INVALID_LINKID || func == NULL)
389*5895Syz147064 		return (DLADM_STATUS_BADARG);
390*5895Syz147064 
391*5895Syz147064 	status = dladm_datalink_id2info(linkid, NULL, &class, &media, NULL, 0);
392*5895Syz147064 	if (status != DLADM_STATUS_OK)
393*5895Syz147064 		return (status);
394*5895Syz147064 
395*5895Syz147064 	for (i = 0; i < DLADM_MAX_PROPS; i++) {
396*5895Syz147064 		if (!(prop_table[i].pd_class & class))
397*5895Syz147064 			continue;
398*5895Syz147064 
399*5895Syz147064 		if (!DATALINK_MEDIA_ACCEPTED(prop_table[i].pd_dmedia, media))
400*5895Syz147064 			continue;
401*5895Syz147064 
402*5895Syz147064 		if (func(linkid, prop_table[i].pd_name, arg) ==
403*5895Syz147064 		    DLADM_WALK_TERMINATE) {
404*5895Syz147064 			break;
405*5895Syz147064 		}
406*5895Syz147064 	}
407*5895Syz147064 
408*5895Syz147064 	return (DLADM_STATUS_OK);
409*5895Syz147064 }
4103448Sdh155122 
411*5895Syz147064 /*
412*5895Syz147064  * Get linkprop of the given specific link.
413*5895Syz147064  */
414*5895Syz147064 dladm_status_t
415*5895Syz147064 dladm_get_linkprop(datalink_id_t linkid, dladm_prop_type_t type,
416*5895Syz147064     const char *prop_name, char **prop_val, uint_t *val_cntp)
417*5895Syz147064 {
418*5895Syz147064 	dladm_status_t		status = DLADM_STATUS_OK;
419*5895Syz147064 	datalink_class_t	class;
420*5895Syz147064 	uint_t			media;
421*5895Syz147064 	prop_desc_t		*pdp;
422*5895Syz147064 	uint_t			cnt;
423*5895Syz147064 	int			i;
424*5895Syz147064 
425*5895Syz147064 	if (linkid == DATALINK_INVALID_LINKID || prop_name == NULL ||
426*5895Syz147064 	    prop_val == NULL || val_cntp == NULL || *val_cntp == 0)
427*5895Syz147064 		return (DLADM_STATUS_BADARG);
428*5895Syz147064 
429*5895Syz147064 	for (i = 0; i < DLADM_MAX_PROPS; i++)
430*5895Syz147064 		if (strcasecmp(prop_name, prop_table[i].pd_name) == 0)
431*5895Syz147064 			break;
432*5895Syz147064 
433*5895Syz147064 	if (i == DLADM_MAX_PROPS)
434*5895Syz147064 		return (DLADM_STATUS_NOTFOUND);
435*5895Syz147064 
436*5895Syz147064 	pdp = &prop_table[i];
437*5895Syz147064 
438*5895Syz147064 	status = dladm_datalink_id2info(linkid, NULL, &class, &media, NULL, 0);
439*5895Syz147064 	if (status != DLADM_STATUS_OK)
440*5895Syz147064 		return (status);
441*5895Syz147064 
442*5895Syz147064 	if (!(pdp->pd_class & class))
443*5895Syz147064 		return (DLADM_STATUS_BADARG);
444*5895Syz147064 
445*5895Syz147064 	if (!DATALINK_MEDIA_ACCEPTED(pdp->pd_dmedia, media))
4463147Sxc151355 		return (DLADM_STATUS_BADARG);
4473147Sxc151355 
448*5895Syz147064 	switch (type) {
449*5895Syz147064 	case DLADM_PROP_VAL_CURRENT:
450*5895Syz147064 		status = pdp->pd_get(linkid, prop_val, val_cntp);
451*5895Syz147064 		break;
452*5895Syz147064 
453*5895Syz147064 	case DLADM_PROP_VAL_DEFAULT:
454*5895Syz147064 		if (pdp->pd_defval.vd_name == NULL) {
455*5895Syz147064 			status = DLADM_STATUS_NOTSUP;
456*5895Syz147064 			break;
457*5895Syz147064 		}
458*5895Syz147064 		(void) strcpy(*prop_val, pdp->pd_defval.vd_name);
459*5895Syz147064 		*val_cntp = 1;
460*5895Syz147064 		break;
4613448Sdh155122 
462*5895Syz147064 	case DLADM_PROP_VAL_MODIFIABLE:
463*5895Syz147064 		if (pdp->pd_getmod != NULL) {
464*5895Syz147064 			status = pdp->pd_getmod(linkid, prop_val, val_cntp);
465*5895Syz147064 			break;
466*5895Syz147064 		}
467*5895Syz147064 		cnt = pdp->pd_noptval;
468*5895Syz147064 		if (cnt == 0) {
469*5895Syz147064 			status = DLADM_STATUS_NOTSUP;
470*5895Syz147064 		} else if (cnt > *val_cntp) {
471*5895Syz147064 			status = DLADM_STATUS_TOOSMALL;
472*5895Syz147064 		} else {
473*5895Syz147064 			for (i = 0; i < cnt; i++) {
474*5895Syz147064 				(void) strcpy(prop_val[i],
475*5895Syz147064 				    pdp->pd_optval[i].vd_name);
476*5895Syz147064 			}
477*5895Syz147064 			*val_cntp = cnt;
478*5895Syz147064 		}
479*5895Syz147064 		break;
480*5895Syz147064 	case DLADM_PROP_VAL_PERSISTENT:
481*5895Syz147064 		if (pdp->pd_flags & PD_TEMPONLY)
482*5895Syz147064 			return (DLADM_STATUS_TEMPONLY);
483*5895Syz147064 		status = i_dladm_get_linkprop_db(linkid, prop_name,
484*5895Syz147064 		    prop_val, val_cntp);
485*5895Syz147064 		break;
486*5895Syz147064 	default:
487*5895Syz147064 		status = DLADM_STATUS_BADARG;
488*5895Syz147064 		break;
4893147Sxc151355 	}
4903448Sdh155122 
491*5895Syz147064 	return (status);
492*5895Syz147064 }
493*5895Syz147064 
494*5895Syz147064 /*ARGSUSED*/
495*5895Syz147064 static int
496*5895Syz147064 i_dladm_init_one_prop(datalink_id_t linkid, const char *prop_name, void *arg)
497*5895Syz147064 {
498*5895Syz147064 	char	*buf, **propvals;
499*5895Syz147064 	uint_t	i, valcnt = DLADM_MAX_PROP_VALCNT;
500*5895Syz147064 
501*5895Syz147064 	if ((buf = malloc((sizeof (char *) + DLADM_PROP_VAL_MAX) *
502*5895Syz147064 	    DLADM_MAX_PROP_VALCNT)) == NULL) {
503*5895Syz147064 		return (DLADM_WALK_CONTINUE);
504*5895Syz147064 	}
505*5895Syz147064 
506*5895Syz147064 	propvals = (char **)(void *)buf;
507*5895Syz147064 	for (i = 0; i < valcnt; i++) {
508*5895Syz147064 		propvals[i] = buf +
509*5895Syz147064 		    sizeof (char *) * DLADM_MAX_PROP_VALCNT +
510*5895Syz147064 		    i * DLADM_PROP_VAL_MAX;
511*5895Syz147064 	}
512*5895Syz147064 
513*5895Syz147064 	if (dladm_get_linkprop(linkid, DLADM_PROP_VAL_PERSISTENT, prop_name,
514*5895Syz147064 	    propvals, &valcnt) != DLADM_STATUS_OK) {
515*5895Syz147064 		goto done;
516*5895Syz147064 	}
517*5895Syz147064 
518*5895Syz147064 	(void) dladm_set_linkprop(linkid, prop_name, propvals, valcnt,
519*5895Syz147064 	    DLADM_OPT_ACTIVE);
520*5895Syz147064 
521*5895Syz147064 done:
522*5895Syz147064 	if (buf != NULL)
523*5895Syz147064 		free(buf);
524*5895Syz147064 
525*5895Syz147064 	return (DLADM_WALK_CONTINUE);
526*5895Syz147064 }
527*5895Syz147064 
528*5895Syz147064 /*ARGSUSED*/
529*5895Syz147064 static int
530*5895Syz147064 i_dladm_init_linkprop(datalink_id_t linkid, void *arg)
531*5895Syz147064 {
532*5895Syz147064 	(void) dladm_init_linkprop(linkid);
533*5895Syz147064 	return (DLADM_WALK_CONTINUE);
534*5895Syz147064 }
535*5895Syz147064 
536*5895Syz147064 dladm_status_t
537*5895Syz147064 dladm_init_linkprop(datalink_id_t linkid)
538*5895Syz147064 {
539*5895Syz147064 	if (linkid == DATALINK_ALL_LINKID) {
540*5895Syz147064 		(void) dladm_walk_datalink_id(i_dladm_init_linkprop, NULL,
541*5895Syz147064 		    DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE,
542*5895Syz147064 		    DLADM_OPT_PERSIST);
543*5895Syz147064 	} else {
544*5895Syz147064 		(void) dladm_walk_linkprop(linkid, NULL, i_dladm_init_one_prop);
5453448Sdh155122 	}
5463448Sdh155122 	return (DLADM_STATUS_OK);
5473147Sxc151355 }
5483147Sxc151355 
549*5895Syz147064 static dladm_status_t
550*5895Syz147064 do_get_zone(datalink_id_t linkid, char **prop_val, uint_t *val_cnt)
5513147Sxc151355 {
552*5895Syz147064 	char		zone_name[ZONENAME_MAX];
553*5895Syz147064 	zoneid_t	zid;
554*5895Syz147064 	dladm_status_t	status;
5553147Sxc151355 
556*5895Syz147064 	status = dladm_getzid(linkid, &zid);
557*5895Syz147064 	if (status != DLADM_STATUS_OK)
5583448Sdh155122 		return (status);
5593448Sdh155122 
560*5895Syz147064 	*val_cnt = 1;
561*5895Syz147064 	if (zid != GLOBAL_ZONEID) {
562*5895Syz147064 		if (getzonenamebyid(zid, zone_name, sizeof (zone_name)) < 0)
563*5895Syz147064 			return (dladm_errno2status(errno));
5643147Sxc151355 
565*5895Syz147064 		(void) strncpy(*prop_val, zone_name, DLADM_PROP_VAL_MAX);
5663147Sxc151355 	} else {
567*5895Syz147064 		*prop_val[0] = '\0';
5683147Sxc151355 	}
5693147Sxc151355 
5703448Sdh155122 	return (DLADM_STATUS_OK);
5713448Sdh155122 }
5723448Sdh155122 
5733448Sdh155122 typedef int (*zone_get_devroot_t)(char *, char *, size_t);
5743448Sdh155122 
5753448Sdh155122 static int
5763448Sdh155122 i_dladm_get_zone_dev(char *zone_name, char *dev, size_t devlen)
5773448Sdh155122 {
5783448Sdh155122 	char			root[MAXPATHLEN];
5793448Sdh155122 	zone_get_devroot_t	real_zone_get_devroot;
5803448Sdh155122 	void			*dlhandle;
5813448Sdh155122 	void			*sym;
5823448Sdh155122 	int			ret;
5833448Sdh155122 
5843448Sdh155122 	if ((dlhandle = dlopen("libzonecfg.so.1", RTLD_LAZY)) == NULL)
5853448Sdh155122 		return (-1);
5863448Sdh155122 
5873448Sdh155122 	if ((sym = dlsym(dlhandle, "zone_get_devroot")) == NULL) {
5883448Sdh155122 		(void) dlclose(dlhandle);
5893448Sdh155122 		return (-1);
5903448Sdh155122 	}
5913448Sdh155122 
5923448Sdh155122 	real_zone_get_devroot = (zone_get_devroot_t)sym;
5933448Sdh155122 
5943448Sdh155122 	if ((ret = real_zone_get_devroot(zone_name, root, sizeof (root))) == 0)
5953448Sdh155122 		(void) snprintf(dev, devlen, "%s%s", root, "/dev");
5963448Sdh155122 	(void) dlclose(dlhandle);
5973448Sdh155122 	return (ret);
5983448Sdh155122 }
5993448Sdh155122 
6003448Sdh155122 static dladm_status_t
601*5895Syz147064 i_dladm_update_deventry(zoneid_t zid, datalink_id_t linkid, boolean_t add)
6023448Sdh155122 {
6033448Sdh155122 	char		path[MAXPATHLEN];
604*5895Syz147064 	char		name[MAXLINKNAMELEN];
6053448Sdh155122 	di_prof_t	prof = NULL;
6063448Sdh155122 	char		zone_name[ZONENAME_MAX];
6073448Sdh155122 	dladm_status_t	status;
608*5895Syz147064 	int		ret;
6093448Sdh155122 
6103448Sdh155122 	if (getzonenamebyid(zid, zone_name, sizeof (zone_name)) < 0)
6113448Sdh155122 		return (dladm_errno2status(errno));
6123448Sdh155122 	if (i_dladm_get_zone_dev(zone_name, path, sizeof (path)) != 0)
6133448Sdh155122 		return (dladm_errno2status(errno));
6143448Sdh155122 	if (di_prof_init(path, &prof) != 0)
6153448Sdh155122 		return (dladm_errno2status(errno));
6163448Sdh155122 
617*5895Syz147064 	status = dladm_linkid2legacyname(linkid, name, MAXLINKNAMELEN);
618*5895Syz147064 	if (status != DLADM_STATUS_OK)
619*5895Syz147064 		goto cleanup;
620*5895Syz147064 
621*5895Syz147064 	if (add)
622*5895Syz147064 		ret = di_prof_add_dev(prof, name);
623*5895Syz147064 	else
624*5895Syz147064 		ret = di_prof_add_exclude(prof, name);
625*5895Syz147064 
626*5895Syz147064 	if (ret != 0) {
6273448Sdh155122 		status = dladm_errno2status(errno);
6283448Sdh155122 		goto cleanup;
6293448Sdh155122 	}
6303448Sdh155122 
6313448Sdh155122 	if (di_prof_commit(prof) != 0)
6323448Sdh155122 		status = dladm_errno2status(errno);
6333448Sdh155122 cleanup:
6343448Sdh155122 	if (prof)
6353448Sdh155122 		di_prof_fini(prof);
6363448Sdh155122 
6373448Sdh155122 	return (status);
6383448Sdh155122 }
6393448Sdh155122 
6403448Sdh155122 static dladm_status_t
641*5895Syz147064 do_set_zone(datalink_id_t linkid, val_desc_t *vdp, uint_t val_cnt)
6423448Sdh155122 {
6433448Sdh155122 	dladm_status_t	status;
6443448Sdh155122 	zoneid_t	zid_old, zid_new;
645*5895Syz147064 	char		link[MAXLINKNAMELEN];
6463448Sdh155122 
6473448Sdh155122 	if (val_cnt != 1)
6483448Sdh155122 		return (DLADM_STATUS_BADVALCNT);
6493448Sdh155122 
650*5895Syz147064 	status = dladm_getzid(linkid, &zid_old);
6513448Sdh155122 	if (status != DLADM_STATUS_OK)
6523448Sdh155122 		return (status);
6533448Sdh155122 
6543448Sdh155122 	/* Do nothing if setting to current value */
655*5895Syz147064 	zid_new = vdp->vd_val;
6563448Sdh155122 	if (zid_new == zid_old)
6573448Sdh155122 		return (DLADM_STATUS_OK);
6583448Sdh155122 
659*5895Syz147064 	if ((status = dladm_datalink_id2info(linkid, NULL, NULL, NULL,
660*5895Syz147064 	    link, MAXLINKNAMELEN)) != DLADM_STATUS_OK) {
661*5895Syz147064 		return (status);
662*5895Syz147064 	}
663*5895Syz147064 
664*5895Syz147064 	if (zid_new != GLOBAL_ZONEID) {
665*5895Syz147064 		/*
666*5895Syz147064 		 * If the new zoneid is the global zone, we could destroy
667*5895Syz147064 		 * the link (in the case of an implicitly-created VLAN) as a
668*5895Syz147064 		 * result of the dladm_setzid() operation. In that case,
669*5895Syz147064 		 * we defer the operation to the end of this function to avoid
670*5895Syz147064 		 * recreating the VLAN and getting a different linkid during
671*5895Syz147064 		 * the rollback if other operation fails.
672*5895Syz147064 		 *
673*5895Syz147064 		 * Otherwise, dladm_setzid() will hold a reference to the
674*5895Syz147064 		 * link and prevent a link renaming, so we need to do it
675*5895Syz147064 		 * before other operations.
676*5895Syz147064 		 */
677*5895Syz147064 		status = dladm_setzid(link, zid_new);
678*5895Syz147064 		if (status != DLADM_STATUS_OK)
679*5895Syz147064 			return (status);
680*5895Syz147064 	}
681*5895Syz147064 
6823448Sdh155122 	if (zid_old != GLOBAL_ZONEID) {
683*5895Syz147064 		if (zone_remove_datalink(zid_old, link) != 0 &&
6843448Sdh155122 		    errno != ENXIO) {
6853448Sdh155122 			status = dladm_errno2status(errno);
6863448Sdh155122 			goto rollback1;
6873448Sdh155122 		}
6883448Sdh155122 
689*5895Syz147064 		/*
690*5895Syz147064 		 * It is okay to fail to update the /dev entry (some
691*5895Syz147064 		 * vanity-named links do not have a /dev entry).
692*5895Syz147064 		 */
693*5895Syz147064 		(void) i_dladm_update_deventry(zid_old, linkid, B_FALSE);
694*5895Syz147064 	}
695*5895Syz147064 
696*5895Syz147064 	if (zid_new != GLOBAL_ZONEID) {
697*5895Syz147064 		if (zone_add_datalink(zid_new, link) != 0) {
698*5895Syz147064 			status = dladm_errno2status(errno);
699*5895Syz147064 			goto rollback2;
700*5895Syz147064 		}
701*5895Syz147064 
702*5895Syz147064 		(void) i_dladm_update_deventry(zid_new, linkid, B_TRUE);
703*5895Syz147064 	} else {
704*5895Syz147064 		status = dladm_setzid(link, zid_new);
7053448Sdh155122 		if (status != DLADM_STATUS_OK)
7063448Sdh155122 			goto rollback2;
7073448Sdh155122 	}
7083448Sdh155122 
7093448Sdh155122 	return (DLADM_STATUS_OK);
7103448Sdh155122 
7113448Sdh155122 rollback2:
7123448Sdh155122 	if (zid_old != GLOBAL_ZONEID)
713*5895Syz147064 		(void) i_dladm_update_deventry(zid_old, linkid, B_TRUE);
714*5895Syz147064 	if (zid_old != GLOBAL_ZONEID)
715*5895Syz147064 		(void) zone_add_datalink(zid_old, link);
7163448Sdh155122 rollback1:
717*5895Syz147064 	if (zid_new != GLOBAL_ZONEID)
718*5895Syz147064 		(void) dladm_setzid(link, zid_old);
7193448Sdh155122 	return (status);
7203448Sdh155122 }
7213448Sdh155122 
7223448Sdh155122 /* ARGSUSED */
7233448Sdh155122 static dladm_status_t
724*5895Syz147064 do_check_zone(datalink_id_t linkid, char **prop_val, uint_t val_cnt,
725*5895Syz147064     val_desc_t *vdp, boolean_t *needfreep)
7263448Sdh155122 {
727*5895Syz147064 	zoneid_t	zid;
7283448Sdh155122 
7293448Sdh155122 	if (val_cnt != 1)
7303448Sdh155122 		return (DLADM_STATUS_BADVALCNT);
7313448Sdh155122 
7323448Sdh155122 	if ((zid = getzoneidbyname(*prop_val)) == -1)
7333448Sdh155122 		return (DLADM_STATUS_BADVAL);
7343448Sdh155122 
7353448Sdh155122 	if (zid != GLOBAL_ZONEID) {
7363448Sdh155122 		ushort_t	flags;
7373448Sdh155122 
7383448Sdh155122 		if (zone_getattr(zid, ZONE_ATTR_FLAGS, &flags,
7393448Sdh155122 		    sizeof (flags)) < 0) {
7403448Sdh155122 			return (dladm_errno2status(errno));
7413448Sdh155122 		}
7423448Sdh155122 
7433448Sdh155122 		if (!(flags & ZF_NET_EXCL)) {
7443448Sdh155122 			return (DLADM_STATUS_BADVAL);
7453448Sdh155122 		}
7463448Sdh155122 	}
7473448Sdh155122 
748*5895Syz147064 	vdp->vd_val = zid;
749*5895Syz147064 	*needfreep = B_FALSE;
750*5895Syz147064 	return (DLADM_STATUS_OK);
751*5895Syz147064 }
752*5895Syz147064 
753*5895Syz147064 static dladm_status_t
754*5895Syz147064 do_get_autopush(datalink_id_t linkid, char **prop_val, uint_t *val_cnt)
755*5895Syz147064 {
756*5895Syz147064 	dld_ioc_ap_t	dia;
757*5895Syz147064 	int		fd, i, len;
758*5895Syz147064 
759*5895Syz147064 	if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0)
760*5895Syz147064 		return (dladm_errno2status(errno));
761*5895Syz147064 
762*5895Syz147064 	*val_cnt = 1;
763*5895Syz147064 	dia.dia_linkid = linkid;
764*5895Syz147064 	if (i_dladm_ioctl(fd, DLDIOC_GETAUTOPUSH, &dia, sizeof (dia)) < 0) {
765*5895Syz147064 		(*prop_val)[0] = '\0';
766*5895Syz147064 		goto done;
767*5895Syz147064 	}
768*5895Syz147064 
769*5895Syz147064 	for (i = 0, len = 0; i < dia.dia_npush; i++) {
770*5895Syz147064 		if (i != 0) {
771*5895Syz147064 			(void) snprintf(*prop_val + len,
772*5895Syz147064 			    DLADM_PROP_VAL_MAX - len, "%c", AP_DELIMITER);
773*5895Syz147064 			len += 1;
774*5895Syz147064 		}
775*5895Syz147064 		(void) snprintf(*prop_val + len, DLADM_PROP_VAL_MAX - len,
776*5895Syz147064 		    "%s", dia.dia_aplist[i]);
777*5895Syz147064 		len += strlen(dia.dia_aplist[i]);
778*5895Syz147064 		if (dia.dia_anchor - 1 == i) {
779*5895Syz147064 			(void) snprintf(*prop_val + len,
780*5895Syz147064 			    DLADM_PROP_VAL_MAX - len, "%c%s", AP_DELIMITER,
781*5895Syz147064 			    AP_ANCHOR);
782*5895Syz147064 			len += (strlen(AP_ANCHOR) + 1);
783*5895Syz147064 		}
784*5895Syz147064 	}
785*5895Syz147064 
786*5895Syz147064 done:
787*5895Syz147064 	(void) close(fd);
788*5895Syz147064 	return (DLADM_STATUS_OK);
789*5895Syz147064 }
790*5895Syz147064 
791*5895Syz147064 static dladm_status_t
792*5895Syz147064 do_set_autopush(datalink_id_t linkid, val_desc_t *vdp, uint_t val_cnt)
793*5895Syz147064 {
794*5895Syz147064 	dld_ioc_ap_t		dia;
795*5895Syz147064 	struct dlautopush	*dlap = (struct dlautopush *)vdp->vd_val;
796*5895Syz147064 	dladm_status_t		status = DLADM_STATUS_OK;
797*5895Syz147064 	int			fd, i;
798*5895Syz147064 	int			ic_cmd;
799*5895Syz147064 
800*5895Syz147064 	if (val_cnt != 1)
801*5895Syz147064 		return (DLADM_STATUS_BADVALCNT);
802*5895Syz147064 
803*5895Syz147064 	if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0)
804*5895Syz147064 		return (dladm_errno2status(errno));
805*5895Syz147064 
806*5895Syz147064 	dia.dia_linkid = linkid;
807*5895Syz147064 	if (dlap != NULL) {
808*5895Syz147064 		dia.dia_anchor = dlap->dap_anchor;
809*5895Syz147064 		dia.dia_npush = dlap->dap_npush;
810*5895Syz147064 		for (i = 0; i < dia.dia_npush; i++) {
811*5895Syz147064 			(void) strlcpy(dia.dia_aplist[i], dlap->dap_aplist[i],
812*5895Syz147064 			    FMNAMESZ+1);
813*5895Syz147064 		}
814*5895Syz147064 		ic_cmd = DLDIOC_SETAUTOPUSH;
815*5895Syz147064 	} else {
816*5895Syz147064 		ic_cmd = DLDIOC_CLRAUTOPUSH;
817*5895Syz147064 	}
818*5895Syz147064 
819*5895Syz147064 	if (i_dladm_ioctl(fd, ic_cmd, &dia, sizeof (dia)) < 0)
820*5895Syz147064 		status = dladm_errno2status(errno);
821*5895Syz147064 
822*5895Syz147064 	(void) close(fd);
823*5895Syz147064 	return (status);
824*5895Syz147064 }
825*5895Syz147064 
826*5895Syz147064 /*
827*5895Syz147064  * Add the specified module to the dlautopush structure; returns a
828*5895Syz147064  * DLADM_STATUS_* code.
829*5895Syz147064  */
830*5895Syz147064 dladm_status_t
831*5895Syz147064 i_dladm_add_ap_module(const char *module, struct dlautopush *dlap)
832*5895Syz147064 {
833*5895Syz147064 	if ((strlen(module) == 0) || (strlen(module) > FMNAMESZ))
834*5895Syz147064 		return (DLADM_STATUS_BADVAL);
835*5895Syz147064 
836*5895Syz147064 	if (strncasecmp(module, AP_ANCHOR, strlen(AP_ANCHOR)) == 0) {
837*5895Syz147064 		/*
838*5895Syz147064 		 * We don't allow multiple anchors, and the anchor must
839*5895Syz147064 		 * be after at least one module.
840*5895Syz147064 		 */
841*5895Syz147064 		if (dlap->dap_anchor != 0)
842*5895Syz147064 			return (DLADM_STATUS_BADVAL);
843*5895Syz147064 		if (dlap->dap_npush == 0)
844*5895Syz147064 			return (DLADM_STATUS_BADVAL);
845*5895Syz147064 
846*5895Syz147064 		dlap->dap_anchor = dlap->dap_npush;
847*5895Syz147064 		return (DLADM_STATUS_OK);
848*5895Syz147064 	}
849*5895Syz147064 	if (dlap->dap_npush > MAXAPUSH)
850*5895Syz147064 		return (DLADM_STATUS_BADVALCNT);
851*5895Syz147064 
852*5895Syz147064 	(void) strlcpy(dlap->dap_aplist[dlap->dap_npush++], module,
853*5895Syz147064 	    FMNAMESZ + 1);
854*5895Syz147064 
855*5895Syz147064 	return (DLADM_STATUS_OK);
856*5895Syz147064 }
857*5895Syz147064 
858*5895Syz147064 /*
859*5895Syz147064  * Currently, both '.' and ' '(space) can be used as the delimiters between
860*5895Syz147064  * autopush modules. The former is used in dladm set-linkprop, and the
861*5895Syz147064  * latter is used in the autopush(1M) file.
862*5895Syz147064  */
863*5895Syz147064 /* ARGSUSED */
864*5895Syz147064 static dladm_status_t
865*5895Syz147064 do_check_autopush(datalink_id_t linkid, char **prop_val, uint_t val_cnt,
866*5895Syz147064     val_desc_t *vdp, boolean_t *needfreep)
867*5895Syz147064 {
868*5895Syz147064 	char			*module;
869*5895Syz147064 	struct dlautopush	*dlap;
870*5895Syz147064 	dladm_status_t		status;
871*5895Syz147064 	char			val[DLADM_PROP_VAL_MAX];
872*5895Syz147064 	char			delimiters[4];
873*5895Syz147064 
874*5895Syz147064 	if (val_cnt != 1)
875*5895Syz147064 		return (DLADM_STATUS_BADVALCNT);
876*5895Syz147064 
877*5895Syz147064 	dlap = malloc(sizeof (struct dlautopush));
878*5895Syz147064 	if (dlap == NULL)
8793448Sdh155122 		return (DLADM_STATUS_NOMEM);
8803448Sdh155122 
881*5895Syz147064 	(void) memset(dlap, 0, sizeof (struct dlautopush));
882*5895Syz147064 	(void) snprintf(delimiters, 4, " %c\n", AP_DELIMITER);
883*5895Syz147064 	bcopy(*prop_val, val, DLADM_PROP_VAL_MAX);
884*5895Syz147064 	module = strtok(val, delimiters);
885*5895Syz147064 	while (module != NULL) {
886*5895Syz147064 		status = i_dladm_add_ap_module(module, dlap);
887*5895Syz147064 		if (status != DLADM_STATUS_OK)
888*5895Syz147064 			return (status);
889*5895Syz147064 		module = strtok(NULL, delimiters);
890*5895Syz147064 	}
891*5895Syz147064 
892*5895Syz147064 	vdp->vd_val = (uintptr_t)dlap;
893*5895Syz147064 	*needfreep = B_TRUE;
8943448Sdh155122 	return (DLADM_STATUS_OK);
8953448Sdh155122 }
8963448Sdh155122 
8973448Sdh155122 static dladm_status_t
898*5895Syz147064 do_get_rate_common(datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
899*5895Syz147064     uint_t id)
9003448Sdh155122 {
901*5895Syz147064 	wl_rates_t	*wrp;
902*5895Syz147064 	uint_t		i;
903*5895Syz147064 	wldp_t		*gbuf = NULL;
904*5895Syz147064 	dladm_status_t	status = DLADM_STATUS_OK;
905*5895Syz147064 
906*5895Syz147064 	if ((gbuf = malloc(MAX_BUF_LEN)) == NULL) {
907*5895Syz147064 		status = DLADM_STATUS_NOMEM;
908*5895Syz147064 		goto done;
909*5895Syz147064 	}
910*5895Syz147064 
911*5895Syz147064 	status = i_dladm_wlan_get_ioctl(linkid, gbuf, id);
912*5895Syz147064 	if (status != DLADM_STATUS_OK)
913*5895Syz147064 		goto done;
914*5895Syz147064 
915*5895Syz147064 	wrp = (wl_rates_t *)gbuf->wldp_buf;
916*5895Syz147064 	if (wrp->wl_rates_num > *val_cnt) {
917*5895Syz147064 		status = DLADM_STATUS_TOOSMALL;
918*5895Syz147064 		goto done;
919*5895Syz147064 	}
920*5895Syz147064 
921*5895Syz147064 	if (wrp->wl_rates_rates[0] == 0) {
922*5895Syz147064 		prop_val[0][0] = '\0';
923*5895Syz147064 		*val_cnt = 1;
924*5895Syz147064 		goto done;
925*5895Syz147064 	}
926*5895Syz147064 
927*5895Syz147064 	for (i = 0; i < wrp->wl_rates_num; i++) {
928*5895Syz147064 		(void) snprintf(prop_val[i], DLADM_STRSIZE, "%.*f",
929*5895Syz147064 		    wrp->wl_rates_rates[i] % 2,
930*5895Syz147064 		    (float)wrp->wl_rates_rates[i] / 2);
931*5895Syz147064 	}
932*5895Syz147064 	*val_cnt = wrp->wl_rates_num;
9333448Sdh155122 
934*5895Syz147064 done:
935*5895Syz147064 	free(gbuf);
936*5895Syz147064 	return (status);
937*5895Syz147064 }
938*5895Syz147064 
939*5895Syz147064 static dladm_status_t
940*5895Syz147064 do_get_rate_prop(datalink_id_t linkid, char **prop_val, uint_t *val_cnt)
941*5895Syz147064 {
942*5895Syz147064 	return (do_get_rate_common(linkid, prop_val, val_cnt,
943*5895Syz147064 	    WL_DESIRED_RATES));
944*5895Syz147064 }
945*5895Syz147064 
946*5895Syz147064 static dladm_status_t
947*5895Syz147064 do_get_rate_mod(datalink_id_t linkid, char **prop_val, uint_t *val_cnt)
948*5895Syz147064 {
949*5895Syz147064 	return (do_get_rate_common(linkid, prop_val, val_cnt,
950*5895Syz147064 	    WL_SUPPORTED_RATES));
951*5895Syz147064 }
952*5895Syz147064 
953*5895Syz147064 static dladm_status_t
954*5895Syz147064 do_set_rate(datalink_id_t linkid, dladm_wlan_rates_t *rates)
955*5895Syz147064 {
956*5895Syz147064 	int		i;
957*5895Syz147064 	uint_t		len;
958*5895Syz147064 	wldp_t		*gbuf;
959*5895Syz147064 	wl_rates_t	*wrp;
960*5895Syz147064 	dladm_status_t	status = DLADM_STATUS_OK;
961*5895Syz147064 
962*5895Syz147064 	if ((gbuf = malloc(MAX_BUF_LEN)) == NULL)
963*5895Syz147064 		return (DLADM_STATUS_NOMEM);
964*5895Syz147064 
965*5895Syz147064 	(void) memset(gbuf, 0, MAX_BUF_LEN);
9663448Sdh155122 
967*5895Syz147064 	wrp = (wl_rates_t *)gbuf->wldp_buf;
968*5895Syz147064 	for (i = 0; i < rates->wr_cnt; i++)
969*5895Syz147064 		wrp->wl_rates_rates[i] = rates->wr_rates[i];
970*5895Syz147064 	wrp->wl_rates_num = rates->wr_cnt;
971*5895Syz147064 
972*5895Syz147064 	len = offsetof(wl_rates_t, wl_rates_rates) +
973*5895Syz147064 	    (rates->wr_cnt * sizeof (char)) + WIFI_BUF_OFFSET;
974*5895Syz147064 	status = i_dladm_wlan_ioctl(linkid, gbuf, WL_DESIRED_RATES, len,
975*5895Syz147064 	    WLAN_SET_PARAM, len);
976*5895Syz147064 
977*5895Syz147064 	free(gbuf);
978*5895Syz147064 	return (status);
979*5895Syz147064 }
9803448Sdh155122 
981*5895Syz147064 static dladm_status_t
982*5895Syz147064 do_set_rate_prop(datalink_id_t linkid, val_desc_t *vdp, uint_t val_cnt)
983*5895Syz147064 {
984*5895Syz147064 	dladm_wlan_rates_t	rates;
985*5895Syz147064 	dladm_status_t		status;
986*5895Syz147064 
987*5895Syz147064 	if (val_cnt != 1)
988*5895Syz147064 		return (DLADM_STATUS_BADVALCNT);
989*5895Syz147064 
990*5895Syz147064 	rates.wr_cnt = 1;
991*5895Syz147064 	rates.wr_rates[0] = vdp[0].vd_val;
992*5895Syz147064 
993*5895Syz147064 	status = do_set_rate(linkid, &rates);
994*5895Syz147064 
995*5895Syz147064 done:
996*5895Syz147064 	return (status);
997*5895Syz147064 }
9983448Sdh155122 
999*5895Syz147064 /* ARGSUSED */
1000*5895Syz147064 static dladm_status_t
1001*5895Syz147064 do_check_rate(datalink_id_t linkid, char **prop_val, uint_t val_cnt,
1002*5895Syz147064     val_desc_t *vdp, boolean_t *needfreep)
1003*5895Syz147064 {
1004*5895Syz147064 	int		i;
1005*5895Syz147064 	uint_t		modval_cnt = MAX_SUPPORT_RATES;
1006*5895Syz147064 	char		*buf, **modval;
1007*5895Syz147064 	dladm_status_t	status;
1008*5895Syz147064 
1009*5895Syz147064 	if (val_cnt != 1)
1010*5895Syz147064 		return (DLADM_STATUS_BADVALCNT);
1011*5895Syz147064 
1012*5895Syz147064 	buf = malloc((sizeof (char *) + DLADM_STRSIZE) *
1013*5895Syz147064 	    MAX_SUPPORT_RATES);
1014*5895Syz147064 	if (buf == NULL) {
1015*5895Syz147064 		status = DLADM_STATUS_NOMEM;
1016*5895Syz147064 		goto done;
1017*5895Syz147064 	}
10183448Sdh155122 
1019*5895Syz147064 	modval = (char **)(void *)buf;
1020*5895Syz147064 	for (i = 0; i < MAX_SUPPORT_RATES; i++) {
1021*5895Syz147064 		modval[i] = buf + sizeof (char *) * MAX_SUPPORT_RATES +
1022*5895Syz147064 		    i * DLADM_STRSIZE;
1023*5895Syz147064 	}
1024*5895Syz147064 
1025*5895Syz147064 	status = do_get_rate_mod(linkid, modval, &modval_cnt);
1026*5895Syz147064 	if (status != DLADM_STATUS_OK)
1027*5895Syz147064 		goto done;
1028*5895Syz147064 
1029*5895Syz147064 	for (i = 0; i < modval_cnt; i++) {
1030*5895Syz147064 		if (strcasecmp(*prop_val, modval[i]) == 0) {
1031*5895Syz147064 			vdp->vd_val = (uint_t)(atof(*prop_val) * 2);
1032*5895Syz147064 			status = DLADM_STATUS_OK;
1033*5895Syz147064 
1034*5895Syz147064 			/*
1035*5895Syz147064 			 * Does not need the caller to free the vdp->vd_val
1036*5895Syz147064 			 */
1037*5895Syz147064 			*needfreep = B_FALSE;
10383448Sdh155122 			break;
10393448Sdh155122 		}
1040*5895Syz147064 	}
1041*5895Syz147064 	if (i == modval_cnt)
1042*5895Syz147064 		status = DLADM_STATUS_BADVAL;
1043*5895Syz147064 done:
1044*5895Syz147064 	free(buf);
1045*5895Syz147064 	return (status);
1046*5895Syz147064 }
1047*5895Syz147064 
1048*5895Syz147064 static dladm_status_t
1049*5895Syz147064 do_get_phyconf(datalink_id_t linkid, wldp_t *gbuf)
1050*5895Syz147064 {
1051*5895Syz147064 	return (i_dladm_wlan_get_ioctl(linkid, gbuf, WL_PHY_CONFIG));
1052*5895Syz147064 }
1053*5895Syz147064 
1054*5895Syz147064 static dladm_status_t
1055*5895Syz147064 do_get_channel_prop(datalink_id_t linkid, char **prop_val, uint_t *val_cnt)
1056*5895Syz147064 {
1057*5895Syz147064 	uint32_t	channel;
1058*5895Syz147064 	wldp_t		*gbuf;
1059*5895Syz147064 	dladm_status_t	status = DLADM_STATUS_OK;
1060*5895Syz147064 
1061*5895Syz147064 	if ((gbuf = malloc(MAX_BUF_LEN)) == NULL)
1062*5895Syz147064 		return (DLADM_STATUS_NOMEM);
1063*5895Syz147064 
1064*5895Syz147064 	if ((status = do_get_phyconf(linkid, gbuf)) != DLADM_STATUS_OK)
1065*5895Syz147064 		goto done;
1066*5895Syz147064 
1067*5895Syz147064 	if (!i_dladm_wlan_convert_chan((wl_phy_conf_t *)gbuf->wldp_buf,
1068*5895Syz147064 	    &channel)) {
1069*5895Syz147064 		status = DLADM_STATUS_NOTFOUND;
1070*5895Syz147064 		goto done;
1071*5895Syz147064 	}
1072*5895Syz147064 
1073*5895Syz147064 	(void) snprintf(*prop_val, DLADM_STRSIZE, "%u", channel);
1074*5895Syz147064 	*val_cnt = 1;
10753448Sdh155122 
1076*5895Syz147064 done:
1077*5895Syz147064 	free(gbuf);
1078*5895Syz147064 	return (status);
1079*5895Syz147064 }
1080*5895Syz147064 
1081*5895Syz147064 static dladm_status_t
1082*5895Syz147064 do_get_powermode(datalink_id_t linkid, wldp_t *gbuf)
1083*5895Syz147064 {
1084*5895Syz147064 	return (i_dladm_wlan_get_ioctl(linkid, gbuf, WL_POWER_MODE));
1085*5895Syz147064 }
1086*5895Syz147064 
1087*5895Syz147064 static dladm_status_t
1088*5895Syz147064 do_get_powermode_prop(datalink_id_t linkid, char **prop_val, uint_t *val_cnt)
1089*5895Syz147064 {
1090*5895Syz147064 	wl_ps_mode_t	*mode;
1091*5895Syz147064 	const char	*s;
1092*5895Syz147064 	wldp_t		*gbuf;
1093*5895Syz147064 	dladm_status_t	status = DLADM_STATUS_OK;
1094*5895Syz147064 
1095*5895Syz147064 	if ((gbuf = malloc(MAX_BUF_LEN)) == NULL)
1096*5895Syz147064 		return (DLADM_STATUS_NOMEM);
1097*5895Syz147064 
1098*5895Syz147064 	if ((status = do_get_powermode(linkid, gbuf)) != DLADM_STATUS_OK)
1099*5895Syz147064 		goto done;
1100*5895Syz147064 
1101*5895Syz147064 	mode = (wl_ps_mode_t *)(gbuf->wldp_buf);
1102*5895Syz147064 	switch (mode->wl_ps_mode) {
1103*5895Syz147064 	case WL_PM_AM:
1104*5895Syz147064 		s = "off";
1105*5895Syz147064 		break;
1106*5895Syz147064 	case WL_PM_MPS:
1107*5895Syz147064 		s = "max";
1108*5895Syz147064 		break;
1109*5895Syz147064 	case WL_PM_FAST:
1110*5895Syz147064 		s = "fast";
11113448Sdh155122 		break;
11123448Sdh155122 	default:
1113*5895Syz147064 		status = DLADM_STATUS_NOTFOUND;
1114*5895Syz147064 		goto done;
1115*5895Syz147064 	}
1116*5895Syz147064 	(void) snprintf(*prop_val, DLADM_STRSIZE, "%s", s);
1117*5895Syz147064 	*val_cnt = 1;
1118*5895Syz147064 
1119*5895Syz147064 done:
1120*5895Syz147064 	free(gbuf);
1121*5895Syz147064 	return (status);
1122*5895Syz147064 }
1123*5895Syz147064 
1124*5895Syz147064 static dladm_status_t
1125*5895Syz147064 do_set_powermode(datalink_id_t linkid, dladm_wlan_powermode_t *pm)
1126*5895Syz147064 {
1127*5895Syz147064 	wl_ps_mode_t    ps_mode;
1128*5895Syz147064 
1129*5895Syz147064 	(void) memset(&ps_mode, 0xff, sizeof (ps_mode));
1130*5895Syz147064 
1131*5895Syz147064 	switch (*pm) {
1132*5895Syz147064 	case DLADM_WLAN_PM_OFF:
1133*5895Syz147064 		ps_mode.wl_ps_mode = WL_PM_AM;
11343448Sdh155122 		break;
1135*5895Syz147064 	case DLADM_WLAN_PM_MAX:
1136*5895Syz147064 		ps_mode.wl_ps_mode = WL_PM_MPS;
1137*5895Syz147064 		break;
1138*5895Syz147064 	case DLADM_WLAN_PM_FAST:
1139*5895Syz147064 		ps_mode.wl_ps_mode = WL_PM_FAST;
1140*5895Syz147064 		break;
1141*5895Syz147064 	default:
1142*5895Syz147064 		return (DLADM_STATUS_NOTSUP);
11433448Sdh155122 	}
1144*5895Syz147064 	return (i_dladm_wlan_set_ioctl(linkid, WL_POWER_MODE, &ps_mode,
1145*5895Syz147064 	    sizeof (ps_mode)));
1146*5895Syz147064 }
1147*5895Syz147064 
1148*5895Syz147064 /* ARGSUSED */
1149*5895Syz147064 static dladm_status_t
1150*5895Syz147064 do_set_powermode_prop(datalink_id_t linkid, val_desc_t *vdp, uint_t val_cnt)
1151*5895Syz147064 {
1152*5895Syz147064 	dladm_wlan_powermode_t powermode = (dladm_wlan_powermode_t)vdp->vd_val;
1153*5895Syz147064 	dladm_status_t status;
1154*5895Syz147064 
1155*5895Syz147064 	if (val_cnt != 1)
1156*5895Syz147064 		return (DLADM_STATUS_BADVALCNT);
1157*5895Syz147064 
1158*5895Syz147064 	status = do_set_powermode(linkid, &powermode);
11593448Sdh155122 
11603448Sdh155122 	return (status);
11613448Sdh155122 }
11623448Sdh155122 
11633448Sdh155122 static dladm_status_t
1164*5895Syz147064 do_get_radio(datalink_id_t linkid, wldp_t *gbuf)
11653448Sdh155122 {
1166*5895Syz147064 	return (i_dladm_wlan_get_ioctl(linkid, gbuf, WL_RADIO));
1167*5895Syz147064 }
11683448Sdh155122 
1169*5895Syz147064 static dladm_status_t
1170*5895Syz147064 do_get_radio_prop(datalink_id_t linkid, char **prop_val, uint_t *val_cnt)
1171*5895Syz147064 {
1172*5895Syz147064 	wl_radio_t	radio;
1173*5895Syz147064 	const char	*s;
1174*5895Syz147064 	wldp_t		*gbuf;
1175*5895Syz147064 	dladm_status_t	status = DLADM_STATUS_OK;
11763448Sdh155122 
1177*5895Syz147064 	if ((gbuf = malloc(MAX_BUF_LEN)) == NULL)
1178*5895Syz147064 		return (DLADM_STATUS_NOMEM);
11793448Sdh155122 
1180*5895Syz147064 	if ((status = do_get_radio(linkid, gbuf)) != DLADM_STATUS_OK)
1181*5895Syz147064 		goto done;
11823448Sdh155122 
1183*5895Syz147064 	radio = *(wl_radio_t *)(gbuf->wldp_buf);
1184*5895Syz147064 	switch (radio) {
1185*5895Syz147064 	case B_TRUE:
1186*5895Syz147064 		s = "on";
1187*5895Syz147064 		break;
1188*5895Syz147064 	case B_FALSE:
1189*5895Syz147064 		s = "off";
1190*5895Syz147064 		break;
1191*5895Syz147064 	default:
1192*5895Syz147064 		status = DLADM_STATUS_NOTFOUND;
1193*5895Syz147064 		goto done;
1194*5895Syz147064 	}
1195*5895Syz147064 	(void) snprintf(*prop_val, DLADM_STRSIZE, "%s", s);
1196*5895Syz147064 	*val_cnt = 1;
11973448Sdh155122 
1198*5895Syz147064 done:
1199*5895Syz147064 	free(gbuf);
12003448Sdh155122 	return (status);
12013448Sdh155122 }
12023448Sdh155122 
12033448Sdh155122 static dladm_status_t
1204*5895Syz147064 do_set_radio(datalink_id_t linkid, dladm_wlan_radio_t *radio)
12053448Sdh155122 {
1206*5895Syz147064 	wl_radio_t r;
12073448Sdh155122 
1208*5895Syz147064 	switch (*radio) {
1209*5895Syz147064 	case DLADM_WLAN_RADIO_ON:
1210*5895Syz147064 		r = B_TRUE;
1211*5895Syz147064 		break;
1212*5895Syz147064 	case DLADM_WLAN_RADIO_OFF:
1213*5895Syz147064 		r = B_FALSE;
1214*5895Syz147064 		break;
1215*5895Syz147064 	default:
1216*5895Syz147064 		return (DLADM_STATUS_NOTSUP);
1217*5895Syz147064 	}
1218*5895Syz147064 	return (i_dladm_wlan_set_ioctl(linkid, WL_RADIO, &r, sizeof (r)));
1219*5895Syz147064 }
12203448Sdh155122 
1221*5895Syz147064 /* ARGSUSED */
1222*5895Syz147064 static dladm_status_t
1223*5895Syz147064 do_set_radio_prop(datalink_id_t linkid, val_desc_t *vdp, uint_t val_cnt)
1224*5895Syz147064 {
1225*5895Syz147064 	dladm_wlan_radio_t radio = (dladm_wlan_radio_t)vdp->vd_val;
1226*5895Syz147064 	dladm_status_t status;
12273448Sdh155122 
1228*5895Syz147064 	if (val_cnt != 1)
1229*5895Syz147064 		return (DLADM_STATUS_BADVALCNT);
1230*5895Syz147064 
1231*5895Syz147064 	status = do_set_radio(linkid, &radio);
12323448Sdh155122 
12333448Sdh155122 	return (status);
12343448Sdh155122 }
12353448Sdh155122 
1236*5895Syz147064 static dladm_status_t
1237*5895Syz147064 i_dladm_set_linkprop_db(datalink_id_t linkid, const char *prop_name,
1238*5895Syz147064     char **prop_val, uint_t val_cnt)
12393448Sdh155122 {
1240*5895Syz147064 	char		buf[MAXLINELEN];
1241*5895Syz147064 	int		i;
1242*5895Syz147064 	dladm_conf_t	conf;
1243*5895Syz147064 	dladm_status_t	status;
12443448Sdh155122 
1245*5895Syz147064 	status = dladm_read_conf(linkid, &conf);
1246*5895Syz147064 	if (status != DLADM_STATUS_OK)
1247*5895Syz147064 		return (status);
12483448Sdh155122 
1249*5895Syz147064 	/*
1250*5895Syz147064 	 * reset case.
1251*5895Syz147064 	 */
1252*5895Syz147064 	if (val_cnt == 0) {
1253*5895Syz147064 		status = dladm_unset_conf_field(conf, prop_name);
1254*5895Syz147064 		if (status == DLADM_STATUS_OK)
1255*5895Syz147064 			status = dladm_write_conf(conf);
1256*5895Syz147064 		goto done;
1257*5895Syz147064 	}
12583448Sdh155122 
1259*5895Syz147064 	buf[0] = '\0';
1260*5895Syz147064 	for (i = 0; i < val_cnt; i++) {
1261*5895Syz147064 		(void) strlcat(buf, prop_val[i], MAXLINELEN);
1262*5895Syz147064 		if (i != val_cnt - 1)
1263*5895Syz147064 			(void) strlcat(buf, ",", MAXLINELEN);
12643448Sdh155122 	}
12653448Sdh155122 
1266*5895Syz147064 	status = dladm_set_conf_field(conf, prop_name, DLADM_TYPE_STR, buf);
1267*5895Syz147064 	if (status == DLADM_STATUS_OK)
1268*5895Syz147064 		status = dladm_write_conf(conf);
1269*5895Syz147064 
1270*5895Syz147064 done:
1271*5895Syz147064 	dladm_destroy_conf(conf);
1272*5895Syz147064 	return (status);
12733448Sdh155122 }
1274*5895Syz147064 
1275*5895Syz147064 static dladm_status_t
1276*5895Syz147064 i_dladm_get_linkprop_db(datalink_id_t linkid, const char *prop_name,
1277*5895Syz147064     char **prop_val, uint_t *val_cntp)
1278*5895Syz147064 {
1279*5895Syz147064 	char		buf[MAXLINELEN], *str;
1280*5895Syz147064 	uint_t		cnt = 0;
1281*5895Syz147064 	dladm_conf_t	conf;
1282*5895Syz147064 	dladm_status_t	status;
1283*5895Syz147064 
1284*5895Syz147064 	status = dladm_read_conf(linkid, &conf);
1285*5895Syz147064 	if (status != DLADM_STATUS_OK)
1286*5895Syz147064 		return (status);
1287*5895Syz147064 
1288*5895Syz147064 	status = dladm_get_conf_field(conf, prop_name, buf, MAXLINELEN);
1289*5895Syz147064 	if (status != DLADM_STATUS_OK)
1290*5895Syz147064 		goto done;
1291*5895Syz147064 
1292*5895Syz147064 	str = strtok(buf, ",");
1293*5895Syz147064 	while (str != NULL) {
1294*5895Syz147064 		if (cnt == *val_cntp) {
1295*5895Syz147064 			status = DLADM_STATUS_TOOSMALL;
1296*5895Syz147064 			goto done;
1297*5895Syz147064 		}
1298*5895Syz147064 		(void) strlcpy(prop_val[cnt++], str, DLADM_PROP_VAL_MAX);
1299*5895Syz147064 		str = strtok(NULL, ",");
1300*5895Syz147064 	}
1301*5895Syz147064 
1302*5895Syz147064 	*val_cntp = cnt;
1303*5895Syz147064 
1304*5895Syz147064 done:
1305*5895Syz147064 	dladm_destroy_conf(conf);
1306*5895Syz147064 	return (status);
1307*5895Syz147064 }
1308