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 2010 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 <inttypes.h>
55 #include <sys/ethernet.h>
56 #include <inet/iptun.h>
57 #include <net/wpa.h>
58 #include <sys/sysmacros.h>
59 #include <sys/vlan.h>
60 #include <libdlbridge.h>
61 #include <stp_in.h>
62 #include <netinet/dhcp.h>
63 #include <netinet/dhcp6.h>
64 #include <net/if_types.h>
65 #include <libinetutil.h>
66 #include <pool.h>
67 
68 /*
69  * The linkprop get() callback.
70  * - pd: 	pointer to the prop_desc_t
71  * - propstrp:	a property string array to keep the returned property.
72  *		Caller allocated.
73  * - cntp:	number of returned properties.
74  *		Caller also uses it to indicate how many it expects.
75  */
76 struct prop_desc;
77 typedef struct prop_desc prop_desc_t;
78 
79 typedef dladm_status_t	pd_getf_t(dladm_handle_t, prop_desc_t *pdp,
80 			datalink_id_t, char **propstp, uint_t *cntp,
81 			datalink_media_t, uint_t, uint_t *);
82 
83 /*
84  * The linkprop set() callback.
85  * - propval:	a val_desc_t array which keeps the property values to be set.
86  * - cnt:	number of properties to be set.
87  * - flags: 	additional flags passed down the system call.
88  *
89  * pd_set takes val_desc_t given by pd_check(), translates it into
90  * a format suitable for kernel consumption. This may require allocation
91  * of ioctl buffers etc. pd_set() may call another common routine (used
92  * by all other pd_sets) which invokes the ioctl.
93  */
94 typedef dladm_status_t	pd_setf_t(dladm_handle_t, prop_desc_t *, datalink_id_t,
95 			    val_desc_t *propval, uint_t cnt, uint_t flags,
96 			    datalink_media_t);
97 
98 /*
99  * The linkprop check() callback.
100  * - propstrp:	property string array which keeps the property to be checked.
101  * - cnt:	number of properties.
102  * - propval:	return value; the property values of the given property strings.
103  *
104  * pd_check checks that the input values are valid. It does so by
105  * iteraring through the pd_modval list for the property. If
106  * the modifiable values cannot be expressed as a list, a pd_check
107  * specific to this property can be used. If the input values are
108  * verified to be valid, pd_check allocates a val_desc_t and fills it
109  * with either a val_desc_t found on the pd_modval list or something
110  * generated on the fly.
111  */
112 typedef dladm_status_t	pd_checkf_t(dladm_handle_t, prop_desc_t *pdp,
113 			    datalink_id_t, char **propstrp, uint_t cnt,
114 			    uint_t flags, val_desc_t *propval,
115 			    datalink_media_t);
116 
117 typedef struct link_attr_s {
118 	mac_prop_id_t	pp_id;
119 	size_t		pp_valsize;
120 	char		*pp_name;
121 } link_attr_t;
122 
123 typedef struct dladm_linkprop_args_s {
124 	dladm_status_t	dla_status;
125 	uint_t		dla_flags;
126 } dladm_linkprop_args_t;
127 
128 static dld_ioc_macprop_t *i_dladm_buf_alloc_by_name(size_t, datalink_id_t,
129 			    const char *, uint_t, dladm_status_t *);
130 static dld_ioc_macprop_t *i_dladm_buf_alloc_by_id(size_t, datalink_id_t,
131 			    mac_prop_id_t, uint_t, dladm_status_t *);
132 static dladm_status_t	i_dladm_get_public_prop(dladm_handle_t, datalink_id_t,
133 			    char *, uint_t, uint_t *, void *, size_t);
134 
135 static dladm_status_t	i_dladm_set_private_prop(dladm_handle_t, datalink_id_t,
136 			    const char *, char **, uint_t, uint_t);
137 static dladm_status_t	i_dladm_get_priv_prop(dladm_handle_t, datalink_id_t,
138 			    const char *, char **, uint_t *, dladm_prop_type_t,
139 			    uint_t);
140 static dladm_status_t	i_dladm_macprop(dladm_handle_t, void *, boolean_t);
141 static const char	*dladm_perm2str(uint_t, char *);
142 static link_attr_t	*dladm_name2prop(const char *);
143 static link_attr_t	*dladm_id2prop(mac_prop_id_t);
144 
145 static pd_getf_t	get_zone, get_autopush, get_rate_mod, get_rate,
146 			get_speed, get_channel, get_powermode, get_radio,
147 			get_duplex, get_link_state, get_binary, get_uint32,
148 			get_flowctl, get_maxbw, get_cpus, get_priority,
149 			get_tagmode, get_range, get_stp, get_bridge_forward,
150 			get_bridge_pvid, get_protection, get_rxrings,
151 			get_txrings, get_cntavail,
152 			get_allowedips, get_allowedcids, get_pool,
153 			get_rings_range;
154 
155 static pd_setf_t	set_zone, set_rate, set_powermode, set_radio,
156 			set_public_prop, set_resource, set_stp_prop,
157 			set_bridge_forward, set_bridge_pvid;
158 
159 static pd_checkf_t	check_zone, check_autopush, check_rate, check_hoplimit,
160 			check_encaplim, check_uint32, check_maxbw, check_cpus,
161 			check_stp_prop, check_bridge_pvid, check_allowedips,
162 			check_allowedcids, check_rings,
163 			check_pool, check_prop;
164 
165 struct prop_desc {
166 	/*
167 	 * link property name
168 	 */
169 	char			*pd_name;
170 
171 	/*
172 	 * default property value, can be set to { "", NULL }
173 	 */
174 	val_desc_t		pd_defval;
175 
176 	/*
177 	 * list of optional property values, can be NULL.
178 	 *
179 	 * This is set to non-NULL if there is a list of possible property
180 	 * values.  pd_optval would point to the array of possible values.
181 	 */
182 	val_desc_t		*pd_optval;
183 
184 	/*
185 	 * count of the above optional property values. 0 if pd_optval is NULL.
186 	 */
187 	uint_t			pd_noptval;
188 
189 	/*
190 	 * callback to set link property; set to NULL if this property is
191 	 * read-only and may be called before or after permanent update; see
192 	 * flags.
193 	 */
194 	pd_setf_t		*pd_set;
195 
196 	/*
197 	 * callback to get modifiable link property
198 	 */
199 	pd_getf_t		*pd_getmod;
200 
201 	/*
202 	 * callback to get current link property
203 	 */
204 	pd_getf_t		*pd_get;
205 
206 	/*
207 	 * callback to validate link property value, set to NULL if pd_optval
208 	 * is not NULL. In that case, validate the value by comparing it with
209 	 * the pd_optval. Return a val_desc_t array pointer if the value is
210 	 * valid.
211 	 */
212 	pd_checkf_t		*pd_check;
213 
214 	uint_t			pd_flags;
215 #define	PD_TEMPONLY	0x1	/* property is temporary only */
216 #define	PD_CHECK_ALLOC	0x2	/* alloc vd_val as part of pd_check */
217 #define	PD_AFTER_PERM	0x4	/* pd_set after db update; no temporary */
218 	/*
219 	 * indicate link classes this property applies to.
220 	 */
221 	datalink_class_t	pd_class;
222 
223 	/*
224 	 * indicate link media type this property applies to.
225 	 */
226 	datalink_media_t	pd_dmedia;
227 };
228 
229 #define	MAC_PROP_BUFSIZE(v)	sizeof (dld_ioc_macprop_t) + (v) - 1
230 
231 /*
232  * Supported link properties enumerated in the prop_table[] array are
233  * computed using the callback functions in that array. To compute the
234  * property value, multiple distinct system calls may be needed (e.g.,
235  * for wifi speed, we need to issue system calls to get desired/supported
236  * rates). The link_attr[] table enumerates the interfaces to the kernel,
237  * and the type/size of the data passed in the user-kernel interface.
238  */
239 static link_attr_t link_attr[] = {
240 	{ MAC_PROP_DUPLEX,	sizeof (link_duplex_t),	"duplex"},
241 
242 	{ MAC_PROP_SPEED,	sizeof (uint64_t),	"speed"},
243 
244 	{ MAC_PROP_STATUS,	sizeof (link_state_t),	"state"},
245 
246 	{ MAC_PROP_AUTONEG,	sizeof (uint8_t),	"adv_autoneg_cap"},
247 
248 	{ MAC_PROP_MTU,		sizeof (uint32_t),	"mtu"},
249 
250 	{ MAC_PROP_FLOWCTRL,	sizeof (link_flowctrl_t), "flowctrl"},
251 
252 	{ MAC_PROP_ZONE,	sizeof (dld_ioc_zid_t),	"zone"},
253 
254 	{ MAC_PROP_AUTOPUSH,	sizeof (struct dlautopush), "autopush"},
255 
256 	{ MAC_PROP_ADV_10GFDX_CAP, sizeof (uint8_t),	"adv_10gfdx_cap"},
257 
258 	{ MAC_PROP_EN_10GFDX_CAP, sizeof (uint8_t),	"en_10gfdx_cap"},
259 
260 	{ MAC_PROP_ADV_1000FDX_CAP, sizeof (uint8_t),	"adv_1000fdx_cap"},
261 
262 	{ MAC_PROP_EN_1000FDX_CAP, sizeof (uint8_t),	"en_1000fdx_cap"},
263 
264 	{ MAC_PROP_ADV_1000HDX_CAP, sizeof (uint8_t),	"adv_1000hdx_cap"},
265 
266 	{ MAC_PROP_EN_1000HDX_CAP, sizeof (uint8_t),	"en_1000hdx_cap"},
267 
268 	{ MAC_PROP_ADV_100FDX_CAP, sizeof (uint8_t),	"adv_100fdx_cap"},
269 
270 	{ MAC_PROP_EN_100FDX_CAP, sizeof (uint8_t),	"en_100fdx_cap"},
271 
272 	{ MAC_PROP_ADV_100HDX_CAP, sizeof (uint8_t),	"adv_100hdx_cap"},
273 
274 	{ MAC_PROP_EN_100HDX_CAP, sizeof (uint8_t),	"en_100hdx_cap"},
275 
276 	{ MAC_PROP_ADV_10FDX_CAP, sizeof (uint8_t),	"adv_10fdx_cap"},
277 
278 	{ MAC_PROP_EN_10FDX_CAP, sizeof (uint8_t),	"en_10fdx_cap"},
279 
280 	{ MAC_PROP_ADV_10HDX_CAP, sizeof (uint8_t),	"adv_10hdx_cap"},
281 
282 	{ MAC_PROP_EN_10HDX_CAP, sizeof (uint8_t),	"en_10hdx_cap"},
283 
284 	{ MAC_PROP_WL_ESSID,	sizeof (wl_linkstatus_t), "essid"},
285 
286 	{ MAC_PROP_WL_BSSID,	sizeof (wl_bssid_t),	"bssid"},
287 
288 	{ MAC_PROP_WL_BSSTYPE,	sizeof (wl_bss_type_t),	"bsstype"},
289 
290 	{ MAC_PROP_WL_LINKSTATUS, sizeof (wl_linkstatus_t), "wl_linkstatus"},
291 
292 	/* wl_rates_t has variable length */
293 	{ MAC_PROP_WL_DESIRED_RATES, sizeof (wl_rates_t), "desired_rates"},
294 
295 	/* wl_rates_t has variable length */
296 	{ MAC_PROP_WL_SUPPORTED_RATES, sizeof (wl_rates_t), "supported_rates"},
297 
298 	{ MAC_PROP_WL_AUTH_MODE, sizeof (wl_authmode_t), "authmode"},
299 
300 	{ MAC_PROP_WL_ENCRYPTION, sizeof (wl_encryption_t), "encryption"},
301 
302 	{ MAC_PROP_WL_RSSI,	sizeof (wl_rssi_t),	"signal"},
303 
304 	{ MAC_PROP_WL_PHY_CONFIG, sizeof (wl_phy_conf_t), "phy_conf"},
305 
306 	{ MAC_PROP_WL_CAPABILITY, sizeof (wl_capability_t), "capability"},
307 
308 	{ MAC_PROP_WL_WPA,	sizeof (wl_wpa_t),	"wpa"},
309 
310 	/*  wl_wpa_ess_t has variable length */
311 	{ MAC_PROP_WL_SCANRESULTS, sizeof (wl_wpa_ess_t), "scan_results"},
312 
313 	{ MAC_PROP_WL_POWER_MODE, sizeof (wl_ps_mode_t), "powermode"},
314 
315 	{ MAC_PROP_WL_RADIO,	sizeof (dladm_wlan_radio_t), "wl_radio"},
316 
317 	{ MAC_PROP_WL_ESS_LIST, sizeof (wl_ess_list_t),	"wl_ess_list"},
318 
319 	{ MAC_PROP_WL_KEY_TAB,	sizeof (wl_wep_key_tab_t), "wl_wep_key"},
320 
321 	{ MAC_PROP_WL_CREATE_IBSS, sizeof (wl_create_ibss_t), "createibss"},
322 
323 	/* wl_wpa_ie_t has variable length */
324 	{ MAC_PROP_WL_SETOPTIE,	sizeof (wl_wpa_ie_t),	"set_ie"},
325 
326 	{ MAC_PROP_WL_DELKEY,	sizeof (wl_del_key_t),	"wpa_del_key"},
327 
328 	{ MAC_PROP_WL_KEY,	sizeof (wl_key_t),	"wl_key"},
329 
330 	{ MAC_PROP_WL_MLME,	sizeof (wl_mlme_t),	"mlme"},
331 
332 	{ MAC_PROP_TAGMODE,	sizeof (link_tagmode_t),	"tagmode"},
333 
334 	{ MAC_PROP_IPTUN_HOPLIMIT, sizeof (uint32_t),	"hoplimit"},
335 
336 	{ MAC_PROP_IPTUN_ENCAPLIMIT, sizeof (uint32_t),	"encaplimit"},
337 
338 	{ MAC_PROP_PVID,	sizeof (uint16_t),	"default_tag"},
339 
340 	{ MAC_PROP_LLIMIT,	sizeof (uint32_t),	"learn_limit"},
341 
342 	{ MAC_PROP_LDECAY,	sizeof (uint32_t),	"learn_decay"},
343 
344 	{ MAC_PROP_RESOURCE,	sizeof (mac_resource_props_t),	"resource"},
345 
346 	{ MAC_PROP_RESOURCE_EFF, sizeof (mac_resource_props_t),
347 	    "resource-effective"},
348 
349 	{ MAC_PROP_RXRINGSRANGE, sizeof (mac_propval_range_t),	"rxrings"},
350 
351 	{ MAC_PROP_TXRINGSRANGE, sizeof (mac_propval_range_t),	"txrings"},
352 
353 	{ MAC_PROP_MAX_TX_RINGS_AVAIL,	sizeof (uint_t),
354 	    "txrings-available"},
355 
356 	{ MAC_PROP_MAX_RX_RINGS_AVAIL,	sizeof (uint_t),
357 	    "rxrings-available"},
358 
359 	{ MAC_PROP_MAX_RXHWCLNT_AVAIL,	sizeof (uint_t), "rxhwclnt-available"},
360 
361 	{ MAC_PROP_MAX_TXHWCLNT_AVAIL,	sizeof (uint_t), "txhwclnt-available"},
362 
363 	{ MAC_PROP_PRIVATE,	0,			"driver-private"}
364 };
365 
366 typedef struct bridge_public_prop_s {
367 	const char	*bpp_name;
368 	int		bpp_code;
369 } bridge_public_prop_t;
370 
371 static const bridge_public_prop_t bridge_prop[] = {
372 	{ "stp", PT_CFG_NON_STP },
373 	{ "stp_priority", PT_CFG_PRIO },
374 	{ "stp_cost", PT_CFG_COST },
375 	{ "stp_edge", PT_CFG_EDGE },
376 	{ "stp_p2p", PT_CFG_P2P },
377 	{ "stp_mcheck", PT_CFG_MCHECK },
378 	{ NULL, 0 }
379 };
380 
381 static  val_desc_t	link_duplex_vals[] = {
382 	{ "half", 	LINK_DUPLEX_HALF	},
383 	{ "full", 	LINK_DUPLEX_HALF	}
384 };
385 static  val_desc_t	link_status_vals[] = {
386 	{ "up",		LINK_STATE_UP		},
387 	{ "down",	LINK_STATE_DOWN		}
388 };
389 static  val_desc_t	link_01_vals[] = {
390 	{ "1",		1			},
391 	{ "0",		0			}
392 };
393 static  val_desc_t	link_flow_vals[] = {
394 	{ "no",		LINK_FLOWCTRL_NONE	},
395 	{ "tx",		LINK_FLOWCTRL_TX	},
396 	{ "rx",		LINK_FLOWCTRL_RX	},
397 	{ "bi",		LINK_FLOWCTRL_BI	}
398 };
399 static  val_desc_t	link_priority_vals[] = {
400 	{ "low",	MPL_LOW	},
401 	{ "medium",	MPL_MEDIUM	},
402 	{ "high",	MPL_HIGH	}
403 };
404 
405 static val_desc_t	link_tagmode_vals[] = {
406 	{ "normal",	LINK_TAGMODE_NORMAL	},
407 	{ "vlanonly",	LINK_TAGMODE_VLANONLY	}
408 };
409 
410 static  val_desc_t	link_protect_vals[] = {
411 	{ "mac-nospoof",	MPT_MACNOSPOOF	},
412 	{ "restricted",		MPT_RESTRICTED	},
413 	{ "ip-nospoof",		MPT_IPNOSPOOF	},
414 	{ "dhcp-nospoof",	MPT_DHCPNOSPOOF	},
415 };
416 
417 static val_desc_t	dladm_wlan_radio_vals[] = {
418 	{ "on",		DLADM_WLAN_RADIO_ON	},
419 	{ "off",	DLADM_WLAN_RADIO_OFF	}
420 };
421 
422 static val_desc_t	dladm_wlan_powermode_vals[] = {
423 	{ "off",	DLADM_WLAN_PM_OFF	},
424 	{ "fast",	DLADM_WLAN_PM_FAST	},
425 	{ "max",	DLADM_WLAN_PM_MAX	}
426 };
427 
428 static  val_desc_t	stp_p2p_vals[] = {
429 	{ "true",	P2P_FORCE_TRUE		},
430 	{ "false",	P2P_FORCE_FALSE		},
431 	{ "auto",	P2P_AUTO		}
432 };
433 
434 #define	VALCNT(vals)    (sizeof ((vals)) / sizeof (val_desc_t))
435 #define	RESET_VAL	((uintptr_t)-1)
436 #define	UNSPEC_VAL	((uintptr_t)-2)
437 
438 static prop_desc_t	prop_table[] = {
439 	{ "channel",	{ NULL, 0 },
440 	    NULL, 0, NULL, NULL,
441 	    get_channel, NULL, 0,
442 	    DATALINK_CLASS_PHYS, DL_WIFI },
443 
444 	{ "powermode",	{ "off", DLADM_WLAN_PM_OFF },
445 	    dladm_wlan_powermode_vals, VALCNT(dladm_wlan_powermode_vals),
446 	    set_powermode, NULL,
447 	    get_powermode, NULL, 0,
448 	    DATALINK_CLASS_PHYS, DL_WIFI },
449 
450 	{ "radio",	{ "on", DLADM_WLAN_RADIO_ON },
451 	    dladm_wlan_radio_vals, VALCNT(dladm_wlan_radio_vals),
452 	    set_radio, NULL,
453 	    get_radio, NULL, 0,
454 	    DATALINK_CLASS_PHYS, DL_WIFI },
455 
456 	{ "speed",	{ "", 0 }, NULL, 0,
457 	    set_rate, get_rate_mod,
458 	    get_rate, check_rate, 0,
459 	    DATALINK_CLASS_PHYS, DATALINK_ANY_MEDIATYPE },
460 
461 	{ "autopush",	{ "", 0 }, NULL, 0,
462 	    set_public_prop, NULL,
463 	    get_autopush, check_autopush, PD_CHECK_ALLOC,
464 	    DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
465 
466 	{ "zone",	{ "", 0 }, NULL, 0,
467 	    set_zone, NULL,
468 	    get_zone, check_zone, PD_TEMPONLY|PD_CHECK_ALLOC,
469 	    DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
470 
471 	{ "duplex",	{ "", 0 },
472 	    link_duplex_vals, VALCNT(link_duplex_vals),
473 	    NULL, NULL, get_duplex, NULL,
474 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
475 
476 	{ "state",	{ "up", LINK_STATE_UP },
477 	    link_status_vals, VALCNT(link_status_vals),
478 	    NULL, NULL, get_link_state, NULL,
479 	    0, DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
480 
481 	{ "adv_autoneg_cap", { "", 0 },
482 	    link_01_vals, VALCNT(link_01_vals),
483 	    set_public_prop, NULL, get_binary, NULL,
484 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
485 
486 	{ "mtu", { "", 0 }, NULL, 0,
487 	    set_public_prop, get_range,
488 	    get_uint32, check_uint32, 0, DATALINK_CLASS_ALL,
489 	    DATALINK_ANY_MEDIATYPE },
490 
491 	{ "flowctrl", { "", 0 },
492 	    link_flow_vals, VALCNT(link_flow_vals),
493 	    set_public_prop, NULL, get_flowctl, NULL,
494 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
495 
496 	{ "adv_10gfdx_cap", { "", 0 },
497 	    link_01_vals, VALCNT(link_01_vals),
498 	    NULL, NULL, get_binary, NULL,
499 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
500 
501 	{ "en_10gfdx_cap", { "", 0 },
502 	    link_01_vals, VALCNT(link_01_vals),
503 	    set_public_prop, NULL, get_binary, NULL,
504 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
505 
506 	{ "adv_1000fdx_cap", { "", 0 },
507 	    link_01_vals, VALCNT(link_01_vals),
508 	    NULL, NULL, get_binary, NULL,
509 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
510 
511 	{ "en_1000fdx_cap", { "", 0 },
512 	    link_01_vals, VALCNT(link_01_vals),
513 	    set_public_prop, NULL, get_binary, NULL,
514 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
515 
516 	{ "adv_1000hdx_cap", { "", 0 },
517 	    link_01_vals, VALCNT(link_01_vals),
518 	    NULL, NULL, get_binary, NULL,
519 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
520 
521 	{ "en_1000hdx_cap", { "", 0 },
522 	    link_01_vals, VALCNT(link_01_vals),
523 	    set_public_prop, NULL, get_binary, NULL,
524 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
525 
526 	{ "adv_100fdx_cap", { "", 0 },
527 	    link_01_vals, VALCNT(link_01_vals),
528 	    NULL, NULL, get_binary, NULL,
529 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
530 
531 	{ "en_100fdx_cap", { "", 0 },
532 	    link_01_vals, VALCNT(link_01_vals),
533 	    set_public_prop, NULL, get_binary, NULL,
534 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
535 
536 	{ "adv_100hdx_cap", { "", 0 },
537 	    link_01_vals, VALCNT(link_01_vals),
538 	    NULL, NULL, get_binary, NULL,
539 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
540 
541 	{ "en_100hdx_cap", { "", 0 },
542 	    link_01_vals, VALCNT(link_01_vals),
543 	    set_public_prop, NULL, get_binary, NULL,
544 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
545 
546 	{ "adv_10fdx_cap", { "", 0 },
547 	    link_01_vals, VALCNT(link_01_vals),
548 	    NULL, NULL, get_binary, NULL,
549 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
550 
551 	{ "en_10fdx_cap", { "", 0 },
552 	    link_01_vals, VALCNT(link_01_vals),
553 	    set_public_prop, NULL, get_binary, NULL,
554 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
555 
556 	{ "adv_10hdx_cap", { "", 0 },
557 	    link_01_vals, VALCNT(link_01_vals),
558 	    NULL, NULL, get_binary, NULL,
559 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
560 
561 	{ "en_10hdx_cap", { "", 0 },
562 	    link_01_vals, VALCNT(link_01_vals),
563 	    set_public_prop, NULL, get_binary, NULL,
564 	    0, DATALINK_CLASS_PHYS, DL_ETHER },
565 
566 	{ "maxbw", { "--", RESET_VAL }, NULL, 0,
567 	    set_resource, NULL,
568 	    get_maxbw, check_maxbw, PD_CHECK_ALLOC,
569 	    DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
570 
571 	{ "cpus", { "--", RESET_VAL }, NULL, 0,
572 	    set_resource, NULL,
573 	    get_cpus, check_cpus, 0,
574 	    DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
575 
576 	{ "cpus-effective", { "--", 0 },
577 	    NULL, 0, NULL, NULL,
578 	    get_cpus, 0, 0,
579 	    DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
580 
581 	{ "pool", { "--", RESET_VAL }, NULL, 0,
582 	    set_resource, NULL,
583 	    get_pool, check_pool, 0,
584 	    DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
585 
586 	{ "pool-effective", { "--", 0 },
587 	    NULL, 0, NULL, NULL,
588 	    get_pool, 0, 0,
589 	    DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
590 
591 	{ "priority", { "high", MPL_RESET },
592 	    link_priority_vals, VALCNT(link_priority_vals), set_resource,
593 	    NULL, get_priority, check_prop, 0,
594 	    DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
595 
596 	{ "tagmode", { "vlanonly", LINK_TAGMODE_VLANONLY },
597 	    link_tagmode_vals, VALCNT(link_tagmode_vals),
598 	    set_public_prop, NULL, get_tagmode,
599 	    NULL, 0,
600 	    DATALINK_CLASS_PHYS | DATALINK_CLASS_AGGR | DATALINK_CLASS_VNIC,
601 	    DL_ETHER },
602 
603 	{ "hoplimit", { "", 0 }, NULL, 0,
604 	    set_public_prop, get_range, get_uint32,
605 	    check_hoplimit, 0, DATALINK_CLASS_IPTUN, DATALINK_ANY_MEDIATYPE},
606 
607 	{ "encaplimit", { "", 0 }, NULL, 0,
608 	    set_public_prop, get_range, get_uint32,
609 	    check_encaplim, 0, DATALINK_CLASS_IPTUN, DL_IPV6},
610 
611 	{ "forward", { "1", 1 },
612 	    link_01_vals, VALCNT(link_01_vals),
613 	    set_bridge_forward, NULL, get_bridge_forward, NULL, PD_AFTER_PERM,
614 	    DATALINK_CLASS_ALL & ~DATALINK_CLASS_VNIC, DL_ETHER },
615 
616 	{ "default_tag", { "1", 1 }, NULL, 0,
617 	    set_bridge_pvid, NULL, get_bridge_pvid, check_bridge_pvid,
618 	    0, DATALINK_CLASS_PHYS|DATALINK_CLASS_AGGR|
619 	    DATALINK_CLASS_ETHERSTUB|DATALINK_CLASS_SIMNET, DL_ETHER },
620 
621 	{ "learn_limit", { "1000", 1000 }, NULL, 0,
622 	    set_public_prop, NULL, get_uint32,
623 	    check_uint32, 0,
624 	    DATALINK_CLASS_PHYS|DATALINK_CLASS_AGGR|
625 	    DATALINK_CLASS_ETHERSTUB|DATALINK_CLASS_SIMNET, DL_ETHER },
626 
627 	{ "learn_decay", { "200", 200 }, NULL, 0,
628 	    set_public_prop, NULL, get_uint32,
629 	    check_uint32, 0,
630 	    DATALINK_CLASS_PHYS|DATALINK_CLASS_AGGR|
631 	    DATALINK_CLASS_ETHERSTUB|DATALINK_CLASS_SIMNET, DL_ETHER },
632 
633 	{ "stp", { "1", 1 },
634 	    link_01_vals, VALCNT(link_01_vals),
635 	    set_stp_prop, NULL, get_stp, NULL, PD_AFTER_PERM,
636 	    DATALINK_CLASS_PHYS|DATALINK_CLASS_AGGR|
637 	    DATALINK_CLASS_ETHERSTUB|DATALINK_CLASS_SIMNET, DL_ETHER },
638 
639 	{ "stp_priority", { "128", 128 }, NULL, 0,
640 	    set_stp_prop, NULL, get_stp, check_stp_prop, PD_AFTER_PERM,
641 	    DATALINK_CLASS_PHYS|DATALINK_CLASS_AGGR|
642 	    DATALINK_CLASS_ETHERSTUB|DATALINK_CLASS_SIMNET, DL_ETHER },
643 
644 	{ "stp_cost", { "auto", 0 }, NULL, 0,
645 	    set_stp_prop, NULL, get_stp, check_stp_prop, PD_AFTER_PERM,
646 	    DATALINK_CLASS_PHYS|DATALINK_CLASS_AGGR|
647 	    DATALINK_CLASS_ETHERSTUB|DATALINK_CLASS_SIMNET, DL_ETHER },
648 
649 	{ "stp_edge", { "1", 1 },
650 	    link_01_vals, VALCNT(link_01_vals),
651 	    set_stp_prop, NULL, get_stp, NULL, PD_AFTER_PERM,
652 	    DATALINK_CLASS_PHYS|DATALINK_CLASS_AGGR|
653 	    DATALINK_CLASS_ETHERSTUB|DATALINK_CLASS_SIMNET, DL_ETHER },
654 
655 	{ "stp_p2p", { "auto", P2P_AUTO },
656 	    stp_p2p_vals, VALCNT(stp_p2p_vals),
657 	    set_stp_prop, NULL, get_stp, NULL, PD_AFTER_PERM,
658 	    DATALINK_CLASS_PHYS|DATALINK_CLASS_AGGR|
659 	    DATALINK_CLASS_ETHERSTUB|DATALINK_CLASS_SIMNET, DL_ETHER },
660 
661 	{ "stp_mcheck", { "0", 0 },
662 	    link_01_vals, VALCNT(link_01_vals),
663 	    set_stp_prop, NULL, get_stp, check_stp_prop, PD_AFTER_PERM,
664 	    DATALINK_CLASS_PHYS|DATALINK_CLASS_AGGR|
665 	    DATALINK_CLASS_ETHERSTUB|DATALINK_CLASS_SIMNET, DL_ETHER },
666 
667 	{ "protection", { "--", RESET_VAL },
668 	    link_protect_vals, VALCNT(link_protect_vals),
669 	    set_resource, NULL, get_protection, check_prop, 0,
670 	    DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
671 
672 	{ "allowed-ips", { "--", 0 },
673 	    NULL, 0, set_resource, NULL,
674 	    get_allowedips, check_allowedips, PD_CHECK_ALLOC,
675 	    DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
676 
677 	{ "allowed-dhcp-cids", { "--", 0 },
678 	    NULL, 0, set_resource, NULL,
679 	    get_allowedcids, check_allowedcids, PD_CHECK_ALLOC,
680 	    DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
681 
682 	{ "rxrings", { "--", RESET_VAL }, NULL, 0,
683 	    set_resource, get_rings_range, get_rxrings, check_rings, 0,
684 	    DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
685 
686 	{ "rxrings-effective", { "--", 0 },
687 	    NULL, 0, NULL, NULL,
688 	    get_rxrings, NULL, 0,
689 	    DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
690 
691 	{ "txrings", { "--", RESET_VAL }, NULL, 0,
692 	    set_resource, get_rings_range, get_txrings, check_rings, 0,
693 	    DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
694 
695 	{ "txrings-effective", { "--", 0 },
696 	    NULL, 0, NULL, NULL,
697 	    get_txrings, NULL, 0,
698 	    DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
699 
700 	{ "txrings-available", { "", 0 }, NULL, 0,
701 	    NULL, NULL, get_cntavail, NULL, 0,
702 	    DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
703 
704 	{ "rxrings-available", { "", 0 }, NULL, 0,
705 	    NULL, NULL, get_cntavail, NULL, 0,
706 	    DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
707 
708 	{ "rxhwclnt-available", { "", 0 }, NULL, 0,
709 	    NULL, NULL, get_cntavail, NULL, 0,
710 	    DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
711 
712 	{ "txhwclnt-available", { "", 0 }, NULL, 0,
713 	    NULL, NULL, get_cntavail, NULL, 0,
714 	    DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
715 
716 };
717 
718 #define	DLADM_MAX_PROPS	(sizeof (prop_table) / sizeof (prop_desc_t))
719 
720 static resource_prop_t rsrc_prop_table[] = {
721 	{"maxbw",		extract_maxbw},
722 	{"priority",		extract_priority},
723 	{"cpus",		extract_cpus},
724 	{"cpus-effective",	extract_cpus},
725 	{"pool",		extract_pool},
726 	{"pool-effective",	extract_pool},
727 	{"protection",		extract_protection},
728 	{"allowed-ips",		extract_allowedips},
729 	{"allowed-dhcp-cids",	extract_allowedcids},
730 	{"rxrings",		extract_rxrings},
731 	{"rxrings-effective",	extract_rxrings},
732 	{"txrings",		extract_txrings},
733 	{"txrings-effective",	extract_txrings}
734 };
735 #define	DLADM_MAX_RSRC_PROP (sizeof (rsrc_prop_table) / \
736 	sizeof (resource_prop_t))
737 
738 /*
739  * when retrieving  private properties, we pass down a buffer with
740  * DLADM_PROP_BUF_CHUNK of space for the driver to return the property value.
741  */
742 #define	DLADM_PROP_BUF_CHUNK	1024
743 
744 static dladm_status_t	i_dladm_set_linkprop_db(dladm_handle_t, datalink_id_t,
745 			    const char *, char **, uint_t);
746 static dladm_status_t	i_dladm_get_linkprop_db(dladm_handle_t, datalink_id_t,
747 			    const char *, char **, uint_t *);
748 static dladm_status_t	i_dladm_walk_linkprop_priv_db(dladm_handle_t,
749 			    datalink_id_t, void *, int (*)(dladm_handle_t,
750 			    datalink_id_t, const char *, void *));
751 static dladm_status_t	i_dladm_set_single_prop(dladm_handle_t, datalink_id_t,
752 			    datalink_class_t, uint32_t, prop_desc_t *, char **,
753 			    uint_t, uint_t);
754 static dladm_status_t	i_dladm_set_linkprop(dladm_handle_t, datalink_id_t,
755 			    const char *, char **, uint_t, uint_t);
756 static dladm_status_t	i_dladm_getset_defval(dladm_handle_t, prop_desc_t *,
757 			    datalink_id_t, datalink_media_t, uint_t);
758 
759 /*
760  * Unfortunately, MAX_SCAN_SUPPORT_RATES is too small to allow all
761  * rates to be retrieved. However, we cannot increase it at this
762  * time because it will break binary compatibility with unbundled
763  * WiFi drivers and utilities. So for now we define an additional
764  * constant, MAX_SUPPORT_RATES, to allow all rates to be retrieved.
765  */
766 #define	MAX_SUPPORT_RATES	64
767 
768 #define	AP_ANCHOR	"[anchor]"
769 #define	AP_DELIMITER	'.'
770 
771 /* ARGSUSED */
772 static dladm_status_t
773 check_prop(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
774     char **prop_val, uint_t val_cnt, uint_t flags, val_desc_t *vdp,
775     datalink_media_t media)
776 {
777 	int		i, j;
778 
779 	for (j = 0; j < val_cnt; j++) {
780 		for (i = 0; i < pdp->pd_noptval; i++) {
781 			if (strcasecmp(prop_val[j],
782 			    pdp->pd_optval[i].vd_name) == 0) {
783 				break;
784 			}
785 		}
786 		if (i == pdp->pd_noptval)
787 			return (DLADM_STATUS_BADVAL);
788 
789 		(void) memcpy(&vdp[j], &pdp->pd_optval[i], sizeof (val_desc_t));
790 	}
791 	return (DLADM_STATUS_OK);
792 }
793 
794 static dladm_status_t
795 i_dladm_set_single_prop(dladm_handle_t handle, datalink_id_t linkid,
796     datalink_class_t class, uint32_t media, prop_desc_t *pdp, char **prop_val,
797     uint_t val_cnt, uint_t flags)
798 {
799 	dladm_status_t	status = DLADM_STATUS_OK;
800 	val_desc_t	*vdp = NULL;
801 	boolean_t	needfree = B_FALSE;
802 	uint_t		cnt, i;
803 
804 	if (!(pdp->pd_class & class))
805 		return (DLADM_STATUS_BADARG);
806 
807 	if (!DATALINK_MEDIA_ACCEPTED(pdp->pd_dmedia, media))
808 		return (DLADM_STATUS_BADARG);
809 
810 	if ((flags & DLADM_OPT_PERSIST) && (pdp->pd_flags & PD_TEMPONLY))
811 		return (DLADM_STATUS_TEMPONLY);
812 
813 	if (!(flags & DLADM_OPT_ACTIVE))
814 		return (DLADM_STATUS_OK);
815 
816 	if (pdp->pd_set == NULL)
817 		return (DLADM_STATUS_PROPRDONLY);
818 
819 	if (prop_val != NULL) {
820 		vdp = calloc(val_cnt, sizeof (val_desc_t));
821 		if (vdp == NULL)
822 			return (DLADM_STATUS_NOMEM);
823 
824 		if (pdp->pd_check != NULL) {
825 			needfree = ((pdp->pd_flags & PD_CHECK_ALLOC) != 0);
826 			status = pdp->pd_check(handle, pdp, linkid, prop_val,
827 			    val_cnt, flags, vdp, media);
828 		} else if (pdp->pd_optval != NULL) {
829 			status = check_prop(handle, pdp, linkid, prop_val,
830 			    val_cnt, flags, vdp, media);
831 		} else {
832 			status = DLADM_STATUS_BADARG;
833 		}
834 
835 		if (status != DLADM_STATUS_OK)
836 			goto done;
837 
838 		cnt = val_cnt;
839 	} else {
840 		boolean_t	defval = B_FALSE;
841 
842 		if (pdp->pd_defval.vd_name == NULL)
843 			return (DLADM_STATUS_NOTSUP);
844 
845 		cnt = 1;
846 		defval = (strlen(pdp->pd_defval.vd_name) > 0);
847 		if ((pdp->pd_flags & PD_CHECK_ALLOC) != 0 || defval) {
848 			if ((vdp = calloc(1, sizeof (val_desc_t))) == NULL)
849 				return (DLADM_STATUS_NOMEM);
850 
851 			if (defval) {
852 				(void) memcpy(vdp, &pdp->pd_defval,
853 				    sizeof (val_desc_t));
854 			} else if (pdp->pd_check != NULL) {
855 				status = pdp->pd_check(handle, pdp, linkid,
856 				    prop_val, cnt, flags, vdp, media);
857 				if (status != DLADM_STATUS_OK)
858 					goto done;
859 			}
860 		} else {
861 			status = i_dladm_getset_defval(handle, pdp, linkid,
862 			    media, flags);
863 			return (status);
864 		}
865 	}
866 	if (pdp->pd_flags & PD_AFTER_PERM)
867 		status = (flags & DLADM_OPT_PERSIST) ? DLADM_STATUS_OK :
868 		    DLADM_STATUS_PERMONLY;
869 	else
870 		status = pdp->pd_set(handle, pdp, linkid, vdp, cnt, flags,
871 		    media);
872 	if (needfree) {
873 		for (i = 0; i < cnt; i++)
874 			free((void *)((val_desc_t *)vdp + i)->vd_val);
875 	}
876 done:
877 	free(vdp);
878 	return (status);
879 }
880 
881 static dladm_status_t
882 i_dladm_set_linkprop(dladm_handle_t handle, datalink_id_t linkid,
883     const char *prop_name, char **prop_val, uint_t val_cnt, uint_t flags)
884 {
885 	int			i;
886 	boolean_t		found = B_FALSE;
887 	datalink_class_t	class;
888 	uint32_t		media;
889 	dladm_status_t		status = DLADM_STATUS_OK;
890 
891 	status = dladm_datalink_id2info(handle, linkid, NULL, &class, &media,
892 	    NULL, 0);
893 	if (status != DLADM_STATUS_OK)
894 		return (status);
895 
896 	for (i = 0; i < DLADM_MAX_PROPS; i++) {
897 		prop_desc_t	*pdp = &prop_table[i];
898 		dladm_status_t	s;
899 
900 		if (prop_name != NULL &&
901 		    (strcasecmp(prop_name, pdp->pd_name) != 0))
902 			continue;
903 		found = B_TRUE;
904 		s = i_dladm_set_single_prop(handle, linkid, class, media, pdp,
905 		    prop_val, val_cnt, flags);
906 
907 		if (prop_name != NULL) {
908 			status = s;
909 			break;
910 		} else {
911 			if (s != DLADM_STATUS_OK &&
912 			    s != DLADM_STATUS_NOTSUP)
913 				status = s;
914 		}
915 	}
916 	if (!found) {
917 		if (prop_name[0] == '_') {
918 			/* other private properties */
919 			status = i_dladm_set_private_prop(handle, linkid,
920 			    prop_name, prop_val, val_cnt, flags);
921 		} else  {
922 			status = DLADM_STATUS_NOTFOUND;
923 		}
924 	}
925 	return (status);
926 }
927 
928 /*
929  * Set/reset link property for specific link
930  */
931 dladm_status_t
932 dladm_set_linkprop(dladm_handle_t handle, datalink_id_t linkid,
933     const char *prop_name, char **prop_val, uint_t val_cnt, uint_t flags)
934 {
935 	dladm_status_t	status = DLADM_STATUS_OK;
936 
937 	if ((linkid == DATALINK_INVALID_LINKID) || (flags == 0) ||
938 	    (prop_val == NULL && val_cnt > 0) ||
939 	    (prop_val != NULL && val_cnt == 0) ||
940 	    (prop_name == NULL && prop_val != NULL)) {
941 		return (DLADM_STATUS_BADARG);
942 	}
943 
944 	/*
945 	 * Check for valid link property against the flags passed
946 	 * and set the link property when active flag is passed.
947 	 */
948 	status = i_dladm_set_linkprop(handle, linkid, prop_name, prop_val,
949 	    val_cnt, flags);
950 	if (status != DLADM_STATUS_OK)
951 		return (status);
952 
953 	if (flags & DLADM_OPT_PERSIST) {
954 		status = i_dladm_set_linkprop_db(handle, linkid, prop_name,
955 		    prop_val, val_cnt);
956 
957 		if (status == DLADM_STATUS_OK && (flags & DLADM_OPT_ACTIVE)) {
958 			prop_desc_t *pdp = prop_table;
959 			int i;
960 
961 			for (i = 0; i < DLADM_MAX_PROPS; i++, pdp++) {
962 				if (!(pdp->pd_flags & PD_AFTER_PERM))
963 					continue;
964 				if (prop_name != NULL &&
965 				    strcasecmp(prop_name, pdp->pd_name) != 0)
966 					continue;
967 				status = pdp->pd_set(handle, pdp, linkid, NULL,
968 				    0, flags, 0);
969 			}
970 		}
971 	}
972 	return (status);
973 }
974 
975 /*
976  * Walk all link properties of the given specific link.
977  *
978  * Note: this function currently lacks the ability to walk _all_ private
979  * properties if the link, because there is no kernel interface to
980  * retrieve all known private property names. Once such an interface
981  * is added, this function should be fixed accordingly.
982  */
983 dladm_status_t
984 dladm_walk_linkprop(dladm_handle_t handle, datalink_id_t linkid, void *arg,
985     int (*func)(dladm_handle_t, datalink_id_t, const char *, void *))
986 {
987 	dladm_status_t		status;
988 	datalink_class_t	class;
989 	uint_t			media;
990 	int			i;
991 
992 	if (linkid == DATALINK_INVALID_LINKID || func == NULL)
993 		return (DLADM_STATUS_BADARG);
994 
995 	status = dladm_datalink_id2info(handle, linkid, NULL, &class, &media,
996 	    NULL, 0);
997 	if (status != DLADM_STATUS_OK)
998 		return (status);
999 
1000 	/* public */
1001 	for (i = 0; i < DLADM_MAX_PROPS; i++) {
1002 		if (!(prop_table[i].pd_class & class))
1003 			continue;
1004 
1005 		if (!DATALINK_MEDIA_ACCEPTED(prop_table[i].pd_dmedia, media))
1006 			continue;
1007 
1008 		if (func(handle, linkid, prop_table[i].pd_name, arg) ==
1009 		    DLADM_WALK_TERMINATE) {
1010 			break;
1011 		}
1012 	}
1013 
1014 	/* private */
1015 	status = i_dladm_walk_linkprop_priv_db(handle, linkid, arg, func);
1016 
1017 	return (status);
1018 }
1019 
1020 /*
1021  * Get linkprop of the given specific link.
1022  */
1023 dladm_status_t
1024 dladm_get_linkprop(dladm_handle_t handle, datalink_id_t linkid,
1025     dladm_prop_type_t type, const char *prop_name, char **prop_val,
1026     uint_t *val_cntp)
1027 {
1028 	dladm_status_t		status = DLADM_STATUS_OK;
1029 	datalink_class_t	class;
1030 	uint_t			media;
1031 	prop_desc_t		*pdp;
1032 	uint_t			cnt, dld_flags = 0;
1033 	int			i;
1034 	uint_t			perm_flags;
1035 
1036 	if (type == DLADM_PROP_VAL_DEFAULT)
1037 		dld_flags |= DLD_PROP_DEFAULT;
1038 	else if (type == DLADM_PROP_VAL_MODIFIABLE)
1039 		dld_flags |= DLD_PROP_POSSIBLE;
1040 
1041 	if (linkid == DATALINK_INVALID_LINKID || prop_name == NULL ||
1042 	    prop_val == NULL || val_cntp == NULL || *val_cntp == 0)
1043 		return (DLADM_STATUS_BADARG);
1044 
1045 	for (i = 0; i < DLADM_MAX_PROPS; i++)
1046 		if (strcasecmp(prop_name, prop_table[i].pd_name) == 0)
1047 			break;
1048 
1049 	if (i == DLADM_MAX_PROPS) {
1050 		if (prop_name[0] == '_') {
1051 			/*
1052 			 * private property.
1053 			 */
1054 			if (type == DLADM_PROP_VAL_PERSISTENT)
1055 				return (i_dladm_get_linkprop_db(handle, linkid,
1056 				    prop_name, prop_val, val_cntp));
1057 			else
1058 				return (i_dladm_get_priv_prop(handle, linkid,
1059 				    prop_name, prop_val, val_cntp, type,
1060 				    dld_flags));
1061 		} else {
1062 			return (DLADM_STATUS_NOTFOUND);
1063 		}
1064 	}
1065 
1066 	pdp = &prop_table[i];
1067 
1068 	status = dladm_datalink_id2info(handle, linkid, NULL, &class, &media,
1069 	    NULL, 0);
1070 	if (status != DLADM_STATUS_OK)
1071 		return (status);
1072 
1073 	if (!(pdp->pd_class & class))
1074 		return (DLADM_STATUS_BADARG);
1075 
1076 	if (!DATALINK_MEDIA_ACCEPTED(pdp->pd_dmedia, media))
1077 		return (DLADM_STATUS_BADARG);
1078 
1079 	switch (type) {
1080 	case DLADM_PROP_VAL_CURRENT:
1081 		status = pdp->pd_get(handle, pdp, linkid, prop_val, val_cntp,
1082 		    media, dld_flags, &perm_flags);
1083 		break;
1084 
1085 	case DLADM_PROP_VAL_PERM:
1086 		if (pdp->pd_set == NULL) {
1087 			perm_flags = MAC_PROP_PERM_READ;
1088 		} else {
1089 			status = pdp->pd_get(handle, pdp, linkid, prop_val,
1090 			    val_cntp, media, dld_flags, &perm_flags);
1091 		}
1092 
1093 		*prop_val[0] = '\0';
1094 		*val_cntp = 1;
1095 		if (status == DLADM_STATUS_OK)
1096 			(void) dladm_perm2str(perm_flags, *prop_val);
1097 		break;
1098 
1099 	case DLADM_PROP_VAL_DEFAULT:
1100 		/*
1101 		 * If defaults are not defined for the property,
1102 		 * pd_defval.vd_name should be null. If the driver
1103 		 * has to be contacted for the value, vd_name should
1104 		 * be the empty string (""). Otherwise, dladm will
1105 		 * just print whatever is in the table.
1106 		 */
1107 		if (pdp->pd_defval.vd_name == NULL) {
1108 			status = DLADM_STATUS_NOTSUP;
1109 			break;
1110 		}
1111 
1112 		if (strlen(pdp->pd_defval.vd_name) == 0) {
1113 			status = pdp->pd_get(handle, pdp, linkid, prop_val,
1114 			    val_cntp, media, dld_flags, &perm_flags);
1115 		} else {
1116 			(void) strcpy(*prop_val, pdp->pd_defval.vd_name);
1117 		}
1118 		*val_cntp = 1;
1119 		break;
1120 
1121 	case DLADM_PROP_VAL_MODIFIABLE:
1122 		if (pdp->pd_getmod != NULL) {
1123 			status = pdp->pd_getmod(handle, pdp, linkid, prop_val,
1124 			    val_cntp, media, dld_flags, &perm_flags);
1125 			break;
1126 		}
1127 		cnt = pdp->pd_noptval;
1128 		if (cnt == 0) {
1129 			status = DLADM_STATUS_NOTSUP;
1130 		} else if (cnt > *val_cntp) {
1131 			status = DLADM_STATUS_TOOSMALL;
1132 		} else {
1133 			for (i = 0; i < cnt; i++) {
1134 				(void) strcpy(prop_val[i],
1135 				    pdp->pd_optval[i].vd_name);
1136 			}
1137 			*val_cntp = cnt;
1138 		}
1139 		break;
1140 	case DLADM_PROP_VAL_PERSISTENT:
1141 		if (pdp->pd_flags & PD_TEMPONLY)
1142 			return (DLADM_STATUS_TEMPONLY);
1143 		status = i_dladm_get_linkprop_db(handle, linkid, prop_name,
1144 		    prop_val, val_cntp);
1145 		break;
1146 	default:
1147 		status = DLADM_STATUS_BADARG;
1148 		break;
1149 	}
1150 
1151 	return (status);
1152 }
1153 
1154 /*
1155  * Get linkprop of the given specific link and run any possible conversion
1156  * of the values using the check function for the property. Fails if the
1157  * check function doesn't succeed for the property value.
1158  */
1159 dladm_status_t
1160 dladm_get_linkprop_values(dladm_handle_t handle, datalink_id_t linkid,
1161     dladm_prop_type_t type, const char *prop_name, uint_t *ret_val,
1162     uint_t *val_cntp)
1163 {
1164 	dladm_status_t		status;
1165 	datalink_class_t	class;
1166 	uint_t			media;
1167 	prop_desc_t		*pdp;
1168 	uint_t			dld_flags;
1169 	int			valc, i;
1170 	char			**prop_val;
1171 	uint_t			perm_flags;
1172 
1173 	if (linkid == DATALINK_INVALID_LINKID || prop_name == NULL ||
1174 	    ret_val == NULL || val_cntp == NULL || *val_cntp == 0)
1175 		return (DLADM_STATUS_BADARG);
1176 
1177 	for (pdp = prop_table; pdp < prop_table + DLADM_MAX_PROPS; pdp++)
1178 		if (strcasecmp(prop_name, pdp->pd_name) == 0)
1179 			break;
1180 
1181 	if (pdp == prop_table + DLADM_MAX_PROPS)
1182 		return (DLADM_STATUS_NOTFOUND);
1183 
1184 	if (pdp->pd_flags & PD_CHECK_ALLOC)
1185 		return (DLADM_STATUS_BADARG);
1186 
1187 	status = dladm_datalink_id2info(handle, linkid, NULL, &class, &media,
1188 	    NULL, 0);
1189 	if (status != DLADM_STATUS_OK)
1190 		return (status);
1191 
1192 	if (!(pdp->pd_class & class))
1193 		return (DLADM_STATUS_BADARG);
1194 
1195 	if (!DATALINK_MEDIA_ACCEPTED(pdp->pd_dmedia, media))
1196 		return (DLADM_STATUS_BADARG);
1197 
1198 	prop_val = malloc(*val_cntp * sizeof (*prop_val) +
1199 	    *val_cntp * DLADM_PROP_VAL_MAX);
1200 	if (prop_val == NULL)
1201 		return (DLADM_STATUS_NOMEM);
1202 	for (valc = 0; valc < *val_cntp; valc++)
1203 		prop_val[valc] = (char *)(prop_val + *val_cntp) +
1204 		    valc * DLADM_PROP_VAL_MAX;
1205 
1206 	dld_flags = (type == DLADM_PROP_VAL_DEFAULT) ? DLD_PROP_DEFAULT : 0;
1207 
1208 	switch (type) {
1209 	case DLADM_PROP_VAL_CURRENT:
1210 		status = pdp->pd_get(handle, pdp, linkid, prop_val, val_cntp,
1211 		    media, dld_flags, &perm_flags);
1212 		break;
1213 
1214 	case DLADM_PROP_VAL_DEFAULT:
1215 		/*
1216 		 * If defaults are not defined for the property,
1217 		 * pd_defval.vd_name should be null. If the driver
1218 		 * has to be contacted for the value, vd_name should
1219 		 * be the empty string (""). Otherwise, dladm will
1220 		 * just print whatever is in the table.
1221 		 */
1222 		if (pdp->pd_defval.vd_name == NULL) {
1223 			status = DLADM_STATUS_NOTSUP;
1224 			break;
1225 		}
1226 
1227 		if (pdp->pd_defval.vd_name[0] != '\0') {
1228 			*val_cntp = 1;
1229 			*ret_val = pdp->pd_defval.vd_val;
1230 			free(prop_val);
1231 			return (DLADM_STATUS_OK);
1232 		}
1233 		status = pdp->pd_get(handle, pdp, linkid, prop_val, val_cntp,
1234 		    media, dld_flags, &perm_flags);
1235 		break;
1236 
1237 	case DLADM_PROP_VAL_PERSISTENT:
1238 		if (pdp->pd_flags & PD_TEMPONLY)
1239 			status = DLADM_STATUS_TEMPONLY;
1240 		else
1241 			status = i_dladm_get_linkprop_db(handle, linkid,
1242 			    prop_name, prop_val, val_cntp);
1243 		break;
1244 
1245 	default:
1246 		status = DLADM_STATUS_BADARG;
1247 		break;
1248 	}
1249 
1250 	if (status == DLADM_STATUS_OK) {
1251 		if (pdp->pd_check != NULL) {
1252 			val_desc_t *vdp;
1253 
1254 			vdp = malloc(sizeof (val_desc_t) * *val_cntp);
1255 			if (vdp == NULL)
1256 				status = DLADM_STATUS_NOMEM;
1257 			else
1258 				status = pdp->pd_check(handle, pdp, linkid,
1259 				    prop_val, *val_cntp, 0, vdp, media);
1260 			if (status == DLADM_STATUS_OK) {
1261 				for (valc = 0; valc < *val_cntp; valc++)
1262 					ret_val[valc] = vdp[valc].vd_val;
1263 			}
1264 			free(vdp);
1265 		} else {
1266 			for (valc = 0; valc < *val_cntp; valc++) {
1267 				for (i = 0; i < pdp->pd_noptval; i++) {
1268 					if (strcmp(pdp->pd_optval[i].vd_name,
1269 					    prop_val[valc]) == 0) {
1270 						ret_val[valc] =
1271 						    pdp->pd_optval[i].vd_val;
1272 						break;
1273 					}
1274 				}
1275 				if (i == pdp->pd_noptval) {
1276 					status = DLADM_STATUS_FAILED;
1277 					break;
1278 				}
1279 			}
1280 		}
1281 	}
1282 
1283 	free(prop_val);
1284 
1285 	return (status);
1286 }
1287 
1288 /*ARGSUSED*/
1289 static int
1290 i_dladm_init_one_prop(dladm_handle_t handle, datalink_id_t linkid,
1291     const char *prop_name, void *arg)
1292 {
1293 	char			*buf, **propvals;
1294 	uint_t			i, valcnt = DLADM_MAX_PROP_VALCNT;
1295 	dladm_status_t		status;
1296 	dladm_linkprop_args_t	*dla = arg;
1297 
1298 	if ((buf = malloc((sizeof (char *) + DLADM_PROP_VAL_MAX) *
1299 	    DLADM_MAX_PROP_VALCNT)) == NULL) {
1300 		return (DLADM_WALK_CONTINUE);
1301 	}
1302 
1303 	propvals = (char **)(void *)buf;
1304 	for (i = 0; i < valcnt; i++) {
1305 		propvals[i] = buf +
1306 		    sizeof (char *) * DLADM_MAX_PROP_VALCNT +
1307 		    i * DLADM_PROP_VAL_MAX;
1308 	}
1309 
1310 	if (dladm_get_linkprop(handle, linkid, DLADM_PROP_VAL_PERSISTENT,
1311 	    prop_name, propvals, &valcnt) != DLADM_STATUS_OK) {
1312 		goto done;
1313 	}
1314 
1315 	status = dladm_set_linkprop(handle, linkid, prop_name, propvals,
1316 	    valcnt, dla->dla_flags | DLADM_OPT_ACTIVE);
1317 
1318 	if (status != DLADM_STATUS_OK)
1319 		dla->dla_status = status;
1320 
1321 done:
1322 	if (buf != NULL)
1323 		free(buf);
1324 
1325 	return (DLADM_WALK_CONTINUE);
1326 }
1327 
1328 /*ARGSUSED*/
1329 static int
1330 i_dladm_init_linkprop(dladm_handle_t handle, datalink_id_t linkid, void *arg)
1331 {
1332 	datalink_class_t	class;
1333 	dladm_status_t		status;
1334 
1335 	status = dladm_datalink_id2info(handle, linkid, NULL, &class, NULL,
1336 	    NULL, 0);
1337 	if (status != DLADM_STATUS_OK)
1338 		return (DLADM_WALK_TERMINATE);
1339 
1340 	if ((class & (DATALINK_CLASS_VNIC | DATALINK_CLASS_VLAN)) == 0)
1341 		(void) dladm_init_linkprop(handle, linkid, B_TRUE);
1342 
1343 	return (DLADM_WALK_CONTINUE);
1344 }
1345 
1346 dladm_status_t
1347 dladm_init_linkprop(dladm_handle_t handle, datalink_id_t linkid,
1348     boolean_t any_media)
1349 {
1350 	dladm_status_t		status = DLADM_STATUS_OK;
1351 	datalink_media_t	dmedia;
1352 	uint32_t		media;
1353 	dladm_linkprop_args_t	*dla;
1354 
1355 	dmedia = any_media ? DATALINK_ANY_MEDIATYPE : DL_WIFI;
1356 
1357 	dla = malloc(sizeof (dladm_linkprop_args_t));
1358 	if (dla == NULL)
1359 		return (DLADM_STATUS_NOMEM);
1360 	dla->dla_flags = DLADM_OPT_BOOT;
1361 	dla->dla_status = DLADM_STATUS_OK;
1362 
1363 	if (linkid == DATALINK_ALL_LINKID) {
1364 		(void) dladm_walk_datalink_id(i_dladm_init_linkprop, handle,
1365 		    NULL, DATALINK_CLASS_ALL, dmedia, DLADM_OPT_PERSIST);
1366 	} else if (any_media ||
1367 	    ((dladm_datalink_id2info(handle, linkid, NULL, NULL, &media, NULL,
1368 	    0) == DLADM_STATUS_OK) &&
1369 	    DATALINK_MEDIA_ACCEPTED(dmedia, media))) {
1370 		(void) dladm_walk_linkprop(handle, linkid, (void *)dla,
1371 		    i_dladm_init_one_prop);
1372 		status = dla->dla_status;
1373 	}
1374 	free(dla);
1375 	return (status);
1376 }
1377 
1378 /* ARGSUSED */
1379 static dladm_status_t
1380 get_zone(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
1381     char **prop_val, uint_t *val_cnt, datalink_media_t media,
1382     uint_t flags, uint_t *perm_flags)
1383 {
1384 	char			zone_name[ZONENAME_MAX];
1385 	zoneid_t		zid;
1386 	dladm_status_t		status;
1387 
1388 	if (flags != 0)
1389 		return (DLADM_STATUS_NOTSUP);
1390 
1391 	status = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags,
1392 	    perm_flags, &zid, sizeof (zid));
1393 	if (status != DLADM_STATUS_OK)
1394 		return (status);
1395 
1396 	*val_cnt = 1;
1397 	if (zid != GLOBAL_ZONEID) {
1398 		if (getzonenamebyid(zid, zone_name, sizeof (zone_name)) < 0) {
1399 			return (dladm_errno2status(errno));
1400 		}
1401 
1402 		(void) strncpy(*prop_val, zone_name, DLADM_PROP_VAL_MAX);
1403 	} else {
1404 		*prop_val[0] = '\0';
1405 	}
1406 
1407 	return (DLADM_STATUS_OK);
1408 }
1409 
1410 typedef int (*zone_get_devroot_t)(char *, char *, size_t);
1411 
1412 static int
1413 i_dladm_get_zone_dev(char *zone_name, char *dev, size_t devlen)
1414 {
1415 	char			root[MAXPATHLEN];
1416 	zone_get_devroot_t	real_zone_get_devroot;
1417 	void			*dlhandle;
1418 	void			*sym;
1419 	int			ret;
1420 
1421 	if ((dlhandle = dlopen("libzonecfg.so.1", RTLD_LAZY)) == NULL)
1422 		return (-1);
1423 
1424 	if ((sym = dlsym(dlhandle, "zone_get_devroot")) == NULL) {
1425 		(void) dlclose(dlhandle);
1426 		return (-1);
1427 	}
1428 
1429 	real_zone_get_devroot = (zone_get_devroot_t)sym;
1430 
1431 	if ((ret = real_zone_get_devroot(zone_name, root, sizeof (root))) == 0)
1432 		(void) snprintf(dev, devlen, "%s%s", root, "/dev");
1433 	(void) dlclose(dlhandle);
1434 	return (ret);
1435 }
1436 
1437 static dladm_status_t
1438 i_dladm_update_deventry(dladm_handle_t handle, zoneid_t zid,
1439     datalink_id_t linkid, boolean_t add)
1440 {
1441 	char		path[MAXPATHLEN];
1442 	char		name[MAXLINKNAMELEN];
1443 	di_prof_t	prof = NULL;
1444 	char		zone_name[ZONENAME_MAX];
1445 	dladm_status_t	status;
1446 	int		ret;
1447 
1448 	if (getzonenamebyid(zid, zone_name, sizeof (zone_name)) < 0)
1449 		return (dladm_errno2status(errno));
1450 	if (i_dladm_get_zone_dev(zone_name, path, sizeof (path)) != 0)
1451 		return (dladm_errno2status(errno));
1452 	if (di_prof_init(path, &prof) != 0)
1453 		return (dladm_errno2status(errno));
1454 
1455 	status = dladm_linkid2legacyname(handle, linkid, name, MAXLINKNAMELEN);
1456 	if (status != DLADM_STATUS_OK)
1457 		goto cleanup;
1458 
1459 	if (add)
1460 		ret = di_prof_add_dev(prof, name);
1461 	else
1462 		ret = di_prof_add_exclude(prof, name);
1463 
1464 	if (ret != 0) {
1465 		status = dladm_errno2status(errno);
1466 		goto cleanup;
1467 	}
1468 
1469 	if (di_prof_commit(prof) != 0)
1470 		status = dladm_errno2status(errno);
1471 cleanup:
1472 	if (prof)
1473 		di_prof_fini(prof);
1474 
1475 	return (status);
1476 }
1477 
1478 /* ARGSUSED */
1479 static dladm_status_t
1480 set_zone(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
1481     val_desc_t *vdp, uint_t val_cnt, uint_t flags, datalink_media_t media)
1482 {
1483 	dladm_status_t		status = DLADM_STATUS_OK;
1484 	zoneid_t		zid_old, zid_new;
1485 	dld_ioc_zid_t		*dzp;
1486 
1487 	if (val_cnt != 1)
1488 		return (DLADM_STATUS_BADVALCNT);
1489 
1490 	dzp = (dld_ioc_zid_t *)vdp->vd_val;
1491 
1492 	status = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags,
1493 	    NULL, &zid_old, sizeof (zid_old));
1494 	if (status != DLADM_STATUS_OK)
1495 		return (status);
1496 
1497 	zid_new = dzp->diz_zid;
1498 	if (zid_new == zid_old)
1499 		return (DLADM_STATUS_OK);
1500 
1501 	if ((status = set_public_prop(handle, pdp, linkid, vdp, val_cnt,
1502 	    flags, media)) != DLADM_STATUS_OK)
1503 		return (status);
1504 
1505 	/*
1506 	 * It is okay to fail to update the /dev entry (some vanity-named
1507 	 * links do not have a /dev entry).
1508 	 */
1509 	if (zid_old != GLOBAL_ZONEID) {
1510 		(void) i_dladm_update_deventry(handle, zid_old, linkid,
1511 		    B_FALSE);
1512 	}
1513 	if (zid_new != GLOBAL_ZONEID)
1514 		(void) i_dladm_update_deventry(handle, zid_new, linkid, B_TRUE);
1515 
1516 	return (DLADM_STATUS_OK);
1517 }
1518 
1519 /* ARGSUSED */
1520 static dladm_status_t
1521 check_zone(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
1522     char **prop_val, uint_t val_cnt, uint_t flags, val_desc_t *vdp,
1523     datalink_media_t media)
1524 {
1525 	char		*zone_name;
1526 	zoneid_t	zoneid;
1527 	dladm_status_t	status = DLADM_STATUS_OK;
1528 	dld_ioc_zid_t	*dzp;
1529 
1530 	if (val_cnt != 1)
1531 		return (DLADM_STATUS_BADVALCNT);
1532 
1533 	dzp = malloc(sizeof (dld_ioc_zid_t));
1534 	if (dzp == NULL)
1535 		return (DLADM_STATUS_NOMEM);
1536 
1537 	zone_name = (prop_val != NULL) ? *prop_val : GLOBAL_ZONENAME;
1538 	if ((zoneid = getzoneidbyname(zone_name)) == -1) {
1539 		status = DLADM_STATUS_BADVAL;
1540 		goto done;
1541 	}
1542 
1543 	if (zoneid != GLOBAL_ZONEID) {
1544 		ushort_t	flags;
1545 
1546 		if (zone_getattr(zoneid, ZONE_ATTR_FLAGS, &flags,
1547 		    sizeof (flags)) < 0) {
1548 			status = dladm_errno2status(errno);
1549 			goto done;
1550 		}
1551 
1552 		if (!(flags & ZF_NET_EXCL)) {
1553 			status = DLADM_STATUS_BADVAL;
1554 			goto done;
1555 		}
1556 	}
1557 
1558 	(void) memset(dzp, 0, sizeof (dld_ioc_zid_t));
1559 
1560 	dzp->diz_zid = zoneid;
1561 	dzp->diz_linkid = linkid;
1562 
1563 	vdp->vd_val = (uintptr_t)dzp;
1564 	return (DLADM_STATUS_OK);
1565 done:
1566 	free(dzp);
1567 	return (status);
1568 }
1569 
1570 /* ARGSUSED */
1571 static dladm_status_t
1572 get_maxbw(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
1573     char **prop_val, uint_t *val_cnt, datalink_media_t media,
1574     uint_t flags, uint_t *perm_flags)
1575 {
1576 	mac_resource_props_t	mrp;
1577 	dladm_status_t		status;
1578 
1579 	status = i_dladm_get_public_prop(handle, linkid, "resource", flags,
1580 	    perm_flags, &mrp, sizeof (mrp));
1581 	if (status != DLADM_STATUS_OK)
1582 		return (status);
1583 
1584 	if ((mrp.mrp_mask & MRP_MAXBW) == 0) {
1585 		*val_cnt = 0;
1586 		return (DLADM_STATUS_OK);
1587 	}
1588 
1589 	(void) dladm_bw2str(mrp.mrp_maxbw, prop_val[0]);
1590 	*val_cnt = 1;
1591 	return (DLADM_STATUS_OK);
1592 }
1593 
1594 /* ARGSUSED */
1595 static dladm_status_t
1596 check_maxbw(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
1597     char **prop_val, uint_t val_cnt, uint_t flags, val_desc_t *vdp,
1598     datalink_media_t media)
1599 {
1600 	uint64_t	*maxbw;
1601 	dladm_status_t	status = DLADM_STATUS_OK;
1602 
1603 	if (val_cnt != 1)
1604 		return (DLADM_STATUS_BADVALCNT);
1605 
1606 	maxbw = malloc(sizeof (uint64_t));
1607 	if (maxbw == NULL)
1608 		return (DLADM_STATUS_NOMEM);
1609 
1610 	status = dladm_str2bw(*prop_val, maxbw);
1611 	if (status != DLADM_STATUS_OK) {
1612 		free(maxbw);
1613 		return (status);
1614 	}
1615 
1616 	if ((*maxbw < MRP_MAXBW_MINVAL) && (*maxbw != 0)) {
1617 		free(maxbw);
1618 		return (DLADM_STATUS_MINMAXBW);
1619 	}
1620 
1621 	vdp->vd_val = (uintptr_t)maxbw;
1622 	return (DLADM_STATUS_OK);
1623 }
1624 
1625 /* ARGSUSED */
1626 dladm_status_t
1627 extract_maxbw(val_desc_t *vdp, uint_t cnt, void *arg)
1628 {
1629 	mac_resource_props_t *mrp = arg;
1630 
1631 	if (vdp->vd_val == RESET_VAL) {
1632 		mrp->mrp_maxbw = MRP_MAXBW_RESETVAL;
1633 	} else {
1634 		bcopy((char *)vdp->vd_val, &mrp->mrp_maxbw, sizeof (uint64_t));
1635 	}
1636 	mrp->mrp_mask |= MRP_MAXBW;
1637 
1638 	return (DLADM_STATUS_OK);
1639 }
1640 
1641 /* ARGSUSED */
1642 static dladm_status_t
1643 get_cpus(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
1644     char **prop_val, uint_t *val_cnt, datalink_media_t media,
1645     uint_t flags, uint_t *perm_flags)
1646 {
1647 	dladm_status_t		status;
1648 	mac_resource_props_t	mrp;
1649 	int			i;
1650 	uint32_t		ncpus;
1651 
1652 	if (strcmp(pdp->pd_name, "cpus-effective") == 0) {
1653 		status = i_dladm_get_public_prop(handle, linkid,
1654 		    "resource-effective", flags, perm_flags, &mrp,
1655 		    sizeof (mrp));
1656 	} else {
1657 		status = i_dladm_get_public_prop(handle, linkid,
1658 		    "resource", flags, perm_flags, &mrp, sizeof (mrp));
1659 	}
1660 
1661 	if (status != DLADM_STATUS_OK)
1662 		return (status);
1663 
1664 	ncpus = mrp.mrp_ncpus;
1665 	if (ncpus > *val_cnt)
1666 		return (DLADM_STATUS_TOOSMALL);
1667 
1668 	if (ncpus == 0) {
1669 		*val_cnt = 0;
1670 		return (DLADM_STATUS_OK);
1671 	}
1672 
1673 	*val_cnt = ncpus;
1674 	for (i = 0; i < ncpus; i++) {
1675 		(void) snprintf(prop_val[i], DLADM_PROP_VAL_MAX,
1676 		    "%u", mrp.mrp_cpu[i]);
1677 	}
1678 	return (DLADM_STATUS_OK);
1679 }
1680 
1681 /* ARGSUSED */
1682 static dladm_status_t
1683 check_cpus(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
1684     char **prop_val, uint_t val_cnt, uint_t flags, val_desc_t *vdp,
1685     datalink_media_t media)
1686 {
1687 	uint32_t		cpuid;
1688 	int			i, j, rc;
1689 	char			*endp;
1690 	long			nproc = sysconf(_SC_NPROCESSORS_CONF);
1691 	mac_resource_props_t	mrp;
1692 	dladm_status_t		status;
1693 	uint_t			perm_flags;
1694 
1695 	/* Get the current pool property */
1696 	status = i_dladm_get_public_prop(handle, linkid, "resource", 0,
1697 	    &perm_flags, &mrp, sizeof (mrp));
1698 
1699 	if (status == DLADM_STATUS_OK) {
1700 		/* Can't set cpus if a pool is set */
1701 		if (strlen(mrp.mrp_pool) != 0)
1702 			return (DLADM_STATUS_POOLCPU);
1703 	}
1704 
1705 	bzero(&mrp, sizeof (mac_resource_props_t));
1706 
1707 	for (i = 0; i < val_cnt; i++) {
1708 		errno = 0;
1709 		cpuid = strtol(prop_val[i], &endp, 10);
1710 		if (errno != 0 || *endp != '\0')
1711 			return (DLADM_STATUS_BADVAL);
1712 
1713 		if (cpuid >= nproc)
1714 			return (DLADM_STATUS_CPUMAX);
1715 
1716 		rc = p_online(cpuid, P_STATUS);
1717 		if (rc < 1)
1718 			return (DLADM_STATUS_CPUERR);
1719 
1720 		if (rc != P_ONLINE)
1721 			return (DLADM_STATUS_CPUNOTONLINE);
1722 
1723 		vdp[i].vd_val = (uintptr_t)cpuid;
1724 	}
1725 
1726 	/* Check for duplicates */
1727 	for (i = 0; i < val_cnt; i++) {
1728 		for (j = 0; j < val_cnt; j++) {
1729 			if (i != j && vdp[i].vd_val == vdp[j].vd_val)
1730 				return (DLADM_STATUS_BADVAL);
1731 		}
1732 	}
1733 	return (DLADM_STATUS_OK);
1734 }
1735 
1736 /* ARGSUSED */
1737 dladm_status_t
1738 extract_cpus(val_desc_t *vdp, uint_t cnt, void *arg)
1739 {
1740 	mac_resource_props_t	*mrp = arg;
1741 	int			i;
1742 
1743 	if (vdp[0].vd_val == RESET_VAL) {
1744 		bzero(&mrp->mrp_cpus, sizeof (mac_cpus_t));
1745 		mrp->mrp_mask |= MRP_CPUS;
1746 		return (DLADM_STATUS_OK);
1747 	}
1748 
1749 	for (i = 0; i < cnt; i++)
1750 		mrp->mrp_cpu[i] = (uint32_t)vdp[i].vd_val;
1751 
1752 	mrp->mrp_ncpus = cnt;
1753 	mrp->mrp_mask |= (MRP_CPUS|MRP_CPUS_USERSPEC);
1754 	mrp->mrp_fanout_mode = MCM_CPUS;
1755 	mrp->mrp_rx_intr_cpu = -1;
1756 
1757 	return (DLADM_STATUS_OK);
1758 }
1759 
1760 /*
1761  * Get the pool datalink property from the kernel.  This is used
1762  * for both the user specified pool and effective pool properties.
1763  */
1764 /* ARGSUSED */
1765 static dladm_status_t
1766 get_pool(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
1767     char **prop_val, uint_t *val_cnt, datalink_media_t media,
1768     uint_t flags, uint_t *perm_flags)
1769 {
1770 	mac_resource_props_t	mrp;
1771 	dladm_status_t		status;
1772 
1773 	if (strcmp(pdp->pd_name, "pool-effective") == 0) {
1774 		status = i_dladm_get_public_prop(handle, linkid,
1775 		    "resource-effective", flags, perm_flags, &mrp,
1776 		    sizeof (mrp));
1777 	} else {
1778 		status = i_dladm_get_public_prop(handle, linkid,
1779 		    "resource", flags, perm_flags, &mrp, sizeof (mrp));
1780 	}
1781 
1782 	if (status != DLADM_STATUS_OK)
1783 		return (status);
1784 
1785 	if (strlen(mrp.mrp_pool) == 0) {
1786 		(*prop_val)[0] = '\0';
1787 	} else {
1788 		(void) snprintf(*prop_val, DLADM_PROP_VAL_MAX,
1789 		    "%s", mrp.mrp_pool);
1790 	}
1791 	*val_cnt = 1;
1792 
1793 	return (DLADM_STATUS_OK);
1794 }
1795 
1796 /* ARGSUSED */
1797 static dladm_status_t
1798 check_pool(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
1799     char **prop_val, uint_t val_cnt, uint_t flags, val_desc_t *vdp,
1800     datalink_media_t media)
1801 {
1802 	pool_conf_t		*poolconf;
1803 	pool_t			*pool;
1804 	mac_resource_props_t	mrp;
1805 	dladm_status_t		status;
1806 	uint_t			perm_flags;
1807 	char			*poolname;
1808 
1809 	/* Get the current cpus property */
1810 	status = i_dladm_get_public_prop(handle, linkid, "resource", 0,
1811 	    &perm_flags, &mrp, sizeof (mrp));
1812 
1813 	if (status == DLADM_STATUS_OK) {
1814 		/* Can't set pool if cpus are set */
1815 		if (mrp.mrp_ncpus != 0)
1816 			return (DLADM_STATUS_POOLCPU);
1817 	}
1818 
1819 	poolname = malloc(sizeof (mrp.mrp_pool));
1820 	if (poolname == NULL)
1821 		return (DLADM_STATUS_NOMEM);
1822 
1823 	/* Check for pool's availability if not booting */
1824 	if ((flags & DLADM_OPT_BOOT) == 0) {
1825 
1826 		/* Allocate and open pool configuration */
1827 		if ((poolconf = pool_conf_alloc()) == NULL)
1828 			return (DLADM_STATUS_BADVAL);
1829 
1830 		if (pool_conf_open(poolconf, pool_dynamic_location(), PO_RDONLY)
1831 		    != PO_SUCCESS) {
1832 			pool_conf_free(poolconf);
1833 			return (DLADM_STATUS_BADVAL);
1834 		}
1835 
1836 		/* Look for pool name */
1837 		if ((pool = pool_get_pool(poolconf, *prop_val)) == NULL) {
1838 			pool_conf_free(poolconf);
1839 			return (DLADM_STATUS_BADVAL);
1840 		}
1841 
1842 		pool_conf_free(poolconf);
1843 		free(pool);
1844 	}
1845 
1846 	(void) strlcpy(poolname, *prop_val, sizeof (mrp.mrp_pool));
1847 	vdp->vd_val = (uintptr_t)poolname;
1848 
1849 	return (DLADM_STATUS_OK);
1850 }
1851 
1852 /* ARGSUSED */
1853 dladm_status_t
1854 extract_pool(val_desc_t *vdp, uint_t cnt, void *arg)
1855 {
1856 	mac_resource_props_t	*mrp = (mac_resource_props_t *)arg;
1857 
1858 	if (vdp->vd_val == RESET_VAL) {
1859 		bzero(&mrp->mrp_pool, sizeof (mrp->mrp_pool));
1860 		mrp->mrp_mask |= MRP_POOL;
1861 		return (DLADM_STATUS_OK);
1862 	}
1863 
1864 	(void) strlcpy(mrp->mrp_pool, (char *)vdp->vd_val,
1865 	    sizeof (mrp->mrp_pool));
1866 	mrp->mrp_mask |= MRP_POOL;
1867 	/*
1868 	 * Use MCM_CPUS since the fanout count is not user specified
1869 	 * and will be determined by the cpu list generated from the
1870 	 * pool.
1871 	 */
1872 	mrp->mrp_fanout_mode = MCM_CPUS;
1873 
1874 	return (DLADM_STATUS_OK);
1875 }
1876 
1877 /* ARGSUSED */
1878 static dladm_status_t
1879 get_priority(dladm_handle_t handle, prop_desc_t *pdp,
1880     datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
1881     datalink_media_t media, uint_t flags, uint_t *perm_flags)
1882 {
1883 	mac_resource_props_t	mrp;
1884 	mac_priority_level_t	pri;
1885 	dladm_status_t		status;
1886 
1887 	status = i_dladm_get_public_prop(handle, linkid, "resource", flags,
1888 	    perm_flags, &mrp, sizeof (mrp));
1889 	if (status != DLADM_STATUS_OK)
1890 		return (status);
1891 
1892 	pri = ((mrp.mrp_mask & MRP_PRIORITY) == 0) ? MPL_HIGH :
1893 	    mrp.mrp_priority;
1894 
1895 	(void) dladm_pri2str(pri, prop_val[0]);
1896 	*val_cnt = 1;
1897 	return (DLADM_STATUS_OK);
1898 }
1899 
1900 /* ARGSUSED */
1901 dladm_status_t
1902 extract_priority(val_desc_t *vdp, uint_t cnt, void *arg)
1903 {
1904 	mac_resource_props_t *mrp = arg;
1905 
1906 	if (cnt != 1)
1907 		return (DLADM_STATUS_BADVAL);
1908 
1909 	mrp->mrp_priority = (mac_priority_level_t)vdp->vd_val;
1910 	mrp->mrp_mask |= MRP_PRIORITY;
1911 
1912 	return (DLADM_STATUS_OK);
1913 }
1914 
1915 /*
1916  * Determines the size of the structure that needs to be sent to drivers
1917  * for retrieving the property range values.
1918  */
1919 static int
1920 i_dladm_range_size(mac_propval_range_t *r, size_t *sz)
1921 {
1922 	uint_t count = r->mpr_count;
1923 
1924 	*sz = sizeof (mac_propval_range_t);
1925 	--count;
1926 
1927 	switch (r->mpr_type) {
1928 	case MAC_PROPVAL_UINT32:
1929 		*sz += (count * sizeof (mac_propval_uint32_range_t));
1930 		return (0);
1931 	default:
1932 		break;
1933 	}
1934 	*sz = 0;
1935 	return (EINVAL);
1936 }
1937 
1938 
1939 /* ARGSUSED */
1940 static dladm_status_t
1941 check_rings(dladm_handle_t handle, prop_desc_t *pdp,
1942     datalink_id_t linkid, char **prop_val, uint_t val_cnt, uint_t flags,
1943     val_desc_t *v, datalink_media_t media)
1944 {
1945 	if (val_cnt != 1)
1946 		return (DLADM_STATUS_BADVAL);
1947 	if (strncasecmp(prop_val[0], "hw", strlen("hw")) == 0) {
1948 		v->vd_val = UNSPEC_VAL;
1949 	} else if (strncasecmp(prop_val[0], "sw", strlen("sw")) == 0) {
1950 		v->vd_val = 0;
1951 	} else {
1952 		v->vd_val = strtoul(prop_val[0], NULL, 0);
1953 		if (v->vd_val == 0)
1954 			return (DLADM_STATUS_BADVAL);
1955 	}
1956 	return (DLADM_STATUS_OK);
1957 }
1958 
1959 /* ARGSUSED */
1960 static dladm_status_t
1961 get_rings_range(dladm_handle_t handle, prop_desc_t *pdp,
1962     datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
1963     datalink_media_t media, uint_t flags, uint_t *perm_flags)
1964 {
1965 	dld_ioc_macprop_t *dip;
1966 	dladm_status_t status = DLADM_STATUS_OK;
1967 	mac_propval_range_t *rangep;
1968 	size_t	sz;
1969 	mac_propval_uint32_range_t *ur;
1970 
1971 	sz = sizeof (mac_propval_range_t);
1972 
1973 	if ((dip = i_dladm_buf_alloc_by_name(sz, linkid, pdp->pd_name, flags,
1974 	    &status)) == NULL)
1975 		return (status);
1976 
1977 	status = i_dladm_macprop(handle, dip, B_FALSE);
1978 	if (status != DLADM_STATUS_OK)
1979 		return (status);
1980 
1981 	rangep = (mac_propval_range_t *)(void *)&dip->pr_val;
1982 	*val_cnt = 1;
1983 	ur = &rangep->mpr_range_uint32[0];
1984 	/* This is the case where the dev doesn't have any rings/groups */
1985 	if (rangep->mpr_count == 0) {
1986 		(*prop_val)[0] = '\0';
1987 	/*
1988 	 * This is the case where the dev supports rings, but static
1989 	 * grouping.
1990 	 */
1991 	} else if (ur->mpur_min == ur->mpur_max &&
1992 	    ur->mpur_max == 0) {
1993 		(void) snprintf(prop_val[0], DLADM_PROP_VAL_MAX, "sw,hw");
1994 	/*
1995 	 * This is the case where the dev supports rings and dynamic
1996 	 * grouping, but has only one value (say 2 rings and 2 groups).
1997 	 */
1998 	} else if (ur->mpur_min == ur->mpur_max) {
1999 		(void) snprintf(prop_val[0], DLADM_PROP_VAL_MAX, "sw,hw,%d",
2000 		    ur->mpur_min);
2001 	/*
2002 	 * This is the case where the dev supports rings and dynamic
2003 	 * grouping and has a range of rings.
2004 	 */
2005 	} else {
2006 		(void) snprintf(prop_val[0], DLADM_PROP_VAL_MAX,
2007 		    "sw,hw,<%ld-%ld>", ur->mpur_min, ur->mpur_max);
2008 	}
2009 	free(dip);
2010 	return (status);
2011 }
2012 
2013 
2014 /* ARGSUSED */
2015 static dladm_status_t
2016 get_rxrings(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
2017     char **prop_val, uint_t *val_cnt, datalink_media_t media,
2018     uint_t flags, uint_t *perm_flags)
2019 {
2020 	mac_resource_props_t	mrp;
2021 	dladm_status_t		status;
2022 	uint32_t		nrings = 0;
2023 
2024 	/*
2025 	 * Get the number of (effective-)rings from the resource property.
2026 	 */
2027 	if (strcmp(pdp->pd_name, "rxrings-effective") == 0) {
2028 		status = i_dladm_get_public_prop(handle, linkid,
2029 		    "resource-effective", flags, perm_flags, &mrp,
2030 		    sizeof (mrp));
2031 	} else {
2032 		/*
2033 		 * Get the permissions from the "rxrings" property.
2034 		 */
2035 		status = i_dladm_get_public_prop(handle, linkid, "rxrings",
2036 		    flags, perm_flags, NULL, 0);
2037 		if (status != DLADM_STATUS_OK)
2038 			return (status);
2039 
2040 		status = i_dladm_get_public_prop(handle, linkid,
2041 		    "resource", flags, NULL, &mrp, sizeof (mrp));
2042 	}
2043 
2044 	if (status != DLADM_STATUS_OK)
2045 		return (status);
2046 
2047 	if ((mrp.mrp_mask & MRP_RX_RINGS) == 0) {
2048 		*val_cnt = 0;
2049 		return (DLADM_STATUS_OK);
2050 	}
2051 	nrings = mrp.mrp_nrxrings;
2052 	*val_cnt = 1;
2053 	if (mrp.mrp_mask & MRP_RXRINGS_UNSPEC)
2054 		(void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "hw");
2055 	else if (nrings == 0)
2056 		(void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "sw");
2057 	else
2058 		(void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "%ld", nrings);
2059 	return (DLADM_STATUS_OK);
2060 }
2061 
2062 /* ARGSUSED */
2063 dladm_status_t
2064 extract_rxrings(val_desc_t *vdp, uint_t cnt, void *arg)
2065 {
2066 	mac_resource_props_t	*mrp = (mac_resource_props_t *)arg;
2067 
2068 	mrp->mrp_nrxrings = 0;
2069 	if (vdp->vd_val == RESET_VAL)
2070 		mrp->mrp_mask = MRP_RINGS_RESET;
2071 	else if (vdp->vd_val == UNSPEC_VAL)
2072 		mrp->mrp_mask = MRP_RXRINGS_UNSPEC;
2073 	else
2074 		mrp->mrp_nrxrings = vdp->vd_val;
2075 	mrp->mrp_mask |= MRP_RX_RINGS;
2076 
2077 	return (DLADM_STATUS_OK);
2078 }
2079 
2080 /* ARGSUSED */
2081 static dladm_status_t
2082 get_txrings(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
2083     char **prop_val, uint_t *val_cnt, datalink_media_t media,
2084     uint_t flags, uint_t *perm_flags)
2085 {
2086 	mac_resource_props_t	mrp;
2087 	dladm_status_t		status;
2088 	uint32_t		nrings = 0;
2089 
2090 
2091 	/*
2092 	 * Get the number of (effective-)rings from the resource property.
2093 	 */
2094 	if (strcmp(pdp->pd_name, "txrings-effective") == 0) {
2095 		status = i_dladm_get_public_prop(handle, linkid,
2096 		    "resource-effective", flags, perm_flags, &mrp,
2097 		    sizeof (mrp));
2098 	} else {
2099 		/*
2100 		 * Get the permissions from the "txrings" property.
2101 		 */
2102 		status = i_dladm_get_public_prop(handle, linkid, "txrings",
2103 		    flags, perm_flags, NULL, 0);
2104 		if (status != DLADM_STATUS_OK)
2105 			return (status);
2106 
2107 		/*
2108 		 * Get the number of rings from the "resource" property.
2109 		 */
2110 		status = i_dladm_get_public_prop(handle, linkid, "resource",
2111 		    flags, NULL, &mrp, sizeof (mrp));
2112 	}
2113 
2114 	if (status != DLADM_STATUS_OK)
2115 		return (status);
2116 
2117 	if ((mrp.mrp_mask & MRP_TX_RINGS) == 0) {
2118 		*val_cnt = 0;
2119 		return (DLADM_STATUS_OK);
2120 	}
2121 	nrings = mrp.mrp_ntxrings;
2122 	*val_cnt = 1;
2123 	if (mrp.mrp_mask & MRP_TXRINGS_UNSPEC)
2124 		(void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "hw");
2125 	else if (nrings == 0)
2126 		(void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "sw");
2127 	else
2128 		(void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "%ld", nrings);
2129 	return (DLADM_STATUS_OK);
2130 }
2131 
2132 /* ARGSUSED */
2133 dladm_status_t
2134 extract_txrings(val_desc_t *vdp, uint_t cnt, void *arg)
2135 {
2136 	mac_resource_props_t	*mrp = (mac_resource_props_t *)arg;
2137 
2138 	mrp->mrp_ntxrings = 0;
2139 	if (vdp->vd_val == RESET_VAL)
2140 		mrp->mrp_mask = MRP_RINGS_RESET;
2141 	else if (vdp->vd_val == UNSPEC_VAL)
2142 		mrp->mrp_mask = MRP_TXRINGS_UNSPEC;
2143 	else
2144 		mrp->mrp_ntxrings = vdp->vd_val;
2145 	mrp->mrp_mask |= MRP_TX_RINGS;
2146 
2147 	return (DLADM_STATUS_OK);
2148 }
2149 
2150 /* ARGSUSED */
2151 static dladm_status_t
2152 get_cntavail(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
2153     char **prop_val, uint_t *val_cnt, datalink_media_t media, uint_t flags,
2154     uint_t *perm_flags)
2155 {
2156 	if (flags & DLD_PROP_DEFAULT)
2157 		return (DLADM_STATUS_NOTDEFINED);
2158 
2159 	return (get_uint32(handle, pdp, linkid, prop_val, val_cnt, media,
2160 	    flags, perm_flags));
2161 }
2162 
2163 /* ARGSUSED */
2164 static dladm_status_t
2165 set_resource(dladm_handle_t handle, prop_desc_t *pdp,
2166     datalink_id_t linkid, val_desc_t *vdp, uint_t val_cnt,
2167     uint_t flags, datalink_media_t media)
2168 {
2169 	mac_resource_props_t	mrp;
2170 	dladm_status_t		status = DLADM_STATUS_OK;
2171 	dld_ioc_macprop_t	*dip;
2172 	int			i;
2173 
2174 	bzero(&mrp, sizeof (mac_resource_props_t));
2175 	dip = i_dladm_buf_alloc_by_name(0, linkid, "resource",
2176 	    flags, &status);
2177 
2178 	if (dip == NULL)
2179 		return (status);
2180 
2181 	for (i = 0; i < DLADM_MAX_RSRC_PROP; i++) {
2182 		resource_prop_t	*rp = &rsrc_prop_table[i];
2183 
2184 		if (strcmp(pdp->pd_name, rp->rp_name) != 0)
2185 			continue;
2186 
2187 		status = rp->rp_extract(vdp, val_cnt, &mrp);
2188 		if (status != DLADM_STATUS_OK)
2189 			goto done;
2190 
2191 		break;
2192 	}
2193 
2194 	(void) memcpy(dip->pr_val, &mrp, dip->pr_valsize);
2195 	status = i_dladm_macprop(handle, dip, B_TRUE);
2196 
2197 done:
2198 	free(dip);
2199 	return (status);
2200 }
2201 
2202 /* ARGSUSED */
2203 static dladm_status_t
2204 get_protection(dladm_handle_t handle, prop_desc_t *pdp,
2205     datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
2206     datalink_media_t media, uint_t flags, uint_t *perm_flags)
2207 {
2208 	mac_resource_props_t	mrp;
2209 	mac_protect_t		*p;
2210 	dladm_status_t		status;
2211 	uint32_t		i, cnt = 0, setbits[32];
2212 
2213 	status = i_dladm_get_public_prop(handle, linkid, "resource", flags,
2214 	    perm_flags, &mrp, sizeof (mrp));
2215 	if (status != DLADM_STATUS_OK)
2216 		return (status);
2217 
2218 	p = &mrp.mrp_protect;
2219 	if ((mrp.mrp_mask & MRP_PROTECT) == 0) {
2220 		*val_cnt = 0;
2221 		return (DLADM_STATUS_OK);
2222 	}
2223 	dladm_find_setbits32(p->mp_types, setbits, &cnt);
2224 	if (cnt > *val_cnt)
2225 		return (DLADM_STATUS_BADVALCNT);
2226 
2227 	for (i = 0; i < cnt; i++)
2228 		(void) dladm_protect2str(setbits[i], prop_val[i]);
2229 
2230 	*val_cnt = cnt;
2231 	return (DLADM_STATUS_OK);
2232 }
2233 
2234 /* ARGSUSED */
2235 static dladm_status_t
2236 get_allowedips(dladm_handle_t handle, prop_desc_t *pdp,
2237     datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
2238     datalink_media_t media, uint_t flags, uint_t *perm_flags)
2239 {
2240 	mac_resource_props_t	mrp;
2241 	mac_protect_t		*p;
2242 	dladm_status_t		status;
2243 	int			i;
2244 
2245 	status = i_dladm_get_public_prop(handle, linkid, "resource", flags,
2246 	    perm_flags, &mrp, sizeof (mrp));
2247 	if (status != DLADM_STATUS_OK)
2248 		return (status);
2249 
2250 	p = &mrp.mrp_protect;
2251 	if (p->mp_ipaddrcnt == 0) {
2252 		*val_cnt = 0;
2253 		return (DLADM_STATUS_OK);
2254 	}
2255 	if (p->mp_ipaddrcnt > *val_cnt)
2256 		return (DLADM_STATUS_BADVALCNT);
2257 
2258 	for (i = 0; i < p->mp_ipaddrcnt; i++) {
2259 		if (p->mp_ipaddrs[i].ip_version == IPV4_VERSION) {
2260 			ipaddr_t	v4addr;
2261 
2262 			v4addr = V4_PART_OF_V6(p->mp_ipaddrs[i].ip_addr);
2263 			(void) dladm_ipv4addr2str(&v4addr, prop_val[i]);
2264 		} else {
2265 			(void) dladm_ipv6addr2str(&p->mp_ipaddrs[i].ip_addr,
2266 			    prop_val[i]);
2267 		}
2268 	}
2269 	*val_cnt = p->mp_ipaddrcnt;
2270 	return (DLADM_STATUS_OK);
2271 }
2272 
2273 dladm_status_t
2274 extract_protection(val_desc_t *vdp, uint_t cnt, void *arg)
2275 {
2276 	mac_resource_props_t	*mrp = arg;
2277 	uint32_t		types = 0;
2278 	int			i;
2279 
2280 	for (i = 0; i < cnt; i++)
2281 		types |= (uint32_t)vdp[i].vd_val;
2282 
2283 	mrp->mrp_protect.mp_types = types;
2284 	mrp->mrp_mask |= MRP_PROTECT;
2285 	return (DLADM_STATUS_OK);
2286 }
2287 
2288 dladm_status_t
2289 extract_allowedips(val_desc_t *vdp, uint_t cnt, void *arg)
2290 {
2291 	mac_resource_props_t	*mrp = arg;
2292 	mac_protect_t		*p = &mrp->mrp_protect;
2293 	int			i;
2294 
2295 	if (vdp->vd_val == 0) {
2296 		cnt = (uint_t)-1;
2297 	} else {
2298 		for (i = 0; i < cnt; i++) {
2299 			bcopy((void *)vdp[i].vd_val, &p->mp_ipaddrs[i],
2300 			    sizeof (mac_ipaddr_t));
2301 		}
2302 	}
2303 	p->mp_ipaddrcnt = cnt;
2304 	mrp->mrp_mask |= MRP_PROTECT;
2305 	return (DLADM_STATUS_OK);
2306 }
2307 
2308 static dladm_status_t
2309 check_single_ip(char *buf, mac_ipaddr_t *addr)
2310 {
2311 	dladm_status_t	status;
2312 	ipaddr_t	v4addr;
2313 	in6_addr_t	v6addr;
2314 	boolean_t	isv4 = B_TRUE;
2315 
2316 	status = dladm_str2ipv4addr(buf, &v4addr);
2317 	if (status == DLADM_STATUS_INVALID_IP) {
2318 		status = dladm_str2ipv6addr(buf, &v6addr);
2319 		if (status == DLADM_STATUS_OK)
2320 			isv4 = B_FALSE;
2321 	}
2322 	if (status != DLADM_STATUS_OK)
2323 		return (status);
2324 
2325 	if (isv4) {
2326 		if (v4addr == INADDR_ANY)
2327 			return (DLADM_STATUS_INVALID_IP);
2328 
2329 		IN6_IPADDR_TO_V4MAPPED(v4addr, &addr->ip_addr);
2330 		addr->ip_version = IPV4_VERSION;
2331 	} else {
2332 		if (IN6_IS_ADDR_UNSPECIFIED(&v6addr))
2333 			return (DLADM_STATUS_INVALID_IP);
2334 
2335 		addr->ip_addr = v6addr;
2336 		addr->ip_version = IPV6_VERSION;
2337 	}
2338 	return (DLADM_STATUS_OK);
2339 }
2340 
2341 /* ARGSUSED */
2342 static dladm_status_t
2343 check_allowedips(dladm_handle_t handle, prop_desc_t *pdp,
2344     datalink_id_t linkid, char **prop_val, uint_t val_cnt, uint_t flags,
2345     val_desc_t *vdp, datalink_media_t media)
2346 {
2347 	dladm_status_t	status;
2348 	mac_ipaddr_t	*addr;
2349 	int		i;
2350 
2351 	if (val_cnt > MPT_MAXIPADDR)
2352 		return (DLADM_STATUS_BADVALCNT);
2353 
2354 	for (i = 0; i < val_cnt; i++) {
2355 		if ((addr = calloc(1, sizeof (mac_ipaddr_t))) == NULL) {
2356 			status = DLADM_STATUS_NOMEM;
2357 			goto fail;
2358 		}
2359 		vdp[i].vd_val = (uintptr_t)addr;
2360 
2361 		status = check_single_ip(prop_val[i], addr);
2362 		if (status != DLADM_STATUS_OK)
2363 			goto fail;
2364 	}
2365 	return (DLADM_STATUS_OK);
2366 
2367 fail:
2368 	for (i = 0; i < val_cnt; i++) {
2369 		free((void *)vdp[i].vd_val);
2370 		vdp[i].vd_val = NULL;
2371 	}
2372 	return (status);
2373 }
2374 
2375 static void
2376 dladm_cid2str(mac_dhcpcid_t *cid, char *buf)
2377 {
2378 	char	tmp_buf[DLADM_STRSIZE];
2379 	uint_t	hexlen;
2380 
2381 	switch (cid->dc_form) {
2382 	case CIDFORM_TYPED: {
2383 		uint16_t	duidtype, hwtype;
2384 		uint32_t	timestamp, ennum;
2385 		char		*lladdr;
2386 
2387 		if (cid->dc_len < sizeof (duidtype))
2388 			goto fail;
2389 
2390 		bcopy(cid->dc_id, &duidtype, sizeof (duidtype));
2391 		duidtype = ntohs(duidtype);
2392 		switch (duidtype) {
2393 		case DHCPV6_DUID_LLT: {
2394 			duid_llt_t	llt;
2395 
2396 			if (cid->dc_len < sizeof (llt))
2397 				goto fail;
2398 
2399 			bcopy(cid->dc_id, &llt, sizeof (llt));
2400 			hwtype = ntohs(llt.dllt_hwtype);
2401 			timestamp = ntohl(llt.dllt_time);
2402 			lladdr = _link_ntoa(cid->dc_id + sizeof (llt),
2403 			    NULL, cid->dc_len - sizeof (llt), IFT_OTHER);
2404 			if (lladdr == NULL)
2405 				goto fail;
2406 
2407 			(void) snprintf(buf, DLADM_STRSIZE, "%d.%d.%d.%s",
2408 			    duidtype, hwtype, timestamp, lladdr);
2409 			free(lladdr);
2410 			break;
2411 		}
2412 		case DHCPV6_DUID_EN: {
2413 			duid_en_t	en;
2414 
2415 			if (cid->dc_len < sizeof (en))
2416 				goto fail;
2417 
2418 			bcopy(cid->dc_id, &en, sizeof (en));
2419 			ennum = DHCPV6_GET_ENTNUM(&en);
2420 			hexlen = sizeof (tmp_buf);
2421 			if (octet_to_hexascii(cid->dc_id + sizeof (en),
2422 			    cid->dc_len - sizeof (en), tmp_buf, &hexlen) != 0)
2423 				goto fail;
2424 
2425 			(void) snprintf(buf, DLADM_STRSIZE, "%d.%d.%s",
2426 			    duidtype, ennum, tmp_buf);
2427 			break;
2428 		}
2429 		case DHCPV6_DUID_LL: {
2430 			duid_ll_t	ll;
2431 
2432 			if (cid->dc_len < sizeof (ll))
2433 				goto fail;
2434 
2435 			bcopy(cid->dc_id, &ll, sizeof (ll));
2436 			hwtype = ntohs(ll.dll_hwtype);
2437 			lladdr = _link_ntoa(cid->dc_id + sizeof (ll),
2438 			    NULL, cid->dc_len - sizeof (ll), IFT_OTHER);
2439 			if (lladdr == NULL)
2440 				goto fail;
2441 
2442 			(void) snprintf(buf, DLADM_STRSIZE, "%d.%d.%s",
2443 			    duidtype, hwtype, lladdr);
2444 			free(lladdr);
2445 			break;
2446 		}
2447 		default: {
2448 			hexlen = sizeof (tmp_buf);
2449 			if (octet_to_hexascii(cid->dc_id + sizeof (duidtype),
2450 			    cid->dc_len - sizeof (duidtype),
2451 			    tmp_buf, &hexlen) != 0)
2452 				goto fail;
2453 
2454 			(void) snprintf(buf, DLADM_STRSIZE, "%d.%s",
2455 			    duidtype, tmp_buf);
2456 		}
2457 		}
2458 		break;
2459 	}
2460 	case CIDFORM_HEX: {
2461 		hexlen = sizeof (tmp_buf);
2462 		if (octet_to_hexascii(cid->dc_id, cid->dc_len,
2463 		    tmp_buf, &hexlen) != 0)
2464 			goto fail;
2465 
2466 		(void) snprintf(buf, DLADM_STRSIZE, "0x%s", tmp_buf);
2467 		break;
2468 	}
2469 	case CIDFORM_STR: {
2470 		int	i;
2471 
2472 		for (i = 0; i < cid->dc_len; i++) {
2473 			if (!isprint(cid->dc_id[i]))
2474 				goto fail;
2475 		}
2476 		(void) snprintf(buf, DLADM_STRSIZE, "%s", cid->dc_id);
2477 		break;
2478 	}
2479 	default:
2480 		goto fail;
2481 	}
2482 	return;
2483 
2484 fail:
2485 	(void) snprintf(buf, DLADM_STRSIZE, "<unknown>");
2486 }
2487 
2488 static dladm_status_t
2489 dladm_str2cid(char *buf, mac_dhcpcid_t *cid)
2490 {
2491 	char	*ptr = buf;
2492 	char	tmp_buf[DLADM_STRSIZE];
2493 	uint_t	hexlen, cidlen;
2494 
2495 	bzero(cid, sizeof (*cid));
2496 	if (isdigit(*ptr) &&
2497 	    ptr[strspn(ptr, "0123456789")] == '.') {
2498 		char	*cp;
2499 		ulong_t	duidtype;
2500 		ulong_t	subtype;
2501 		ulong_t	timestamp;
2502 		uchar_t	*lladdr;
2503 		int	addrlen;
2504 
2505 		errno = 0;
2506 		duidtype = strtoul(ptr, &cp, 0);
2507 		if (ptr == cp || errno != 0 || *cp != '.' ||
2508 		    duidtype > USHRT_MAX)
2509 			return (DLADM_STATUS_BADARG);
2510 		ptr = cp + 1;
2511 
2512 		if (duidtype != 0 && duidtype <= DHCPV6_DUID_LL) {
2513 			errno = 0;
2514 			subtype = strtoul(ptr, &cp, 0);
2515 			if (ptr == cp || errno != 0 || *cp != '.')
2516 				return (DLADM_STATUS_BADARG);
2517 			ptr = cp + 1;
2518 		}
2519 		switch (duidtype) {
2520 		case DHCPV6_DUID_LLT: {
2521 			duid_llt_t	llt;
2522 
2523 			errno = 0;
2524 			timestamp = strtoul(ptr, &cp, 0);
2525 			if (ptr == cp || errno != 0 || *cp != '.')
2526 				return (DLADM_STATUS_BADARG);
2527 
2528 			ptr = cp + 1;
2529 			lladdr = _link_aton(ptr, &addrlen);
2530 			if (lladdr == NULL)
2531 				return (DLADM_STATUS_BADARG);
2532 
2533 			cidlen = sizeof (llt) + addrlen;
2534 			if (cidlen > sizeof (cid->dc_id)) {
2535 				free(lladdr);
2536 				return (DLADM_STATUS_TOOSMALL);
2537 			}
2538 			llt.dllt_dutype = htons(duidtype);
2539 			llt.dllt_hwtype = htons(subtype);
2540 			llt.dllt_time = htonl(timestamp);
2541 			bcopy(&llt, cid->dc_id, sizeof (llt));
2542 			bcopy(lladdr, cid->dc_id + sizeof (llt), addrlen);
2543 			free(lladdr);
2544 			break;
2545 		}
2546 		case DHCPV6_DUID_LL: {
2547 			duid_ll_t	ll;
2548 
2549 			lladdr = _link_aton(ptr, &addrlen);
2550 			if (lladdr == NULL)
2551 				return (DLADM_STATUS_BADARG);
2552 
2553 			cidlen = sizeof (ll) + addrlen;
2554 			if (cidlen > sizeof (cid->dc_id)) {
2555 				free(lladdr);
2556 				return (DLADM_STATUS_TOOSMALL);
2557 			}
2558 			ll.dll_dutype = htons(duidtype);
2559 			ll.dll_hwtype = htons(subtype);
2560 			bcopy(&ll, cid->dc_id, sizeof (ll));
2561 			bcopy(lladdr, cid->dc_id + sizeof (ll), addrlen);
2562 			free(lladdr);
2563 			break;
2564 		}
2565 		default: {
2566 			hexlen = sizeof (tmp_buf);
2567 			if (hexascii_to_octet(ptr, strlen(ptr),
2568 			    tmp_buf, &hexlen) != 0)
2569 				return (DLADM_STATUS_BADARG);
2570 
2571 			if (duidtype == DHCPV6_DUID_EN) {
2572 				duid_en_t	en;
2573 
2574 				en.den_dutype = htons(duidtype);
2575 				DHCPV6_SET_ENTNUM(&en, subtype);
2576 
2577 				cidlen = sizeof (en) + hexlen;
2578 				if (cidlen > sizeof (cid->dc_id))
2579 					return (DLADM_STATUS_TOOSMALL);
2580 
2581 				bcopy(&en, cid->dc_id, sizeof (en));
2582 				bcopy(tmp_buf, cid->dc_id + sizeof (en),
2583 				    hexlen);
2584 			} else {
2585 				uint16_t	dutype = htons(duidtype);
2586 
2587 				cidlen = sizeof (dutype) + hexlen;
2588 				if (cidlen > sizeof (cid->dc_id))
2589 					return (DLADM_STATUS_TOOSMALL);
2590 
2591 				bcopy(&dutype, cid->dc_id, sizeof (dutype));
2592 				bcopy(tmp_buf, cid->dc_id + sizeof (dutype),
2593 				    hexlen);
2594 			}
2595 			break;
2596 		}
2597 		}
2598 		cid->dc_form = CIDFORM_TYPED;
2599 	} else if (strncasecmp("0x", ptr, 2) == 0 && ptr[2] != '\0') {
2600 		ptr += 2;
2601 		hexlen = sizeof (tmp_buf);
2602 		if (hexascii_to_octet(ptr, strlen(ptr), tmp_buf,
2603 		    &hexlen) != 0) {
2604 			return (DLADM_STATUS_BADARG);
2605 		}
2606 		cidlen = hexlen;
2607 		if (cidlen > sizeof (cid->dc_id))
2608 			return (DLADM_STATUS_TOOSMALL);
2609 
2610 		bcopy(tmp_buf, cid->dc_id, cidlen);
2611 		cid->dc_form = CIDFORM_HEX;
2612 	} else {
2613 		cidlen = strlen(ptr);
2614 		if (cidlen > sizeof (cid->dc_id))
2615 			return (DLADM_STATUS_TOOSMALL);
2616 
2617 		bcopy(ptr, cid->dc_id, cidlen);
2618 		cid->dc_form = CIDFORM_STR;
2619 	}
2620 	cid->dc_len = cidlen;
2621 	return (DLADM_STATUS_OK);
2622 }
2623 
2624 /* ARGSUSED */
2625 static dladm_status_t
2626 get_allowedcids(dladm_handle_t handle, prop_desc_t *pdp,
2627     datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
2628     datalink_media_t media, uint_t flags, uint_t *perm_flags)
2629 {
2630 	mac_resource_props_t	mrp;
2631 	mac_protect_t		*p;
2632 	dladm_status_t		status;
2633 	int			i;
2634 
2635 	status = i_dladm_get_public_prop(handle, linkid, "resource", flags,
2636 	    perm_flags, &mrp, sizeof (mrp));
2637 	if (status != DLADM_STATUS_OK)
2638 		return (status);
2639 
2640 	p = &mrp.mrp_protect;
2641 	if (p->mp_cidcnt == 0) {
2642 		*val_cnt = 0;
2643 		return (DLADM_STATUS_OK);
2644 	}
2645 	if (p->mp_cidcnt > *val_cnt)
2646 		return (DLADM_STATUS_BADVALCNT);
2647 
2648 	for (i = 0; i < p->mp_cidcnt; i++) {
2649 		mac_dhcpcid_t	*cid = &p->mp_cids[i];
2650 
2651 		dladm_cid2str(cid, prop_val[i]);
2652 	}
2653 	*val_cnt = p->mp_cidcnt;
2654 	return (DLADM_STATUS_OK);
2655 }
2656 
2657 dladm_status_t
2658 extract_allowedcids(val_desc_t *vdp, uint_t cnt, void *arg)
2659 {
2660 	mac_resource_props_t	*mrp = arg;
2661 	mac_protect_t		*p = &mrp->mrp_protect;
2662 	int			i;
2663 
2664 	if (vdp->vd_val == 0) {
2665 		cnt = (uint_t)-1;
2666 	} else {
2667 		for (i = 0; i < cnt; i++) {
2668 			bcopy((void *)vdp[i].vd_val, &p->mp_cids[i],
2669 			    sizeof (mac_dhcpcid_t));
2670 		}
2671 	}
2672 	p->mp_cidcnt = cnt;
2673 	mrp->mrp_mask |= MRP_PROTECT;
2674 	return (DLADM_STATUS_OK);
2675 }
2676 
2677 /* ARGSUSED */
2678 static dladm_status_t
2679 check_allowedcids(dladm_handle_t handle, prop_desc_t *pdp,
2680     datalink_id_t linkid, char **prop_val, uint_t val_cnt,
2681     uint_t flags, val_desc_t *vdp, datalink_media_t media)
2682 {
2683 	dladm_status_t	status;
2684 	mac_dhcpcid_t	*cid;
2685 	int		i;
2686 
2687 	if (val_cnt > MPT_MAXCID)
2688 		return (DLADM_STATUS_BADVALCNT);
2689 
2690 	for (i = 0; i < val_cnt; i++) {
2691 		if ((cid = calloc(1, sizeof (mac_dhcpcid_t))) == NULL) {
2692 			status = DLADM_STATUS_NOMEM;
2693 			goto fail;
2694 		}
2695 		vdp[i].vd_val = (uintptr_t)cid;
2696 
2697 		status = dladm_str2cid(prop_val[i], cid);
2698 		if (status != DLADM_STATUS_OK)
2699 			goto fail;
2700 	}
2701 	return (DLADM_STATUS_OK);
2702 
2703 fail:
2704 	for (i = 0; i < val_cnt; i++) {
2705 		free((void *)vdp[i].vd_val);
2706 		vdp[i].vd_val = NULL;
2707 	}
2708 	return (status);
2709 }
2710 
2711 /* ARGSUSED */
2712 static dladm_status_t
2713 get_autopush(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
2714     char **prop_val, uint_t *val_cnt, datalink_media_t media,
2715     uint_t flags, uint_t *perm_flags)
2716 {
2717 	struct		dlautopush dlap;
2718 	int		i, len;
2719 	dladm_status_t	status;
2720 
2721 	if (flags & DLD_PROP_DEFAULT)
2722 		return (DLADM_STATUS_NOTDEFINED);
2723 
2724 	status = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags,
2725 	    perm_flags, &dlap, sizeof (dlap));
2726 	if (status != DLADM_STATUS_OK)
2727 		return (status);
2728 
2729 	if (dlap.dap_npush == 0) {
2730 		*val_cnt = 0;
2731 		return (DLADM_STATUS_OK);
2732 	}
2733 	for (i = 0, len = 0; i < dlap.dap_npush; i++) {
2734 		if (i != 0) {
2735 			(void) snprintf(*prop_val + len,
2736 			    DLADM_PROP_VAL_MAX - len, "%c", AP_DELIMITER);
2737 			len += 1;
2738 		}
2739 		(void) snprintf(*prop_val + len, DLADM_PROP_VAL_MAX - len,
2740 		    "%s", dlap.dap_aplist[i]);
2741 		len += strlen(dlap.dap_aplist[i]);
2742 		if (dlap.dap_anchor - 1 == i) {
2743 			(void) snprintf(*prop_val + len,
2744 			    DLADM_PROP_VAL_MAX - len, "%c%s", AP_DELIMITER,
2745 			    AP_ANCHOR);
2746 			len += (strlen(AP_ANCHOR) + 1);
2747 		}
2748 	}
2749 	*val_cnt = 1;
2750 	return (DLADM_STATUS_OK);
2751 }
2752 
2753 /*
2754  * Add the specified module to the dlautopush structure; returns a
2755  * DLADM_STATUS_* code.
2756  */
2757 dladm_status_t
2758 i_dladm_add_ap_module(const char *module, struct dlautopush *dlap)
2759 {
2760 	if ((strlen(module) == 0) || (strlen(module) > FMNAMESZ))
2761 		return (DLADM_STATUS_BADVAL);
2762 
2763 	if (strncasecmp(module, AP_ANCHOR, strlen(AP_ANCHOR)) == 0) {
2764 		/*
2765 		 * We don't allow multiple anchors, and the anchor must
2766 		 * be after at least one module.
2767 		 */
2768 		if (dlap->dap_anchor != 0)
2769 			return (DLADM_STATUS_BADVAL);
2770 		if (dlap->dap_npush == 0)
2771 			return (DLADM_STATUS_BADVAL);
2772 
2773 		dlap->dap_anchor = dlap->dap_npush;
2774 		return (DLADM_STATUS_OK);
2775 	}
2776 	if (dlap->dap_npush >= MAXAPUSH)
2777 		return (DLADM_STATUS_BADVALCNT);
2778 
2779 	(void) strlcpy(dlap->dap_aplist[dlap->dap_npush++], module,
2780 	    FMNAMESZ + 1);
2781 
2782 	return (DLADM_STATUS_OK);
2783 }
2784 
2785 /*
2786  * Currently, both '.' and ' '(space) can be used as the delimiters between
2787  * autopush modules. The former is used in dladm set-linkprop, and the
2788  * latter is used in the autopush(1M) file.
2789  */
2790 /* ARGSUSED */
2791 static dladm_status_t
2792 check_autopush(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
2793     char **prop_val, uint_t val_cnt, uint_t flags, val_desc_t *vdp,
2794     datalink_media_t media)
2795 {
2796 	char			*module;
2797 	struct dlautopush	*dlap;
2798 	dladm_status_t		status;
2799 	char			val[DLADM_PROP_VAL_MAX];
2800 	char			delimiters[4];
2801 
2802 	if (val_cnt != 1)
2803 		return (DLADM_STATUS_BADVALCNT);
2804 
2805 	if (prop_val != NULL) {
2806 		dlap = malloc(sizeof (struct dlautopush));
2807 		if (dlap == NULL)
2808 			return (DLADM_STATUS_NOMEM);
2809 
2810 		(void) memset(dlap, 0, sizeof (struct dlautopush));
2811 		(void) snprintf(delimiters, 4, " %c\n", AP_DELIMITER);
2812 		bcopy(*prop_val, val, DLADM_PROP_VAL_MAX);
2813 		module = strtok(val, delimiters);
2814 		while (module != NULL) {
2815 			status = i_dladm_add_ap_module(module, dlap);
2816 			if (status != DLADM_STATUS_OK)
2817 				return (status);
2818 			module = strtok(NULL, delimiters);
2819 		}
2820 
2821 		vdp->vd_val = (uintptr_t)dlap;
2822 	} else {
2823 		vdp->vd_val = 0;
2824 	}
2825 	return (DLADM_STATUS_OK);
2826 }
2827 
2828 #define	WLDP_BUFSIZE (MAX_BUF_LEN - WIFI_BUF_OFFSET)
2829 
2830 /* ARGSUSED */
2831 static dladm_status_t
2832 get_rate_common(dladm_handle_t handle, prop_desc_t *pdp,
2833     datalink_id_t linkid, char **prop_val, uint_t *val_cnt, uint_t id,
2834     uint_t *perm_flags)
2835 {
2836 	wl_rates_t	*wrp;
2837 	uint_t		i;
2838 	dladm_status_t	status = DLADM_STATUS_OK;
2839 
2840 	wrp = malloc(WLDP_BUFSIZE);
2841 	if (wrp == NULL)
2842 		return (DLADM_STATUS_NOMEM);
2843 
2844 	status = i_dladm_wlan_param(handle, linkid, wrp, id, WLDP_BUFSIZE,
2845 	    B_FALSE);
2846 	if (status != DLADM_STATUS_OK)
2847 		goto done;
2848 
2849 	if (wrp->wl_rates_num > *val_cnt) {
2850 		status = DLADM_STATUS_TOOSMALL;
2851 		goto done;
2852 	}
2853 
2854 	if (wrp->wl_rates_rates[0] == 0) {
2855 		prop_val[0][0] = '\0';
2856 		*val_cnt = 1;
2857 		goto done;
2858 	}
2859 
2860 	for (i = 0; i < wrp->wl_rates_num; i++) {
2861 		(void) snprintf(prop_val[i], DLADM_STRSIZE, "%.*f",
2862 		    wrp->wl_rates_rates[i] % 2,
2863 		    (float)wrp->wl_rates_rates[i] / 2);
2864 	}
2865 	*val_cnt = wrp->wl_rates_num;
2866 	*perm_flags = MAC_PROP_PERM_RW;
2867 
2868 done:
2869 	free(wrp);
2870 	return (status);
2871 }
2872 
2873 static dladm_status_t
2874 get_rate(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
2875     char **prop_val, uint_t *val_cnt, datalink_media_t media,
2876     uint_t flags, uint_t *perm_flags)
2877 {
2878 	if (media != DL_WIFI) {
2879 		return (get_speed(handle, pdp, linkid, prop_val,
2880 		    val_cnt, media, flags, perm_flags));
2881 	}
2882 
2883 	return (get_rate_common(handle, pdp, linkid, prop_val, val_cnt,
2884 	    MAC_PROP_WL_DESIRED_RATES, perm_flags));
2885 }
2886 
2887 /* ARGSUSED */
2888 static dladm_status_t
2889 get_rate_mod(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
2890     char **prop_val, uint_t *val_cnt, datalink_media_t media,
2891     uint_t flags, uint_t *perm_flags)
2892 {
2893 	switch (media) {
2894 	case DL_ETHER:
2895 		/*
2896 		 * Speed for ethernet links is unbounded. E.g., 802.11b
2897 		 * links can have a speed of 5.5 Gbps.
2898 		 */
2899 		return (DLADM_STATUS_NOTSUP);
2900 
2901 	case DL_WIFI:
2902 		return (get_rate_common(handle, pdp, linkid, prop_val,
2903 		    val_cnt, MAC_PROP_WL_SUPPORTED_RATES, perm_flags));
2904 	default:
2905 		return (DLADM_STATUS_BADARG);
2906 	}
2907 }
2908 
2909 static dladm_status_t
2910 set_wlan_rate(dladm_handle_t handle, datalink_id_t linkid,
2911     dladm_wlan_rates_t *rates)
2912 {
2913 	int		i;
2914 	uint_t		len;
2915 	wl_rates_t	*wrp;
2916 	dladm_status_t	status = DLADM_STATUS_OK;
2917 
2918 	wrp = malloc(WLDP_BUFSIZE);
2919 	if (wrp == NULL)
2920 		return (DLADM_STATUS_NOMEM);
2921 
2922 	bzero(wrp, WLDP_BUFSIZE);
2923 	for (i = 0; i < rates->wr_cnt; i++)
2924 		wrp->wl_rates_rates[i] = rates->wr_rates[i];
2925 	wrp->wl_rates_num = rates->wr_cnt;
2926 
2927 	len = offsetof(wl_rates_t, wl_rates_rates) +
2928 	    (rates->wr_cnt * sizeof (char)) + WIFI_BUF_OFFSET;
2929 	status = i_dladm_wlan_param(handle, linkid, wrp,
2930 	    MAC_PROP_WL_DESIRED_RATES, len, B_TRUE);
2931 
2932 	free(wrp);
2933 	return (status);
2934 }
2935 
2936 /* ARGSUSED */
2937 static dladm_status_t
2938 set_rate(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
2939     val_desc_t *vdp, uint_t val_cnt, uint_t flags, datalink_media_t media)
2940 {
2941 	dladm_wlan_rates_t	rates;
2942 	dladm_status_t		status;
2943 
2944 	/*
2945 	 * can currently set rate on WIFI links only.
2946 	 */
2947 	if (media != DL_WIFI)
2948 		return (DLADM_STATUS_PROPRDONLY);
2949 
2950 	if (val_cnt != 1)
2951 		return (DLADM_STATUS_BADVALCNT);
2952 
2953 	rates.wr_cnt = 1;
2954 	rates.wr_rates[0] = vdp[0].vd_val;
2955 
2956 	status = set_wlan_rate(handle, linkid, &rates);
2957 
2958 	return (status);
2959 }
2960 
2961 /* ARGSUSED */
2962 static dladm_status_t
2963 check_rate(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
2964     char **prop_val, uint_t val_cnt, uint_t flags, val_desc_t *vdp,
2965     datalink_media_t media)
2966 {
2967 	int		i;
2968 	uint_t		modval_cnt = MAX_SUPPORT_RATES;
2969 	char		*buf, **modval;
2970 	dladm_status_t	status;
2971 	uint_t 		perm_flags;
2972 
2973 	if (val_cnt != 1)
2974 		return (DLADM_STATUS_BADVALCNT);
2975 
2976 	buf = malloc((sizeof (char *) + DLADM_STRSIZE) *
2977 	    MAX_SUPPORT_RATES);
2978 	if (buf == NULL) {
2979 		status = DLADM_STATUS_NOMEM;
2980 		goto done;
2981 	}
2982 
2983 	modval = (char **)(void *)buf;
2984 	for (i = 0; i < MAX_SUPPORT_RATES; i++) {
2985 		modval[i] = buf + sizeof (char *) * MAX_SUPPORT_RATES +
2986 		    i * DLADM_STRSIZE;
2987 	}
2988 
2989 	status = get_rate_mod(handle, NULL, linkid, modval, &modval_cnt,
2990 	    media, 0, &perm_flags);
2991 	if (status != DLADM_STATUS_OK)
2992 		goto done;
2993 
2994 	for (i = 0; i < modval_cnt; i++) {
2995 		if (strcasecmp(*prop_val, modval[i]) == 0) {
2996 			vdp->vd_val = (uintptr_t)(uint_t)
2997 			    (atof(*prop_val) * 2);
2998 			status = DLADM_STATUS_OK;
2999 			break;
3000 		}
3001 	}
3002 	if (i == modval_cnt)
3003 		status = DLADM_STATUS_BADVAL;
3004 done:
3005 	free(buf);
3006 	return (status);
3007 }
3008 
3009 static dladm_status_t
3010 get_phyconf(dladm_handle_t handle, datalink_id_t linkid, void *buf,
3011     int buflen)
3012 {
3013 	return (i_dladm_wlan_param(handle, linkid, buf, MAC_PROP_WL_PHY_CONFIG,
3014 	    buflen, B_FALSE));
3015 }
3016 
3017 /* ARGSUSED */
3018 static dladm_status_t
3019 get_channel(dladm_handle_t handle, prop_desc_t *pdp,
3020     datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
3021     datalink_media_t media, uint_t flags, uint_t *perm_flags)
3022 {
3023 	uint32_t	channel;
3024 	char		buf[WLDP_BUFSIZE];
3025 	dladm_status_t	status;
3026 	wl_phy_conf_t	wl_phy_conf;
3027 
3028 	if ((status = get_phyconf(handle, linkid, buf, sizeof (buf)))
3029 	    != DLADM_STATUS_OK)
3030 		return (status);
3031 
3032 	(void) memcpy(&wl_phy_conf, buf, sizeof (wl_phy_conf));
3033 	if (!i_dladm_wlan_convert_chan(&wl_phy_conf, &channel))
3034 		return (DLADM_STATUS_NOTFOUND);
3035 
3036 	(void) snprintf(*prop_val, DLADM_STRSIZE, "%u", channel);
3037 	*val_cnt = 1;
3038 	*perm_flags = MAC_PROP_PERM_READ;
3039 	return (DLADM_STATUS_OK);
3040 }
3041 
3042 /* ARGSUSED */
3043 static dladm_status_t
3044 get_powermode(dladm_handle_t handle, prop_desc_t *pdp,
3045     datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
3046     datalink_media_t media, uint_t flags, uint_t *perm_flags)
3047 {
3048 	wl_ps_mode_t	mode;
3049 	const char	*s;
3050 	char		buf[WLDP_BUFSIZE];
3051 	dladm_status_t	status;
3052 
3053 	if ((status = i_dladm_wlan_param(handle, linkid, buf,
3054 	    MAC_PROP_WL_POWER_MODE, sizeof (buf), B_FALSE)) != DLADM_STATUS_OK)
3055 		return (status);
3056 
3057 	(void) memcpy(&mode, buf, sizeof (mode));
3058 	switch (mode.wl_ps_mode) {
3059 	case WL_PM_AM:
3060 		s = "off";
3061 		break;
3062 	case WL_PM_MPS:
3063 		s = "max";
3064 		break;
3065 	case WL_PM_FAST:
3066 		s = "fast";
3067 		break;
3068 	default:
3069 		return (DLADM_STATUS_NOTFOUND);
3070 	}
3071 	(void) snprintf(*prop_val, DLADM_STRSIZE, "%s", s);
3072 	*val_cnt = 1;
3073 	*perm_flags = MAC_PROP_PERM_RW;
3074 	return (DLADM_STATUS_OK);
3075 }
3076 
3077 /* ARGSUSED */
3078 static dladm_status_t
3079 set_powermode(dladm_handle_t handle, prop_desc_t *pdp,
3080     datalink_id_t linkid, val_desc_t *vdp, uint_t val_cnt, uint_t flags,
3081     datalink_media_t media)
3082 {
3083 	dladm_wlan_powermode_t	powermode = vdp->vd_val;
3084 	wl_ps_mode_t		ps_mode;
3085 
3086 	if (val_cnt != 1)
3087 		return (DLADM_STATUS_BADVALCNT);
3088 
3089 	(void) memset(&ps_mode, 0xff, sizeof (ps_mode));
3090 
3091 	switch (powermode) {
3092 	case DLADM_WLAN_PM_OFF:
3093 		ps_mode.wl_ps_mode = WL_PM_AM;
3094 		break;
3095 	case DLADM_WLAN_PM_MAX:
3096 		ps_mode.wl_ps_mode = WL_PM_MPS;
3097 		break;
3098 	case DLADM_WLAN_PM_FAST:
3099 		ps_mode.wl_ps_mode = WL_PM_FAST;
3100 		break;
3101 	default:
3102 		return (DLADM_STATUS_NOTSUP);
3103 	}
3104 	return (i_dladm_wlan_param(handle, linkid, &ps_mode,
3105 	    MAC_PROP_WL_POWER_MODE, sizeof (ps_mode), B_TRUE));
3106 }
3107 
3108 /* ARGSUSED */
3109 static dladm_status_t
3110 get_radio(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
3111     char **prop_val, uint_t *val_cnt, datalink_media_t media,
3112     uint_t flags, uint_t *perm_flags)
3113 {
3114 	wl_radio_t	radio;
3115 	const char	*s;
3116 	char		buf[WLDP_BUFSIZE];
3117 	dladm_status_t	status;
3118 
3119 	if ((status = i_dladm_wlan_param(handle, linkid, buf,
3120 	    MAC_PROP_WL_RADIO, sizeof (buf), B_FALSE)) != DLADM_STATUS_OK)
3121 		return (status);
3122 
3123 	(void) memcpy(&radio, buf, sizeof (radio));
3124 	switch (radio) {
3125 	case B_TRUE:
3126 		s = "on";
3127 		break;
3128 	case B_FALSE:
3129 		s = "off";
3130 		break;
3131 	default:
3132 		return (DLADM_STATUS_NOTFOUND);
3133 	}
3134 	(void) snprintf(*prop_val, DLADM_STRSIZE, "%s", s);
3135 	*val_cnt = 1;
3136 	*perm_flags = MAC_PROP_PERM_RW;
3137 	return (DLADM_STATUS_OK);
3138 }
3139 
3140 /* ARGSUSED */
3141 static dladm_status_t
3142 set_radio(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
3143     val_desc_t *vdp, uint_t val_cnt, uint_t flags, datalink_media_t media)
3144 {
3145 	dladm_wlan_radio_t	radio = vdp->vd_val;
3146 	wl_radio_t		r;
3147 
3148 	if (val_cnt != 1)
3149 		return (DLADM_STATUS_BADVALCNT);
3150 
3151 	switch (radio) {
3152 	case DLADM_WLAN_RADIO_ON:
3153 		r = B_TRUE;
3154 		break;
3155 	case DLADM_WLAN_RADIO_OFF:
3156 		r = B_FALSE;
3157 		break;
3158 	default:
3159 		return (DLADM_STATUS_NOTSUP);
3160 	}
3161 	return (i_dladm_wlan_param(handle, linkid, &r, MAC_PROP_WL_RADIO,
3162 	    sizeof (r), B_TRUE));
3163 }
3164 
3165 /* ARGSUSED */
3166 static dladm_status_t
3167 check_hoplimit(dladm_handle_t handle, prop_desc_t *pdp,
3168     datalink_id_t linkid, char **prop_val, uint_t val_cnt, uint_t flags,
3169     val_desc_t *vdp, datalink_media_t media)
3170 {
3171 	int32_t	hlim;
3172 	char	*ep;
3173 
3174 	if (val_cnt != 1)
3175 		return (DLADM_STATUS_BADVALCNT);
3176 
3177 	errno = 0;
3178 	hlim = strtol(*prop_val, &ep, 10);
3179 	if (errno != 0 || ep == *prop_val || hlim < 1 ||
3180 	    hlim > (int32_t)UINT8_MAX)
3181 		return (DLADM_STATUS_BADVAL);
3182 	vdp->vd_val = hlim;
3183 	return (DLADM_STATUS_OK);
3184 }
3185 
3186 /* ARGSUSED */
3187 static dladm_status_t
3188 check_encaplim(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
3189     char **prop_val, uint_t val_cnt, uint_t flags, val_desc_t *vdp,
3190     datalink_media_t media)
3191 {
3192 	int32_t	elim;
3193 	char	*ep;
3194 
3195 	if (media != DL_IPV6)
3196 		return (DLADM_STATUS_BADARG);
3197 
3198 	if (val_cnt != 1)
3199 		return (DLADM_STATUS_BADVALCNT);
3200 
3201 	errno = 0;
3202 	elim = strtol(*prop_val, &ep, 10);
3203 	if (errno != 0 || ep == *prop_val || elim < 0 ||
3204 	    elim > (int32_t)UINT8_MAX)
3205 		return (DLADM_STATUS_BADVAL);
3206 	vdp->vd_val = elim;
3207 	return (DLADM_STATUS_OK);
3208 }
3209 
3210 static dladm_status_t
3211 i_dladm_set_linkprop_db(dladm_handle_t handle, datalink_id_t linkid,
3212     const char *prop_name, char **prop_val, uint_t val_cnt)
3213 {
3214 	char		buf[MAXLINELEN];
3215 	int		i;
3216 	dladm_conf_t	conf;
3217 	dladm_status_t	status;
3218 
3219 	status = dladm_read_conf(handle, linkid, &conf);
3220 	if (status != DLADM_STATUS_OK)
3221 		return (status);
3222 
3223 	/*
3224 	 * reset case.
3225 	 */
3226 	if (val_cnt == 0) {
3227 		status = dladm_unset_conf_field(handle, conf, prop_name);
3228 		if (status == DLADM_STATUS_OK)
3229 			status = dladm_write_conf(handle, conf);
3230 		goto done;
3231 	}
3232 
3233 	buf[0] = '\0';
3234 	for (i = 0; i < val_cnt; i++) {
3235 		(void) strlcat(buf, prop_val[i], MAXLINELEN);
3236 		if (i != val_cnt - 1)
3237 			(void) strlcat(buf, ",", MAXLINELEN);
3238 	}
3239 
3240 	status = dladm_set_conf_field(handle, conf, prop_name, DLADM_TYPE_STR,
3241 	    buf);
3242 	if (status == DLADM_STATUS_OK)
3243 		status = dladm_write_conf(handle, conf);
3244 
3245 done:
3246 	dladm_destroy_conf(handle, conf);
3247 	return (status);
3248 }
3249 
3250 static dladm_status_t
3251 i_dladm_get_linkprop_db(dladm_handle_t handle, datalink_id_t linkid,
3252     const char *prop_name, char **prop_val, uint_t *val_cntp)
3253 {
3254 	char		buf[MAXLINELEN], *str;
3255 	uint_t		cnt = 0;
3256 	dladm_conf_t	conf;
3257 	dladm_status_t	status;
3258 
3259 	status = dladm_read_conf(handle, linkid, &conf);
3260 	if (status != DLADM_STATUS_OK)
3261 		return (status);
3262 
3263 	status = dladm_get_conf_field(handle, conf, prop_name, buf, MAXLINELEN);
3264 	if (status != DLADM_STATUS_OK)
3265 		goto done;
3266 
3267 	str = strtok(buf, ",");
3268 	while (str != NULL) {
3269 		if (cnt == *val_cntp) {
3270 			status = DLADM_STATUS_TOOSMALL;
3271 			goto done;
3272 		}
3273 		(void) strlcpy(prop_val[cnt++], str, DLADM_PROP_VAL_MAX);
3274 		str = strtok(NULL, ",");
3275 	}
3276 
3277 	*val_cntp = cnt;
3278 
3279 done:
3280 	dladm_destroy_conf(handle, conf);
3281 	return (status);
3282 }
3283 
3284 /*
3285  * Walk persistent private link properties of a link.
3286  */
3287 static dladm_status_t
3288 i_dladm_walk_linkprop_priv_db(dladm_handle_t handle, datalink_id_t linkid,
3289     void *arg, int (*func)(dladm_handle_t, datalink_id_t, const char *, void *))
3290 {
3291 	dladm_status_t		status;
3292 	dladm_conf_t		conf;
3293 	char			last_attr[MAXLINKATTRLEN];
3294 	char			attr[MAXLINKATTRLEN];
3295 	char			attrval[MAXLINKATTRVALLEN];
3296 	size_t			attrsz;
3297 
3298 	if (linkid == DATALINK_INVALID_LINKID || func == NULL)
3299 		return (DLADM_STATUS_BADARG);
3300 
3301 	status = dladm_read_conf(handle, linkid, &conf);
3302 	if (status != DLADM_STATUS_OK)
3303 		return (status);
3304 
3305 	last_attr[0] = '\0';
3306 	while ((status = dladm_getnext_conf_linkprop(handle, conf, last_attr,
3307 	    attr, attrval, MAXLINKATTRVALLEN, &attrsz)) == DLADM_STATUS_OK) {
3308 		if (attr[0] == '_') {
3309 			if (func(handle, linkid, attr, arg) ==
3310 			    DLADM_WALK_TERMINATE)
3311 				break;
3312 		}
3313 		(void) strlcpy(last_attr, attr, MAXLINKATTRLEN);
3314 	}
3315 
3316 	dladm_destroy_conf(handle, conf);
3317 	return (DLADM_STATUS_OK);
3318 }
3319 
3320 static link_attr_t *
3321 dladm_name2prop(const char *prop_name)
3322 {
3323 	link_attr_t *p;
3324 
3325 	for (p = link_attr; p->pp_id != MAC_PROP_PRIVATE; p++) {
3326 		if (strcmp(p->pp_name, prop_name) == 0)
3327 			break;
3328 	}
3329 	return (p);
3330 }
3331 
3332 static link_attr_t *
3333 dladm_id2prop(mac_prop_id_t propid)
3334 {
3335 	link_attr_t *p;
3336 
3337 	for (p = link_attr; p->pp_id != MAC_PROP_PRIVATE; p++) {
3338 		if (p->pp_id == propid)
3339 			break;
3340 	}
3341 	return (p);
3342 }
3343 
3344 static dld_ioc_macprop_t *
3345 i_dladm_buf_alloc_impl(size_t valsize, datalink_id_t linkid,
3346     const char *prop_name, mac_prop_id_t propid, uint_t flags,
3347     dladm_status_t *status)
3348 {
3349 	int dsize;
3350 	dld_ioc_macprop_t *dip;
3351 
3352 	*status = DLADM_STATUS_OK;
3353 	dsize = MAC_PROP_BUFSIZE(valsize);
3354 	dip = malloc(dsize);
3355 	if (dip == NULL) {
3356 		*status = DLADM_STATUS_NOMEM;
3357 		return (NULL);
3358 	}
3359 	bzero(dip, dsize);
3360 	dip->pr_valsize = valsize;
3361 	(void) strlcpy(dip->pr_name, prop_name, sizeof (dip->pr_name));
3362 	dip->pr_linkid = linkid;
3363 	dip->pr_num = propid;
3364 	dip->pr_flags = flags;
3365 	return (dip);
3366 }
3367 
3368 static dld_ioc_macprop_t *
3369 i_dladm_buf_alloc_by_name(size_t valsize, datalink_id_t linkid,
3370     const char *prop_name, uint_t flags, dladm_status_t *status)
3371 {
3372 	link_attr_t *p;
3373 
3374 	p = dladm_name2prop(prop_name);
3375 	valsize = MAX(p->pp_valsize, valsize);
3376 	return (i_dladm_buf_alloc_impl(valsize, linkid, prop_name, p->pp_id,
3377 	    flags, status));
3378 }
3379 
3380 static dld_ioc_macprop_t *
3381 i_dladm_buf_alloc_by_id(size_t valsize, datalink_id_t linkid,
3382     mac_prop_id_t propid, uint_t flags, dladm_status_t *status)
3383 {
3384 	link_attr_t *p;
3385 
3386 	p = dladm_id2prop(propid);
3387 	valsize = MAX(p->pp_valsize, valsize);
3388 	return (i_dladm_buf_alloc_impl(valsize, linkid, p->pp_name, propid,
3389 	    flags, status));
3390 }
3391 
3392 /* ARGSUSED */
3393 static dladm_status_t
3394 set_public_prop(dladm_handle_t handle, prop_desc_t *pdp,
3395     datalink_id_t linkid, val_desc_t *vdp, uint_t val_cnt, uint_t flags,
3396     datalink_media_t media)
3397 {
3398 	dld_ioc_macprop_t	*dip;
3399 	dladm_status_t	status = DLADM_STATUS_OK;
3400 	uint8_t		u8;
3401 	uint16_t	u16;
3402 	uint32_t	u32;
3403 	void		*val;
3404 
3405 	dip = i_dladm_buf_alloc_by_name(0, linkid, pdp->pd_name, 0, &status);
3406 	if (dip == NULL)
3407 		return (status);
3408 
3409 	if (pdp->pd_flags & PD_CHECK_ALLOC)
3410 		val = (void *)vdp->vd_val;
3411 	else {
3412 		/*
3413 		 * Currently all 1/2/4-byte size properties are byte/word/int.
3414 		 * No need (yet) to distinguish these from arrays of same size.
3415 		 */
3416 		switch (dip->pr_valsize) {
3417 		case 1:
3418 			u8 = vdp->vd_val;
3419 			val = &u8;
3420 			break;
3421 		case 2:
3422 			u16 = vdp->vd_val;
3423 			val = &u16;
3424 			break;
3425 		case 4:
3426 			u32 = vdp->vd_val;
3427 			val = &u32;
3428 			break;
3429 		default:
3430 			val = &vdp->vd_val;
3431 			break;
3432 		}
3433 	}
3434 
3435 	if (val != NULL)
3436 		(void) memcpy(dip->pr_val, val, dip->pr_valsize);
3437 	else
3438 		dip->pr_valsize = 0;
3439 
3440 	status = i_dladm_macprop(handle, dip, B_TRUE);
3441 
3442 done:
3443 	free(dip);
3444 	return (status);
3445 }
3446 
3447 dladm_status_t
3448 i_dladm_macprop(dladm_handle_t handle, void *dip, boolean_t set)
3449 {
3450 	dladm_status_t status = DLADM_STATUS_OK;
3451 
3452 	if (ioctl(dladm_dld_fd(handle),
3453 	    (set ? DLDIOC_SETMACPROP : DLDIOC_GETMACPROP), dip))
3454 		status = dladm_errno2status(errno);
3455 
3456 	return (status);
3457 }
3458 
3459 static dladm_status_t
3460 i_dladm_get_public_prop(dladm_handle_t handle, datalink_id_t linkid,
3461     char *prop_name, uint_t flags, uint_t *perm_flags, void *arg, size_t size)
3462 {
3463 	dld_ioc_macprop_t	*dip;
3464 	dladm_status_t		status;
3465 
3466 	dip = i_dladm_buf_alloc_by_name(0, linkid, prop_name, flags, &status);
3467 	if (dip == NULL)
3468 		return (DLADM_STATUS_NOMEM);
3469 
3470 	status = i_dladm_macprop(handle, dip, B_FALSE);
3471 	if (status != DLADM_STATUS_OK) {
3472 		free(dip);
3473 		return (status);
3474 	}
3475 
3476 	if (perm_flags != NULL)
3477 		*perm_flags = dip->pr_perm_flags;
3478 
3479 	if (arg != NULL)
3480 		(void) memcpy(arg, dip->pr_val, size);
3481 	free(dip);
3482 	return (DLADM_STATUS_OK);
3483 }
3484 
3485 /* ARGSUSED */
3486 static dladm_status_t
3487 check_uint32(dladm_handle_t handle, prop_desc_t *pdp,
3488     datalink_id_t linkid, char **prop_val, uint_t val_cnt, uint_t flags,
3489     val_desc_t *v, datalink_media_t media)
3490 {
3491 	if (val_cnt != 1)
3492 		return (DLADM_STATUS_BADVAL);
3493 	v->vd_val = strtoul(prop_val[0], NULL, 0);
3494 	return (DLADM_STATUS_OK);
3495 }
3496 
3497 /* ARGSUSED */
3498 static dladm_status_t
3499 get_duplex(dladm_handle_t handle, prop_desc_t *pdp,
3500     datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
3501     datalink_media_t media, uint_t flags, uint_t *perm_flags)
3502 {
3503 	link_duplex_t   link_duplex;
3504 	dladm_status_t  status;
3505 
3506 	if ((status = dladm_get_single_mac_stat(handle, linkid, "link_duplex",
3507 	    KSTAT_DATA_UINT32, &link_duplex)) != 0)
3508 		return (status);
3509 
3510 	switch (link_duplex) {
3511 	case LINK_DUPLEX_FULL:
3512 		(void) strcpy(*prop_val, "full");
3513 		break;
3514 	case LINK_DUPLEX_HALF:
3515 		(void) strcpy(*prop_val, "half");
3516 		break;
3517 	default:
3518 		(void) strcpy(*prop_val, "unknown");
3519 		break;
3520 	}
3521 	*val_cnt = 1;
3522 	return (DLADM_STATUS_OK);
3523 }
3524 
3525 /* ARGSUSED */
3526 static dladm_status_t
3527 get_speed(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
3528     char **prop_val, uint_t *val_cnt, datalink_media_t media, uint_t flags,
3529     uint_t *perm_flags)
3530 {
3531 	uint64_t	ifspeed = 0;
3532 	dladm_status_t status;
3533 
3534 	if ((status = dladm_get_single_mac_stat(handle, linkid, "ifspeed",
3535 	    KSTAT_DATA_UINT64, &ifspeed)) != 0)
3536 		return (status);
3537 
3538 	if ((ifspeed % 1000000) != 0) {
3539 		(void) snprintf(*prop_val, DLADM_PROP_VAL_MAX,
3540 		    "%llf", ifspeed / (float)1000000); /* Mbps */
3541 	} else {
3542 		(void) snprintf(*prop_val, DLADM_PROP_VAL_MAX,
3543 		    "%llu", ifspeed / 1000000); /* Mbps */
3544 	}
3545 	*val_cnt = 1;
3546 	*perm_flags = MAC_PROP_PERM_READ;
3547 	return (DLADM_STATUS_OK);
3548 }
3549 
3550 /* ARGSUSED */
3551 static dladm_status_t
3552 get_link_state(dladm_handle_t handle, prop_desc_t *pdp,
3553     datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
3554     datalink_media_t media, uint_t flags, uint_t *perm_flags)
3555 {
3556 	link_state_t		link_state;
3557 	dladm_status_t		status;
3558 
3559 	status = dladm_get_state(handle, linkid, &link_state);
3560 	if (status != DLADM_STATUS_OK)
3561 		return (status);
3562 
3563 	switch (link_state) {
3564 	case LINK_STATE_UP:
3565 		(void) strcpy(*prop_val, "up");
3566 		break;
3567 	case LINK_STATE_DOWN:
3568 		(void) strcpy(*prop_val, "down");
3569 		break;
3570 	default:
3571 		(void) strcpy(*prop_val, "unknown");
3572 		break;
3573 	}
3574 	*val_cnt = 1;
3575 	*perm_flags = MAC_PROP_PERM_READ;
3576 	return (DLADM_STATUS_OK);
3577 }
3578 
3579 /* ARGSUSED */
3580 static dladm_status_t
3581 get_binary(dladm_handle_t handle, prop_desc_t *pdp,
3582     datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
3583     datalink_media_t media, uint_t flags, uint_t *perm_flags)
3584 {
3585 	dladm_status_t	status;
3586 	uint_t		v = 0;
3587 
3588 	status = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags,
3589 	    perm_flags, &v, sizeof (v));
3590 	if (status != DLADM_STATUS_OK)
3591 		return (status);
3592 
3593 	(void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "%d", (uint_t)(v > 0));
3594 	*val_cnt = 1;
3595 	return (DLADM_STATUS_OK);
3596 }
3597 
3598 /* ARGSUSED */
3599 static dladm_status_t
3600 get_uint32(dladm_handle_t handle, prop_desc_t *pdp,
3601     datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
3602     datalink_media_t media, uint_t flags, uint_t *perm_flags)
3603 {
3604 	dladm_status_t	status;
3605 	uint32_t	v = 0;
3606 
3607 	status = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags,
3608 	    perm_flags, &v, sizeof (v));
3609 	if (status != DLADM_STATUS_OK)
3610 		return (status);
3611 
3612 	(void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "%ld", v);
3613 	*val_cnt = 1;
3614 	return (DLADM_STATUS_OK);
3615 }
3616 
3617 /* ARGSUSED */
3618 static dladm_status_t
3619 get_range(dladm_handle_t handle, prop_desc_t *pdp,
3620     datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
3621     datalink_media_t media, uint_t flags, uint_t *perm_flags)
3622 {
3623 	dld_ioc_macprop_t *dip;
3624 	dladm_status_t status = DLADM_STATUS_OK;
3625 	size_t	sz;
3626 	mac_propval_range_t *rangep;
3627 
3628 	sz = sizeof (mac_propval_range_t);
3629 
3630 	/*
3631 	 * As caller we don't know number of value ranges, the driver
3632 	 * supports. To begin with we assume that number to be 1. If the
3633 	 * buffer size is insufficient, driver returns back with the
3634 	 * actual count of value ranges. See mac.h for more details.
3635 	 */
3636 retry:
3637 	if ((dip = i_dladm_buf_alloc_by_name(sz, linkid, pdp->pd_name, flags,
3638 	    &status)) == NULL)
3639 		return (status);
3640 
3641 	status = i_dladm_macprop(handle, dip, B_FALSE);
3642 	if (status != DLADM_STATUS_OK) {
3643 		if (status == DLADM_STATUS_TOOSMALL) {
3644 			int err;
3645 
3646 			rangep = (mac_propval_range_t *)(void *)&dip->pr_val;
3647 			if ((err = i_dladm_range_size(rangep, &sz)) == 0) {
3648 				free(dip);
3649 				goto retry;
3650 			} else {
3651 				status = dladm_errno2status(err);
3652 			}
3653 		}
3654 		free(dip);
3655 		return (status);
3656 	}
3657 
3658 	rangep = (mac_propval_range_t *)(void *)&dip->pr_val;
3659 	if (rangep->mpr_count == 0) {
3660 		*val_cnt = 1;
3661 		(void) snprintf(prop_val[0], DLADM_PROP_VAL_MAX, "--");
3662 		goto done;
3663 	}
3664 
3665 	switch (rangep->mpr_type) {
3666 	case MAC_PROPVAL_UINT32: {
3667 		mac_propval_uint32_range_t *ur;
3668 		uint_t	count = rangep->mpr_count, i;
3669 
3670 		ur = &rangep->mpr_range_uint32[0];
3671 
3672 		for (i = 0; i < count; i++, ur++) {
3673 			if (ur->mpur_min == ur->mpur_max) {
3674 				(void) snprintf(prop_val[i], DLADM_PROP_VAL_MAX,
3675 				    "%ld", ur->mpur_min);
3676 			} else {
3677 				(void) snprintf(prop_val[i], DLADM_PROP_VAL_MAX,
3678 				    "%ld-%ld", ur->mpur_min, ur->mpur_max);
3679 			}
3680 		}
3681 		*val_cnt = count;
3682 		break;
3683 	}
3684 	default:
3685 		status = DLADM_STATUS_BADARG;
3686 		break;
3687 	}
3688 done:
3689 	free(dip);
3690 	return (status);
3691 }
3692 
3693 /* ARGSUSED */
3694 static dladm_status_t
3695 get_tagmode(dladm_handle_t handle, prop_desc_t *pdp,
3696     datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
3697     datalink_media_t media, uint_t flags, uint_t *perm_flags)
3698 {
3699 	link_tagmode_t		mode;
3700 	dladm_status_t		status;
3701 
3702 	status = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags,
3703 	    perm_flags, &mode, sizeof (mode));
3704 	if (status != DLADM_STATUS_OK)
3705 		return (status);
3706 
3707 	switch (mode) {
3708 	case LINK_TAGMODE_NORMAL:
3709 		(void) strlcpy(*prop_val, "normal", DLADM_PROP_VAL_MAX);
3710 		break;
3711 	case LINK_TAGMODE_VLANONLY:
3712 		(void) strlcpy(*prop_val, "vlanonly", DLADM_PROP_VAL_MAX);
3713 		break;
3714 	default:
3715 		(void) strlcpy(*prop_val, "unknown", DLADM_PROP_VAL_MAX);
3716 	}
3717 	*val_cnt = 1;
3718 	return (DLADM_STATUS_OK);
3719 }
3720 
3721 /* ARGSUSED */
3722 static dladm_status_t
3723 get_flowctl(dladm_handle_t handle, prop_desc_t *pdp,
3724     datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
3725     datalink_media_t media, uint_t flags, uint_t *perm_flags)
3726 {
3727 	link_flowctrl_t	v;
3728 	dladm_status_t	status;
3729 
3730 	status = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags,
3731 	    perm_flags, &v, sizeof (v));
3732 	if (status != DLADM_STATUS_OK)
3733 		return (status);
3734 
3735 	switch (v) {
3736 	case LINK_FLOWCTRL_NONE:
3737 		(void) sprintf(*prop_val, "no");
3738 		break;
3739 	case LINK_FLOWCTRL_RX:
3740 		(void) sprintf(*prop_val, "rx");
3741 		break;
3742 	case LINK_FLOWCTRL_TX:
3743 		(void) sprintf(*prop_val, "tx");
3744 		break;
3745 	case LINK_FLOWCTRL_BI:
3746 		(void) sprintf(*prop_val, "bi");
3747 		break;
3748 	}
3749 	*val_cnt = 1;
3750 	return (DLADM_STATUS_OK);
3751 }
3752 
3753 
3754 /* ARGSUSED */
3755 static dladm_status_t
3756 i_dladm_set_private_prop(dladm_handle_t handle, datalink_id_t linkid,
3757     const char *prop_name, char **prop_val, uint_t val_cnt, uint_t flags)
3758 
3759 {
3760 	int		i, slen;
3761 	int 		bufsize = 0;
3762 	dld_ioc_macprop_t *dip = NULL;
3763 	uchar_t 	*dp;
3764 	link_attr_t *p;
3765 	dladm_status_t	status = DLADM_STATUS_OK;
3766 
3767 	if ((prop_name == NULL && prop_val != NULL) ||
3768 	    (prop_val != NULL && val_cnt == 0))
3769 		return (DLADM_STATUS_BADARG);
3770 	p = dladm_name2prop(prop_name);
3771 	if (p->pp_id != MAC_PROP_PRIVATE)
3772 		return (DLADM_STATUS_BADARG);
3773 
3774 	if (!(flags & DLADM_OPT_ACTIVE))
3775 		return (DLADM_STATUS_OK);
3776 
3777 	/*
3778 	 * private properties: all parsing is done in the kernel.
3779 	 * allocate a enough space for each property + its separator (',').
3780 	 */
3781 	for (i = 0; i < val_cnt; i++) {
3782 		bufsize += strlen(prop_val[i]) + 1;
3783 	}
3784 
3785 	if (prop_val == NULL) {
3786 		/*
3787 		 * getting default value. so use more buffer space.
3788 		 */
3789 		bufsize += DLADM_PROP_BUF_CHUNK;
3790 	}
3791 
3792 	dip = i_dladm_buf_alloc_by_name(bufsize + 1, linkid, prop_name,
3793 	    (prop_val != NULL ? 0 : DLD_PROP_DEFAULT), &status);
3794 	if (dip == NULL)
3795 		return (status);
3796 
3797 	dp = (uchar_t *)dip->pr_val;
3798 	slen = 0;
3799 
3800 	if (prop_val == NULL) {
3801 		status = i_dladm_macprop(handle, dip, B_FALSE);
3802 		dip->pr_flags = 0;
3803 	} else {
3804 		for (i = 0; i < val_cnt; i++) {
3805 			int plen = 0;
3806 
3807 			plen = strlen(prop_val[i]);
3808 			bcopy(prop_val[i], dp, plen);
3809 			slen += plen;
3810 			/*
3811 			 * add a "," separator and update dp.
3812 			 */
3813 			if (i != (val_cnt -1))
3814 				dp[slen++] = ',';
3815 			dp += (plen + 1);
3816 		}
3817 	}
3818 	if (status == DLADM_STATUS_OK)
3819 		status = i_dladm_macprop(handle, dip, B_TRUE);
3820 
3821 	free(dip);
3822 	return (status);
3823 }
3824 
3825 static dladm_status_t
3826 i_dladm_get_priv_prop(dladm_handle_t handle, datalink_id_t linkid,
3827     const char *prop_name, char **prop_val, uint_t *val_cnt,
3828     dladm_prop_type_t type, uint_t dld_flags)
3829 {
3830 	dladm_status_t	status = DLADM_STATUS_OK;
3831 	dld_ioc_macprop_t *dip = NULL;
3832 	link_attr_t *p;
3833 
3834 	if ((prop_name == NULL && prop_val != NULL) ||
3835 	    (prop_val != NULL && val_cnt == 0))
3836 		return (DLADM_STATUS_BADARG);
3837 
3838 	p = dladm_name2prop(prop_name);
3839 	if (p->pp_id != MAC_PROP_PRIVATE)
3840 		return (DLADM_STATUS_BADARG);
3841 
3842 	/*
3843 	 * private properties: all parsing is done in the kernel.
3844 	 */
3845 	dip = i_dladm_buf_alloc_by_name(DLADM_PROP_BUF_CHUNK, linkid, prop_name,
3846 	    dld_flags, &status);
3847 	if (dip == NULL)
3848 		return (status);
3849 
3850 	if ((status = i_dladm_macprop(handle, dip, B_FALSE)) ==
3851 	    DLADM_STATUS_OK) {
3852 		if (type == DLADM_PROP_VAL_PERM) {
3853 			(void) dladm_perm2str(dip->pr_perm_flags, *prop_val);
3854 		} else if (type == DLADM_PROP_VAL_MODIFIABLE) {
3855 			*prop_val[0] = '\0';
3856 		} else {
3857 			(void) strncpy(*prop_val, dip->pr_val,
3858 			    DLADM_PROP_VAL_MAX);
3859 		}
3860 		*val_cnt = 1;
3861 	} else if ((status == DLADM_STATUS_NOTSUP) &&
3862 	    (type == DLADM_PROP_VAL_CURRENT)) {
3863 		status = DLADM_STATUS_NOTFOUND;
3864 	}
3865 	free(dip);
3866 	return (status);
3867 }
3868 
3869 
3870 static dladm_status_t
3871 i_dladm_getset_defval(dladm_handle_t handle, prop_desc_t *pdp,
3872     datalink_id_t linkid, datalink_media_t media, uint_t flags)
3873 {
3874 	dladm_status_t status;
3875 	char **prop_vals = NULL, *buf;
3876 	size_t bufsize;
3877 	uint_t cnt;
3878 	int i;
3879 	uint_t perm_flags;
3880 
3881 	/*
3882 	 * Allocate buffer needed for prop_vals array. We can have at most
3883 	 * DLADM_MAX_PROP_VALCNT char *prop_vals[] entries, where
3884 	 * each entry has max size DLADM_PROP_VAL_MAX
3885 	 */
3886 	bufsize =
3887 	    (sizeof (char *) + DLADM_PROP_VAL_MAX) * DLADM_MAX_PROP_VALCNT;
3888 	buf = malloc(bufsize);
3889 	prop_vals = (char **)(void *)buf;
3890 	for (i = 0; i < DLADM_MAX_PROP_VALCNT; i++) {
3891 		prop_vals[i] = buf +
3892 		    sizeof (char *) * DLADM_MAX_PROP_VALCNT +
3893 		    i * DLADM_PROP_VAL_MAX;
3894 	}
3895 
3896 	/*
3897 	 * For properties which have pdp->pd_defval.vd_name as a non-empty
3898 	 * string, the "" itself is used to reset the property (exceptions
3899 	 * are zone and autopush, which populate vdp->vd_val). So
3900 	 * libdladm can copy pdp->pd_defval over to the val_desc_t passed
3901 	 * down on the setprop using the global values in the table. For
3902 	 * other cases (vd_name is ""), doing reset-linkprop will cause
3903 	 * libdladm to do a getprop to find the default value and then do
3904 	 * a setprop to reset the value to default.
3905 	 */
3906 	status = pdp->pd_get(handle, pdp, linkid, prop_vals, &cnt, media,
3907 	    DLD_PROP_DEFAULT, &perm_flags);
3908 	if (status == DLADM_STATUS_OK) {
3909 		if (perm_flags == MAC_PROP_PERM_RW) {
3910 			status = i_dladm_set_single_prop(handle, linkid,
3911 			    pdp->pd_class, media, pdp, prop_vals, cnt, flags);
3912 		}
3913 		else
3914 			status = DLADM_STATUS_NOTSUP;
3915 	}
3916 	free(buf);
3917 	return (status);
3918 }
3919 
3920 /* ARGSUSED */
3921 static dladm_status_t
3922 get_stp(dladm_handle_t handle, struct prop_desc *pd, datalink_id_t linkid,
3923     char **prop_val, uint_t *val_cnt, datalink_media_t media, uint_t flags,
3924     uint_t *perm_flags)
3925 {
3926 	const bridge_public_prop_t *bpp;
3927 	dladm_status_t retv;
3928 	int val, i;
3929 
3930 	if (flags != 0)
3931 		return (DLADM_STATUS_NOTSUP);
3932 	*perm_flags = MAC_PROP_PERM_RW;
3933 	*val_cnt = 1;
3934 	for (bpp = bridge_prop; bpp->bpp_name != NULL; bpp++)
3935 		if (strcmp(bpp->bpp_name, pd->pd_name) == 0)
3936 			break;
3937 	retv = dladm_bridge_get_port_cfg(handle, linkid, bpp->bpp_code, &val);
3938 	/* If the daemon isn't running, then return the persistent value */
3939 	if (retv == DLADM_STATUS_NOTFOUND) {
3940 		if (i_dladm_get_linkprop_db(handle, linkid, pd->pd_name,
3941 		    prop_val, val_cnt) != DLADM_STATUS_OK)
3942 			(void) strlcpy(*prop_val, pd->pd_defval.vd_name,
3943 			    DLADM_PROP_VAL_MAX);
3944 		return (DLADM_STATUS_OK);
3945 	}
3946 	if (retv != DLADM_STATUS_OK) {
3947 		(void) strlcpy(*prop_val, "?", DLADM_PROP_VAL_MAX);
3948 		return (retv);
3949 	}
3950 	if (val == pd->pd_defval.vd_val && pd->pd_defval.vd_name[0] != '\0') {
3951 		(void) strlcpy(*prop_val, pd->pd_defval.vd_name,
3952 		    DLADM_PROP_VAL_MAX);
3953 		return (DLADM_STATUS_OK);
3954 	}
3955 	for (i = 0; i < pd->pd_noptval; i++) {
3956 		if (val == pd->pd_optval[i].vd_val) {
3957 			(void) strlcpy(*prop_val, pd->pd_optval[i].vd_name,
3958 			    DLADM_PROP_VAL_MAX);
3959 			return (DLADM_STATUS_OK);
3960 		}
3961 	}
3962 	(void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "%u", (unsigned)val);
3963 	return (DLADM_STATUS_OK);
3964 }
3965 
3966 /* ARGSUSED1 */
3967 static dladm_status_t
3968 set_stp_prop(dladm_handle_t handle, prop_desc_t *pd, datalink_id_t linkid,
3969     val_desc_t *vdp, uint_t val_cnt, uint_t flags, datalink_media_t media)
3970 {
3971 	/*
3972 	 * Special case for mcheck: the daemon resets the value to zero, and we
3973 	 * don't want the daemon to refresh itself; it leads to deadlock.
3974 	 */
3975 	if (flags & DLADM_OPT_NOREFRESH)
3976 		return (DLADM_STATUS_OK);
3977 
3978 	/* Tell the running daemon, if any */
3979 	return (dladm_bridge_refresh(handle, linkid));
3980 }
3981 
3982 /*
3983  * This is used only for stp_priority, stp_cost, and stp_mcheck.
3984  */
3985 /* ARGSUSED */
3986 static dladm_status_t
3987 check_stp_prop(dladm_handle_t handle, struct prop_desc *pd,
3988     datalink_id_t linkid, char **prop_val, uint_t val_cnt, uint_t flags,
3989     val_desc_t *vdp, datalink_media_t media)
3990 {
3991 	char *cp;
3992 	boolean_t iscost;
3993 
3994 	if (val_cnt != 1)
3995 		return (DLADM_STATUS_BADVALCNT);
3996 
3997 	if (prop_val == NULL) {
3998 		vdp->vd_val = 0;
3999 	} else {
4000 		/* Only stp_priority and stp_cost use this function */
4001 		iscost = strcmp(pd->pd_name, "stp_cost") == 0;
4002 
4003 		if (iscost && strcmp(prop_val[0], "auto") == 0) {
4004 			/* Illegal value 0 is allowed to mean "automatic" */
4005 			vdp->vd_val = 0;
4006 		} else {
4007 			errno = 0;
4008 			vdp->vd_val = strtoul(prop_val[0], &cp, 0);
4009 			if (errno != 0 || *cp != '\0')
4010 				return (DLADM_STATUS_BADVAL);
4011 		}
4012 	}
4013 
4014 	if (iscost) {
4015 		return (vdp->vd_val > 65535 ? DLADM_STATUS_BADVAL :
4016 		    DLADM_STATUS_OK);
4017 	} else {
4018 		if (vdp->vd_val > 255)
4019 			return (DLADM_STATUS_BADVAL);
4020 		/*
4021 		 * If the user is setting stp_mcheck non-zero, then (per the
4022 		 * IEEE management standards and UNH testing) we need to check
4023 		 * whether this link is part of a bridge that is running RSTP.
4024 		 * If it's not, then setting the flag is an error.  Note that
4025 		 * errors are intentionally discarded here; it's the value
4026 		 * that's the problem -- it's not a bad value, merely one that
4027 		 * can't be used now.
4028 		 */
4029 		if (strcmp(pd->pd_name, "stp_mcheck") == 0 &&
4030 		    vdp->vd_val != 0) {
4031 			char bridge[MAXLINKNAMELEN];
4032 			UID_STP_CFG_T cfg;
4033 			dladm_bridge_prot_t brprot;
4034 
4035 			if (dladm_bridge_getlink(handle, linkid, bridge,
4036 			    sizeof (bridge)) != DLADM_STATUS_OK ||
4037 			    dladm_bridge_get_properties(bridge, &cfg,
4038 			    &brprot) != DLADM_STATUS_OK)
4039 				return (DLADM_STATUS_FAILED);
4040 			if (cfg.force_version <= 1)
4041 				return (DLADM_STATUS_FAILED);
4042 		}
4043 		return (DLADM_STATUS_OK);
4044 	}
4045 }
4046 
4047 /* ARGSUSED */
4048 static dladm_status_t
4049 get_bridge_forward(dladm_handle_t handle, struct prop_desc *pd,
4050     datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
4051     datalink_media_t media, uint_t flags, uint_t *perm_flags)
4052 {
4053 	dladm_status_t retv;
4054 	uint_t val;
4055 
4056 	if (flags != 0)
4057 		return (DLADM_STATUS_NOTSUP);
4058 	*perm_flags = MAC_PROP_PERM_RW;
4059 	*val_cnt = 1;
4060 	retv = dladm_bridge_get_forwarding(handle, linkid, &val);
4061 	if (retv == DLADM_STATUS_NOTFOUND) {
4062 		if (i_dladm_get_linkprop_db(handle, linkid, pd->pd_name,
4063 		    prop_val, val_cnt) != DLADM_STATUS_OK)
4064 			(void) strlcpy(*prop_val, pd->pd_defval.vd_name,
4065 			    DLADM_PROP_VAL_MAX);
4066 		return (DLADM_STATUS_OK);
4067 	}
4068 	if (retv == DLADM_STATUS_OK)
4069 		(void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "%u", val);
4070 	else
4071 		(void) strlcpy(*prop_val, "?", DLADM_PROP_VAL_MAX);
4072 	return (retv);
4073 }
4074 
4075 /* ARGSUSED */
4076 static dladm_status_t
4077 set_bridge_forward(dladm_handle_t handle, prop_desc_t *pd, datalink_id_t linkid,
4078     val_desc_t *vdp, uint_t val_cnt, uint_t flags, datalink_media_t media)
4079 {
4080 	/* Tell the running daemon, if any */
4081 	return (dladm_bridge_refresh(handle, linkid));
4082 }
4083 
4084 /* ARGSUSED */
4085 static dladm_status_t
4086 get_bridge_pvid(dladm_handle_t handle, struct prop_desc *pd,
4087     datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
4088     datalink_media_t media, uint_t flags, uint_t *perm_flags)
4089 {
4090 	dladm_status_t status;
4091 	dld_ioc_macprop_t *dip;
4092 	uint16_t pvid;
4093 
4094 	if (flags != 0)
4095 		return (DLADM_STATUS_NOTSUP);
4096 	*perm_flags = MAC_PROP_PERM_RW;
4097 	*val_cnt = 1;
4098 	dip = i_dladm_buf_alloc_by_id(sizeof (uint16_t), linkid, MAC_PROP_PVID,
4099 	    0, &status);
4100 	if (dip == NULL)
4101 		return (status);
4102 	status = i_dladm_macprop(handle, dip, B_FALSE);
4103 	if (status == DLADM_STATUS_OK) {
4104 		(void) memcpy(&pvid, dip->pr_val, sizeof (pvid));
4105 		(void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "%u", pvid);
4106 	} else {
4107 		(void) strlcpy(*prop_val, "?", DLADM_PROP_VAL_MAX);
4108 	}
4109 	free(dip);
4110 	return (status);
4111 }
4112 
4113 /* ARGSUSED */
4114 static dladm_status_t
4115 set_bridge_pvid(dladm_handle_t handle, prop_desc_t *pd, datalink_id_t linkid,
4116     val_desc_t *vdp, uint_t val_cnt, uint_t flags, datalink_media_t media)
4117 {
4118 	dladm_status_t status;
4119 	dld_ioc_macprop_t *dip;
4120 	uint16_t pvid;
4121 
4122 	dip = i_dladm_buf_alloc_by_id(sizeof (uint16_t), linkid, MAC_PROP_PVID,
4123 	    0, &status);
4124 	if (dip == NULL)
4125 		return (status);
4126 	pvid = vdp->vd_val;
4127 	(void) memcpy(dip->pr_val, &pvid, sizeof (pvid));
4128 	status = i_dladm_macprop(handle, dip, B_TRUE);
4129 	free(dip);
4130 	if (status != DLADM_STATUS_OK)
4131 		return (status);
4132 
4133 	/* Tell the running daemon, if any */
4134 	return (dladm_bridge_refresh(handle, linkid));
4135 }
4136 
4137 /* ARGSUSED */
4138 static dladm_status_t
4139 check_bridge_pvid(dladm_handle_t handle, struct prop_desc *pd,
4140     datalink_id_t linkid, char **prop_val, uint_t val_cnt, uint_t flags,
4141     val_desc_t *vdp, datalink_media_t media)
4142 {
4143 	char *cp;
4144 
4145 	if (val_cnt != 1)
4146 		return (DLADM_STATUS_BADVALCNT);
4147 
4148 	if (prop_val == NULL) {
4149 		vdp->vd_val = 1;
4150 	} else {
4151 		errno = 0;
4152 		vdp->vd_val = strtoul(prop_val[0], &cp, 0);
4153 		if (errno != 0 || *cp != '\0')
4154 			return (DLADM_STATUS_BADVAL);
4155 	}
4156 
4157 	return (vdp->vd_val > VLAN_ID_MAX ? DLADM_STATUS_BADVAL :
4158 	    DLADM_STATUS_OK);
4159 }
4160 
4161 dladm_status_t
4162 i_dladm_wlan_param(dladm_handle_t handle, datalink_id_t linkid, void *buf,
4163     mac_prop_id_t cmd, size_t len, boolean_t set)
4164 {
4165 	uint32_t		flags;
4166 	dladm_status_t		status;
4167 	uint32_t		media;
4168 	dld_ioc_macprop_t	*dip;
4169 	void			*dp;
4170 
4171 	if ((status = dladm_datalink_id2info(handle, linkid, &flags, NULL,
4172 	    &media, NULL, 0)) != DLADM_STATUS_OK) {
4173 		return (status);
4174 	}
4175 
4176 	if (media != DL_WIFI)
4177 		return (DLADM_STATUS_BADARG);
4178 
4179 	if (!(flags & DLADM_OPT_ACTIVE))
4180 		return (DLADM_STATUS_TEMPONLY);
4181 
4182 	if (len == (MAX_BUF_LEN - WIFI_BUF_OFFSET))
4183 		len = MAX_BUF_LEN - sizeof (dld_ioc_macprop_t) - 1;
4184 
4185 	dip = i_dladm_buf_alloc_by_id(len, linkid, cmd, 0, &status);
4186 	if (dip == NULL)
4187 		return (DLADM_STATUS_NOMEM);
4188 
4189 	dp = (uchar_t *)dip->pr_val;
4190 	if (set)
4191 		(void) memcpy(dp, buf, len);
4192 
4193 	status = i_dladm_macprop(handle, dip, set);
4194 	if (status == DLADM_STATUS_OK) {
4195 		if (!set)
4196 			(void) memcpy(buf, dp, len);
4197 	}
4198 
4199 	free(dip);
4200 	return (status);
4201 }
4202 
4203 dladm_status_t
4204 dladm_parse_link_props(char *str, dladm_arg_list_t **listp, boolean_t novalues)
4205 {
4206 	return (dladm_parse_args(str, listp, novalues));
4207 }
4208 
4209 /*
4210  * Retrieve the one link property from the database
4211  */
4212 /*ARGSUSED*/
4213 static int
4214 i_dladm_get_one_prop(dladm_handle_t handle, datalink_id_t linkid,
4215     const char *prop_name, void *arg)
4216 {
4217 	dladm_arg_list_t	*proplist = arg;
4218 	dladm_arg_info_t	*aip = NULL;
4219 
4220 	aip = &proplist->al_info[proplist->al_count];
4221 	/*
4222 	 * it is fine to point to prop_name since prop_name points to the
4223 	 * prop_table[n].pd_name.
4224 	 */
4225 	aip->ai_name = prop_name;
4226 
4227 	(void) dladm_get_linkprop(handle, linkid, DLADM_PROP_VAL_PERSISTENT,
4228 	    prop_name, aip->ai_val, &aip->ai_count);
4229 
4230 	if (aip->ai_count != 0)
4231 		proplist->al_count++;
4232 
4233 	return (DLADM_WALK_CONTINUE);
4234 }
4235 
4236 
4237 /*
4238  * Retrieve all link properties for a link from the database and
4239  * return a property list.
4240  */
4241 dladm_status_t
4242 dladm_link_get_proplist(dladm_handle_t handle, datalink_id_t linkid,
4243     dladm_arg_list_t **listp)
4244 {
4245 	dladm_arg_list_t	*list;
4246 	dladm_status_t		status = DLADM_STATUS_OK;
4247 
4248 	list = calloc(1, sizeof (dladm_arg_list_t));
4249 	if (list == NULL)
4250 		return (dladm_errno2status(errno));
4251 
4252 	status = dladm_walk_linkprop(handle, linkid, list,
4253 	    i_dladm_get_one_prop);
4254 
4255 	*listp = list;
4256 	return (status);
4257 }
4258 
4259 /*
4260  * Retrieve the named property from a proplist, check the value and
4261  * convert to a kernel structure.
4262  */
4263 static dladm_status_t
4264 i_dladm_link_proplist_extract_one(dladm_handle_t handle,
4265     dladm_arg_list_t *proplist, const char *name, uint_t flags, void *arg)
4266 {
4267 	dladm_status_t		status;
4268 	dladm_arg_info_t	*aip = NULL;
4269 	int			i, j;
4270 
4271 	/* Find named property in proplist */
4272 	for (i = 0; i < proplist->al_count; i++) {
4273 		aip = &proplist->al_info[i];
4274 		if (strcasecmp(aip->ai_name, name) == 0)
4275 			break;
4276 	}
4277 
4278 	/* Property not in list */
4279 	if (i == proplist->al_count)
4280 		return (DLADM_STATUS_OK);
4281 
4282 	for (i = 0; i < DLADM_MAX_PROPS; i++) {
4283 		prop_desc_t	*pdp = &prop_table[i];
4284 		val_desc_t	*vdp;
4285 
4286 		vdp = malloc(sizeof (val_desc_t) * aip->ai_count);
4287 		if (vdp == NULL)
4288 			return (DLADM_STATUS_NOMEM);
4289 
4290 		if (strcasecmp(aip->ai_name, pdp->pd_name) != 0)
4291 			continue;
4292 
4293 		if (aip->ai_val == NULL)
4294 			return (DLADM_STATUS_BADARG);
4295 
4296 		/* Check property value */
4297 		if (pdp->pd_check != NULL) {
4298 			status = pdp->pd_check(handle, pdp, 0, aip->ai_val,
4299 			    aip->ai_count, flags, vdp, 0);
4300 		} else {
4301 			status = DLADM_STATUS_BADARG;
4302 		}
4303 
4304 		if (status != DLADM_STATUS_OK)
4305 			return (status);
4306 
4307 		for (j = 0; j < DLADM_MAX_RSRC_PROP; j++) {
4308 			resource_prop_t	*rpp = &rsrc_prop_table[j];
4309 
4310 			if (strcasecmp(aip->ai_name, rpp->rp_name) != 0)
4311 				continue;
4312 
4313 			/* Extract kernel structure */
4314 			if (rpp->rp_extract != NULL) {
4315 				status = rpp->rp_extract(vdp,
4316 				    aip->ai_count, arg);
4317 			} else {
4318 				status = DLADM_STATUS_BADARG;
4319 			}
4320 			break;
4321 		}
4322 
4323 		if (status != DLADM_STATUS_OK)
4324 			return (status);
4325 
4326 		break;
4327 	}
4328 	return (status);
4329 }
4330 
4331 /*
4332  * Extract properties from a proplist and convert to mac_resource_props_t.
4333  */
4334 dladm_status_t
4335 dladm_link_proplist_extract(dladm_handle_t handle, dladm_arg_list_t *proplist,
4336     mac_resource_props_t *mrp, uint_t flags)
4337 {
4338 	dladm_status_t	status;
4339 	int		i;
4340 
4341 	for (i = 0; i < DLADM_MAX_RSRC_PROP; i++) {
4342 		status = i_dladm_link_proplist_extract_one(handle,
4343 		    proplist, rsrc_prop_table[i].rp_name, flags, mrp);
4344 		if (status != DLADM_STATUS_OK)
4345 			return (status);
4346 	}
4347 	return (status);
4348 }
4349 
4350 static const char *
4351 dladm_perm2str(uint_t perm, char *buf)
4352 {
4353 	(void) snprintf(buf, DLADM_STRSIZE, "%c%c",
4354 	    ((perm & MAC_PROP_PERM_READ) != 0) ? 'r' : '-',
4355 	    ((perm & MAC_PROP_PERM_WRITE) != 0) ? 'w' : '-');
4356 	return (buf);
4357 }
4358 
4359 dladm_status_t
4360 dladm_get_state(dladm_handle_t handle, datalink_id_t linkid,
4361     link_state_t *state)
4362 {
4363 	uint_t			perms;
4364 
4365 	return (i_dladm_get_public_prop(handle, linkid, "state", 0,
4366 	    &perms, state, sizeof (*state)));
4367 }
4368 
4369 boolean_t
4370 dladm_attr_is_linkprop(const char *name)
4371 {
4372 	/* non-property attribute names */
4373 	const char *nonprop[] = {
4374 		/* dlmgmtd core attributes */
4375 		"name",
4376 		"class",
4377 		"media",
4378 		FPHYMAJ,
4379 		FPHYINST,
4380 		FDEVNAME,
4381 
4382 		/* other attributes for vlan, aggr, etc */
4383 		DLADM_ATTR_NAMES
4384 	};
4385 	boolean_t	is_nonprop = B_FALSE;
4386 	int		i;
4387 
4388 	for (i = 0; i < sizeof (nonprop) / sizeof (nonprop[0]); i++) {
4389 		if (strcmp(name, nonprop[i]) == 0) {
4390 			is_nonprop = B_TRUE;
4391 			break;
4392 		}
4393 	}
4394 
4395 	return (!is_nonprop);
4396 }
4397 
4398 dladm_status_t
4399 dladm_linkprop_is_set(dladm_handle_t handle, datalink_id_t linkid,
4400     dladm_prop_type_t type, const char *prop_name, boolean_t *is_set)
4401 {
4402 	char		*buf, **propvals;
4403 	uint_t		valcnt = DLADM_MAX_PROP_VALCNT;
4404 	int		i;
4405 	dladm_status_t	status = DLADM_STATUS_OK;
4406 
4407 	*is_set = B_FALSE;
4408 
4409 	if ((buf = malloc((sizeof (char *) + DLADM_PROP_VAL_MAX) *
4410 	    DLADM_MAX_PROP_VALCNT)) == NULL)
4411 		return (DLADM_STATUS_NOMEM);
4412 
4413 	propvals = (char **)(void *)buf;
4414 	for (i = 0; i < valcnt; i++) {
4415 		propvals[i] = buf +
4416 		    sizeof (char *) * DLADM_MAX_PROP_VALCNT +
4417 		    i * DLADM_PROP_VAL_MAX;
4418 	}
4419 
4420 	if (dladm_get_linkprop(handle, linkid, type, prop_name, propvals,
4421 	    &valcnt) != DLADM_STATUS_OK) {
4422 		goto done;
4423 	}
4424 
4425 	if ((strcmp(prop_name, "pool") == 0) && (strlen(*propvals) != 0)) {
4426 		*is_set = B_TRUE;
4427 	} else if ((strcmp(prop_name, "cpus") == 0) && (valcnt != 0)) {
4428 		*is_set = B_TRUE;
4429 	} else if ((strcmp(prop_name, "_softmac") == 0) && (valcnt != 0) &&
4430 	    (strcmp(propvals[0], "true") == 0)) {
4431 		*is_set = B_TRUE;
4432 	}
4433 
4434 done:
4435 	if (buf != NULL)
4436 		free(buf);
4437 	return (status);
4438 }
4439