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