xref: /titanic_50/usr/src/lib/libdladm/common/linkprop.c (revision d42c7aec1963a7ded6694ac33a5bd96422fc8ca7)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #include <stdlib.h>
27 #include <strings.h>
28 #include <errno.h>
29 #include <ctype.h>
30 #include <stddef.h>
31 #include <sys/types.h>
32 #include <sys/stat.h>
33 #include <sys/dld.h>
34 #include <sys/zone.h>
35 #include <fcntl.h>
36 #include <unistd.h>
37 #include <libdevinfo.h>
38 #include <zone.h>
39 #include <libdllink.h>
40 #include <libdladm_impl.h>
41 #include <libdlwlan_impl.h>
42 #include <libdlwlan.h>
43 #include <libdlvlan.h>
44 #include <libdlvnic.h>
45 #include <libintl.h>
46 #include <dlfcn.h>
47 #include <link.h>
48 #include <inet/wifi_ioctl.h>
49 #include <libdladm.h>
50 #include <libdlstat.h>
51 #include <sys/param.h>
52 #include <sys/debug.h>
53 #include <sys/dld.h>
54 #include <sys/mac_flow.h>
55 #include <inttypes.h>
56 #include <sys/ethernet.h>
57 #include <net/wpa.h>
58 #include <sys/sysmacros.h>
59 
60 /*
61  * The linkprop get() callback.
62  * - pd: 	pointer to the prop_desc_t
63  * - propstrp:	a property string array to keep the returned property.
64  *		Caller allocated.
65  * - cntp:	number of returned properties.
66  *		Caller also uses it to indicate how many it expects.
67  */
68 struct prop_desc;
69 typedef struct prop_desc prop_desc_t;
70 
71 typedef dladm_status_t	pd_getf_t(dladm_handle_t, prop_desc_t *pdp,
72 			datalink_id_t, char **propstp, uint_t *cntp,
73 			datalink_media_t, uint_t, uint_t *);
74 
75 /*
76  * The linkprop set() callback.
77  * - propval:	a val_desc_t array which keeps the property values to be set.
78  * - cnt:	number of properties to be set.
79  * - flags: 	additional flags passed down the system call.
80  *
81  * pd_set takes val_desc_t given by pd_check(), translates it into
82  * a format suitable for kernel consumption. This may require allocation
83  * of ioctl buffers etc. pd_set() may call another common routine (used
84  * by all other pd_sets) which invokes the ioctl.
85  */
86 typedef dladm_status_t	pd_setf_t(dladm_handle_t, prop_desc_t *, datalink_id_t,
87 			    val_desc_t *propval, uint_t cnt, uint_t flags,
88 			    datalink_media_t);
89 
90 /*
91  * The linkprop check() callback.
92  * - propstrp:	property string array which keeps the property to be checked.
93  * - cnt:	number of properties.
94  * - propval:	return value; the property values of the given property strings.
95  *
96  * pd_check checks that the input values are valid. It does so by
97  * iteraring through the pd_modval list for the property. If
98  * the modifiable values cannot be expressed as a list, a pd_check
99  * specific to this property can be used. If the input values are
100  * verified to be valid, pd_check allocates a val_desc_t and fills it
101  * with either a val_desc_t found on the pd_modval list or something
102  * generated on the fly.
103  */
104 typedef dladm_status_t	pd_checkf_t(dladm_handle_t, prop_desc_t *pdp,
105 			    datalink_id_t, char **propstrp, uint_t cnt,
106 			    val_desc_t *propval, datalink_media_t);
107 
108 typedef struct link_attr_s {
109 	mac_prop_id_t	pp_id;
110 	size_t		pp_valsize;
111 	char		*pp_name;
112 } link_attr_t;
113 
114 static dld_ioc_macprop_t *i_dladm_buf_alloc_by_name(size_t, datalink_id_t,
115 			    const char *, uint_t, dladm_status_t *);
116 static dld_ioc_macprop_t *i_dladm_buf_alloc_by_id(size_t, datalink_id_t,
117 			    mac_prop_id_t, uint_t, dladm_status_t *);
118 static dld_ioc_macprop_t *i_dladm_get_public_prop(dladm_handle_t, datalink_id_t,
119 			    char *, uint_t, dladm_status_t *, uint_t *);
120 
121 static dladm_status_t i_dladm_set_prop(dladm_handle_t, datalink_id_t,
122 			    const char *, char **, uint_t, uint_t);
123 static dladm_status_t i_dladm_get_priv_prop(dladm_handle_t, datalink_id_t,
124 			    const char *, char **, uint_t *, dladm_prop_type_t,
125 			    uint_t);
126 static link_attr_t *dladm_name2prop(const char *);
127 static link_attr_t *dladm_id2prop(mac_prop_id_t);
128 
129 static pd_getf_t	do_get_zone, do_get_autopush, do_get_rate_mod,
130 			do_get_rate_prop, do_get_channel_prop,
131 			do_get_powermode_prop, do_get_radio_prop,
132 			i_dladm_duplex_get, i_dladm_status_get,
133 			i_dladm_binary_get, i_dladm_uint32_get,
134 			i_dladm_flowctl_get, i_dladm_maxbw_get,
135 			i_dladm_cpus_get, i_dladm_priority_get;
136 
137 static pd_setf_t	do_set_zone, do_set_rate_prop,
138 			do_set_powermode_prop, do_set_radio_prop,
139 			i_dladm_set_public_prop, do_set_res, do_set_cpus;
140 
141 static pd_checkf_t	do_check_zone, do_check_autopush, do_check_rate,
142 			i_dladm_defmtu_check, do_check_maxbw, do_check_cpus,
143 			do_check_priority;
144 
145 static dladm_status_t	i_dladm_speed_get(dladm_handle_t, prop_desc_t *,
146 			    datalink_id_t, char **, uint_t *, uint_t, uint_t *);
147 static dladm_status_t	i_dladm_wlan_get_legacy_ioctl(dladm_handle_t,
148 			    datalink_id_t, void *, uint_t, uint_t);
149 static dladm_status_t	i_dladm_wlan_set_legacy_ioctl(dladm_handle_t,
150 			    datalink_id_t, void *, uint_t, uint_t);
151 static dladm_status_t	i_dladm_macprop(dladm_handle_t, void *, boolean_t);
152 static const char	*dladm_perm2str(uint_t, char *);
153 
154 struct prop_desc {
155 	/*
156 	 * link property name
157 	 */
158 	char			*pd_name;
159 
160 	/*
161 	 * default property value, can be set to { "", NULL }
162 	 */
163 	val_desc_t		pd_defval;
164 
165 	/*
166 	 * list of optional property values, can be NULL.
167 	 *
168 	 * This is set to non-NULL if there is a list of possible property
169 	 * values.  pd_optval would point to the array of possible values.
170 	 */
171 	val_desc_t		*pd_optval;
172 
173 	/*
174 	 * count of the above optional property values. 0 if pd_optval is NULL.
175 	 */
176 	uint_t			pd_noptval;
177 
178 	/*
179 	 * callback to set link property;
180 	 * set to NULL if this property is read-only
181 	 */
182 	pd_setf_t		*pd_set;
183 
184 	/*
185 	 * callback to get modifiable link property
186 	 */
187 	pd_getf_t		*pd_getmod;
188 
189 	/*
190 	 * callback to get current link property
191 	 */
192 	pd_getf_t		*pd_get;
193 
194 	/*
195 	 * callback to validate link property value, set to NULL if pd_optval
196 	 * is not NULL. In that case, validate the value by comparing it with
197 	 * the pd_optval. Return a val_desc_t array pointer if the value is
198 	 * valid.
199 	 */
200 	pd_checkf_t		*pd_check;
201 
202 	uint_t			pd_flags;
203 #define	PD_TEMPONLY	0x1	/* property is temporary only */
204 #define	PD_CHECK_ALLOC	0x2	/* alloc vd_val as part of pd_check */
205 	/*
206 	 * indicate link classes this property applies to.
207 	 */
208 	datalink_class_t	pd_class;
209 
210 	/*
211 	 * indicate link media type this property applies to.
212 	 */
213 	datalink_media_t	pd_dmedia;
214 };
215 
216 #define	MAC_PROP_BUFSIZE(v)	sizeof (dld_ioc_macprop_t) + (v) - 1
217 
218 /*
219  * Supported link properties enumerated in the prop_table[] array are
220  * computed using the callback functions in that array. To compute the
221  * property value, multiple distinct system calls may be needed (e.g.,
222  * for wifi speed, we need to issue system calls to get desired/supported
223  * rates). The link_attr[] table enumerates the interfaces to the kernel,
224  * and the type/size of the data passed in the user-kernel interface.
225  */
226 static link_attr_t link_attr[] = {
227 	{ MAC_PROP_DUPLEX,	sizeof (link_duplex_t),	"duplex"},
228 
229 	{ MAC_PROP_SPEED,	sizeof (uint64_t),	"speed"},
230 
231 	{ MAC_PROP_STATUS,	sizeof (link_state_t),	"state"},
232 
233 	{ MAC_PROP_AUTONEG,	sizeof (uint8_t),	"adv_autoneg_cap"},
234 
235 	{ MAC_PROP_MTU,		sizeof (uint32_t),	"mtu"},
236 
237 	{ MAC_PROP_FLOWCTRL,	sizeof (link_flowctrl_t), "flowctrl"},
238 
239 	{ MAC_PROP_ZONE,	sizeof (dld_ioc_zid_t),	"zone"},
240 
241 	{ MAC_PROP_AUTOPUSH,	sizeof (struct dlautopush), "autopush"},
242 
243 	{ MAC_PROP_ADV_1000FDX_CAP, sizeof (uint8_t),	"adv_1000fdx_cap"},
244 
245 	{ MAC_PROP_EN_1000FDX_CAP, sizeof (uint8_t),	"en_1000fdx_cap"},
246 
247 	{ MAC_PROP_ADV_1000HDX_CAP, sizeof (uint8_t),	"adv_1000hdx_cap"},
248 
249 	{ MAC_PROP_EN_1000HDX_CAP, sizeof (uint8_t),	"en_1000hdx_cap"},
250 
251 	{ MAC_PROP_ADV_100FDX_CAP, sizeof (uint8_t),	"adv_100fdx_cap"},
252 
253 	{ MAC_PROP_EN_100FDX_CAP, sizeof (uint8_t),	"en_100fdx_cap"},
254 
255 	{ MAC_PROP_ADV_100HDX_CAP, sizeof (uint8_t),	"adv_100hdx_cap"},
256 
257 	{ MAC_PROP_EN_100HDX_CAP, sizeof (uint8_t),	"en_100hdx_cap"},
258 
259 	{ MAC_PROP_ADV_10FDX_CAP, sizeof (uint8_t),	"adv_10fdx_cap"},
260 
261 	{ MAC_PROP_EN_10FDX_CAP, sizeof (uint8_t),	"en_10fdx_cap"},
262 
263 	{ MAC_PROP_ADV_10HDX_CAP, sizeof (uint8_t),	"adv_10hdx_cap"},
264 
265 	{ MAC_PROP_EN_10HDX_CAP, sizeof (uint8_t),	"en_10hdx_cap"},
266 
267 	{ MAC_PROP_WL_ESSID,	sizeof (wl_linkstatus_t), "essid"},
268 
269 	{ MAC_PROP_WL_BSSID,	sizeof (wl_bssid_t),	"bssid"},
270 
271 	{ MAC_PROP_WL_BSSTYPE,	sizeof (wl_bss_type_t),	"bsstype"},
272 
273 	{ MAC_PROP_WL_LINKSTATUS, sizeof (wl_linkstatus_t), "wl_linkstatus"},
274 
275 	/* wl_rates_t has variable length */
276 	{ MAC_PROP_WL_DESIRED_RATES, sizeof (wl_rates_t), "desired_rates"},
277 
278 	/* wl_rates_t has variable length */
279 	{ MAC_PROP_WL_SUPPORTED_RATES, sizeof (wl_rates_t), "supported_rates"},
280 
281 	{ MAC_PROP_WL_AUTH_MODE, sizeof (wl_authmode_t), "authmode"},
282 
283 	{ MAC_PROP_WL_ENCRYPTION, sizeof (wl_encryption_t), "encryption"},
284 
285 	{ MAC_PROP_WL_RSSI,	sizeof (wl_rssi_t),	"signal"},
286 
287 	{ MAC_PROP_WL_PHY_CONFIG, sizeof (wl_phy_conf_t), "phy_conf"},
288 
289 	{ MAC_PROP_WL_CAPABILITY, sizeof (wl_capability_t), "capability"},
290 
291 	{ MAC_PROP_WL_WPA,	sizeof (wl_wpa_t),	"wpa"},
292 
293 	/*  wl_wpa_ess_t has variable length */
294 	{ MAC_PROP_WL_SCANRESULTS, sizeof (wl_wpa_ess_t), "scan_results"},
295 
296 	{ MAC_PROP_WL_POWER_MODE, sizeof (wl_ps_mode_t), "powermode"},
297 
298 	{ MAC_PROP_WL_RADIO,	sizeof (dladm_wlan_radio_t), "wl_radio"},
299 
300 	{ MAC_PROP_WL_ESS_LIST, sizeof (wl_ess_list_t),	"wl_ess_list"},
301 
302 	{ MAC_PROP_WL_KEY_TAB,	sizeof (wl_wep_key_tab_t), "wl_wep_key"},
303 
304 	{ MAC_PROP_WL_CREATE_IBSS, sizeof (wl_create_ibss_t), "createibss"},
305 
306 	/* wl_wpa_ie_t has variable length */
307 	{ MAC_PROP_WL_SETOPTIE,	sizeof (wl_wpa_ie_t),	"set_ie"},
308 
309 	{ MAC_PROP_WL_DELKEY,	sizeof (wl_del_key_t),	"wpa_del_key"},
310 
311 	{ MAC_PROP_WL_KEY,	sizeof (wl_key_t),	"wl_key"},
312 
313 	{ MAC_PROP_WL_MLME,	sizeof (wl_mlme_t),	"mlme"},
314 
315 	{ MAC_PROP_MAXBW,	sizeof (mac_resource_props_t),	"maxbw"},
316 
317 	{ MAC_PROP_PRIO,	sizeof (mac_resource_props_t),	"priority"},
318 
319 	{ MAC_PROP_BIND_CPU,	sizeof (mac_resource_props_t),	"cpus"},
320 
321 	{ MAC_PROP_PRIVATE,	0,			"driver-private"}
322 
323 };
324 
325 static  val_desc_t	link_duplex_vals[] = {
326 	{ "half", 	LINK_DUPLEX_HALF	},
327 	{ "full", 	LINK_DUPLEX_HALF	}
328 };
329 static  val_desc_t	link_status_vals[] = {
330 	{ "up",		LINK_STATE_UP		},
331 	{ "down",	LINK_STATE_DOWN		}
332 };
333 static  val_desc_t	link_01_vals[] = {
334 	{ "1",		1			},
335 	{ "0",		0			}
336 };
337 static  val_desc_t	link_flow_vals[] = {
338 	{ "no",		LINK_FLOWCTRL_NONE	},
339 	{ "tx",		LINK_FLOWCTRL_TX	},
340 	{ "rx",		LINK_FLOWCTRL_RX	},
341 	{ "bi",		LINK_FLOWCTRL_BI	}
342 };
343 static  val_desc_t	link_priority_vals[] = {
344 	{ "low",	MPL_LOW	},
345 	{ "medium",	MPL_MEDIUM	},
346 	{ "high",	MPL_HIGH	}
347 };
348 
349 static val_desc_t	dladm_wlan_radio_vals[] = {
350 	{ "on",		DLADM_WLAN_RADIO_ON	},
351 	{ "off",	DLADM_WLAN_RADIO_OFF	}
352 };
353 
354 static val_desc_t	dladm_wlan_powermode_vals[] = {
355 	{ "off",	DLADM_WLAN_PM_OFF	},
356 	{ "fast",	DLADM_WLAN_PM_FAST	},
357 	{ "max",	DLADM_WLAN_PM_MAX	}
358 };
359 
360 #define	VALCNT(vals)    (sizeof ((vals)) / sizeof (val_desc_t))
361 #define	RESET_VAL	((uintptr_t)-1)
362 
363 static prop_desc_t	prop_table[] = {
364 	{ "channel",	{ NULL, 0 },
365 	    NULL, 0, NULL, NULL,
366 	    do_get_channel_prop, NULL, 0,
367 	    DATALINK_CLASS_PHYS, DL_WIFI },
368 
369 	{ "powermode",	{ "off", DLADM_WLAN_PM_OFF },
370 	    dladm_wlan_powermode_vals, VALCNT(dladm_wlan_powermode_vals),
371 	    do_set_powermode_prop, NULL,
372 	    do_get_powermode_prop, NULL, 0,
373 	    DATALINK_CLASS_PHYS, DL_WIFI },
374 
375 	{ "radio",	{ "on", DLADM_WLAN_RADIO_ON },
376 	    dladm_wlan_radio_vals, VALCNT(dladm_wlan_radio_vals),
377 	    do_set_radio_prop, NULL,
378 	    do_get_radio_prop, NULL, 0,
379 	    DATALINK_CLASS_PHYS, DL_WIFI },
380 
381 	{ "speed",	{ "", 0 }, NULL, 0,
382 	    do_set_rate_prop, do_get_rate_mod,
383 	    do_get_rate_prop, do_check_rate, 0,
384 	    DATALINK_CLASS_PHYS, DATALINK_ANY_MEDIATYPE },
385 
386 	{ "autopush",	{ "", 0 }, NULL, 0,
387 	    i_dladm_set_public_prop, NULL,
388 	    do_get_autopush, do_check_autopush, PD_CHECK_ALLOC,
389 	    DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
390 
391 	{ "zone",	{ "", 0 }, NULL, 0,
392 	    do_set_zone, NULL,
393 	    do_get_zone, do_check_zone, PD_TEMPONLY|PD_CHECK_ALLOC,
394 	    DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
395 
396 	{ "duplex",	{ "", 0 },
397 	    link_duplex_vals, VALCNT(link_duplex_vals),
398 	    NULL, NULL, i_dladm_duplex_get, NULL,
399 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
400 
401 	{ "state",	{ "up", LINK_STATE_UP },
402 	    link_status_vals, VALCNT(link_status_vals),
403 	    NULL, NULL, i_dladm_status_get, NULL,
404 	    0, DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
405 
406 	{ "adv_autoneg_cap", { "1", 1 },
407 	    link_01_vals, VALCNT(link_01_vals),
408 	    i_dladm_set_public_prop, NULL, i_dladm_binary_get, NULL,
409 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
410 
411 	{ "mtu", { "", 0 }, NULL, 0,
412 	    i_dladm_set_public_prop, NULL, i_dladm_uint32_get,
413 	    i_dladm_defmtu_check, 0, DATALINK_CLASS_ALL,
414 	    DATALINK_ANY_MEDIATYPE },
415 
416 	{ "flowctrl", { "", 0 },
417 	    link_flow_vals, VALCNT(link_flow_vals),
418 	    i_dladm_set_public_prop, NULL, i_dladm_flowctl_get, NULL,
419 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
420 
421 	{ "adv_1000fdx_cap", { "", 0 },
422 	    link_01_vals, VALCNT(link_01_vals),
423 	    NULL, NULL, i_dladm_binary_get, NULL,
424 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
425 
426 	{ "en_1000fdx_cap", { "", 0 },
427 	    link_01_vals, VALCNT(link_01_vals),
428 	    i_dladm_set_public_prop, NULL, i_dladm_binary_get, NULL,
429 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
430 
431 	{ "adv_1000hdx_cap", { "", 0 },
432 	    link_01_vals, VALCNT(link_01_vals),
433 	    NULL, NULL, i_dladm_binary_get, NULL,
434 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
435 
436 	{ "en_1000hdx_cap", { "", 0 },
437 	    link_01_vals, VALCNT(link_01_vals),
438 	    i_dladm_set_public_prop, NULL, i_dladm_binary_get, NULL,
439 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
440 
441 	{ "adv_100fdx_cap", { "", 0 },
442 	    link_01_vals, VALCNT(link_01_vals),
443 	    NULL, NULL, i_dladm_binary_get, NULL,
444 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
445 
446 	{ "en_100fdx_cap", { "", 0 },
447 	    link_01_vals, VALCNT(link_01_vals),
448 	    i_dladm_set_public_prop, NULL, i_dladm_binary_get, NULL,
449 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
450 
451 	{ "adv_100hdx_cap", { "", 0 },
452 	    link_01_vals, VALCNT(link_01_vals),
453 	    NULL, NULL, i_dladm_binary_get, NULL,
454 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
455 
456 	{ "en_100hdx_cap", { "", 0 },
457 	    link_01_vals, VALCNT(link_01_vals),
458 	    i_dladm_set_public_prop, NULL, i_dladm_binary_get, NULL,
459 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
460 
461 	{ "adv_10fdx_cap", { "", 0 },
462 	    link_01_vals, VALCNT(link_01_vals),
463 	    NULL, NULL, i_dladm_binary_get, NULL,
464 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
465 
466 	{ "en_10fdx_cap", { "", 0 },
467 	    link_01_vals, VALCNT(link_01_vals),
468 	    i_dladm_set_public_prop, NULL, i_dladm_binary_get, NULL,
469 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
470 
471 	{ "adv_10hdx_cap", { "", 0 },
472 	    link_01_vals, VALCNT(link_01_vals),
473 	    NULL, NULL, i_dladm_binary_get, NULL,
474 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
475 
476 	{ "en_10hdx_cap", { "", 0 },
477 	    link_01_vals, VALCNT(link_01_vals),
478 	    i_dladm_set_public_prop, NULL, i_dladm_binary_get, NULL,
479 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
480 
481 	{ "maxbw", { "--", RESET_VAL }, NULL, 0,
482 	    do_set_res, NULL,
483 	    i_dladm_maxbw_get, do_check_maxbw, PD_CHECK_ALLOC,
484 	    DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
485 
486 	{ "cpus", { "--", RESET_VAL }, NULL, 0,
487 	    do_set_cpus, NULL,
488 	    i_dladm_cpus_get, do_check_cpus, 0,
489 	    DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
490 
491 	{ "priority", { "high", RESET_VAL },
492 	    link_priority_vals, VALCNT(link_priority_vals), do_set_res, NULL,
493 	    i_dladm_priority_get, do_check_priority, PD_CHECK_ALLOC,
494 	    DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
495 };
496 
497 #define	DLADM_MAX_PROPS	(sizeof (prop_table) / sizeof (prop_desc_t))
498 
499 static resource_prop_t rsrc_prop_table[] = {
500 	{"maxbw",	do_extract_maxbw},
501 	{"priority",	do_extract_priority},
502 	{"cpus",	do_extract_cpus}
503 };
504 #define	DLADM_MAX_RSRC_PROP (sizeof (rsrc_prop_table) / \
505 	sizeof (resource_prop_t))
506 
507 /*
508  * when retrieving  private properties, we pass down a buffer with
509  * DLADM_PROP_BUF_CHUNK of space for the driver to return the property value.
510  */
511 #define	DLADM_PROP_BUF_CHUNK	1024
512 
513 static dladm_status_t	i_dladm_set_linkprop_db(dladm_handle_t, datalink_id_t,
514 			    const char *, char **, uint_t);
515 static dladm_status_t	i_dladm_get_linkprop_db(dladm_handle_t, datalink_id_t,
516 			    const char *, char **, uint_t *);
517 static dladm_status_t	i_dladm_walk_linkprop_priv_db(dladm_handle_t,
518 			    datalink_id_t, void *, int (*)(dladm_handle_t,
519 			    datalink_id_t, const char *, void *));
520 static dladm_status_t	i_dladm_set_single_prop(dladm_handle_t, datalink_id_t,
521 			    datalink_class_t, uint32_t, prop_desc_t *, char **,
522 			    uint_t, uint_t);
523 static dladm_status_t	i_dladm_set_linkprop(dladm_handle_t, datalink_id_t,
524 			    const char *, char **, uint_t, uint_t);
525 static dladm_status_t	i_dladm_getset_defval(dladm_handle_t, prop_desc_t *,
526 			    datalink_id_t, datalink_media_t, uint_t);
527 
528 /*
529  * Unfortunately, MAX_SCAN_SUPPORT_RATES is too small to allow all
530  * rates to be retrieved. However, we cannot increase it at this
531  * time because it will break binary compatibility with unbundled
532  * WiFi drivers and utilities. So for now we define an additional
533  * constant, MAX_SUPPORT_RATES, to allow all rates to be retrieved.
534  */
535 #define	MAX_SUPPORT_RATES	64
536 
537 #define	AP_ANCHOR	"[anchor]"
538 #define	AP_DELIMITER	'.'
539 
540 static dladm_status_t
541 do_check_prop(prop_desc_t *pdp, char **prop_val, uint_t val_cnt,
542     val_desc_t *vdp)
543 {
544 	int		i, j;
545 	dladm_status_t	status = DLADM_STATUS_OK;
546 
547 	for (j = 0; j < val_cnt; j++) {
548 		for (i = 0; i < pdp->pd_noptval; i++) {
549 			if (strcasecmp(*prop_val,
550 			    pdp->pd_optval[i].vd_name) == 0) {
551 				break;
552 			}
553 		}
554 		if (i == pdp->pd_noptval) {
555 			status = DLADM_STATUS_BADVAL;
556 			goto done;
557 		}
558 		(void) memcpy(vdp + j, &pdp->pd_optval[i], sizeof (val_desc_t));
559 	}
560 
561 done:
562 	return (status);
563 }
564 
565 static dladm_status_t
566 i_dladm_set_single_prop(dladm_handle_t handle, datalink_id_t linkid,
567     datalink_class_t class, uint32_t media, prop_desc_t *pdp, char **prop_val,
568     uint_t val_cnt, uint_t flags)
569 {
570 	dladm_status_t	status = DLADM_STATUS_OK;
571 	val_desc_t	*vdp = NULL;
572 	boolean_t	needfree = B_FALSE;
573 	uint_t		cnt, i;
574 
575 	if (!(pdp->pd_class & class))
576 		return (DLADM_STATUS_BADARG);
577 
578 	if (!DATALINK_MEDIA_ACCEPTED(pdp->pd_dmedia, media))
579 		return (DLADM_STATUS_BADARG);
580 
581 	if ((flags & DLADM_OPT_PERSIST) && (pdp->pd_flags & PD_TEMPONLY))
582 		return (DLADM_STATUS_TEMPONLY);
583 
584 	if (!(flags & DLADM_OPT_ACTIVE))
585 		return (DLADM_STATUS_OK);
586 
587 	if (pdp->pd_set == NULL)
588 		return (DLADM_STATUS_PROPRDONLY);
589 
590 	if (prop_val != NULL) {
591 		vdp = malloc(sizeof (val_desc_t) * val_cnt);
592 		if (vdp == NULL)
593 			return (DLADM_STATUS_NOMEM);
594 
595 		if (pdp->pd_check != NULL) {
596 			needfree = ((pdp->pd_flags & PD_CHECK_ALLOC) != 0);
597 			status = pdp->pd_check(handle, pdp, linkid, prop_val,
598 			    val_cnt, vdp, media);
599 		} else if (pdp->pd_optval != NULL) {
600 			status = do_check_prop(pdp, prop_val, val_cnt, vdp);
601 		} else {
602 			status = DLADM_STATUS_BADARG;
603 		}
604 
605 		if (status != DLADM_STATUS_OK)
606 			goto done;
607 
608 		cnt = val_cnt;
609 	} else {
610 		boolean_t	defval = B_FALSE;
611 
612 		if (pdp->pd_defval.vd_name == NULL)
613 			return (DLADM_STATUS_NOTSUP);
614 
615 		cnt = 1;
616 		defval = (strlen(pdp->pd_defval.vd_name) > 0);
617 		if ((pdp->pd_flags & PD_CHECK_ALLOC) != 0 || defval) {
618 			if ((vdp = malloc(sizeof (val_desc_t))) == NULL)
619 				return (DLADM_STATUS_NOMEM);
620 
621 			if (defval) {
622 				(void) memcpy(vdp, &pdp->pd_defval,
623 				    sizeof (val_desc_t));
624 			} else if (pdp->pd_check != NULL) {
625 				status = pdp->pd_check(handle, pdp, linkid,
626 				    prop_val, cnt, vdp, media);
627 				if (status != DLADM_STATUS_OK)
628 					goto done;
629 			}
630 		} else {
631 			status = i_dladm_getset_defval(handle, pdp, linkid,
632 			    media, flags);
633 			return (status);
634 		}
635 	}
636 	status = pdp->pd_set(handle, pdp, linkid, vdp, cnt, flags, media);
637 	if (needfree) {
638 		for (i = 0; i < cnt; i++)
639 			free((void *)((val_desc_t *)vdp + i)->vd_val);
640 	}
641 done:
642 	free(vdp);
643 	return (status);
644 }
645 
646 static dladm_status_t
647 i_dladm_set_linkprop(dladm_handle_t handle, datalink_id_t linkid,
648     const char *prop_name, char **prop_val, uint_t val_cnt, uint_t flags)
649 {
650 	int			i;
651 	boolean_t		found = B_FALSE;
652 	datalink_class_t	class;
653 	uint32_t		media;
654 	dladm_status_t		status = DLADM_STATUS_OK;
655 
656 	status = dladm_datalink_id2info(handle, linkid, NULL, &class, &media,
657 	    NULL, 0);
658 	if (status != DLADM_STATUS_OK)
659 		return (status);
660 
661 	for (i = 0; i < DLADM_MAX_PROPS; i++) {
662 		prop_desc_t	*pdp = &prop_table[i];
663 		dladm_status_t	s;
664 
665 		if (prop_name != NULL &&
666 		    (strcasecmp(prop_name, pdp->pd_name) != 0))
667 			continue;
668 		found = B_TRUE;
669 		s = i_dladm_set_single_prop(handle, linkid, class, media, pdp,
670 		    prop_val, val_cnt, flags);
671 
672 		if (prop_name != NULL) {
673 			status = s;
674 			break;
675 		} else {
676 			if (s != DLADM_STATUS_OK &&
677 			    s != DLADM_STATUS_NOTSUP)
678 				status = s;
679 		}
680 	}
681 	if (!found) {
682 		if (prop_name[0] == '_') {
683 			/* other private properties */
684 			status = i_dladm_set_prop(handle, linkid, prop_name,
685 			    prop_val, val_cnt, flags);
686 		} else  {
687 			status = DLADM_STATUS_NOTFOUND;
688 		}
689 	}
690 
691 	return (status);
692 }
693 
694 /*
695  * Set/reset link property for specific link
696  */
697 dladm_status_t
698 dladm_set_linkprop(dladm_handle_t handle, datalink_id_t linkid,
699     const char *prop_name, char **prop_val, uint_t val_cnt, uint_t flags)
700 {
701 	dladm_status_t	status = DLADM_STATUS_OK;
702 
703 	if ((linkid == DATALINK_INVALID_LINKID) || (flags == 0) ||
704 	    (prop_val == NULL && val_cnt > 0) ||
705 	    (prop_val != NULL && val_cnt == 0) ||
706 	    (prop_name == NULL && prop_val != NULL)) {
707 		return (DLADM_STATUS_BADARG);
708 	}
709 
710 	status = i_dladm_set_linkprop(handle, linkid, prop_name, prop_val,
711 	    val_cnt, flags);
712 	if (status != DLADM_STATUS_OK)
713 		return (status);
714 
715 	if (flags & DLADM_OPT_PERSIST) {
716 		status = i_dladm_set_linkprop_db(handle, linkid, prop_name,
717 		    prop_val, val_cnt);
718 	}
719 	return (status);
720 }
721 
722 /*
723  * Walk all link properties of the given specific link.
724  *
725  * Note: this function currently lacks the ability to walk _all_ private
726  * properties if the link, because there is no kernel interface to
727  * retrieve all known private property names. Once such an interface
728  * is added, this function should be fixed accordingly.
729  */
730 dladm_status_t
731 dladm_walk_linkprop(dladm_handle_t handle, datalink_id_t linkid, void *arg,
732     int (*func)(dladm_handle_t, datalink_id_t, const char *, void *))
733 {
734 	dladm_status_t		status;
735 	datalink_class_t	class;
736 	uint_t			media;
737 	int			i;
738 
739 	if (linkid == DATALINK_INVALID_LINKID || func == NULL)
740 		return (DLADM_STATUS_BADARG);
741 
742 	status = dladm_datalink_id2info(handle, linkid, NULL, &class, &media,
743 	    NULL, 0);
744 	if (status != DLADM_STATUS_OK)
745 		return (status);
746 
747 	/* public */
748 	for (i = 0; i < DLADM_MAX_PROPS; i++) {
749 		if (!(prop_table[i].pd_class & class))
750 			continue;
751 
752 		if (!DATALINK_MEDIA_ACCEPTED(prop_table[i].pd_dmedia, media))
753 			continue;
754 
755 		if (func(handle, linkid, prop_table[i].pd_name, arg) ==
756 		    DLADM_WALK_TERMINATE) {
757 			break;
758 		}
759 	}
760 
761 	/* private */
762 	status = i_dladm_walk_linkprop_priv_db(handle, linkid, arg, func);
763 
764 	return (status);
765 }
766 
767 /*
768  * Get linkprop of the given specific link.
769  */
770 dladm_status_t
771 dladm_get_linkprop(dladm_handle_t handle, datalink_id_t linkid,
772     dladm_prop_type_t type, const char *prop_name, char **prop_val,
773     uint_t *val_cntp)
774 {
775 	dladm_status_t		status = DLADM_STATUS_OK;
776 	datalink_class_t	class;
777 	uint_t			media;
778 	prop_desc_t		*pdp;
779 	uint_t			cnt, dld_flags = 0;
780 	int			i;
781 	uint_t			perm_flags;
782 
783 	if (type == DLADM_PROP_VAL_DEFAULT)
784 		dld_flags = MAC_PROP_DEFAULT;
785 
786 	if (linkid == DATALINK_INVALID_LINKID || prop_name == NULL ||
787 	    prop_val == NULL || val_cntp == NULL || *val_cntp == 0)
788 		return (DLADM_STATUS_BADARG);
789 
790 	for (i = 0; i < DLADM_MAX_PROPS; i++)
791 		if (strcasecmp(prop_name, prop_table[i].pd_name) == 0)
792 			break;
793 
794 	if (i == DLADM_MAX_PROPS) {
795 		if (prop_name[0] == '_') {
796 			/*
797 			 * private property.
798 			 */
799 			if (type == DLADM_PROP_VAL_PERSISTENT)
800 				return (i_dladm_get_linkprop_db(handle, linkid,
801 				    prop_name, prop_val, val_cntp));
802 			else
803 				return (i_dladm_get_priv_prop(handle, linkid,
804 				    prop_name, prop_val, val_cntp, type,
805 				    dld_flags));
806 		} else {
807 			return (DLADM_STATUS_NOTFOUND);
808 		}
809 	}
810 
811 	pdp = &prop_table[i];
812 
813 	status = dladm_datalink_id2info(handle, linkid, NULL, &class, &media,
814 	    NULL, 0);
815 	if (status != DLADM_STATUS_OK)
816 		return (status);
817 
818 	if (!(pdp->pd_class & class))
819 		return (DLADM_STATUS_BADARG);
820 
821 	if (!DATALINK_MEDIA_ACCEPTED(pdp->pd_dmedia, media))
822 		return (DLADM_STATUS_BADARG);
823 
824 	switch (type) {
825 	case DLADM_PROP_VAL_CURRENT:
826 		status = pdp->pd_get(handle, pdp, linkid, prop_val, val_cntp,
827 		    media, dld_flags, &perm_flags);
828 		break;
829 
830 	case DLADM_PROP_VAL_PERM:
831 		if (pdp->pd_set == NULL) {
832 			perm_flags = MAC_PROP_PERM_READ;
833 			*val_cntp = 1;
834 		} else {
835 			status = pdp->pd_get(handle, pdp, linkid, prop_val,
836 			    val_cntp, media, dld_flags, &perm_flags);
837 		}
838 
839 		*prop_val[0] = '\0';
840 		if (status == DLADM_STATUS_OK)
841 			(void) dladm_perm2str(perm_flags, *prop_val);
842 		break;
843 
844 	case DLADM_PROP_VAL_DEFAULT:
845 		/*
846 		 * If defaults are not defined for the property,
847 		 * pd_defval.vd_name should be null. If the driver
848 		 * has to be contacted for the value, vd_name should
849 		 * be the empty string (""). Otherwise, dladm will
850 		 * just print whatever is in the table.
851 		 */
852 		if (pdp->pd_defval.vd_name == NULL) {
853 			status = DLADM_STATUS_NOTSUP;
854 			break;
855 		}
856 
857 		if (strlen(pdp->pd_defval.vd_name) == 0) {
858 			status = pdp->pd_get(handle, pdp, linkid, prop_val,
859 			    val_cntp, media, dld_flags, &perm_flags);
860 		} else {
861 			(void) strcpy(*prop_val, pdp->pd_defval.vd_name);
862 		}
863 		*val_cntp = 1;
864 		break;
865 
866 	case DLADM_PROP_VAL_MODIFIABLE:
867 		if (pdp->pd_getmod != NULL) {
868 			status = pdp->pd_getmod(handle, pdp, linkid, prop_val,
869 			    val_cntp, media, dld_flags, &perm_flags);
870 			break;
871 		}
872 		cnt = pdp->pd_noptval;
873 		if (cnt == 0) {
874 			status = DLADM_STATUS_NOTSUP;
875 		} else if (cnt > *val_cntp) {
876 			status = DLADM_STATUS_TOOSMALL;
877 		} else {
878 			for (i = 0; i < cnt; i++) {
879 				(void) strcpy(prop_val[i],
880 				    pdp->pd_optval[i].vd_name);
881 			}
882 			*val_cntp = cnt;
883 		}
884 		break;
885 	case DLADM_PROP_VAL_PERSISTENT:
886 		if (pdp->pd_flags & PD_TEMPONLY)
887 			return (DLADM_STATUS_TEMPONLY);
888 		status = i_dladm_get_linkprop_db(handle, linkid, prop_name,
889 		    prop_val, val_cntp);
890 		break;
891 	default:
892 		status = DLADM_STATUS_BADARG;
893 		break;
894 	}
895 
896 	return (status);
897 }
898 
899 /*ARGSUSED*/
900 static int
901 i_dladm_init_one_prop(dladm_handle_t handle, datalink_id_t linkid,
902     const char *prop_name, void *arg)
903 {
904 	char	*buf, **propvals;
905 	uint_t	i, valcnt = DLADM_MAX_PROP_VALCNT;
906 
907 	if ((buf = malloc((sizeof (char *) + DLADM_PROP_VAL_MAX) *
908 	    DLADM_MAX_PROP_VALCNT)) == NULL) {
909 		return (DLADM_WALK_CONTINUE);
910 	}
911 
912 	propvals = (char **)(void *)buf;
913 	for (i = 0; i < valcnt; i++) {
914 		propvals[i] = buf +
915 		    sizeof (char *) * DLADM_MAX_PROP_VALCNT +
916 		    i * DLADM_PROP_VAL_MAX;
917 	}
918 
919 	if (dladm_get_linkprop(handle, linkid, DLADM_PROP_VAL_PERSISTENT,
920 	    prop_name, propvals, &valcnt) != DLADM_STATUS_OK) {
921 		goto done;
922 	}
923 
924 	(void) dladm_set_linkprop(handle, linkid, prop_name, propvals, valcnt,
925 	    DLADM_OPT_ACTIVE);
926 
927 done:
928 	if (buf != NULL)
929 		free(buf);
930 
931 	return (DLADM_WALK_CONTINUE);
932 }
933 
934 /*ARGSUSED*/
935 static int
936 i_dladm_init_linkprop(dladm_handle_t handle, datalink_id_t linkid, void *arg)
937 {
938 	datalink_class_t	class;
939 	dladm_status_t		status;
940 
941 	status = dladm_datalink_id2info(handle, linkid, NULL, &class, NULL,
942 	    NULL, 0);
943 	if (status != DLADM_STATUS_OK)
944 		return (DLADM_WALK_TERMINATE);
945 
946 	if ((class & (DATALINK_CLASS_VNIC | DATALINK_CLASS_VLAN)) == 0)
947 		(void) dladm_init_linkprop(handle, linkid, B_TRUE);
948 
949 	return (DLADM_WALK_CONTINUE);
950 }
951 
952 dladm_status_t
953 dladm_init_linkprop(dladm_handle_t handle, datalink_id_t linkid,
954     boolean_t any_media)
955 {
956 	datalink_media_t	dmedia;
957 	uint32_t		media;
958 
959 	dmedia = any_media ? DATALINK_ANY_MEDIATYPE : DL_WIFI;
960 
961 	if (linkid == DATALINK_ALL_LINKID) {
962 		(void) dladm_walk_datalink_id(i_dladm_init_linkprop, handle,
963 		    NULL, DATALINK_CLASS_ALL, dmedia, DLADM_OPT_PERSIST);
964 	} else if (any_media ||
965 	    ((dladm_datalink_id2info(handle, linkid, NULL, NULL, &media, NULL,
966 	    0) == DLADM_STATUS_OK) &&
967 	    DATALINK_MEDIA_ACCEPTED(dmedia, media))) {
968 		(void) dladm_walk_linkprop(handle, linkid, NULL,
969 		    i_dladm_init_one_prop);
970 	}
971 	return (DLADM_STATUS_OK);
972 }
973 
974 /* ARGSUSED */
975 static dladm_status_t
976 do_get_zone(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
977     char **prop_val, uint_t *val_cnt, datalink_media_t media,
978     uint_t flags, uint_t *perm_flags)
979 {
980 	char			zone_name[ZONENAME_MAX];
981 	zoneid_t		zid;
982 	dladm_status_t		status;
983 	char			*cp;
984 	dld_ioc_macprop_t	*dip;
985 
986 	if (flags != 0)
987 		return (DLADM_STATUS_NOTSUP);
988 
989 	dip = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags,
990 	    &status, perm_flags);
991 	if (status != DLADM_STATUS_OK)
992 		return (status);
993 
994 	cp = dip->pr_val;
995 	(void) memcpy(&zid, cp, sizeof (zid));
996 	free(dip);
997 
998 	*val_cnt = 1;
999 	if (zid != GLOBAL_ZONEID) {
1000 		if (getzonenamebyid(zid, zone_name, sizeof (zone_name)) < 0) {
1001 			return (dladm_errno2status(errno));
1002 		}
1003 
1004 		(void) strncpy(*prop_val, zone_name, DLADM_PROP_VAL_MAX);
1005 	} else {
1006 		*prop_val[0] = '\0';
1007 	}
1008 
1009 	return (DLADM_STATUS_OK);
1010 }
1011 
1012 typedef int (*zone_get_devroot_t)(char *, char *, size_t);
1013 
1014 static int
1015 i_dladm_get_zone_dev(char *zone_name, char *dev, size_t devlen)
1016 {
1017 	char			root[MAXPATHLEN];
1018 	zone_get_devroot_t	real_zone_get_devroot;
1019 	void			*dlhandle;
1020 	void			*sym;
1021 	int			ret;
1022 
1023 	if ((dlhandle = dlopen("libzonecfg.so.1", RTLD_LAZY)) == NULL)
1024 		return (-1);
1025 
1026 	if ((sym = dlsym(dlhandle, "zone_get_devroot")) == NULL) {
1027 		(void) dlclose(dlhandle);
1028 		return (-1);
1029 	}
1030 
1031 	real_zone_get_devroot = (zone_get_devroot_t)sym;
1032 
1033 	if ((ret = real_zone_get_devroot(zone_name, root, sizeof (root))) == 0)
1034 		(void) snprintf(dev, devlen, "%s%s", root, "/dev");
1035 	(void) dlclose(dlhandle);
1036 	return (ret);
1037 }
1038 
1039 static dladm_status_t
1040 i_dladm_update_deventry(dladm_handle_t handle, zoneid_t zid,
1041     datalink_id_t linkid, boolean_t add)
1042 {
1043 	char		path[MAXPATHLEN];
1044 	char		name[MAXLINKNAMELEN];
1045 	di_prof_t	prof = NULL;
1046 	char		zone_name[ZONENAME_MAX];
1047 	dladm_status_t	status;
1048 	int		ret;
1049 
1050 	if (getzonenamebyid(zid, zone_name, sizeof (zone_name)) < 0)
1051 		return (dladm_errno2status(errno));
1052 	if (i_dladm_get_zone_dev(zone_name, path, sizeof (path)) != 0)
1053 		return (dladm_errno2status(errno));
1054 	if (di_prof_init(path, &prof) != 0)
1055 		return (dladm_errno2status(errno));
1056 
1057 	status = dladm_linkid2legacyname(handle, linkid, name, MAXLINKNAMELEN);
1058 	if (status != DLADM_STATUS_OK)
1059 		goto cleanup;
1060 
1061 	if (add)
1062 		ret = di_prof_add_dev(prof, name);
1063 	else
1064 		ret = di_prof_add_exclude(prof, name);
1065 
1066 	if (ret != 0) {
1067 		status = dladm_errno2status(errno);
1068 		goto cleanup;
1069 	}
1070 
1071 	if (di_prof_commit(prof) != 0)
1072 		status = dladm_errno2status(errno);
1073 cleanup:
1074 	if (prof)
1075 		di_prof_fini(prof);
1076 
1077 	return (status);
1078 }
1079 
1080 /* ARGSUSED */
1081 static dladm_status_t
1082 do_set_zone(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
1083     val_desc_t *vdp, uint_t val_cnt, uint_t flags, datalink_media_t media)
1084 {
1085 	dladm_status_t		status = DLADM_STATUS_OK;
1086 	zoneid_t		zid_old, zid_new;
1087 	char			link[MAXLINKNAMELEN];
1088 	char			*cp;
1089 	dld_ioc_macprop_t	*dip;
1090 	dld_ioc_zid_t		*dzp;
1091 
1092 	if (val_cnt != 1)
1093 		return (DLADM_STATUS_BADVALCNT);
1094 
1095 	dzp = (dld_ioc_zid_t *)vdp->vd_val;
1096 
1097 	dip = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags,
1098 	    &status, NULL);
1099 	if (status != DLADM_STATUS_OK)
1100 		return (status);
1101 
1102 	cp = dip->pr_val;
1103 	(void) memcpy(&zid_old, cp, sizeof (zid_old));
1104 	free(dip);
1105 
1106 	zid_new = dzp->diz_zid;
1107 	(void) strlcpy(link, dzp->diz_link, MAXLINKNAMELEN);
1108 
1109 	/* Do nothing if setting to current value */
1110 	if (zid_new == zid_old)
1111 		return (status);
1112 
1113 	if (zid_new != GLOBAL_ZONEID) {
1114 		/*
1115 		 * If the new zoneid is the global zone, we could destroy
1116 		 * the link (in the case of an implicitly-created VLAN) as a
1117 		 * result of setting the zoneid. In that case, we defer the
1118 		 * operation to the end of this function to avoid recreating
1119 		 * the VLAN and getting a different linkid during the rollback
1120 		 * if other operation fails.
1121 		 *
1122 		 * Otherwise, this operation will hold a reference to the
1123 		 * link and prevent a link renaming, so we need to do it
1124 		 * before other operations.
1125 		 */
1126 		status = i_dladm_set_public_prop(handle, pdp, linkid, vdp,
1127 		    val_cnt, flags, media);
1128 		if (status != DLADM_STATUS_OK)
1129 			return (status);
1130 	}
1131 
1132 	if (zid_old != GLOBAL_ZONEID) {
1133 		if (zone_remove_datalink(zid_old, link) != 0 &&
1134 		    errno != ENXIO) {
1135 			status = dladm_errno2status(errno);
1136 			goto rollback1;
1137 		}
1138 
1139 		/*
1140 		 * It is okay to fail to update the /dev entry (some
1141 		 * vanity-named links do not have a /dev entry).
1142 		 */
1143 		(void) i_dladm_update_deventry(handle, zid_old, linkid,
1144 		    B_FALSE);
1145 	}
1146 
1147 	if (zid_new != GLOBAL_ZONEID) {
1148 		if (zone_add_datalink(zid_new, link) != 0) {
1149 			status = dladm_errno2status(errno);
1150 			goto rollback2;
1151 		}
1152 
1153 		(void) i_dladm_update_deventry(handle, zid_new, linkid, B_TRUE);
1154 	} else {
1155 		status = i_dladm_set_public_prop(handle, pdp, linkid, vdp,
1156 		    val_cnt, flags, media);
1157 		if (status != DLADM_STATUS_OK)
1158 			goto rollback2;
1159 	}
1160 
1161 	return (DLADM_STATUS_OK);
1162 
1163 rollback2:
1164 	if (zid_old != GLOBAL_ZONEID)
1165 		(void) i_dladm_update_deventry(handle, zid_old, linkid, B_TRUE);
1166 	if (zid_old != GLOBAL_ZONEID)
1167 		(void) zone_add_datalink(zid_old, link);
1168 rollback1:
1169 	if (zid_new != GLOBAL_ZONEID) {
1170 		dzp->diz_zid = zid_old;
1171 		(void) i_dladm_set_public_prop(handle, pdp, linkid, vdp,
1172 		    val_cnt, flags, media);
1173 	}
1174 
1175 	return (status);
1176 }
1177 
1178 /* ARGSUSED */
1179 static dladm_status_t
1180 do_check_zone(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
1181     char **prop_val, uint_t val_cnt, val_desc_t *vdp, datalink_media_t media)
1182 {
1183 	char		*zone_name;
1184 	char		linkname[MAXLINKNAMELEN];
1185 	zoneid_t	zoneid;
1186 	dladm_status_t	status = DLADM_STATUS_OK;
1187 	dld_ioc_zid_t	*dzp;
1188 
1189 	if (val_cnt != 1)
1190 		return (DLADM_STATUS_BADVALCNT);
1191 
1192 	dzp = malloc(sizeof (dld_ioc_zid_t));
1193 	if (dzp == NULL)
1194 		return (DLADM_STATUS_NOMEM);
1195 
1196 	if ((status = dladm_datalink_id2info(handle, linkid, NULL, NULL, NULL,
1197 	    linkname, MAXLINKNAMELEN)) != DLADM_STATUS_OK) {
1198 		goto done;
1199 	}
1200 
1201 	zone_name = (prop_val != NULL) ? *prop_val : GLOBAL_ZONENAME;
1202 	if (strlen(linkname) > MAXLINKNAMELEN) {
1203 		status = DLADM_STATUS_BADVAL;
1204 		goto done;
1205 	}
1206 
1207 	if ((zoneid = getzoneidbyname(zone_name)) == -1) {
1208 		status = DLADM_STATUS_BADVAL;
1209 		goto done;
1210 	}
1211 
1212 	if (zoneid != GLOBAL_ZONEID) {
1213 		ushort_t	flags;
1214 
1215 		if (zone_getattr(zoneid, ZONE_ATTR_FLAGS, &flags,
1216 		    sizeof (flags)) < 0) {
1217 			status = dladm_errno2status(errno);
1218 			goto done;
1219 		}
1220 
1221 		if (!(flags & ZF_NET_EXCL)) {
1222 			status = DLADM_STATUS_BADVAL;
1223 			goto done;
1224 		}
1225 	}
1226 
1227 	(void) memset(dzp, 0, sizeof (dld_ioc_zid_t));
1228 
1229 	dzp->diz_zid = zoneid;
1230 	(void) strlcpy(dzp->diz_link, linkname, MAXLINKNAMELEN);
1231 
1232 	vdp->vd_val = (uintptr_t)dzp;
1233 	return (DLADM_STATUS_OK);
1234 done:
1235 	free(dzp);
1236 	return (status);
1237 }
1238 
1239 /* ARGSUSED */
1240 static dladm_status_t
1241 i_dladm_maxbw_get(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
1242     char **prop_val, uint_t *val_cnt, datalink_media_t media,
1243     uint_t flags, uint_t *perm_flags)
1244 {
1245 	dld_ioc_macprop_t	*dip;
1246 	mac_resource_props_t	mrp;
1247 	dladm_status_t		status;
1248 
1249 	dip = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags,
1250 	    &status, perm_flags);
1251 	if (dip == NULL)
1252 		return (status);
1253 
1254 	bcopy(dip->pr_val, &mrp, sizeof (mac_resource_props_t));
1255 	free(dip);
1256 
1257 	if ((mrp.mrp_mask & MRP_MAXBW) == 0) {
1258 		(*prop_val)[0] = '\0';
1259 	} else {
1260 		(void) dladm_bw2str(mrp.mrp_maxbw, prop_val[0]);
1261 	}
1262 	*val_cnt = 1;
1263 	return (DLADM_STATUS_OK);
1264 }
1265 
1266 /* ARGSUSED */
1267 static dladm_status_t
1268 do_check_maxbw(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
1269     char **prop_val, uint_t val_cnt, val_desc_t *vdp, datalink_media_t media)
1270 {
1271 	uint64_t	*maxbw;
1272 	dladm_status_t	status = DLADM_STATUS_OK;
1273 
1274 	if (val_cnt != 1)
1275 		return (DLADM_STATUS_BADVALCNT);
1276 
1277 	maxbw = malloc(sizeof (uint64_t));
1278 	if (maxbw == NULL)
1279 		return (DLADM_STATUS_NOMEM);
1280 
1281 	status = dladm_str2bw(*prop_val, maxbw);
1282 	if (status != DLADM_STATUS_OK) {
1283 		free(maxbw);
1284 		return (status);
1285 	}
1286 
1287 	if ((*maxbw < MRP_MAXBW_MINVAL) && (*maxbw != 0)) {
1288 		free(maxbw);
1289 		return (DLADM_STATUS_MINMAXBW);
1290 	}
1291 
1292 	vdp->vd_val = (uintptr_t)maxbw;
1293 	return (DLADM_STATUS_OK);
1294 }
1295 
1296 /* ARGSUSED */
1297 dladm_status_t
1298 do_extract_maxbw(val_desc_t *vdp, void *arg, uint_t cnt)
1299 {
1300 	mac_resource_props_t *mrp = (mac_resource_props_t *)arg;
1301 
1302 	bcopy((char *)vdp->vd_val, &mrp->mrp_maxbw, sizeof (uint64_t));
1303 	mrp->mrp_mask |= MRP_MAXBW;
1304 
1305 	return (DLADM_STATUS_OK);
1306 }
1307 
1308 /* ARGSUSED */
1309 static dladm_status_t
1310 i_dladm_cpus_get(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
1311     char **prop_val, uint_t *val_cnt, datalink_media_t media,
1312     uint_t flags, uint_t *perm_flags)
1313 {
1314 	dld_ioc_macprop_t	*dip;
1315 	mac_resource_props_t	mrp;
1316 	int			i;
1317 	uint32_t		ncpus;
1318 	uchar_t			*cp;
1319 	dladm_status_t		status;
1320 
1321 	dip = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags,
1322 	    &status, perm_flags);
1323 	if (dip == NULL)
1324 		return (status);
1325 
1326 	cp = (uchar_t *)dip->pr_val;
1327 	(void) memcpy(&mrp, cp, sizeof (mac_resource_props_t));
1328 	free(dip);
1329 
1330 	ncpus = mrp.mrp_ncpus;
1331 
1332 	if (ncpus > *val_cnt)
1333 		return (DLADM_STATUS_TOOSMALL);
1334 
1335 	if (ncpus == 0) {
1336 		(*prop_val)[0] = '\0';
1337 		*val_cnt = 1;
1338 		return (DLADM_STATUS_OK);
1339 	}
1340 
1341 	*val_cnt = ncpus;
1342 	for (i = 0; i < ncpus; i++) {
1343 		(void) snprintf(prop_val[i], DLADM_PROP_VAL_MAX,
1344 		    "%u", mrp.mrp_cpu[i]);
1345 	}
1346 	return (DLADM_STATUS_OK);
1347 }
1348 
1349 /* ARGSUSED */
1350 static dladm_status_t
1351 do_set_res(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
1352     val_desc_t *vdp, uint_t val_cnt, uint_t flags, datalink_media_t media)
1353 {
1354 	mac_resource_props_t	mrp;
1355 	dladm_status_t		status = DLADM_STATUS_OK;
1356 	dld_ioc_macprop_t	*dip;
1357 
1358 	bzero(&mrp, sizeof (mac_resource_props_t));
1359 	dip = i_dladm_buf_alloc_by_name(0, linkid, pdp->pd_name,
1360 	    flags, &status);
1361 
1362 	if (dip == NULL)
1363 		return (status);
1364 
1365 	if (vdp->vd_val == RESET_VAL) {
1366 		switch (dip->pr_num) {
1367 		case MAC_PROP_MAXBW:
1368 			mrp.mrp_maxbw = MRP_MAXBW_RESETVAL;
1369 			mrp.mrp_mask = MRP_MAXBW;
1370 			break;
1371 		case MAC_PROP_PRIO:
1372 			mrp.mrp_priority = MPL_RESET;
1373 			mrp.mrp_mask = MRP_PRIORITY;
1374 			break;
1375 		default:
1376 			free(dip);
1377 			return (DLADM_STATUS_BADARG);
1378 		}
1379 	} else {
1380 		switch (dip->pr_num) {
1381 		case MAC_PROP_MAXBW:
1382 			bcopy((void *)vdp->vd_val, &mrp.mrp_maxbw,
1383 			    sizeof (uint64_t));
1384 			mrp.mrp_mask = MRP_MAXBW;
1385 			break;
1386 		case MAC_PROP_PRIO:
1387 			bcopy((void *)vdp->vd_val, &mrp.mrp_priority,
1388 			    sizeof (mac_priority_level_t));
1389 			mrp.mrp_mask = MRP_PRIORITY;
1390 			break;
1391 		default:
1392 			free(dip);
1393 			return (DLADM_STATUS_BADARG);
1394 		}
1395 	}
1396 
1397 	(void) memcpy(dip->pr_val, &mrp, dip->pr_valsize);
1398 	status = i_dladm_macprop(handle, dip, B_TRUE);
1399 	free(dip);
1400 	return (status);
1401 }
1402 
1403 /* ARGSUSED */
1404 static dladm_status_t
1405 do_set_cpus(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
1406     val_desc_t *vdp, uint_t val_cnt, uint_t flags, datalink_media_t media)
1407 {
1408 	mac_resource_props_t	mrp;
1409 	dladm_status_t		status;
1410 	dld_ioc_macprop_t	*dip;
1411 	datalink_class_t	class;
1412 
1413 	/*
1414 	 * CPU bindings can be set on VNIC and regular physical links.
1415 	 * However VNICs fails the dladm_phys_info test(). So apply
1416 	 * the phys_info test only on physical links.
1417 	 */
1418 	if ((status = dladm_datalink_id2info(handle, linkid, NULL, &class,
1419 	    NULL, NULL, 0)) != DLADM_STATUS_OK) {
1420 		return (status);
1421 	}
1422 
1423 	/*
1424 	 * We set intr_cpu to -1. The interrupt will be retargetted,
1425 	 * if possible when the setup is complete in MAC.
1426 	 */
1427 	bzero(&mrp, sizeof (mac_resource_props_t));
1428 	mrp.mrp_mask = MRP_CPUS;
1429 	if (vdp != NULL && vdp->vd_val != RESET_VAL) {
1430 		mac_resource_props_t	*vmrp;
1431 
1432 		vmrp = (mac_resource_props_t *)vdp->vd_val;
1433 		if (vmrp->mrp_ncpus > 0) {
1434 			bcopy(vmrp, &mrp, sizeof (mac_resource_props_t));
1435 			mrp.mrp_mask = MRP_CPUS;
1436 		}
1437 		mrp.mrp_mask |= MRP_CPUS_USERSPEC;
1438 		mrp.mrp_fanout_mode = MCM_CPUS;
1439 		mrp.mrp_intr_cpu = -1;
1440 	}
1441 
1442 	dip = i_dladm_buf_alloc_by_name(0, linkid, pdp->pd_name,
1443 	    flags, &status);
1444 	if (dip == NULL)
1445 		return (status);
1446 
1447 	(void) memcpy(dip->pr_val, &mrp, dip->pr_valsize);
1448 	status = i_dladm_macprop(handle, dip, B_TRUE);
1449 	free(dip);
1450 	return (status);
1451 }
1452 
1453 /* ARGSUSED */
1454 static dladm_status_t
1455 do_check_cpus(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
1456     char **prop_val, uint_t val_cnt, val_desc_t *vdp, datalink_media_t media)
1457 {
1458 	uint32_t		cpuid;
1459 	int			i, j, rc;
1460 	long			nproc = sysconf(_SC_NPROCESSORS_CONF);
1461 	mac_resource_props_t	*mrp;
1462 
1463 	mrp = malloc(sizeof (mac_resource_props_t));
1464 	if (mrp == NULL)
1465 		return (DLADM_STATUS_NOMEM);
1466 
1467 	for (i = 0; i < val_cnt; i++) {
1468 		errno = 0;
1469 		cpuid = strtol(prop_val[i], (char **)NULL, 10);
1470 		if (errno != 0 || cpuid >= nproc) {
1471 			free(mrp);
1472 			return (DLADM_STATUS_CPUMAX);
1473 		}
1474 		rc = p_online(cpuid, P_STATUS);
1475 		if (rc < 1) {
1476 			free(mrp);
1477 			return (DLADM_STATUS_CPUERR);
1478 		}
1479 		if (rc != P_ONLINE) {
1480 			free(mrp);
1481 			return (DLADM_STATUS_CPUNOTONLINE);
1482 		}
1483 		mrp->mrp_cpu[i] = cpuid;
1484 	}
1485 	mrp->mrp_ncpus = (uint32_t)val_cnt;
1486 
1487 	/* Check for duplicates */
1488 	for (i = 0; i < val_cnt; i++) {
1489 		for (j = 0; j < val_cnt; j++) {
1490 			if (i != j && mrp->mrp_cpu[i] == mrp->mrp_cpu[j]) {
1491 				free(mrp);
1492 				return (DLADM_STATUS_BADARG);
1493 			}
1494 		}
1495 	}
1496 	vdp->vd_val = (uintptr_t)mrp;
1497 
1498 	return (DLADM_STATUS_OK);
1499 }
1500 
1501 /* ARGSUSED */
1502 dladm_status_t
1503 do_extract_cpus(val_desc_t *vdp, void *arg, uint_t cnt)
1504 {
1505 	mac_resource_props_t	*mrp = (mac_resource_props_t *)arg;
1506 	mac_resource_props_t	*vmrp = (mac_resource_props_t *)vdp->vd_val;
1507 	int			i;
1508 
1509 	for (i = 0; i < vmrp->mrp_ncpus; i++) {
1510 		mrp->mrp_cpu[i] = vmrp->mrp_cpu[i];
1511 	}
1512 	mrp->mrp_ncpus = vmrp->mrp_ncpus;
1513 	mrp->mrp_mask |= (MRP_CPUS|MRP_CPUS_USERSPEC);
1514 	mrp->mrp_fanout_mode = MCM_CPUS;
1515 
1516 	return (DLADM_STATUS_OK);
1517 }
1518 
1519 /* ARGSUSED */
1520 static dladm_status_t
1521 i_dladm_priority_get(dladm_handle_t handle, prop_desc_t *pdp,
1522     datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
1523     datalink_media_t media, uint_t flags, uint_t *perm_flags)
1524 {
1525 	dld_ioc_macprop_t	*dip;
1526 	mac_resource_props_t	mrp;
1527 	mac_priority_level_t	pri;
1528 	dladm_status_t		status;
1529 
1530 	dip = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags,
1531 	    &status, perm_flags);
1532 	if (dip == NULL)
1533 		return (status);
1534 
1535 	bcopy(dip->pr_val, &mrp, sizeof (mac_resource_props_t));
1536 	free(dip);
1537 
1538 	pri = ((mrp.mrp_mask & MRP_PRIORITY) == 0) ? MPL_HIGH :
1539 	    mrp.mrp_priority;
1540 
1541 	(void) dladm_pri2str(pri, prop_val[0]);
1542 	*val_cnt = 1;
1543 	return (DLADM_STATUS_OK);
1544 }
1545 
1546 /* ARGSUSED */
1547 static dladm_status_t
1548 do_check_priority(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
1549     char **prop_val, uint_t val_cnt, val_desc_t *vdp, datalink_media_t media)
1550 {
1551 	mac_priority_level_t	*pri;
1552 	dladm_status_t	status = DLADM_STATUS_OK;
1553 
1554 	if (val_cnt != 1)
1555 		return (DLADM_STATUS_BADVALCNT);
1556 
1557 	pri = malloc(sizeof (mac_priority_level_t));
1558 	if (pri == NULL)
1559 		return (DLADM_STATUS_NOMEM);
1560 
1561 	status = dladm_str2pri(*prop_val, pri);
1562 	if (status != DLADM_STATUS_OK) {
1563 		free(pri);
1564 		return (status);
1565 	}
1566 
1567 	if (*pri < MPL_LOW || *pri > MPL_HIGH) {
1568 		free(pri);
1569 		return (DLADM_STATUS_BADVAL);
1570 	}
1571 
1572 	vdp->vd_val = (uintptr_t)pri;
1573 	return (DLADM_STATUS_OK);
1574 }
1575 
1576 /* ARGSUSED */
1577 dladm_status_t
1578 do_extract_priority(val_desc_t *vdp, void *arg, uint_t cnt)
1579 {
1580 	mac_resource_props_t *mrp = (mac_resource_props_t *)arg;
1581 
1582 	bcopy((char *)vdp->vd_val, &mrp->mrp_priority,
1583 	    sizeof (mac_priority_level_t));
1584 	mrp->mrp_mask |= MRP_PRIORITY;
1585 
1586 	return (DLADM_STATUS_OK);
1587 }
1588 
1589 /* ARGSUSED */
1590 static dladm_status_t
1591 do_get_autopush(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
1592     char **prop_val, uint_t *val_cnt, datalink_media_t media,
1593     uint_t flags, uint_t *perm_flags)
1594 {
1595 	struct		dlautopush dlap;
1596 	int		i, len;
1597 	dladm_status_t	status;
1598 	dld_ioc_macprop_t	*dip;
1599 
1600 	if (flags & MAC_PROP_DEFAULT)
1601 		return (DLADM_STATUS_NOTDEFINED);
1602 
1603 	*val_cnt = 1;
1604 	dip = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags,
1605 	    &status, perm_flags);
1606 	if (dip == NULL) {
1607 		(*prop_val)[0] = '\0';
1608 		return (DLADM_STATUS_OK);
1609 	}
1610 	(void) memcpy(&dlap, dip->pr_val, sizeof (dlap));
1611 
1612 	for (i = 0, len = 0; i < dlap.dap_npush; i++) {
1613 		if (i != 0) {
1614 			(void) snprintf(*prop_val + len,
1615 			    DLADM_PROP_VAL_MAX - len, "%c", AP_DELIMITER);
1616 			len += 1;
1617 		}
1618 		(void) snprintf(*prop_val + len, DLADM_PROP_VAL_MAX - len,
1619 		    "%s", dlap.dap_aplist[i]);
1620 		len += strlen(dlap.dap_aplist[i]);
1621 		if (dlap.dap_anchor - 1 == i) {
1622 			(void) snprintf(*prop_val + len,
1623 			    DLADM_PROP_VAL_MAX - len, "%c%s", AP_DELIMITER,
1624 			    AP_ANCHOR);
1625 			len += (strlen(AP_ANCHOR) + 1);
1626 		}
1627 	}
1628 	free(dip);
1629 done:
1630 	return (DLADM_STATUS_OK);
1631 }
1632 
1633 /*
1634  * Add the specified module to the dlautopush structure; returns a
1635  * DLADM_STATUS_* code.
1636  */
1637 dladm_status_t
1638 i_dladm_add_ap_module(const char *module, struct dlautopush *dlap)
1639 {
1640 	if ((strlen(module) == 0) || (strlen(module) > FMNAMESZ))
1641 		return (DLADM_STATUS_BADVAL);
1642 
1643 	if (strncasecmp(module, AP_ANCHOR, strlen(AP_ANCHOR)) == 0) {
1644 		/*
1645 		 * We don't allow multiple anchors, and the anchor must
1646 		 * be after at least one module.
1647 		 */
1648 		if (dlap->dap_anchor != 0)
1649 			return (DLADM_STATUS_BADVAL);
1650 		if (dlap->dap_npush == 0)
1651 			return (DLADM_STATUS_BADVAL);
1652 
1653 		dlap->dap_anchor = dlap->dap_npush;
1654 		return (DLADM_STATUS_OK);
1655 	}
1656 	if (dlap->dap_npush > MAXAPUSH)
1657 		return (DLADM_STATUS_BADVALCNT);
1658 
1659 	(void) strlcpy(dlap->dap_aplist[dlap->dap_npush++], module,
1660 	    FMNAMESZ + 1);
1661 
1662 	return (DLADM_STATUS_OK);
1663 }
1664 
1665 /*
1666  * Currently, both '.' and ' '(space) can be used as the delimiters between
1667  * autopush modules. The former is used in dladm set-linkprop, and the
1668  * latter is used in the autopush(1M) file.
1669  */
1670 /* ARGSUSED */
1671 static dladm_status_t
1672 do_check_autopush(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
1673     char **prop_val, uint_t val_cnt, val_desc_t *vdp, datalink_media_t media)
1674 {
1675 	char			*module;
1676 	struct dlautopush	*dlap;
1677 	dladm_status_t		status;
1678 	char			val[DLADM_PROP_VAL_MAX];
1679 	char			delimiters[4];
1680 
1681 	if (val_cnt != 1)
1682 		return (DLADM_STATUS_BADVALCNT);
1683 
1684 	if (prop_val != NULL) {
1685 		dlap = malloc(sizeof (struct dlautopush));
1686 		if (dlap == NULL)
1687 			return (DLADM_STATUS_NOMEM);
1688 
1689 		(void) memset(dlap, 0, sizeof (struct dlautopush));
1690 		(void) snprintf(delimiters, 4, " %c\n", AP_DELIMITER);
1691 		bcopy(*prop_val, val, DLADM_PROP_VAL_MAX);
1692 		module = strtok(val, delimiters);
1693 		while (module != NULL) {
1694 			status = i_dladm_add_ap_module(module, dlap);
1695 			if (status != DLADM_STATUS_OK)
1696 				return (status);
1697 			module = strtok(NULL, delimiters);
1698 		}
1699 
1700 		vdp->vd_val = (uintptr_t)dlap;
1701 	} else {
1702 		vdp->vd_val = 0;
1703 	}
1704 	return (DLADM_STATUS_OK);
1705 }
1706 
1707 #define	WLDP_BUFSIZE (MAX_BUF_LEN - WIFI_BUF_OFFSET)
1708 
1709 /* ARGSUSED */
1710 static dladm_status_t
1711 do_get_rate_common(dladm_handle_t handle, prop_desc_t *pdp,
1712     datalink_id_t linkid, char **prop_val, uint_t *val_cnt, uint_t id,
1713     uint_t *perm_flags)
1714 {
1715 	wl_rates_t	*wrp;
1716 	uint_t		i;
1717 	dladm_status_t	status = DLADM_STATUS_OK;
1718 
1719 	wrp = malloc(WLDP_BUFSIZE);
1720 	if (wrp == NULL)
1721 		return (DLADM_STATUS_NOMEM);
1722 
1723 	status = i_dladm_wlan_param(handle, linkid, wrp, id, WLDP_BUFSIZE,
1724 	    B_FALSE);
1725 	if (status != DLADM_STATUS_OK)
1726 		goto done;
1727 
1728 	if (wrp->wl_rates_num > *val_cnt) {
1729 		status = DLADM_STATUS_TOOSMALL;
1730 		goto done;
1731 	}
1732 
1733 	if (wrp->wl_rates_rates[0] == 0) {
1734 		prop_val[0][0] = '\0';
1735 		*val_cnt = 1;
1736 		goto done;
1737 	}
1738 
1739 	for (i = 0; i < wrp->wl_rates_num; i++) {
1740 		(void) snprintf(prop_val[i], DLADM_STRSIZE, "%.*f",
1741 		    wrp->wl_rates_rates[i] % 2,
1742 		    (float)wrp->wl_rates_rates[i] / 2);
1743 	}
1744 	*val_cnt = wrp->wl_rates_num;
1745 	*perm_flags = MAC_PROP_PERM_RW;
1746 
1747 done:
1748 	free(wrp);
1749 	return (status);
1750 }
1751 
1752 static dladm_status_t
1753 do_get_rate_prop(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
1754     char **prop_val, uint_t *val_cnt, datalink_media_t media,
1755     uint_t flags, uint_t *perm_flags)
1756 {
1757 	if (media != DL_WIFI) {
1758 		return (i_dladm_speed_get(handle, pdp, linkid, prop_val,
1759 		    val_cnt, flags, perm_flags));
1760 	}
1761 
1762 	return (do_get_rate_common(handle, pdp, linkid, prop_val, val_cnt,
1763 	    MAC_PROP_WL_DESIRED_RATES, perm_flags));
1764 }
1765 
1766 /* ARGSUSED */
1767 static dladm_status_t
1768 do_get_rate_mod(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
1769     char **prop_val, uint_t *val_cnt, datalink_media_t media,
1770     uint_t flags, uint_t *perm_flags)
1771 {
1772 	switch (media) {
1773 	case DL_ETHER:
1774 		/*
1775 		 * Speed for ethernet links is unbounded. E.g., 802.11b
1776 		 * links can have a speed of 5.5 Gbps.
1777 		 */
1778 		return (DLADM_STATUS_NOTSUP);
1779 
1780 	case DL_WIFI:
1781 		return (do_get_rate_common(handle, pdp, linkid, prop_val,
1782 		    val_cnt, MAC_PROP_WL_SUPPORTED_RATES, perm_flags));
1783 	default:
1784 		return (DLADM_STATUS_BADARG);
1785 	}
1786 }
1787 
1788 static dladm_status_t
1789 do_set_rate(dladm_handle_t handle, datalink_id_t linkid,
1790     dladm_wlan_rates_t *rates)
1791 {
1792 	int		i;
1793 	uint_t		len;
1794 	wl_rates_t	*wrp;
1795 	dladm_status_t	status = DLADM_STATUS_OK;
1796 
1797 	wrp = malloc(WLDP_BUFSIZE);
1798 	if (wrp == NULL)
1799 		return (DLADM_STATUS_NOMEM);
1800 
1801 	bzero(wrp, WLDP_BUFSIZE);
1802 	for (i = 0; i < rates->wr_cnt; i++)
1803 		wrp->wl_rates_rates[i] = rates->wr_rates[i];
1804 	wrp->wl_rates_num = rates->wr_cnt;
1805 
1806 	len = offsetof(wl_rates_t, wl_rates_rates) +
1807 	    (rates->wr_cnt * sizeof (char)) + WIFI_BUF_OFFSET;
1808 	status = i_dladm_wlan_param(handle, linkid, wrp,
1809 	    MAC_PROP_WL_DESIRED_RATES, len, B_TRUE);
1810 
1811 	free(wrp);
1812 	return (status);
1813 }
1814 
1815 /* ARGSUSED */
1816 static dladm_status_t
1817 do_set_rate_prop(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
1818     val_desc_t *vdp, uint_t val_cnt, uint_t flags, datalink_media_t media)
1819 {
1820 	dladm_wlan_rates_t	rates;
1821 	dladm_status_t		status;
1822 
1823 	/*
1824 	 * can currently set rate on WIFI links only.
1825 	 */
1826 	if (media != DL_WIFI)
1827 		return (DLADM_STATUS_PROPRDONLY);
1828 
1829 	if (val_cnt != 1)
1830 		return (DLADM_STATUS_BADVALCNT);
1831 
1832 	rates.wr_cnt = 1;
1833 	rates.wr_rates[0] = vdp[0].vd_val;
1834 
1835 	status = do_set_rate(handle, linkid, &rates);
1836 
1837 done:
1838 	return (status);
1839 }
1840 
1841 /* ARGSUSED */
1842 static dladm_status_t
1843 do_check_rate(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
1844     char **prop_val, uint_t val_cnt, val_desc_t *vdp, datalink_media_t media)
1845 {
1846 	int		i;
1847 	uint_t		modval_cnt = MAX_SUPPORT_RATES;
1848 	char		*buf, **modval;
1849 	dladm_status_t	status;
1850 	uint_t 		perm_flags;
1851 
1852 	if (val_cnt != 1)
1853 		return (DLADM_STATUS_BADVALCNT);
1854 
1855 	buf = malloc((sizeof (char *) + DLADM_STRSIZE) *
1856 	    MAX_SUPPORT_RATES);
1857 	if (buf == NULL) {
1858 		status = DLADM_STATUS_NOMEM;
1859 		goto done;
1860 	}
1861 
1862 	modval = (char **)(void *)buf;
1863 	for (i = 0; i < MAX_SUPPORT_RATES; i++) {
1864 		modval[i] = buf + sizeof (char *) * MAX_SUPPORT_RATES +
1865 		    i * DLADM_STRSIZE;
1866 	}
1867 
1868 	status = do_get_rate_mod(handle, NULL, linkid, modval, &modval_cnt,
1869 	    media, 0, &perm_flags);
1870 	if (status != DLADM_STATUS_OK)
1871 		goto done;
1872 
1873 	for (i = 0; i < modval_cnt; i++) {
1874 		if (strcasecmp(*prop_val, modval[i]) == 0) {
1875 			vdp->vd_val = (uintptr_t)(uint_t)
1876 			    (atof(*prop_val) * 2);
1877 			status = DLADM_STATUS_OK;
1878 			break;
1879 		}
1880 	}
1881 	if (i == modval_cnt)
1882 		status = DLADM_STATUS_BADVAL;
1883 done:
1884 	free(buf);
1885 	return (status);
1886 }
1887 
1888 static dladm_status_t
1889 do_get_phyconf(dladm_handle_t handle, datalink_id_t linkid, void *buf,
1890     int buflen)
1891 {
1892 	return (i_dladm_wlan_param(handle, linkid, buf, MAC_PROP_WL_PHY_CONFIG,
1893 	    buflen, B_FALSE));
1894 }
1895 
1896 /* ARGSUSED */
1897 static dladm_status_t
1898 do_get_channel_prop(dladm_handle_t handle, prop_desc_t *pdp,
1899     datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
1900     datalink_media_t media, uint_t flags, uint_t *perm_flags)
1901 {
1902 	uint32_t	channel;
1903 	char		buf[WLDP_BUFSIZE];
1904 	dladm_status_t	status = DLADM_STATUS_OK;
1905 	wl_phy_conf_t	wl_phy_conf;
1906 
1907 	if ((status = do_get_phyconf(handle, linkid, buf, sizeof (buf)))
1908 	    != DLADM_STATUS_OK)
1909 		goto done;
1910 
1911 	(void) memcpy(&wl_phy_conf, buf, sizeof (wl_phy_conf));
1912 	if (!i_dladm_wlan_convert_chan(&wl_phy_conf, &channel)) {
1913 		status = DLADM_STATUS_NOTFOUND;
1914 		goto done;
1915 	}
1916 
1917 	(void) snprintf(*prop_val, DLADM_STRSIZE, "%u", channel);
1918 	*val_cnt = 1;
1919 	*perm_flags = MAC_PROP_PERM_READ;
1920 done:
1921 	return (status);
1922 }
1923 
1924 static dladm_status_t
1925 do_get_powermode(dladm_handle_t handle, datalink_id_t linkid, void *buf,
1926     int buflen)
1927 {
1928 	return (i_dladm_wlan_param(handle, linkid, buf, MAC_PROP_WL_POWER_MODE,
1929 	    buflen, B_FALSE));
1930 }
1931 
1932 /* ARGSUSED */
1933 static dladm_status_t
1934 do_get_powermode_prop(dladm_handle_t handle, prop_desc_t *pdp,
1935     datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
1936     datalink_media_t media, uint_t flags, uint_t *perm_flags)
1937 {
1938 	wl_ps_mode_t	mode;
1939 	const char	*s;
1940 	char		buf[WLDP_BUFSIZE];
1941 	dladm_status_t	status = DLADM_STATUS_OK;
1942 
1943 	if ((status = do_get_powermode(handle, linkid, buf, sizeof (buf)))
1944 	    != DLADM_STATUS_OK)
1945 		goto done;
1946 
1947 	(void) memcpy(&mode, buf, sizeof (mode));
1948 	switch (mode.wl_ps_mode) {
1949 	case WL_PM_AM:
1950 		s = "off";
1951 		break;
1952 	case WL_PM_MPS:
1953 		s = "max";
1954 		break;
1955 	case WL_PM_FAST:
1956 		s = "fast";
1957 		break;
1958 	default:
1959 		status = DLADM_STATUS_NOTFOUND;
1960 		goto done;
1961 	}
1962 	(void) snprintf(*prop_val, DLADM_STRSIZE, "%s", s);
1963 	*val_cnt = 1;
1964 	*perm_flags = MAC_PROP_PERM_RW;
1965 done:
1966 	return (status);
1967 }
1968 
1969 static dladm_status_t
1970 do_set_powermode(dladm_handle_t handle, datalink_id_t linkid,
1971     dladm_wlan_powermode_t *pm)
1972 {
1973 	wl_ps_mode_t    ps_mode;
1974 
1975 	(void) memset(&ps_mode, 0xff, sizeof (ps_mode));
1976 
1977 	switch (*pm) {
1978 	case DLADM_WLAN_PM_OFF:
1979 		ps_mode.wl_ps_mode = WL_PM_AM;
1980 		break;
1981 	case DLADM_WLAN_PM_MAX:
1982 		ps_mode.wl_ps_mode = WL_PM_MPS;
1983 		break;
1984 	case DLADM_WLAN_PM_FAST:
1985 		ps_mode.wl_ps_mode = WL_PM_FAST;
1986 		break;
1987 	default:
1988 		return (DLADM_STATUS_NOTSUP);
1989 	}
1990 	return (i_dladm_wlan_param(handle, linkid, &ps_mode,
1991 	    MAC_PROP_WL_POWER_MODE, sizeof (ps_mode), B_TRUE));
1992 }
1993 
1994 /* ARGSUSED */
1995 static dladm_status_t
1996 do_set_powermode_prop(dladm_handle_t handle, prop_desc_t *pdp,
1997     datalink_id_t linkid, val_desc_t *vdp, uint_t val_cnt, uint_t flags,
1998     datalink_media_t media)
1999 {
2000 	dladm_wlan_powermode_t powermode = (dladm_wlan_powermode_t)vdp->vd_val;
2001 	dladm_status_t status;
2002 
2003 	if (val_cnt != 1)
2004 		return (DLADM_STATUS_BADVALCNT);
2005 
2006 	status = do_set_powermode(handle, linkid, &powermode);
2007 
2008 	return (status);
2009 }
2010 
2011 static dladm_status_t
2012 do_get_radio(dladm_handle_t handle, datalink_id_t linkid, void *buf, int buflen)
2013 {
2014 	return (i_dladm_wlan_param(handle, linkid, buf, MAC_PROP_WL_RADIO,
2015 	    buflen, B_FALSE));
2016 }
2017 
2018 /* ARGSUSED */
2019 static dladm_status_t
2020 do_get_radio_prop(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
2021     char **prop_val, uint_t *val_cnt, datalink_media_t media,
2022     uint_t flags, uint_t *perm_flags)
2023 {
2024 	wl_radio_t	radio;
2025 	const char	*s;
2026 	char		buf[WLDP_BUFSIZE];
2027 	dladm_status_t	status = DLADM_STATUS_OK;
2028 
2029 	if ((status = do_get_radio(handle, linkid, buf, sizeof (buf)))
2030 	    != DLADM_STATUS_OK)
2031 		goto done;
2032 
2033 	(void) memcpy(&radio, buf, sizeof (radio));
2034 	switch (radio) {
2035 	case B_TRUE:
2036 		s = "on";
2037 		break;
2038 	case B_FALSE:
2039 		s = "off";
2040 		break;
2041 	default:
2042 		status = DLADM_STATUS_NOTFOUND;
2043 		goto done;
2044 	}
2045 	(void) snprintf(*prop_val, DLADM_STRSIZE, "%s", s);
2046 	*val_cnt = 1;
2047 	*perm_flags = MAC_PROP_PERM_RW;
2048 done:
2049 	return (status);
2050 }
2051 
2052 static dladm_status_t
2053 do_set_radio(dladm_handle_t handle, datalink_id_t linkid,
2054     dladm_wlan_radio_t *radio)
2055 {
2056 	wl_radio_t r;
2057 
2058 	switch (*radio) {
2059 	case DLADM_WLAN_RADIO_ON:
2060 		r = B_TRUE;
2061 		break;
2062 	case DLADM_WLAN_RADIO_OFF:
2063 		r = B_FALSE;
2064 		break;
2065 	default:
2066 		return (DLADM_STATUS_NOTSUP);
2067 	}
2068 	return (i_dladm_wlan_param(handle, linkid, &r, MAC_PROP_WL_RADIO,
2069 	    sizeof (r), B_TRUE));
2070 }
2071 
2072 /* ARGSUSED */
2073 static dladm_status_t
2074 do_set_radio_prop(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
2075     val_desc_t *vdp, uint_t val_cnt, uint_t fags, datalink_media_t media)
2076 {
2077 	dladm_wlan_radio_t radio = (dladm_wlan_radio_t)vdp->vd_val;
2078 	dladm_status_t status;
2079 
2080 	if (val_cnt != 1)
2081 		return (DLADM_STATUS_BADVALCNT);
2082 
2083 	status = do_set_radio(handle, linkid, &radio);
2084 
2085 	return (status);
2086 }
2087 
2088 static dladm_status_t
2089 i_dladm_set_linkprop_db(dladm_handle_t handle, datalink_id_t linkid,
2090     const char *prop_name, char **prop_val, uint_t val_cnt)
2091 {
2092 	char		buf[MAXLINELEN];
2093 	int		i;
2094 	dladm_conf_t	conf;
2095 	dladm_status_t	status;
2096 
2097 	status = dladm_read_conf(handle, linkid, &conf);
2098 	if (status != DLADM_STATUS_OK)
2099 		return (status);
2100 
2101 	/*
2102 	 * reset case.
2103 	 */
2104 	if (val_cnt == 0) {
2105 		status = dladm_unset_conf_field(handle, conf, prop_name);
2106 		if (status == DLADM_STATUS_OK)
2107 			status = dladm_write_conf(handle, conf);
2108 		goto done;
2109 	}
2110 
2111 	buf[0] = '\0';
2112 	for (i = 0; i < val_cnt; i++) {
2113 		(void) strlcat(buf, prop_val[i], MAXLINELEN);
2114 		if (i != val_cnt - 1)
2115 			(void) strlcat(buf, ",", MAXLINELEN);
2116 	}
2117 
2118 	status = dladm_set_conf_field(handle, conf, prop_name, DLADM_TYPE_STR,
2119 	    buf);
2120 	if (status == DLADM_STATUS_OK)
2121 		status = dladm_write_conf(handle, conf);
2122 
2123 done:
2124 	dladm_destroy_conf(handle, conf);
2125 	return (status);
2126 }
2127 
2128 static dladm_status_t
2129 i_dladm_get_linkprop_db(dladm_handle_t handle, datalink_id_t linkid,
2130     const char *prop_name, char **prop_val, uint_t *val_cntp)
2131 {
2132 	char		buf[MAXLINELEN], *str;
2133 	uint_t		cnt = 0;
2134 	dladm_conf_t	conf;
2135 	dladm_status_t	status;
2136 
2137 	status = dladm_read_conf(handle, linkid, &conf);
2138 	if (status != DLADM_STATUS_OK)
2139 		return (status);
2140 
2141 	status = dladm_get_conf_field(handle, conf, prop_name, buf, MAXLINELEN);
2142 	if (status != DLADM_STATUS_OK)
2143 		goto done;
2144 
2145 	str = strtok(buf, ",");
2146 	while (str != NULL) {
2147 		if (cnt == *val_cntp) {
2148 			status = DLADM_STATUS_TOOSMALL;
2149 			goto done;
2150 		}
2151 		(void) strlcpy(prop_val[cnt++], str, DLADM_PROP_VAL_MAX);
2152 		str = strtok(NULL, ",");
2153 	}
2154 
2155 	*val_cntp = cnt;
2156 
2157 done:
2158 	dladm_destroy_conf(handle, conf);
2159 	return (status);
2160 }
2161 
2162 /*
2163  * Walk persistent private link properties of a link.
2164  */
2165 static dladm_status_t
2166 i_dladm_walk_linkprop_priv_db(dladm_handle_t handle, datalink_id_t linkid,
2167     void *arg, int (*func)(dladm_handle_t, datalink_id_t, const char *, void *))
2168 {
2169 	dladm_status_t		status;
2170 	dladm_conf_t		conf;
2171 	char			last_attr[MAXLINKATTRLEN];
2172 	char			attr[MAXLINKATTRLEN];
2173 	char			attrval[MAXLINKATTRVALLEN];
2174 	size_t			attrsz;
2175 
2176 	if (linkid == DATALINK_INVALID_LINKID || func == NULL)
2177 		return (DLADM_STATUS_BADARG);
2178 
2179 	status = dladm_read_conf(handle, linkid, &conf);
2180 	if (status != DLADM_STATUS_OK)
2181 		return (status);
2182 
2183 	last_attr[0] = '\0';
2184 	while ((status = dladm_getnext_conf_linkprop(handle, conf, last_attr,
2185 	    attr, attrval, MAXLINKATTRVALLEN, &attrsz)) == DLADM_STATUS_OK) {
2186 		if (attr[0] == '_') {
2187 			if (func(handle, linkid, attr, arg) ==
2188 			    DLADM_WALK_TERMINATE)
2189 				break;
2190 		}
2191 		(void) strlcpy(last_attr, attr, MAXLINKATTRLEN);
2192 	}
2193 
2194 	dladm_destroy_conf(handle, conf);
2195 	return (DLADM_STATUS_OK);
2196 }
2197 
2198 static link_attr_t *
2199 dladm_name2prop(const char *prop_name)
2200 {
2201 	link_attr_t *p;
2202 
2203 	for (p = link_attr; p->pp_id != MAC_PROP_PRIVATE; p++) {
2204 		if (strcmp(p->pp_name, prop_name) == 0)
2205 			break;
2206 	}
2207 	return (p);
2208 }
2209 
2210 static link_attr_t *
2211 dladm_id2prop(mac_prop_id_t propid)
2212 {
2213 	link_attr_t *p;
2214 
2215 	for (p = link_attr; p->pp_id != MAC_PROP_PRIVATE; p++) {
2216 		if (p->pp_id == propid)
2217 			break;
2218 	}
2219 	return (p);
2220 }
2221 
2222 static dld_ioc_macprop_t *
2223 i_dladm_buf_alloc_impl(size_t valsize, datalink_id_t linkid,
2224     const char *prop_name, mac_prop_id_t propid, uint_t flags,
2225     dladm_status_t *status)
2226 {
2227 	int dsize;
2228 	dld_ioc_macprop_t *dip;
2229 
2230 	*status = DLADM_STATUS_OK;
2231 	dsize = MAC_PROP_BUFSIZE(valsize);
2232 	dip = malloc(dsize);
2233 	if (dip == NULL) {
2234 		*status = DLADM_STATUS_NOMEM;
2235 		return (NULL);
2236 	}
2237 	bzero(dip, dsize);
2238 	dip->pr_valsize = valsize;
2239 	(void) strlcpy(dip->pr_name, prop_name, sizeof (dip->pr_name));
2240 	dip->pr_version = MAC_PROP_VERSION;
2241 	dip->pr_linkid = linkid;
2242 	dip->pr_num = propid;
2243 	dip->pr_flags = flags;
2244 	return (dip);
2245 }
2246 
2247 static dld_ioc_macprop_t *
2248 i_dladm_buf_alloc_by_name(size_t valsize, datalink_id_t linkid,
2249     const char *prop_name, uint_t flags, dladm_status_t *status)
2250 {
2251 	link_attr_t *p;
2252 
2253 	p = dladm_name2prop(prop_name);
2254 	valsize = MAX(p->pp_valsize, valsize);
2255 	return (i_dladm_buf_alloc_impl(valsize, linkid, prop_name, p->pp_id,
2256 	    flags, status));
2257 }
2258 
2259 static dld_ioc_macprop_t *
2260 i_dladm_buf_alloc_by_id(size_t valsize, datalink_id_t linkid,
2261     mac_prop_id_t propid, uint_t flags, dladm_status_t *status)
2262 {
2263 	link_attr_t *p;
2264 
2265 	p = dladm_id2prop(propid);
2266 	valsize = MAX(p->pp_valsize, valsize);
2267 	return (i_dladm_buf_alloc_impl(valsize, linkid, p->pp_name, propid,
2268 	    flags, status));
2269 }
2270 
2271 /* ARGSUSED */
2272 static dladm_status_t
2273 i_dladm_set_public_prop(dladm_handle_t handle, prop_desc_t *pdp,
2274     datalink_id_t linkid, val_desc_t *vdp, uint_t val_cnt, uint_t flags,
2275     datalink_media_t media)
2276 {
2277 	dld_ioc_macprop_t	*dip;
2278 	dladm_status_t	status = DLADM_STATUS_OK;
2279 	uint8_t		u8;
2280 	uint16_t	u16;
2281 	uint32_t	u32;
2282 	void		*val;
2283 
2284 	dip = i_dladm_buf_alloc_by_name(0, linkid, pdp->pd_name, 0, &status);
2285 	if (dip == NULL)
2286 		return (status);
2287 
2288 	if (pdp->pd_flags & PD_CHECK_ALLOC)
2289 		val = (void *)vdp->vd_val;
2290 	else {
2291 		/*
2292 		 * Currently all 1/2/4-byte size properties are byte/word/int.
2293 		 * No need (yet) to distinguish these from arrays of same size.
2294 		 */
2295 		switch (dip->pr_valsize) {
2296 		case 1:
2297 			u8 = vdp->vd_val;
2298 			val = &u8;
2299 			break;
2300 		case 2:
2301 			u16 = vdp->vd_val;
2302 			val = &u16;
2303 			break;
2304 		case 4:
2305 			u32 = vdp->vd_val;
2306 			val = &u32;
2307 			break;
2308 		default:
2309 			val = &vdp->vd_val;
2310 			break;
2311 		}
2312 	}
2313 
2314 	if (val != NULL)
2315 		(void) memcpy(dip->pr_val, val, dip->pr_valsize);
2316 	else
2317 		dip->pr_valsize = 0;
2318 
2319 	status = i_dladm_macprop(handle, dip, B_TRUE);
2320 
2321 done:
2322 	free(dip);
2323 	return (status);
2324 }
2325 
2326 dladm_status_t
2327 i_dladm_macprop(dladm_handle_t handle, void *dip, boolean_t set)
2328 {
2329 	dladm_status_t status = DLADM_STATUS_OK;
2330 
2331 	if (ioctl(dladm_dld_fd(handle),
2332 	    (set ? DLDIOC_SETMACPROP : DLDIOC_GETMACPROP), dip))
2333 		status = dladm_errno2status(errno);
2334 
2335 	return (status);
2336 }
2337 
2338 static dld_ioc_macprop_t *
2339 i_dladm_get_public_prop(dladm_handle_t handle, datalink_id_t linkid,
2340     char *prop_name, uint_t flags, dladm_status_t *status, uint_t *perm_flags)
2341 {
2342 	dld_ioc_macprop_t *dip = NULL;
2343 
2344 	dip = i_dladm_buf_alloc_by_name(0, linkid, prop_name, flags, status);
2345 	if (dip == NULL)
2346 		return (NULL);
2347 
2348 	*status = i_dladm_macprop(handle, dip, B_FALSE);
2349 	if (*status != DLADM_STATUS_OK) {
2350 		free(dip);
2351 		return (NULL);
2352 	}
2353 	if (perm_flags != NULL)
2354 		*perm_flags = dip->pr_perm_flags;
2355 
2356 	return (dip);
2357 }
2358 
2359 /* ARGSUSED */
2360 static dladm_status_t
2361 i_dladm_defmtu_check(dladm_handle_t handle, prop_desc_t *pdp,
2362     datalink_id_t linkid, char **prop_val, uint_t val_cnt, val_desc_t *v,
2363     datalink_media_t media)
2364 {
2365 	if (val_cnt != 1)
2366 		return (DLADM_STATUS_BADVAL);
2367 	v->vd_val = atoi(prop_val[0]);
2368 	return (DLADM_STATUS_OK);
2369 }
2370 
2371 /* ARGSUSED */
2372 static dladm_status_t
2373 i_dladm_duplex_get(dladm_handle_t handle, prop_desc_t *pdp,
2374     datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
2375     datalink_media_t media, uint_t flags, uint_t *perm_flags)
2376 {
2377 	link_duplex_t   link_duplex;
2378 	dladm_status_t  status;
2379 
2380 	if ((status = dladm_get_single_mac_stat(handle, linkid, "link_duplex",
2381 	    KSTAT_DATA_UINT32, &link_duplex)) != 0)
2382 		return (status);
2383 
2384 	switch (link_duplex) {
2385 	case LINK_DUPLEX_FULL:
2386 		(void) strcpy(*prop_val, "full");
2387 		break;
2388 	case LINK_DUPLEX_HALF:
2389 		(void) strcpy(*prop_val, "half");
2390 		break;
2391 	default:
2392 		(void) strcpy(*prop_val, "unknown");
2393 		break;
2394 	}
2395 	*val_cnt = 1;
2396 	return (DLADM_STATUS_OK);
2397 }
2398 
2399 /* ARGSUSED */
2400 static dladm_status_t
2401 i_dladm_speed_get(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
2402     char **prop_val, uint_t *val_cnt, uint_t flags, uint_t *perm_flags)
2403 {
2404 	uint64_t	ifspeed = 0;
2405 	dladm_status_t status;
2406 
2407 	if ((status = dladm_get_single_mac_stat(handle, linkid, "ifspeed",
2408 	    KSTAT_DATA_UINT64, &ifspeed)) != 0)
2409 		return (status);
2410 
2411 	if ((ifspeed % 1000000) != 0) {
2412 		(void) snprintf(*prop_val, DLADM_PROP_VAL_MAX,
2413 		    "%llf", ifspeed / (float)1000000); /* Mbps */
2414 	} else {
2415 		(void) snprintf(*prop_val, DLADM_PROP_VAL_MAX,
2416 		    "%llu", ifspeed / 1000000); /* Mbps */
2417 	}
2418 	*val_cnt = 1;
2419 	*perm_flags = MAC_PROP_PERM_READ;
2420 	return (DLADM_STATUS_OK);
2421 }
2422 
2423 /* ARGSUSED */
2424 static dladm_status_t
2425 i_dladm_status_get(dladm_handle_t handle, prop_desc_t *pdp,
2426     datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
2427     datalink_media_t media, uint_t flags, uint_t *perm_flags)
2428 {
2429 	link_state_t		link_state;
2430 	dladm_status_t		status;
2431 
2432 	status = i_dladm_get_state(handle, linkid, &link_state);
2433 	if (status != DLADM_STATUS_OK)
2434 		return (status);
2435 
2436 	switch (link_state) {
2437 	case LINK_STATE_UP:
2438 		(void) strcpy(*prop_val, "up");
2439 		break;
2440 	case LINK_STATE_DOWN:
2441 		(void) strcpy(*prop_val, "down");
2442 		break;
2443 	default:
2444 		(void) strcpy(*prop_val, "unknown");
2445 		break;
2446 	}
2447 	*val_cnt = 1;
2448 	*perm_flags = MAC_PROP_PERM_READ;
2449 	return (DLADM_STATUS_OK);
2450 }
2451 
2452 /* ARGSUSED */
2453 static dladm_status_t
2454 i_dladm_binary_get(dladm_handle_t handle, prop_desc_t *pdp,
2455     datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
2456     datalink_media_t media, uint_t flags, uint_t *perm_flags)
2457 {
2458 	dld_ioc_macprop_t *dip;
2459 	dladm_status_t status;
2460 
2461 	dip = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags,
2462 	    &status, perm_flags);
2463 	if (dip == NULL)
2464 		return (status);
2465 
2466 	(void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "%x", dip->pr_val[0]);
2467 	free(dip);
2468 	*val_cnt = 1;
2469 	return (DLADM_STATUS_OK);
2470 }
2471 
2472 /* ARGSUSED */
2473 static dladm_status_t
2474 i_dladm_uint32_get(dladm_handle_t handle, prop_desc_t *pdp,
2475     datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
2476     datalink_media_t media, uint_t flags, uint_t *perm_flags)
2477 {
2478 	dld_ioc_macprop_t *dip;
2479 	uint32_t v = 0;
2480 	uchar_t *cp;
2481 	dladm_status_t status;
2482 
2483 	dip = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags,
2484 	    &status, perm_flags);
2485 	if (dip == NULL)
2486 		return (status);
2487 
2488 	cp = (uchar_t *)dip->pr_val;
2489 	(void) memcpy(&v, cp, sizeof (v));
2490 	(void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "%ld", v);
2491 	free(dip);
2492 	*val_cnt = 1;
2493 	return (DLADM_STATUS_OK);
2494 }
2495 
2496 /* ARGSUSED */
2497 static dladm_status_t
2498 i_dladm_flowctl_get(dladm_handle_t handle, prop_desc_t *pdp,
2499     datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
2500     datalink_media_t media, uint_t flags, uint_t *perm_flags)
2501 {
2502 	dld_ioc_macprop_t *dip;
2503 	link_flowctrl_t v;
2504 	dladm_status_t status;
2505 	uchar_t *cp;
2506 
2507 	dip = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags,
2508 	    &status, perm_flags);
2509 	if (dip == NULL)
2510 		return (status);
2511 
2512 	cp = (uchar_t *)dip->pr_val;
2513 	(void) memcpy(&v, cp, sizeof (v));
2514 	switch (v) {
2515 	case LINK_FLOWCTRL_NONE:
2516 		(void) sprintf(*prop_val, "no");
2517 		break;
2518 	case LINK_FLOWCTRL_RX:
2519 		(void) sprintf(*prop_val, "rx");
2520 		break;
2521 	case LINK_FLOWCTRL_TX:
2522 		(void) sprintf(*prop_val, "tx");
2523 		break;
2524 	case LINK_FLOWCTRL_BI:
2525 		(void) sprintf(*prop_val, "bi");
2526 		break;
2527 	}
2528 	free(dip);
2529 	*val_cnt = 1;
2530 	return (DLADM_STATUS_OK);
2531 }
2532 
2533 
2534 /* ARGSUSED */
2535 static dladm_status_t
2536 i_dladm_set_prop(dladm_handle_t handle, datalink_id_t linkid,
2537     const char *prop_name, char **prop_val, uint_t val_cnt, uint_t flags)
2538 
2539 {
2540 	int		i, slen;
2541 	int 		bufsize = 0;
2542 	dld_ioc_macprop_t *dip = NULL;
2543 	uchar_t 	*dp;
2544 	link_attr_t *p;
2545 	dladm_status_t	status = DLADM_STATUS_OK;
2546 
2547 	if ((prop_name == NULL && prop_val != NULL) ||
2548 	    (prop_val != NULL && val_cnt == 0))
2549 		return (DLADM_STATUS_BADARG);
2550 	p = dladm_name2prop(prop_name);
2551 	if (p->pp_id != MAC_PROP_PRIVATE)
2552 		return (DLADM_STATUS_BADARG);
2553 
2554 	/*
2555 	 * private properties: all parsing is done in the kernel.
2556 	 * allocate a enough space for each property + its separator (',').
2557 	 */
2558 	for (i = 0; i < val_cnt; i++) {
2559 		bufsize += strlen(prop_val[i]) + 1;
2560 	}
2561 
2562 	if (prop_val == NULL) {
2563 		/*
2564 		 * getting default value. so use more buffer space.
2565 		 */
2566 		bufsize += DLADM_PROP_BUF_CHUNK;
2567 	}
2568 
2569 	dip = i_dladm_buf_alloc_by_name(bufsize + 1, linkid, prop_name,
2570 	    (prop_val != NULL ? 0 : MAC_PROP_DEFAULT), &status);
2571 	if (dip == NULL)
2572 		return (status);
2573 
2574 	dp = (uchar_t *)dip->pr_val;
2575 	slen = 0;
2576 
2577 	if (prop_val == NULL) {
2578 		status = i_dladm_macprop(handle, dip, B_FALSE);
2579 		dip->pr_flags = 0;
2580 	} else {
2581 		for (i = 0; i < val_cnt; i++) {
2582 			int plen = 0;
2583 
2584 			plen = strlen(prop_val[i]);
2585 			bcopy(prop_val[i], dp, plen);
2586 			slen += plen;
2587 			/*
2588 			 * add a "," separator and update dp.
2589 			 */
2590 			if (i != (val_cnt -1))
2591 				dp[slen++] = ',';
2592 			dp += (plen + 1);
2593 		}
2594 	}
2595 	if (status == DLADM_STATUS_OK)
2596 		status = i_dladm_macprop(handle, dip, B_TRUE);
2597 
2598 	free(dip);
2599 	return (status);
2600 }
2601 
2602 static dladm_status_t
2603 i_dladm_get_priv_prop(dladm_handle_t handle, datalink_id_t linkid,
2604     const char *prop_name, char **prop_val, uint_t *val_cnt,
2605     dladm_prop_type_t type, uint_t dld_flags)
2606 {
2607 	dladm_status_t	status = DLADM_STATUS_OK;
2608 	dld_ioc_macprop_t *dip = NULL;
2609 	link_attr_t *p;
2610 
2611 	if ((prop_name == NULL && prop_val != NULL) ||
2612 	    (prop_val != NULL && val_cnt == 0))
2613 		return (DLADM_STATUS_BADARG);
2614 
2615 	p = dladm_name2prop(prop_name);
2616 	if (p->pp_id != MAC_PROP_PRIVATE)
2617 		return (DLADM_STATUS_BADARG);
2618 
2619 	/*
2620 	 * private properties: all parsing is done in the kernel.
2621 	 */
2622 	dip = i_dladm_buf_alloc_by_name(DLADM_PROP_BUF_CHUNK, linkid, prop_name,
2623 	    dld_flags, &status);
2624 	if (dip == NULL)
2625 		return (status);
2626 
2627 	if ((status = i_dladm_macprop(handle, dip, B_FALSE)) ==
2628 	    DLADM_STATUS_OK) {
2629 		if (type == DLADM_PROP_VAL_PERM) {
2630 			(void) dladm_perm2str(dip->pr_perm_flags, *prop_val);
2631 		} else if (type == DLADM_PROP_VAL_MODIFIABLE) {
2632 			*prop_val[0] = '\0';
2633 		} else {
2634 			(void) strncpy(*prop_val, dip->pr_val,
2635 			    DLADM_PROP_VAL_MAX);
2636 		}
2637 		*val_cnt = 1;
2638 	} else if ((status == DLADM_STATUS_NOTSUP) &&
2639 	    (type == DLADM_PROP_VAL_CURRENT)) {
2640 		status = DLADM_STATUS_NOTFOUND;
2641 	}
2642 	free(dip);
2643 	return (status);
2644 }
2645 
2646 
2647 static dladm_status_t
2648 i_dladm_getset_defval(dladm_handle_t handle, prop_desc_t *pdp,
2649     datalink_id_t linkid, datalink_media_t media, uint_t flags)
2650 {
2651 	dladm_status_t status;
2652 	char **prop_vals = NULL, *buf;
2653 	size_t bufsize;
2654 	uint_t cnt;
2655 	int i;
2656 	uint_t perm_flags;
2657 
2658 	/*
2659 	 * Allocate buffer needed for prop_vals array. We can have at most
2660 	 * DLADM_MAX_PROP_VALCNT char *prop_vals[] entries, where
2661 	 * each entry has max size DLADM_PROP_VAL_MAX
2662 	 */
2663 	bufsize =
2664 	    (sizeof (char *) + DLADM_PROP_VAL_MAX) * DLADM_MAX_PROP_VALCNT;
2665 	buf = malloc(bufsize);
2666 	prop_vals = (char **)(void *)buf;
2667 	for (i = 0; i < DLADM_MAX_PROP_VALCNT; i++) {
2668 		prop_vals[i] = buf +
2669 		    sizeof (char *) * DLADM_MAX_PROP_VALCNT +
2670 		    i * DLADM_PROP_VAL_MAX;
2671 	}
2672 
2673 	/*
2674 	 * For properties which have pdp->pd_defval.vd_name as a non-empty
2675 	 * string, the "" itself is used to reset the property (exceptions
2676 	 * are zone and autopush, which populate vdp->vd_val). So
2677 	 * libdladm can copy pdp->pd_defval over to the val_desc_t passed
2678 	 * down on the setprop using the global values in the table. For
2679 	 * other cases (vd_name is ""), doing reset-linkprop will cause
2680 	 * libdladm to do a getprop to find the default value and then do
2681 	 * a setprop to reset the value to default.
2682 	 */
2683 	status = pdp->pd_get(handle, pdp, linkid, prop_vals, &cnt, media,
2684 	    MAC_PROP_DEFAULT, &perm_flags);
2685 	if (status == DLADM_STATUS_OK) {
2686 		if (perm_flags == MAC_PROP_PERM_RW) {
2687 			status = i_dladm_set_single_prop(handle, linkid,
2688 			    pdp->pd_class, media, pdp, prop_vals, cnt, flags);
2689 		}
2690 		else
2691 			status = DLADM_STATUS_NOTSUP;
2692 	}
2693 	free(buf);
2694 	return (status);
2695 }
2696 
2697 int
2698 macprop_to_wifi(mac_prop_id_t wl_prop)
2699 {
2700 	switch (wl_prop) {
2701 	case MAC_PROP_WL_ESSID:
2702 		return (WL_ESSID);
2703 	case MAC_PROP_WL_BSSID:
2704 		return (WL_BSSID);
2705 	case MAC_PROP_WL_BSSTYPE:
2706 		return (WL_BSS_TYPE);
2707 	case MAC_PROP_WL_LINKSTATUS:
2708 		return (WL_LINKSTATUS);
2709 	case MAC_PROP_WL_DESIRED_RATES:
2710 		return (WL_DESIRED_RATES);
2711 	case MAC_PROP_WL_SUPPORTED_RATES:
2712 		return (WL_SUPPORTED_RATES);
2713 	case MAC_PROP_WL_AUTH_MODE:
2714 		return (WL_AUTH_MODE);
2715 	case MAC_PROP_WL_ENCRYPTION:
2716 		return (WL_ENCRYPTION);
2717 	case MAC_PROP_WL_RSSI:
2718 		return (WL_RSSI);
2719 	case MAC_PROP_WL_PHY_CONFIG:
2720 		return (WL_PHY_CONFIG);
2721 	case MAC_PROP_WL_CAPABILITY:
2722 		return (WL_CAPABILITY);
2723 	case MAC_PROP_WL_WPA:
2724 		return (WL_WPA);
2725 	case MAC_PROP_WL_SCANRESULTS:
2726 		return (WL_SCANRESULTS);
2727 	case MAC_PROP_WL_POWER_MODE:
2728 		return (WL_POWER_MODE);
2729 	case MAC_PROP_WL_RADIO:
2730 		return (WL_RADIO);
2731 	case MAC_PROP_WL_ESS_LIST:
2732 		return (WL_ESS_LIST);
2733 	case MAC_PROP_WL_KEY_TAB:
2734 		return (WL_WEP_KEY_TAB);
2735 	case MAC_PROP_WL_CREATE_IBSS:
2736 		return (WL_CREATE_IBSS);
2737 	case MAC_PROP_WL_SETOPTIE:
2738 		return (WL_SETOPTIE);
2739 	case MAC_PROP_WL_DELKEY:
2740 		return (WL_DELKEY);
2741 	case MAC_PROP_WL_KEY:
2742 		return (WL_KEY);
2743 	case MAC_PROP_WL_MLME:
2744 		return (WL_MLME);
2745 	default:
2746 		return (-1);
2747 	}
2748 }
2749 
2750 dladm_status_t
2751 i_dladm_wlan_param(dladm_handle_t handle, datalink_id_t linkid, void *buf,
2752     mac_prop_id_t cmd, size_t len, boolean_t set)
2753 {
2754 	uint32_t		flags;
2755 	dladm_status_t		status;
2756 	uint32_t		media;
2757 	dld_ioc_macprop_t	*dip;
2758 	void			*dp;
2759 
2760 	if ((status = dladm_datalink_id2info(handle, linkid, &flags, NULL,
2761 	    &media, NULL, 0)) != DLADM_STATUS_OK) {
2762 		return (status);
2763 	}
2764 
2765 	if (media != DL_WIFI)
2766 		return (DLADM_STATUS_BADARG);
2767 
2768 	if (!(flags & DLADM_OPT_ACTIVE))
2769 		return (DLADM_STATUS_TEMPONLY);
2770 
2771 	if (len == (MAX_BUF_LEN - WIFI_BUF_OFFSET))
2772 		len = MAX_BUF_LEN - sizeof (dld_ioc_macprop_t) - 1;
2773 
2774 	dip = i_dladm_buf_alloc_by_id(len, linkid, cmd, 0, &status);
2775 	if (dip == NULL)
2776 		return (DLADM_STATUS_NOMEM);
2777 
2778 	dp = (uchar_t *)dip->pr_val;
2779 	if (set)
2780 		(void) memcpy(dp, buf, len);
2781 
2782 	status = i_dladm_macprop(handle, dip, set);
2783 	if (status == DLADM_STATUS_NOTSUP) {
2784 		if (set) {
2785 			status = i_dladm_wlan_set_legacy_ioctl(handle, linkid,
2786 			    buf, len, macprop_to_wifi(cmd));
2787 		} else {
2788 			status = i_dladm_wlan_get_legacy_ioctl(handle, linkid,
2789 			    buf, len, macprop_to_wifi(cmd));
2790 		}
2791 	} else if (status == DLADM_STATUS_OK) {
2792 		if (!set)
2793 			(void) memcpy(buf, dp, len);
2794 	}
2795 
2796 	free(dip);
2797 	return (status);
2798 }
2799 
2800 static dladm_status_t
2801 i_dladm_wlan_get_legacy_ioctl(dladm_handle_t handle, datalink_id_t linkid,
2802     void *buf, uint_t buflen, uint_t id)
2803 {
2804 	wldp_t *gbuf;
2805 	dladm_status_t status;
2806 
2807 	if ((gbuf = malloc(MAX_BUF_LEN)) == NULL)
2808 		return (DLADM_STATUS_NOMEM);
2809 
2810 	(void) memset(gbuf, 0, MAX_BUF_LEN);
2811 	status = i_dladm_wlan_legacy_ioctl(handle, linkid, gbuf, id,
2812 	    MAX_BUF_LEN, WLAN_GET_PARAM, sizeof (wldp_t));
2813 	if (status == DLADM_STATUS_OK)
2814 		(void) memcpy(buf, gbuf->wldp_buf, buflen);
2815 
2816 	free(gbuf);
2817 	return (status);
2818 }
2819 
2820 static dladm_status_t
2821 i_dladm_wlan_set_legacy_ioctl(dladm_handle_t handle, datalink_id_t linkid,
2822     void *buf, uint_t buflen, uint_t id)
2823 {
2824 	wldp_t *gbuf;
2825 	dladm_status_t status = DLADM_STATUS_OK;
2826 
2827 	if ((gbuf = malloc(MAX_BUF_LEN)) == NULL)
2828 		return (DLADM_STATUS_NOMEM);
2829 
2830 	(void) memset(gbuf, 0, MAX_BUF_LEN);
2831 	(void) memcpy(gbuf->wldp_buf, buf, buflen);
2832 	buflen += WIFI_BUF_OFFSET;
2833 	status = i_dladm_wlan_legacy_ioctl(handle, linkid, gbuf, id, buflen,
2834 	    WLAN_SET_PARAM, buflen);
2835 
2836 	free(gbuf);
2837 	return (status);
2838 }
2839 
2840 dladm_status_t
2841 dladm_parse_link_props(char *str, dladm_arg_list_t **listp, boolean_t novalues)
2842 {
2843 	return (dladm_parse_args(str, listp, novalues));
2844 }
2845 
2846 /*
2847  * Retrieve the one link property from the database
2848  */
2849 /*ARGSUSED*/
2850 static int
2851 i_dladm_get_one_prop(dladm_handle_t handle, datalink_id_t linkid,
2852     const char *prop_name, void *arg)
2853 {
2854 	dladm_arg_list_t	*proplist = arg;
2855 	dladm_arg_info_t	*aip = NULL;
2856 
2857 	aip = &proplist->al_info[proplist->al_count];
2858 	/*
2859 	 * it is fine to point to prop_name since prop_name points to the
2860 	 * prop_table[n].pd_name.
2861 	 */
2862 	aip->ai_name = prop_name;
2863 
2864 	(void) dladm_get_linkprop(handle, linkid, DLADM_PROP_VAL_PERSISTENT,
2865 	    prop_name, aip->ai_val, &aip->ai_count);
2866 
2867 	if (aip->ai_count != 0)
2868 		proplist->al_count++;
2869 
2870 	return (DLADM_WALK_CONTINUE);
2871 }
2872 
2873 
2874 /*
2875  * Retrieve all link properties for a link from the database and
2876  * return a property list.
2877  */
2878 dladm_status_t
2879 dladm_link_get_proplist(dladm_handle_t handle, datalink_id_t linkid,
2880     dladm_arg_list_t **listp)
2881 {
2882 	dladm_arg_list_t	*list;
2883 	dladm_status_t		status = DLADM_STATUS_OK;
2884 
2885 	list = calloc(1, sizeof (dladm_arg_list_t));
2886 	if (list == NULL)
2887 		return (dladm_errno2status(errno));
2888 
2889 	status = dladm_walk_linkprop(handle, linkid, list,
2890 	    i_dladm_get_one_prop);
2891 
2892 	*listp = list;
2893 	return (status);
2894 }
2895 
2896 /*
2897  * Retrieve the named property from a proplist, check the value and
2898  * convert to a kernel structure.
2899  */
2900 static dladm_status_t
2901 i_dladm_link_proplist_extract_one(dladm_handle_t handle,
2902     dladm_arg_list_t *proplist, const char *name, void *val)
2903 {
2904 	dladm_status_t		status;
2905 	dladm_arg_info_t	*aip = NULL;
2906 	int			i, j;
2907 
2908 	/* Find named property in proplist */
2909 	for (i = 0; i < proplist->al_count; i++) {
2910 		aip = &proplist->al_info[i];
2911 		if (strcasecmp(aip->ai_name, name) == 0)
2912 			break;
2913 	}
2914 
2915 	/* Property not in list */
2916 	if (i == proplist->al_count)
2917 		return (DLADM_STATUS_OK);
2918 
2919 	for (i = 0; i < DLADM_MAX_PROPS; i++) {
2920 		prop_desc_t	*pdp = &prop_table[i];
2921 		val_desc_t	*vdp;
2922 
2923 		vdp = malloc(sizeof (val_desc_t) * aip->ai_count);
2924 		if (vdp == NULL)
2925 			return (DLADM_STATUS_NOMEM);
2926 
2927 		if (strcasecmp(aip->ai_name, pdp->pd_name) != 0)
2928 			continue;
2929 
2930 		if (aip->ai_val == NULL)
2931 			return (DLADM_STATUS_BADARG);
2932 
2933 		/* Check property value */
2934 		if (pdp->pd_check != NULL) {
2935 			status = pdp->pd_check(handle, pdp, 0, aip->ai_val,
2936 			    aip->ai_count, vdp, 0);
2937 		} else {
2938 			status = DLADM_STATUS_BADARG;
2939 		}
2940 
2941 		if (status != DLADM_STATUS_OK)
2942 			return (status);
2943 
2944 		for (j = 0; j < DLADM_MAX_RSRC_PROP; j++) {
2945 			resource_prop_t	*rpp = &rsrc_prop_table[j];
2946 
2947 			if (strcasecmp(aip->ai_name, rpp->rp_name) != 0)
2948 				continue;
2949 
2950 			/* Extract kernel structure */
2951 			if (rpp->rp_extract != NULL) {
2952 				status = rpp->rp_extract(vdp, val,
2953 				    aip->ai_count);
2954 			} else {
2955 				status = DLADM_STATUS_BADARG;
2956 			}
2957 			break;
2958 		}
2959 
2960 		if (status != DLADM_STATUS_OK)
2961 			return (status);
2962 
2963 		break;
2964 	}
2965 	return (status);
2966 }
2967 
2968 /*
2969  * Extract properties from a proplist and convert to mac_resource_props_t.
2970  */
2971 dladm_status_t
2972 dladm_link_proplist_extract(dladm_handle_t handle, dladm_arg_list_t *proplist,
2973     mac_resource_props_t *mrp)
2974 {
2975 	dladm_status_t	status = DLADM_STATUS_OK;
2976 
2977 	status = i_dladm_link_proplist_extract_one(handle, proplist, "maxbw",
2978 	    mrp);
2979 	if (status != DLADM_STATUS_OK)
2980 		return (status);
2981 	status = i_dladm_link_proplist_extract_one(handle, proplist, "priority",
2982 	    mrp);
2983 	if (status != DLADM_STATUS_OK)
2984 		return (status);
2985 	status = i_dladm_link_proplist_extract_one(handle, proplist, "cpus",
2986 	    mrp);
2987 	if (status != DLADM_STATUS_OK)
2988 		return (status);
2989 	return (status);
2990 }
2991 
2992 static const char *
2993 dladm_perm2str(uint_t perm, char *buf)
2994 {
2995 	(void) snprintf(buf, DLADM_STRSIZE, "%c%c",
2996 	    ((perm & MAC_PROP_PERM_READ) != 0) ? 'r' : '-',
2997 	    ((perm & MAC_PROP_PERM_WRITE) != 0) ? 'w' : '-');
2998 	return (buf);
2999 }
3000 
3001 dladm_status_t
3002 i_dladm_get_state(dladm_handle_t handle, datalink_id_t linkid,
3003     link_state_t *state)
3004 {
3005 	dld_ioc_macprop_t	*dip;
3006 	dladm_status_t		status;
3007 	uint_t			perms;
3008 
3009 	dip = i_dladm_get_public_prop(handle, linkid, "state", 0, &status,
3010 	    &perms);
3011 	if (status != DLADM_STATUS_OK)
3012 		return (status);
3013 	(void) memcpy(state, dip->pr_val, sizeof (*state));
3014 	free(dip);
3015 	return (status);
3016 }
3017 
3018 boolean_t
3019 dladm_attr_is_linkprop(const char *name)
3020 {
3021 	/* non-property attribute names */
3022 	const char *nonprop[] = {
3023 		/* dlmgmtd core attributes */
3024 		"name",
3025 		"class",
3026 		"media",
3027 		FPHYMAJ,
3028 		FPHYINST,
3029 		FDEVNAME,
3030 
3031 		/* other attributes for vlan, aggr, etc */
3032 		DLADM_ATTR_NAMES
3033 	};
3034 	boolean_t	is_nonprop = B_FALSE;
3035 	int		i;
3036 
3037 	for (i = 0; i < sizeof (nonprop) / sizeof (nonprop[0]); i++) {
3038 		if (strcmp(name, nonprop[i]) == 0) {
3039 			is_nonprop = B_TRUE;
3040 			break;
3041 		}
3042 	}
3043 
3044 	return (!is_nonprop);
3045 }
3046