6659 nvlist_free(NULL) is a no-op
[illumos-gate.git] / usr / src / lib / libdladm / common / linkprop.c
blob171e23dc2cb0580db380fdf2eeff1bdcb23c0bd4
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
22 * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright (c) 2014, Joyent, Inc. All rights reserved.
24 * Copyright 2015 Garrett D'Amore <garrett@damore.org>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <strings.h>
30 #include <errno.h>
31 #include <ctype.h>
32 #include <stddef.h>
33 #include <sys/types.h>
34 #include <sys/stat.h>
35 #include <sys/dld.h>
36 #include <sys/zone.h>
37 #include <fcntl.h>
38 #include <unistd.h>
39 #include <libdevinfo.h>
40 #include <zone.h>
41 #include <libdllink.h>
42 #include <libdladm_impl.h>
43 #include <libdlwlan_impl.h>
44 #include <libdlwlan.h>
45 #include <libdlvlan.h>
46 #include <libdlvnic.h>
47 #include <libdlib.h>
48 #include <libintl.h>
49 #include <dlfcn.h>
50 #include <link.h>
51 #include <inet/wifi_ioctl.h>
52 #include <libdladm.h>
53 #include <libdlstat.h>
54 #include <sys/param.h>
55 #include <sys/debug.h>
56 #include <sys/dld.h>
57 #include <inttypes.h>
58 #include <sys/ethernet.h>
59 #include <inet/iptun.h>
60 #include <net/wpa.h>
61 #include <sys/sysmacros.h>
62 #include <sys/vlan.h>
63 #include <libdlbridge.h>
64 #include <stp_in.h>
65 #include <netinet/dhcp.h>
66 #include <netinet/dhcp6.h>
67 #include <net/if_types.h>
68 #include <libinetutil.h>
69 #include <pool.h>
70 #include <libdlaggr.h>
73 * The linkprop get() callback.
74 * - pd: pointer to the prop_desc_t
75 * - propstrp: a property string array to keep the returned property.
76 * Caller allocated.
77 * - cntp: number of returned properties.
78 * Caller also uses it to indicate how many it expects.
80 struct prop_desc;
81 typedef struct prop_desc prop_desc_t;
83 typedef dladm_status_t pd_getf_t(dladm_handle_t, prop_desc_t *pdp,
84 datalink_id_t, char **propstp, uint_t *cntp,
85 datalink_media_t, uint_t, uint_t *);
88 * The linkprop set() callback.
89 * - propval: a val_desc_t array which keeps the property values to be set.
90 * - cnt: number of properties to be set.
91 * - flags: additional flags passed down the system call.
93 * pd_set takes val_desc_t given by pd_check(), translates it into
94 * a format suitable for kernel consumption. This may require allocation
95 * of ioctl buffers etc. pd_set() may call another common routine (used
96 * by all other pd_sets) which invokes the ioctl.
98 typedef dladm_status_t pd_setf_t(dladm_handle_t, prop_desc_t *, datalink_id_t,
99 val_desc_t *propval, uint_t cnt, uint_t flags,
100 datalink_media_t);
103 * The linkprop check() callback.
104 * - propstrp: property string array which keeps the property to be checked.
105 * - cnt: number of properties.
106 * - propval: return value; the property values of the given property strings.
108 * pd_check checks that the input values are valid. It does so by
109 * iteraring through the pd_modval list for the property. If
110 * the modifiable values cannot be expressed as a list, a pd_check
111 * specific to this property can be used. If the input values are
112 * verified to be valid, pd_check allocates a val_desc_t and fills it
113 * with either a val_desc_t found on the pd_modval list or something
114 * generated on the fly.
116 typedef dladm_status_t pd_checkf_t(dladm_handle_t, prop_desc_t *pdp,
117 datalink_id_t, char **propstrp, uint_t *cnt,
118 uint_t flags, val_desc_t **propval,
119 datalink_media_t);
121 typedef struct link_attr_s {
122 mac_prop_id_t pp_id;
123 size_t pp_valsize;
124 char *pp_name;
125 } link_attr_t;
127 typedef struct dladm_linkprop_args_s {
128 dladm_status_t dla_status;
129 uint_t dla_flags;
130 } dladm_linkprop_args_t;
132 static dld_ioc_macprop_t *i_dladm_buf_alloc_by_name(size_t, datalink_id_t,
133 const char *, uint_t, dladm_status_t *);
134 static dld_ioc_macprop_t *i_dladm_buf_alloc_by_id(size_t, datalink_id_t,
135 mac_prop_id_t, uint_t, dladm_status_t *);
136 static dladm_status_t i_dladm_get_public_prop(dladm_handle_t, datalink_id_t,
137 char *, uint_t, uint_t *, void *, size_t);
139 static dladm_status_t i_dladm_set_private_prop(dladm_handle_t, datalink_id_t,
140 const char *, char **, uint_t, uint_t);
141 static dladm_status_t i_dladm_get_priv_prop(dladm_handle_t, datalink_id_t,
142 const char *, char **, uint_t *, dladm_prop_type_t,
143 uint_t);
144 static dladm_status_t i_dladm_macprop(dladm_handle_t, void *, boolean_t);
145 static const char *dladm_perm2str(uint_t, char *);
146 static link_attr_t *dladm_name2prop(const char *);
147 static link_attr_t *dladm_id2prop(mac_prop_id_t);
149 static pd_getf_t get_zone, get_autopush, get_rate_mod, get_rate,
150 get_speed, get_channel, get_powermode, get_radio,
151 get_duplex, get_link_state, get_binary, get_uint32,
152 get_flowctl, get_maxbw, get_cpus, get_priority,
153 get_tagmode, get_range, get_stp, get_bridge_forward,
154 get_bridge_pvid, get_protection, get_rxrings,
155 get_txrings, get_cntavail, get_secondary_macs,
156 get_allowedips, get_allowedcids, get_pool,
157 get_rings_range, get_linkmode_prop;
159 static pd_setf_t set_zone, set_rate, set_powermode, set_radio,
160 set_public_prop, set_resource, set_stp_prop,
161 set_bridge_forward, set_bridge_pvid, set_secondary_macs;
163 static pd_checkf_t check_zone, check_autopush, check_rate, check_hoplimit,
164 check_encaplim, check_uint32, check_maxbw, check_cpus,
165 check_stp_prop, check_bridge_pvid, check_allowedips,
166 check_allowedcids, check_secondary_macs, check_rings,
167 check_pool, check_prop;
169 struct prop_desc {
171 * link property name
173 char *pd_name;
176 * default property value, can be set to { "", NULL }
178 val_desc_t pd_defval;
181 * list of optional property values, can be NULL.
183 * This is set to non-NULL if there is a list of possible property
184 * values. pd_optval would point to the array of possible values.
186 val_desc_t *pd_optval;
189 * count of the above optional property values. 0 if pd_optval is NULL.
191 uint_t pd_noptval;
194 * callback to set link property; set to NULL if this property is
195 * read-only and may be called before or after permanent update; see
196 * flags.
198 pd_setf_t *pd_set;
201 * callback to get modifiable link property
203 pd_getf_t *pd_getmod;
206 * callback to get current link property
208 pd_getf_t *pd_get;
211 * callback to validate link property value, set to NULL if pd_optval
212 * is not NULL. In that case, validate the value by comparing it with
213 * the pd_optval. Return a val_desc_t array pointer if the value is
214 * valid.
216 pd_checkf_t *pd_check;
218 uint_t pd_flags;
219 #define PD_TEMPONLY 0x1 /* property is temporary only */
220 #define PD_CHECK_ALLOC 0x2 /* alloc vd_val as part of pd_check */
221 #define PD_AFTER_PERM 0x4 /* pd_set after db update; no temporary */
223 * indicate link classes this property applies to.
225 datalink_class_t pd_class;
228 * indicate link media type this property applies to.
230 datalink_media_t pd_dmedia;
233 #define MAC_PROP_BUFSIZE(v) sizeof (dld_ioc_macprop_t) + (v) - 1
236 * Supported link properties enumerated in the prop_table[] array are
237 * computed using the callback functions in that array. To compute the
238 * property value, multiple distinct system calls may be needed (e.g.,
239 * for wifi speed, we need to issue system calls to get desired/supported
240 * rates). The link_attr[] table enumerates the interfaces to the kernel,
241 * and the type/size of the data passed in the user-kernel interface.
243 static link_attr_t link_attr[] = {
244 { MAC_PROP_DUPLEX, sizeof (link_duplex_t), "duplex"},
246 { MAC_PROP_SPEED, sizeof (uint64_t), "speed"},
248 { MAC_PROP_STATUS, sizeof (link_state_t), "state"},
250 { MAC_PROP_AUTONEG, sizeof (uint8_t), "adv_autoneg_cap"},
252 { MAC_PROP_MTU, sizeof (uint32_t), "mtu"},
254 { MAC_PROP_FLOWCTRL, sizeof (link_flowctrl_t), "flowctrl"},
256 { MAC_PROP_ZONE, sizeof (dld_ioc_zid_t), "zone"},
258 { MAC_PROP_AUTOPUSH, sizeof (struct dlautopush), "autopush"},
260 { MAC_PROP_ADV_5000FDX_CAP, sizeof (uint8_t), "adv_5000fdx_cap"},
262 { MAC_PROP_EN_5000FDX_CAP, sizeof (uint8_t), "en_5000fdx_cap"},
264 { MAC_PROP_ADV_2500FDX_CAP, sizeof (uint8_t), "adv_2500fdx_cap"},
266 { MAC_PROP_EN_2500FDX_CAP, sizeof (uint8_t), "en_2500fdx_cap"},
268 { MAC_PROP_ADV_100GFDX_CAP, sizeof (uint8_t), "adv_100gfdx_cap"},
270 { MAC_PROP_EN_100GFDX_CAP, sizeof (uint8_t), "en_100gfdx_cap"},
272 { MAC_PROP_ADV_40GFDX_CAP, sizeof (uint8_t), "adv_40gfdx_cap"},
274 { MAC_PROP_EN_40GFDX_CAP, sizeof (uint8_t), "en_40gfdx_cap"},
276 { MAC_PROP_ADV_10GFDX_CAP, sizeof (uint8_t), "adv_10gfdx_cap"},
278 { MAC_PROP_EN_10GFDX_CAP, sizeof (uint8_t), "en_10gfdx_cap"},
280 { MAC_PROP_ADV_1000FDX_CAP, sizeof (uint8_t), "adv_1000fdx_cap"},
282 { MAC_PROP_EN_1000FDX_CAP, sizeof (uint8_t), "en_1000fdx_cap"},
284 { MAC_PROP_ADV_1000HDX_CAP, sizeof (uint8_t), "adv_1000hdx_cap"},
286 { MAC_PROP_EN_1000HDX_CAP, sizeof (uint8_t), "en_1000hdx_cap"},
288 { MAC_PROP_ADV_100FDX_CAP, sizeof (uint8_t), "adv_100fdx_cap"},
290 { MAC_PROP_EN_100FDX_CAP, sizeof (uint8_t), "en_100fdx_cap"},
292 { MAC_PROP_ADV_100HDX_CAP, sizeof (uint8_t), "adv_100hdx_cap"},
294 { MAC_PROP_EN_100HDX_CAP, sizeof (uint8_t), "en_100hdx_cap"},
296 { MAC_PROP_ADV_10FDX_CAP, sizeof (uint8_t), "adv_10fdx_cap"},
298 { MAC_PROP_EN_10FDX_CAP, sizeof (uint8_t), "en_10fdx_cap"},
300 { MAC_PROP_ADV_10HDX_CAP, sizeof (uint8_t), "adv_10hdx_cap"},
302 { MAC_PROP_EN_10HDX_CAP, sizeof (uint8_t), "en_10hdx_cap"},
304 { MAC_PROP_WL_ESSID, sizeof (wl_linkstatus_t), "essid"},
306 { MAC_PROP_WL_BSSID, sizeof (wl_bssid_t), "bssid"},
308 { MAC_PROP_WL_BSSTYPE, sizeof (wl_bss_type_t), "bsstype"},
310 { MAC_PROP_WL_LINKSTATUS, sizeof (wl_linkstatus_t), "wl_linkstatus"},
312 /* wl_rates_t has variable length */
313 { MAC_PROP_WL_DESIRED_RATES, sizeof (wl_rates_t), "desired_rates"},
315 /* wl_rates_t has variable length */
316 { MAC_PROP_WL_SUPPORTED_RATES, sizeof (wl_rates_t), "supported_rates"},
318 { MAC_PROP_WL_AUTH_MODE, sizeof (wl_authmode_t), "authmode"},
320 { MAC_PROP_WL_ENCRYPTION, sizeof (wl_encryption_t), "encryption"},
322 { MAC_PROP_WL_RSSI, sizeof (wl_rssi_t), "signal"},
324 { MAC_PROP_WL_PHY_CONFIG, sizeof (wl_phy_conf_t), "phy_conf"},
326 { MAC_PROP_WL_CAPABILITY, sizeof (wl_capability_t), "capability"},
328 { MAC_PROP_WL_WPA, sizeof (wl_wpa_t), "wpa"},
330 /* wl_wpa_ess_t has variable length */
331 { MAC_PROP_WL_SCANRESULTS, sizeof (wl_wpa_ess_t), "scan_results"},
333 { MAC_PROP_WL_POWER_MODE, sizeof (wl_ps_mode_t), "powermode"},
335 { MAC_PROP_WL_RADIO, sizeof (dladm_wlan_radio_t), "wl_radio"},
337 { MAC_PROP_WL_ESS_LIST, sizeof (wl_ess_list_t), "wl_ess_list"},
339 { MAC_PROP_WL_KEY_TAB, sizeof (wl_wep_key_tab_t), "wl_wep_key"},
341 { MAC_PROP_WL_CREATE_IBSS, sizeof (wl_create_ibss_t), "createibss"},
343 /* wl_wpa_ie_t has variable length */
344 { MAC_PROP_WL_SETOPTIE, sizeof (wl_wpa_ie_t), "set_ie"},
346 { MAC_PROP_WL_DELKEY, sizeof (wl_del_key_t), "wpa_del_key"},
348 { MAC_PROP_WL_KEY, sizeof (wl_key_t), "wl_key"},
350 { MAC_PROP_WL_MLME, sizeof (wl_mlme_t), "mlme"},
352 { MAC_PROP_TAGMODE, sizeof (link_tagmode_t), "tagmode"},
354 { MAC_PROP_IPTUN_HOPLIMIT, sizeof (uint32_t), "hoplimit"},
356 { MAC_PROP_IPTUN_ENCAPLIMIT, sizeof (uint32_t), "encaplimit"},
358 { MAC_PROP_PVID, sizeof (uint16_t), "default_tag"},
360 { MAC_PROP_LLIMIT, sizeof (uint32_t), "learn_limit"},
362 { MAC_PROP_LDECAY, sizeof (uint32_t), "learn_decay"},
364 { MAC_PROP_RESOURCE, sizeof (mac_resource_props_t), "resource"},
366 { MAC_PROP_RESOURCE_EFF, sizeof (mac_resource_props_t),
367 "resource-effective"},
369 { MAC_PROP_RXRINGSRANGE, sizeof (mac_propval_range_t), "rxrings"},
371 { MAC_PROP_TXRINGSRANGE, sizeof (mac_propval_range_t), "txrings"},
373 { MAC_PROP_MAX_TX_RINGS_AVAIL, sizeof (uint_t),
374 "txrings-available"},
376 { MAC_PROP_MAX_RX_RINGS_AVAIL, sizeof (uint_t),
377 "rxrings-available"},
379 { MAC_PROP_MAX_RXHWCLNT_AVAIL, sizeof (uint_t), "rxhwclnt-available"},
381 { MAC_PROP_MAX_TXHWCLNT_AVAIL, sizeof (uint_t), "txhwclnt-available"},
383 { MAC_PROP_IB_LINKMODE, sizeof (uint32_t), "linkmode"},
385 { MAC_PROP_SECONDARY_ADDRS, sizeof (mac_secondary_addr_t),
386 "secondary-macs"},
388 { MAC_PROP_PRIVATE, 0, "driver-private"}
391 typedef struct bridge_public_prop_s {
392 const char *bpp_name;
393 int bpp_code;
394 } bridge_public_prop_t;
396 static const bridge_public_prop_t bridge_prop[] = {
397 { "stp", PT_CFG_NON_STP },
398 { "stp_priority", PT_CFG_PRIO },
399 { "stp_cost", PT_CFG_COST },
400 { "stp_edge", PT_CFG_EDGE },
401 { "stp_p2p", PT_CFG_P2P },
402 { "stp_mcheck", PT_CFG_MCHECK },
403 { NULL, 0 }
406 static val_desc_t link_duplex_vals[] = {
407 { "half", LINK_DUPLEX_HALF },
408 { "full", LINK_DUPLEX_HALF }
410 static val_desc_t link_status_vals[] = {
411 { "up", LINK_STATE_UP },
412 { "down", LINK_STATE_DOWN }
414 static val_desc_t link_01_vals[] = {
415 { "1", 1 },
416 { "0", 0 }
418 static val_desc_t link_flow_vals[] = {
419 { "no", LINK_FLOWCTRL_NONE },
420 { "tx", LINK_FLOWCTRL_TX },
421 { "rx", LINK_FLOWCTRL_RX },
422 { "bi", LINK_FLOWCTRL_BI }
424 static val_desc_t link_priority_vals[] = {
425 { "low", MPL_LOW },
426 { "medium", MPL_MEDIUM },
427 { "high", MPL_HIGH }
430 static val_desc_t link_tagmode_vals[] = {
431 { "normal", LINK_TAGMODE_NORMAL },
432 { "vlanonly", LINK_TAGMODE_VLANONLY }
435 static val_desc_t link_protect_vals[] = {
436 { "mac-nospoof", MPT_MACNOSPOOF },
437 { "restricted", MPT_RESTRICTED },
438 { "ip-nospoof", MPT_IPNOSPOOF },
439 { "dhcp-nospoof", MPT_DHCPNOSPOOF },
442 static val_desc_t dladm_wlan_radio_vals[] = {
443 { "on", DLADM_WLAN_RADIO_ON },
444 { "off", DLADM_WLAN_RADIO_OFF }
447 static val_desc_t dladm_wlan_powermode_vals[] = {
448 { "off", DLADM_WLAN_PM_OFF },
449 { "fast", DLADM_WLAN_PM_FAST },
450 { "max", DLADM_WLAN_PM_MAX }
453 static val_desc_t stp_p2p_vals[] = {
454 { "true", P2P_FORCE_TRUE },
455 { "false", P2P_FORCE_FALSE },
456 { "auto", P2P_AUTO }
459 static val_desc_t dladm_part_linkmode_vals[] = {
460 { "cm", DLADM_PART_CM_MODE },
461 { "ud", DLADM_PART_UD_MODE },
464 #define VALCNT(vals) (sizeof ((vals)) / sizeof (val_desc_t))
465 #define RESET_VAL ((uintptr_t)-1)
466 #define UNSPEC_VAL ((uintptr_t)-2)
469 * For the default, if defaults are not defined for the property,
470 * pd_defval.vd_name should be null. If the driver has to be contacted for the
471 * value, vd_name should be the empty string (""). Otherwise, dladm will
472 * just print whatever is in the table.
474 static prop_desc_t prop_table[] = {
475 { "channel", { NULL, 0 },
476 NULL, 0, NULL, NULL,
477 get_channel, NULL, 0,
478 DATALINK_CLASS_PHYS, DL_WIFI },
480 { "powermode", { "off", DLADM_WLAN_PM_OFF },
481 dladm_wlan_powermode_vals, VALCNT(dladm_wlan_powermode_vals),
482 set_powermode, NULL,
483 get_powermode, NULL, 0,
484 DATALINK_CLASS_PHYS, DL_WIFI },
486 { "radio", { "on", DLADM_WLAN_RADIO_ON },
487 dladm_wlan_radio_vals, VALCNT(dladm_wlan_radio_vals),
488 set_radio, NULL,
489 get_radio, NULL, 0,
490 DATALINK_CLASS_PHYS, DL_WIFI },
492 { "linkmode", { "cm", DLADM_PART_CM_MODE },
493 dladm_part_linkmode_vals, VALCNT(dladm_part_linkmode_vals),
494 set_public_prop, NULL, get_linkmode_prop, NULL, 0,
495 DATALINK_CLASS_PART, DL_IB },
497 { "speed", { "", 0 }, NULL, 0,
498 set_rate, get_rate_mod,
499 get_rate, check_rate, 0,
500 DATALINK_CLASS_PHYS, DATALINK_ANY_MEDIATYPE },
502 { "autopush", { "", 0 }, NULL, 0,
503 set_public_prop, NULL,
504 get_autopush, check_autopush, PD_CHECK_ALLOC,
505 DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
507 { "zone", { "", 0 }, NULL, 0,
508 set_zone, NULL,
509 get_zone, check_zone, PD_TEMPONLY|PD_CHECK_ALLOC,
510 DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
512 { "duplex", { "", 0 },
513 link_duplex_vals, VALCNT(link_duplex_vals),
514 NULL, NULL, get_duplex, NULL,
515 0, DATALINK_CLASS_PHYS, DL_ETHER },
517 { "state", { "up", LINK_STATE_UP },
518 link_status_vals, VALCNT(link_status_vals),
519 NULL, NULL, get_link_state, NULL,
520 0, DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
522 { "adv_autoneg_cap", { "", 0 },
523 link_01_vals, VALCNT(link_01_vals),
524 set_public_prop, NULL, get_binary, NULL,
525 0, DATALINK_CLASS_PHYS, DL_ETHER },
527 { "mtu", { "", 0 }, NULL, 0,
528 set_public_prop, get_range,
529 get_uint32, check_uint32, 0, DATALINK_CLASS_ALL,
530 DATALINK_ANY_MEDIATYPE },
532 { "flowctrl", { "", 0 },
533 link_flow_vals, VALCNT(link_flow_vals),
534 set_public_prop, NULL, get_flowctl, NULL,
535 0, DATALINK_CLASS_PHYS, DL_ETHER },
537 { "secondary-macs", { "--", 0 }, NULL, 0,
538 set_secondary_macs, NULL,
539 get_secondary_macs, check_secondary_macs, PD_CHECK_ALLOC,
540 DATALINK_CLASS_VNIC, DL_ETHER },
542 { "adv_100gfdx_cap", { "", 0 },
543 link_01_vals, VALCNT(link_01_vals),
544 NULL, NULL, get_binary, NULL,
545 0, DATALINK_CLASS_PHYS, DL_ETHER },
547 { "en_100gfdx_cap", { "", 0 },
548 link_01_vals, VALCNT(link_01_vals),
549 set_public_prop, NULL, get_binary, NULL,
550 0, DATALINK_CLASS_PHYS, DL_ETHER },
552 { "adv_40gfdx_cap", { "", 0 },
553 link_01_vals, VALCNT(link_01_vals),
554 NULL, NULL, get_binary, NULL,
555 0, DATALINK_CLASS_PHYS, DL_ETHER },
557 { "en_40gfdx_cap", { "", 0 },
558 link_01_vals, VALCNT(link_01_vals),
559 set_public_prop, NULL, get_binary, NULL,
560 0, DATALINK_CLASS_PHYS, DL_ETHER },
562 { "adv_10gfdx_cap", { "", 0 },
563 link_01_vals, VALCNT(link_01_vals),
564 NULL, NULL, get_binary, NULL,
565 0, DATALINK_CLASS_PHYS, DL_ETHER },
567 { "en_10gfdx_cap", { "", 0 },
568 link_01_vals, VALCNT(link_01_vals),
569 set_public_prop, NULL, get_binary, NULL,
570 0, DATALINK_CLASS_PHYS, DL_ETHER },
572 { "adv_5000fdx_cap", { "", 0 },
573 link_01_vals, VALCNT(link_01_vals),
574 NULL, NULL, get_binary, NULL,
575 0, DATALINK_CLASS_PHYS, DL_ETHER },
577 { "en_5000fdx_cap", { "", 0 },
578 link_01_vals, VALCNT(link_01_vals),
579 set_public_prop, NULL, get_binary, NULL,
580 0, DATALINK_CLASS_PHYS, DL_ETHER },
582 { "adv_2500fdx_cap", { "", 0 },
583 link_01_vals, VALCNT(link_01_vals),
584 NULL, NULL, get_binary, NULL,
585 0, DATALINK_CLASS_PHYS, DL_ETHER },
587 { "en_2500fdx_cap", { "", 0 },
588 link_01_vals, VALCNT(link_01_vals),
589 set_public_prop, NULL, get_binary, NULL,
590 0, DATALINK_CLASS_PHYS, DL_ETHER },
592 { "adv_1000fdx_cap", { "", 0 },
593 link_01_vals, VALCNT(link_01_vals),
594 NULL, NULL, get_binary, NULL,
595 0, DATALINK_CLASS_PHYS, DL_ETHER },
597 { "en_1000fdx_cap", { "", 0 },
598 link_01_vals, VALCNT(link_01_vals),
599 set_public_prop, NULL, get_binary, NULL,
600 0, DATALINK_CLASS_PHYS, DL_ETHER },
602 { "adv_1000hdx_cap", { "", 0 },
603 link_01_vals, VALCNT(link_01_vals),
604 NULL, NULL, get_binary, NULL,
605 0, DATALINK_CLASS_PHYS, DL_ETHER },
607 { "en_1000hdx_cap", { "", 0 },
608 link_01_vals, VALCNT(link_01_vals),
609 set_public_prop, NULL, get_binary, NULL,
610 0, DATALINK_CLASS_PHYS, DL_ETHER },
612 { "adv_100fdx_cap", { "", 0 },
613 link_01_vals, VALCNT(link_01_vals),
614 NULL, NULL, get_binary, NULL,
615 0, DATALINK_CLASS_PHYS, DL_ETHER },
617 { "en_100fdx_cap", { "", 0 },
618 link_01_vals, VALCNT(link_01_vals),
619 set_public_prop, NULL, get_binary, NULL,
620 0, DATALINK_CLASS_PHYS, DL_ETHER },
622 { "adv_100hdx_cap", { "", 0 },
623 link_01_vals, VALCNT(link_01_vals),
624 NULL, NULL, get_binary, NULL,
625 0, DATALINK_CLASS_PHYS, DL_ETHER },
627 { "en_100hdx_cap", { "", 0 },
628 link_01_vals, VALCNT(link_01_vals),
629 set_public_prop, NULL, get_binary, NULL,
630 0, DATALINK_CLASS_PHYS, DL_ETHER },
632 { "adv_10fdx_cap", { "", 0 },
633 link_01_vals, VALCNT(link_01_vals),
634 NULL, NULL, get_binary, NULL,
635 0, DATALINK_CLASS_PHYS, DL_ETHER },
637 { "en_10fdx_cap", { "", 0 },
638 link_01_vals, VALCNT(link_01_vals),
639 set_public_prop, NULL, get_binary, NULL,
640 0, DATALINK_CLASS_PHYS, DL_ETHER },
642 { "adv_10hdx_cap", { "", 0 },
643 link_01_vals, VALCNT(link_01_vals),
644 NULL, NULL, get_binary, NULL,
645 0, DATALINK_CLASS_PHYS, DL_ETHER },
647 { "en_10hdx_cap", { "", 0 },
648 link_01_vals, VALCNT(link_01_vals),
649 set_public_prop, NULL, get_binary, NULL,
650 0, DATALINK_CLASS_PHYS, DL_ETHER },
652 { "maxbw", { "--", RESET_VAL }, NULL, 0,
653 set_resource, NULL,
654 get_maxbw, check_maxbw, PD_CHECK_ALLOC,
655 DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
657 { "cpus", { "--", RESET_VAL }, NULL, 0,
658 set_resource, NULL,
659 get_cpus, check_cpus, 0,
660 DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
662 { "cpus-effective", { "--", 0 },
663 NULL, 0, NULL, NULL,
664 get_cpus, 0, 0,
665 DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
667 { "pool", { "--", RESET_VAL }, NULL, 0,
668 set_resource, NULL,
669 get_pool, check_pool, 0,
670 DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
672 { "pool-effective", { "--", 0 },
673 NULL, 0, NULL, NULL,
674 get_pool, 0, 0,
675 DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
677 { "priority", { "high", MPL_RESET },
678 link_priority_vals, VALCNT(link_priority_vals), set_resource,
679 NULL, get_priority, check_prop, 0,
680 DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
682 { "tagmode", { "vlanonly", LINK_TAGMODE_VLANONLY },
683 link_tagmode_vals, VALCNT(link_tagmode_vals),
684 set_public_prop, NULL, get_tagmode,
685 NULL, 0,
686 DATALINK_CLASS_PHYS | DATALINK_CLASS_AGGR | DATALINK_CLASS_VNIC,
687 DL_ETHER },
689 { "hoplimit", { "", 0 }, NULL, 0,
690 set_public_prop, get_range, get_uint32,
691 check_hoplimit, 0, DATALINK_CLASS_IPTUN, DATALINK_ANY_MEDIATYPE},
693 { "encaplimit", { "", 0 }, NULL, 0,
694 set_public_prop, get_range, get_uint32,
695 check_encaplim, 0, DATALINK_CLASS_IPTUN, DL_IPV6},
697 { "forward", { "1", 1 },
698 link_01_vals, VALCNT(link_01_vals),
699 set_bridge_forward, NULL, get_bridge_forward, NULL, PD_AFTER_PERM,
700 DATALINK_CLASS_ALL & ~DATALINK_CLASS_VNIC, DL_ETHER },
702 { "default_tag", { "1", 1 }, NULL, 0,
703 set_bridge_pvid, NULL, get_bridge_pvid, check_bridge_pvid,
704 0, DATALINK_CLASS_PHYS|DATALINK_CLASS_AGGR|
705 DATALINK_CLASS_ETHERSTUB|DATALINK_CLASS_SIMNET, DL_ETHER },
707 { "learn_limit", { "1000", 1000 }, NULL, 0,
708 set_public_prop, NULL, get_uint32,
709 check_uint32, 0,
710 DATALINK_CLASS_PHYS|DATALINK_CLASS_AGGR|
711 DATALINK_CLASS_ETHERSTUB|DATALINK_CLASS_SIMNET, DL_ETHER },
713 { "learn_decay", { "200", 200 }, NULL, 0,
714 set_public_prop, NULL, get_uint32,
715 check_uint32, 0,
716 DATALINK_CLASS_PHYS|DATALINK_CLASS_AGGR|
717 DATALINK_CLASS_ETHERSTUB|DATALINK_CLASS_SIMNET, DL_ETHER },
719 { "stp", { "1", 1 },
720 link_01_vals, VALCNT(link_01_vals),
721 set_stp_prop, NULL, get_stp, NULL, PD_AFTER_PERM,
722 DATALINK_CLASS_PHYS|DATALINK_CLASS_AGGR|
723 DATALINK_CLASS_ETHERSTUB|DATALINK_CLASS_SIMNET, DL_ETHER },
725 { "stp_priority", { "128", 128 }, NULL, 0,
726 set_stp_prop, NULL, get_stp, check_stp_prop, PD_AFTER_PERM,
727 DATALINK_CLASS_PHYS|DATALINK_CLASS_AGGR|
728 DATALINK_CLASS_ETHERSTUB|DATALINK_CLASS_SIMNET, DL_ETHER },
730 { "stp_cost", { "auto", 0 }, NULL, 0,
731 set_stp_prop, NULL, get_stp, check_stp_prop, PD_AFTER_PERM,
732 DATALINK_CLASS_PHYS|DATALINK_CLASS_AGGR|
733 DATALINK_CLASS_ETHERSTUB|DATALINK_CLASS_SIMNET, DL_ETHER },
735 { "stp_edge", { "1", 1 },
736 link_01_vals, VALCNT(link_01_vals),
737 set_stp_prop, NULL, get_stp, NULL, PD_AFTER_PERM,
738 DATALINK_CLASS_PHYS|DATALINK_CLASS_AGGR|
739 DATALINK_CLASS_ETHERSTUB|DATALINK_CLASS_SIMNET, DL_ETHER },
741 { "stp_p2p", { "auto", P2P_AUTO },
742 stp_p2p_vals, VALCNT(stp_p2p_vals),
743 set_stp_prop, NULL, get_stp, NULL, PD_AFTER_PERM,
744 DATALINK_CLASS_PHYS|DATALINK_CLASS_AGGR|
745 DATALINK_CLASS_ETHERSTUB|DATALINK_CLASS_SIMNET, DL_ETHER },
747 { "stp_mcheck", { "0", 0 },
748 link_01_vals, VALCNT(link_01_vals),
749 set_stp_prop, NULL, get_stp, check_stp_prop, PD_AFTER_PERM,
750 DATALINK_CLASS_PHYS|DATALINK_CLASS_AGGR|
751 DATALINK_CLASS_ETHERSTUB|DATALINK_CLASS_SIMNET, DL_ETHER },
753 { "protection", { "--", RESET_VAL },
754 link_protect_vals, VALCNT(link_protect_vals),
755 set_resource, NULL, get_protection, check_prop, 0,
756 DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
758 { "allowed-ips", { "--", 0 },
759 NULL, 0, set_resource, NULL,
760 get_allowedips, check_allowedips, PD_CHECK_ALLOC,
761 DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
763 { "allowed-dhcp-cids", { "--", 0 },
764 NULL, 0, set_resource, NULL,
765 get_allowedcids, check_allowedcids, PD_CHECK_ALLOC,
766 DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
768 { "rxrings", { "--", RESET_VAL }, NULL, 0,
769 set_resource, get_rings_range, get_rxrings, check_rings, 0,
770 DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
772 { "rxrings-effective", { "--", 0 },
773 NULL, 0, NULL, NULL,
774 get_rxrings, NULL, 0,
775 DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
777 { "txrings", { "--", RESET_VAL }, NULL, 0,
778 set_resource, get_rings_range, get_txrings, check_rings, 0,
779 DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
781 { "txrings-effective", { "--", 0 },
782 NULL, 0, NULL, NULL,
783 get_txrings, NULL, 0,
784 DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
786 { "txrings-available", { "", 0 }, NULL, 0,
787 NULL, NULL, get_cntavail, NULL, 0,
788 DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
790 { "rxrings-available", { "", 0 }, NULL, 0,
791 NULL, NULL, get_cntavail, NULL, 0,
792 DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
794 { "rxhwclnt-available", { "", 0 }, NULL, 0,
795 NULL, NULL, get_cntavail, NULL, 0,
796 DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
798 { "txhwclnt-available", { "", 0 }, NULL, 0,
799 NULL, NULL, get_cntavail, NULL, 0,
800 DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
804 #define DLADM_MAX_PROPS (sizeof (prop_table) / sizeof (prop_desc_t))
806 static resource_prop_t rsrc_prop_table[] = {
807 {"maxbw", extract_maxbw},
808 {"priority", extract_priority},
809 {"cpus", extract_cpus},
810 {"cpus-effective", extract_cpus},
811 {"pool", extract_pool},
812 {"pool-effective", extract_pool},
813 {"protection", extract_protection},
814 {"allowed-ips", extract_allowedips},
815 {"allowed-dhcp-cids", extract_allowedcids},
816 {"rxrings", extract_rxrings},
817 {"rxrings-effective", extract_rxrings},
818 {"txrings", extract_txrings},
819 {"txrings-effective", extract_txrings}
821 #define DLADM_MAX_RSRC_PROP (sizeof (rsrc_prop_table) / \
822 sizeof (resource_prop_t))
825 * when retrieving private properties, we pass down a buffer with
826 * DLADM_PROP_BUF_CHUNK of space for the driver to return the property value.
828 #define DLADM_PROP_BUF_CHUNK 1024
830 static dladm_status_t i_dladm_set_linkprop_db(dladm_handle_t, datalink_id_t,
831 const char *, char **, uint_t);
832 static dladm_status_t i_dladm_get_linkprop_db(dladm_handle_t, datalink_id_t,
833 const char *, char **, uint_t *);
834 static dladm_status_t i_dladm_walk_linkprop_priv_db(dladm_handle_t,
835 datalink_id_t, void *, int (*)(dladm_handle_t,
836 datalink_id_t, const char *, void *));
837 static dladm_status_t i_dladm_set_single_prop(dladm_handle_t, datalink_id_t,
838 datalink_class_t, uint32_t, prop_desc_t *, char **,
839 uint_t, uint_t);
840 static dladm_status_t i_dladm_set_linkprop(dladm_handle_t, datalink_id_t,
841 const char *, char **, uint_t, uint_t);
842 static dladm_status_t i_dladm_getset_defval(dladm_handle_t, prop_desc_t *,
843 datalink_id_t, datalink_media_t, uint_t);
846 * Unfortunately, MAX_SCAN_SUPPORT_RATES is too small to allow all
847 * rates to be retrieved. However, we cannot increase it at this
848 * time because it will break binary compatibility with unbundled
849 * WiFi drivers and utilities. So for now we define an additional
850 * constant, MAX_SUPPORT_RATES, to allow all rates to be retrieved.
852 #define MAX_SUPPORT_RATES 64
854 #define AP_ANCHOR "[anchor]"
855 #define AP_DELIMITER '.'
857 /* ARGSUSED */
858 static dladm_status_t
859 check_prop(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
860 char **prop_val, uint_t *val_cntp, uint_t flags, val_desc_t **vdpp,
861 datalink_media_t media)
863 int i, j;
864 uint_t val_cnt = *val_cntp;
865 val_desc_t *vdp = *vdpp;
867 for (j = 0; j < val_cnt; j++) {
868 for (i = 0; i < pdp->pd_noptval; i++) {
869 if (strcasecmp(prop_val[j],
870 pdp->pd_optval[i].vd_name) == 0) {
871 break;
874 if (i == pdp->pd_noptval)
875 return (DLADM_STATUS_BADVAL);
877 (void) memcpy(&vdp[j], &pdp->pd_optval[i], sizeof (val_desc_t));
879 return (DLADM_STATUS_OK);
882 static dladm_status_t
883 i_dladm_set_single_prop(dladm_handle_t handle, datalink_id_t linkid,
884 datalink_class_t class, uint32_t media, prop_desc_t *pdp, char **prop_val,
885 uint_t val_cnt, uint_t flags)
887 dladm_status_t status = DLADM_STATUS_OK;
888 val_desc_t *vdp = NULL;
889 boolean_t needfree = B_FALSE;
890 uint_t cnt, i;
892 if (!(pdp->pd_class & class))
893 return (DLADM_STATUS_BADARG);
895 if (!DATALINK_MEDIA_ACCEPTED(pdp->pd_dmedia, media))
896 return (DLADM_STATUS_BADARG);
898 if ((flags & DLADM_OPT_PERSIST) && (pdp->pd_flags & PD_TEMPONLY))
899 return (DLADM_STATUS_TEMPONLY);
901 if (!(flags & DLADM_OPT_ACTIVE))
902 return (DLADM_STATUS_OK);
904 if (pdp->pd_set == NULL)
905 return (DLADM_STATUS_PROPRDONLY);
907 if (prop_val != NULL) {
908 vdp = calloc(val_cnt, sizeof (val_desc_t));
909 if (vdp == NULL)
910 return (DLADM_STATUS_NOMEM);
912 if (pdp->pd_check != NULL) {
913 needfree = ((pdp->pd_flags & PD_CHECK_ALLOC) != 0);
914 status = pdp->pd_check(handle, pdp, linkid, prop_val,
915 &val_cnt, flags, &vdp, media);
916 } else if (pdp->pd_optval != NULL) {
917 status = check_prop(handle, pdp, linkid, prop_val,
918 &val_cnt, flags, &vdp, media);
919 } else {
920 status = DLADM_STATUS_BADARG;
923 if (status != DLADM_STATUS_OK)
924 goto done;
926 cnt = val_cnt;
927 } else {
928 boolean_t defval = B_FALSE;
930 if (pdp->pd_defval.vd_name == NULL)
931 return (DLADM_STATUS_NOTSUP);
933 cnt = 1;
934 defval = (strlen(pdp->pd_defval.vd_name) > 0);
935 if ((pdp->pd_flags & PD_CHECK_ALLOC) != 0 || defval) {
936 if ((vdp = calloc(1, sizeof (val_desc_t))) == NULL)
937 return (DLADM_STATUS_NOMEM);
939 if (defval) {
940 (void) memcpy(vdp, &pdp->pd_defval,
941 sizeof (val_desc_t));
942 } else if (pdp->pd_check != NULL) {
943 status = pdp->pd_check(handle, pdp, linkid,
944 prop_val, &cnt, flags, &vdp, media);
945 if (status != DLADM_STATUS_OK)
946 goto done;
948 } else {
949 status = i_dladm_getset_defval(handle, pdp, linkid,
950 media, flags);
951 return (status);
954 if (pdp->pd_flags & PD_AFTER_PERM)
955 status = (flags & DLADM_OPT_PERSIST) ? DLADM_STATUS_OK :
956 DLADM_STATUS_PERMONLY;
957 else
958 status = pdp->pd_set(handle, pdp, linkid, vdp, cnt, flags,
959 media);
960 if (needfree) {
961 for (i = 0; i < cnt; i++)
962 free((void *)((val_desc_t *)vdp + i)->vd_val);
964 done:
965 free(vdp);
966 return (status);
969 static dladm_status_t
970 i_dladm_set_linkprop(dladm_handle_t handle, datalink_id_t linkid,
971 const char *prop_name, char **prop_val, uint_t val_cnt, uint_t flags)
973 int i;
974 boolean_t found = B_FALSE;
975 datalink_class_t class;
976 uint32_t media;
977 dladm_status_t status = DLADM_STATUS_OK;
979 status = dladm_datalink_id2info(handle, linkid, NULL, &class, &media,
980 NULL, 0);
981 if (status != DLADM_STATUS_OK)
982 return (status);
984 for (i = 0; i < DLADM_MAX_PROPS; i++) {
985 prop_desc_t *pdp = &prop_table[i];
986 dladm_status_t s;
988 if (prop_name != NULL &&
989 (strcasecmp(prop_name, pdp->pd_name) != 0))
990 continue;
991 found = B_TRUE;
992 s = i_dladm_set_single_prop(handle, linkid, class, media, pdp,
993 prop_val, val_cnt, flags);
995 if (prop_name != NULL) {
996 status = s;
997 break;
998 } else {
999 if (s != DLADM_STATUS_OK &&
1000 s != DLADM_STATUS_NOTSUP)
1001 status = s;
1004 if (!found) {
1005 if (prop_name[0] == '_') {
1006 /* other private properties */
1007 status = i_dladm_set_private_prop(handle, linkid,
1008 prop_name, prop_val, val_cnt, flags);
1009 } else {
1010 status = DLADM_STATUS_NOTFOUND;
1013 return (status);
1017 * Set/reset link property for specific link
1019 dladm_status_t
1020 dladm_set_linkprop(dladm_handle_t handle, datalink_id_t linkid,
1021 const char *prop_name, char **prop_val, uint_t val_cnt, uint_t flags)
1023 dladm_status_t status = DLADM_STATUS_OK;
1025 if ((linkid == DATALINK_INVALID_LINKID) || (flags == 0) ||
1026 (prop_val == NULL && val_cnt > 0) ||
1027 (prop_val != NULL && val_cnt == 0) ||
1028 (prop_name == NULL && prop_val != NULL)) {
1029 return (DLADM_STATUS_BADARG);
1033 * Check for valid link property against the flags passed
1034 * and set the link property when active flag is passed.
1036 status = i_dladm_set_linkprop(handle, linkid, prop_name, prop_val,
1037 val_cnt, flags);
1038 if (status != DLADM_STATUS_OK)
1039 return (status);
1041 if (flags & DLADM_OPT_PERSIST) {
1042 status = i_dladm_set_linkprop_db(handle, linkid, prop_name,
1043 prop_val, val_cnt);
1045 if (status == DLADM_STATUS_OK && (flags & DLADM_OPT_ACTIVE)) {
1046 prop_desc_t *pdp = prop_table;
1047 int i;
1049 for (i = 0; i < DLADM_MAX_PROPS; i++, pdp++) {
1050 if (!(pdp->pd_flags & PD_AFTER_PERM))
1051 continue;
1052 if (prop_name != NULL &&
1053 strcasecmp(prop_name, pdp->pd_name) != 0)
1054 continue;
1055 status = pdp->pd_set(handle, pdp, linkid, NULL,
1056 0, flags, 0);
1060 return (status);
1064 * Walk all link properties of the given specific link.
1066 * Note: this function currently lacks the ability to walk _all_ private
1067 * properties if the link, because there is no kernel interface to
1068 * retrieve all known private property names. Once such an interface
1069 * is added, this function should be fixed accordingly.
1071 dladm_status_t
1072 dladm_walk_linkprop(dladm_handle_t handle, datalink_id_t linkid, void *arg,
1073 int (*func)(dladm_handle_t, datalink_id_t, const char *, void *))
1075 dladm_status_t status;
1076 datalink_class_t class;
1077 uint_t media;
1078 int i;
1080 if (linkid == DATALINK_INVALID_LINKID || func == NULL)
1081 return (DLADM_STATUS_BADARG);
1083 status = dladm_datalink_id2info(handle, linkid, NULL, &class, &media,
1084 NULL, 0);
1085 if (status != DLADM_STATUS_OK)
1086 return (status);
1088 /* public */
1089 for (i = 0; i < DLADM_MAX_PROPS; i++) {
1090 if (!(prop_table[i].pd_class & class))
1091 continue;
1093 if (!DATALINK_MEDIA_ACCEPTED(prop_table[i].pd_dmedia, media))
1094 continue;
1096 if (func(handle, linkid, prop_table[i].pd_name, arg) ==
1097 DLADM_WALK_TERMINATE) {
1098 break;
1102 /* private */
1103 status = i_dladm_walk_linkprop_priv_db(handle, linkid, arg, func);
1105 return (status);
1109 * Get linkprop of the given specific link.
1111 dladm_status_t
1112 dladm_get_linkprop(dladm_handle_t handle, datalink_id_t linkid,
1113 dladm_prop_type_t type, const char *prop_name, char **prop_val,
1114 uint_t *val_cntp)
1116 dladm_status_t status = DLADM_STATUS_OK;
1117 datalink_class_t class;
1118 uint_t media;
1119 prop_desc_t *pdp;
1120 uint_t cnt, dld_flags = 0;
1121 int i;
1122 uint_t perm_flags;
1124 if (type == DLADM_PROP_VAL_DEFAULT)
1125 dld_flags |= DLD_PROP_DEFAULT;
1126 else if (type == DLADM_PROP_VAL_MODIFIABLE)
1127 dld_flags |= DLD_PROP_POSSIBLE;
1129 if (linkid == DATALINK_INVALID_LINKID || prop_name == NULL ||
1130 prop_val == NULL || val_cntp == NULL || *val_cntp == 0)
1131 return (DLADM_STATUS_BADARG);
1133 for (i = 0; i < DLADM_MAX_PROPS; i++)
1134 if (strcasecmp(prop_name, prop_table[i].pd_name) == 0)
1135 break;
1137 if (i == DLADM_MAX_PROPS) {
1138 if (prop_name[0] == '_') {
1140 * private property.
1142 if (type == DLADM_PROP_VAL_PERSISTENT)
1143 return (i_dladm_get_linkprop_db(handle, linkid,
1144 prop_name, prop_val, val_cntp));
1145 else
1146 return (i_dladm_get_priv_prop(handle, linkid,
1147 prop_name, prop_val, val_cntp, type,
1148 dld_flags));
1149 } else {
1150 return (DLADM_STATUS_NOTFOUND);
1154 pdp = &prop_table[i];
1156 status = dladm_datalink_id2info(handle, linkid, NULL, &class, &media,
1157 NULL, 0);
1158 if (status != DLADM_STATUS_OK)
1159 return (status);
1161 if (!(pdp->pd_class & class))
1162 return (DLADM_STATUS_BADARG);
1164 if (!DATALINK_MEDIA_ACCEPTED(pdp->pd_dmedia, media))
1165 return (DLADM_STATUS_BADARG);
1167 switch (type) {
1168 case DLADM_PROP_VAL_CURRENT:
1169 status = pdp->pd_get(handle, pdp, linkid, prop_val, val_cntp,
1170 media, dld_flags, &perm_flags);
1171 break;
1173 case DLADM_PROP_VAL_PERM:
1174 if (pdp->pd_set == NULL) {
1175 perm_flags = MAC_PROP_PERM_READ;
1176 } else {
1177 status = pdp->pd_get(handle, pdp, linkid, prop_val,
1178 val_cntp, media, dld_flags, &perm_flags);
1181 *prop_val[0] = '\0';
1182 *val_cntp = 1;
1183 if (status == DLADM_STATUS_OK)
1184 (void) dladm_perm2str(perm_flags, *prop_val);
1185 break;
1187 case DLADM_PROP_VAL_DEFAULT:
1189 * If defaults are not defined for the property,
1190 * pd_defval.vd_name should be null. If the driver
1191 * has to be contacted for the value, vd_name should
1192 * be the empty string (""). Otherwise, dladm will
1193 * just print whatever is in the table.
1195 if (pdp->pd_defval.vd_name == NULL) {
1196 status = DLADM_STATUS_NOTSUP;
1197 break;
1200 if (strlen(pdp->pd_defval.vd_name) == 0) {
1201 status = pdp->pd_get(handle, pdp, linkid, prop_val,
1202 val_cntp, media, dld_flags, &perm_flags);
1203 } else {
1204 (void) strcpy(*prop_val, pdp->pd_defval.vd_name);
1206 *val_cntp = 1;
1207 break;
1209 case DLADM_PROP_VAL_MODIFIABLE:
1210 if (pdp->pd_getmod != NULL) {
1211 status = pdp->pd_getmod(handle, pdp, linkid, prop_val,
1212 val_cntp, media, dld_flags, &perm_flags);
1213 break;
1215 cnt = pdp->pd_noptval;
1216 if (cnt == 0) {
1217 status = DLADM_STATUS_NOTSUP;
1218 } else if (cnt > *val_cntp) {
1219 status = DLADM_STATUS_TOOSMALL;
1220 } else {
1221 for (i = 0; i < cnt; i++) {
1222 (void) strcpy(prop_val[i],
1223 pdp->pd_optval[i].vd_name);
1225 *val_cntp = cnt;
1227 break;
1228 case DLADM_PROP_VAL_PERSISTENT:
1229 if (pdp->pd_flags & PD_TEMPONLY)
1230 return (DLADM_STATUS_TEMPONLY);
1231 status = i_dladm_get_linkprop_db(handle, linkid, prop_name,
1232 prop_val, val_cntp);
1233 break;
1234 default:
1235 status = DLADM_STATUS_BADARG;
1236 break;
1239 return (status);
1243 * Get linkprop of the given specific link and run any possible conversion
1244 * of the values using the check function for the property. Fails if the
1245 * check function doesn't succeed for the property value.
1247 dladm_status_t
1248 dladm_get_linkprop_values(dladm_handle_t handle, datalink_id_t linkid,
1249 dladm_prop_type_t type, const char *prop_name, uint_t *ret_val,
1250 uint_t *val_cntp)
1252 dladm_status_t status;
1253 datalink_class_t class;
1254 uint_t media;
1255 prop_desc_t *pdp;
1256 uint_t dld_flags;
1257 int valc, i;
1258 char **prop_val;
1259 uint_t perm_flags;
1261 if (linkid == DATALINK_INVALID_LINKID || prop_name == NULL ||
1262 ret_val == NULL || val_cntp == NULL || *val_cntp == 0)
1263 return (DLADM_STATUS_BADARG);
1265 for (pdp = prop_table; pdp < prop_table + DLADM_MAX_PROPS; pdp++)
1266 if (strcasecmp(prop_name, pdp->pd_name) == 0)
1267 break;
1269 if (pdp == prop_table + DLADM_MAX_PROPS)
1270 return (DLADM_STATUS_NOTFOUND);
1272 if (pdp->pd_flags & PD_CHECK_ALLOC)
1273 return (DLADM_STATUS_BADARG);
1275 status = dladm_datalink_id2info(handle, linkid, NULL, &class, &media,
1276 NULL, 0);
1277 if (status != DLADM_STATUS_OK)
1278 return (status);
1280 if (!(pdp->pd_class & class))
1281 return (DLADM_STATUS_BADARG);
1283 if (!DATALINK_MEDIA_ACCEPTED(pdp->pd_dmedia, media))
1284 return (DLADM_STATUS_BADARG);
1286 prop_val = malloc(*val_cntp * sizeof (*prop_val) +
1287 *val_cntp * DLADM_PROP_VAL_MAX);
1288 if (prop_val == NULL)
1289 return (DLADM_STATUS_NOMEM);
1290 for (valc = 0; valc < *val_cntp; valc++)
1291 prop_val[valc] = (char *)(prop_val + *val_cntp) +
1292 valc * DLADM_PROP_VAL_MAX;
1294 dld_flags = (type == DLADM_PROP_VAL_DEFAULT) ? DLD_PROP_DEFAULT : 0;
1296 switch (type) {
1297 case DLADM_PROP_VAL_CURRENT:
1298 status = pdp->pd_get(handle, pdp, linkid, prop_val, val_cntp,
1299 media, dld_flags, &perm_flags);
1300 break;
1302 case DLADM_PROP_VAL_DEFAULT:
1304 * If defaults are not defined for the property,
1305 * pd_defval.vd_name should be null. If the driver
1306 * has to be contacted for the value, vd_name should
1307 * be the empty string (""). Otherwise, dladm will
1308 * just print whatever is in the table.
1310 if (pdp->pd_defval.vd_name == NULL) {
1311 status = DLADM_STATUS_NOTSUP;
1312 break;
1315 if (pdp->pd_defval.vd_name[0] != '\0') {
1316 *val_cntp = 1;
1317 *ret_val = pdp->pd_defval.vd_val;
1318 free(prop_val);
1319 return (DLADM_STATUS_OK);
1321 status = pdp->pd_get(handle, pdp, linkid, prop_val, val_cntp,
1322 media, dld_flags, &perm_flags);
1323 break;
1325 case DLADM_PROP_VAL_PERSISTENT:
1326 if (pdp->pd_flags & PD_TEMPONLY)
1327 status = DLADM_STATUS_TEMPONLY;
1328 else
1329 status = i_dladm_get_linkprop_db(handle, linkid,
1330 prop_name, prop_val, val_cntp);
1331 break;
1333 default:
1334 status = DLADM_STATUS_BADARG;
1335 break;
1338 if (status == DLADM_STATUS_OK) {
1339 if (pdp->pd_check != NULL) {
1340 val_desc_t *vdp;
1342 vdp = malloc(sizeof (val_desc_t) * *val_cntp);
1343 if (vdp == NULL)
1344 status = DLADM_STATUS_NOMEM;
1345 else
1346 status = pdp->pd_check(handle, pdp, linkid,
1347 prop_val, val_cntp, 0, &vdp, media);
1348 if (status == DLADM_STATUS_OK) {
1349 for (valc = 0; valc < *val_cntp; valc++)
1350 ret_val[valc] = vdp[valc].vd_val;
1352 free(vdp);
1353 } else {
1354 for (valc = 0; valc < *val_cntp; valc++) {
1355 for (i = 0; i < pdp->pd_noptval; i++) {
1356 if (strcmp(pdp->pd_optval[i].vd_name,
1357 prop_val[valc]) == 0) {
1358 ret_val[valc] =
1359 pdp->pd_optval[i].vd_val;
1360 break;
1363 if (i == pdp->pd_noptval) {
1364 status = DLADM_STATUS_FAILED;
1365 break;
1371 free(prop_val);
1373 return (status);
1376 /*ARGSUSED*/
1377 static int
1378 i_dladm_init_one_prop(dladm_handle_t handle, datalink_id_t linkid,
1379 const char *prop_name, void *arg)
1381 char *buf, **propvals;
1382 uint_t i, valcnt = DLADM_MAX_PROP_VALCNT;
1383 dladm_status_t status;
1384 dladm_linkprop_args_t *dla = arg;
1386 if ((buf = malloc((sizeof (char *) + DLADM_PROP_VAL_MAX) *
1387 DLADM_MAX_PROP_VALCNT)) == NULL) {
1388 return (DLADM_WALK_CONTINUE);
1391 propvals = (char **)(void *)buf;
1392 for (i = 0; i < valcnt; i++) {
1393 propvals[i] = buf +
1394 sizeof (char *) * DLADM_MAX_PROP_VALCNT +
1395 i * DLADM_PROP_VAL_MAX;
1398 if (dladm_get_linkprop(handle, linkid, DLADM_PROP_VAL_PERSISTENT,
1399 prop_name, propvals, &valcnt) != DLADM_STATUS_OK) {
1400 goto done;
1403 status = dladm_set_linkprop(handle, linkid, prop_name, propvals,
1404 valcnt, dla->dla_flags | DLADM_OPT_ACTIVE);
1406 if (status != DLADM_STATUS_OK)
1407 dla->dla_status = status;
1409 done:
1410 if (buf != NULL)
1411 free(buf);
1413 return (DLADM_WALK_CONTINUE);
1416 /*ARGSUSED*/
1417 static int
1418 i_dladm_init_linkprop(dladm_handle_t handle, datalink_id_t linkid, void *arg)
1420 datalink_class_t class;
1421 dladm_status_t status;
1423 status = dladm_datalink_id2info(handle, linkid, NULL, &class, NULL,
1424 NULL, 0);
1425 if (status != DLADM_STATUS_OK)
1426 return (DLADM_WALK_TERMINATE);
1428 if ((class & (DATALINK_CLASS_VNIC | DATALINK_CLASS_VLAN)) == 0)
1429 (void) dladm_init_linkprop(handle, linkid, B_TRUE);
1431 return (DLADM_WALK_CONTINUE);
1434 dladm_status_t
1435 dladm_init_linkprop(dladm_handle_t handle, datalink_id_t linkid,
1436 boolean_t any_media)
1438 dladm_status_t status = DLADM_STATUS_OK;
1439 datalink_media_t dmedia;
1440 uint32_t media;
1441 dladm_linkprop_args_t *dla;
1443 dmedia = any_media ? DATALINK_ANY_MEDIATYPE : DL_WIFI;
1445 dla = malloc(sizeof (dladm_linkprop_args_t));
1446 if (dla == NULL)
1447 return (DLADM_STATUS_NOMEM);
1448 dla->dla_flags = DLADM_OPT_BOOT;
1449 dla->dla_status = DLADM_STATUS_OK;
1451 if (linkid == DATALINK_ALL_LINKID) {
1452 (void) dladm_walk_datalink_id(i_dladm_init_linkprop, handle,
1453 NULL, DATALINK_CLASS_ALL, dmedia, DLADM_OPT_PERSIST);
1454 } else if (any_media ||
1455 ((dladm_datalink_id2info(handle, linkid, NULL, NULL, &media, NULL,
1456 0) == DLADM_STATUS_OK) &&
1457 DATALINK_MEDIA_ACCEPTED(dmedia, media))) {
1458 (void) dladm_walk_linkprop(handle, linkid, (void *)dla,
1459 i_dladm_init_one_prop);
1460 status = dla->dla_status;
1462 free(dla);
1463 return (status);
1466 /* ARGSUSED */
1467 static dladm_status_t
1468 get_zone(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
1469 char **prop_val, uint_t *val_cnt, datalink_media_t media,
1470 uint_t flags, uint_t *perm_flags)
1472 char zone_name[ZONENAME_MAX];
1473 zoneid_t zid;
1474 dladm_status_t status;
1476 if (flags != 0)
1477 return (DLADM_STATUS_NOTSUP);
1479 status = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags,
1480 perm_flags, &zid, sizeof (zid));
1481 if (status != DLADM_STATUS_OK)
1482 return (status);
1484 *val_cnt = 1;
1485 if (zid != GLOBAL_ZONEID) {
1486 if (getzonenamebyid(zid, zone_name, sizeof (zone_name)) < 0) {
1487 return (dladm_errno2status(errno));
1490 (void) strncpy(*prop_val, zone_name, DLADM_PROP_VAL_MAX);
1491 } else {
1492 *prop_val[0] = '\0';
1495 return (DLADM_STATUS_OK);
1498 typedef int (*zone_get_devroot_t)(char *, char *, size_t);
1500 static int
1501 i_dladm_get_zone_dev(char *zone_name, char *dev, size_t devlen)
1503 char root[MAXPATHLEN];
1504 zone_get_devroot_t real_zone_get_devroot;
1505 void *dlhandle;
1506 void *sym;
1507 int ret;
1509 if ((dlhandle = dlopen("libzonecfg.so.1", RTLD_LAZY)) == NULL)
1510 return (-1);
1512 if ((sym = dlsym(dlhandle, "zone_get_devroot")) == NULL) {
1513 (void) dlclose(dlhandle);
1514 return (-1);
1517 real_zone_get_devroot = (zone_get_devroot_t)sym;
1519 if ((ret = real_zone_get_devroot(zone_name, root, sizeof (root))) == 0)
1520 (void) snprintf(dev, devlen, "%s%s", root, "/dev");
1521 (void) dlclose(dlhandle);
1522 return (ret);
1525 static dladm_status_t
1526 i_dladm_update_deventry(dladm_handle_t handle, zoneid_t zid,
1527 datalink_id_t linkid, boolean_t add)
1529 char path[MAXPATHLEN];
1530 char name[MAXLINKNAMELEN];
1531 di_prof_t prof = NULL;
1532 char zone_name[ZONENAME_MAX];
1533 dladm_status_t status;
1534 int ret;
1536 if (getzonenamebyid(zid, zone_name, sizeof (zone_name)) < 0)
1537 return (dladm_errno2status(errno));
1538 if (i_dladm_get_zone_dev(zone_name, path, sizeof (path)) != 0)
1539 return (dladm_errno2status(errno));
1540 if (di_prof_init(path, &prof) != 0)
1541 return (dladm_errno2status(errno));
1543 status = dladm_linkid2legacyname(handle, linkid, name, MAXLINKNAMELEN);
1544 if (status != DLADM_STATUS_OK)
1545 goto cleanup;
1547 if (add)
1548 ret = di_prof_add_dev(prof, name);
1549 else
1550 ret = di_prof_add_exclude(prof, name);
1552 if (ret != 0) {
1553 status = dladm_errno2status(errno);
1554 goto cleanup;
1557 if (di_prof_commit(prof) != 0)
1558 status = dladm_errno2status(errno);
1559 cleanup:
1560 if (prof)
1561 di_prof_fini(prof);
1563 return (status);
1566 /* ARGSUSED */
1567 static dladm_status_t
1568 set_zone(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
1569 val_desc_t *vdp, uint_t val_cnt, uint_t flags, datalink_media_t media)
1571 dladm_status_t status = DLADM_STATUS_OK;
1572 zoneid_t zid_old, zid_new;
1573 dld_ioc_zid_t *dzp;
1575 if (val_cnt != 1)
1576 return (DLADM_STATUS_BADVALCNT);
1578 dzp = (dld_ioc_zid_t *)vdp->vd_val;
1580 status = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags,
1581 NULL, &zid_old, sizeof (zid_old));
1582 if (status != DLADM_STATUS_OK)
1583 return (status);
1585 zid_new = dzp->diz_zid;
1586 if (zid_new == zid_old)
1587 return (DLADM_STATUS_OK);
1589 if ((status = set_public_prop(handle, pdp, linkid, vdp, val_cnt,
1590 flags, media)) != DLADM_STATUS_OK)
1591 return (status);
1594 * It is okay to fail to update the /dev entry (some vanity-named
1595 * links do not have a /dev entry).
1597 if (zid_old != GLOBAL_ZONEID) {
1598 (void) i_dladm_update_deventry(handle, zid_old, linkid,
1599 B_FALSE);
1601 if (zid_new != GLOBAL_ZONEID)
1602 (void) i_dladm_update_deventry(handle, zid_new, linkid, B_TRUE);
1604 return (DLADM_STATUS_OK);
1607 /* ARGSUSED */
1608 static dladm_status_t
1609 check_zone(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
1610 char **prop_val, uint_t *val_cntp, uint_t flags, val_desc_t **vdpp,
1611 datalink_media_t media)
1613 char *zone_name;
1614 zoneid_t zoneid;
1615 dladm_status_t status = DLADM_STATUS_OK;
1616 dld_ioc_zid_t *dzp;
1617 uint_t val_cnt = *val_cntp;
1618 val_desc_t *vdp = *vdpp;
1620 if (val_cnt != 1)
1621 return (DLADM_STATUS_BADVALCNT);
1623 dzp = malloc(sizeof (dld_ioc_zid_t));
1624 if (dzp == NULL)
1625 return (DLADM_STATUS_NOMEM);
1627 zone_name = (prop_val != NULL) ? *prop_val : GLOBAL_ZONENAME;
1628 if ((zoneid = getzoneidbyname(zone_name)) == -1) {
1629 status = DLADM_STATUS_BADVAL;
1630 goto done;
1633 if (zoneid != GLOBAL_ZONEID) {
1634 ushort_t flags;
1636 if (zone_getattr(zoneid, ZONE_ATTR_FLAGS, &flags,
1637 sizeof (flags)) < 0) {
1638 status = dladm_errno2status(errno);
1639 goto done;
1642 if (!(flags & ZF_NET_EXCL)) {
1643 status = DLADM_STATUS_BADVAL;
1644 goto done;
1648 (void) memset(dzp, 0, sizeof (dld_ioc_zid_t));
1650 dzp->diz_zid = zoneid;
1651 dzp->diz_linkid = linkid;
1653 vdp->vd_val = (uintptr_t)dzp;
1654 return (DLADM_STATUS_OK);
1655 done:
1656 free(dzp);
1657 return (status);
1660 /* ARGSUSED */
1661 static dladm_status_t
1662 get_maxbw(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
1663 char **prop_val, uint_t *val_cnt, datalink_media_t media,
1664 uint_t flags, uint_t *perm_flags)
1666 mac_resource_props_t mrp;
1667 dladm_status_t status;
1669 status = i_dladm_get_public_prop(handle, linkid, "resource", flags,
1670 perm_flags, &mrp, sizeof (mrp));
1671 if (status != DLADM_STATUS_OK)
1672 return (status);
1674 if ((mrp.mrp_mask & MRP_MAXBW) == 0) {
1675 *val_cnt = 0;
1676 return (DLADM_STATUS_OK);
1679 (void) dladm_bw2str(mrp.mrp_maxbw, prop_val[0]);
1680 *val_cnt = 1;
1681 return (DLADM_STATUS_OK);
1684 /* ARGSUSED */
1685 static dladm_status_t
1686 check_maxbw(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
1687 char **prop_val, uint_t *val_cntp, uint_t flags, val_desc_t **vdpp,
1688 datalink_media_t media)
1690 uint64_t *maxbw;
1691 dladm_status_t status = DLADM_STATUS_OK;
1692 uint_t val_cnt = *val_cntp;
1693 val_desc_t *vdp = *vdpp;
1695 if (val_cnt != 1)
1696 return (DLADM_STATUS_BADVALCNT);
1698 maxbw = malloc(sizeof (uint64_t));
1699 if (maxbw == NULL)
1700 return (DLADM_STATUS_NOMEM);
1702 status = dladm_str2bw(*prop_val, maxbw);
1703 if (status != DLADM_STATUS_OK) {
1704 free(maxbw);
1705 return (status);
1708 if ((*maxbw < MRP_MAXBW_MINVAL) && (*maxbw != 0)) {
1709 free(maxbw);
1710 return (DLADM_STATUS_MINMAXBW);
1713 vdp->vd_val = (uintptr_t)maxbw;
1714 return (DLADM_STATUS_OK);
1717 /* ARGSUSED */
1718 dladm_status_t
1719 extract_maxbw(val_desc_t *vdp, uint_t cnt, void *arg)
1721 mac_resource_props_t *mrp = arg;
1723 if (vdp->vd_val == RESET_VAL) {
1724 mrp->mrp_maxbw = MRP_MAXBW_RESETVAL;
1725 } else {
1726 bcopy((char *)vdp->vd_val, &mrp->mrp_maxbw, sizeof (uint64_t));
1728 mrp->mrp_mask |= MRP_MAXBW;
1730 return (DLADM_STATUS_OK);
1733 /* ARGSUSED */
1734 static dladm_status_t
1735 get_cpus(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
1736 char **prop_val, uint_t *val_cnt, datalink_media_t media,
1737 uint_t flags, uint_t *perm_flags)
1739 dladm_status_t status;
1740 mac_resource_props_t mrp;
1741 mac_propval_range_t *pv_range;
1742 int err;
1744 if (strcmp(pdp->pd_name, "cpus-effective") == 0) {
1745 status = i_dladm_get_public_prop(handle, linkid,
1746 "resource-effective", flags, perm_flags, &mrp,
1747 sizeof (mrp));
1748 } else {
1749 status = i_dladm_get_public_prop(handle, linkid,
1750 "resource", flags, perm_flags, &mrp, sizeof (mrp));
1753 if (status != DLADM_STATUS_OK)
1754 return (status);
1756 if (mrp.mrp_ncpus > *val_cnt)
1757 return (DLADM_STATUS_TOOSMALL);
1759 if (mrp.mrp_ncpus == 0) {
1760 *val_cnt = 0;
1761 return (DLADM_STATUS_OK);
1764 /* Sort CPU list and convert it to a mac_propval_range */
1765 status = dladm_list2range(mrp.mrp_cpu, mrp.mrp_ncpus,
1766 MAC_PROPVAL_UINT32, &pv_range);
1767 if (status != DLADM_STATUS_OK)
1768 return (status);
1770 /* Write CPU ranges and individual CPUs */
1771 err = dladm_range2strs(pv_range, prop_val);
1772 if (err != 0) {
1773 free(pv_range);
1774 return (dladm_errno2status(err));
1777 *val_cnt = pv_range->mpr_count;
1778 free(pv_range);
1780 return (DLADM_STATUS_OK);
1783 /* ARGSUSED */
1784 static dladm_status_t
1785 check_cpus(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
1786 char **prop_val, uint_t *val_cntp, uint_t flags, val_desc_t **vdpp,
1787 datalink_media_t media)
1789 int i, j, rc;
1790 long nproc = sysconf(_SC_NPROCESSORS_CONF);
1791 mac_resource_props_t mrp;
1792 mac_propval_range_t *pv_range;
1793 uint_t perm_flags;
1794 uint32_t ncpus;
1795 uint32_t *cpus = mrp.mrp_cpu;
1796 val_desc_t *vdp = *vdpp;
1797 val_desc_t *newvdp;
1798 uint_t val_cnt = *val_cntp;
1799 dladm_status_t status = DLADM_STATUS_OK;
1801 /* Get the current pool property */
1802 status = i_dladm_get_public_prop(handle, linkid, "resource", 0,
1803 &perm_flags, &mrp, sizeof (mrp));
1805 if (status == DLADM_STATUS_OK) {
1806 /* Can't set cpus if a pool is set */
1807 if (strlen(mrp.mrp_pool) != 0)
1808 return (DLADM_STATUS_POOLCPU);
1811 /* Read ranges and convert to mac_propval_range */
1812 status = dladm_strs2range(prop_val, val_cnt, MAC_PROPVAL_UINT32,
1813 &pv_range);
1814 if (status != DLADM_STATUS_OK)
1815 goto done1;
1817 /* Convert mac_propval_range to a single CPU list */
1818 ncpus = MRP_NCPUS;
1819 status = dladm_range2list(pv_range, cpus, &ncpus);
1820 if (status != DLADM_STATUS_OK)
1821 goto done1;
1824 * If a range of CPUs was entered, update value count and reallocate
1825 * the array of val_desc_t's. The array allocated was sized for
1826 * indvidual elements, but needs to be reallocated to accomodate the
1827 * expanded list of CPUs.
1829 if (val_cnt < ncpus) {
1830 newvdp = calloc(*val_cntp, sizeof (val_desc_t));
1831 if (newvdp == NULL) {
1832 status = DLADM_STATUS_NOMEM;
1833 goto done1;
1835 vdp = newvdp;
1838 /* Check if all CPUs in the list are online */
1839 for (i = 0; i < ncpus; i++) {
1840 if (cpus[i] >= nproc) {
1841 status = DLADM_STATUS_BADCPUID;
1842 goto done2;
1845 rc = p_online(cpus[i], P_STATUS);
1846 if (rc < 1) {
1847 status = DLADM_STATUS_CPUERR;
1848 goto done2;
1851 if (rc != P_ONLINE) {
1852 status = DLADM_STATUS_CPUNOTONLINE;
1853 goto done2;
1856 vdp[i].vd_val = (uintptr_t)cpus[i];
1859 /* Check for duplicate CPUs */
1860 for (i = 0; i < *val_cntp; i++) {
1861 for (j = 0; j < *val_cntp; j++) {
1862 if (i != j && vdp[i].vd_val == vdp[j].vd_val) {
1863 status = DLADM_STATUS_BADVAL;
1864 goto done2;
1869 /* Update *val_cntp and *vdpp if everything was OK */
1870 if (val_cnt < ncpus) {
1871 *val_cntp = ncpus;
1872 free(*vdpp);
1873 *vdpp = newvdp;
1876 status = DLADM_STATUS_OK;
1877 goto done1;
1879 done2:
1880 free(newvdp);
1881 done1:
1882 free(pv_range);
1883 return (status);
1886 /* ARGSUSED */
1887 dladm_status_t
1888 extract_cpus(val_desc_t *vdp, uint_t cnt, void *arg)
1890 mac_resource_props_t *mrp = arg;
1891 int i;
1893 if (vdp[0].vd_val == RESET_VAL) {
1894 bzero(&mrp->mrp_cpus, sizeof (mac_cpus_t));
1895 mrp->mrp_mask |= MRP_CPUS;
1896 return (DLADM_STATUS_OK);
1899 for (i = 0; i < cnt; i++)
1900 mrp->mrp_cpu[i] = (uint32_t)vdp[i].vd_val;
1902 mrp->mrp_ncpus = cnt;
1903 mrp->mrp_mask |= (MRP_CPUS|MRP_CPUS_USERSPEC);
1904 mrp->mrp_fanout_mode = MCM_CPUS;
1905 mrp->mrp_rx_intr_cpu = -1;
1907 return (DLADM_STATUS_OK);
1911 * Get the pool datalink property from the kernel. This is used
1912 * for both the user specified pool and effective pool properties.
1914 /* ARGSUSED */
1915 static dladm_status_t
1916 get_pool(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
1917 char **prop_val, uint_t *val_cnt, datalink_media_t media,
1918 uint_t flags, uint_t *perm_flags)
1920 mac_resource_props_t mrp;
1921 dladm_status_t status;
1923 if (strcmp(pdp->pd_name, "pool-effective") == 0) {
1924 status = i_dladm_get_public_prop(handle, linkid,
1925 "resource-effective", flags, perm_flags, &mrp,
1926 sizeof (mrp));
1927 } else {
1928 status = i_dladm_get_public_prop(handle, linkid,
1929 "resource", flags, perm_flags, &mrp, sizeof (mrp));
1932 if (status != DLADM_STATUS_OK)
1933 return (status);
1935 if (strlen(mrp.mrp_pool) == 0) {
1936 (*prop_val)[0] = '\0';
1937 } else {
1938 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX,
1939 "%s", mrp.mrp_pool);
1941 *val_cnt = 1;
1943 return (DLADM_STATUS_OK);
1946 /* ARGSUSED */
1947 static dladm_status_t
1948 check_pool(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
1949 char **prop_val, uint_t *val_cntp, uint_t flags, val_desc_t **vdpp,
1950 datalink_media_t media)
1952 pool_conf_t *poolconf;
1953 pool_t *pool;
1954 mac_resource_props_t mrp;
1955 dladm_status_t status;
1956 uint_t perm_flags;
1957 char *poolname;
1958 val_desc_t *vdp = *vdpp;
1960 /* Get the current cpus property */
1961 status = i_dladm_get_public_prop(handle, linkid, "resource", 0,
1962 &perm_flags, &mrp, sizeof (mrp));
1964 if (status == DLADM_STATUS_OK) {
1965 /* Can't set pool if cpus are set */
1966 if (mrp.mrp_ncpus != 0)
1967 return (DLADM_STATUS_POOLCPU);
1970 poolname = malloc(sizeof (mrp.mrp_pool));
1971 if (poolname == NULL)
1972 return (DLADM_STATUS_NOMEM);
1974 /* Check for pool's availability if not booting */
1975 if ((flags & DLADM_OPT_BOOT) == 0) {
1977 /* Allocate and open pool configuration */
1978 if ((poolconf = pool_conf_alloc()) == NULL)
1979 return (DLADM_STATUS_BADVAL);
1981 if (pool_conf_open(poolconf, pool_dynamic_location(), PO_RDONLY)
1982 != PO_SUCCESS) {
1983 pool_conf_free(poolconf);
1984 return (DLADM_STATUS_BADVAL);
1987 /* Look for pool name */
1988 if ((pool = pool_get_pool(poolconf, *prop_val)) == NULL) {
1989 pool_conf_free(poolconf);
1990 return (DLADM_STATUS_BADVAL);
1993 pool_conf_free(poolconf);
1994 free(pool);
1997 (void) strlcpy(poolname, *prop_val, sizeof (mrp.mrp_pool));
1998 vdp->vd_val = (uintptr_t)poolname;
2000 return (DLADM_STATUS_OK);
2003 /* ARGSUSED */
2004 dladm_status_t
2005 extract_pool(val_desc_t *vdp, uint_t cnt, void *arg)
2007 mac_resource_props_t *mrp = (mac_resource_props_t *)arg;
2009 if (vdp->vd_val == RESET_VAL) {
2010 bzero(&mrp->mrp_pool, sizeof (mrp->mrp_pool));
2011 mrp->mrp_mask |= MRP_POOL;
2012 return (DLADM_STATUS_OK);
2015 (void) strlcpy(mrp->mrp_pool, (char *)vdp->vd_val,
2016 sizeof (mrp->mrp_pool));
2017 mrp->mrp_mask |= MRP_POOL;
2019 * Use MCM_CPUS since the fanout count is not user specified
2020 * and will be determined by the cpu list generated from the
2021 * pool.
2023 mrp->mrp_fanout_mode = MCM_CPUS;
2025 return (DLADM_STATUS_OK);
2028 /* ARGSUSED */
2029 static dladm_status_t
2030 get_priority(dladm_handle_t handle, prop_desc_t *pdp,
2031 datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
2032 datalink_media_t media, uint_t flags, uint_t *perm_flags)
2034 mac_resource_props_t mrp;
2035 mac_priority_level_t pri;
2036 dladm_status_t status;
2038 status = i_dladm_get_public_prop(handle, linkid, "resource", flags,
2039 perm_flags, &mrp, sizeof (mrp));
2040 if (status != DLADM_STATUS_OK)
2041 return (status);
2043 pri = ((mrp.mrp_mask & MRP_PRIORITY) == 0) ? MPL_HIGH :
2044 mrp.mrp_priority;
2046 (void) dladm_pri2str(pri, prop_val[0]);
2047 *val_cnt = 1;
2048 return (DLADM_STATUS_OK);
2051 /* ARGSUSED */
2052 dladm_status_t
2053 extract_priority(val_desc_t *vdp, uint_t cnt, void *arg)
2055 mac_resource_props_t *mrp = arg;
2057 if (cnt != 1)
2058 return (DLADM_STATUS_BADVAL);
2060 mrp->mrp_priority = (mac_priority_level_t)vdp->vd_val;
2061 mrp->mrp_mask |= MRP_PRIORITY;
2063 return (DLADM_STATUS_OK);
2067 * Determines the size of the structure that needs to be sent to drivers
2068 * for retrieving the property range values.
2070 static int
2071 i_dladm_range_size(mac_propval_range_t *r, size_t *sz, uint_t *rcount)
2073 uint_t count = r->mpr_count;
2075 *sz = sizeof (mac_propval_range_t);
2076 *rcount = count;
2077 --count;
2079 switch (r->mpr_type) {
2080 case MAC_PROPVAL_UINT32:
2081 *sz += (count * sizeof (mac_propval_uint32_range_t));
2082 return (0);
2083 default:
2084 break;
2086 *sz = 0;
2087 *rcount = 0;
2088 return (EINVAL);
2092 /* ARGSUSED */
2093 static dladm_status_t
2094 check_rings(dladm_handle_t handle, prop_desc_t *pdp,
2095 datalink_id_t linkid, char **prop_val, uint_t *val_cntp, uint_t flags,
2096 val_desc_t **vp, datalink_media_t media)
2098 uint_t val_cnt = *val_cntp;
2099 val_desc_t *v = *vp;
2101 if (val_cnt != 1)
2102 return (DLADM_STATUS_BADVAL);
2103 if (strncasecmp(prop_val[0], "hw", strlen("hw")) == 0) {
2104 v->vd_val = UNSPEC_VAL;
2105 } else if (strncasecmp(prop_val[0], "sw", strlen("sw")) == 0) {
2106 v->vd_val = 0;
2107 } else {
2108 v->vd_val = strtoul(prop_val[0], NULL, 0);
2109 if (v->vd_val == 0)
2110 return (DLADM_STATUS_BADVAL);
2112 return (DLADM_STATUS_OK);
2115 /* ARGSUSED */
2116 static dladm_status_t
2117 get_rings_range(dladm_handle_t handle, prop_desc_t *pdp,
2118 datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
2119 datalink_media_t media, uint_t flags, uint_t *perm_flags)
2121 dld_ioc_macprop_t *dip;
2122 dladm_status_t status = DLADM_STATUS_OK;
2123 mac_propval_range_t *rangep;
2124 size_t sz;
2125 mac_propval_uint32_range_t *ur;
2127 sz = sizeof (mac_propval_range_t);
2129 if ((dip = i_dladm_buf_alloc_by_name(sz, linkid, pdp->pd_name, flags,
2130 &status)) == NULL)
2131 return (status);
2133 status = i_dladm_macprop(handle, dip, B_FALSE);
2134 if (status != DLADM_STATUS_OK)
2135 return (status);
2137 rangep = (mac_propval_range_t *)(void *)&dip->pr_val;
2138 *val_cnt = 1;
2139 ur = &rangep->mpr_range_uint32[0];
2140 /* This is the case where the dev doesn't have any rings/groups */
2141 if (rangep->mpr_count == 0) {
2142 (*prop_val)[0] = '\0';
2144 * This is the case where the dev supports rings, but static
2145 * grouping.
2147 } else if (ur->mpur_min == ur->mpur_max &&
2148 ur->mpur_max == 0) {
2149 (void) snprintf(prop_val[0], DLADM_PROP_VAL_MAX, "sw,hw");
2151 * This is the case where the dev supports rings and dynamic
2152 * grouping, but has only one value (say 2 rings and 2 groups).
2154 } else if (ur->mpur_min == ur->mpur_max) {
2155 (void) snprintf(prop_val[0], DLADM_PROP_VAL_MAX, "sw,hw,%d",
2156 ur->mpur_min);
2158 * This is the case where the dev supports rings and dynamic
2159 * grouping and has a range of rings.
2161 } else {
2162 (void) snprintf(prop_val[0], DLADM_PROP_VAL_MAX,
2163 "sw,hw,<%ld-%ld>", ur->mpur_min, ur->mpur_max);
2165 free(dip);
2166 return (status);
2170 /* ARGSUSED */
2171 static dladm_status_t
2172 get_rxrings(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
2173 char **prop_val, uint_t *val_cnt, datalink_media_t media,
2174 uint_t flags, uint_t *perm_flags)
2176 mac_resource_props_t mrp;
2177 dladm_status_t status;
2178 uint32_t nrings = 0;
2181 * Get the number of (effective-)rings from the resource property.
2183 if (strcmp(pdp->pd_name, "rxrings-effective") == 0) {
2184 status = i_dladm_get_public_prop(handle, linkid,
2185 "resource-effective", flags, perm_flags, &mrp,
2186 sizeof (mrp));
2187 } else {
2189 * Get the permissions from the "rxrings" property.
2191 status = i_dladm_get_public_prop(handle, linkid, "rxrings",
2192 flags, perm_flags, NULL, 0);
2193 if (status != DLADM_STATUS_OK)
2194 return (status);
2196 status = i_dladm_get_public_prop(handle, linkid,
2197 "resource", flags, NULL, &mrp, sizeof (mrp));
2200 if (status != DLADM_STATUS_OK)
2201 return (status);
2203 if ((mrp.mrp_mask & MRP_RX_RINGS) == 0) {
2204 *val_cnt = 0;
2205 return (DLADM_STATUS_OK);
2207 nrings = mrp.mrp_nrxrings;
2208 *val_cnt = 1;
2209 if (mrp.mrp_mask & MRP_RXRINGS_UNSPEC)
2210 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "hw");
2211 else if (nrings == 0)
2212 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "sw");
2213 else
2214 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "%ld", nrings);
2215 return (DLADM_STATUS_OK);
2218 /* ARGSUSED */
2219 dladm_status_t
2220 extract_rxrings(val_desc_t *vdp, uint_t cnt, void *arg)
2222 mac_resource_props_t *mrp = (mac_resource_props_t *)arg;
2224 mrp->mrp_nrxrings = 0;
2225 if (vdp->vd_val == RESET_VAL)
2226 mrp->mrp_mask = MRP_RINGS_RESET;
2227 else if (vdp->vd_val == UNSPEC_VAL)
2228 mrp->mrp_mask = MRP_RXRINGS_UNSPEC;
2229 else
2230 mrp->mrp_nrxrings = vdp->vd_val;
2231 mrp->mrp_mask |= MRP_RX_RINGS;
2233 return (DLADM_STATUS_OK);
2236 /* ARGSUSED */
2237 static dladm_status_t
2238 get_txrings(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
2239 char **prop_val, uint_t *val_cnt, datalink_media_t media,
2240 uint_t flags, uint_t *perm_flags)
2242 mac_resource_props_t mrp;
2243 dladm_status_t status;
2244 uint32_t nrings = 0;
2248 * Get the number of (effective-)rings from the resource property.
2250 if (strcmp(pdp->pd_name, "txrings-effective") == 0) {
2251 status = i_dladm_get_public_prop(handle, linkid,
2252 "resource-effective", flags, perm_flags, &mrp,
2253 sizeof (mrp));
2254 } else {
2256 * Get the permissions from the "txrings" property.
2258 status = i_dladm_get_public_prop(handle, linkid, "txrings",
2259 flags, perm_flags, NULL, 0);
2260 if (status != DLADM_STATUS_OK)
2261 return (status);
2264 * Get the number of rings from the "resource" property.
2266 status = i_dladm_get_public_prop(handle, linkid, "resource",
2267 flags, NULL, &mrp, sizeof (mrp));
2270 if (status != DLADM_STATUS_OK)
2271 return (status);
2273 if ((mrp.mrp_mask & MRP_TX_RINGS) == 0) {
2274 *val_cnt = 0;
2275 return (DLADM_STATUS_OK);
2277 nrings = mrp.mrp_ntxrings;
2278 *val_cnt = 1;
2279 if (mrp.mrp_mask & MRP_TXRINGS_UNSPEC)
2280 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "hw");
2281 else if (nrings == 0)
2282 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "sw");
2283 else
2284 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "%ld", nrings);
2285 return (DLADM_STATUS_OK);
2288 /* ARGSUSED */
2289 dladm_status_t
2290 extract_txrings(val_desc_t *vdp, uint_t cnt, void *arg)
2292 mac_resource_props_t *mrp = (mac_resource_props_t *)arg;
2294 mrp->mrp_ntxrings = 0;
2295 if (vdp->vd_val == RESET_VAL)
2296 mrp->mrp_mask = MRP_RINGS_RESET;
2297 else if (vdp->vd_val == UNSPEC_VAL)
2298 mrp->mrp_mask = MRP_TXRINGS_UNSPEC;
2299 else
2300 mrp->mrp_ntxrings = vdp->vd_val;
2301 mrp->mrp_mask |= MRP_TX_RINGS;
2303 return (DLADM_STATUS_OK);
2306 /* ARGSUSED */
2307 static dladm_status_t
2308 get_cntavail(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
2309 char **prop_val, uint_t *val_cnt, datalink_media_t media, uint_t flags,
2310 uint_t *perm_flags)
2312 if (flags & DLD_PROP_DEFAULT)
2313 return (DLADM_STATUS_NOTDEFINED);
2315 return (get_uint32(handle, pdp, linkid, prop_val, val_cnt, media,
2316 flags, perm_flags));
2319 /* ARGSUSED */
2320 static dladm_status_t
2321 set_resource(dladm_handle_t handle, prop_desc_t *pdp,
2322 datalink_id_t linkid, val_desc_t *vdp, uint_t val_cnt,
2323 uint_t flags, datalink_media_t media)
2325 mac_resource_props_t mrp;
2326 dladm_status_t status = DLADM_STATUS_OK;
2327 dld_ioc_macprop_t *dip;
2328 int i;
2330 bzero(&mrp, sizeof (mac_resource_props_t));
2331 dip = i_dladm_buf_alloc_by_name(0, linkid, "resource",
2332 flags, &status);
2334 if (dip == NULL)
2335 return (status);
2337 for (i = 0; i < DLADM_MAX_RSRC_PROP; i++) {
2338 resource_prop_t *rp = &rsrc_prop_table[i];
2340 if (strcmp(pdp->pd_name, rp->rp_name) != 0)
2341 continue;
2343 status = rp->rp_extract(vdp, val_cnt, &mrp);
2344 if (status != DLADM_STATUS_OK)
2345 goto done;
2347 break;
2350 (void) memcpy(dip->pr_val, &mrp, dip->pr_valsize);
2351 status = i_dladm_macprop(handle, dip, B_TRUE);
2353 done:
2354 free(dip);
2355 return (status);
2358 /* ARGSUSED */
2359 static dladm_status_t
2360 get_protection(dladm_handle_t handle, prop_desc_t *pdp,
2361 datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
2362 datalink_media_t media, uint_t flags, uint_t *perm_flags)
2364 mac_resource_props_t mrp;
2365 mac_protect_t *p;
2366 dladm_status_t status;
2367 uint32_t i, cnt = 0, setbits[32];
2369 status = i_dladm_get_public_prop(handle, linkid, "resource", flags,
2370 perm_flags, &mrp, sizeof (mrp));
2371 if (status != DLADM_STATUS_OK)
2372 return (status);
2374 p = &mrp.mrp_protect;
2375 if ((mrp.mrp_mask & MRP_PROTECT) == 0) {
2376 *val_cnt = 0;
2377 return (DLADM_STATUS_OK);
2379 dladm_find_setbits32(p->mp_types, setbits, &cnt);
2380 if (cnt > *val_cnt)
2381 return (DLADM_STATUS_BADVALCNT);
2383 for (i = 0; i < cnt; i++)
2384 (void) dladm_protect2str(setbits[i], prop_val[i]);
2386 *val_cnt = cnt;
2387 return (DLADM_STATUS_OK);
2390 /* ARGSUSED */
2391 static dladm_status_t
2392 get_allowedips(dladm_handle_t handle, prop_desc_t *pdp,
2393 datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
2394 datalink_media_t media, uint_t flags, uint_t *perm_flags)
2396 mac_resource_props_t mrp;
2397 mac_protect_t *p;
2398 dladm_status_t status;
2399 int i;
2401 status = i_dladm_get_public_prop(handle, linkid, "resource", flags,
2402 perm_flags, &mrp, sizeof (mrp));
2403 if (status != DLADM_STATUS_OK)
2404 return (status);
2406 p = &mrp.mrp_protect;
2407 if (p->mp_ipaddrcnt == 0) {
2408 *val_cnt = 0;
2409 return (DLADM_STATUS_OK);
2411 if (p->mp_ipaddrcnt > *val_cnt)
2412 return (DLADM_STATUS_BADVALCNT);
2414 for (i = 0; i < p->mp_ipaddrcnt; i++) {
2415 int len;
2416 if (p->mp_ipaddrs[i].ip_version == IPV4_VERSION) {
2417 ipaddr_t v4addr;
2419 v4addr = V4_PART_OF_V6(p->mp_ipaddrs[i].ip_addr);
2420 (void) dladm_ipv4addr2str(&v4addr, prop_val[i]);
2421 } else {
2422 (void) dladm_ipv6addr2str(&p->mp_ipaddrs[i].ip_addr,
2423 prop_val[i]);
2425 len = strlen(prop_val[i]);
2426 (void) sprintf(prop_val[i] + len, "/%d",
2427 p->mp_ipaddrs[i].ip_netmask);
2429 *val_cnt = p->mp_ipaddrcnt;
2430 return (DLADM_STATUS_OK);
2433 dladm_status_t
2434 extract_protection(val_desc_t *vdp, uint_t cnt, void *arg)
2436 mac_resource_props_t *mrp = arg;
2437 uint32_t types = 0;
2438 int i;
2440 for (i = 0; i < cnt; i++)
2441 types |= (uint32_t)vdp[i].vd_val;
2443 mrp->mrp_protect.mp_types = types;
2444 mrp->mrp_mask |= MRP_PROTECT;
2445 return (DLADM_STATUS_OK);
2448 dladm_status_t
2449 extract_allowedips(val_desc_t *vdp, uint_t cnt, void *arg)
2451 mac_resource_props_t *mrp = arg;
2452 mac_protect_t *p = &mrp->mrp_protect;
2453 int i;
2455 if (vdp->vd_val == 0) {
2456 cnt = (uint_t)-1;
2457 } else {
2458 for (i = 0; i < cnt; i++) {
2459 bcopy((void *)vdp[i].vd_val, &p->mp_ipaddrs[i],
2460 sizeof (mac_ipaddr_t));
2463 p->mp_ipaddrcnt = cnt;
2464 mrp->mrp_mask |= MRP_PROTECT;
2465 return (DLADM_STATUS_OK);
2468 static dladm_status_t
2469 check_single_ip(char *buf, mac_ipaddr_t *addr)
2471 dladm_status_t status;
2472 ipaddr_t v4addr;
2473 in6_addr_t v6addr;
2474 boolean_t isv4 = B_TRUE;
2475 char *p;
2476 uint32_t mask = 0;
2479 * If the IP address is in CIDR format, parse the bits component
2480 * seperately. An address in this style will be used to indicate an
2481 * entire subnet, so it must be a network number with no host address.
2483 if ((p = strchr(buf, '/')) != NULL) {
2484 char *end = NULL;
2486 *p++ = '\0';
2487 if (!isdigit(*p))
2488 return (DLADM_STATUS_INVALID_IP);
2489 mask = strtol(p, &end, 10);
2490 if (end != NULL && *end != '\0')
2491 return (DLADM_STATUS_INVALID_IP);
2492 if (mask > 128|| mask < 1)
2493 return (DLADM_STATUS_INVALID_IP);
2496 status = dladm_str2ipv4addr(buf, &v4addr);
2497 if (status == DLADM_STATUS_INVALID_IP) {
2498 status = dladm_str2ipv6addr(buf, &v6addr);
2499 if (status == DLADM_STATUS_OK)
2500 isv4 = B_FALSE;
2502 if (status != DLADM_STATUS_OK)
2503 return (status);
2505 if (isv4) {
2506 if (v4addr == INADDR_ANY)
2507 return (DLADM_STATUS_INVALID_IP);
2509 IN6_IPADDR_TO_V4MAPPED(v4addr, &addr->ip_addr);
2510 addr->ip_version = IPV4_VERSION;
2511 if (p != NULL) {
2512 uint32_t smask;
2515 * Validate the netmask is in the proper range for v4
2517 if (mask > 32 || mask < 1)
2518 return (DLADM_STATUS_INVALID_IP);
2521 * We have a CIDR style address, confirm that only the
2522 * network number is set.
2524 smask = 0xFFFFFFFFu << (32 - mask);
2525 if (htonl(v4addr) & ~smask)
2526 return (DLADM_STATUS_INVALID_IP);
2527 } else {
2528 mask = 32;
2530 addr->ip_netmask = mask;
2531 } else {
2532 if (IN6_IS_ADDR_UNSPECIFIED(&v6addr))
2533 return (DLADM_STATUS_INVALID_IP);
2535 if (IN6_IS_ADDR_V4MAPPED_ANY(&v6addr))
2536 return (DLADM_STATUS_INVALID_IP);
2538 if (p != NULL) {
2539 int i, off, high;
2542 * Note that the address in our buffer is stored in
2543 * network byte order.
2545 off = 0;
2546 for (i = 3; i >= 0; i--) {
2547 high = ffsl(ntohl(v6addr._S6_un._S6_u32[i]));
2548 if (high != 0)
2549 break;
2550 off += 32;
2552 off += high;
2553 if (128 - off >= mask)
2554 return (DLADM_STATUS_INVALID_IP);
2555 } else {
2556 mask = 128;
2559 addr->ip_addr = v6addr;
2560 addr->ip_version = IPV6_VERSION;
2561 addr->ip_netmask = mask;
2563 return (DLADM_STATUS_OK);
2566 /* ARGSUSED */
2567 static dladm_status_t
2568 check_allowedips(dladm_handle_t handle, prop_desc_t *pdp,
2569 datalink_id_t linkid, char **prop_val, uint_t *val_cntp, uint_t flags,
2570 val_desc_t **vdpp, datalink_media_t media)
2572 dladm_status_t status;
2573 mac_ipaddr_t *addr;
2574 int i;
2575 uint_t val_cnt = *val_cntp;
2576 val_desc_t *vdp = *vdpp;
2578 if (val_cnt > MPT_MAXIPADDR)
2579 return (DLADM_STATUS_BADVALCNT);
2581 for (i = 0; i < val_cnt; i++) {
2582 if ((addr = calloc(1, sizeof (mac_ipaddr_t))) == NULL) {
2583 status = DLADM_STATUS_NOMEM;
2584 goto fail;
2586 vdp[i].vd_val = (uintptr_t)addr;
2588 status = check_single_ip(prop_val[i], addr);
2589 if (status != DLADM_STATUS_OK)
2590 goto fail;
2592 return (DLADM_STATUS_OK);
2594 fail:
2595 for (i = 0; i < val_cnt; i++) {
2596 free((void *)vdp[i].vd_val);
2597 vdp[i].vd_val = NULL;
2599 return (status);
2602 static void
2603 dladm_cid2str(mac_dhcpcid_t *cid, char *buf)
2605 char tmp_buf[DLADM_STRSIZE];
2606 uint_t hexlen;
2608 switch (cid->dc_form) {
2609 case CIDFORM_TYPED: {
2610 uint16_t duidtype, hwtype;
2611 uint32_t timestamp, ennum;
2612 char *lladdr;
2614 if (cid->dc_len < sizeof (duidtype))
2615 goto fail;
2617 bcopy(cid->dc_id, &duidtype, sizeof (duidtype));
2618 duidtype = ntohs(duidtype);
2619 switch (duidtype) {
2620 case DHCPV6_DUID_LLT: {
2621 duid_llt_t llt;
2623 if (cid->dc_len < sizeof (llt))
2624 goto fail;
2626 bcopy(cid->dc_id, &llt, sizeof (llt));
2627 hwtype = ntohs(llt.dllt_hwtype);
2628 timestamp = ntohl(llt.dllt_time);
2629 lladdr = _link_ntoa(cid->dc_id + sizeof (llt),
2630 NULL, cid->dc_len - sizeof (llt), IFT_OTHER);
2631 if (lladdr == NULL)
2632 goto fail;
2634 (void) snprintf(buf, DLADM_STRSIZE, "%d.%d.%d.%s",
2635 duidtype, hwtype, timestamp, lladdr);
2636 free(lladdr);
2637 break;
2639 case DHCPV6_DUID_EN: {
2640 duid_en_t en;
2642 if (cid->dc_len < sizeof (en))
2643 goto fail;
2645 bcopy(cid->dc_id, &en, sizeof (en));
2646 ennum = DHCPV6_GET_ENTNUM(&en);
2647 hexlen = sizeof (tmp_buf);
2648 if (octet_to_hexascii(cid->dc_id + sizeof (en),
2649 cid->dc_len - sizeof (en), tmp_buf, &hexlen) != 0)
2650 goto fail;
2652 (void) snprintf(buf, DLADM_STRSIZE, "%d.%d.%s",
2653 duidtype, ennum, tmp_buf);
2654 break;
2656 case DHCPV6_DUID_LL: {
2657 duid_ll_t ll;
2659 if (cid->dc_len < sizeof (ll))
2660 goto fail;
2662 bcopy(cid->dc_id, &ll, sizeof (ll));
2663 hwtype = ntohs(ll.dll_hwtype);
2664 lladdr = _link_ntoa(cid->dc_id + sizeof (ll),
2665 NULL, cid->dc_len - sizeof (ll), IFT_OTHER);
2666 if (lladdr == NULL)
2667 goto fail;
2669 (void) snprintf(buf, DLADM_STRSIZE, "%d.%d.%s",
2670 duidtype, hwtype, lladdr);
2671 free(lladdr);
2672 break;
2674 default: {
2675 hexlen = sizeof (tmp_buf);
2676 if (octet_to_hexascii(cid->dc_id + sizeof (duidtype),
2677 cid->dc_len - sizeof (duidtype),
2678 tmp_buf, &hexlen) != 0)
2679 goto fail;
2681 (void) snprintf(buf, DLADM_STRSIZE, "%d.%s",
2682 duidtype, tmp_buf);
2685 break;
2687 case CIDFORM_HEX: {
2688 hexlen = sizeof (tmp_buf);
2689 if (octet_to_hexascii(cid->dc_id, cid->dc_len,
2690 tmp_buf, &hexlen) != 0)
2691 goto fail;
2693 (void) snprintf(buf, DLADM_STRSIZE, "0x%s", tmp_buf);
2694 break;
2696 case CIDFORM_STR: {
2697 int i;
2699 for (i = 0; i < cid->dc_len; i++) {
2700 if (!isprint(cid->dc_id[i]))
2701 goto fail;
2703 (void) snprintf(buf, DLADM_STRSIZE, "%s", cid->dc_id);
2704 break;
2706 default:
2707 goto fail;
2709 return;
2711 fail:
2712 (void) snprintf(buf, DLADM_STRSIZE, "<unknown>");
2715 static dladm_status_t
2716 dladm_str2cid(char *buf, mac_dhcpcid_t *cid)
2718 char *ptr = buf;
2719 char tmp_buf[DLADM_STRSIZE];
2720 uint_t hexlen, cidlen;
2722 bzero(cid, sizeof (*cid));
2723 if (isdigit(*ptr) &&
2724 ptr[strspn(ptr, "0123456789")] == '.') {
2725 char *cp;
2726 ulong_t duidtype;
2727 ulong_t subtype;
2728 ulong_t timestamp;
2729 uchar_t *lladdr;
2730 int addrlen;
2732 errno = 0;
2733 duidtype = strtoul(ptr, &cp, 0);
2734 if (ptr == cp || errno != 0 || *cp != '.' ||
2735 duidtype > USHRT_MAX)
2736 return (DLADM_STATUS_BADARG);
2737 ptr = cp + 1;
2739 if (duidtype != 0 && duidtype <= DHCPV6_DUID_LL) {
2740 errno = 0;
2741 subtype = strtoul(ptr, &cp, 0);
2742 if (ptr == cp || errno != 0 || *cp != '.')
2743 return (DLADM_STATUS_BADARG);
2744 ptr = cp + 1;
2746 switch (duidtype) {
2747 case DHCPV6_DUID_LLT: {
2748 duid_llt_t llt;
2750 errno = 0;
2751 timestamp = strtoul(ptr, &cp, 0);
2752 if (ptr == cp || errno != 0 || *cp != '.')
2753 return (DLADM_STATUS_BADARG);
2755 ptr = cp + 1;
2756 lladdr = _link_aton(ptr, &addrlen);
2757 if (lladdr == NULL)
2758 return (DLADM_STATUS_BADARG);
2760 cidlen = sizeof (llt) + addrlen;
2761 if (cidlen > sizeof (cid->dc_id)) {
2762 free(lladdr);
2763 return (DLADM_STATUS_TOOSMALL);
2765 llt.dllt_dutype = htons(duidtype);
2766 llt.dllt_hwtype = htons(subtype);
2767 llt.dllt_time = htonl(timestamp);
2768 bcopy(&llt, cid->dc_id, sizeof (llt));
2769 bcopy(lladdr, cid->dc_id + sizeof (llt), addrlen);
2770 free(lladdr);
2771 break;
2773 case DHCPV6_DUID_LL: {
2774 duid_ll_t ll;
2776 lladdr = _link_aton(ptr, &addrlen);
2777 if (lladdr == NULL)
2778 return (DLADM_STATUS_BADARG);
2780 cidlen = sizeof (ll) + addrlen;
2781 if (cidlen > sizeof (cid->dc_id)) {
2782 free(lladdr);
2783 return (DLADM_STATUS_TOOSMALL);
2785 ll.dll_dutype = htons(duidtype);
2786 ll.dll_hwtype = htons(subtype);
2787 bcopy(&ll, cid->dc_id, sizeof (ll));
2788 bcopy(lladdr, cid->dc_id + sizeof (ll), addrlen);
2789 free(lladdr);
2790 break;
2792 default: {
2793 hexlen = sizeof (tmp_buf);
2794 if (hexascii_to_octet(ptr, strlen(ptr),
2795 tmp_buf, &hexlen) != 0)
2796 return (DLADM_STATUS_BADARG);
2798 if (duidtype == DHCPV6_DUID_EN) {
2799 duid_en_t en;
2801 en.den_dutype = htons(duidtype);
2802 DHCPV6_SET_ENTNUM(&en, subtype);
2804 cidlen = sizeof (en) + hexlen;
2805 if (cidlen > sizeof (cid->dc_id))
2806 return (DLADM_STATUS_TOOSMALL);
2808 bcopy(&en, cid->dc_id, sizeof (en));
2809 bcopy(tmp_buf, cid->dc_id + sizeof (en),
2810 hexlen);
2811 } else {
2812 uint16_t dutype = htons(duidtype);
2814 cidlen = sizeof (dutype) + hexlen;
2815 if (cidlen > sizeof (cid->dc_id))
2816 return (DLADM_STATUS_TOOSMALL);
2818 bcopy(&dutype, cid->dc_id, sizeof (dutype));
2819 bcopy(tmp_buf, cid->dc_id + sizeof (dutype),
2820 hexlen);
2822 break;
2825 cid->dc_form = CIDFORM_TYPED;
2826 } else if (strncasecmp("0x", ptr, 2) == 0 && ptr[2] != '\0') {
2827 ptr += 2;
2828 hexlen = sizeof (tmp_buf);
2829 if (hexascii_to_octet(ptr, strlen(ptr), tmp_buf,
2830 &hexlen) != 0) {
2831 return (DLADM_STATUS_BADARG);
2833 cidlen = hexlen;
2834 if (cidlen > sizeof (cid->dc_id))
2835 return (DLADM_STATUS_TOOSMALL);
2837 bcopy(tmp_buf, cid->dc_id, cidlen);
2838 cid->dc_form = CIDFORM_HEX;
2839 } else {
2840 cidlen = strlen(ptr);
2841 if (cidlen > sizeof (cid->dc_id))
2842 return (DLADM_STATUS_TOOSMALL);
2844 bcopy(ptr, cid->dc_id, cidlen);
2845 cid->dc_form = CIDFORM_STR;
2847 cid->dc_len = cidlen;
2848 return (DLADM_STATUS_OK);
2851 /* ARGSUSED */
2852 static dladm_status_t
2853 get_allowedcids(dladm_handle_t handle, prop_desc_t *pdp,
2854 datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
2855 datalink_media_t media, uint_t flags, uint_t *perm_flags)
2857 mac_resource_props_t mrp;
2858 mac_protect_t *p;
2859 dladm_status_t status;
2860 int i;
2862 status = i_dladm_get_public_prop(handle, linkid, "resource", flags,
2863 perm_flags, &mrp, sizeof (mrp));
2864 if (status != DLADM_STATUS_OK)
2865 return (status);
2867 p = &mrp.mrp_protect;
2868 if (p->mp_cidcnt == 0) {
2869 *val_cnt = 0;
2870 return (DLADM_STATUS_OK);
2872 if (p->mp_cidcnt > *val_cnt)
2873 return (DLADM_STATUS_BADVALCNT);
2875 for (i = 0; i < p->mp_cidcnt; i++) {
2876 mac_dhcpcid_t *cid = &p->mp_cids[i];
2878 dladm_cid2str(cid, prop_val[i]);
2880 *val_cnt = p->mp_cidcnt;
2881 return (DLADM_STATUS_OK);
2884 dladm_status_t
2885 extract_allowedcids(val_desc_t *vdp, uint_t cnt, void *arg)
2887 mac_resource_props_t *mrp = arg;
2888 mac_protect_t *p = &mrp->mrp_protect;
2889 int i;
2891 if (vdp->vd_val == 0) {
2892 cnt = (uint_t)-1;
2893 } else {
2894 for (i = 0; i < cnt; i++) {
2895 bcopy((void *)vdp[i].vd_val, &p->mp_cids[i],
2896 sizeof (mac_dhcpcid_t));
2899 p->mp_cidcnt = cnt;
2900 mrp->mrp_mask |= MRP_PROTECT;
2901 return (DLADM_STATUS_OK);
2904 /* ARGSUSED */
2905 static dladm_status_t
2906 check_allowedcids(dladm_handle_t handle, prop_desc_t *pdp,
2907 datalink_id_t linkid, char **prop_val, uint_t *val_cntp,
2908 uint_t flags, val_desc_t **vdpp, datalink_media_t media)
2910 dladm_status_t status;
2911 mac_dhcpcid_t *cid;
2912 int i;
2913 uint_t val_cnt = *val_cntp;
2914 val_desc_t *vdp = *vdpp;
2916 if (val_cnt > MPT_MAXCID)
2917 return (DLADM_STATUS_BADVALCNT);
2919 for (i = 0; i < val_cnt; i++) {
2920 if ((cid = calloc(1, sizeof (mac_dhcpcid_t))) == NULL) {
2921 status = DLADM_STATUS_NOMEM;
2922 goto fail;
2924 vdp[i].vd_val = (uintptr_t)cid;
2926 status = dladm_str2cid(prop_val[i], cid);
2927 if (status != DLADM_STATUS_OK)
2928 goto fail;
2930 return (DLADM_STATUS_OK);
2932 fail:
2933 for (i = 0; i < val_cnt; i++) {
2934 free((void *)vdp[i].vd_val);
2935 vdp[i].vd_val = NULL;
2937 return (status);
2940 /* ARGSUSED */
2941 static dladm_status_t
2942 get_secondary_macs(dladm_handle_t handle, prop_desc_t *pdp,
2943 datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
2944 datalink_media_t media, uint_t flags, uint_t *perm_flags)
2946 mac_secondary_addr_t sa;
2947 dladm_status_t status;
2948 int i;
2950 status = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags,
2951 perm_flags, &sa, sizeof (sa));
2952 if (status != DLADM_STATUS_OK)
2953 return (status);
2955 if (sa.ms_addrcnt > *val_cnt)
2956 return (DLADM_STATUS_BADVALCNT);
2958 for (i = 0; i < sa.ms_addrcnt; i++) {
2959 if (dladm_aggr_macaddr2str(
2960 (const unsigned char *)&sa.ms_addrs[i], prop_val[i]) ==
2961 NULL) {
2962 *val_cnt = i;
2963 return (DLADM_STATUS_NOMEM);
2966 *val_cnt = sa.ms_addrcnt;
2967 return (DLADM_STATUS_OK);
2970 /* ARGSUSED */
2971 static dladm_status_t
2972 check_secondary_macs(dladm_handle_t handle, prop_desc_t *pdp,
2973 datalink_id_t linkid, char **prop_val, uint_t *val_cntp, uint_t flags,
2974 val_desc_t **vdpp, datalink_media_t media)
2976 dladm_status_t status;
2977 uchar_t *addr;
2978 uint_t len = 0;
2979 int i;
2980 uint_t val_cnt = *val_cntp;
2981 val_desc_t *vdp = *vdpp;
2983 if (val_cnt >= MPT_MAXMACADDR)
2984 return (DLADM_STATUS_BADVALCNT);
2986 for (i = 0; i < val_cnt; i++) {
2987 addr = _link_aton(prop_val[i], (int *)&len);
2988 if (addr == NULL) {
2989 if (len == (uint_t)-1)
2990 status = DLADM_STATUS_MACADDRINVAL;
2991 else
2992 status = DLADM_STATUS_NOMEM;
2993 goto fail;
2996 vdp[i].vd_val = (uintptr_t)addr;
2998 return (DLADM_STATUS_OK);
3000 fail:
3001 for (i = 0; i < val_cnt; i++) {
3002 free((void *)vdp[i].vd_val);
3003 vdp[i].vd_val = NULL;
3005 return (status);
3008 /* ARGSUSED */
3009 static dladm_status_t
3010 set_secondary_macs(dladm_handle_t handle, prop_desc_t *pd, datalink_id_t linkid,
3011 val_desc_t *vdp, uint_t val_cnt, uint_t flags, datalink_media_t media)
3013 dladm_status_t status;
3014 dld_ioc_macprop_t *dip;
3015 int i;
3016 mac_secondary_addr_t msa;
3018 dip = i_dladm_buf_alloc_by_name(0, linkid, "secondary-macs", 0,
3019 &status);
3020 if (dip == NULL)
3021 return (status);
3023 if (vdp->vd_val == 0) {
3024 val_cnt = (uint_t)-1;
3025 } else {
3026 for (i = 0; i < val_cnt; i++) {
3027 bcopy((void *)vdp[i].vd_val, msa.ms_addrs[i],
3028 MAXMACADDRLEN);
3031 msa.ms_addrcnt = val_cnt;
3032 bcopy(&msa, dip->pr_val, dip->pr_valsize);
3034 status = i_dladm_macprop(handle, dip, B_TRUE);
3036 free(dip);
3037 return (status);
3040 /* ARGSUSED */
3041 static dladm_status_t
3042 get_autopush(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
3043 char **prop_val, uint_t *val_cnt, datalink_media_t media,
3044 uint_t flags, uint_t *perm_flags)
3046 struct dlautopush dlap;
3047 int i, len;
3048 dladm_status_t status;
3050 if (flags & DLD_PROP_DEFAULT)
3051 return (DLADM_STATUS_NOTDEFINED);
3053 status = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags,
3054 perm_flags, &dlap, sizeof (dlap));
3055 if (status != DLADM_STATUS_OK)
3056 return (status);
3058 if (dlap.dap_npush == 0) {
3059 *val_cnt = 0;
3060 return (DLADM_STATUS_OK);
3062 for (i = 0, len = 0; i < dlap.dap_npush; i++) {
3063 if (i != 0) {
3064 (void) snprintf(*prop_val + len,
3065 DLADM_PROP_VAL_MAX - len, "%c", AP_DELIMITER);
3066 len += 1;
3068 (void) snprintf(*prop_val + len, DLADM_PROP_VAL_MAX - len,
3069 "%s", dlap.dap_aplist[i]);
3070 len += strlen(dlap.dap_aplist[i]);
3071 if (dlap.dap_anchor - 1 == i) {
3072 (void) snprintf(*prop_val + len,
3073 DLADM_PROP_VAL_MAX - len, "%c%s", AP_DELIMITER,
3074 AP_ANCHOR);
3075 len += (strlen(AP_ANCHOR) + 1);
3078 *val_cnt = 1;
3079 return (DLADM_STATUS_OK);
3083 * Add the specified module to the dlautopush structure; returns a
3084 * DLADM_STATUS_* code.
3086 dladm_status_t
3087 i_dladm_add_ap_module(const char *module, struct dlautopush *dlap)
3089 if ((strlen(module) == 0) || (strlen(module) > FMNAMESZ))
3090 return (DLADM_STATUS_BADVAL);
3092 if (strncasecmp(module, AP_ANCHOR, strlen(AP_ANCHOR)) == 0) {
3094 * We don't allow multiple anchors, and the anchor must
3095 * be after at least one module.
3097 if (dlap->dap_anchor != 0)
3098 return (DLADM_STATUS_BADVAL);
3099 if (dlap->dap_npush == 0)
3100 return (DLADM_STATUS_BADVAL);
3102 dlap->dap_anchor = dlap->dap_npush;
3103 return (DLADM_STATUS_OK);
3105 if (dlap->dap_npush >= MAXAPUSH)
3106 return (DLADM_STATUS_BADVALCNT);
3108 (void) strlcpy(dlap->dap_aplist[dlap->dap_npush++], module,
3109 FMNAMESZ + 1);
3111 return (DLADM_STATUS_OK);
3115 * Currently, both '.' and ' '(space) can be used as the delimiters between
3116 * autopush modules. The former is used in dladm set-linkprop, and the
3117 * latter is used in the autopush(1M) file.
3119 /* ARGSUSED */
3120 static dladm_status_t
3121 check_autopush(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
3122 char **prop_val, uint_t *val_cntp, uint_t flags, val_desc_t **vdpp,
3123 datalink_media_t media)
3125 char *module;
3126 struct dlautopush *dlap;
3127 dladm_status_t status;
3128 char val[DLADM_PROP_VAL_MAX];
3129 char delimiters[4];
3130 uint_t val_cnt = *val_cntp;
3131 val_desc_t *vdp = *vdpp;
3133 if (val_cnt != 1)
3134 return (DLADM_STATUS_BADVALCNT);
3136 if (prop_val != NULL) {
3137 dlap = malloc(sizeof (struct dlautopush));
3138 if (dlap == NULL)
3139 return (DLADM_STATUS_NOMEM);
3141 (void) memset(dlap, 0, sizeof (struct dlautopush));
3142 (void) snprintf(delimiters, 4, " %c\n", AP_DELIMITER);
3143 bcopy(*prop_val, val, DLADM_PROP_VAL_MAX);
3144 module = strtok(val, delimiters);
3145 while (module != NULL) {
3146 status = i_dladm_add_ap_module(module, dlap);
3147 if (status != DLADM_STATUS_OK)
3148 return (status);
3149 module = strtok(NULL, delimiters);
3152 vdp->vd_val = (uintptr_t)dlap;
3153 } else {
3154 vdp->vd_val = 0;
3156 return (DLADM_STATUS_OK);
3159 #define WLDP_BUFSIZE (MAX_BUF_LEN - WIFI_BUF_OFFSET)
3161 /* ARGSUSED */
3162 static dladm_status_t
3163 get_rate_common(dladm_handle_t handle, prop_desc_t *pdp,
3164 datalink_id_t linkid, char **prop_val, uint_t *val_cnt, uint_t id,
3165 uint_t *perm_flags)
3167 wl_rates_t *wrp;
3168 uint_t i;
3169 dladm_status_t status = DLADM_STATUS_OK;
3171 wrp = malloc(WLDP_BUFSIZE);
3172 if (wrp == NULL)
3173 return (DLADM_STATUS_NOMEM);
3175 status = i_dladm_wlan_param(handle, linkid, wrp, id, WLDP_BUFSIZE,
3176 B_FALSE);
3177 if (status != DLADM_STATUS_OK)
3178 goto done;
3180 if (wrp->wl_rates_num > *val_cnt) {
3181 status = DLADM_STATUS_TOOSMALL;
3182 goto done;
3185 if (wrp->wl_rates_rates[0] == 0) {
3186 prop_val[0][0] = '\0';
3187 *val_cnt = 1;
3188 goto done;
3191 for (i = 0; i < wrp->wl_rates_num; i++) {
3192 (void) snprintf(prop_val[i], DLADM_STRSIZE, "%.*f",
3193 wrp->wl_rates_rates[i] % 2,
3194 (float)wrp->wl_rates_rates[i] / 2);
3196 *val_cnt = wrp->wl_rates_num;
3197 *perm_flags = MAC_PROP_PERM_RW;
3199 done:
3200 free(wrp);
3201 return (status);
3204 static dladm_status_t
3205 get_rate(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
3206 char **prop_val, uint_t *val_cnt, datalink_media_t media,
3207 uint_t flags, uint_t *perm_flags)
3209 if (media != DL_WIFI) {
3210 return (get_speed(handle, pdp, linkid, prop_val,
3211 val_cnt, media, flags, perm_flags));
3214 return (get_rate_common(handle, pdp, linkid, prop_val, val_cnt,
3215 MAC_PROP_WL_DESIRED_RATES, perm_flags));
3218 /* ARGSUSED */
3219 static dladm_status_t
3220 get_rate_mod(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
3221 char **prop_val, uint_t *val_cnt, datalink_media_t media,
3222 uint_t flags, uint_t *perm_flags)
3224 switch (media) {
3225 case DL_ETHER:
3227 * Speed for ethernet links is unbounded. E.g., 802.11b
3228 * links can have a speed of 5.5 Gbps.
3230 return (DLADM_STATUS_NOTSUP);
3232 case DL_WIFI:
3233 return (get_rate_common(handle, pdp, linkid, prop_val,
3234 val_cnt, MAC_PROP_WL_SUPPORTED_RATES, perm_flags));
3235 default:
3236 return (DLADM_STATUS_BADARG);
3240 static dladm_status_t
3241 set_wlan_rate(dladm_handle_t handle, datalink_id_t linkid,
3242 dladm_wlan_rates_t *rates)
3244 int i;
3245 uint_t len;
3246 wl_rates_t *wrp;
3247 dladm_status_t status = DLADM_STATUS_OK;
3249 wrp = malloc(WLDP_BUFSIZE);
3250 if (wrp == NULL)
3251 return (DLADM_STATUS_NOMEM);
3253 bzero(wrp, WLDP_BUFSIZE);
3254 for (i = 0; i < rates->wr_cnt; i++)
3255 wrp->wl_rates_rates[i] = rates->wr_rates[i];
3256 wrp->wl_rates_num = rates->wr_cnt;
3258 len = offsetof(wl_rates_t, wl_rates_rates) +
3259 (rates->wr_cnt * sizeof (char)) + WIFI_BUF_OFFSET;
3260 status = i_dladm_wlan_param(handle, linkid, wrp,
3261 MAC_PROP_WL_DESIRED_RATES, len, B_TRUE);
3263 free(wrp);
3264 return (status);
3267 /* ARGSUSED */
3268 static dladm_status_t
3269 set_rate(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
3270 val_desc_t *vdp, uint_t val_cnt, uint_t flags, datalink_media_t media)
3272 dladm_wlan_rates_t rates;
3273 dladm_status_t status;
3276 * can currently set rate on WIFI links only.
3278 if (media != DL_WIFI)
3279 return (DLADM_STATUS_PROPRDONLY);
3281 if (val_cnt != 1)
3282 return (DLADM_STATUS_BADVALCNT);
3284 rates.wr_cnt = 1;
3285 rates.wr_rates[0] = vdp[0].vd_val;
3287 status = set_wlan_rate(handle, linkid, &rates);
3289 return (status);
3292 /* ARGSUSED */
3293 static dladm_status_t
3294 check_rate(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
3295 char **prop_val, uint_t *val_cntp, uint_t flags, val_desc_t **vdpp,
3296 datalink_media_t media)
3298 int i;
3299 uint_t modval_cnt = MAX_SUPPORT_RATES;
3300 char *buf, **modval;
3301 dladm_status_t status;
3302 uint_t perm_flags;
3303 uint_t val_cnt = *val_cntp;
3304 val_desc_t *vdp = *vdpp;
3306 if (val_cnt != 1)
3307 return (DLADM_STATUS_BADVALCNT);
3309 buf = malloc((sizeof (char *) + DLADM_STRSIZE) *
3310 MAX_SUPPORT_RATES);
3311 if (buf == NULL) {
3312 status = DLADM_STATUS_NOMEM;
3313 goto done;
3316 modval = (char **)(void *)buf;
3317 for (i = 0; i < MAX_SUPPORT_RATES; i++) {
3318 modval[i] = buf + sizeof (char *) * MAX_SUPPORT_RATES +
3319 i * DLADM_STRSIZE;
3322 status = get_rate_mod(handle, NULL, linkid, modval, &modval_cnt,
3323 media, 0, &perm_flags);
3324 if (status != DLADM_STATUS_OK)
3325 goto done;
3327 for (i = 0; i < modval_cnt; i++) {
3328 if (strcasecmp(*prop_val, modval[i]) == 0) {
3329 vdp->vd_val = (uintptr_t)(uint_t)
3330 (atof(*prop_val) * 2);
3331 status = DLADM_STATUS_OK;
3332 break;
3335 if (i == modval_cnt)
3336 status = DLADM_STATUS_BADVAL;
3337 done:
3338 free(buf);
3339 return (status);
3342 static dladm_status_t
3343 get_phyconf(dladm_handle_t handle, datalink_id_t linkid, void *buf,
3344 int buflen)
3346 return (i_dladm_wlan_param(handle, linkid, buf, MAC_PROP_WL_PHY_CONFIG,
3347 buflen, B_FALSE));
3350 /* ARGSUSED */
3351 static dladm_status_t
3352 get_channel(dladm_handle_t handle, prop_desc_t *pdp,
3353 datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
3354 datalink_media_t media, uint_t flags, uint_t *perm_flags)
3356 uint32_t channel;
3357 char buf[WLDP_BUFSIZE];
3358 dladm_status_t status;
3359 wl_phy_conf_t wl_phy_conf;
3361 if ((status = get_phyconf(handle, linkid, buf, sizeof (buf)))
3362 != DLADM_STATUS_OK)
3363 return (status);
3365 (void) memcpy(&wl_phy_conf, buf, sizeof (wl_phy_conf));
3366 if (!i_dladm_wlan_convert_chan(&wl_phy_conf, &channel))
3367 return (DLADM_STATUS_NOTFOUND);
3369 (void) snprintf(*prop_val, DLADM_STRSIZE, "%u", channel);
3370 *val_cnt = 1;
3371 *perm_flags = MAC_PROP_PERM_READ;
3372 return (DLADM_STATUS_OK);
3375 /* ARGSUSED */
3376 static dladm_status_t
3377 get_powermode(dladm_handle_t handle, prop_desc_t *pdp,
3378 datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
3379 datalink_media_t media, uint_t flags, uint_t *perm_flags)
3381 wl_ps_mode_t mode;
3382 const char *s;
3383 char buf[WLDP_BUFSIZE];
3384 dladm_status_t status;
3386 if ((status = i_dladm_wlan_param(handle, linkid, buf,
3387 MAC_PROP_WL_POWER_MODE, sizeof (buf), B_FALSE)) != DLADM_STATUS_OK)
3388 return (status);
3390 (void) memcpy(&mode, buf, sizeof (mode));
3391 switch (mode.wl_ps_mode) {
3392 case WL_PM_AM:
3393 s = "off";
3394 break;
3395 case WL_PM_MPS:
3396 s = "max";
3397 break;
3398 case WL_PM_FAST:
3399 s = "fast";
3400 break;
3401 default:
3402 return (DLADM_STATUS_NOTFOUND);
3404 (void) snprintf(*prop_val, DLADM_STRSIZE, "%s", s);
3405 *val_cnt = 1;
3406 *perm_flags = MAC_PROP_PERM_RW;
3407 return (DLADM_STATUS_OK);
3410 /* ARGSUSED */
3411 static dladm_status_t
3412 set_powermode(dladm_handle_t handle, prop_desc_t *pdp,
3413 datalink_id_t linkid, val_desc_t *vdp, uint_t val_cnt, uint_t flags,
3414 datalink_media_t media)
3416 dladm_wlan_powermode_t powermode = vdp->vd_val;
3417 wl_ps_mode_t ps_mode;
3419 if (val_cnt != 1)
3420 return (DLADM_STATUS_BADVALCNT);
3422 (void) memset(&ps_mode, 0xff, sizeof (ps_mode));
3424 switch (powermode) {
3425 case DLADM_WLAN_PM_OFF:
3426 ps_mode.wl_ps_mode = WL_PM_AM;
3427 break;
3428 case DLADM_WLAN_PM_MAX:
3429 ps_mode.wl_ps_mode = WL_PM_MPS;
3430 break;
3431 case DLADM_WLAN_PM_FAST:
3432 ps_mode.wl_ps_mode = WL_PM_FAST;
3433 break;
3434 default:
3435 return (DLADM_STATUS_NOTSUP);
3437 return (i_dladm_wlan_param(handle, linkid, &ps_mode,
3438 MAC_PROP_WL_POWER_MODE, sizeof (ps_mode), B_TRUE));
3441 /* ARGSUSED */
3442 static dladm_status_t
3443 get_radio(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
3444 char **prop_val, uint_t *val_cnt, datalink_media_t media,
3445 uint_t flags, uint_t *perm_flags)
3447 wl_radio_t radio;
3448 const char *s;
3449 char buf[WLDP_BUFSIZE];
3450 dladm_status_t status;
3452 if ((status = i_dladm_wlan_param(handle, linkid, buf,
3453 MAC_PROP_WL_RADIO, sizeof (buf), B_FALSE)) != DLADM_STATUS_OK)
3454 return (status);
3456 (void) memcpy(&radio, buf, sizeof (radio));
3457 switch (radio) {
3458 case B_TRUE:
3459 s = "on";
3460 break;
3461 case B_FALSE:
3462 s = "off";
3463 break;
3464 default:
3465 return (DLADM_STATUS_NOTFOUND);
3467 (void) snprintf(*prop_val, DLADM_STRSIZE, "%s", s);
3468 *val_cnt = 1;
3469 *perm_flags = MAC_PROP_PERM_RW;
3470 return (DLADM_STATUS_OK);
3473 /* ARGSUSED */
3474 static dladm_status_t
3475 set_radio(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
3476 val_desc_t *vdp, uint_t val_cnt, uint_t flags, datalink_media_t media)
3478 dladm_wlan_radio_t radio = vdp->vd_val;
3479 wl_radio_t r;
3481 if (val_cnt != 1)
3482 return (DLADM_STATUS_BADVALCNT);
3484 switch (radio) {
3485 case DLADM_WLAN_RADIO_ON:
3486 r = B_TRUE;
3487 break;
3488 case DLADM_WLAN_RADIO_OFF:
3489 r = B_FALSE;
3490 break;
3491 default:
3492 return (DLADM_STATUS_NOTSUP);
3494 return (i_dladm_wlan_param(handle, linkid, &r, MAC_PROP_WL_RADIO,
3495 sizeof (r), B_TRUE));
3498 /* ARGSUSED */
3499 static dladm_status_t
3500 check_hoplimit(dladm_handle_t handle, prop_desc_t *pdp,
3501 datalink_id_t linkid, char **prop_val, uint_t *val_cntp, uint_t flags,
3502 val_desc_t **vdpp, datalink_media_t media)
3504 int32_t hlim;
3505 char *ep;
3506 uint_t val_cnt = *val_cntp;
3507 val_desc_t *vdp = *vdpp;
3509 if (val_cnt != 1)
3510 return (DLADM_STATUS_BADVALCNT);
3512 errno = 0;
3513 hlim = strtol(*prop_val, &ep, 10);
3514 if (errno != 0 || ep == *prop_val || hlim < 1 ||
3515 hlim > (int32_t)UINT8_MAX)
3516 return (DLADM_STATUS_BADVAL);
3517 vdp->vd_val = hlim;
3518 return (DLADM_STATUS_OK);
3521 /* ARGSUSED */
3522 static dladm_status_t
3523 check_encaplim(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
3524 char **prop_val, uint_t *val_cntp, uint_t flags, val_desc_t **vdpp,
3525 datalink_media_t media)
3527 int32_t elim;
3528 char *ep;
3529 uint_t val_cnt = *val_cntp;
3530 val_desc_t *vdp = *vdpp;
3532 if (media != DL_IPV6)
3533 return (DLADM_STATUS_BADARG);
3535 if (val_cnt != 1)
3536 return (DLADM_STATUS_BADVALCNT);
3538 errno = 0;
3539 elim = strtol(*prop_val, &ep, 10);
3540 if (errno != 0 || ep == *prop_val || elim < 0 ||
3541 elim > (int32_t)UINT8_MAX)
3542 return (DLADM_STATUS_BADVAL);
3543 vdp->vd_val = elim;
3544 return (DLADM_STATUS_OK);
3547 static dladm_status_t
3548 i_dladm_set_linkprop_db(dladm_handle_t handle, datalink_id_t linkid,
3549 const char *prop_name, char **prop_val, uint_t val_cnt)
3551 char buf[MAXLINELEN];
3552 int i;
3553 dladm_conf_t conf;
3554 dladm_status_t status;
3556 status = dladm_open_conf(handle, linkid, &conf);
3557 if (status != DLADM_STATUS_OK)
3558 return (status);
3561 * reset case.
3563 if (val_cnt == 0) {
3564 status = dladm_unset_conf_field(handle, conf, prop_name);
3565 if (status == DLADM_STATUS_OK)
3566 status = dladm_write_conf(handle, conf);
3567 goto done;
3570 buf[0] = '\0';
3571 for (i = 0; i < val_cnt; i++) {
3572 (void) strlcat(buf, prop_val[i], MAXLINELEN);
3573 if (i != val_cnt - 1)
3574 (void) strlcat(buf, ",", MAXLINELEN);
3577 status = dladm_set_conf_field(handle, conf, prop_name, DLADM_TYPE_STR,
3578 buf);
3579 if (status == DLADM_STATUS_OK)
3580 status = dladm_write_conf(handle, conf);
3582 done:
3583 dladm_destroy_conf(handle, conf);
3584 return (status);
3587 static dladm_status_t
3588 i_dladm_get_linkprop_db(dladm_handle_t handle, datalink_id_t linkid,
3589 const char *prop_name, char **prop_val, uint_t *val_cntp)
3591 char buf[MAXLINELEN], *str;
3592 uint_t cnt = 0;
3593 dladm_conf_t conf;
3594 dladm_status_t status;
3596 status = dladm_getsnap_conf(handle, linkid, &conf);
3597 if (status != DLADM_STATUS_OK)
3598 return (status);
3600 status = dladm_get_conf_field(handle, conf, prop_name, buf, MAXLINELEN);
3601 if (status != DLADM_STATUS_OK)
3602 goto done;
3604 str = strtok(buf, ",");
3605 while (str != NULL) {
3606 if (cnt == *val_cntp) {
3607 status = DLADM_STATUS_TOOSMALL;
3608 goto done;
3610 (void) strlcpy(prop_val[cnt++], str, DLADM_PROP_VAL_MAX);
3611 str = strtok(NULL, ",");
3614 *val_cntp = cnt;
3616 done:
3617 dladm_destroy_conf(handle, conf);
3618 return (status);
3622 * Walk persistent private link properties of a link.
3624 static dladm_status_t
3625 i_dladm_walk_linkprop_priv_db(dladm_handle_t handle, datalink_id_t linkid,
3626 void *arg, int (*func)(dladm_handle_t, datalink_id_t, const char *, void *))
3628 dladm_status_t status;
3629 dladm_conf_t conf;
3630 char last_attr[MAXLINKATTRLEN];
3631 char attr[MAXLINKATTRLEN];
3632 char attrval[MAXLINKATTRVALLEN];
3633 size_t attrsz;
3635 if (linkid == DATALINK_INVALID_LINKID || func == NULL)
3636 return (DLADM_STATUS_BADARG);
3638 status = dladm_getsnap_conf(handle, linkid, &conf);
3639 if (status != DLADM_STATUS_OK)
3640 return (status);
3642 last_attr[0] = '\0';
3643 while ((status = dladm_getnext_conf_linkprop(handle, conf, last_attr,
3644 attr, attrval, MAXLINKATTRVALLEN, &attrsz)) == DLADM_STATUS_OK) {
3645 if (attr[0] == '_') {
3646 if (func(handle, linkid, attr, arg) ==
3647 DLADM_WALK_TERMINATE)
3648 break;
3650 (void) strlcpy(last_attr, attr, MAXLINKATTRLEN);
3653 dladm_destroy_conf(handle, conf);
3654 return (DLADM_STATUS_OK);
3657 static link_attr_t *
3658 dladm_name2prop(const char *prop_name)
3660 link_attr_t *p;
3662 for (p = link_attr; p->pp_id != MAC_PROP_PRIVATE; p++) {
3663 if (strcmp(p->pp_name, prop_name) == 0)
3664 break;
3666 return (p);
3669 static link_attr_t *
3670 dladm_id2prop(mac_prop_id_t propid)
3672 link_attr_t *p;
3674 for (p = link_attr; p->pp_id != MAC_PROP_PRIVATE; p++) {
3675 if (p->pp_id == propid)
3676 break;
3678 return (p);
3681 static dld_ioc_macprop_t *
3682 i_dladm_buf_alloc_impl(size_t valsize, datalink_id_t linkid,
3683 const char *prop_name, mac_prop_id_t propid, uint_t flags,
3684 dladm_status_t *status)
3686 int dsize;
3687 dld_ioc_macprop_t *dip;
3689 *status = DLADM_STATUS_OK;
3690 dsize = MAC_PROP_BUFSIZE(valsize);
3691 dip = malloc(dsize);
3692 if (dip == NULL) {
3693 *status = DLADM_STATUS_NOMEM;
3694 return (NULL);
3696 bzero(dip, dsize);
3697 dip->pr_valsize = valsize;
3698 (void) strlcpy(dip->pr_name, prop_name, sizeof (dip->pr_name));
3699 dip->pr_linkid = linkid;
3700 dip->pr_num = propid;
3701 dip->pr_flags = flags;
3702 return (dip);
3705 static dld_ioc_macprop_t *
3706 i_dladm_buf_alloc_by_name(size_t valsize, datalink_id_t linkid,
3707 const char *prop_name, uint_t flags, dladm_status_t *status)
3709 link_attr_t *p;
3711 p = dladm_name2prop(prop_name);
3712 valsize = MAX(p->pp_valsize, valsize);
3713 return (i_dladm_buf_alloc_impl(valsize, linkid, prop_name, p->pp_id,
3714 flags, status));
3717 static dld_ioc_macprop_t *
3718 i_dladm_buf_alloc_by_id(size_t valsize, datalink_id_t linkid,
3719 mac_prop_id_t propid, uint_t flags, dladm_status_t *status)
3721 link_attr_t *p;
3723 p = dladm_id2prop(propid);
3724 valsize = MAX(p->pp_valsize, valsize);
3725 return (i_dladm_buf_alloc_impl(valsize, linkid, p->pp_name, propid,
3726 flags, status));
3729 /* ARGSUSED */
3730 static dladm_status_t
3731 set_public_prop(dladm_handle_t handle, prop_desc_t *pdp,
3732 datalink_id_t linkid, val_desc_t *vdp, uint_t val_cnt, uint_t flags,
3733 datalink_media_t media)
3735 dld_ioc_macprop_t *dip;
3736 dladm_status_t status = DLADM_STATUS_OK;
3737 uint8_t u8;
3738 uint16_t u16;
3739 uint32_t u32;
3740 void *val;
3742 dip = i_dladm_buf_alloc_by_name(0, linkid, pdp->pd_name, 0, &status);
3743 if (dip == NULL)
3744 return (status);
3746 if (pdp->pd_flags & PD_CHECK_ALLOC)
3747 val = (void *)vdp->vd_val;
3748 else {
3750 * Currently all 1/2/4-byte size properties are byte/word/int.
3751 * No need (yet) to distinguish these from arrays of same size.
3753 switch (dip->pr_valsize) {
3754 case 1:
3755 u8 = vdp->vd_val;
3756 val = &u8;
3757 break;
3758 case 2:
3759 u16 = vdp->vd_val;
3760 val = &u16;
3761 break;
3762 case 4:
3763 u32 = vdp->vd_val;
3764 val = &u32;
3765 break;
3766 default:
3767 val = &vdp->vd_val;
3768 break;
3772 if (val != NULL)
3773 (void) memcpy(dip->pr_val, val, dip->pr_valsize);
3774 else
3775 dip->pr_valsize = 0;
3777 status = i_dladm_macprop(handle, dip, B_TRUE);
3779 done:
3780 free(dip);
3781 return (status);
3784 dladm_status_t
3785 i_dladm_macprop(dladm_handle_t handle, void *dip, boolean_t set)
3787 dladm_status_t status = DLADM_STATUS_OK;
3789 if (ioctl(dladm_dld_fd(handle),
3790 (set ? DLDIOC_SETMACPROP : DLDIOC_GETMACPROP), dip))
3791 status = dladm_errno2status(errno);
3793 return (status);
3796 static dladm_status_t
3797 i_dladm_get_public_prop(dladm_handle_t handle, datalink_id_t linkid,
3798 char *prop_name, uint_t flags, uint_t *perm_flags, void *arg, size_t size)
3800 dld_ioc_macprop_t *dip;
3801 dladm_status_t status;
3803 dip = i_dladm_buf_alloc_by_name(0, linkid, prop_name, flags, &status);
3804 if (dip == NULL)
3805 return (DLADM_STATUS_NOMEM);
3807 status = i_dladm_macprop(handle, dip, B_FALSE);
3808 if (status != DLADM_STATUS_OK) {
3809 free(dip);
3810 return (status);
3813 if (perm_flags != NULL)
3814 *perm_flags = dip->pr_perm_flags;
3816 if (arg != NULL)
3817 (void) memcpy(arg, dip->pr_val, size);
3818 free(dip);
3819 return (DLADM_STATUS_OK);
3822 /* ARGSUSED */
3823 static dladm_status_t
3824 check_uint32(dladm_handle_t handle, prop_desc_t *pdp,
3825 datalink_id_t linkid, char **prop_val, uint_t *val_cntp, uint_t flags,
3826 val_desc_t **vp, datalink_media_t media)
3828 uint_t val_cnt = *val_cntp;
3829 val_desc_t *v = *vp;
3831 if (val_cnt != 1)
3832 return (DLADM_STATUS_BADVAL);
3833 v->vd_val = strtoul(prop_val[0], NULL, 0);
3834 return (DLADM_STATUS_OK);
3837 /* ARGSUSED */
3838 static dladm_status_t
3839 get_duplex(dladm_handle_t handle, prop_desc_t *pdp,
3840 datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
3841 datalink_media_t media, uint_t flags, uint_t *perm_flags)
3843 link_duplex_t link_duplex;
3844 dladm_status_t status;
3846 if ((status = dladm_get_single_mac_stat(handle, linkid, "link_duplex",
3847 KSTAT_DATA_UINT32, &link_duplex)) != 0)
3848 return (status);
3850 switch (link_duplex) {
3851 case LINK_DUPLEX_FULL:
3852 (void) strcpy(*prop_val, "full");
3853 break;
3854 case LINK_DUPLEX_HALF:
3855 (void) strcpy(*prop_val, "half");
3856 break;
3857 default:
3858 (void) strcpy(*prop_val, "unknown");
3859 break;
3861 *val_cnt = 1;
3862 return (DLADM_STATUS_OK);
3865 /* ARGSUSED */
3866 static dladm_status_t
3867 get_speed(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
3868 char **prop_val, uint_t *val_cnt, datalink_media_t media, uint_t flags,
3869 uint_t *perm_flags)
3871 uint64_t ifspeed = 0;
3872 dladm_status_t status;
3874 if ((status = dladm_get_single_mac_stat(handle, linkid, "ifspeed",
3875 KSTAT_DATA_UINT64, &ifspeed)) != 0)
3876 return (status);
3878 if ((ifspeed % 1000000) != 0) {
3879 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX,
3880 "%llf", ifspeed / (float)1000000); /* Mbps */
3881 } else {
3882 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX,
3883 "%llu", ifspeed / 1000000); /* Mbps */
3885 *val_cnt = 1;
3886 *perm_flags = MAC_PROP_PERM_READ;
3887 return (DLADM_STATUS_OK);
3890 /* ARGSUSED */
3891 static dladm_status_t
3892 get_link_state(dladm_handle_t handle, prop_desc_t *pdp,
3893 datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
3894 datalink_media_t media, uint_t flags, uint_t *perm_flags)
3896 link_state_t link_state;
3897 dladm_status_t status;
3899 status = dladm_get_state(handle, linkid, &link_state);
3900 if (status != DLADM_STATUS_OK)
3901 return (status);
3903 switch (link_state) {
3904 case LINK_STATE_UP:
3905 (void) strcpy(*prop_val, "up");
3906 break;
3907 case LINK_STATE_DOWN:
3908 (void) strcpy(*prop_val, "down");
3909 break;
3910 default:
3911 (void) strcpy(*prop_val, "unknown");
3912 break;
3914 *val_cnt = 1;
3915 *perm_flags = MAC_PROP_PERM_READ;
3916 return (DLADM_STATUS_OK);
3919 /* ARGSUSED */
3920 static dladm_status_t
3921 get_binary(dladm_handle_t handle, prop_desc_t *pdp,
3922 datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
3923 datalink_media_t media, uint_t flags, uint_t *perm_flags)
3925 dladm_status_t status;
3926 uint_t v = 0;
3928 status = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags,
3929 perm_flags, &v, sizeof (v));
3930 if (status != DLADM_STATUS_OK)
3931 return (status);
3933 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "%d", (uint_t)(v > 0));
3934 *val_cnt = 1;
3935 return (DLADM_STATUS_OK);
3938 /* ARGSUSED */
3939 static dladm_status_t
3940 get_uint32(dladm_handle_t handle, prop_desc_t *pdp,
3941 datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
3942 datalink_media_t media, uint_t flags, uint_t *perm_flags)
3944 dladm_status_t status;
3945 uint32_t v = 0;
3947 status = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags,
3948 perm_flags, &v, sizeof (v));
3949 if (status != DLADM_STATUS_OK)
3950 return (status);
3952 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "%ld", v);
3953 *val_cnt = 1;
3954 return (DLADM_STATUS_OK);
3957 /* ARGSUSED */
3958 static dladm_status_t
3959 get_range(dladm_handle_t handle, prop_desc_t *pdp,
3960 datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
3961 datalink_media_t media, uint_t flags, uint_t *perm_flags)
3963 dld_ioc_macprop_t *dip;
3964 dladm_status_t status = DLADM_STATUS_OK;
3965 size_t sz;
3966 uint_t rcount;
3967 mac_propval_range_t *rangep;
3970 * As caller we don't know number of value ranges, the driver
3971 * supports. To begin with we assume that number to be 1. If the
3972 * buffer size is insufficient, driver returns back with the
3973 * actual count of value ranges. See mac.h for more details.
3975 sz = sizeof (mac_propval_range_t);
3976 rcount = 1;
3977 retry:
3978 if ((dip = i_dladm_buf_alloc_by_name(sz, linkid, pdp->pd_name, flags,
3979 &status)) == NULL)
3980 return (status);
3982 rangep = (mac_propval_range_t *)(void *)&dip->pr_val;
3983 rangep->mpr_count = rcount;
3985 status = i_dladm_macprop(handle, dip, B_FALSE);
3986 if (status != DLADM_STATUS_OK) {
3987 if (status == DLADM_STATUS_TOOSMALL) {
3988 int err;
3990 if ((err = i_dladm_range_size(rangep, &sz, &rcount))
3991 == 0) {
3992 free(dip);
3993 goto retry;
3994 } else {
3995 status = dladm_errno2status(err);
3998 free(dip);
3999 return (status);
4002 if (rangep->mpr_count == 0) {
4003 *val_cnt = 1;
4004 (void) snprintf(prop_val[0], DLADM_PROP_VAL_MAX, "--");
4005 goto done;
4008 switch (rangep->mpr_type) {
4009 case MAC_PROPVAL_UINT32: {
4010 mac_propval_uint32_range_t *ur;
4011 uint_t count = rangep->mpr_count, i;
4013 ur = &rangep->mpr_range_uint32[0];
4015 for (i = 0; i < count; i++, ur++) {
4016 if (ur->mpur_min == ur->mpur_max) {
4017 (void) snprintf(prop_val[i], DLADM_PROP_VAL_MAX,
4018 "%ld", ur->mpur_min);
4019 } else {
4020 (void) snprintf(prop_val[i], DLADM_PROP_VAL_MAX,
4021 "%ld-%ld", ur->mpur_min, ur->mpur_max);
4024 *val_cnt = count;
4025 break;
4027 default:
4028 status = DLADM_STATUS_BADARG;
4029 break;
4031 done:
4032 free(dip);
4033 return (status);
4036 /* ARGSUSED */
4037 static dladm_status_t
4038 get_tagmode(dladm_handle_t handle, prop_desc_t *pdp,
4039 datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
4040 datalink_media_t media, uint_t flags, uint_t *perm_flags)
4042 link_tagmode_t mode;
4043 dladm_status_t status;
4045 status = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags,
4046 perm_flags, &mode, sizeof (mode));
4047 if (status != DLADM_STATUS_OK)
4048 return (status);
4050 switch (mode) {
4051 case LINK_TAGMODE_NORMAL:
4052 (void) strlcpy(*prop_val, "normal", DLADM_PROP_VAL_MAX);
4053 break;
4054 case LINK_TAGMODE_VLANONLY:
4055 (void) strlcpy(*prop_val, "vlanonly", DLADM_PROP_VAL_MAX);
4056 break;
4057 default:
4058 (void) strlcpy(*prop_val, "unknown", DLADM_PROP_VAL_MAX);
4060 *val_cnt = 1;
4061 return (DLADM_STATUS_OK);
4064 /* ARGSUSED */
4065 static dladm_status_t
4066 get_flowctl(dladm_handle_t handle, prop_desc_t *pdp,
4067 datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
4068 datalink_media_t media, uint_t flags, uint_t *perm_flags)
4070 link_flowctrl_t v;
4071 dladm_status_t status;
4073 status = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags,
4074 perm_flags, &v, sizeof (v));
4075 if (status != DLADM_STATUS_OK)
4076 return (status);
4078 switch (v) {
4079 case LINK_FLOWCTRL_NONE:
4080 (void) sprintf(*prop_val, "no");
4081 break;
4082 case LINK_FLOWCTRL_RX:
4083 (void) sprintf(*prop_val, "rx");
4084 break;
4085 case LINK_FLOWCTRL_TX:
4086 (void) sprintf(*prop_val, "tx");
4087 break;
4088 case LINK_FLOWCTRL_BI:
4089 (void) sprintf(*prop_val, "bi");
4090 break;
4092 *val_cnt = 1;
4093 return (DLADM_STATUS_OK);
4097 /* ARGSUSED */
4098 static dladm_status_t
4099 i_dladm_set_private_prop(dladm_handle_t handle, datalink_id_t linkid,
4100 const char *prop_name, char **prop_val, uint_t val_cnt, uint_t flags)
4103 int i, slen;
4104 int bufsize = 0;
4105 dld_ioc_macprop_t *dip = NULL;
4106 uchar_t *dp;
4107 link_attr_t *p;
4108 dladm_status_t status = DLADM_STATUS_OK;
4110 if ((prop_name == NULL && prop_val != NULL) ||
4111 (prop_val != NULL && val_cnt == 0))
4112 return (DLADM_STATUS_BADARG);
4113 p = dladm_name2prop(prop_name);
4114 if (p->pp_id != MAC_PROP_PRIVATE)
4115 return (DLADM_STATUS_BADARG);
4117 if (!(flags & DLADM_OPT_ACTIVE))
4118 return (DLADM_STATUS_OK);
4121 * private properties: all parsing is done in the kernel.
4122 * allocate a enough space for each property + its separator (',').
4124 for (i = 0; i < val_cnt; i++) {
4125 bufsize += strlen(prop_val[i]) + 1;
4128 if (prop_val == NULL) {
4130 * getting default value. so use more buffer space.
4132 bufsize += DLADM_PROP_BUF_CHUNK;
4135 dip = i_dladm_buf_alloc_by_name(bufsize + 1, linkid, prop_name,
4136 (prop_val != NULL ? 0 : DLD_PROP_DEFAULT), &status);
4137 if (dip == NULL)
4138 return (status);
4140 dp = (uchar_t *)dip->pr_val;
4141 slen = 0;
4143 if (prop_val == NULL) {
4144 status = i_dladm_macprop(handle, dip, B_FALSE);
4145 dip->pr_flags = 0;
4146 } else {
4147 for (i = 0; i < val_cnt; i++) {
4148 int plen = 0;
4150 plen = strlen(prop_val[i]);
4151 bcopy(prop_val[i], dp, plen);
4152 slen += plen;
4154 * add a "," separator and update dp.
4156 if (i != (val_cnt -1))
4157 dp[slen++] = ',';
4158 dp += (plen + 1);
4161 if (status == DLADM_STATUS_OK)
4162 status = i_dladm_macprop(handle, dip, B_TRUE);
4164 free(dip);
4165 return (status);
4168 static dladm_status_t
4169 i_dladm_get_priv_prop(dladm_handle_t handle, datalink_id_t linkid,
4170 const char *prop_name, char **prop_val, uint_t *val_cnt,
4171 dladm_prop_type_t type, uint_t dld_flags)
4173 dladm_status_t status = DLADM_STATUS_OK;
4174 dld_ioc_macprop_t *dip = NULL;
4175 link_attr_t *p;
4177 if ((prop_name == NULL && prop_val != NULL) ||
4178 (prop_val != NULL && val_cnt == 0))
4179 return (DLADM_STATUS_BADARG);
4181 p = dladm_name2prop(prop_name);
4182 if (p->pp_id != MAC_PROP_PRIVATE)
4183 return (DLADM_STATUS_BADARG);
4186 * private properties: all parsing is done in the kernel.
4188 dip = i_dladm_buf_alloc_by_name(DLADM_PROP_BUF_CHUNK, linkid, prop_name,
4189 dld_flags, &status);
4190 if (dip == NULL)
4191 return (status);
4193 if ((status = i_dladm_macprop(handle, dip, B_FALSE)) ==
4194 DLADM_STATUS_OK) {
4195 if (type == DLADM_PROP_VAL_PERM) {
4196 (void) dladm_perm2str(dip->pr_perm_flags, *prop_val);
4197 } else if (type == DLADM_PROP_VAL_MODIFIABLE) {
4198 *prop_val[0] = '\0';
4199 } else {
4200 (void) strncpy(*prop_val, dip->pr_val,
4201 DLADM_PROP_VAL_MAX);
4203 *val_cnt = 1;
4204 } else if ((status == DLADM_STATUS_NOTSUP) &&
4205 (type == DLADM_PROP_VAL_CURRENT)) {
4206 status = DLADM_STATUS_NOTFOUND;
4208 free(dip);
4209 return (status);
4213 static dladm_status_t
4214 i_dladm_getset_defval(dladm_handle_t handle, prop_desc_t *pdp,
4215 datalink_id_t linkid, datalink_media_t media, uint_t flags)
4217 dladm_status_t status;
4218 char **prop_vals = NULL, *buf;
4219 size_t bufsize;
4220 uint_t cnt;
4221 int i;
4222 uint_t perm_flags;
4225 * Allocate buffer needed for prop_vals array. We can have at most
4226 * DLADM_MAX_PROP_VALCNT char *prop_vals[] entries, where
4227 * each entry has max size DLADM_PROP_VAL_MAX
4229 bufsize =
4230 (sizeof (char *) + DLADM_PROP_VAL_MAX) * DLADM_MAX_PROP_VALCNT;
4231 buf = malloc(bufsize);
4232 prop_vals = (char **)(void *)buf;
4233 for (i = 0; i < DLADM_MAX_PROP_VALCNT; i++) {
4234 prop_vals[i] = buf +
4235 sizeof (char *) * DLADM_MAX_PROP_VALCNT +
4236 i * DLADM_PROP_VAL_MAX;
4240 * For properties which have pdp->pd_defval.vd_name as a non-empty
4241 * string, the "" itself is used to reset the property (exceptions
4242 * are zone and autopush, which populate vdp->vd_val). So
4243 * libdladm can copy pdp->pd_defval over to the val_desc_t passed
4244 * down on the setprop using the global values in the table. For
4245 * other cases (vd_name is ""), doing reset-linkprop will cause
4246 * libdladm to do a getprop to find the default value and then do
4247 * a setprop to reset the value to default.
4249 status = pdp->pd_get(handle, pdp, linkid, prop_vals, &cnt, media,
4250 DLD_PROP_DEFAULT, &perm_flags);
4251 if (status == DLADM_STATUS_OK) {
4252 if (perm_flags == MAC_PROP_PERM_RW) {
4253 status = i_dladm_set_single_prop(handle, linkid,
4254 pdp->pd_class, media, pdp, prop_vals, cnt, flags);
4256 else
4257 status = DLADM_STATUS_NOTSUP;
4259 free(buf);
4260 return (status);
4263 /* ARGSUSED */
4264 static dladm_status_t
4265 get_stp(dladm_handle_t handle, struct prop_desc *pd, datalink_id_t linkid,
4266 char **prop_val, uint_t *val_cnt, datalink_media_t media, uint_t flags,
4267 uint_t *perm_flags)
4269 const bridge_public_prop_t *bpp;
4270 dladm_status_t retv;
4271 int val, i;
4273 if (flags != 0)
4274 return (DLADM_STATUS_NOTSUP);
4275 *perm_flags = MAC_PROP_PERM_RW;
4276 *val_cnt = 1;
4277 for (bpp = bridge_prop; bpp->bpp_name != NULL; bpp++)
4278 if (strcmp(bpp->bpp_name, pd->pd_name) == 0)
4279 break;
4280 retv = dladm_bridge_get_port_cfg(handle, linkid, bpp->bpp_code, &val);
4281 /* If the daemon isn't running, then return the persistent value */
4282 if (retv == DLADM_STATUS_NOTFOUND) {
4283 if (i_dladm_get_linkprop_db(handle, linkid, pd->pd_name,
4284 prop_val, val_cnt) != DLADM_STATUS_OK)
4285 (void) strlcpy(*prop_val, pd->pd_defval.vd_name,
4286 DLADM_PROP_VAL_MAX);
4287 return (DLADM_STATUS_OK);
4289 if (retv != DLADM_STATUS_OK) {
4290 (void) strlcpy(*prop_val, "?", DLADM_PROP_VAL_MAX);
4291 return (retv);
4293 if (val == pd->pd_defval.vd_val && pd->pd_defval.vd_name[0] != '\0') {
4294 (void) strlcpy(*prop_val, pd->pd_defval.vd_name,
4295 DLADM_PROP_VAL_MAX);
4296 return (DLADM_STATUS_OK);
4298 for (i = 0; i < pd->pd_noptval; i++) {
4299 if (val == pd->pd_optval[i].vd_val) {
4300 (void) strlcpy(*prop_val, pd->pd_optval[i].vd_name,
4301 DLADM_PROP_VAL_MAX);
4302 return (DLADM_STATUS_OK);
4305 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "%u", (unsigned)val);
4306 return (DLADM_STATUS_OK);
4309 /* ARGSUSED1 */
4310 static dladm_status_t
4311 set_stp_prop(dladm_handle_t handle, prop_desc_t *pd, datalink_id_t linkid,
4312 val_desc_t *vdp, uint_t val_cnt, uint_t flags, datalink_media_t media)
4315 * Special case for mcheck: the daemon resets the value to zero, and we
4316 * don't want the daemon to refresh itself; it leads to deadlock.
4318 if (flags & DLADM_OPT_NOREFRESH)
4319 return (DLADM_STATUS_OK);
4321 /* Tell the running daemon, if any */
4322 return (dladm_bridge_refresh(handle, linkid));
4326 * This is used only for stp_priority, stp_cost, and stp_mcheck.
4328 /* ARGSUSED */
4329 static dladm_status_t
4330 check_stp_prop(dladm_handle_t handle, struct prop_desc *pd,
4331 datalink_id_t linkid, char **prop_val, uint_t *val_cntp, uint_t flags,
4332 val_desc_t **vdpp, datalink_media_t media)
4334 char *cp;
4335 boolean_t iscost;
4336 uint_t val_cnt = *val_cntp;
4337 val_desc_t *vdp = *vdpp;
4339 if (val_cnt != 1)
4340 return (DLADM_STATUS_BADVALCNT);
4342 if (prop_val == NULL) {
4343 vdp->vd_val = 0;
4344 } else {
4345 /* Only stp_priority and stp_cost use this function */
4346 iscost = strcmp(pd->pd_name, "stp_cost") == 0;
4348 if (iscost && strcmp(prop_val[0], "auto") == 0) {
4349 /* Illegal value 0 is allowed to mean "automatic" */
4350 vdp->vd_val = 0;
4351 } else {
4352 errno = 0;
4353 vdp->vd_val = strtoul(prop_val[0], &cp, 0);
4354 if (errno != 0 || *cp != '\0')
4355 return (DLADM_STATUS_BADVAL);
4359 if (iscost) {
4360 return (vdp->vd_val > 65535 ? DLADM_STATUS_BADVAL :
4361 DLADM_STATUS_OK);
4362 } else {
4363 if (vdp->vd_val > 255)
4364 return (DLADM_STATUS_BADVAL);
4366 * If the user is setting stp_mcheck non-zero, then (per the
4367 * IEEE management standards and UNH testing) we need to check
4368 * whether this link is part of a bridge that is running RSTP.
4369 * If it's not, then setting the flag is an error. Note that
4370 * errors are intentionally discarded here; it's the value
4371 * that's the problem -- it's not a bad value, merely one that
4372 * can't be used now.
4374 if (strcmp(pd->pd_name, "stp_mcheck") == 0 &&
4375 vdp->vd_val != 0) {
4376 char bridge[MAXLINKNAMELEN];
4377 UID_STP_CFG_T cfg;
4378 dladm_bridge_prot_t brprot;
4380 if (dladm_bridge_getlink(handle, linkid, bridge,
4381 sizeof (bridge)) != DLADM_STATUS_OK ||
4382 dladm_bridge_get_properties(bridge, &cfg,
4383 &brprot) != DLADM_STATUS_OK)
4384 return (DLADM_STATUS_FAILED);
4385 if (cfg.force_version <= 1)
4386 return (DLADM_STATUS_FAILED);
4388 return (DLADM_STATUS_OK);
4392 /* ARGSUSED */
4393 static dladm_status_t
4394 get_bridge_forward(dladm_handle_t handle, struct prop_desc *pd,
4395 datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
4396 datalink_media_t media, uint_t flags, uint_t *perm_flags)
4398 dladm_status_t retv;
4399 uint_t val;
4401 if (flags != 0)
4402 return (DLADM_STATUS_NOTSUP);
4403 *perm_flags = MAC_PROP_PERM_RW;
4404 *val_cnt = 1;
4405 retv = dladm_bridge_get_forwarding(handle, linkid, &val);
4406 if (retv == DLADM_STATUS_NOTFOUND) {
4407 if (i_dladm_get_linkprop_db(handle, linkid, pd->pd_name,
4408 prop_val, val_cnt) != DLADM_STATUS_OK)
4409 (void) strlcpy(*prop_val, pd->pd_defval.vd_name,
4410 DLADM_PROP_VAL_MAX);
4411 return (DLADM_STATUS_OK);
4413 if (retv == DLADM_STATUS_OK)
4414 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "%u", val);
4415 else
4416 (void) strlcpy(*prop_val, "?", DLADM_PROP_VAL_MAX);
4417 return (retv);
4420 /* ARGSUSED */
4421 static dladm_status_t
4422 set_bridge_forward(dladm_handle_t handle, prop_desc_t *pd, datalink_id_t linkid,
4423 val_desc_t *vdp, uint_t val_cnt, uint_t flags, datalink_media_t media)
4425 /* Tell the running daemon, if any */
4426 return (dladm_bridge_refresh(handle, linkid));
4429 /* ARGSUSED */
4430 static dladm_status_t
4431 get_bridge_pvid(dladm_handle_t handle, struct prop_desc *pd,
4432 datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
4433 datalink_media_t media, uint_t flags, uint_t *perm_flags)
4435 dladm_status_t status;
4436 dld_ioc_macprop_t *dip;
4437 uint16_t pvid;
4439 if (flags != 0)
4440 return (DLADM_STATUS_NOTSUP);
4441 *perm_flags = MAC_PROP_PERM_RW;
4442 *val_cnt = 1;
4443 dip = i_dladm_buf_alloc_by_id(sizeof (uint16_t), linkid, MAC_PROP_PVID,
4444 0, &status);
4445 if (dip == NULL)
4446 return (status);
4447 status = i_dladm_macprop(handle, dip, B_FALSE);
4448 if (status == DLADM_STATUS_OK) {
4449 (void) memcpy(&pvid, dip->pr_val, sizeof (pvid));
4450 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "%u", pvid);
4451 } else {
4452 (void) strlcpy(*prop_val, "?", DLADM_PROP_VAL_MAX);
4454 free(dip);
4455 return (status);
4458 /* ARGSUSED */
4459 static dladm_status_t
4460 set_bridge_pvid(dladm_handle_t handle, prop_desc_t *pd, datalink_id_t linkid,
4461 val_desc_t *vdp, uint_t val_cnt, uint_t flags, datalink_media_t media)
4463 dladm_status_t status;
4464 dld_ioc_macprop_t *dip;
4465 uint16_t pvid;
4467 dip = i_dladm_buf_alloc_by_id(sizeof (uint16_t), linkid, MAC_PROP_PVID,
4468 0, &status);
4469 if (dip == NULL)
4470 return (status);
4471 pvid = vdp->vd_val;
4472 (void) memcpy(dip->pr_val, &pvid, sizeof (pvid));
4473 status = i_dladm_macprop(handle, dip, B_TRUE);
4474 free(dip);
4475 if (status != DLADM_STATUS_OK)
4476 return (status);
4478 /* Tell the running daemon, if any */
4479 return (dladm_bridge_refresh(handle, linkid));
4482 /* ARGSUSED */
4483 static dladm_status_t
4484 check_bridge_pvid(dladm_handle_t handle, struct prop_desc *pd,
4485 datalink_id_t linkid, char **prop_val, uint_t *val_cntp, uint_t flags,
4486 val_desc_t **vdpp, datalink_media_t media)
4488 char *cp;
4489 uint_t val_cnt = *val_cntp;
4490 val_desc_t *vdp = *vdpp;
4492 if (val_cnt != 1)
4493 return (DLADM_STATUS_BADVALCNT);
4495 if (prop_val == NULL) {
4496 vdp->vd_val = 1;
4497 } else {
4498 errno = 0;
4499 vdp->vd_val = strtoul(prop_val[0], &cp, 0);
4500 if (errno != 0 || *cp != '\0')
4501 return (DLADM_STATUS_BADVAL);
4504 return (vdp->vd_val > VLAN_ID_MAX ? DLADM_STATUS_BADVAL :
4505 DLADM_STATUS_OK);
4508 dladm_status_t
4509 i_dladm_wlan_param(dladm_handle_t handle, datalink_id_t linkid, void *buf,
4510 mac_prop_id_t cmd, size_t len, boolean_t set)
4512 uint32_t flags;
4513 dladm_status_t status;
4514 uint32_t media;
4515 dld_ioc_macprop_t *dip;
4516 void *dp;
4518 if ((status = dladm_datalink_id2info(handle, linkid, &flags, NULL,
4519 &media, NULL, 0)) != DLADM_STATUS_OK) {
4520 return (status);
4523 if (media != DL_WIFI)
4524 return (DLADM_STATUS_BADARG);
4526 if (!(flags & DLADM_OPT_ACTIVE))
4527 return (DLADM_STATUS_TEMPONLY);
4529 if (len == (MAX_BUF_LEN - WIFI_BUF_OFFSET))
4530 len = MAX_BUF_LEN - sizeof (dld_ioc_macprop_t) - 1;
4532 dip = i_dladm_buf_alloc_by_id(len, linkid, cmd, 0, &status);
4533 if (dip == NULL)
4534 return (DLADM_STATUS_NOMEM);
4536 dp = (uchar_t *)dip->pr_val;
4537 if (set)
4538 (void) memcpy(dp, buf, len);
4540 status = i_dladm_macprop(handle, dip, set);
4541 if (status == DLADM_STATUS_OK) {
4542 if (!set)
4543 (void) memcpy(buf, dp, len);
4546 free(dip);
4547 return (status);
4550 dladm_status_t
4551 dladm_parse_link_props(char *str, dladm_arg_list_t **listp, boolean_t novalues)
4553 return (dladm_parse_args(str, listp, novalues));
4557 * Retrieve the one link property from the database
4559 /*ARGSUSED*/
4560 static int
4561 i_dladm_get_one_prop(dladm_handle_t handle, datalink_id_t linkid,
4562 const char *prop_name, void *arg)
4564 dladm_arg_list_t *proplist = arg;
4565 dladm_arg_info_t *aip = NULL;
4567 aip = &proplist->al_info[proplist->al_count];
4569 * it is fine to point to prop_name since prop_name points to the
4570 * prop_table[n].pd_name.
4572 aip->ai_name = prop_name;
4574 (void) dladm_get_linkprop(handle, linkid, DLADM_PROP_VAL_PERSISTENT,
4575 prop_name, aip->ai_val, &aip->ai_count);
4577 if (aip->ai_count != 0)
4578 proplist->al_count++;
4580 return (DLADM_WALK_CONTINUE);
4585 * Retrieve all link properties for a link from the database and
4586 * return a property list.
4588 dladm_status_t
4589 dladm_link_get_proplist(dladm_handle_t handle, datalink_id_t linkid,
4590 dladm_arg_list_t **listp)
4592 dladm_arg_list_t *list;
4593 dladm_status_t status = DLADM_STATUS_OK;
4595 list = calloc(1, sizeof (dladm_arg_list_t));
4596 if (list == NULL)
4597 return (dladm_errno2status(errno));
4599 status = dladm_walk_linkprop(handle, linkid, list,
4600 i_dladm_get_one_prop);
4602 *listp = list;
4603 return (status);
4607 * Retrieve the named property from a proplist, check the value and
4608 * convert to a kernel structure.
4610 static dladm_status_t
4611 i_dladm_link_proplist_extract_one(dladm_handle_t handle,
4612 dladm_arg_list_t *proplist, const char *name, uint_t flags, void *arg)
4614 dladm_status_t status;
4615 dladm_arg_info_t *aip = NULL;
4616 int i, j;
4618 /* Find named property in proplist */
4619 for (i = 0; i < proplist->al_count; i++) {
4620 aip = &proplist->al_info[i];
4621 if (strcasecmp(aip->ai_name, name) == 0)
4622 break;
4625 /* Property not in list */
4626 if (i == proplist->al_count)
4627 return (DLADM_STATUS_OK);
4629 for (i = 0; i < DLADM_MAX_PROPS; i++) {
4630 prop_desc_t *pdp = &prop_table[i];
4631 val_desc_t *vdp;
4633 vdp = malloc(sizeof (val_desc_t) * aip->ai_count);
4634 if (vdp == NULL)
4635 return (DLADM_STATUS_NOMEM);
4637 if (strcasecmp(aip->ai_name, pdp->pd_name) != 0)
4638 continue;
4640 if (aip->ai_val == NULL)
4641 return (DLADM_STATUS_BADARG);
4643 /* Check property value */
4644 if (pdp->pd_check != NULL) {
4645 status = pdp->pd_check(handle, pdp, 0, aip->ai_val,
4646 &(aip->ai_count), flags, &vdp, 0);
4647 } else {
4648 status = DLADM_STATUS_BADARG;
4651 if (status != DLADM_STATUS_OK)
4652 return (status);
4654 for (j = 0; j < DLADM_MAX_RSRC_PROP; j++) {
4655 resource_prop_t *rpp = &rsrc_prop_table[j];
4657 if (strcasecmp(aip->ai_name, rpp->rp_name) != 0)
4658 continue;
4660 /* Extract kernel structure */
4661 if (rpp->rp_extract != NULL) {
4662 status = rpp->rp_extract(vdp,
4663 aip->ai_count, arg);
4664 } else {
4665 status = DLADM_STATUS_BADARG;
4667 break;
4670 if (status != DLADM_STATUS_OK)
4671 return (status);
4673 break;
4675 return (status);
4679 * Extract properties from a proplist and convert to mac_resource_props_t.
4681 dladm_status_t
4682 dladm_link_proplist_extract(dladm_handle_t handle, dladm_arg_list_t *proplist,
4683 mac_resource_props_t *mrp, uint_t flags)
4685 dladm_status_t status;
4686 int i;
4688 for (i = 0; i < DLADM_MAX_RSRC_PROP; i++) {
4689 status = i_dladm_link_proplist_extract_one(handle,
4690 proplist, rsrc_prop_table[i].rp_name, flags, mrp);
4691 if (status != DLADM_STATUS_OK)
4692 return (status);
4694 return (status);
4697 static const char *
4698 dladm_perm2str(uint_t perm, char *buf)
4700 (void) snprintf(buf, DLADM_STRSIZE, "%c%c",
4701 ((perm & MAC_PROP_PERM_READ) != 0) ? 'r' : '-',
4702 ((perm & MAC_PROP_PERM_WRITE) != 0) ? 'w' : '-');
4703 return (buf);
4706 dladm_status_t
4707 dladm_get_state(dladm_handle_t handle, datalink_id_t linkid,
4708 link_state_t *state)
4710 uint_t perms;
4712 return (i_dladm_get_public_prop(handle, linkid, "state", 0,
4713 &perms, state, sizeof (*state)));
4716 boolean_t
4717 dladm_attr_is_linkprop(const char *name)
4719 /* non-property attribute names */
4720 const char *nonprop[] = {
4721 /* dlmgmtd core attributes */
4722 "name",
4723 "class",
4724 "media",
4725 FPHYMAJ,
4726 FPHYINST,
4727 FDEVNAME,
4729 /* other attributes for vlan, aggr, etc */
4730 DLADM_ATTR_NAMES
4732 boolean_t is_nonprop = B_FALSE;
4733 int i;
4735 for (i = 0; i < sizeof (nonprop) / sizeof (nonprop[0]); i++) {
4736 if (strcmp(name, nonprop[i]) == 0) {
4737 is_nonprop = B_TRUE;
4738 break;
4742 return (!is_nonprop);
4745 dladm_status_t
4746 dladm_linkprop_is_set(dladm_handle_t handle, datalink_id_t linkid,
4747 dladm_prop_type_t type, const char *prop_name, boolean_t *is_set)
4749 char *buf, **propvals;
4750 uint_t valcnt = DLADM_MAX_PROP_VALCNT;
4751 int i;
4752 dladm_status_t status = DLADM_STATUS_OK;
4753 size_t bufsize;
4755 *is_set = B_FALSE;
4757 bufsize = (sizeof (char *) + DLADM_PROP_VAL_MAX) *
4758 DLADM_MAX_PROP_VALCNT;
4759 if ((buf = calloc(1, bufsize)) == NULL)
4760 return (DLADM_STATUS_NOMEM);
4762 propvals = (char **)(void *)buf;
4763 for (i = 0; i < valcnt; i++) {
4764 propvals[i] = buf +
4765 sizeof (char *) * DLADM_MAX_PROP_VALCNT +
4766 i * DLADM_PROP_VAL_MAX;
4769 if (dladm_get_linkprop(handle, linkid, type, prop_name, propvals,
4770 &valcnt) != DLADM_STATUS_OK) {
4771 goto done;
4775 * valcnt is always set to 1 by get_pool(), hence we need to check
4776 * for a non-null string to see if it is set. For protection,
4777 * secondary-macs and allowed-ips, we can check either the *propval
4778 * or the valcnt.
4780 if ((strcmp(prop_name, "pool") == 0 ||
4781 strcmp(prop_name, "protection") == 0 ||
4782 strcmp(prop_name, "secondary-macs") == 0 ||
4783 strcmp(prop_name, "allowed-ips") == 0) &&
4784 (strlen(*propvals) != 0)) {
4785 *is_set = B_TRUE;
4786 } else if ((strcmp(prop_name, "cpus") == 0) && (valcnt != 0)) {
4787 *is_set = B_TRUE;
4788 } else if ((strcmp(prop_name, "_softmac") == 0) && (valcnt != 0) &&
4789 (strcmp(propvals[0], "true") == 0)) {
4790 *is_set = B_TRUE;
4793 done:
4794 if (buf != NULL)
4795 free(buf);
4796 return (status);
4799 /* ARGSUSED */
4800 static dladm_status_t
4801 get_linkmode_prop(dladm_handle_t handle, prop_desc_t *pdp,
4802 datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
4803 datalink_media_t media, uint_t flags, uint_t *perm_flags)
4805 char *s;
4806 uint32_t v;
4807 dladm_status_t status;
4809 status = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags,
4810 perm_flags, &v, sizeof (v));
4811 if (status != DLADM_STATUS_OK)
4812 return (status);
4814 switch (v) {
4815 case DLADM_PART_CM_MODE:
4816 s = "cm";
4817 break;
4818 case DLADM_PART_UD_MODE:
4819 s = "ud";
4820 break;
4821 default:
4822 s = "";
4823 break;
4825 (void) snprintf(prop_val[0], DLADM_STRSIZE, "%s", s);
4827 *val_cnt = 1;
4828 return (DLADM_STATUS_OK);