xref: /titanic_51/usr/src/lib/libdladm/common/linkprop.c (revision 5c066ec28ea93f3a7c93082611a61747f255290a)
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_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, dld_maxbw_get, dld_cpus_get,
135 			dld_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 	    dld_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 	    dld_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 	    dld_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_set_single_prop(dladm_handle_t, datalink_id_t,
518 			    datalink_class_t, uint32_t, prop_desc_t *, char **,
519 			    uint_t, uint_t);
520 static dladm_status_t	i_dladm_set_linkprop(dladm_handle_t, datalink_id_t,
521 			    const char *, char **, uint_t, uint_t);
522 static dladm_status_t	i_dladm_getset_defval(dladm_handle_t, prop_desc_t *,
523 			    datalink_id_t, datalink_media_t, uint_t);
524 
525 static dladm_status_t	link_proplist_check(dladm_arg_list_t *);
526 
527 /*
528  * Unfortunately, MAX_SCAN_SUPPORT_RATES is too small to allow all
529  * rates to be retrieved. However, we cannot increase it at this
530  * time because it will break binary compatibility with unbundled
531  * WiFi drivers and utilities. So for now we define an additional
532  * constant, MAX_SUPPORT_RATES, to allow all rates to be retrieved.
533  */
534 #define	MAX_SUPPORT_RATES	64
535 
536 #define	AP_ANCHOR	"[anchor]"
537 #define	AP_DELIMITER	'.'
538 
539 static dladm_status_t
540 do_check_prop(prop_desc_t *pdp, char **prop_val, uint_t val_cnt,
541     val_desc_t *vdp)
542 {
543 	int		i, j;
544 	dladm_status_t	status = DLADM_STATUS_OK;
545 
546 	for (j = 0; j < val_cnt; j++) {
547 		for (i = 0; i < pdp->pd_noptval; i++) {
548 			if (strcasecmp(*prop_val,
549 			    pdp->pd_optval[i].vd_name) == 0) {
550 				break;
551 			}
552 		}
553 		if (i == pdp->pd_noptval) {
554 			status = DLADM_STATUS_BADVAL;
555 			goto done;
556 		}
557 		(void) memcpy(vdp + j, &pdp->pd_optval[i], sizeof (val_desc_t));
558 	}
559 
560 done:
561 	return (status);
562 }
563 
564 static dladm_status_t
565 i_dladm_set_single_prop(dladm_handle_t handle, datalink_id_t linkid,
566     datalink_class_t class, uint32_t media, prop_desc_t *pdp, char **prop_val,
567     uint_t val_cnt, uint_t flags)
568 {
569 	dladm_status_t	status = DLADM_STATUS_OK;
570 	val_desc_t	*vdp = NULL;
571 	boolean_t	needfree = B_FALSE;
572 	uint_t		cnt, i;
573 
574 	if (!(pdp->pd_class & class))
575 		return (DLADM_STATUS_BADARG);
576 
577 	if (!DATALINK_MEDIA_ACCEPTED(pdp->pd_dmedia, media))
578 		return (DLADM_STATUS_BADARG);
579 
580 	if ((flags & DLADM_OPT_PERSIST) && (pdp->pd_flags & PD_TEMPONLY))
581 		return (DLADM_STATUS_TEMPONLY);
582 
583 	if (!(flags & DLADM_OPT_ACTIVE))
584 		return (DLADM_STATUS_OK);
585 
586 	if (pdp->pd_set == NULL)
587 		return (DLADM_STATUS_PROPRDONLY);
588 
589 	if (prop_val != NULL) {
590 		vdp = malloc(sizeof (val_desc_t) * val_cnt);
591 		if (vdp == NULL)
592 			return (DLADM_STATUS_NOMEM);
593 
594 		if (pdp->pd_check != NULL) {
595 			needfree = ((pdp->pd_flags & PD_CHECK_ALLOC) != 0);
596 			status = pdp->pd_check(handle, pdp, linkid, prop_val,
597 			    val_cnt, vdp, media);
598 		} else if (pdp->pd_optval != NULL) {
599 			status = do_check_prop(pdp, prop_val, val_cnt, vdp);
600 		} else {
601 			status = DLADM_STATUS_BADARG;
602 		}
603 
604 		if (status != DLADM_STATUS_OK)
605 			goto done;
606 
607 		cnt = val_cnt;
608 	} else {
609 		boolean_t	defval = B_FALSE;
610 
611 		if (pdp->pd_defval.vd_name == NULL)
612 			return (DLADM_STATUS_NOTSUP);
613 
614 		cnt = 1;
615 		defval = (strlen(pdp->pd_defval.vd_name) > 0);
616 		if ((pdp->pd_flags & PD_CHECK_ALLOC) != 0 || defval) {
617 			if ((vdp = malloc(sizeof (val_desc_t))) == NULL)
618 				return (DLADM_STATUS_NOMEM);
619 
620 			if (defval) {
621 				(void) memcpy(vdp, &pdp->pd_defval,
622 				    sizeof (val_desc_t));
623 			} else if (pdp->pd_check != NULL) {
624 				status = pdp->pd_check(handle, pdp, linkid,
625 				    prop_val, cnt, vdp, media);
626 				if (status != DLADM_STATUS_OK)
627 					goto done;
628 			}
629 		} else {
630 			status = i_dladm_getset_defval(handle, pdp, linkid,
631 			    media, flags);
632 			return (status);
633 		}
634 	}
635 	status = pdp->pd_set(handle, pdp, linkid, vdp, cnt, flags, media);
636 	if (needfree) {
637 		for (i = 0; i < cnt; i++)
638 			free((void *)((val_desc_t *)vdp + i)->vd_val);
639 	}
640 done:
641 	free(vdp);
642 	return (status);
643 }
644 
645 static dladm_status_t
646 i_dladm_set_linkprop(dladm_handle_t handle, datalink_id_t linkid,
647     const char *prop_name, char **prop_val, uint_t val_cnt, uint_t flags)
648 {
649 	int			i;
650 	boolean_t		found = B_FALSE;
651 	datalink_class_t	class;
652 	uint32_t		media;
653 	dladm_status_t		status = DLADM_STATUS_OK;
654 
655 	status = dladm_datalink_id2info(handle, linkid, NULL, &class, &media,
656 	    NULL, 0);
657 	if (status != DLADM_STATUS_OK)
658 		return (status);
659 
660 	for (i = 0; i < DLADM_MAX_PROPS; i++) {
661 		prop_desc_t	*pdp = &prop_table[i];
662 		dladm_status_t	s;
663 
664 		if (prop_name != NULL &&
665 		    (strcasecmp(prop_name, pdp->pd_name) != 0))
666 			continue;
667 		found = B_TRUE;
668 		s = i_dladm_set_single_prop(handle, linkid, class, media, pdp,
669 		    prop_val, val_cnt, flags);
670 
671 		if (prop_name != NULL) {
672 			status = s;
673 			break;
674 		} else {
675 			if (s != DLADM_STATUS_OK &&
676 			    s != DLADM_STATUS_NOTSUP)
677 				status = s;
678 		}
679 	}
680 	if (!found) {
681 		if (prop_name[0] == '_') {
682 			/* other private properties */
683 			status = i_dladm_set_prop(handle, linkid, prop_name,
684 			    prop_val, val_cnt, flags);
685 		} else  {
686 			status = DLADM_STATUS_NOTFOUND;
687 		}
688 	}
689 
690 	return (status);
691 }
692 
693 /*
694  * Set/reset link property for specific link
695  */
696 dladm_status_t
697 dladm_set_linkprop(dladm_handle_t handle, datalink_id_t linkid,
698     const char *prop_name, char **prop_val, uint_t val_cnt, uint_t flags)
699 {
700 	dladm_status_t	status = DLADM_STATUS_OK;
701 
702 	if ((linkid == DATALINK_INVALID_LINKID) || (flags == 0) ||
703 	    (prop_val == NULL && val_cnt > 0) ||
704 	    (prop_val != NULL && val_cnt == 0) ||
705 	    (prop_name == NULL && prop_val != NULL)) {
706 		return (DLADM_STATUS_BADARG);
707 	}
708 
709 	status = i_dladm_set_linkprop(handle, linkid, prop_name, prop_val,
710 	    val_cnt, flags);
711 	if (status != DLADM_STATUS_OK)
712 		return (status);
713 
714 	if (flags & DLADM_OPT_PERSIST) {
715 		status = i_dladm_set_linkprop_db(handle, linkid, prop_name,
716 		    prop_val, val_cnt);
717 	}
718 	return (status);
719 }
720 
721 /*
722  * Walk link properties of the given specific link.
723  */
724 dladm_status_t
725 dladm_walk_linkprop(dladm_handle_t handle, datalink_id_t linkid, void *arg,
726     int (*func)(dladm_handle_t, datalink_id_t, const char *, void *))
727 {
728 	dladm_status_t		status;
729 	datalink_class_t	class;
730 	uint_t			media;
731 	int			i;
732 
733 	if (linkid == DATALINK_INVALID_LINKID || func == NULL)
734 		return (DLADM_STATUS_BADARG);
735 
736 	status = dladm_datalink_id2info(handle, linkid, NULL, &class, &media,
737 	    NULL, 0);
738 	if (status != DLADM_STATUS_OK)
739 		return (status);
740 
741 	for (i = 0; i < DLADM_MAX_PROPS; i++) {
742 		if (!(prop_table[i].pd_class & class))
743 			continue;
744 
745 		if (!DATALINK_MEDIA_ACCEPTED(prop_table[i].pd_dmedia, media))
746 			continue;
747 
748 		if (func(handle, linkid, prop_table[i].pd_name, arg) ==
749 		    DLADM_WALK_TERMINATE) {
750 			break;
751 		}
752 	}
753 
754 	return (DLADM_STATUS_OK);
755 }
756 
757 /*
758  * Get linkprop of the given specific link.
759  */
760 dladm_status_t
761 dladm_get_linkprop(dladm_handle_t handle, datalink_id_t linkid,
762     dladm_prop_type_t type, const char *prop_name, char **prop_val,
763     uint_t *val_cntp)
764 {
765 	dladm_status_t		status = DLADM_STATUS_OK;
766 	datalink_class_t	class;
767 	uint_t			media;
768 	prop_desc_t		*pdp;
769 	uint_t			cnt, dld_flags = 0;
770 	int			i;
771 	uint_t			perm_flags;
772 
773 	if (type == DLADM_PROP_VAL_DEFAULT)
774 		dld_flags = MAC_PROP_DEFAULT;
775 
776 	if (linkid == DATALINK_INVALID_LINKID || prop_name == NULL ||
777 	    prop_val == NULL || val_cntp == NULL || *val_cntp == 0)
778 		return (DLADM_STATUS_BADARG);
779 
780 	for (i = 0; i < DLADM_MAX_PROPS; i++)
781 		if (strcasecmp(prop_name, prop_table[i].pd_name) == 0)
782 			break;
783 
784 	if (i == DLADM_MAX_PROPS) {
785 		if (prop_name[0] == '_') {
786 			/*
787 			 * private property.
788 			 */
789 			return (i_dladm_get_prop(handle, linkid, prop_name,
790 			    prop_val, val_cntp, type, dld_flags));
791 		} else {
792 			return (DLADM_STATUS_NOTFOUND);
793 		}
794 	}
795 
796 	pdp = &prop_table[i];
797 
798 	status = dladm_datalink_id2info(handle, linkid, NULL, &class, &media,
799 	    NULL, 0);
800 	if (status != DLADM_STATUS_OK)
801 		return (status);
802 
803 	if (!(pdp->pd_class & class))
804 		return (DLADM_STATUS_BADARG);
805 
806 	if (!DATALINK_MEDIA_ACCEPTED(pdp->pd_dmedia, media))
807 		return (DLADM_STATUS_BADARG);
808 
809 	switch (type) {
810 	case DLADM_PROP_VAL_CURRENT:
811 		status = pdp->pd_get(handle, pdp, linkid, prop_val, val_cntp,
812 		    media, dld_flags, &perm_flags);
813 		break;
814 
815 	case DLADM_PROP_VAL_PERM:
816 		if (pdp->pd_set == NULL) {
817 			perm_flags = MAC_PROP_PERM_READ;
818 			*val_cntp = 1;
819 		} else {
820 			status = pdp->pd_get(handle, pdp, linkid, prop_val,
821 			    val_cntp, media, dld_flags, &perm_flags);
822 		}
823 
824 		*prop_val[0] = '\0';
825 		if (status == DLADM_STATUS_OK)
826 			(void) dladm_perm2str(perm_flags, *prop_val);
827 		break;
828 
829 	case DLADM_PROP_VAL_DEFAULT:
830 		/*
831 		 * If defaults are not defined for the property,
832 		 * pd_defval.vd_name should be null. If the driver
833 		 * has to be contacted for the value, vd_name should
834 		 * be the empty string (""). Otherwise, dladm will
835 		 * just print whatever is in the table.
836 		 */
837 		if (pdp->pd_defval.vd_name == NULL) {
838 			status = DLADM_STATUS_NOTSUP;
839 			break;
840 		}
841 
842 		if (strlen(pdp->pd_defval.vd_name) == 0) {
843 			status = pdp->pd_get(handle, pdp, linkid, prop_val,
844 			    val_cntp, media, dld_flags, &perm_flags);
845 		} else {
846 			(void) strcpy(*prop_val, pdp->pd_defval.vd_name);
847 		}
848 		*val_cntp = 1;
849 		break;
850 
851 	case DLADM_PROP_VAL_MODIFIABLE:
852 		if (pdp->pd_getmod != NULL) {
853 			status = pdp->pd_getmod(handle, pdp, linkid, prop_val,
854 			    val_cntp, media, dld_flags, &perm_flags);
855 			break;
856 		}
857 		cnt = pdp->pd_noptval;
858 		if (cnt == 0) {
859 			status = DLADM_STATUS_NOTSUP;
860 		} else if (cnt > *val_cntp) {
861 			status = DLADM_STATUS_TOOSMALL;
862 		} else {
863 			for (i = 0; i < cnt; i++) {
864 				(void) strcpy(prop_val[i],
865 				    pdp->pd_optval[i].vd_name);
866 			}
867 			*val_cntp = cnt;
868 		}
869 		break;
870 	case DLADM_PROP_VAL_PERSISTENT:
871 		if (pdp->pd_flags & PD_TEMPONLY)
872 			return (DLADM_STATUS_TEMPONLY);
873 		status = i_dladm_get_linkprop_db(handle, linkid, prop_name,
874 		    prop_val, val_cntp);
875 		break;
876 	default:
877 		status = DLADM_STATUS_BADARG;
878 		break;
879 	}
880 
881 	return (status);
882 }
883 
884 /*ARGSUSED*/
885 static int
886 i_dladm_init_one_prop(dladm_handle_t handle, datalink_id_t linkid,
887     const char *prop_name, void *arg)
888 {
889 	char	*buf, **propvals;
890 	uint_t	i, valcnt = DLADM_MAX_PROP_VALCNT;
891 
892 	if ((buf = malloc((sizeof (char *) + DLADM_PROP_VAL_MAX) *
893 	    DLADM_MAX_PROP_VALCNT)) == NULL) {
894 		return (DLADM_WALK_CONTINUE);
895 	}
896 
897 	propvals = (char **)(void *)buf;
898 	for (i = 0; i < valcnt; i++) {
899 		propvals[i] = buf +
900 		    sizeof (char *) * DLADM_MAX_PROP_VALCNT +
901 		    i * DLADM_PROP_VAL_MAX;
902 	}
903 
904 	if (dladm_get_linkprop(handle, linkid, DLADM_PROP_VAL_PERSISTENT,
905 	    prop_name, propvals, &valcnt) != DLADM_STATUS_OK) {
906 		goto done;
907 	}
908 
909 	(void) dladm_set_linkprop(handle, linkid, prop_name, propvals, valcnt,
910 	    DLADM_OPT_ACTIVE);
911 
912 done:
913 	if (buf != NULL)
914 		free(buf);
915 
916 	return (DLADM_WALK_CONTINUE);
917 }
918 
919 /*ARGSUSED*/
920 static int
921 i_dladm_init_linkprop(dladm_handle_t handle, datalink_id_t linkid, void *arg)
922 {
923 	datalink_class_t	class;
924 	dladm_status_t		status;
925 
926 	status = dladm_datalink_id2info(handle, linkid, NULL, &class, NULL,
927 	    NULL, 0);
928 	if (status != DLADM_STATUS_OK)
929 		return (DLADM_WALK_TERMINATE);
930 
931 	if ((class & (DATALINK_CLASS_VNIC | DATALINK_CLASS_VLAN)) == 0)
932 		(void) dladm_init_linkprop(handle, linkid, B_TRUE);
933 
934 	return (DLADM_WALK_CONTINUE);
935 }
936 
937 dladm_status_t
938 dladm_init_linkprop(dladm_handle_t handle, datalink_id_t linkid,
939     boolean_t any_media)
940 {
941 	datalink_media_t	dmedia;
942 	uint32_t		media;
943 
944 	dmedia = any_media ? DATALINK_ANY_MEDIATYPE : DL_WIFI;
945 
946 	if (linkid == DATALINK_ALL_LINKID) {
947 		(void) dladm_walk_datalink_id(i_dladm_init_linkprop, handle,
948 		    NULL, DATALINK_CLASS_ALL, dmedia, DLADM_OPT_PERSIST);
949 	} else if (any_media ||
950 	    ((dladm_datalink_id2info(handle, linkid, NULL, NULL, &media, NULL,
951 	    0) == DLADM_STATUS_OK) &&
952 	    DATALINK_MEDIA_ACCEPTED(dmedia, media))) {
953 		(void) dladm_walk_linkprop(handle, linkid, NULL,
954 		    i_dladm_init_one_prop);
955 	}
956 	return (DLADM_STATUS_OK);
957 }
958 
959 /* ARGSUSED */
960 static dladm_status_t
961 do_get_zone(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
962     char **prop_val, uint_t *val_cnt, datalink_media_t media,
963     uint_t flags, uint_t *perm_flags)
964 {
965 	char			zone_name[ZONENAME_MAX];
966 	zoneid_t		zid;
967 	dladm_status_t		status;
968 	char			*cp;
969 	dld_ioc_macprop_t	*dip;
970 
971 	if (flags != 0)
972 		return (DLADM_STATUS_NOTSUP);
973 
974 	dip = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags,
975 	    &status, perm_flags);
976 	if (status != DLADM_STATUS_OK)
977 		return (status);
978 
979 	cp = dip->pr_val;
980 	(void) memcpy(&zid, cp, sizeof (zid));
981 	free(dip);
982 
983 	*val_cnt = 1;
984 	if (zid != GLOBAL_ZONEID) {
985 		if (getzonenamebyid(zid, zone_name, sizeof (zone_name)) < 0) {
986 			return (dladm_errno2status(errno));
987 		}
988 
989 		(void) strncpy(*prop_val, zone_name, DLADM_PROP_VAL_MAX);
990 	} else {
991 		*prop_val[0] = '\0';
992 	}
993 
994 	return (DLADM_STATUS_OK);
995 }
996 
997 typedef int (*zone_get_devroot_t)(char *, char *, size_t);
998 
999 static int
1000 i_dladm_get_zone_dev(char *zone_name, char *dev, size_t devlen)
1001 {
1002 	char			root[MAXPATHLEN];
1003 	zone_get_devroot_t	real_zone_get_devroot;
1004 	void			*dlhandle;
1005 	void			*sym;
1006 	int			ret;
1007 
1008 	if ((dlhandle = dlopen("libzonecfg.so.1", RTLD_LAZY)) == NULL)
1009 		return (-1);
1010 
1011 	if ((sym = dlsym(dlhandle, "zone_get_devroot")) == NULL) {
1012 		(void) dlclose(dlhandle);
1013 		return (-1);
1014 	}
1015 
1016 	real_zone_get_devroot = (zone_get_devroot_t)sym;
1017 
1018 	if ((ret = real_zone_get_devroot(zone_name, root, sizeof (root))) == 0)
1019 		(void) snprintf(dev, devlen, "%s%s", root, "/dev");
1020 	(void) dlclose(dlhandle);
1021 	return (ret);
1022 }
1023 
1024 static dladm_status_t
1025 i_dladm_update_deventry(dladm_handle_t handle, zoneid_t zid,
1026     datalink_id_t linkid, boolean_t add)
1027 {
1028 	char		path[MAXPATHLEN];
1029 	char		name[MAXLINKNAMELEN];
1030 	di_prof_t	prof = NULL;
1031 	char		zone_name[ZONENAME_MAX];
1032 	dladm_status_t	status;
1033 	int		ret;
1034 
1035 	if (getzonenamebyid(zid, zone_name, sizeof (zone_name)) < 0)
1036 		return (dladm_errno2status(errno));
1037 	if (i_dladm_get_zone_dev(zone_name, path, sizeof (path)) != 0)
1038 		return (dladm_errno2status(errno));
1039 	if (di_prof_init(path, &prof) != 0)
1040 		return (dladm_errno2status(errno));
1041 
1042 	status = dladm_linkid2legacyname(handle, linkid, name, MAXLINKNAMELEN);
1043 	if (status != DLADM_STATUS_OK)
1044 		goto cleanup;
1045 
1046 	if (add)
1047 		ret = di_prof_add_dev(prof, name);
1048 	else
1049 		ret = di_prof_add_exclude(prof, name);
1050 
1051 	if (ret != 0) {
1052 		status = dladm_errno2status(errno);
1053 		goto cleanup;
1054 	}
1055 
1056 	if (di_prof_commit(prof) != 0)
1057 		status = dladm_errno2status(errno);
1058 cleanup:
1059 	if (prof)
1060 		di_prof_fini(prof);
1061 
1062 	return (status);
1063 }
1064 
1065 /* ARGSUSED */
1066 static dladm_status_t
1067 do_set_zone(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
1068     val_desc_t *vdp, uint_t val_cnt, uint_t flags, datalink_media_t media)
1069 {
1070 	dladm_status_t		status = DLADM_STATUS_OK;
1071 	zoneid_t		zid_old, zid_new;
1072 	char			link[MAXLINKNAMELEN];
1073 	char			*cp;
1074 	dld_ioc_macprop_t	*dip;
1075 	dld_ioc_zid_t		*dzp;
1076 
1077 	if (val_cnt != 1)
1078 		return (DLADM_STATUS_BADVALCNT);
1079 
1080 	dzp = (dld_ioc_zid_t *)vdp->vd_val;
1081 
1082 	dip = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags,
1083 	    &status, NULL);
1084 	if (status != DLADM_STATUS_OK)
1085 		return (status);
1086 
1087 	cp = dip->pr_val;
1088 	(void) memcpy(&zid_old, cp, sizeof (zid_old));
1089 	free(dip);
1090 
1091 	zid_new = dzp->diz_zid;
1092 	(void) strlcpy(link, dzp->diz_link, MAXLINKNAMELEN);
1093 
1094 	/* Do nothing if setting to current value */
1095 	if (zid_new == zid_old)
1096 		return (status);
1097 
1098 	if (zid_new != GLOBAL_ZONEID) {
1099 		/*
1100 		 * If the new zoneid is the global zone, we could destroy
1101 		 * the link (in the case of an implicitly-created VLAN) as a
1102 		 * result of setting the zoneid. In that case, we defer the
1103 		 * operation to the end of this function to avoid recreating
1104 		 * the VLAN and getting a different linkid during the rollback
1105 		 * if other operation fails.
1106 		 *
1107 		 * Otherwise, this operation will hold a reference to the
1108 		 * link and prevent a link renaming, so we need to do it
1109 		 * before other operations.
1110 		 */
1111 		status = i_dladm_set_public_prop(handle, pdp, linkid, vdp,
1112 		    val_cnt, flags, media);
1113 		if (status != DLADM_STATUS_OK)
1114 			return (status);
1115 	}
1116 
1117 	if (zid_old != GLOBAL_ZONEID) {
1118 		if (zone_remove_datalink(zid_old, link) != 0 &&
1119 		    errno != ENXIO) {
1120 			status = dladm_errno2status(errno);
1121 			goto rollback1;
1122 		}
1123 
1124 		/*
1125 		 * It is okay to fail to update the /dev entry (some
1126 		 * vanity-named links do not have a /dev entry).
1127 		 */
1128 		(void) i_dladm_update_deventry(handle, zid_old, linkid,
1129 		    B_FALSE);
1130 	}
1131 
1132 	if (zid_new != GLOBAL_ZONEID) {
1133 		if (zone_add_datalink(zid_new, link) != 0) {
1134 			status = dladm_errno2status(errno);
1135 			goto rollback2;
1136 		}
1137 
1138 		(void) i_dladm_update_deventry(handle, zid_new, linkid, B_TRUE);
1139 	} else {
1140 		status = i_dladm_set_public_prop(handle, pdp, linkid, vdp,
1141 		    val_cnt, flags, media);
1142 		if (status != DLADM_STATUS_OK)
1143 			goto rollback2;
1144 	}
1145 
1146 	return (DLADM_STATUS_OK);
1147 
1148 rollback2:
1149 	if (zid_old != GLOBAL_ZONEID)
1150 		(void) i_dladm_update_deventry(handle, zid_old, linkid, B_TRUE);
1151 	if (zid_old != GLOBAL_ZONEID)
1152 		(void) zone_add_datalink(zid_old, link);
1153 rollback1:
1154 	if (zid_new != GLOBAL_ZONEID) {
1155 		dzp->diz_zid = zid_old;
1156 		(void) i_dladm_set_public_prop(handle, pdp, linkid, vdp,
1157 		    val_cnt, flags, media);
1158 	}
1159 
1160 	return (status);
1161 }
1162 
1163 /* ARGSUSED */
1164 static dladm_status_t
1165 do_check_zone(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
1166     char **prop_val, uint_t val_cnt, val_desc_t *vdp, datalink_media_t media)
1167 {
1168 	char		*zone_name;
1169 	char		linkname[MAXLINKNAMELEN];
1170 	zoneid_t	zoneid;
1171 	dladm_status_t	status = DLADM_STATUS_OK;
1172 	dld_ioc_zid_t	*dzp;
1173 
1174 	if (val_cnt != 1)
1175 		return (DLADM_STATUS_BADVALCNT);
1176 
1177 	dzp = malloc(sizeof (dld_ioc_zid_t));
1178 	if (dzp == NULL)
1179 		return (DLADM_STATUS_NOMEM);
1180 
1181 	if ((status = dladm_datalink_id2info(handle, linkid, NULL, NULL, NULL,
1182 	    linkname, MAXLINKNAMELEN)) != DLADM_STATUS_OK) {
1183 		goto done;
1184 	}
1185 
1186 	zone_name = (prop_val != NULL) ? *prop_val : GLOBAL_ZONENAME;
1187 	if (strlen(linkname) > MAXLINKNAMELEN) {
1188 		status = DLADM_STATUS_BADVAL;
1189 		goto done;
1190 	}
1191 
1192 	if ((zoneid = getzoneidbyname(zone_name)) == -1) {
1193 		status = DLADM_STATUS_BADVAL;
1194 		goto done;
1195 	}
1196 
1197 	if (zoneid != GLOBAL_ZONEID) {
1198 		ushort_t	flags;
1199 
1200 		if (zone_getattr(zoneid, ZONE_ATTR_FLAGS, &flags,
1201 		    sizeof (flags)) < 0) {
1202 			status = dladm_errno2status(errno);
1203 			goto done;
1204 		}
1205 
1206 		if (!(flags & ZF_NET_EXCL)) {
1207 			status = DLADM_STATUS_BADVAL;
1208 			goto done;
1209 		}
1210 	}
1211 
1212 	(void) memset(dzp, 0, sizeof (dld_ioc_zid_t));
1213 
1214 	dzp->diz_zid = zoneid;
1215 	(void) strlcpy(dzp->diz_link, linkname, MAXLINKNAMELEN);
1216 
1217 	vdp->vd_val = (uintptr_t)dzp;
1218 	return (DLADM_STATUS_OK);
1219 done:
1220 	free(dzp);
1221 	return (status);
1222 }
1223 
1224 /* ARGSUSED */
1225 static dladm_status_t
1226 dld_maxbw_get(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
1227     char **prop_val, uint_t *val_cnt, datalink_media_t media,
1228     uint_t flags, uint_t *perm_flags)
1229 {
1230 	dld_ioc_macprop_t	*dip;
1231 	mac_resource_props_t	mrp;
1232 	dladm_status_t		status;
1233 
1234 	dip = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags,
1235 	    &status, perm_flags);
1236 	if (dip == NULL)
1237 		return (status);
1238 
1239 	bcopy(dip->pr_val, &mrp, sizeof (mac_resource_props_t));
1240 	free(dip);
1241 
1242 	if ((mrp.mrp_mask & MRP_MAXBW) == 0) {
1243 		(*prop_val)[0] = '\0';
1244 	} else {
1245 		(void) dladm_bw2str(mrp.mrp_maxbw, prop_val[0]);
1246 	}
1247 	*val_cnt = 1;
1248 	return (DLADM_STATUS_OK);
1249 }
1250 
1251 /* ARGSUSED */
1252 static dladm_status_t
1253 do_check_maxbw(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
1254     char **prop_val, uint_t val_cnt, val_desc_t *vdp, datalink_media_t media)
1255 {
1256 	uint64_t	*maxbw;
1257 	dladm_status_t	status = DLADM_STATUS_OK;
1258 
1259 	if (val_cnt != 1)
1260 		return (DLADM_STATUS_BADVALCNT);
1261 
1262 	maxbw = malloc(sizeof (uint64_t));
1263 	if (maxbw == NULL)
1264 		return (DLADM_STATUS_NOMEM);
1265 
1266 	status = dladm_str2bw(*prop_val, maxbw);
1267 	if (status != DLADM_STATUS_OK) {
1268 		free(maxbw);
1269 		return (status);
1270 	}
1271 
1272 	if ((*maxbw < MRP_MAXBW_MINVAL) && (*maxbw != 0)) {
1273 		free(maxbw);
1274 		return (DLADM_STATUS_MINMAXBW);
1275 	}
1276 
1277 	vdp->vd_val = (uintptr_t)maxbw;
1278 	return (DLADM_STATUS_OK);
1279 }
1280 
1281 /* ARGSUSED */
1282 dladm_status_t
1283 do_extract_maxbw(val_desc_t *vdp, void *arg, uint_t cnt)
1284 {
1285 	mac_resource_props_t *mrp = (mac_resource_props_t *)arg;
1286 
1287 	bcopy((char *)vdp->vd_val, &mrp->mrp_maxbw, sizeof (uint64_t));
1288 	mrp->mrp_mask |= MRP_MAXBW;
1289 
1290 	return (DLADM_STATUS_OK);
1291 }
1292 
1293 /* ARGSUSED */
1294 static dladm_status_t
1295 dld_cpus_get(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
1296     char **prop_val, uint_t *val_cnt, datalink_media_t media,
1297     uint_t flags, uint_t *perm_flags)
1298 {
1299 	dld_ioc_macprop_t	*dip;
1300 	mac_resource_props_t	mrp;
1301 	int			i;
1302 	uint32_t		ncpus;
1303 	uchar_t			*cp;
1304 	dladm_status_t		status;
1305 
1306 	dip = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags,
1307 	    &status, perm_flags);
1308 	if (dip == NULL)
1309 		return (status);
1310 
1311 	cp = (uchar_t *)dip->pr_val;
1312 	(void) memcpy(&mrp, cp, sizeof (mac_resource_props_t));
1313 	free(dip);
1314 
1315 	ncpus = mrp.mrp_ncpus;
1316 
1317 	if (ncpus > *val_cnt)
1318 		return (DLADM_STATUS_TOOSMALL);
1319 
1320 	if (ncpus == 0) {
1321 		(*prop_val)[0] = '\0';
1322 		*val_cnt = 1;
1323 		return (DLADM_STATUS_OK);
1324 	}
1325 
1326 	*val_cnt = ncpus;
1327 	for (i = 0; i < ncpus; i++) {
1328 		(void) snprintf(prop_val[i], DLADM_PROP_VAL_MAX,
1329 		    "%u", mrp.mrp_cpu[i]);
1330 	}
1331 	return (DLADM_STATUS_OK);
1332 }
1333 
1334 /* ARGSUSED */
1335 static dladm_status_t
1336 do_set_res(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
1337     val_desc_t *vdp, uint_t val_cnt, uint_t flags, datalink_media_t media)
1338 {
1339 	mac_resource_props_t	mrp;
1340 	dladm_status_t		status = DLADM_STATUS_OK;
1341 	dld_ioc_macprop_t	*dip;
1342 
1343 	bzero(&mrp, sizeof (mac_resource_props_t));
1344 	dip = i_dladm_buf_alloc_by_name(0, linkid, pdp->pd_name,
1345 	    flags, &status);
1346 
1347 	if (dip == NULL)
1348 		return (status);
1349 
1350 	if (vdp->vd_val == RESET_VAL) {
1351 		switch (dip->pr_num) {
1352 		case MAC_PROP_MAXBW:
1353 			mrp.mrp_maxbw = MRP_MAXBW_RESETVAL;
1354 			mrp.mrp_mask = MRP_MAXBW;
1355 			break;
1356 		case MAC_PROP_PRIO:
1357 			mrp.mrp_priority = MPL_RESET;
1358 			mrp.mrp_mask = MRP_PRIORITY;
1359 			break;
1360 		default:
1361 			free(dip);
1362 			return (DLADM_STATUS_BADARG);
1363 		}
1364 	} else {
1365 		switch (dip->pr_num) {
1366 		case MAC_PROP_MAXBW:
1367 			bcopy((void *)vdp->vd_val, &mrp.mrp_maxbw,
1368 			    sizeof (uint64_t));
1369 			mrp.mrp_mask = MRP_MAXBW;
1370 			break;
1371 		case MAC_PROP_PRIO:
1372 			bcopy((void *)vdp->vd_val, &mrp.mrp_priority,
1373 			    sizeof (mac_priority_level_t));
1374 			mrp.mrp_mask = MRP_PRIORITY;
1375 			break;
1376 		default:
1377 			free(dip);
1378 			return (DLADM_STATUS_BADARG);
1379 		}
1380 	}
1381 
1382 	(void) memcpy(dip->pr_val, &mrp, dip->pr_valsize);
1383 	status = i_dladm_macprop(handle, dip, B_TRUE);
1384 	free(dip);
1385 	return (status);
1386 }
1387 
1388 /* ARGSUSED */
1389 static dladm_status_t
1390 do_set_cpus(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
1391     val_desc_t *vdp, uint_t val_cnt, uint_t flags, datalink_media_t media)
1392 {
1393 	mac_resource_props_t	mrp;
1394 	dladm_status_t		status;
1395 	dld_ioc_macprop_t	*dip;
1396 	datalink_class_t	class;
1397 
1398 	/*
1399 	 * CPU bindings can be set on VNIC and regular physical links.
1400 	 * However VNICs fails the dladm_phys_info test(). So apply
1401 	 * the phys_info test only on physical links.
1402 	 */
1403 	if ((status = dladm_datalink_id2info(handle, linkid, NULL, &class,
1404 	    NULL, NULL, 0)) != DLADM_STATUS_OK) {
1405 		return (status);
1406 	}
1407 
1408 	/*
1409 	 * We set intr_cpu to -1. The interrupt will be retargetted,
1410 	 * if possible when the setup is complete in MAC.
1411 	 */
1412 	bzero(&mrp, sizeof (mac_resource_props_t));
1413 	mrp.mrp_mask = MRP_CPUS;
1414 	if (vdp != NULL && vdp->vd_val != RESET_VAL) {
1415 		mac_resource_props_t	*vmrp;
1416 
1417 		vmrp = (mac_resource_props_t *)vdp->vd_val;
1418 		if (vmrp->mrp_ncpus > 0) {
1419 			bcopy(vmrp, &mrp, sizeof (mac_resource_props_t));
1420 			mrp.mrp_mask = MRP_CPUS;
1421 		}
1422 		mrp.mrp_mask |= MRP_CPUS_USERSPEC;
1423 		mrp.mrp_fanout_mode = MCM_CPUS;
1424 		mrp.mrp_intr_cpu = -1;
1425 	}
1426 
1427 	dip = i_dladm_buf_alloc_by_name(0, linkid, pdp->pd_name,
1428 	    flags, &status);
1429 	if (dip == NULL)
1430 		return (status);
1431 
1432 	(void) memcpy(dip->pr_val, &mrp, dip->pr_valsize);
1433 	status = i_dladm_macprop(handle, dip, B_TRUE);
1434 	free(dip);
1435 	return (status);
1436 }
1437 
1438 /* ARGSUSED */
1439 static dladm_status_t
1440 do_check_cpus(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
1441     char **prop_val, uint_t val_cnt, val_desc_t *vdp, datalink_media_t media)
1442 {
1443 	uint32_t		cpuid;
1444 	int			i, j, rc;
1445 	long			nproc = sysconf(_SC_NPROCESSORS_CONF);
1446 	mac_resource_props_t	*mrp;
1447 
1448 	mrp = malloc(sizeof (mac_resource_props_t));
1449 	if (mrp == NULL)
1450 		return (DLADM_STATUS_NOMEM);
1451 
1452 	for (i = 0; i < val_cnt; i++) {
1453 		errno = 0;
1454 		cpuid = strtol(prop_val[i], (char **)NULL, 10);
1455 		if (errno != 0 || cpuid >= nproc) {
1456 			free(mrp);
1457 			return (DLADM_STATUS_CPUMAX);
1458 		}
1459 		rc = p_online(cpuid, P_STATUS);
1460 		if (rc < 1) {
1461 			free(mrp);
1462 			return (DLADM_STATUS_CPUERR);
1463 		}
1464 		if (rc != P_ONLINE) {
1465 			free(mrp);
1466 			return (DLADM_STATUS_CPUNOTONLINE);
1467 		}
1468 		mrp->mrp_cpu[i] = cpuid;
1469 	}
1470 	mrp->mrp_ncpus = (uint32_t)val_cnt;
1471 
1472 	/* Check for duplicates */
1473 	for (i = 0; i < val_cnt; i++) {
1474 		for (j = 0; j < val_cnt; j++) {
1475 			if (i != j && mrp->mrp_cpu[i] == mrp->mrp_cpu[j]) {
1476 				free(mrp);
1477 				return (DLADM_STATUS_BADARG);
1478 			}
1479 		}
1480 	}
1481 	vdp->vd_val = (uintptr_t)mrp;
1482 
1483 	return (DLADM_STATUS_OK);
1484 }
1485 
1486 /* ARGSUSED */
1487 dladm_status_t
1488 do_extract_cpus(val_desc_t *vdp, void *arg, uint_t cnt)
1489 {
1490 	mac_resource_props_t	*mrp = (mac_resource_props_t *)arg;
1491 	mac_resource_props_t	*vmrp = (mac_resource_props_t *)vdp->vd_val;
1492 	int			i;
1493 
1494 	for (i = 0; i < vmrp->mrp_ncpus; i++) {
1495 		mrp->mrp_cpu[i] = vmrp->mrp_cpu[i];
1496 	}
1497 	mrp->mrp_ncpus = vmrp->mrp_ncpus;
1498 	mrp->mrp_mask |= (MRP_CPUS|MRP_CPUS_USERSPEC);
1499 	mrp->mrp_fanout_mode = MCM_CPUS;
1500 
1501 	return (DLADM_STATUS_OK);
1502 }
1503 
1504 /* ARGSUSED */
1505 static dladm_status_t
1506 dld_priority_get(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
1507     char **prop_val, uint_t *val_cnt, datalink_media_t media,
1508     uint_t flags, uint_t *perm_flags)
1509 {
1510 	dld_ioc_macprop_t	*dip;
1511 	mac_resource_props_t	mrp;
1512 	mac_priority_level_t	pri;
1513 	dladm_status_t		status;
1514 
1515 	dip = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags,
1516 	    &status, perm_flags);
1517 	if (dip == NULL)
1518 		return (status);
1519 
1520 	bcopy(dip->pr_val, &mrp, sizeof (mac_resource_props_t));
1521 	free(dip);
1522 
1523 	pri = ((mrp.mrp_mask & MRP_PRIORITY) == 0) ? MPL_HIGH :
1524 	    mrp.mrp_priority;
1525 
1526 	(void) dladm_pri2str(pri, prop_val[0]);
1527 	*val_cnt = 1;
1528 	return (DLADM_STATUS_OK);
1529 }
1530 
1531 /* ARGSUSED */
1532 static dladm_status_t
1533 do_check_priority(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
1534     char **prop_val, uint_t val_cnt, val_desc_t *vdp, datalink_media_t media)
1535 {
1536 	mac_priority_level_t	*pri;
1537 	dladm_status_t	status = DLADM_STATUS_OK;
1538 
1539 	if (val_cnt != 1)
1540 		return (DLADM_STATUS_BADVALCNT);
1541 
1542 	pri = malloc(sizeof (mac_priority_level_t));
1543 	if (pri == NULL)
1544 		return (DLADM_STATUS_NOMEM);
1545 
1546 	status = dladm_str2pri(*prop_val, pri);
1547 	if (status != DLADM_STATUS_OK) {
1548 		free(pri);
1549 		return (status);
1550 	}
1551 
1552 	if (*pri < MPL_LOW || *pri > MPL_HIGH) {
1553 		free(pri);
1554 		return (DLADM_STATUS_BADVAL);
1555 	}
1556 
1557 	vdp->vd_val = (uintptr_t)pri;
1558 	return (DLADM_STATUS_OK);
1559 }
1560 
1561 /* ARGSUSED */
1562 dladm_status_t
1563 do_extract_priority(val_desc_t *vdp, void *arg, uint_t cnt)
1564 {
1565 	mac_resource_props_t *mrp = (mac_resource_props_t *)arg;
1566 
1567 	bcopy((char *)vdp->vd_val, &mrp->mrp_priority,
1568 	    sizeof (mac_priority_level_t));
1569 	mrp->mrp_mask |= MRP_PRIORITY;
1570 
1571 	return (DLADM_STATUS_OK);
1572 }
1573 
1574 /* ARGSUSED */
1575 static dladm_status_t
1576 do_get_autopush(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
1577     char **prop_val, uint_t *val_cnt, datalink_media_t media,
1578     uint_t flags, uint_t *perm_flags)
1579 {
1580 	struct		dlautopush dlap;
1581 	int		i, len;
1582 	dladm_status_t	status;
1583 	dld_ioc_macprop_t	*dip;
1584 
1585 	if (flags & MAC_PROP_DEFAULT)
1586 		return (DLADM_STATUS_NOTDEFINED);
1587 
1588 	*val_cnt = 1;
1589 	dip = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags,
1590 	    &status, perm_flags);
1591 	if (dip == NULL) {
1592 		(*prop_val)[0] = '\0';
1593 		return (DLADM_STATUS_OK);
1594 	}
1595 	(void) memcpy(&dlap, dip->pr_val, sizeof (dlap));
1596 
1597 	for (i = 0, len = 0; i < dlap.dap_npush; i++) {
1598 		if (i != 0) {
1599 			(void) snprintf(*prop_val + len,
1600 			    DLADM_PROP_VAL_MAX - len, "%c", AP_DELIMITER);
1601 			len += 1;
1602 		}
1603 		(void) snprintf(*prop_val + len, DLADM_PROP_VAL_MAX - len,
1604 		    "%s", dlap.dap_aplist[i]);
1605 		len += strlen(dlap.dap_aplist[i]);
1606 		if (dlap.dap_anchor - 1 == i) {
1607 			(void) snprintf(*prop_val + len,
1608 			    DLADM_PROP_VAL_MAX - len, "%c%s", AP_DELIMITER,
1609 			    AP_ANCHOR);
1610 			len += (strlen(AP_ANCHOR) + 1);
1611 		}
1612 	}
1613 	free(dip);
1614 done:
1615 	return (DLADM_STATUS_OK);
1616 }
1617 
1618 /*
1619  * Add the specified module to the dlautopush structure; returns a
1620  * DLADM_STATUS_* code.
1621  */
1622 dladm_status_t
1623 i_dladm_add_ap_module(const char *module, struct dlautopush *dlap)
1624 {
1625 	if ((strlen(module) == 0) || (strlen(module) > FMNAMESZ))
1626 		return (DLADM_STATUS_BADVAL);
1627 
1628 	if (strncasecmp(module, AP_ANCHOR, strlen(AP_ANCHOR)) == 0) {
1629 		/*
1630 		 * We don't allow multiple anchors, and the anchor must
1631 		 * be after at least one module.
1632 		 */
1633 		if (dlap->dap_anchor != 0)
1634 			return (DLADM_STATUS_BADVAL);
1635 		if (dlap->dap_npush == 0)
1636 			return (DLADM_STATUS_BADVAL);
1637 
1638 		dlap->dap_anchor = dlap->dap_npush;
1639 		return (DLADM_STATUS_OK);
1640 	}
1641 	if (dlap->dap_npush > MAXAPUSH)
1642 		return (DLADM_STATUS_BADVALCNT);
1643 
1644 	(void) strlcpy(dlap->dap_aplist[dlap->dap_npush++], module,
1645 	    FMNAMESZ + 1);
1646 
1647 	return (DLADM_STATUS_OK);
1648 }
1649 
1650 /*
1651  * Currently, both '.' and ' '(space) can be used as the delimiters between
1652  * autopush modules. The former is used in dladm set-linkprop, and the
1653  * latter is used in the autopush(1M) file.
1654  */
1655 /* ARGSUSED */
1656 static dladm_status_t
1657 do_check_autopush(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
1658     char **prop_val, uint_t val_cnt, val_desc_t *vdp, datalink_media_t media)
1659 {
1660 	char			*module;
1661 	struct dlautopush	*dlap;
1662 	dladm_status_t		status;
1663 	char			val[DLADM_PROP_VAL_MAX];
1664 	char			delimiters[4];
1665 
1666 	if (val_cnt != 1)
1667 		return (DLADM_STATUS_BADVALCNT);
1668 
1669 	if (prop_val != NULL) {
1670 		dlap = malloc(sizeof (struct dlautopush));
1671 		if (dlap == NULL)
1672 			return (DLADM_STATUS_NOMEM);
1673 
1674 		(void) memset(dlap, 0, sizeof (struct dlautopush));
1675 		(void) snprintf(delimiters, 4, " %c\n", AP_DELIMITER);
1676 		bcopy(*prop_val, val, DLADM_PROP_VAL_MAX);
1677 		module = strtok(val, delimiters);
1678 		while (module != NULL) {
1679 			status = i_dladm_add_ap_module(module, dlap);
1680 			if (status != DLADM_STATUS_OK)
1681 				return (status);
1682 			module = strtok(NULL, delimiters);
1683 		}
1684 
1685 		vdp->vd_val = (uintptr_t)dlap;
1686 	} else {
1687 		vdp->vd_val = 0;
1688 	}
1689 	return (DLADM_STATUS_OK);
1690 }
1691 
1692 #define	WLDP_BUFSIZE (MAX_BUF_LEN - WIFI_BUF_OFFSET)
1693 
1694 /* ARGSUSED */
1695 static dladm_status_t
1696 do_get_rate_common(dladm_handle_t handle, prop_desc_t *pdp,
1697     datalink_id_t linkid, char **prop_val, uint_t *val_cnt, uint_t id,
1698     uint_t *perm_flags)
1699 {
1700 	wl_rates_t	*wrp;
1701 	uint_t		i;
1702 	dladm_status_t	status = DLADM_STATUS_OK;
1703 
1704 	wrp = malloc(WLDP_BUFSIZE);
1705 	if (wrp == NULL)
1706 		return (DLADM_STATUS_NOMEM);
1707 
1708 	status = i_dladm_wlan_param(handle, linkid, wrp, id, WLDP_BUFSIZE,
1709 	    B_FALSE);
1710 	if (status != DLADM_STATUS_OK)
1711 		goto done;
1712 
1713 	if (wrp->wl_rates_num > *val_cnt) {
1714 		status = DLADM_STATUS_TOOSMALL;
1715 		goto done;
1716 	}
1717 
1718 	if (wrp->wl_rates_rates[0] == 0) {
1719 		prop_val[0][0] = '\0';
1720 		*val_cnt = 1;
1721 		goto done;
1722 	}
1723 
1724 	for (i = 0; i < wrp->wl_rates_num; i++) {
1725 		(void) snprintf(prop_val[i], DLADM_STRSIZE, "%.*f",
1726 		    wrp->wl_rates_rates[i] % 2,
1727 		    (float)wrp->wl_rates_rates[i] / 2);
1728 	}
1729 	*val_cnt = wrp->wl_rates_num;
1730 	*perm_flags = MAC_PROP_PERM_RW;
1731 
1732 done:
1733 	free(wrp);
1734 	return (status);
1735 }
1736 
1737 static dladm_status_t
1738 do_get_rate_prop(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
1739     char **prop_val, uint_t *val_cnt, datalink_media_t media,
1740     uint_t flags, uint_t *perm_flags)
1741 {
1742 	if (media != DL_WIFI) {
1743 		return (i_dladm_speed_get(handle, pdp, linkid, prop_val,
1744 		    val_cnt, flags, perm_flags));
1745 	}
1746 
1747 	return (do_get_rate_common(handle, pdp, linkid, prop_val, val_cnt,
1748 	    MAC_PROP_WL_DESIRED_RATES, perm_flags));
1749 }
1750 
1751 /* ARGSUSED */
1752 static dladm_status_t
1753 do_get_rate_mod(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 	switch (media) {
1758 	case DL_ETHER:
1759 		/*
1760 		 * Speed for ethernet links is unbounded. E.g., 802.11b
1761 		 * links can have a speed of 5.5 Gbps.
1762 		 */
1763 		return (DLADM_STATUS_NOTSUP);
1764 
1765 	case DL_WIFI:
1766 		return (do_get_rate_common(handle, pdp, linkid, prop_val,
1767 		    val_cnt, MAC_PROP_WL_SUPPORTED_RATES, perm_flags));
1768 	default:
1769 		return (DLADM_STATUS_BADARG);
1770 	}
1771 }
1772 
1773 static dladm_status_t
1774 do_set_rate(dladm_handle_t handle, datalink_id_t linkid,
1775     dladm_wlan_rates_t *rates)
1776 {
1777 	int		i;
1778 	uint_t		len;
1779 	wl_rates_t	*wrp;
1780 	dladm_status_t	status = DLADM_STATUS_OK;
1781 
1782 	wrp = malloc(WLDP_BUFSIZE);
1783 	if (wrp == NULL)
1784 		return (DLADM_STATUS_NOMEM);
1785 
1786 	bzero(wrp, WLDP_BUFSIZE);
1787 	for (i = 0; i < rates->wr_cnt; i++)
1788 		wrp->wl_rates_rates[i] = rates->wr_rates[i];
1789 	wrp->wl_rates_num = rates->wr_cnt;
1790 
1791 	len = offsetof(wl_rates_t, wl_rates_rates) +
1792 	    (rates->wr_cnt * sizeof (char)) + WIFI_BUF_OFFSET;
1793 	status = i_dladm_wlan_param(handle, linkid, wrp,
1794 	    MAC_PROP_WL_DESIRED_RATES, len, B_TRUE);
1795 
1796 	free(wrp);
1797 	return (status);
1798 }
1799 
1800 /* ARGSUSED */
1801 static dladm_status_t
1802 do_set_rate_prop(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
1803     val_desc_t *vdp, uint_t val_cnt, uint_t flags, datalink_media_t media)
1804 {
1805 	dladm_wlan_rates_t	rates;
1806 	dladm_status_t		status;
1807 
1808 	/*
1809 	 * can currently set rate on WIFI links only.
1810 	 */
1811 	if (media != DL_WIFI)
1812 		return (DLADM_STATUS_PROPRDONLY);
1813 
1814 	if (val_cnt != 1)
1815 		return (DLADM_STATUS_BADVALCNT);
1816 
1817 	rates.wr_cnt = 1;
1818 	rates.wr_rates[0] = vdp[0].vd_val;
1819 
1820 	status = do_set_rate(handle, linkid, &rates);
1821 
1822 done:
1823 	return (status);
1824 }
1825 
1826 /* ARGSUSED */
1827 static dladm_status_t
1828 do_check_rate(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
1829     char **prop_val, uint_t val_cnt, val_desc_t *vdp, datalink_media_t media)
1830 {
1831 	int		i;
1832 	uint_t		modval_cnt = MAX_SUPPORT_RATES;
1833 	char		*buf, **modval;
1834 	dladm_status_t	status;
1835 	uint_t 		perm_flags;
1836 
1837 	if (val_cnt != 1)
1838 		return (DLADM_STATUS_BADVALCNT);
1839 
1840 	buf = malloc((sizeof (char *) + DLADM_STRSIZE) *
1841 	    MAX_SUPPORT_RATES);
1842 	if (buf == NULL) {
1843 		status = DLADM_STATUS_NOMEM;
1844 		goto done;
1845 	}
1846 
1847 	modval = (char **)(void *)buf;
1848 	for (i = 0; i < MAX_SUPPORT_RATES; i++) {
1849 		modval[i] = buf + sizeof (char *) * MAX_SUPPORT_RATES +
1850 		    i * DLADM_STRSIZE;
1851 	}
1852 
1853 	status = do_get_rate_mod(handle, NULL, linkid, modval, &modval_cnt,
1854 	    media, 0, &perm_flags);
1855 	if (status != DLADM_STATUS_OK)
1856 		goto done;
1857 
1858 	for (i = 0; i < modval_cnt; i++) {
1859 		if (strcasecmp(*prop_val, modval[i]) == 0) {
1860 			vdp->vd_val = (uintptr_t)(uint_t)
1861 			    (atof(*prop_val) * 2);
1862 			status = DLADM_STATUS_OK;
1863 			break;
1864 		}
1865 	}
1866 	if (i == modval_cnt)
1867 		status = DLADM_STATUS_BADVAL;
1868 done:
1869 	free(buf);
1870 	return (status);
1871 }
1872 
1873 static dladm_status_t
1874 do_get_phyconf(dladm_handle_t handle, datalink_id_t linkid, void *buf,
1875     int buflen)
1876 {
1877 	return (i_dladm_wlan_param(handle, linkid, buf, MAC_PROP_WL_PHY_CONFIG,
1878 	    buflen, B_FALSE));
1879 }
1880 
1881 /* ARGSUSED */
1882 static dladm_status_t
1883 do_get_channel_prop(dladm_handle_t handle, prop_desc_t *pdp,
1884     datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
1885     datalink_media_t media, uint_t flags, uint_t *perm_flags)
1886 {
1887 	uint32_t	channel;
1888 	char		buf[WLDP_BUFSIZE];
1889 	dladm_status_t	status = DLADM_STATUS_OK;
1890 	wl_phy_conf_t	wl_phy_conf;
1891 
1892 	if ((status = do_get_phyconf(handle, linkid, buf, sizeof (buf)))
1893 	    != DLADM_STATUS_OK)
1894 		goto done;
1895 
1896 	(void) memcpy(&wl_phy_conf, buf, sizeof (wl_phy_conf));
1897 	if (!i_dladm_wlan_convert_chan(&wl_phy_conf, &channel)) {
1898 		status = DLADM_STATUS_NOTFOUND;
1899 		goto done;
1900 	}
1901 
1902 	(void) snprintf(*prop_val, DLADM_STRSIZE, "%u", channel);
1903 	*val_cnt = 1;
1904 	*perm_flags = MAC_PROP_PERM_READ;
1905 done:
1906 	return (status);
1907 }
1908 
1909 static dladm_status_t
1910 do_get_powermode(dladm_handle_t handle, datalink_id_t linkid, void *buf,
1911     int buflen)
1912 {
1913 	return (i_dladm_wlan_param(handle, linkid, buf, MAC_PROP_WL_POWER_MODE,
1914 	    buflen, B_FALSE));
1915 }
1916 
1917 /* ARGSUSED */
1918 static dladm_status_t
1919 do_get_powermode_prop(dladm_handle_t handle, prop_desc_t *pdp,
1920     datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
1921     datalink_media_t media, uint_t flags, uint_t *perm_flags)
1922 {
1923 	wl_ps_mode_t	mode;
1924 	const char	*s;
1925 	char		buf[WLDP_BUFSIZE];
1926 	dladm_status_t	status = DLADM_STATUS_OK;
1927 
1928 	if ((status = do_get_powermode(handle, linkid, buf, sizeof (buf)))
1929 	    != DLADM_STATUS_OK)
1930 		goto done;
1931 
1932 	(void) memcpy(&mode, buf, sizeof (mode));
1933 	switch (mode.wl_ps_mode) {
1934 	case WL_PM_AM:
1935 		s = "off";
1936 		break;
1937 	case WL_PM_MPS:
1938 		s = "max";
1939 		break;
1940 	case WL_PM_FAST:
1941 		s = "fast";
1942 		break;
1943 	default:
1944 		status = DLADM_STATUS_NOTFOUND;
1945 		goto done;
1946 	}
1947 	(void) snprintf(*prop_val, DLADM_STRSIZE, "%s", s);
1948 	*val_cnt = 1;
1949 	*perm_flags = MAC_PROP_PERM_RW;
1950 done:
1951 	return (status);
1952 }
1953 
1954 static dladm_status_t
1955 do_set_powermode(dladm_handle_t handle, datalink_id_t linkid,
1956     dladm_wlan_powermode_t *pm)
1957 {
1958 	wl_ps_mode_t    ps_mode;
1959 
1960 	(void) memset(&ps_mode, 0xff, sizeof (ps_mode));
1961 
1962 	switch (*pm) {
1963 	case DLADM_WLAN_PM_OFF:
1964 		ps_mode.wl_ps_mode = WL_PM_AM;
1965 		break;
1966 	case DLADM_WLAN_PM_MAX:
1967 		ps_mode.wl_ps_mode = WL_PM_MPS;
1968 		break;
1969 	case DLADM_WLAN_PM_FAST:
1970 		ps_mode.wl_ps_mode = WL_PM_FAST;
1971 		break;
1972 	default:
1973 		return (DLADM_STATUS_NOTSUP);
1974 	}
1975 	return (i_dladm_wlan_param(handle, linkid, &ps_mode,
1976 	    MAC_PROP_WL_POWER_MODE, sizeof (ps_mode), B_TRUE));
1977 }
1978 
1979 /* ARGSUSED */
1980 static dladm_status_t
1981 do_set_powermode_prop(dladm_handle_t handle, prop_desc_t *pdp,
1982     datalink_id_t linkid, val_desc_t *vdp, uint_t val_cnt, uint_t flags,
1983     datalink_media_t media)
1984 {
1985 	dladm_wlan_powermode_t powermode = (dladm_wlan_powermode_t)vdp->vd_val;
1986 	dladm_status_t status;
1987 
1988 	if (val_cnt != 1)
1989 		return (DLADM_STATUS_BADVALCNT);
1990 
1991 	status = do_set_powermode(handle, linkid, &powermode);
1992 
1993 	return (status);
1994 }
1995 
1996 static dladm_status_t
1997 do_get_radio(dladm_handle_t handle, datalink_id_t linkid, void *buf, int buflen)
1998 {
1999 	return (i_dladm_wlan_param(handle, linkid, buf, MAC_PROP_WL_RADIO,
2000 	    buflen, B_FALSE));
2001 }
2002 
2003 /* ARGSUSED */
2004 static dladm_status_t
2005 do_get_radio_prop(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
2006     char **prop_val, uint_t *val_cnt, datalink_media_t media,
2007     uint_t flags, uint_t *perm_flags)
2008 {
2009 	wl_radio_t	radio;
2010 	const char	*s;
2011 	char		buf[WLDP_BUFSIZE];
2012 	dladm_status_t	status = DLADM_STATUS_OK;
2013 
2014 	if ((status = do_get_radio(handle, linkid, buf, sizeof (buf)))
2015 	    != DLADM_STATUS_OK)
2016 		goto done;
2017 
2018 	(void) memcpy(&radio, buf, sizeof (radio));
2019 	switch (radio) {
2020 	case B_TRUE:
2021 		s = "on";
2022 		break;
2023 	case B_FALSE:
2024 		s = "off";
2025 		break;
2026 	default:
2027 		status = DLADM_STATUS_NOTFOUND;
2028 		goto done;
2029 	}
2030 	(void) snprintf(*prop_val, DLADM_STRSIZE, "%s", s);
2031 	*val_cnt = 1;
2032 	*perm_flags = MAC_PROP_PERM_RW;
2033 done:
2034 	return (status);
2035 }
2036 
2037 static dladm_status_t
2038 do_set_radio(dladm_handle_t handle, datalink_id_t linkid,
2039     dladm_wlan_radio_t *radio)
2040 {
2041 	wl_radio_t r;
2042 
2043 	switch (*radio) {
2044 	case DLADM_WLAN_RADIO_ON:
2045 		r = B_TRUE;
2046 		break;
2047 	case DLADM_WLAN_RADIO_OFF:
2048 		r = B_FALSE;
2049 		break;
2050 	default:
2051 		return (DLADM_STATUS_NOTSUP);
2052 	}
2053 	return (i_dladm_wlan_param(handle, linkid, &r, MAC_PROP_WL_RADIO,
2054 	    sizeof (r), B_TRUE));
2055 }
2056 
2057 /* ARGSUSED */
2058 static dladm_status_t
2059 do_set_radio_prop(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
2060     val_desc_t *vdp, uint_t val_cnt, uint_t fags, datalink_media_t media)
2061 {
2062 	dladm_wlan_radio_t radio = (dladm_wlan_radio_t)vdp->vd_val;
2063 	dladm_status_t status;
2064 
2065 	if (val_cnt != 1)
2066 		return (DLADM_STATUS_BADVALCNT);
2067 
2068 	status = do_set_radio(handle, linkid, &radio);
2069 
2070 	return (status);
2071 }
2072 
2073 static dladm_status_t
2074 i_dladm_set_linkprop_db(dladm_handle_t handle, datalink_id_t linkid,
2075     const char *prop_name, char **prop_val, uint_t val_cnt)
2076 {
2077 	char		buf[MAXLINELEN];
2078 	int		i;
2079 	dladm_conf_t	conf;
2080 	dladm_status_t	status;
2081 
2082 	status = dladm_read_conf(handle, linkid, &conf);
2083 	if (status != DLADM_STATUS_OK)
2084 		return (status);
2085 
2086 	/*
2087 	 * reset case.
2088 	 */
2089 	if (val_cnt == 0) {
2090 		status = dladm_unset_conf_field(handle, conf, prop_name);
2091 		if (status == DLADM_STATUS_OK)
2092 			status = dladm_write_conf(handle, conf);
2093 		goto done;
2094 	}
2095 
2096 	buf[0] = '\0';
2097 	for (i = 0; i < val_cnt; i++) {
2098 		(void) strlcat(buf, prop_val[i], MAXLINELEN);
2099 		if (i != val_cnt - 1)
2100 			(void) strlcat(buf, ",", MAXLINELEN);
2101 	}
2102 
2103 	status = dladm_set_conf_field(handle, conf, prop_name, DLADM_TYPE_STR,
2104 	    buf);
2105 	if (status == DLADM_STATUS_OK)
2106 		status = dladm_write_conf(handle, conf);
2107 
2108 done:
2109 	dladm_destroy_conf(handle, conf);
2110 	return (status);
2111 }
2112 
2113 static dladm_status_t
2114 i_dladm_get_linkprop_db(dladm_handle_t handle, datalink_id_t linkid,
2115     const char *prop_name, char **prop_val, uint_t *val_cntp)
2116 {
2117 	char		buf[MAXLINELEN], *str;
2118 	uint_t		cnt = 0;
2119 	dladm_conf_t	conf;
2120 	dladm_status_t	status;
2121 
2122 	status = dladm_read_conf(handle, linkid, &conf);
2123 	if (status != DLADM_STATUS_OK)
2124 		return (status);
2125 
2126 	status = dladm_get_conf_field(handle, conf, prop_name, buf, MAXLINELEN);
2127 	if (status != DLADM_STATUS_OK)
2128 		goto done;
2129 
2130 	str = strtok(buf, ",");
2131 	while (str != NULL) {
2132 		if (cnt == *val_cntp) {
2133 			status = DLADM_STATUS_TOOSMALL;
2134 			goto done;
2135 		}
2136 		(void) strlcpy(prop_val[cnt++], str, DLADM_PROP_VAL_MAX);
2137 		str = strtok(NULL, ",");
2138 	}
2139 
2140 	*val_cntp = cnt;
2141 
2142 done:
2143 	dladm_destroy_conf(handle, conf);
2144 	return (status);
2145 }
2146 
2147 static link_attr_t *
2148 dladm_name2prop(const char *prop_name)
2149 {
2150 	link_attr_t *p;
2151 
2152 	for (p = link_attr; p->pp_id != MAC_PROP_PRIVATE; p++) {
2153 		if (strcmp(p->pp_name, prop_name) == 0)
2154 			break;
2155 	}
2156 	return (p);
2157 }
2158 
2159 static link_attr_t *
2160 dladm_id2prop(mac_prop_id_t propid)
2161 {
2162 	link_attr_t *p;
2163 
2164 	for (p = link_attr; p->pp_id != MAC_PROP_PRIVATE; p++) {
2165 		if (p->pp_id == propid)
2166 			break;
2167 	}
2168 	return (p);
2169 }
2170 
2171 static dld_ioc_macprop_t *
2172 i_dladm_buf_alloc_impl(size_t valsize, datalink_id_t linkid,
2173     const char *prop_name, mac_prop_id_t propid, uint_t flags,
2174     dladm_status_t *status)
2175 {
2176 	int dsize;
2177 	dld_ioc_macprop_t *dip;
2178 
2179 	*status = DLADM_STATUS_OK;
2180 	dsize = MAC_PROP_BUFSIZE(valsize);
2181 	dip = malloc(dsize);
2182 	if (dip == NULL) {
2183 		*status = DLADM_STATUS_NOMEM;
2184 		return (NULL);
2185 	}
2186 	bzero(dip, dsize);
2187 	dip->pr_valsize = valsize;
2188 	(void) strlcpy(dip->pr_name, prop_name, sizeof (dip->pr_name));
2189 	dip->pr_version = MAC_PROP_VERSION;
2190 	dip->pr_linkid = linkid;
2191 	dip->pr_num = propid;
2192 	dip->pr_flags = flags;
2193 	return (dip);
2194 }
2195 
2196 static dld_ioc_macprop_t *
2197 i_dladm_buf_alloc_by_name(size_t valsize, datalink_id_t linkid,
2198     const char *prop_name, uint_t flags, dladm_status_t *status)
2199 {
2200 	link_attr_t *p;
2201 
2202 	p = dladm_name2prop(prop_name);
2203 	valsize = MAX(p->pp_valsize, valsize);
2204 	return (i_dladm_buf_alloc_impl(valsize, linkid, prop_name, p->pp_id,
2205 	    flags, status));
2206 }
2207 
2208 static dld_ioc_macprop_t *
2209 i_dladm_buf_alloc_by_id(size_t valsize, datalink_id_t linkid,
2210     mac_prop_id_t propid, uint_t flags, dladm_status_t *status)
2211 {
2212 	link_attr_t *p;
2213 
2214 	p = dladm_id2prop(propid);
2215 	valsize = MAX(p->pp_valsize, valsize);
2216 	return (i_dladm_buf_alloc_impl(valsize, linkid, p->pp_name, propid,
2217 	    flags, status));
2218 }
2219 
2220 /* ARGSUSED */
2221 static dladm_status_t
2222 i_dladm_set_public_prop(dladm_handle_t handle, prop_desc_t *pdp,
2223     datalink_id_t linkid, val_desc_t *vdp, uint_t val_cnt, uint_t flags,
2224     datalink_media_t media)
2225 {
2226 	dld_ioc_macprop_t	*dip;
2227 	dladm_status_t	status = DLADM_STATUS_OK;
2228 	uint8_t		u8;
2229 	uint16_t	u16;
2230 	uint32_t	u32;
2231 	void		*val;
2232 
2233 	dip = i_dladm_buf_alloc_by_name(0, linkid, pdp->pd_name, 0, &status);
2234 	if (dip == NULL)
2235 		return (status);
2236 
2237 	if (pdp->pd_flags & PD_CHECK_ALLOC)
2238 		val = (void *)vdp->vd_val;
2239 	else {
2240 		/*
2241 		 * Currently all 1/2/4-byte size properties are byte/word/int.
2242 		 * No need (yet) to distinguish these from arrays of same size.
2243 		 */
2244 		switch (dip->pr_valsize) {
2245 		case 1:
2246 			u8 = vdp->vd_val;
2247 			val = &u8;
2248 			break;
2249 		case 2:
2250 			u16 = vdp->vd_val;
2251 			val = &u16;
2252 			break;
2253 		case 4:
2254 			u32 = vdp->vd_val;
2255 			val = &u32;
2256 			break;
2257 		default:
2258 			val = &vdp->vd_val;
2259 			break;
2260 		}
2261 	}
2262 
2263 	if (val != NULL)
2264 		(void) memcpy(dip->pr_val, val, dip->pr_valsize);
2265 	else
2266 		dip->pr_valsize = 0;
2267 
2268 	status = i_dladm_macprop(handle, dip, B_TRUE);
2269 
2270 done:
2271 	free(dip);
2272 	return (status);
2273 }
2274 
2275 dladm_status_t
2276 i_dladm_macprop(dladm_handle_t handle, void *dip, boolean_t set)
2277 {
2278 	dladm_status_t status = DLADM_STATUS_OK;
2279 
2280 	if (ioctl(dladm_dld_fd(handle),
2281 	    (set ? DLDIOC_SETMACPROP : DLDIOC_GETMACPROP), dip))
2282 		status = dladm_errno2status(errno);
2283 
2284 	return (status);
2285 }
2286 
2287 static dld_ioc_macprop_t *
2288 i_dladm_get_public_prop(dladm_handle_t handle, datalink_id_t linkid,
2289     char *prop_name, uint_t flags, dladm_status_t *status, uint_t *perm_flags)
2290 {
2291 	dld_ioc_macprop_t *dip = NULL;
2292 
2293 	dip = i_dladm_buf_alloc_by_name(0, linkid, prop_name, flags, status);
2294 	if (dip == NULL)
2295 		return (NULL);
2296 
2297 	*status = i_dladm_macprop(handle, dip, B_FALSE);
2298 	if (*status != DLADM_STATUS_OK) {
2299 		free(dip);
2300 		return (NULL);
2301 	}
2302 	if (perm_flags != NULL)
2303 		*perm_flags = dip->pr_perm_flags;
2304 
2305 	return (dip);
2306 }
2307 
2308 /* ARGSUSED */
2309 static dladm_status_t
2310 i_dladm_defmtu_check(dladm_handle_t handle, prop_desc_t *pdp,
2311     datalink_id_t linkid, char **prop_val, uint_t val_cnt, val_desc_t *v,
2312     datalink_media_t media)
2313 {
2314 	if (val_cnt != 1)
2315 		return (DLADM_STATUS_BADVAL);
2316 	v->vd_val = atoi(prop_val[0]);
2317 	return (DLADM_STATUS_OK);
2318 }
2319 
2320 /* ARGSUSED */
2321 static dladm_status_t
2322 i_dladm_duplex_get(dladm_handle_t handle, prop_desc_t *pdp,
2323     datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
2324     datalink_media_t media, uint_t flags, uint_t *perm_flags)
2325 {
2326 	link_duplex_t   link_duplex;
2327 	dladm_status_t  status;
2328 
2329 	if ((status = dladm_get_single_mac_stat(handle, linkid, "link_duplex",
2330 	    KSTAT_DATA_UINT32, &link_duplex)) != 0)
2331 		return (status);
2332 
2333 	switch (link_duplex) {
2334 	case LINK_DUPLEX_FULL:
2335 		(void) strcpy(*prop_val, "full");
2336 		break;
2337 	case LINK_DUPLEX_HALF:
2338 		(void) strcpy(*prop_val, "half");
2339 		break;
2340 	default:
2341 		(void) strcpy(*prop_val, "unknown");
2342 		break;
2343 	}
2344 	*val_cnt = 1;
2345 	return (DLADM_STATUS_OK);
2346 }
2347 
2348 /* ARGSUSED */
2349 static dladm_status_t
2350 i_dladm_speed_get(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
2351     char **prop_val, uint_t *val_cnt, uint_t flags, uint_t *perm_flags)
2352 {
2353 	uint64_t	ifspeed = 0;
2354 	dladm_status_t status;
2355 
2356 	if ((status = dladm_get_single_mac_stat(handle, linkid, "ifspeed",
2357 	    KSTAT_DATA_UINT64, &ifspeed)) != 0)
2358 		return (status);
2359 
2360 	if ((ifspeed % 1000000) != 0) {
2361 		(void) snprintf(*prop_val, DLADM_PROP_VAL_MAX,
2362 		    "%llf", ifspeed / (float)1000000); /* Mbps */
2363 	} else {
2364 		(void) snprintf(*prop_val, DLADM_PROP_VAL_MAX,
2365 		    "%llu", ifspeed / 1000000); /* Mbps */
2366 	}
2367 	*val_cnt = 1;
2368 	*perm_flags = MAC_PROP_PERM_READ;
2369 	return (DLADM_STATUS_OK);
2370 }
2371 
2372 /* ARGSUSED */
2373 static dladm_status_t
2374 i_dladm_status_get(dladm_handle_t handle, prop_desc_t *pdp,
2375     datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
2376     datalink_media_t media, uint_t flags, uint_t *perm_flags)
2377 {
2378 	link_state_t		link_state;
2379 	dladm_status_t		status;
2380 
2381 	status = i_dladm_get_state(handle, linkid, &link_state);
2382 	if (status != DLADM_STATUS_OK)
2383 		return (status);
2384 
2385 	switch (link_state) {
2386 	case LINK_STATE_UP:
2387 		(void) strcpy(*prop_val, "up");
2388 		break;
2389 	case LINK_STATE_DOWN:
2390 		(void) strcpy(*prop_val, "down");
2391 		break;
2392 	default:
2393 		(void) strcpy(*prop_val, "unknown");
2394 		break;
2395 	}
2396 	*val_cnt = 1;
2397 	*perm_flags = MAC_PROP_PERM_READ;
2398 	return (DLADM_STATUS_OK);
2399 }
2400 
2401 /* ARGSUSED */
2402 static dladm_status_t
2403 i_dladm_binary_get(dladm_handle_t handle, prop_desc_t *pdp,
2404     datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
2405     datalink_media_t media, uint_t flags, uint_t *perm_flags)
2406 {
2407 	dld_ioc_macprop_t *dip;
2408 	dladm_status_t status;
2409 
2410 	dip = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags,
2411 	    &status, perm_flags);
2412 	if (dip == NULL)
2413 		return (status);
2414 
2415 	(void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "%x", dip->pr_val[0]);
2416 	free(dip);
2417 	*val_cnt = 1;
2418 	return (DLADM_STATUS_OK);
2419 }
2420 
2421 /* ARGSUSED */
2422 static dladm_status_t
2423 i_dladm_uint32_get(dladm_handle_t handle, prop_desc_t *pdp,
2424     datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
2425     datalink_media_t media, uint_t flags, uint_t *perm_flags)
2426 {
2427 	dld_ioc_macprop_t *dip;
2428 	uint32_t v = 0;
2429 	uchar_t *cp;
2430 	dladm_status_t status;
2431 
2432 	dip = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags,
2433 	    &status, perm_flags);
2434 	if (dip == NULL)
2435 		return (status);
2436 
2437 	cp = (uchar_t *)dip->pr_val;
2438 	(void) memcpy(&v, cp, sizeof (v));
2439 	(void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "%ld", v);
2440 	free(dip);
2441 	*val_cnt = 1;
2442 	return (DLADM_STATUS_OK);
2443 }
2444 
2445 /* ARGSUSED */
2446 static dladm_status_t
2447 i_dladm_flowctl_get(dladm_handle_t handle, prop_desc_t *pdp,
2448     datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
2449     datalink_media_t media, uint_t flags, uint_t *perm_flags)
2450 {
2451 	dld_ioc_macprop_t *dip;
2452 	link_flowctrl_t v;
2453 	dladm_status_t status;
2454 	uchar_t *cp;
2455 
2456 	dip = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags,
2457 	    &status, perm_flags);
2458 	if (dip == NULL)
2459 		return (status);
2460 
2461 	cp = (uchar_t *)dip->pr_val;
2462 	(void) memcpy(&v, cp, sizeof (v));
2463 	switch (v) {
2464 	case LINK_FLOWCTRL_NONE:
2465 		(void) sprintf(*prop_val, "no");
2466 		break;
2467 	case LINK_FLOWCTRL_RX:
2468 		(void) sprintf(*prop_val, "rx");
2469 		break;
2470 	case LINK_FLOWCTRL_TX:
2471 		(void) sprintf(*prop_val, "tx");
2472 		break;
2473 	case LINK_FLOWCTRL_BI:
2474 		(void) sprintf(*prop_val, "bi");
2475 		break;
2476 	}
2477 	free(dip);
2478 	*val_cnt = 1;
2479 	return (DLADM_STATUS_OK);
2480 }
2481 
2482 
2483 /* ARGSUSED */
2484 static dladm_status_t
2485 i_dladm_set_prop(dladm_handle_t handle, datalink_id_t linkid,
2486     const char *prop_name, char **prop_val, uint_t val_cnt, uint_t flags)
2487 
2488 {
2489 	int		i, slen;
2490 	int 		bufsize = 0;
2491 	dld_ioc_macprop_t *dip = NULL;
2492 	uchar_t 	*dp;
2493 	link_attr_t *p;
2494 	dladm_status_t	status = DLADM_STATUS_OK;
2495 
2496 	if ((prop_name == NULL && prop_val != NULL) ||
2497 	    (prop_val != NULL && val_cnt == 0))
2498 		return (DLADM_STATUS_BADARG);
2499 	p = dladm_name2prop(prop_name);
2500 	if (p->pp_id != MAC_PROP_PRIVATE)
2501 		return (DLADM_STATUS_BADARG);
2502 
2503 	/*
2504 	 * private properties: all parsing is done in the kernel.
2505 	 * allocate a enough space for each property + its separator (',').
2506 	 */
2507 	for (i = 0; i < val_cnt; i++) {
2508 		bufsize += strlen(prop_val[i]) + 1;
2509 	}
2510 
2511 	if (prop_val == NULL) {
2512 		/*
2513 		 * getting default value. so use more buffer space.
2514 		 */
2515 		bufsize += DLADM_PROP_BUF_CHUNK;
2516 	}
2517 
2518 	dip = i_dladm_buf_alloc_by_name(bufsize + 1, linkid, prop_name,
2519 	    (prop_val != NULL ? 0 : MAC_PROP_DEFAULT), &status);
2520 	if (dip == NULL)
2521 		return (status);
2522 
2523 	dp = (uchar_t *)dip->pr_val;
2524 	slen = 0;
2525 
2526 	if (prop_val == NULL) {
2527 		status = i_dladm_macprop(handle, dip, B_FALSE);
2528 	} else {
2529 		for (i = 0; i < val_cnt; i++) {
2530 			int plen = 0;
2531 
2532 			plen = strlen(prop_val[i]);
2533 			bcopy(prop_val[i], dp, plen);
2534 			slen += plen;
2535 			/*
2536 			 * add a "," separator and update dp.
2537 			 */
2538 			if (i != (val_cnt -1))
2539 				dp[slen++] = ',';
2540 			dp += (plen + 1);
2541 		}
2542 		status = i_dladm_macprop(handle, dip, B_TRUE);
2543 	}
2544 
2545 	free(dip);
2546 	return (status);
2547 }
2548 
2549 static dladm_status_t
2550 i_dladm_get_prop(dladm_handle_t handle, datalink_id_t linkid,
2551     const char *prop_name, char **prop_val, uint_t *val_cnt,
2552     dladm_prop_type_t type, uint_t dld_flags)
2553 {
2554 	dladm_status_t	status = DLADM_STATUS_OK;
2555 	dld_ioc_macprop_t *dip = NULL;
2556 	link_attr_t *p;
2557 	char tmp = '\0';
2558 
2559 	if ((prop_name == NULL && prop_val != NULL) ||
2560 	    (prop_val != NULL && val_cnt == 0))
2561 		return (DLADM_STATUS_BADARG);
2562 
2563 	p = dladm_name2prop(prop_name);
2564 	if (p->pp_id != MAC_PROP_PRIVATE)
2565 		return (DLADM_STATUS_BADARG);
2566 
2567 	if (type == DLADM_PROP_VAL_MODIFIABLE) {
2568 		*prop_val = &tmp;
2569 		*val_cnt = 1;
2570 		return (DLADM_STATUS_OK);
2571 	}
2572 
2573 	/*
2574 	 * private properties: all parsing is done in the kernel.
2575 	 */
2576 	dip = i_dladm_buf_alloc_by_name(DLADM_PROP_BUF_CHUNK, linkid, prop_name,
2577 	    dld_flags, &status);
2578 	if (dip == NULL)
2579 		return (status);
2580 
2581 	if ((status = i_dladm_macprop(handle, dip, B_FALSE)) ==
2582 	    DLADM_STATUS_OK) {
2583 		if (type == DLADM_PROP_VAL_PERM) {
2584 			(void) dladm_perm2str(dip->pr_perm_flags, *prop_val);
2585 		} else {
2586 			(void) strncpy(*prop_val, dip->pr_val,
2587 			    DLADM_PROP_VAL_MAX);
2588 		}
2589 		*val_cnt = 1;
2590 	}
2591 	free(dip);
2592 	return (status);
2593 }
2594 
2595 
2596 static dladm_status_t
2597 i_dladm_getset_defval(dladm_handle_t handle, prop_desc_t *pdp,
2598     datalink_id_t linkid, datalink_media_t media, uint_t flags)
2599 {
2600 	dladm_status_t status;
2601 	char **prop_vals = NULL, *buf;
2602 	size_t bufsize;
2603 	uint_t cnt;
2604 	int i;
2605 	uint_t perm_flags;
2606 
2607 	/*
2608 	 * Allocate buffer needed for prop_vals array. We can have at most
2609 	 * DLADM_MAX_PROP_VALCNT char *prop_vals[] entries, where
2610 	 * each entry has max size DLADM_PROP_VAL_MAX
2611 	 */
2612 	bufsize =
2613 	    (sizeof (char *) + DLADM_PROP_VAL_MAX) * DLADM_MAX_PROP_VALCNT;
2614 	buf = malloc(bufsize);
2615 	prop_vals = (char **)(void *)buf;
2616 	for (i = 0; i < DLADM_MAX_PROP_VALCNT; i++) {
2617 		prop_vals[i] = buf +
2618 		    sizeof (char *) * DLADM_MAX_PROP_VALCNT +
2619 		    i * DLADM_PROP_VAL_MAX;
2620 	}
2621 
2622 	/*
2623 	 * For properties which have pdp->pd_defval.vd_name as a non-empty
2624 	 * string, the "" itself is used to reset the property (exceptions
2625 	 * are zone and autopush, which populate vdp->vd_val). So
2626 	 * libdladm can copy pdp->pd_defval over to the val_desc_t passed
2627 	 * down on the setprop using the global values in the table. For
2628 	 * other cases (vd_name is ""), doing reset-linkprop will cause
2629 	 * libdladm to do a getprop to find the default value and then do
2630 	 * a setprop to reset the value to default.
2631 	 */
2632 	status = pdp->pd_get(handle, pdp, linkid, prop_vals, &cnt, media,
2633 	    MAC_PROP_DEFAULT, &perm_flags);
2634 	if (status == DLADM_STATUS_OK) {
2635 		if (perm_flags == MAC_PROP_PERM_RW) {
2636 			status = i_dladm_set_single_prop(handle, linkid,
2637 			    pdp->pd_class, media, pdp, prop_vals, cnt, flags);
2638 		}
2639 		else
2640 			status = DLADM_STATUS_NOTSUP;
2641 	}
2642 	free(buf);
2643 	return (status);
2644 }
2645 
2646 int
2647 macprop_to_wifi(mac_prop_id_t wl_prop)
2648 {
2649 	switch (wl_prop) {
2650 	case MAC_PROP_WL_ESSID:
2651 		return (WL_ESSID);
2652 	case MAC_PROP_WL_BSSID:
2653 		return (WL_BSSID);
2654 	case MAC_PROP_WL_BSSTYPE:
2655 		return (WL_BSS_TYPE);
2656 	case MAC_PROP_WL_LINKSTATUS:
2657 		return (WL_LINKSTATUS);
2658 	case MAC_PROP_WL_DESIRED_RATES:
2659 		return (WL_DESIRED_RATES);
2660 	case MAC_PROP_WL_SUPPORTED_RATES:
2661 		return (WL_SUPPORTED_RATES);
2662 	case MAC_PROP_WL_AUTH_MODE:
2663 		return (WL_AUTH_MODE);
2664 	case MAC_PROP_WL_ENCRYPTION:
2665 		return (WL_ENCRYPTION);
2666 	case MAC_PROP_WL_RSSI:
2667 		return (WL_RSSI);
2668 	case MAC_PROP_WL_PHY_CONFIG:
2669 		return (WL_PHY_CONFIG);
2670 	case MAC_PROP_WL_CAPABILITY:
2671 		return (WL_CAPABILITY);
2672 	case MAC_PROP_WL_WPA:
2673 		return (WL_WPA);
2674 	case MAC_PROP_WL_SCANRESULTS:
2675 		return (WL_SCANRESULTS);
2676 	case MAC_PROP_WL_POWER_MODE:
2677 		return (WL_POWER_MODE);
2678 	case MAC_PROP_WL_RADIO:
2679 		return (WL_RADIO);
2680 	case MAC_PROP_WL_ESS_LIST:
2681 		return (WL_ESS_LIST);
2682 	case MAC_PROP_WL_KEY_TAB:
2683 		return (WL_WEP_KEY_TAB);
2684 	case MAC_PROP_WL_CREATE_IBSS:
2685 		return (WL_CREATE_IBSS);
2686 	case MAC_PROP_WL_SETOPTIE:
2687 		return (WL_SETOPTIE);
2688 	case MAC_PROP_WL_DELKEY:
2689 		return (WL_DELKEY);
2690 	case MAC_PROP_WL_KEY:
2691 		return (WL_KEY);
2692 	case MAC_PROP_WL_MLME:
2693 		return (WL_MLME);
2694 	default:
2695 		return (-1);
2696 	}
2697 }
2698 
2699 dladm_status_t
2700 i_dladm_wlan_param(dladm_handle_t handle, datalink_id_t linkid, void *buf,
2701     mac_prop_id_t cmd, size_t len, boolean_t set)
2702 {
2703 	uint32_t		flags;
2704 	dladm_status_t		status;
2705 	uint32_t		media;
2706 	dld_ioc_macprop_t	*dip;
2707 	void			*dp;
2708 
2709 	if ((status = dladm_datalink_id2info(handle, linkid, &flags, NULL,
2710 	    &media, NULL, 0)) != DLADM_STATUS_OK) {
2711 		return (status);
2712 	}
2713 
2714 	if (media != DL_WIFI)
2715 		return (DLADM_STATUS_BADARG);
2716 
2717 	if (!(flags & DLADM_OPT_ACTIVE))
2718 		return (DLADM_STATUS_TEMPONLY);
2719 
2720 	if (len == (MAX_BUF_LEN - WIFI_BUF_OFFSET))
2721 		len = MAX_BUF_LEN - sizeof (dld_ioc_macprop_t) - 1;
2722 
2723 	dip = i_dladm_buf_alloc_by_id(len, linkid, cmd, 0, &status);
2724 	if (dip == NULL)
2725 		return (DLADM_STATUS_NOMEM);
2726 
2727 	dp = (uchar_t *)dip->pr_val;
2728 	if (set)
2729 		(void) memcpy(dp, buf, len);
2730 
2731 	status = i_dladm_macprop(handle, dip, set);
2732 	if (status == DLADM_STATUS_NOTSUP) {
2733 		if (set) {
2734 			status = i_dladm_wlan_set_legacy_ioctl(handle, linkid,
2735 			    buf, len, macprop_to_wifi(cmd));
2736 		} else {
2737 			status = i_dladm_wlan_get_legacy_ioctl(handle, linkid,
2738 			    buf, len, macprop_to_wifi(cmd));
2739 		}
2740 	} else if (status == DLADM_STATUS_OK) {
2741 		if (!set)
2742 			(void) memcpy(buf, dp, len);
2743 	}
2744 
2745 	free(dip);
2746 	return (status);
2747 }
2748 
2749 static dladm_status_t
2750 i_dladm_wlan_get_legacy_ioctl(dladm_handle_t handle, datalink_id_t linkid,
2751     void *buf, uint_t buflen, uint_t id)
2752 {
2753 	wldp_t *gbuf;
2754 	dladm_status_t status;
2755 
2756 	if ((gbuf = malloc(MAX_BUF_LEN)) == NULL)
2757 		return (DLADM_STATUS_NOMEM);
2758 
2759 	(void) memset(gbuf, 0, MAX_BUF_LEN);
2760 	status = i_dladm_wlan_legacy_ioctl(handle, linkid, gbuf, id,
2761 	    MAX_BUF_LEN, WLAN_GET_PARAM, sizeof (wldp_t));
2762 	if (status == DLADM_STATUS_OK)
2763 		(void) memcpy(buf, gbuf->wldp_buf, buflen);
2764 
2765 	free(gbuf);
2766 	return (status);
2767 }
2768 
2769 static dladm_status_t
2770 i_dladm_wlan_set_legacy_ioctl(dladm_handle_t handle, datalink_id_t linkid,
2771     void *buf, uint_t buflen, uint_t id)
2772 {
2773 	wldp_t *gbuf;
2774 	dladm_status_t status = DLADM_STATUS_OK;
2775 
2776 	if ((gbuf = malloc(MAX_BUF_LEN)) == NULL)
2777 		return (DLADM_STATUS_NOMEM);
2778 
2779 	(void) memset(gbuf, 0, MAX_BUF_LEN);
2780 	(void) memcpy(gbuf->wldp_buf, buf, buflen);
2781 	buflen += WIFI_BUF_OFFSET;
2782 	status = i_dladm_wlan_legacy_ioctl(handle, linkid, gbuf, id, buflen,
2783 	    WLAN_SET_PARAM, buflen);
2784 
2785 	free(gbuf);
2786 	return (status);
2787 }
2788 
2789 static dladm_status_t
2790 link_proplist_check(dladm_arg_list_t *proplist)
2791 {
2792 	int		i, j;
2793 	boolean_t	matched;
2794 
2795 	for (i = 0; i < proplist->al_count; i++) {
2796 		matched = B_FALSE;
2797 		for (j = 0; j < DLADM_MAX_PROPS; j++) {
2798 			if (strcmp(proplist->al_info[i].ai_name,
2799 			    prop_table[j].pd_name) == 0)
2800 				matched = B_TRUE;
2801 		}
2802 		if (!matched)
2803 			return (DLADM_STATUS_BADPROP);
2804 	}
2805 	return (DLADM_STATUS_OK);
2806 }
2807 
2808 dladm_status_t
2809 dladm_parse_link_props(char *str, dladm_arg_list_t **listp, boolean_t novalues)
2810 {
2811 	dladm_status_t	status;
2812 
2813 	status = dladm_parse_args(str, listp, novalues);
2814 	if (status != DLADM_STATUS_OK)
2815 		return (status);
2816 
2817 	status = link_proplist_check(*listp);
2818 	if (status != DLADM_STATUS_OK) {
2819 		dladm_free_props(*listp);
2820 		return (status);
2821 	}
2822 
2823 	return (DLADM_STATUS_OK);
2824 }
2825 
2826 /*
2827  * Retrieve the one link property from the database
2828  */
2829 /*ARGSUSED*/
2830 static int
2831 i_dladm_get_one_prop(dladm_handle_t handle, datalink_id_t linkid,
2832     const char *prop_name, void *arg)
2833 {
2834 	dladm_arg_list_t	*proplist = arg;
2835 	dladm_arg_info_t	*aip = NULL;
2836 
2837 	aip = &proplist->al_info[proplist->al_count];
2838 	/*
2839 	 * it is fine to point to prop_name since prop_name points to the
2840 	 * prop_table[n].pd_name.
2841 	 */
2842 	aip->ai_name = prop_name;
2843 
2844 	(void) dladm_get_linkprop(handle, linkid, DLADM_PROP_VAL_PERSISTENT,
2845 	    prop_name, aip->ai_val, &aip->ai_count);
2846 
2847 	if (aip->ai_count != 0)
2848 		proplist->al_count++;
2849 
2850 	return (DLADM_WALK_CONTINUE);
2851 }
2852 
2853 
2854 /*
2855  * Retrieve all link properties for a link from the database and
2856  * return a property list.
2857  */
2858 dladm_status_t
2859 dladm_link_get_proplist(dladm_handle_t handle, datalink_id_t linkid,
2860     dladm_arg_list_t **listp)
2861 {
2862 	dladm_arg_list_t	*list;
2863 	dladm_status_t		status = DLADM_STATUS_OK;
2864 
2865 	list = calloc(1, sizeof (dladm_arg_list_t));
2866 	if (list == NULL)
2867 		return (dladm_errno2status(errno));
2868 
2869 	status = dladm_walk_linkprop(handle, linkid, list,
2870 	    i_dladm_get_one_prop);
2871 
2872 	*listp = list;
2873 	return (status);
2874 }
2875 
2876 /*
2877  * Retrieve the named property from a proplist, check the value and
2878  * convert to a kernel structure.
2879  */
2880 static dladm_status_t
2881 i_dladm_link_proplist_extract_one(dladm_handle_t handle,
2882     dladm_arg_list_t *proplist, const char *name, void *val)
2883 {
2884 	dladm_status_t		status;
2885 	dladm_arg_info_t	*aip = NULL;
2886 	int			i, j;
2887 
2888 	/* Find named property in proplist */
2889 	for (i = 0; i < proplist->al_count; i++) {
2890 		aip = &proplist->al_info[i];
2891 		if (strcasecmp(aip->ai_name, name) == 0)
2892 			break;
2893 	}
2894 
2895 	/* Property not in list */
2896 	if (i == proplist->al_count)
2897 		return (DLADM_STATUS_OK);
2898 
2899 	for (i = 0; i < DLADM_MAX_PROPS; i++) {
2900 		prop_desc_t	*pdp = &prop_table[i];
2901 		val_desc_t	*vdp;
2902 
2903 		vdp = malloc(sizeof (val_desc_t) * aip->ai_count);
2904 		if (vdp == NULL)
2905 			return (DLADM_STATUS_NOMEM);
2906 
2907 		if (strcasecmp(aip->ai_name, pdp->pd_name) != 0)
2908 			continue;
2909 
2910 		if (aip->ai_val == NULL)
2911 			return (DLADM_STATUS_BADARG);
2912 
2913 		/* Check property value */
2914 		if (pdp->pd_check != NULL) {
2915 			status = pdp->pd_check(handle, pdp, 0, aip->ai_val,
2916 			    aip->ai_count, vdp, 0);
2917 		} else {
2918 			status = DLADM_STATUS_BADARG;
2919 		}
2920 
2921 		if (status != DLADM_STATUS_OK)
2922 			return (status);
2923 
2924 		for (j = 0; j < DLADM_MAX_RSRC_PROP; j++) {
2925 			resource_prop_t	*rpp = &rsrc_prop_table[j];
2926 
2927 			if (strcasecmp(aip->ai_name, rpp->rp_name) != 0)
2928 				continue;
2929 
2930 			/* Extract kernel structure */
2931 			if (rpp->rp_extract != NULL) {
2932 				status = rpp->rp_extract(vdp, val,
2933 				    aip->ai_count);
2934 			} else {
2935 				status = DLADM_STATUS_BADARG;
2936 			}
2937 			break;
2938 		}
2939 
2940 		if (status != DLADM_STATUS_OK)
2941 			return (status);
2942 
2943 		break;
2944 	}
2945 	return (status);
2946 }
2947 
2948 /*
2949  * Extract properties from a proplist and convert to mac_resource_props_t.
2950  */
2951 dladm_status_t
2952 dladm_link_proplist_extract(dladm_handle_t handle, dladm_arg_list_t *proplist,
2953     mac_resource_props_t *mrp)
2954 {
2955 	dladm_status_t	status = DLADM_STATUS_OK;
2956 
2957 	status = i_dladm_link_proplist_extract_one(handle, proplist, "maxbw",
2958 	    mrp);
2959 	if (status != DLADM_STATUS_OK)
2960 		return (status);
2961 	status = i_dladm_link_proplist_extract_one(handle, proplist, "priority",
2962 	    mrp);
2963 	if (status != DLADM_STATUS_OK)
2964 		return (status);
2965 	status = i_dladm_link_proplist_extract_one(handle, proplist, "cpus",
2966 	    mrp);
2967 	if (status != DLADM_STATUS_OK)
2968 		return (status);
2969 	return (status);
2970 }
2971 
2972 static const char *
2973 dladm_perm2str(uint_t perm, char *buf)
2974 {
2975 	(void) snprintf(buf, DLADM_STRSIZE, "%c%c",
2976 	    ((perm & MAC_PROP_PERM_READ) != 0) ? 'r' : '-',
2977 	    ((perm & MAC_PROP_PERM_WRITE) != 0) ? 'w' : '-');
2978 	return (buf);
2979 }
2980 
2981 dladm_status_t
2982 i_dladm_get_state(dladm_handle_t handle, datalink_id_t linkid,
2983     link_state_t *state)
2984 {
2985 	dld_ioc_macprop_t	*dip;
2986 	dladm_status_t		status;
2987 	uint_t			perms;
2988 
2989 	dip = i_dladm_get_public_prop(handle, linkid, "state", 0, &status,
2990 	    &perms);
2991 	if (status != DLADM_STATUS_OK)
2992 		return (status);
2993 	(void) memcpy(state, dip->pr_val, sizeof (*state));
2994 	free(dip);
2995 	return (status);
2996 }
2997