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