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