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