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