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