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