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