8354 sync regcomp(3C) with upstream (fix make catalog)
[unleashed/tickless.git] / usr / src / lib / libdladm / common / linkprop.c
blob342584b48833f033f699a86363daef2160872e1b
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 2016 Joyent, Inc.
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,
158 get_promisc_filtered;
160 static pd_setf_t set_zone, set_rate, set_powermode, set_radio,
161 set_public_prop, set_resource, set_stp_prop,
162 set_bridge_forward, set_bridge_pvid, set_secondary_macs,
163 set_promisc_filtered;
165 static pd_checkf_t check_zone, check_autopush, check_rate, check_hoplimit,
166 check_encaplim, check_uint32, check_maxbw, check_cpus,
167 check_stp_prop, check_bridge_pvid, check_allowedips,
168 check_allowedcids, check_secondary_macs, check_rings,
169 check_pool, check_prop;
171 struct prop_desc {
173 * link property name
175 char *pd_name;
178 * default property value, can be set to { "", NULL }
180 val_desc_t pd_defval;
183 * list of optional property values, can be NULL.
185 * This is set to non-NULL if there is a list of possible property
186 * values. pd_optval would point to the array of possible values.
188 val_desc_t *pd_optval;
191 * count of the above optional property values. 0 if pd_optval is NULL.
193 uint_t pd_noptval;
196 * callback to set link property; set to NULL if this property is
197 * read-only and may be called before or after permanent update; see
198 * flags.
200 pd_setf_t *pd_set;
203 * callback to get modifiable link property
205 pd_getf_t *pd_getmod;
208 * callback to get current link property
210 pd_getf_t *pd_get;
213 * callback to validate link property value, set to NULL if pd_optval
214 * is not NULL. In that case, validate the value by comparing it with
215 * the pd_optval. Return a val_desc_t array pointer if the value is
216 * valid.
218 pd_checkf_t *pd_check;
220 uint_t pd_flags;
221 #define PD_TEMPONLY 0x1 /* property is temporary only */
222 #define PD_CHECK_ALLOC 0x2 /* alloc vd_val as part of pd_check */
223 #define PD_AFTER_PERM 0x4 /* pd_set after db update; no temporary */
225 * indicate link classes this property applies to.
227 datalink_class_t pd_class;
230 * indicate link media type this property applies to.
232 datalink_media_t pd_dmedia;
235 #define MAC_PROP_BUFSIZE(v) sizeof (dld_ioc_macprop_t) + (v) - 1
238 * Supported link properties enumerated in the prop_table[] array are
239 * computed using the callback functions in that array. To compute the
240 * property value, multiple distinct system calls may be needed (e.g.,
241 * for wifi speed, we need to issue system calls to get desired/supported
242 * rates). The link_attr[] table enumerates the interfaces to the kernel,
243 * and the type/size of the data passed in the user-kernel interface.
245 static link_attr_t link_attr[] = {
246 { MAC_PROP_DUPLEX, sizeof (link_duplex_t), "duplex"},
248 { MAC_PROP_SPEED, sizeof (uint64_t), "speed"},
250 { MAC_PROP_STATUS, sizeof (link_state_t), "state"},
252 { MAC_PROP_AUTONEG, sizeof (uint8_t), "adv_autoneg_cap"},
254 { MAC_PROP_MTU, sizeof (uint32_t), "mtu"},
256 { MAC_PROP_FLOWCTRL, sizeof (link_flowctrl_t), "flowctrl"},
258 { MAC_PROP_ZONE, sizeof (dld_ioc_zid_t), "zone"},
260 { MAC_PROP_AUTOPUSH, sizeof (struct dlautopush), "autopush"},
262 { MAC_PROP_ADV_5000FDX_CAP, sizeof (uint8_t), "adv_5000fdx_cap"},
264 { MAC_PROP_EN_5000FDX_CAP, sizeof (uint8_t), "en_5000fdx_cap"},
266 { MAC_PROP_ADV_2500FDX_CAP, sizeof (uint8_t), "adv_2500fdx_cap"},
268 { MAC_PROP_EN_2500FDX_CAP, sizeof (uint8_t), "en_2500fdx_cap"},
270 { MAC_PROP_ADV_100GFDX_CAP, sizeof (uint8_t), "adv_100gfdx_cap"},
272 { MAC_PROP_EN_100GFDX_CAP, sizeof (uint8_t), "en_100gfdx_cap"},
274 { MAC_PROP_ADV_50GFDX_CAP, sizeof (uint8_t), "adv_50gfdx_cap"},
276 { MAC_PROP_EN_50GFDX_CAP, sizeof (uint8_t), "en_50gfdx_cap"},
278 { MAC_PROP_ADV_40GFDX_CAP, sizeof (uint8_t), "adv_40gfdx_cap"},
280 { MAC_PROP_EN_40GFDX_CAP, sizeof (uint8_t), "en_40gfdx_cap"},
282 { MAC_PROP_ADV_25GFDX_CAP, sizeof (uint8_t), "adv_25gfdx_cap"},
284 { MAC_PROP_EN_25GFDX_CAP, sizeof (uint8_t), "en_25gfdx_cap"},
286 { MAC_PROP_ADV_10GFDX_CAP, sizeof (uint8_t), "adv_10gfdx_cap"},
288 { MAC_PROP_EN_10GFDX_CAP, sizeof (uint8_t), "en_10gfdx_cap"},
290 { MAC_PROP_ADV_1000FDX_CAP, sizeof (uint8_t), "adv_1000fdx_cap"},
292 { MAC_PROP_EN_1000FDX_CAP, sizeof (uint8_t), "en_1000fdx_cap"},
294 { MAC_PROP_ADV_1000HDX_CAP, sizeof (uint8_t), "adv_1000hdx_cap"},
296 { MAC_PROP_EN_1000HDX_CAP, sizeof (uint8_t), "en_1000hdx_cap"},
298 { MAC_PROP_ADV_100FDX_CAP, sizeof (uint8_t), "adv_100fdx_cap"},
300 { MAC_PROP_EN_100FDX_CAP, sizeof (uint8_t), "en_100fdx_cap"},
302 { MAC_PROP_ADV_100HDX_CAP, sizeof (uint8_t), "adv_100hdx_cap"},
304 { MAC_PROP_EN_100HDX_CAP, sizeof (uint8_t), "en_100hdx_cap"},
306 { MAC_PROP_ADV_10FDX_CAP, sizeof (uint8_t), "adv_10fdx_cap"},
308 { MAC_PROP_EN_10FDX_CAP, sizeof (uint8_t), "en_10fdx_cap"},
310 { MAC_PROP_ADV_10HDX_CAP, sizeof (uint8_t), "adv_10hdx_cap"},
312 { MAC_PROP_EN_10HDX_CAP, sizeof (uint8_t), "en_10hdx_cap"},
314 { MAC_PROP_WL_ESSID, sizeof (wl_linkstatus_t), "essid"},
316 { MAC_PROP_WL_BSSID, sizeof (wl_bssid_t), "bssid"},
318 { MAC_PROP_WL_BSSTYPE, sizeof (wl_bss_type_t), "bsstype"},
320 { MAC_PROP_WL_LINKSTATUS, sizeof (wl_linkstatus_t), "wl_linkstatus"},
322 /* wl_rates_t has variable length */
323 { MAC_PROP_WL_DESIRED_RATES, sizeof (wl_rates_t), "desired_rates"},
325 /* wl_rates_t has variable length */
326 { MAC_PROP_WL_SUPPORTED_RATES, sizeof (wl_rates_t), "supported_rates"},
328 { MAC_PROP_WL_AUTH_MODE, sizeof (wl_authmode_t), "authmode"},
330 { MAC_PROP_WL_ENCRYPTION, sizeof (wl_encryption_t), "encryption"},
332 { MAC_PROP_WL_RSSI, sizeof (wl_rssi_t), "signal"},
334 { MAC_PROP_WL_PHY_CONFIG, sizeof (wl_phy_conf_t), "phy_conf"},
336 { MAC_PROP_WL_CAPABILITY, sizeof (wl_capability_t), "capability"},
338 { MAC_PROP_WL_WPA, sizeof (wl_wpa_t), "wpa"},
340 /* wl_wpa_ess_t has variable length */
341 { MAC_PROP_WL_SCANRESULTS, sizeof (wl_wpa_ess_t), "scan_results"},
343 { MAC_PROP_WL_POWER_MODE, sizeof (wl_ps_mode_t), "powermode"},
345 { MAC_PROP_WL_RADIO, sizeof (dladm_wlan_radio_t), "wl_radio"},
347 { MAC_PROP_WL_ESS_LIST, sizeof (wl_ess_list_t), "wl_ess_list"},
349 { MAC_PROP_WL_KEY_TAB, sizeof (wl_wep_key_tab_t), "wl_wep_key"},
351 { MAC_PROP_WL_CREATE_IBSS, sizeof (wl_create_ibss_t), "createibss"},
353 /* wl_wpa_ie_t has variable length */
354 { MAC_PROP_WL_SETOPTIE, sizeof (wl_wpa_ie_t), "set_ie"},
356 { MAC_PROP_WL_DELKEY, sizeof (wl_del_key_t), "wpa_del_key"},
358 { MAC_PROP_WL_KEY, sizeof (wl_key_t), "wl_key"},
360 { MAC_PROP_WL_MLME, sizeof (wl_mlme_t), "mlme"},
362 { MAC_PROP_TAGMODE, sizeof (link_tagmode_t), "tagmode"},
364 { MAC_PROP_IPTUN_HOPLIMIT, sizeof (uint32_t), "hoplimit"},
366 { MAC_PROP_IPTUN_ENCAPLIMIT, sizeof (uint32_t), "encaplimit"},
368 { MAC_PROP_PVID, sizeof (uint16_t), "default_tag"},
370 { MAC_PROP_LLIMIT, sizeof (uint32_t), "learn_limit"},
372 { MAC_PROP_LDECAY, sizeof (uint32_t), "learn_decay"},
374 { MAC_PROP_RESOURCE, sizeof (mac_resource_props_t), "resource"},
376 { MAC_PROP_RESOURCE_EFF, sizeof (mac_resource_props_t),
377 "resource-effective"},
379 { MAC_PROP_RXRINGSRANGE, sizeof (mac_propval_range_t), "rxrings"},
381 { MAC_PROP_TXRINGSRANGE, sizeof (mac_propval_range_t), "txrings"},
383 { MAC_PROP_MAX_TX_RINGS_AVAIL, sizeof (uint_t),
384 "txrings-available"},
386 { MAC_PROP_MAX_RX_RINGS_AVAIL, sizeof (uint_t),
387 "rxrings-available"},
389 { MAC_PROP_MAX_RXHWCLNT_AVAIL, sizeof (uint_t), "rxhwclnt-available"},
391 { MAC_PROP_MAX_TXHWCLNT_AVAIL, sizeof (uint_t), "txhwclnt-available"},
393 { MAC_PROP_IB_LINKMODE, sizeof (uint32_t), "linkmode"},
395 { MAC_PROP_VN_PROMISC_FILTERED, sizeof (boolean_t), "promisc-filtered"},
397 { MAC_PROP_SECONDARY_ADDRS, sizeof (mac_secondary_addr_t),
398 "secondary-macs"},
400 { MAC_PROP_PRIVATE, 0, "driver-private"}
403 typedef struct bridge_public_prop_s {
404 const char *bpp_name;
405 int bpp_code;
406 } bridge_public_prop_t;
408 static const bridge_public_prop_t bridge_prop[] = {
409 { "stp", PT_CFG_NON_STP },
410 { "stp_priority", PT_CFG_PRIO },
411 { "stp_cost", PT_CFG_COST },
412 { "stp_edge", PT_CFG_EDGE },
413 { "stp_p2p", PT_CFG_P2P },
414 { "stp_mcheck", PT_CFG_MCHECK },
415 { NULL, 0 }
418 static val_desc_t link_duplex_vals[] = {
419 { "half", LINK_DUPLEX_HALF },
420 { "full", LINK_DUPLEX_HALF }
422 static val_desc_t link_status_vals[] = {
423 { "up", LINK_STATE_UP },
424 { "down", LINK_STATE_DOWN }
426 static val_desc_t link_01_vals[] = {
427 { "1", 1 },
428 { "0", 0 }
430 static val_desc_t link_flow_vals[] = {
431 { "no", LINK_FLOWCTRL_NONE },
432 { "tx", LINK_FLOWCTRL_TX },
433 { "rx", LINK_FLOWCTRL_RX },
434 { "bi", LINK_FLOWCTRL_BI }
436 static val_desc_t link_priority_vals[] = {
437 { "low", MPL_LOW },
438 { "medium", MPL_MEDIUM },
439 { "high", MPL_HIGH }
442 static val_desc_t link_tagmode_vals[] = {
443 { "normal", LINK_TAGMODE_NORMAL },
444 { "vlanonly", LINK_TAGMODE_VLANONLY }
447 static val_desc_t link_protect_vals[] = {
448 { "mac-nospoof", MPT_MACNOSPOOF },
449 { "restricted", MPT_RESTRICTED },
450 { "ip-nospoof", MPT_IPNOSPOOF },
451 { "dhcp-nospoof", MPT_DHCPNOSPOOF },
454 static val_desc_t link_promisc_filtered_vals[] = {
455 { "off", B_FALSE },
456 { "on", B_TRUE },
459 static val_desc_t dladm_wlan_radio_vals[] = {
460 { "on", DLADM_WLAN_RADIO_ON },
461 { "off", DLADM_WLAN_RADIO_OFF }
464 static val_desc_t dladm_wlan_powermode_vals[] = {
465 { "off", DLADM_WLAN_PM_OFF },
466 { "fast", DLADM_WLAN_PM_FAST },
467 { "max", DLADM_WLAN_PM_MAX }
470 static val_desc_t stp_p2p_vals[] = {
471 { "true", P2P_FORCE_TRUE },
472 { "false", P2P_FORCE_FALSE },
473 { "auto", P2P_AUTO }
476 static val_desc_t dladm_part_linkmode_vals[] = {
477 { "cm", DLADM_PART_CM_MODE },
478 { "ud", DLADM_PART_UD_MODE },
481 #define VALCNT(vals) (sizeof ((vals)) / sizeof (val_desc_t))
482 #define RESET_VAL ((uintptr_t)-1)
483 #define UNSPEC_VAL ((uintptr_t)-2)
486 * For the default, if defaults are not defined for the property,
487 * pd_defval.vd_name should be null. If the driver has to be contacted for the
488 * value, vd_name should be the empty string (""). Otherwise, dladm will
489 * just print whatever is in the table.
491 static prop_desc_t prop_table[] = {
492 { "channel", { NULL, 0 },
493 NULL, 0, NULL, NULL,
494 get_channel, NULL, 0,
495 DATALINK_CLASS_PHYS, DL_WIFI },
497 { "powermode", { "off", DLADM_WLAN_PM_OFF },
498 dladm_wlan_powermode_vals, VALCNT(dladm_wlan_powermode_vals),
499 set_powermode, NULL,
500 get_powermode, NULL, 0,
501 DATALINK_CLASS_PHYS, DL_WIFI },
503 { "radio", { "on", DLADM_WLAN_RADIO_ON },
504 dladm_wlan_radio_vals, VALCNT(dladm_wlan_radio_vals),
505 set_radio, NULL,
506 get_radio, NULL, 0,
507 DATALINK_CLASS_PHYS, DL_WIFI },
509 { "linkmode", { "cm", DLADM_PART_CM_MODE },
510 dladm_part_linkmode_vals, VALCNT(dladm_part_linkmode_vals),
511 set_public_prop, NULL, get_linkmode_prop, NULL, 0,
512 DATALINK_CLASS_PART, DL_IB },
514 { "speed", { "", 0 }, NULL, 0,
515 set_rate, get_rate_mod,
516 get_rate, check_rate, 0,
517 DATALINK_CLASS_PHYS, DATALINK_ANY_MEDIATYPE },
519 { "autopush", { "", 0 }, NULL, 0,
520 set_public_prop, NULL,
521 get_autopush, check_autopush, PD_CHECK_ALLOC,
522 DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
524 { "zone", { "", 0 }, NULL, 0,
525 set_zone, NULL,
526 get_zone, check_zone, PD_TEMPONLY|PD_CHECK_ALLOC,
527 DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
529 { "duplex", { "", 0 },
530 link_duplex_vals, VALCNT(link_duplex_vals),
531 NULL, NULL, get_duplex, NULL,
532 0, DATALINK_CLASS_PHYS, DL_ETHER },
534 { "state", { "up", LINK_STATE_UP },
535 link_status_vals, VALCNT(link_status_vals),
536 NULL, NULL, get_link_state, NULL,
537 0, DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
539 { "adv_autoneg_cap", { "", 0 },
540 link_01_vals, VALCNT(link_01_vals),
541 set_public_prop, NULL, get_binary, NULL,
542 0, DATALINK_CLASS_PHYS, DL_ETHER },
544 { "mtu", { "", 0 }, NULL, 0,
545 set_public_prop, get_range,
546 get_uint32, check_uint32, 0, DATALINK_CLASS_ALL,
547 DATALINK_ANY_MEDIATYPE },
549 { "flowctrl", { "", 0 },
550 link_flow_vals, VALCNT(link_flow_vals),
551 set_public_prop, NULL, get_flowctl, NULL,
552 0, DATALINK_CLASS_PHYS, DL_ETHER },
554 { "secondary-macs", { "--", 0 }, NULL, 0,
555 set_secondary_macs, NULL,
556 get_secondary_macs, check_secondary_macs, PD_CHECK_ALLOC,
557 DATALINK_CLASS_VNIC, DL_ETHER },
559 { "adv_100gfdx_cap", { "", 0 },
560 link_01_vals, VALCNT(link_01_vals),
561 NULL, NULL, get_binary, NULL,
562 0, DATALINK_CLASS_PHYS, DL_ETHER },
564 { "en_100gfdx_cap", { "", 0 },
565 link_01_vals, VALCNT(link_01_vals),
566 set_public_prop, NULL, get_binary, NULL,
567 0, DATALINK_CLASS_PHYS, DL_ETHER },
569 { "adv_50gfdx_cap", { "", 0 },
570 link_01_vals, VALCNT(link_01_vals),
571 NULL, NULL, get_binary, NULL,
572 0, DATALINK_CLASS_PHYS, DL_ETHER },
574 { "en_50gfdx_cap", { "", 0 },
575 link_01_vals, VALCNT(link_01_vals),
576 set_public_prop, NULL, get_binary, NULL,
577 0, DATALINK_CLASS_PHYS, DL_ETHER },
579 { "adv_40gfdx_cap", { "", 0 },
580 link_01_vals, VALCNT(link_01_vals),
581 NULL, NULL, get_binary, NULL,
582 0, DATALINK_CLASS_PHYS, DL_ETHER },
584 { "en_40gfdx_cap", { "", 0 },
585 link_01_vals, VALCNT(link_01_vals),
586 set_public_prop, NULL, get_binary, NULL,
587 0, DATALINK_CLASS_PHYS, DL_ETHER },
589 { "adv_25gfdx_cap", { "", 0 },
590 link_01_vals, VALCNT(link_01_vals),
591 NULL, NULL, get_binary, NULL,
592 0, DATALINK_CLASS_PHYS, DL_ETHER },
594 { "en_25gfdx_cap", { "", 0 },
595 link_01_vals, VALCNT(link_01_vals),
596 set_public_prop, NULL, get_binary, NULL,
597 0, DATALINK_CLASS_PHYS, DL_ETHER },
599 { "adv_10gfdx_cap", { "", 0 },
600 link_01_vals, VALCNT(link_01_vals),
601 NULL, NULL, get_binary, NULL,
602 0, DATALINK_CLASS_PHYS, DL_ETHER },
604 { "en_10gfdx_cap", { "", 0 },
605 link_01_vals, VALCNT(link_01_vals),
606 set_public_prop, NULL, get_binary, NULL,
607 0, DATALINK_CLASS_PHYS, DL_ETHER },
609 { "adv_5000fdx_cap", { "", 0 },
610 link_01_vals, VALCNT(link_01_vals),
611 NULL, NULL, get_binary, NULL,
612 0, DATALINK_CLASS_PHYS, DL_ETHER },
614 { "en_5000fdx_cap", { "", 0 },
615 link_01_vals, VALCNT(link_01_vals),
616 set_public_prop, NULL, get_binary, NULL,
617 0, DATALINK_CLASS_PHYS, DL_ETHER },
619 { "adv_2500fdx_cap", { "", 0 },
620 link_01_vals, VALCNT(link_01_vals),
621 NULL, NULL, get_binary, NULL,
622 0, DATALINK_CLASS_PHYS, DL_ETHER },
624 { "en_2500fdx_cap", { "", 0 },
625 link_01_vals, VALCNT(link_01_vals),
626 set_public_prop, NULL, get_binary, NULL,
627 0, DATALINK_CLASS_PHYS, DL_ETHER },
629 { "adv_1000fdx_cap", { "", 0 },
630 link_01_vals, VALCNT(link_01_vals),
631 NULL, NULL, get_binary, NULL,
632 0, DATALINK_CLASS_PHYS, DL_ETHER },
634 { "en_1000fdx_cap", { "", 0 },
635 link_01_vals, VALCNT(link_01_vals),
636 set_public_prop, NULL, get_binary, NULL,
637 0, DATALINK_CLASS_PHYS, DL_ETHER },
639 { "adv_1000hdx_cap", { "", 0 },
640 link_01_vals, VALCNT(link_01_vals),
641 NULL, NULL, get_binary, NULL,
642 0, DATALINK_CLASS_PHYS, DL_ETHER },
644 { "en_1000hdx_cap", { "", 0 },
645 link_01_vals, VALCNT(link_01_vals),
646 set_public_prop, NULL, get_binary, NULL,
647 0, DATALINK_CLASS_PHYS, DL_ETHER },
649 { "adv_100fdx_cap", { "", 0 },
650 link_01_vals, VALCNT(link_01_vals),
651 NULL, NULL, get_binary, NULL,
652 0, DATALINK_CLASS_PHYS, DL_ETHER },
654 { "en_100fdx_cap", { "", 0 },
655 link_01_vals, VALCNT(link_01_vals),
656 set_public_prop, NULL, get_binary, NULL,
657 0, DATALINK_CLASS_PHYS, DL_ETHER },
659 { "adv_100hdx_cap", { "", 0 },
660 link_01_vals, VALCNT(link_01_vals),
661 NULL, NULL, get_binary, NULL,
662 0, DATALINK_CLASS_PHYS, DL_ETHER },
664 { "en_100hdx_cap", { "", 0 },
665 link_01_vals, VALCNT(link_01_vals),
666 set_public_prop, NULL, get_binary, NULL,
667 0, DATALINK_CLASS_PHYS, DL_ETHER },
669 { "adv_10fdx_cap", { "", 0 },
670 link_01_vals, VALCNT(link_01_vals),
671 NULL, NULL, get_binary, NULL,
672 0, DATALINK_CLASS_PHYS, DL_ETHER },
674 { "en_10fdx_cap", { "", 0 },
675 link_01_vals, VALCNT(link_01_vals),
676 set_public_prop, NULL, get_binary, NULL,
677 0, DATALINK_CLASS_PHYS, DL_ETHER },
679 { "adv_10hdx_cap", { "", 0 },
680 link_01_vals, VALCNT(link_01_vals),
681 NULL, NULL, get_binary, NULL,
682 0, DATALINK_CLASS_PHYS, DL_ETHER },
684 { "en_10hdx_cap", { "", 0 },
685 link_01_vals, VALCNT(link_01_vals),
686 set_public_prop, NULL, get_binary, NULL,
687 0, DATALINK_CLASS_PHYS, DL_ETHER },
689 { "maxbw", { "--", RESET_VAL }, NULL, 0,
690 set_resource, NULL,
691 get_maxbw, check_maxbw, PD_CHECK_ALLOC,
692 DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
694 { "cpus", { "--", RESET_VAL }, NULL, 0,
695 set_resource, NULL,
696 get_cpus, check_cpus, 0,
697 DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
699 { "cpus-effective", { "--", 0 },
700 NULL, 0, NULL, NULL,
701 get_cpus, 0, 0,
702 DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
704 { "pool", { "--", RESET_VAL }, NULL, 0,
705 set_resource, NULL,
706 get_pool, check_pool, 0,
707 DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
709 { "pool-effective", { "--", 0 },
710 NULL, 0, NULL, NULL,
711 get_pool, 0, 0,
712 DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
714 { "priority", { "high", MPL_RESET },
715 link_priority_vals, VALCNT(link_priority_vals), set_resource,
716 NULL, get_priority, check_prop, 0,
717 DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
719 { "tagmode", { "vlanonly", LINK_TAGMODE_VLANONLY },
720 link_tagmode_vals, VALCNT(link_tagmode_vals),
721 set_public_prop, NULL, get_tagmode,
722 NULL, 0,
723 DATALINK_CLASS_PHYS | DATALINK_CLASS_AGGR | DATALINK_CLASS_VNIC,
724 DL_ETHER },
726 { "hoplimit", { "", 0 }, NULL, 0,
727 set_public_prop, get_range, get_uint32,
728 check_hoplimit, 0, DATALINK_CLASS_IPTUN, DATALINK_ANY_MEDIATYPE},
730 { "encaplimit", { "", 0 }, NULL, 0,
731 set_public_prop, get_range, get_uint32,
732 check_encaplim, 0, DATALINK_CLASS_IPTUN, DL_IPV6},
734 { "forward", { "1", 1 },
735 link_01_vals, VALCNT(link_01_vals),
736 set_bridge_forward, NULL, get_bridge_forward, NULL, PD_AFTER_PERM,
737 DATALINK_CLASS_ALL & ~DATALINK_CLASS_VNIC, DL_ETHER },
739 { "default_tag", { "1", 1 }, NULL, 0,
740 set_bridge_pvid, NULL, get_bridge_pvid, check_bridge_pvid,
741 0, DATALINK_CLASS_PHYS|DATALINK_CLASS_AGGR|
742 DATALINK_CLASS_ETHERSTUB|DATALINK_CLASS_SIMNET, DL_ETHER },
744 { "learn_limit", { "1000", 1000 }, NULL, 0,
745 set_public_prop, NULL, get_uint32,
746 check_uint32, 0,
747 DATALINK_CLASS_PHYS|DATALINK_CLASS_AGGR|
748 DATALINK_CLASS_ETHERSTUB|DATALINK_CLASS_SIMNET, DL_ETHER },
750 { "learn_decay", { "200", 200 }, NULL, 0,
751 set_public_prop, NULL, get_uint32,
752 check_uint32, 0,
753 DATALINK_CLASS_PHYS|DATALINK_CLASS_AGGR|
754 DATALINK_CLASS_ETHERSTUB|DATALINK_CLASS_SIMNET, DL_ETHER },
756 { "stp", { "1", 1 },
757 link_01_vals, VALCNT(link_01_vals),
758 set_stp_prop, NULL, get_stp, NULL, PD_AFTER_PERM,
759 DATALINK_CLASS_PHYS|DATALINK_CLASS_AGGR|
760 DATALINK_CLASS_ETHERSTUB|DATALINK_CLASS_SIMNET, DL_ETHER },
762 { "stp_priority", { "128", 128 }, NULL, 0,
763 set_stp_prop, NULL, get_stp, check_stp_prop, PD_AFTER_PERM,
764 DATALINK_CLASS_PHYS|DATALINK_CLASS_AGGR|
765 DATALINK_CLASS_ETHERSTUB|DATALINK_CLASS_SIMNET, DL_ETHER },
767 { "stp_cost", { "auto", 0 }, NULL, 0,
768 set_stp_prop, NULL, get_stp, check_stp_prop, PD_AFTER_PERM,
769 DATALINK_CLASS_PHYS|DATALINK_CLASS_AGGR|
770 DATALINK_CLASS_ETHERSTUB|DATALINK_CLASS_SIMNET, DL_ETHER },
772 { "stp_edge", { "1", 1 },
773 link_01_vals, VALCNT(link_01_vals),
774 set_stp_prop, NULL, get_stp, NULL, PD_AFTER_PERM,
775 DATALINK_CLASS_PHYS|DATALINK_CLASS_AGGR|
776 DATALINK_CLASS_ETHERSTUB|DATALINK_CLASS_SIMNET, DL_ETHER },
778 { "stp_p2p", { "auto", P2P_AUTO },
779 stp_p2p_vals, VALCNT(stp_p2p_vals),
780 set_stp_prop, NULL, get_stp, NULL, PD_AFTER_PERM,
781 DATALINK_CLASS_PHYS|DATALINK_CLASS_AGGR|
782 DATALINK_CLASS_ETHERSTUB|DATALINK_CLASS_SIMNET, DL_ETHER },
784 { "stp_mcheck", { "0", 0 },
785 link_01_vals, VALCNT(link_01_vals),
786 set_stp_prop, NULL, get_stp, check_stp_prop, PD_AFTER_PERM,
787 DATALINK_CLASS_PHYS|DATALINK_CLASS_AGGR|
788 DATALINK_CLASS_ETHERSTUB|DATALINK_CLASS_SIMNET, DL_ETHER },
790 { "protection", { "--", RESET_VAL },
791 link_protect_vals, VALCNT(link_protect_vals),
792 set_resource, NULL, get_protection, check_prop, 0,
793 DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
795 { "promisc-filtered", { "on", 1 },
796 link_promisc_filtered_vals, VALCNT(link_promisc_filtered_vals),
797 set_promisc_filtered, NULL, get_promisc_filtered, check_prop, 0,
798 DATALINK_CLASS_VNIC, DATALINK_ANY_MEDIATYPE },
801 { "allowed-ips", { "--", 0 },
802 NULL, 0, set_resource, NULL,
803 get_allowedips, check_allowedips, PD_CHECK_ALLOC,
804 DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
806 { "allowed-dhcp-cids", { "--", 0 },
807 NULL, 0, set_resource, NULL,
808 get_allowedcids, check_allowedcids, PD_CHECK_ALLOC,
809 DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
811 { "rxrings", { "--", RESET_VAL }, NULL, 0,
812 set_resource, get_rings_range, get_rxrings, check_rings, 0,
813 DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
815 { "rxrings-effective", { "--", 0 },
816 NULL, 0, NULL, NULL,
817 get_rxrings, NULL, 0,
818 DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
820 { "txrings", { "--", RESET_VAL }, NULL, 0,
821 set_resource, get_rings_range, get_txrings, check_rings, 0,
822 DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
824 { "txrings-effective", { "--", 0 },
825 NULL, 0, NULL, NULL,
826 get_txrings, NULL, 0,
827 DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
829 { "txrings-available", { "", 0 }, NULL, 0,
830 NULL, NULL, get_cntavail, NULL, 0,
831 DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
833 { "rxrings-available", { "", 0 }, NULL, 0,
834 NULL, NULL, get_cntavail, NULL, 0,
835 DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
837 { "rxhwclnt-available", { "", 0 }, NULL, 0,
838 NULL, NULL, get_cntavail, NULL, 0,
839 DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
841 { "txhwclnt-available", { "", 0 }, NULL, 0,
842 NULL, NULL, get_cntavail, NULL, 0,
843 DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
847 #define DLADM_MAX_PROPS (sizeof (prop_table) / sizeof (prop_desc_t))
849 static resource_prop_t rsrc_prop_table[] = {
850 {"maxbw", extract_maxbw},
851 {"priority", extract_priority},
852 {"cpus", extract_cpus},
853 {"cpus-effective", extract_cpus},
854 {"pool", extract_pool},
855 {"pool-effective", extract_pool},
856 {"protection", extract_protection},
857 {"allowed-ips", extract_allowedips},
858 {"allowed-dhcp-cids", extract_allowedcids},
859 {"rxrings", extract_rxrings},
860 {"rxrings-effective", extract_rxrings},
861 {"txrings", extract_txrings},
862 {"txrings-effective", extract_txrings}
864 #define DLADM_MAX_RSRC_PROP (sizeof (rsrc_prop_table) / \
865 sizeof (resource_prop_t))
868 * when retrieving private properties, we pass down a buffer with
869 * DLADM_PROP_BUF_CHUNK of space for the driver to return the property value.
871 #define DLADM_PROP_BUF_CHUNK 1024
873 static dladm_status_t i_dladm_set_linkprop_db(dladm_handle_t, datalink_id_t,
874 const char *, char **, uint_t);
875 static dladm_status_t i_dladm_get_linkprop_db(dladm_handle_t, datalink_id_t,
876 const char *, char **, uint_t *);
877 static dladm_status_t i_dladm_walk_linkprop_priv_db(dladm_handle_t,
878 datalink_id_t, void *, int (*)(dladm_handle_t,
879 datalink_id_t, const char *, void *));
880 static dladm_status_t i_dladm_set_single_prop(dladm_handle_t, datalink_id_t,
881 datalink_class_t, uint32_t, prop_desc_t *, char **,
882 uint_t, uint_t);
883 static dladm_status_t i_dladm_set_linkprop(dladm_handle_t, datalink_id_t,
884 const char *, char **, uint_t, uint_t);
885 static dladm_status_t i_dladm_getset_defval(dladm_handle_t, prop_desc_t *,
886 datalink_id_t, datalink_media_t, uint_t);
889 * Unfortunately, MAX_SCAN_SUPPORT_RATES is too small to allow all
890 * rates to be retrieved. However, we cannot increase it at this
891 * time because it will break binary compatibility with unbundled
892 * WiFi drivers and utilities. So for now we define an additional
893 * constant, MAX_SUPPORT_RATES, to allow all rates to be retrieved.
895 #define MAX_SUPPORT_RATES 64
897 #define AP_ANCHOR "[anchor]"
898 #define AP_DELIMITER '.'
900 /* ARGSUSED */
901 static dladm_status_t
902 check_prop(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
903 char **prop_val, uint_t *val_cntp, uint_t flags, val_desc_t **vdpp,
904 datalink_media_t media)
906 int i, j;
907 uint_t val_cnt = *val_cntp;
908 val_desc_t *vdp = *vdpp;
910 for (j = 0; j < val_cnt; j++) {
911 for (i = 0; i < pdp->pd_noptval; i++) {
912 if (strcasecmp(prop_val[j],
913 pdp->pd_optval[i].vd_name) == 0) {
914 break;
917 if (i == pdp->pd_noptval)
918 return (DLADM_STATUS_BADVAL);
920 (void) memcpy(&vdp[j], &pdp->pd_optval[i], sizeof (val_desc_t));
922 return (DLADM_STATUS_OK);
925 static dladm_status_t
926 i_dladm_set_single_prop(dladm_handle_t handle, datalink_id_t linkid,
927 datalink_class_t class, uint32_t media, prop_desc_t *pdp, char **prop_val,
928 uint_t val_cnt, uint_t flags)
930 dladm_status_t status = DLADM_STATUS_OK;
931 val_desc_t *vdp = NULL;
932 boolean_t needfree = B_FALSE;
933 uint_t cnt, i;
935 if (!(pdp->pd_class & class))
936 return (DLADM_STATUS_BADARG);
938 if (!DATALINK_MEDIA_ACCEPTED(pdp->pd_dmedia, media))
939 return (DLADM_STATUS_BADARG);
941 if ((flags & DLADM_OPT_PERSIST) && (pdp->pd_flags & PD_TEMPONLY))
942 return (DLADM_STATUS_TEMPONLY);
944 if (!(flags & DLADM_OPT_ACTIVE))
945 return (DLADM_STATUS_OK);
947 if (pdp->pd_set == NULL)
948 return (DLADM_STATUS_PROPRDONLY);
950 if (prop_val != NULL) {
951 vdp = calloc(val_cnt, sizeof (val_desc_t));
952 if (vdp == NULL)
953 return (DLADM_STATUS_NOMEM);
955 if (pdp->pd_check != NULL) {
956 needfree = ((pdp->pd_flags & PD_CHECK_ALLOC) != 0);
957 status = pdp->pd_check(handle, pdp, linkid, prop_val,
958 &val_cnt, flags, &vdp, media);
959 } else if (pdp->pd_optval != NULL) {
960 status = check_prop(handle, pdp, linkid, prop_val,
961 &val_cnt, flags, &vdp, media);
962 } else {
963 status = DLADM_STATUS_BADARG;
966 if (status != DLADM_STATUS_OK)
967 goto done;
969 cnt = val_cnt;
970 } else {
971 boolean_t defval;
973 if (pdp->pd_defval.vd_name == NULL)
974 return (DLADM_STATUS_NOTSUP);
976 cnt = 1;
977 defval = (strlen(pdp->pd_defval.vd_name) > 0);
978 if ((pdp->pd_flags & PD_CHECK_ALLOC) == 0 && !defval) {
979 status = i_dladm_getset_defval(handle, pdp, linkid,
980 media, flags);
981 return (status);
984 vdp = calloc(1, sizeof (val_desc_t));
985 if (vdp == NULL)
986 return (DLADM_STATUS_NOMEM);
988 if (defval) {
989 (void) memcpy(vdp, &pdp->pd_defval,
990 sizeof (val_desc_t));
991 } else if (pdp->pd_check != NULL) {
992 needfree = ((pdp->pd_flags & PD_CHECK_ALLOC) != 0);
993 status = pdp->pd_check(handle, pdp, linkid, prop_val,
994 &cnt, flags, &vdp, media);
995 if (status != DLADM_STATUS_OK)
996 goto done;
999 if (pdp->pd_flags & PD_AFTER_PERM)
1000 status = (flags & DLADM_OPT_PERSIST) ? DLADM_STATUS_OK :
1001 DLADM_STATUS_PERMONLY;
1002 else
1003 status = pdp->pd_set(handle, pdp, linkid, vdp, cnt, flags,
1004 media);
1005 if (needfree) {
1006 for (i = 0; i < cnt; i++)
1007 free((void *)((val_desc_t *)vdp + i)->vd_val);
1009 done:
1010 free(vdp);
1011 return (status);
1014 static dladm_status_t
1015 i_dladm_set_linkprop(dladm_handle_t handle, datalink_id_t linkid,
1016 const char *prop_name, char **prop_val, uint_t val_cnt, uint_t flags)
1018 int i;
1019 boolean_t found = B_FALSE;
1020 datalink_class_t class;
1021 uint32_t media;
1022 dladm_status_t status = DLADM_STATUS_OK;
1024 status = dladm_datalink_id2info(handle, linkid, NULL, &class, &media,
1025 NULL, 0);
1026 if (status != DLADM_STATUS_OK)
1027 return (status);
1029 for (i = 0; i < DLADM_MAX_PROPS; i++) {
1030 prop_desc_t *pdp = &prop_table[i];
1031 dladm_status_t s;
1033 if (prop_name != NULL &&
1034 (strcasecmp(prop_name, pdp->pd_name) != 0))
1035 continue;
1036 found = B_TRUE;
1037 s = i_dladm_set_single_prop(handle, linkid, class, media, pdp,
1038 prop_val, val_cnt, flags);
1040 if (prop_name != NULL) {
1041 status = s;
1042 break;
1043 } else {
1044 if (s != DLADM_STATUS_OK &&
1045 s != DLADM_STATUS_NOTSUP)
1046 status = s;
1049 if (!found) {
1050 if (prop_name[0] == '_') {
1051 /* other private properties */
1052 status = i_dladm_set_private_prop(handle, linkid,
1053 prop_name, prop_val, val_cnt, flags);
1054 } else {
1055 status = DLADM_STATUS_NOTFOUND;
1058 return (status);
1062 * Set/reset link property for specific link
1064 dladm_status_t
1065 dladm_set_linkprop(dladm_handle_t handle, datalink_id_t linkid,
1066 const char *prop_name, char **prop_val, uint_t val_cnt, uint_t flags)
1068 dladm_status_t status = DLADM_STATUS_OK;
1070 if ((linkid == DATALINK_INVALID_LINKID) || (flags == 0) ||
1071 (prop_val == NULL && val_cnt > 0) ||
1072 (prop_val != NULL && val_cnt == 0) ||
1073 (prop_name == NULL && prop_val != NULL)) {
1074 return (DLADM_STATUS_BADARG);
1078 * Check for valid link property against the flags passed
1079 * and set the link property when active flag is passed.
1081 status = i_dladm_set_linkprop(handle, linkid, prop_name, prop_val,
1082 val_cnt, flags);
1083 if (status != DLADM_STATUS_OK)
1084 return (status);
1086 if (flags & DLADM_OPT_PERSIST) {
1087 status = i_dladm_set_linkprop_db(handle, linkid, prop_name,
1088 prop_val, val_cnt);
1090 if (status == DLADM_STATUS_OK && (flags & DLADM_OPT_ACTIVE)) {
1091 prop_desc_t *pdp = prop_table;
1092 int i;
1094 for (i = 0; i < DLADM_MAX_PROPS; i++, pdp++) {
1095 if (!(pdp->pd_flags & PD_AFTER_PERM))
1096 continue;
1097 if (prop_name != NULL &&
1098 strcasecmp(prop_name, pdp->pd_name) != 0)
1099 continue;
1100 status = pdp->pd_set(handle, pdp, linkid, NULL,
1101 0, flags, 0);
1105 return (status);
1109 * Walk all link properties of the given specific link.
1111 * Note: this function currently lacks the ability to walk _all_ private
1112 * properties if the link, because there is no kernel interface to
1113 * retrieve all known private property names. Once such an interface
1114 * is added, this function should be fixed accordingly.
1116 dladm_status_t
1117 dladm_walk_linkprop(dladm_handle_t handle, datalink_id_t linkid, void *arg,
1118 int (*func)(dladm_handle_t, datalink_id_t, const char *, void *))
1120 dladm_status_t status;
1121 datalink_class_t class;
1122 uint_t media;
1123 int i;
1125 if (linkid == DATALINK_INVALID_LINKID || func == NULL)
1126 return (DLADM_STATUS_BADARG);
1128 status = dladm_datalink_id2info(handle, linkid, NULL, &class, &media,
1129 NULL, 0);
1130 if (status != DLADM_STATUS_OK)
1131 return (status);
1133 /* public */
1134 for (i = 0; i < DLADM_MAX_PROPS; i++) {
1135 if (!(prop_table[i].pd_class & class))
1136 continue;
1138 if (!DATALINK_MEDIA_ACCEPTED(prop_table[i].pd_dmedia, media))
1139 continue;
1141 if (func(handle, linkid, prop_table[i].pd_name, arg) ==
1142 DLADM_WALK_TERMINATE) {
1143 break;
1147 /* private */
1148 status = i_dladm_walk_linkprop_priv_db(handle, linkid, arg, func);
1150 return (status);
1154 * Get linkprop of the given specific link.
1156 dladm_status_t
1157 dladm_get_linkprop(dladm_handle_t handle, datalink_id_t linkid,
1158 dladm_prop_type_t type, const char *prop_name, char **prop_val,
1159 uint_t *val_cntp)
1161 dladm_status_t status = DLADM_STATUS_OK;
1162 datalink_class_t class;
1163 uint_t media;
1164 prop_desc_t *pdp;
1165 uint_t cnt, dld_flags = 0;
1166 int i;
1167 uint_t perm_flags;
1169 if (type == DLADM_PROP_VAL_DEFAULT)
1170 dld_flags |= DLD_PROP_DEFAULT;
1171 else if (type == DLADM_PROP_VAL_MODIFIABLE)
1172 dld_flags |= DLD_PROP_POSSIBLE;
1174 if (linkid == DATALINK_INVALID_LINKID || prop_name == NULL ||
1175 prop_val == NULL || val_cntp == NULL || *val_cntp == 0)
1176 return (DLADM_STATUS_BADARG);
1178 for (i = 0; i < DLADM_MAX_PROPS; i++)
1179 if (strcasecmp(prop_name, prop_table[i].pd_name) == 0)
1180 break;
1182 if (i == DLADM_MAX_PROPS) {
1183 if (prop_name[0] == '_') {
1185 * private property.
1187 if (type == DLADM_PROP_VAL_PERSISTENT)
1188 return (i_dladm_get_linkprop_db(handle, linkid,
1189 prop_name, prop_val, val_cntp));
1190 else
1191 return (i_dladm_get_priv_prop(handle, linkid,
1192 prop_name, prop_val, val_cntp, type,
1193 dld_flags));
1194 } else {
1195 return (DLADM_STATUS_NOTFOUND);
1199 pdp = &prop_table[i];
1201 status = dladm_datalink_id2info(handle, linkid, NULL, &class, &media,
1202 NULL, 0);
1203 if (status != DLADM_STATUS_OK)
1204 return (status);
1206 if (!(pdp->pd_class & class))
1207 return (DLADM_STATUS_BADARG);
1209 if (!DATALINK_MEDIA_ACCEPTED(pdp->pd_dmedia, media))
1210 return (DLADM_STATUS_BADARG);
1212 switch (type) {
1213 case DLADM_PROP_VAL_CURRENT:
1214 status = pdp->pd_get(handle, pdp, linkid, prop_val, val_cntp,
1215 media, dld_flags, &perm_flags);
1216 break;
1218 case DLADM_PROP_VAL_PERM:
1219 if (pdp->pd_set == NULL) {
1220 perm_flags = MAC_PROP_PERM_READ;
1221 } else {
1222 status = pdp->pd_get(handle, pdp, linkid, prop_val,
1223 val_cntp, media, dld_flags, &perm_flags);
1226 *prop_val[0] = '\0';
1227 *val_cntp = 1;
1228 if (status == DLADM_STATUS_OK)
1229 (void) dladm_perm2str(perm_flags, *prop_val);
1230 break;
1232 case DLADM_PROP_VAL_DEFAULT:
1234 * If defaults are not defined for the property,
1235 * pd_defval.vd_name should be null. If the driver
1236 * has to be contacted for the value, vd_name should
1237 * be the empty string (""). Otherwise, dladm will
1238 * just print whatever is in the table.
1240 if (pdp->pd_defval.vd_name == NULL) {
1241 status = DLADM_STATUS_NOTSUP;
1242 break;
1245 if (strlen(pdp->pd_defval.vd_name) == 0) {
1246 status = pdp->pd_get(handle, pdp, linkid, prop_val,
1247 val_cntp, media, dld_flags, &perm_flags);
1248 } else {
1249 (void) strcpy(*prop_val, pdp->pd_defval.vd_name);
1251 *val_cntp = 1;
1252 break;
1254 case DLADM_PROP_VAL_MODIFIABLE:
1255 if (pdp->pd_getmod != NULL) {
1256 status = pdp->pd_getmod(handle, pdp, linkid, prop_val,
1257 val_cntp, media, dld_flags, &perm_flags);
1258 break;
1260 cnt = pdp->pd_noptval;
1261 if (cnt == 0) {
1262 status = DLADM_STATUS_NOTSUP;
1263 } else if (cnt > *val_cntp) {
1264 status = DLADM_STATUS_TOOSMALL;
1265 } else {
1266 for (i = 0; i < cnt; i++) {
1267 (void) strcpy(prop_val[i],
1268 pdp->pd_optval[i].vd_name);
1270 *val_cntp = cnt;
1272 break;
1273 case DLADM_PROP_VAL_PERSISTENT:
1274 if (pdp->pd_flags & PD_TEMPONLY)
1275 return (DLADM_STATUS_TEMPONLY);
1276 status = i_dladm_get_linkprop_db(handle, linkid, prop_name,
1277 prop_val, val_cntp);
1278 break;
1279 default:
1280 status = DLADM_STATUS_BADARG;
1281 break;
1284 return (status);
1288 * Get linkprop of the given specific link and run any possible conversion
1289 * of the values using the check function for the property. Fails if the
1290 * check function doesn't succeed for the property value.
1292 dladm_status_t
1293 dladm_get_linkprop_values(dladm_handle_t handle, datalink_id_t linkid,
1294 dladm_prop_type_t type, const char *prop_name, uint_t *ret_val,
1295 uint_t *val_cntp)
1297 dladm_status_t status;
1298 datalink_class_t class;
1299 uint_t media;
1300 prop_desc_t *pdp;
1301 uint_t dld_flags;
1302 int valc, i;
1303 char **prop_val;
1304 uint_t perm_flags;
1306 if (linkid == DATALINK_INVALID_LINKID || prop_name == NULL ||
1307 ret_val == NULL || val_cntp == NULL || *val_cntp == 0)
1308 return (DLADM_STATUS_BADARG);
1310 for (pdp = prop_table; pdp < prop_table + DLADM_MAX_PROPS; pdp++)
1311 if (strcasecmp(prop_name, pdp->pd_name) == 0)
1312 break;
1314 if (pdp == prop_table + DLADM_MAX_PROPS)
1315 return (DLADM_STATUS_NOTFOUND);
1317 if (pdp->pd_flags & PD_CHECK_ALLOC)
1318 return (DLADM_STATUS_BADARG);
1320 status = dladm_datalink_id2info(handle, linkid, NULL, &class, &media,
1321 NULL, 0);
1322 if (status != DLADM_STATUS_OK)
1323 return (status);
1325 if (!(pdp->pd_class & class))
1326 return (DLADM_STATUS_BADARG);
1328 if (!DATALINK_MEDIA_ACCEPTED(pdp->pd_dmedia, media))
1329 return (DLADM_STATUS_BADARG);
1331 prop_val = malloc(*val_cntp * sizeof (*prop_val) +
1332 *val_cntp * DLADM_PROP_VAL_MAX);
1333 if (prop_val == NULL)
1334 return (DLADM_STATUS_NOMEM);
1335 for (valc = 0; valc < *val_cntp; valc++)
1336 prop_val[valc] = (char *)(prop_val + *val_cntp) +
1337 valc * DLADM_PROP_VAL_MAX;
1339 dld_flags = (type == DLADM_PROP_VAL_DEFAULT) ? DLD_PROP_DEFAULT : 0;
1341 switch (type) {
1342 case DLADM_PROP_VAL_CURRENT:
1343 status = pdp->pd_get(handle, pdp, linkid, prop_val, val_cntp,
1344 media, dld_flags, &perm_flags);
1345 break;
1347 case DLADM_PROP_VAL_DEFAULT:
1349 * If defaults are not defined for the property,
1350 * pd_defval.vd_name should be null. If the driver
1351 * has to be contacted for the value, vd_name should
1352 * be the empty string (""). Otherwise, dladm will
1353 * just print whatever is in the table.
1355 if (pdp->pd_defval.vd_name == NULL) {
1356 status = DLADM_STATUS_NOTSUP;
1357 break;
1360 if (pdp->pd_defval.vd_name[0] != '\0') {
1361 *val_cntp = 1;
1362 *ret_val = pdp->pd_defval.vd_val;
1363 free(prop_val);
1364 return (DLADM_STATUS_OK);
1366 status = pdp->pd_get(handle, pdp, linkid, prop_val, val_cntp,
1367 media, dld_flags, &perm_flags);
1368 break;
1370 case DLADM_PROP_VAL_PERSISTENT:
1371 if (pdp->pd_flags & PD_TEMPONLY)
1372 status = DLADM_STATUS_TEMPONLY;
1373 else
1374 status = i_dladm_get_linkprop_db(handle, linkid,
1375 prop_name, prop_val, val_cntp);
1376 break;
1378 default:
1379 status = DLADM_STATUS_BADARG;
1380 break;
1383 if (status == DLADM_STATUS_OK) {
1384 if (pdp->pd_check != NULL) {
1385 val_desc_t *vdp;
1387 vdp = malloc(sizeof (val_desc_t) * *val_cntp);
1388 if (vdp == NULL)
1389 status = DLADM_STATUS_NOMEM;
1390 else
1391 status = pdp->pd_check(handle, pdp, linkid,
1392 prop_val, val_cntp, 0, &vdp, media);
1393 if (status == DLADM_STATUS_OK) {
1394 for (valc = 0; valc < *val_cntp; valc++)
1395 ret_val[valc] = vdp[valc].vd_val;
1397 free(vdp);
1398 } else {
1399 for (valc = 0; valc < *val_cntp; valc++) {
1400 for (i = 0; i < pdp->pd_noptval; i++) {
1401 if (strcmp(pdp->pd_optval[i].vd_name,
1402 prop_val[valc]) == 0) {
1403 ret_val[valc] =
1404 pdp->pd_optval[i].vd_val;
1405 break;
1408 if (i == pdp->pd_noptval) {
1409 status = DLADM_STATUS_FAILED;
1410 break;
1416 free(prop_val);
1418 return (status);
1421 /*ARGSUSED*/
1422 static int
1423 i_dladm_init_one_prop(dladm_handle_t handle, datalink_id_t linkid,
1424 const char *prop_name, void *arg)
1426 char *buf, **propvals;
1427 uint_t i, valcnt = DLADM_MAX_PROP_VALCNT;
1428 dladm_status_t status;
1429 dladm_linkprop_args_t *dla = arg;
1431 if ((buf = malloc((sizeof (char *) + DLADM_PROP_VAL_MAX) *
1432 DLADM_MAX_PROP_VALCNT)) == NULL) {
1433 return (DLADM_WALK_CONTINUE);
1436 propvals = (char **)(void *)buf;
1437 for (i = 0; i < valcnt; i++) {
1438 propvals[i] = buf +
1439 sizeof (char *) * DLADM_MAX_PROP_VALCNT +
1440 i * DLADM_PROP_VAL_MAX;
1443 if (dladm_get_linkprop(handle, linkid, DLADM_PROP_VAL_PERSISTENT,
1444 prop_name, propvals, &valcnt) != DLADM_STATUS_OK) {
1445 goto done;
1448 status = dladm_set_linkprop(handle, linkid, prop_name, propvals,
1449 valcnt, dla->dla_flags | DLADM_OPT_ACTIVE);
1451 if (status != DLADM_STATUS_OK)
1452 dla->dla_status = status;
1454 done:
1455 if (buf != NULL)
1456 free(buf);
1458 return (DLADM_WALK_CONTINUE);
1461 /*ARGSUSED*/
1462 static int
1463 i_dladm_init_linkprop(dladm_handle_t handle, datalink_id_t linkid, void *arg)
1465 datalink_class_t class;
1466 dladm_status_t status;
1468 status = dladm_datalink_id2info(handle, linkid, NULL, &class, NULL,
1469 NULL, 0);
1470 if (status != DLADM_STATUS_OK)
1471 return (DLADM_WALK_TERMINATE);
1473 if ((class & (DATALINK_CLASS_VNIC | DATALINK_CLASS_VLAN)) == 0)
1474 (void) dladm_init_linkprop(handle, linkid, B_TRUE);
1476 return (DLADM_WALK_CONTINUE);
1479 dladm_status_t
1480 dladm_init_linkprop(dladm_handle_t handle, datalink_id_t linkid,
1481 boolean_t any_media)
1483 dladm_status_t status = DLADM_STATUS_OK;
1484 datalink_media_t dmedia;
1485 uint32_t media;
1486 dladm_linkprop_args_t *dla;
1488 dmedia = any_media ? DATALINK_ANY_MEDIATYPE : DL_WIFI;
1490 dla = malloc(sizeof (dladm_linkprop_args_t));
1491 if (dla == NULL)
1492 return (DLADM_STATUS_NOMEM);
1493 dla->dla_flags = DLADM_OPT_BOOT;
1494 dla->dla_status = DLADM_STATUS_OK;
1496 if (linkid == DATALINK_ALL_LINKID) {
1497 (void) dladm_walk_datalink_id(i_dladm_init_linkprop, handle,
1498 NULL, DATALINK_CLASS_ALL, dmedia, DLADM_OPT_PERSIST);
1499 } else if (any_media ||
1500 ((dladm_datalink_id2info(handle, linkid, NULL, NULL, &media, NULL,
1501 0) == DLADM_STATUS_OK) &&
1502 DATALINK_MEDIA_ACCEPTED(dmedia, media))) {
1503 (void) dladm_walk_linkprop(handle, linkid, (void *)dla,
1504 i_dladm_init_one_prop);
1505 status = dla->dla_status;
1507 free(dla);
1508 return (status);
1511 /* ARGSUSED */
1512 static dladm_status_t
1513 get_zone(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
1514 char **prop_val, uint_t *val_cnt, datalink_media_t media,
1515 uint_t flags, uint_t *perm_flags)
1517 char zone_name[ZONENAME_MAX];
1518 zoneid_t zid;
1519 dladm_status_t status;
1521 if (flags != 0)
1522 return (DLADM_STATUS_NOTSUP);
1524 status = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags,
1525 perm_flags, &zid, sizeof (zid));
1526 if (status != DLADM_STATUS_OK)
1527 return (status);
1529 *val_cnt = 1;
1530 if (zid != GLOBAL_ZONEID) {
1531 if (getzonenamebyid(zid, zone_name, sizeof (zone_name)) < 0) {
1532 return (dladm_errno2status(errno));
1535 (void) strncpy(*prop_val, zone_name, DLADM_PROP_VAL_MAX);
1536 } else {
1537 *prop_val[0] = '\0';
1540 return (DLADM_STATUS_OK);
1543 typedef int (*zone_get_devroot_t)(char *, char *, size_t);
1545 static int
1546 i_dladm_get_zone_dev(char *zone_name, char *dev, size_t devlen)
1548 char root[MAXPATHLEN];
1549 zone_get_devroot_t real_zone_get_devroot;
1550 void *dlhandle;
1551 void *sym;
1552 int ret;
1554 if ((dlhandle = dlopen("libzonecfg.so.1", RTLD_LAZY)) == NULL)
1555 return (-1);
1557 if ((sym = dlsym(dlhandle, "zone_get_devroot")) == NULL) {
1558 (void) dlclose(dlhandle);
1559 return (-1);
1562 real_zone_get_devroot = (zone_get_devroot_t)sym;
1564 if ((ret = real_zone_get_devroot(zone_name, root, sizeof (root))) == 0)
1565 (void) snprintf(dev, devlen, "%s%s", root, "/dev");
1566 (void) dlclose(dlhandle);
1567 return (ret);
1570 static dladm_status_t
1571 i_dladm_update_deventry(dladm_handle_t handle, zoneid_t zid,
1572 datalink_id_t linkid, boolean_t add)
1574 char path[MAXPATHLEN];
1575 char name[MAXLINKNAMELEN];
1576 di_prof_t prof = NULL;
1577 char zone_name[ZONENAME_MAX];
1578 dladm_status_t status;
1579 int ret;
1581 if (getzonenamebyid(zid, zone_name, sizeof (zone_name)) < 0)
1582 return (dladm_errno2status(errno));
1583 if (i_dladm_get_zone_dev(zone_name, path, sizeof (path)) != 0)
1584 return (dladm_errno2status(errno));
1585 if (di_prof_init(path, &prof) != 0)
1586 return (dladm_errno2status(errno));
1588 status = dladm_linkid2legacyname(handle, linkid, name, MAXLINKNAMELEN);
1589 if (status != DLADM_STATUS_OK)
1590 goto cleanup;
1592 if (add)
1593 ret = di_prof_add_dev(prof, name);
1594 else
1595 ret = di_prof_add_exclude(prof, name);
1597 if (ret != 0) {
1598 status = dladm_errno2status(errno);
1599 goto cleanup;
1602 if (di_prof_commit(prof) != 0)
1603 status = dladm_errno2status(errno);
1604 cleanup:
1605 if (prof)
1606 di_prof_fini(prof);
1608 return (status);
1611 /* ARGSUSED */
1612 static dladm_status_t
1613 set_zone(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
1614 val_desc_t *vdp, uint_t val_cnt, uint_t flags, datalink_media_t media)
1616 dladm_status_t status = DLADM_STATUS_OK;
1617 zoneid_t zid_old, zid_new;
1618 dld_ioc_zid_t *dzp;
1620 if (val_cnt != 1)
1621 return (DLADM_STATUS_BADVALCNT);
1623 dzp = (dld_ioc_zid_t *)vdp->vd_val;
1625 status = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags,
1626 NULL, &zid_old, sizeof (zid_old));
1627 if (status != DLADM_STATUS_OK)
1628 return (status);
1630 zid_new = dzp->diz_zid;
1631 if (zid_new == zid_old)
1632 return (DLADM_STATUS_OK);
1634 if ((status = set_public_prop(handle, pdp, linkid, vdp, val_cnt,
1635 flags, media)) != DLADM_STATUS_OK)
1636 return (status);
1639 * It is okay to fail to update the /dev entry (some vanity-named
1640 * links do not have a /dev entry).
1642 if (zid_old != GLOBAL_ZONEID) {
1643 (void) i_dladm_update_deventry(handle, zid_old, linkid,
1644 B_FALSE);
1646 if (zid_new != GLOBAL_ZONEID)
1647 (void) i_dladm_update_deventry(handle, zid_new, linkid, B_TRUE);
1649 return (DLADM_STATUS_OK);
1652 /* ARGSUSED */
1653 static dladm_status_t
1654 check_zone(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
1655 char **prop_val, uint_t *val_cntp, uint_t flags, val_desc_t **vdpp,
1656 datalink_media_t media)
1658 char *zone_name;
1659 zoneid_t zoneid;
1660 dladm_status_t status = DLADM_STATUS_OK;
1661 dld_ioc_zid_t *dzp;
1662 uint_t val_cnt = *val_cntp;
1663 val_desc_t *vdp = *vdpp;
1665 if (val_cnt != 1)
1666 return (DLADM_STATUS_BADVALCNT);
1668 dzp = malloc(sizeof (dld_ioc_zid_t));
1669 if (dzp == NULL)
1670 return (DLADM_STATUS_NOMEM);
1672 zone_name = (prop_val != NULL) ? *prop_val : GLOBAL_ZONENAME;
1673 if ((zoneid = getzoneidbyname(zone_name)) == -1) {
1674 status = DLADM_STATUS_BADVAL;
1675 goto done;
1678 if (zoneid != GLOBAL_ZONEID) {
1679 ushort_t flags;
1681 if (zone_getattr(zoneid, ZONE_ATTR_FLAGS, &flags,
1682 sizeof (flags)) < 0) {
1683 status = dladm_errno2status(errno);
1684 goto done;
1687 if (!(flags & ZF_NET_EXCL)) {
1688 status = DLADM_STATUS_BADVAL;
1689 goto done;
1693 (void) memset(dzp, 0, sizeof (dld_ioc_zid_t));
1695 dzp->diz_zid = zoneid;
1696 dzp->diz_linkid = linkid;
1698 vdp->vd_val = (uintptr_t)dzp;
1699 return (DLADM_STATUS_OK);
1700 done:
1701 free(dzp);
1702 return (status);
1705 /* ARGSUSED */
1706 static dladm_status_t
1707 get_maxbw(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
1708 char **prop_val, uint_t *val_cnt, datalink_media_t media,
1709 uint_t flags, uint_t *perm_flags)
1711 mac_resource_props_t mrp;
1712 dladm_status_t status;
1714 status = i_dladm_get_public_prop(handle, linkid, "resource", flags,
1715 perm_flags, &mrp, sizeof (mrp));
1716 if (status != DLADM_STATUS_OK)
1717 return (status);
1719 if ((mrp.mrp_mask & MRP_MAXBW) == 0) {
1720 *val_cnt = 0;
1721 return (DLADM_STATUS_OK);
1724 (void) dladm_bw2str(mrp.mrp_maxbw, prop_val[0]);
1725 *val_cnt = 1;
1726 return (DLADM_STATUS_OK);
1729 /* ARGSUSED */
1730 static dladm_status_t
1731 check_maxbw(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
1732 char **prop_val, uint_t *val_cntp, uint_t flags, val_desc_t **vdpp,
1733 datalink_media_t media)
1735 uint64_t *maxbw;
1736 dladm_status_t status = DLADM_STATUS_OK;
1737 uint_t val_cnt = *val_cntp;
1738 val_desc_t *vdp = *vdpp;
1740 if (val_cnt != 1)
1741 return (DLADM_STATUS_BADVALCNT);
1743 maxbw = malloc(sizeof (uint64_t));
1744 if (maxbw == NULL)
1745 return (DLADM_STATUS_NOMEM);
1747 status = dladm_str2bw(*prop_val, maxbw);
1748 if (status != DLADM_STATUS_OK) {
1749 free(maxbw);
1750 return (status);
1753 if ((*maxbw < MRP_MAXBW_MINVAL) && (*maxbw != 0)) {
1754 free(maxbw);
1755 return (DLADM_STATUS_MINMAXBW);
1758 vdp->vd_val = (uintptr_t)maxbw;
1759 return (DLADM_STATUS_OK);
1762 /* ARGSUSED */
1763 dladm_status_t
1764 extract_maxbw(val_desc_t *vdp, uint_t cnt, void *arg)
1766 mac_resource_props_t *mrp = arg;
1768 if (vdp->vd_val == RESET_VAL) {
1769 mrp->mrp_maxbw = MRP_MAXBW_RESETVAL;
1770 } else {
1771 bcopy((char *)vdp->vd_val, &mrp->mrp_maxbw, sizeof (uint64_t));
1773 mrp->mrp_mask |= MRP_MAXBW;
1775 return (DLADM_STATUS_OK);
1778 /* ARGSUSED */
1779 static dladm_status_t
1780 get_cpus(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
1781 char **prop_val, uint_t *val_cnt, datalink_media_t media,
1782 uint_t flags, uint_t *perm_flags)
1784 dladm_status_t status;
1785 mac_resource_props_t mrp;
1786 mac_propval_range_t *pv_range;
1787 int err;
1789 if (strcmp(pdp->pd_name, "cpus-effective") == 0) {
1790 status = i_dladm_get_public_prop(handle, linkid,
1791 "resource-effective", flags, perm_flags, &mrp,
1792 sizeof (mrp));
1793 } else {
1794 status = i_dladm_get_public_prop(handle, linkid,
1795 "resource", flags, perm_flags, &mrp, sizeof (mrp));
1798 if (status != DLADM_STATUS_OK)
1799 return (status);
1801 if (mrp.mrp_ncpus > *val_cnt)
1802 return (DLADM_STATUS_TOOSMALL);
1804 if (mrp.mrp_ncpus == 0) {
1805 *val_cnt = 0;
1806 return (DLADM_STATUS_OK);
1809 /* Sort CPU list and convert it to a mac_propval_range */
1810 status = dladm_list2range(mrp.mrp_cpu, mrp.mrp_ncpus,
1811 MAC_PROPVAL_UINT32, &pv_range);
1812 if (status != DLADM_STATUS_OK)
1813 return (status);
1815 /* Write CPU ranges and individual CPUs */
1816 err = dladm_range2strs(pv_range, prop_val);
1817 if (err != 0) {
1818 free(pv_range);
1819 return (dladm_errno2status(err));
1822 *val_cnt = pv_range->mpr_count;
1823 free(pv_range);
1825 return (DLADM_STATUS_OK);
1828 /* ARGSUSED */
1829 static dladm_status_t
1830 check_cpus(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
1831 char **prop_val, uint_t *val_cntp, uint_t flags, val_desc_t **vdpp,
1832 datalink_media_t media)
1834 int i, j, rc;
1835 long nproc = sysconf(_SC_NPROCESSORS_CONF);
1836 mac_resource_props_t mrp;
1837 mac_propval_range_t *pv_range;
1838 uint_t perm_flags;
1839 uint32_t ncpus;
1840 uint32_t *cpus = mrp.mrp_cpu;
1841 val_desc_t *vdp = *vdpp;
1842 val_desc_t *newvdp;
1843 uint_t val_cnt = *val_cntp;
1844 dladm_status_t status = DLADM_STATUS_OK;
1846 /* Get the current pool property */
1847 status = i_dladm_get_public_prop(handle, linkid, "resource", 0,
1848 &perm_flags, &mrp, sizeof (mrp));
1850 if (status == DLADM_STATUS_OK) {
1851 /* Can't set cpus if a pool is set */
1852 if (strlen(mrp.mrp_pool) != 0)
1853 return (DLADM_STATUS_POOLCPU);
1856 /* Read ranges and convert to mac_propval_range */
1857 status = dladm_strs2range(prop_val, val_cnt, MAC_PROPVAL_UINT32,
1858 &pv_range);
1859 if (status != DLADM_STATUS_OK)
1860 goto done1;
1862 /* Convert mac_propval_range to a single CPU list */
1863 ncpus = MRP_NCPUS;
1864 status = dladm_range2list(pv_range, cpus, &ncpus);
1865 if (status != DLADM_STATUS_OK)
1866 goto done1;
1869 * If a range of CPUs was entered, update value count and reallocate
1870 * the array of val_desc_t's. The array allocated was sized for
1871 * indvidual elements, but needs to be reallocated to accomodate the
1872 * expanded list of CPUs.
1874 if (val_cnt < ncpus) {
1875 newvdp = calloc(*val_cntp, sizeof (val_desc_t));
1876 if (newvdp == NULL) {
1877 status = DLADM_STATUS_NOMEM;
1878 goto done1;
1880 vdp = newvdp;
1883 /* Check if all CPUs in the list are online */
1884 for (i = 0; i < ncpus; i++) {
1885 if (cpus[i] >= nproc) {
1886 status = DLADM_STATUS_BADCPUID;
1887 goto done2;
1890 rc = p_online(cpus[i], P_STATUS);
1891 if (rc < 1) {
1892 status = DLADM_STATUS_CPUERR;
1893 goto done2;
1896 if (rc != P_ONLINE) {
1897 status = DLADM_STATUS_CPUNOTONLINE;
1898 goto done2;
1901 vdp[i].vd_val = (uintptr_t)cpus[i];
1904 /* Check for duplicate CPUs */
1905 for (i = 0; i < *val_cntp; i++) {
1906 for (j = 0; j < *val_cntp; j++) {
1907 if (i != j && vdp[i].vd_val == vdp[j].vd_val) {
1908 status = DLADM_STATUS_BADVAL;
1909 goto done2;
1914 /* Update *val_cntp and *vdpp if everything was OK */
1915 if (val_cnt < ncpus) {
1916 *val_cntp = ncpus;
1917 free(*vdpp);
1918 *vdpp = newvdp;
1921 status = DLADM_STATUS_OK;
1922 goto done1;
1924 done2:
1925 free(newvdp);
1926 done1:
1927 free(pv_range);
1928 return (status);
1931 /* ARGSUSED */
1932 dladm_status_t
1933 extract_cpus(val_desc_t *vdp, uint_t cnt, void *arg)
1935 mac_resource_props_t *mrp = arg;
1936 int i;
1938 if (vdp[0].vd_val == RESET_VAL) {
1939 bzero(&mrp->mrp_cpus, sizeof (mac_cpus_t));
1940 mrp->mrp_mask |= MRP_CPUS;
1941 return (DLADM_STATUS_OK);
1944 for (i = 0; i < cnt; i++)
1945 mrp->mrp_cpu[i] = (uint32_t)vdp[i].vd_val;
1947 mrp->mrp_ncpus = cnt;
1948 mrp->mrp_mask |= (MRP_CPUS|MRP_CPUS_USERSPEC);
1949 mrp->mrp_fanout_mode = MCM_CPUS;
1950 mrp->mrp_rx_intr_cpu = -1;
1952 return (DLADM_STATUS_OK);
1956 * Get the pool datalink property from the kernel. This is used
1957 * for both the user specified pool and effective pool properties.
1959 /* ARGSUSED */
1960 static dladm_status_t
1961 get_pool(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
1962 char **prop_val, uint_t *val_cnt, datalink_media_t media,
1963 uint_t flags, uint_t *perm_flags)
1965 mac_resource_props_t mrp;
1966 dladm_status_t status;
1968 if (strcmp(pdp->pd_name, "pool-effective") == 0) {
1969 status = i_dladm_get_public_prop(handle, linkid,
1970 "resource-effective", flags, perm_flags, &mrp,
1971 sizeof (mrp));
1972 } else {
1973 status = i_dladm_get_public_prop(handle, linkid,
1974 "resource", flags, perm_flags, &mrp, sizeof (mrp));
1977 if (status != DLADM_STATUS_OK)
1978 return (status);
1980 if (strlen(mrp.mrp_pool) == 0) {
1981 (*prop_val)[0] = '\0';
1982 } else {
1983 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX,
1984 "%s", mrp.mrp_pool);
1986 *val_cnt = 1;
1988 return (DLADM_STATUS_OK);
1991 /* ARGSUSED */
1992 static dladm_status_t
1993 check_pool(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
1994 char **prop_val, uint_t *val_cntp, uint_t flags, val_desc_t **vdpp,
1995 datalink_media_t media)
1997 pool_conf_t *poolconf;
1998 pool_t *pool;
1999 mac_resource_props_t mrp;
2000 dladm_status_t status;
2001 uint_t perm_flags;
2002 char *poolname;
2003 val_desc_t *vdp = *vdpp;
2005 /* Get the current cpus property */
2006 status = i_dladm_get_public_prop(handle, linkid, "resource", 0,
2007 &perm_flags, &mrp, sizeof (mrp));
2009 if (status == DLADM_STATUS_OK) {
2010 /* Can't set pool if cpus are set */
2011 if (mrp.mrp_ncpus != 0)
2012 return (DLADM_STATUS_POOLCPU);
2015 poolname = malloc(sizeof (mrp.mrp_pool));
2016 if (poolname == NULL)
2017 return (DLADM_STATUS_NOMEM);
2019 /* Check for pool's availability if not booting */
2020 if ((flags & DLADM_OPT_BOOT) == 0) {
2022 /* Allocate and open pool configuration */
2023 if ((poolconf = pool_conf_alloc()) == NULL)
2024 return (DLADM_STATUS_BADVAL);
2026 if (pool_conf_open(poolconf, pool_dynamic_location(), PO_RDONLY)
2027 != PO_SUCCESS) {
2028 pool_conf_free(poolconf);
2029 return (DLADM_STATUS_BADVAL);
2032 /* Look for pool name */
2033 if ((pool = pool_get_pool(poolconf, *prop_val)) == NULL) {
2034 pool_conf_free(poolconf);
2035 return (DLADM_STATUS_BADVAL);
2038 pool_conf_free(poolconf);
2039 free(pool);
2042 (void) strlcpy(poolname, *prop_val, sizeof (mrp.mrp_pool));
2043 vdp->vd_val = (uintptr_t)poolname;
2045 return (DLADM_STATUS_OK);
2048 /* ARGSUSED */
2049 dladm_status_t
2050 extract_pool(val_desc_t *vdp, uint_t cnt, void *arg)
2052 mac_resource_props_t *mrp = (mac_resource_props_t *)arg;
2054 if (vdp->vd_val == RESET_VAL) {
2055 bzero(&mrp->mrp_pool, sizeof (mrp->mrp_pool));
2056 mrp->mrp_mask |= MRP_POOL;
2057 return (DLADM_STATUS_OK);
2060 (void) strlcpy(mrp->mrp_pool, (char *)vdp->vd_val,
2061 sizeof (mrp->mrp_pool));
2062 mrp->mrp_mask |= MRP_POOL;
2064 * Use MCM_CPUS since the fanout count is not user specified
2065 * and will be determined by the cpu list generated from the
2066 * pool.
2068 mrp->mrp_fanout_mode = MCM_CPUS;
2070 return (DLADM_STATUS_OK);
2073 /* ARGSUSED */
2074 static dladm_status_t
2075 get_priority(dladm_handle_t handle, prop_desc_t *pdp,
2076 datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
2077 datalink_media_t media, uint_t flags, uint_t *perm_flags)
2079 mac_resource_props_t mrp;
2080 mac_priority_level_t pri;
2081 dladm_status_t status;
2083 status = i_dladm_get_public_prop(handle, linkid, "resource", flags,
2084 perm_flags, &mrp, sizeof (mrp));
2085 if (status != DLADM_STATUS_OK)
2086 return (status);
2088 pri = ((mrp.mrp_mask & MRP_PRIORITY) == 0) ? MPL_HIGH :
2089 mrp.mrp_priority;
2091 (void) dladm_pri2str(pri, prop_val[0]);
2092 *val_cnt = 1;
2093 return (DLADM_STATUS_OK);
2096 /* ARGSUSED */
2097 dladm_status_t
2098 extract_priority(val_desc_t *vdp, uint_t cnt, void *arg)
2100 mac_resource_props_t *mrp = arg;
2102 if (cnt != 1)
2103 return (DLADM_STATUS_BADVAL);
2105 mrp->mrp_priority = (mac_priority_level_t)vdp->vd_val;
2106 mrp->mrp_mask |= MRP_PRIORITY;
2108 return (DLADM_STATUS_OK);
2112 * Determines the size of the structure that needs to be sent to drivers
2113 * for retrieving the property range values.
2115 static int
2116 i_dladm_range_size(mac_propval_range_t *r, size_t *sz, uint_t *rcount)
2118 uint_t count = r->mpr_count;
2120 *sz = sizeof (mac_propval_range_t);
2121 *rcount = count;
2122 --count;
2124 switch (r->mpr_type) {
2125 case MAC_PROPVAL_UINT32:
2126 *sz += (count * sizeof (mac_propval_uint32_range_t));
2127 return (0);
2128 default:
2129 break;
2131 *sz = 0;
2132 *rcount = 0;
2133 return (EINVAL);
2137 /* ARGSUSED */
2138 static dladm_status_t
2139 check_rings(dladm_handle_t handle, prop_desc_t *pdp,
2140 datalink_id_t linkid, char **prop_val, uint_t *val_cntp, uint_t flags,
2141 val_desc_t **vp, datalink_media_t media)
2143 uint_t val_cnt = *val_cntp;
2144 val_desc_t *v = *vp;
2146 if (val_cnt != 1)
2147 return (DLADM_STATUS_BADVAL);
2148 if (strncasecmp(prop_val[0], "hw", strlen("hw")) == 0) {
2149 v->vd_val = UNSPEC_VAL;
2150 } else if (strncasecmp(prop_val[0], "sw", strlen("sw")) == 0) {
2151 v->vd_val = 0;
2152 } else {
2153 v->vd_val = strtoul(prop_val[0], NULL, 0);
2154 if (v->vd_val == 0)
2155 return (DLADM_STATUS_BADVAL);
2157 return (DLADM_STATUS_OK);
2160 /* ARGSUSED */
2161 static dladm_status_t
2162 get_rings_range(dladm_handle_t handle, prop_desc_t *pdp,
2163 datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
2164 datalink_media_t media, uint_t flags, uint_t *perm_flags)
2166 dld_ioc_macprop_t *dip;
2167 dladm_status_t status = DLADM_STATUS_OK;
2168 mac_propval_range_t *rangep;
2169 size_t sz;
2170 mac_propval_uint32_range_t *ur;
2172 sz = sizeof (mac_propval_range_t);
2174 if ((dip = i_dladm_buf_alloc_by_name(sz, linkid, pdp->pd_name, flags,
2175 &status)) == NULL)
2176 return (status);
2178 status = i_dladm_macprop(handle, dip, B_FALSE);
2179 if (status != DLADM_STATUS_OK)
2180 return (status);
2182 rangep = (mac_propval_range_t *)(void *)&dip->pr_val;
2183 *val_cnt = 1;
2184 ur = &rangep->mpr_range_uint32[0];
2185 /* This is the case where the dev doesn't have any rings/groups */
2186 if (rangep->mpr_count == 0) {
2187 (*prop_val)[0] = '\0';
2189 * This is the case where the dev supports rings, but static
2190 * grouping.
2192 } else if (ur->mpur_min == ur->mpur_max &&
2193 ur->mpur_max == 0) {
2194 (void) snprintf(prop_val[0], DLADM_PROP_VAL_MAX, "sw,hw");
2196 * This is the case where the dev supports rings and dynamic
2197 * grouping, but has only one value (say 2 rings and 2 groups).
2199 } else if (ur->mpur_min == ur->mpur_max) {
2200 (void) snprintf(prop_val[0], DLADM_PROP_VAL_MAX, "sw,hw,%d",
2201 ur->mpur_min);
2203 * This is the case where the dev supports rings and dynamic
2204 * grouping and has a range of rings.
2206 } else {
2207 (void) snprintf(prop_val[0], DLADM_PROP_VAL_MAX,
2208 "sw,hw,<%ld-%ld>", ur->mpur_min, ur->mpur_max);
2210 free(dip);
2211 return (status);
2215 /* ARGSUSED */
2216 static dladm_status_t
2217 get_rxrings(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
2218 char **prop_val, uint_t *val_cnt, datalink_media_t media,
2219 uint_t flags, uint_t *perm_flags)
2221 mac_resource_props_t mrp;
2222 dladm_status_t status;
2223 uint32_t nrings = 0;
2226 * Get the number of (effective-)rings from the resource property.
2228 if (strcmp(pdp->pd_name, "rxrings-effective") == 0) {
2229 status = i_dladm_get_public_prop(handle, linkid,
2230 "resource-effective", flags, perm_flags, &mrp,
2231 sizeof (mrp));
2232 } else {
2234 * Get the permissions from the "rxrings" property.
2236 status = i_dladm_get_public_prop(handle, linkid, "rxrings",
2237 flags, perm_flags, NULL, 0);
2238 if (status != DLADM_STATUS_OK)
2239 return (status);
2241 status = i_dladm_get_public_prop(handle, linkid,
2242 "resource", flags, NULL, &mrp, sizeof (mrp));
2245 if (status != DLADM_STATUS_OK)
2246 return (status);
2248 if ((mrp.mrp_mask & MRP_RX_RINGS) == 0) {
2249 *val_cnt = 0;
2250 return (DLADM_STATUS_OK);
2252 nrings = mrp.mrp_nrxrings;
2253 *val_cnt = 1;
2254 if (mrp.mrp_mask & MRP_RXRINGS_UNSPEC)
2255 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "hw");
2256 else if (nrings == 0)
2257 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "sw");
2258 else
2259 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "%ld", nrings);
2260 return (DLADM_STATUS_OK);
2263 /* ARGSUSED */
2264 dladm_status_t
2265 extract_rxrings(val_desc_t *vdp, uint_t cnt, void *arg)
2267 mac_resource_props_t *mrp = (mac_resource_props_t *)arg;
2269 mrp->mrp_nrxrings = 0;
2270 if (vdp->vd_val == RESET_VAL)
2271 mrp->mrp_mask = MRP_RINGS_RESET;
2272 else if (vdp->vd_val == UNSPEC_VAL)
2273 mrp->mrp_mask = MRP_RXRINGS_UNSPEC;
2274 else
2275 mrp->mrp_nrxrings = vdp->vd_val;
2276 mrp->mrp_mask |= MRP_RX_RINGS;
2278 return (DLADM_STATUS_OK);
2281 /* ARGSUSED */
2282 static dladm_status_t
2283 get_txrings(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
2284 char **prop_val, uint_t *val_cnt, datalink_media_t media,
2285 uint_t flags, uint_t *perm_flags)
2287 mac_resource_props_t mrp;
2288 dladm_status_t status;
2289 uint32_t nrings = 0;
2293 * Get the number of (effective-)rings from the resource property.
2295 if (strcmp(pdp->pd_name, "txrings-effective") == 0) {
2296 status = i_dladm_get_public_prop(handle, linkid,
2297 "resource-effective", flags, perm_flags, &mrp,
2298 sizeof (mrp));
2299 } else {
2301 * Get the permissions from the "txrings" property.
2303 status = i_dladm_get_public_prop(handle, linkid, "txrings",
2304 flags, perm_flags, NULL, 0);
2305 if (status != DLADM_STATUS_OK)
2306 return (status);
2309 * Get the number of rings from the "resource" property.
2311 status = i_dladm_get_public_prop(handle, linkid, "resource",
2312 flags, NULL, &mrp, sizeof (mrp));
2315 if (status != DLADM_STATUS_OK)
2316 return (status);
2318 if ((mrp.mrp_mask & MRP_TX_RINGS) == 0) {
2319 *val_cnt = 0;
2320 return (DLADM_STATUS_OK);
2322 nrings = mrp.mrp_ntxrings;
2323 *val_cnt = 1;
2324 if (mrp.mrp_mask & MRP_TXRINGS_UNSPEC)
2325 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "hw");
2326 else if (nrings == 0)
2327 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "sw");
2328 else
2329 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "%ld", nrings);
2330 return (DLADM_STATUS_OK);
2333 /* ARGSUSED */
2334 dladm_status_t
2335 extract_txrings(val_desc_t *vdp, uint_t cnt, void *arg)
2337 mac_resource_props_t *mrp = (mac_resource_props_t *)arg;
2339 mrp->mrp_ntxrings = 0;
2340 if (vdp->vd_val == RESET_VAL)
2341 mrp->mrp_mask = MRP_RINGS_RESET;
2342 else if (vdp->vd_val == UNSPEC_VAL)
2343 mrp->mrp_mask = MRP_TXRINGS_UNSPEC;
2344 else
2345 mrp->mrp_ntxrings = vdp->vd_val;
2346 mrp->mrp_mask |= MRP_TX_RINGS;
2348 return (DLADM_STATUS_OK);
2351 /* ARGSUSED */
2352 static dladm_status_t
2353 get_cntavail(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
2354 char **prop_val, uint_t *val_cnt, datalink_media_t media, uint_t flags,
2355 uint_t *perm_flags)
2357 if (flags & DLD_PROP_DEFAULT)
2358 return (DLADM_STATUS_NOTDEFINED);
2360 return (get_uint32(handle, pdp, linkid, prop_val, val_cnt, media,
2361 flags, perm_flags));
2364 /* ARGSUSED */
2365 static dladm_status_t
2366 set_resource(dladm_handle_t handle, prop_desc_t *pdp,
2367 datalink_id_t linkid, val_desc_t *vdp, uint_t val_cnt,
2368 uint_t flags, datalink_media_t media)
2370 mac_resource_props_t mrp;
2371 dladm_status_t status = DLADM_STATUS_OK;
2372 dld_ioc_macprop_t *dip;
2373 int i;
2375 bzero(&mrp, sizeof (mac_resource_props_t));
2376 dip = i_dladm_buf_alloc_by_name(0, linkid, "resource",
2377 flags, &status);
2379 if (dip == NULL)
2380 return (status);
2382 for (i = 0; i < DLADM_MAX_RSRC_PROP; i++) {
2383 resource_prop_t *rp = &rsrc_prop_table[i];
2385 if (strcmp(pdp->pd_name, rp->rp_name) != 0)
2386 continue;
2388 status = rp->rp_extract(vdp, val_cnt, &mrp);
2389 if (status != DLADM_STATUS_OK)
2390 goto done;
2392 break;
2395 (void) memcpy(dip->pr_val, &mrp, dip->pr_valsize);
2396 status = i_dladm_macprop(handle, dip, B_TRUE);
2398 done:
2399 free(dip);
2400 return (status);
2403 /* ARGSUSED */
2404 static dladm_status_t
2405 get_protection(dladm_handle_t handle, prop_desc_t *pdp,
2406 datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
2407 datalink_media_t media, uint_t flags, uint_t *perm_flags)
2409 mac_resource_props_t mrp;
2410 mac_protect_t *p;
2411 dladm_status_t status;
2412 uint32_t i, cnt = 0, setbits[32];
2414 status = i_dladm_get_public_prop(handle, linkid, "resource", flags,
2415 perm_flags, &mrp, sizeof (mrp));
2416 if (status != DLADM_STATUS_OK)
2417 return (status);
2419 p = &mrp.mrp_protect;
2420 if ((mrp.mrp_mask & MRP_PROTECT) == 0) {
2421 *val_cnt = 0;
2422 return (DLADM_STATUS_OK);
2424 dladm_find_setbits32(p->mp_types, setbits, &cnt);
2425 if (cnt > *val_cnt)
2426 return (DLADM_STATUS_BADVALCNT);
2428 for (i = 0; i < cnt; i++)
2429 (void) dladm_protect2str(setbits[i], prop_val[i]);
2431 *val_cnt = cnt;
2432 return (DLADM_STATUS_OK);
2435 /* ARGSUSED */
2436 static dladm_status_t
2437 get_allowedips(dladm_handle_t handle, prop_desc_t *pdp,
2438 datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
2439 datalink_media_t media, uint_t flags, uint_t *perm_flags)
2441 mac_resource_props_t mrp;
2442 mac_protect_t *p;
2443 dladm_status_t status;
2444 int i;
2446 status = i_dladm_get_public_prop(handle, linkid, "resource", flags,
2447 perm_flags, &mrp, sizeof (mrp));
2448 if (status != DLADM_STATUS_OK)
2449 return (status);
2451 p = &mrp.mrp_protect;
2452 if (p->mp_ipaddrcnt == 0) {
2453 *val_cnt = 0;
2454 return (DLADM_STATUS_OK);
2456 if (p->mp_ipaddrcnt > *val_cnt)
2457 return (DLADM_STATUS_BADVALCNT);
2459 for (i = 0; i < p->mp_ipaddrcnt; i++) {
2460 int len;
2461 if (p->mp_ipaddrs[i].ip_version == IPV4_VERSION) {
2462 ipaddr_t v4addr;
2464 v4addr = V4_PART_OF_V6(p->mp_ipaddrs[i].ip_addr);
2465 (void) dladm_ipv4addr2str(&v4addr, prop_val[i]);
2466 } else {
2467 (void) dladm_ipv6addr2str(&p->mp_ipaddrs[i].ip_addr,
2468 prop_val[i]);
2470 len = strlen(prop_val[i]);
2471 (void) sprintf(prop_val[i] + len, "/%d",
2472 p->mp_ipaddrs[i].ip_netmask);
2474 *val_cnt = p->mp_ipaddrcnt;
2475 return (DLADM_STATUS_OK);
2478 dladm_status_t
2479 extract_protection(val_desc_t *vdp, uint_t cnt, void *arg)
2481 mac_resource_props_t *mrp = arg;
2482 uint32_t types = 0;
2483 int i;
2485 for (i = 0; i < cnt; i++)
2486 types |= (uint32_t)vdp[i].vd_val;
2488 mrp->mrp_protect.mp_types = types;
2489 mrp->mrp_mask |= MRP_PROTECT;
2490 return (DLADM_STATUS_OK);
2493 dladm_status_t
2494 extract_allowedips(val_desc_t *vdp, uint_t cnt, void *arg)
2496 mac_resource_props_t *mrp = arg;
2497 mac_protect_t *p = &mrp->mrp_protect;
2498 int i;
2500 if (vdp->vd_val == 0) {
2501 cnt = (uint_t)-1;
2502 } else {
2503 for (i = 0; i < cnt; i++) {
2504 bcopy((void *)vdp[i].vd_val, &p->mp_ipaddrs[i],
2505 sizeof (mac_ipaddr_t));
2508 p->mp_ipaddrcnt = cnt;
2509 mrp->mrp_mask |= MRP_PROTECT;
2510 return (DLADM_STATUS_OK);
2513 static dladm_status_t
2514 check_single_ip(char *buf, mac_ipaddr_t *addr)
2516 dladm_status_t status;
2517 ipaddr_t v4addr;
2518 in6_addr_t v6addr;
2519 boolean_t isv4 = B_TRUE;
2520 char *p;
2521 uint32_t mask = 0;
2524 * If the IP address is in CIDR format, parse the bits component
2525 * seperately. An address in this style will be used to indicate an
2526 * entire subnet, so it must be a network number with no host address.
2528 if ((p = strchr(buf, '/')) != NULL) {
2529 char *end = NULL;
2531 *p++ = '\0';
2532 if (!isdigit(*p))
2533 return (DLADM_STATUS_INVALID_IP);
2534 mask = strtol(p, &end, 10);
2535 if (end != NULL && *end != '\0')
2536 return (DLADM_STATUS_INVALID_IP);
2537 if (mask > 128|| mask < 1)
2538 return (DLADM_STATUS_INVALID_IP);
2541 status = dladm_str2ipv4addr(buf, &v4addr);
2542 if (status == DLADM_STATUS_INVALID_IP) {
2543 status = dladm_str2ipv6addr(buf, &v6addr);
2544 if (status == DLADM_STATUS_OK)
2545 isv4 = B_FALSE;
2547 if (status != DLADM_STATUS_OK)
2548 return (status);
2550 if (isv4) {
2551 if (v4addr == INADDR_ANY)
2552 return (DLADM_STATUS_INVALID_IP);
2554 IN6_IPADDR_TO_V4MAPPED(v4addr, &addr->ip_addr);
2555 addr->ip_version = IPV4_VERSION;
2556 if (p != NULL) {
2557 uint32_t smask;
2560 * Validate the netmask is in the proper range for v4
2562 if (mask > 32 || mask < 1)
2563 return (DLADM_STATUS_INVALID_IP);
2566 * We have a CIDR style address, confirm that only the
2567 * network number is set.
2569 smask = 0xFFFFFFFFu << (32 - mask);
2570 if (htonl(v4addr) & ~smask)
2571 return (DLADM_STATUS_INVALID_IP);
2572 } else {
2573 mask = 32;
2575 addr->ip_netmask = mask;
2576 } else {
2577 if (IN6_IS_ADDR_UNSPECIFIED(&v6addr))
2578 return (DLADM_STATUS_INVALID_IP);
2580 if (IN6_IS_ADDR_V4MAPPED_ANY(&v6addr))
2581 return (DLADM_STATUS_INVALID_IP);
2583 if (p != NULL) {
2584 int i, off, high;
2587 * Note that the address in our buffer is stored in
2588 * network byte order.
2590 off = 0;
2591 for (i = 3; i >= 0; i--) {
2592 high = ffsl(ntohl(v6addr._S6_un._S6_u32[i]));
2593 if (high != 0)
2594 break;
2595 off += 32;
2597 off += high;
2598 if (128 - off >= mask)
2599 return (DLADM_STATUS_INVALID_IP);
2600 } else {
2601 mask = 128;
2604 addr->ip_addr = v6addr;
2605 addr->ip_version = IPV6_VERSION;
2606 addr->ip_netmask = mask;
2608 return (DLADM_STATUS_OK);
2611 /* ARGSUSED */
2612 static dladm_status_t
2613 check_allowedips(dladm_handle_t handle, prop_desc_t *pdp,
2614 datalink_id_t linkid, char **prop_val, uint_t *val_cntp, uint_t flags,
2615 val_desc_t **vdpp, datalink_media_t media)
2617 dladm_status_t status;
2618 mac_ipaddr_t *addr;
2619 int i;
2620 uint_t val_cnt = *val_cntp;
2621 val_desc_t *vdp = *vdpp;
2623 if (val_cnt > MPT_MAXIPADDR)
2624 return (DLADM_STATUS_BADVALCNT);
2626 for (i = 0; i < val_cnt; i++) {
2627 if ((addr = calloc(1, sizeof (mac_ipaddr_t))) == NULL) {
2628 status = DLADM_STATUS_NOMEM;
2629 goto fail;
2631 vdp[i].vd_val = (uintptr_t)addr;
2633 status = check_single_ip(prop_val[i], addr);
2634 if (status != DLADM_STATUS_OK)
2635 goto fail;
2637 return (DLADM_STATUS_OK);
2639 fail:
2640 for (i = 0; i < val_cnt; i++) {
2641 free((void *)vdp[i].vd_val);
2642 vdp[i].vd_val = NULL;
2644 return (status);
2647 static void
2648 dladm_cid2str(mac_dhcpcid_t *cid, char *buf)
2650 char tmp_buf[DLADM_STRSIZE];
2651 uint_t hexlen;
2653 switch (cid->dc_form) {
2654 case CIDFORM_TYPED: {
2655 uint16_t duidtype, hwtype;
2656 uint32_t timestamp, ennum;
2657 char *lladdr;
2659 if (cid->dc_len < sizeof (duidtype))
2660 goto fail;
2662 bcopy(cid->dc_id, &duidtype, sizeof (duidtype));
2663 duidtype = ntohs(duidtype);
2664 switch (duidtype) {
2665 case DHCPV6_DUID_LLT: {
2666 duid_llt_t llt;
2668 if (cid->dc_len < sizeof (llt))
2669 goto fail;
2671 bcopy(cid->dc_id, &llt, sizeof (llt));
2672 hwtype = ntohs(llt.dllt_hwtype);
2673 timestamp = ntohl(llt.dllt_time);
2674 lladdr = _link_ntoa(cid->dc_id + sizeof (llt),
2675 NULL, cid->dc_len - sizeof (llt), IFT_OTHER);
2676 if (lladdr == NULL)
2677 goto fail;
2679 (void) snprintf(buf, DLADM_STRSIZE, "%d.%d.%d.%s",
2680 duidtype, hwtype, timestamp, lladdr);
2681 free(lladdr);
2682 break;
2684 case DHCPV6_DUID_EN: {
2685 duid_en_t en;
2687 if (cid->dc_len < sizeof (en))
2688 goto fail;
2690 bcopy(cid->dc_id, &en, sizeof (en));
2691 ennum = DHCPV6_GET_ENTNUM(&en);
2692 hexlen = sizeof (tmp_buf);
2693 if (octet_to_hexascii(cid->dc_id + sizeof (en),
2694 cid->dc_len - sizeof (en), tmp_buf, &hexlen) != 0)
2695 goto fail;
2697 (void) snprintf(buf, DLADM_STRSIZE, "%d.%d.%s",
2698 duidtype, ennum, tmp_buf);
2699 break;
2701 case DHCPV6_DUID_LL: {
2702 duid_ll_t ll;
2704 if (cid->dc_len < sizeof (ll))
2705 goto fail;
2707 bcopy(cid->dc_id, &ll, sizeof (ll));
2708 hwtype = ntohs(ll.dll_hwtype);
2709 lladdr = _link_ntoa(cid->dc_id + sizeof (ll),
2710 NULL, cid->dc_len - sizeof (ll), IFT_OTHER);
2711 if (lladdr == NULL)
2712 goto fail;
2714 (void) snprintf(buf, DLADM_STRSIZE, "%d.%d.%s",
2715 duidtype, hwtype, lladdr);
2716 free(lladdr);
2717 break;
2719 default: {
2720 hexlen = sizeof (tmp_buf);
2721 if (octet_to_hexascii(cid->dc_id + sizeof (duidtype),
2722 cid->dc_len - sizeof (duidtype),
2723 tmp_buf, &hexlen) != 0)
2724 goto fail;
2726 (void) snprintf(buf, DLADM_STRSIZE, "%d.%s",
2727 duidtype, tmp_buf);
2730 break;
2732 case CIDFORM_HEX: {
2733 hexlen = sizeof (tmp_buf);
2734 if (octet_to_hexascii(cid->dc_id, cid->dc_len,
2735 tmp_buf, &hexlen) != 0)
2736 goto fail;
2738 (void) snprintf(buf, DLADM_STRSIZE, "0x%s", tmp_buf);
2739 break;
2741 case CIDFORM_STR: {
2742 int i;
2744 for (i = 0; i < cid->dc_len; i++) {
2745 if (!isprint(cid->dc_id[i]))
2746 goto fail;
2748 (void) snprintf(buf, DLADM_STRSIZE, "%s", cid->dc_id);
2749 break;
2751 default:
2752 goto fail;
2754 return;
2756 fail:
2757 (void) snprintf(buf, DLADM_STRSIZE, "<unknown>");
2760 static dladm_status_t
2761 dladm_str2cid(char *buf, mac_dhcpcid_t *cid)
2763 char *ptr = buf;
2764 char tmp_buf[DLADM_STRSIZE];
2765 uint_t hexlen, cidlen;
2767 bzero(cid, sizeof (*cid));
2768 if (isdigit(*ptr) &&
2769 ptr[strspn(ptr, "0123456789")] == '.') {
2770 char *cp;
2771 ulong_t duidtype;
2772 ulong_t subtype;
2773 ulong_t timestamp;
2774 uchar_t *lladdr;
2775 int addrlen;
2777 errno = 0;
2778 duidtype = strtoul(ptr, &cp, 0);
2779 if (ptr == cp || errno != 0 || *cp != '.' ||
2780 duidtype > USHRT_MAX)
2781 return (DLADM_STATUS_BADARG);
2782 ptr = cp + 1;
2784 if (duidtype != 0 && duidtype <= DHCPV6_DUID_LL) {
2785 errno = 0;
2786 subtype = strtoul(ptr, &cp, 0);
2787 if (ptr == cp || errno != 0 || *cp != '.')
2788 return (DLADM_STATUS_BADARG);
2789 ptr = cp + 1;
2791 switch (duidtype) {
2792 case DHCPV6_DUID_LLT: {
2793 duid_llt_t llt;
2795 errno = 0;
2796 timestamp = strtoul(ptr, &cp, 0);
2797 if (ptr == cp || errno != 0 || *cp != '.')
2798 return (DLADM_STATUS_BADARG);
2800 ptr = cp + 1;
2801 lladdr = _link_aton(ptr, &addrlen);
2802 if (lladdr == NULL)
2803 return (DLADM_STATUS_BADARG);
2805 cidlen = sizeof (llt) + addrlen;
2806 if (cidlen > sizeof (cid->dc_id)) {
2807 free(lladdr);
2808 return (DLADM_STATUS_TOOSMALL);
2810 llt.dllt_dutype = htons(duidtype);
2811 llt.dllt_hwtype = htons(subtype);
2812 llt.dllt_time = htonl(timestamp);
2813 bcopy(&llt, cid->dc_id, sizeof (llt));
2814 bcopy(lladdr, cid->dc_id + sizeof (llt), addrlen);
2815 free(lladdr);
2816 break;
2818 case DHCPV6_DUID_LL: {
2819 duid_ll_t ll;
2821 lladdr = _link_aton(ptr, &addrlen);
2822 if (lladdr == NULL)
2823 return (DLADM_STATUS_BADARG);
2825 cidlen = sizeof (ll) + addrlen;
2826 if (cidlen > sizeof (cid->dc_id)) {
2827 free(lladdr);
2828 return (DLADM_STATUS_TOOSMALL);
2830 ll.dll_dutype = htons(duidtype);
2831 ll.dll_hwtype = htons(subtype);
2832 bcopy(&ll, cid->dc_id, sizeof (ll));
2833 bcopy(lladdr, cid->dc_id + sizeof (ll), addrlen);
2834 free(lladdr);
2835 break;
2837 default: {
2838 hexlen = sizeof (tmp_buf);
2839 if (hexascii_to_octet(ptr, strlen(ptr),
2840 tmp_buf, &hexlen) != 0)
2841 return (DLADM_STATUS_BADARG);
2843 if (duidtype == DHCPV6_DUID_EN) {
2844 duid_en_t en;
2846 en.den_dutype = htons(duidtype);
2847 DHCPV6_SET_ENTNUM(&en, subtype);
2849 cidlen = sizeof (en) + hexlen;
2850 if (cidlen > sizeof (cid->dc_id))
2851 return (DLADM_STATUS_TOOSMALL);
2853 bcopy(&en, cid->dc_id, sizeof (en));
2854 bcopy(tmp_buf, cid->dc_id + sizeof (en),
2855 hexlen);
2856 } else {
2857 uint16_t dutype = htons(duidtype);
2859 cidlen = sizeof (dutype) + hexlen;
2860 if (cidlen > sizeof (cid->dc_id))
2861 return (DLADM_STATUS_TOOSMALL);
2863 bcopy(&dutype, cid->dc_id, sizeof (dutype));
2864 bcopy(tmp_buf, cid->dc_id + sizeof (dutype),
2865 hexlen);
2867 break;
2870 cid->dc_form = CIDFORM_TYPED;
2871 } else if (strncasecmp("0x", ptr, 2) == 0 && ptr[2] != '\0') {
2872 ptr += 2;
2873 hexlen = sizeof (tmp_buf);
2874 if (hexascii_to_octet(ptr, strlen(ptr), tmp_buf,
2875 &hexlen) != 0) {
2876 return (DLADM_STATUS_BADARG);
2878 cidlen = hexlen;
2879 if (cidlen > sizeof (cid->dc_id))
2880 return (DLADM_STATUS_TOOSMALL);
2882 bcopy(tmp_buf, cid->dc_id, cidlen);
2883 cid->dc_form = CIDFORM_HEX;
2884 } else {
2885 cidlen = strlen(ptr);
2886 if (cidlen > sizeof (cid->dc_id))
2887 return (DLADM_STATUS_TOOSMALL);
2889 bcopy(ptr, cid->dc_id, cidlen);
2890 cid->dc_form = CIDFORM_STR;
2892 cid->dc_len = cidlen;
2893 return (DLADM_STATUS_OK);
2896 /* ARGSUSED */
2897 static dladm_status_t
2898 get_allowedcids(dladm_handle_t handle, prop_desc_t *pdp,
2899 datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
2900 datalink_media_t media, uint_t flags, uint_t *perm_flags)
2902 mac_resource_props_t mrp;
2903 mac_protect_t *p;
2904 dladm_status_t status;
2905 int i;
2907 status = i_dladm_get_public_prop(handle, linkid, "resource", flags,
2908 perm_flags, &mrp, sizeof (mrp));
2909 if (status != DLADM_STATUS_OK)
2910 return (status);
2912 p = &mrp.mrp_protect;
2913 if (p->mp_cidcnt == 0) {
2914 *val_cnt = 0;
2915 return (DLADM_STATUS_OK);
2917 if (p->mp_cidcnt > *val_cnt)
2918 return (DLADM_STATUS_BADVALCNT);
2920 for (i = 0; i < p->mp_cidcnt; i++) {
2921 mac_dhcpcid_t *cid = &p->mp_cids[i];
2923 dladm_cid2str(cid, prop_val[i]);
2925 *val_cnt = p->mp_cidcnt;
2926 return (DLADM_STATUS_OK);
2929 dladm_status_t
2930 extract_allowedcids(val_desc_t *vdp, uint_t cnt, void *arg)
2932 mac_resource_props_t *mrp = arg;
2933 mac_protect_t *p = &mrp->mrp_protect;
2934 int i;
2936 if (vdp->vd_val == 0) {
2937 cnt = (uint_t)-1;
2938 } else {
2939 for (i = 0; i < cnt; i++) {
2940 bcopy((void *)vdp[i].vd_val, &p->mp_cids[i],
2941 sizeof (mac_dhcpcid_t));
2944 p->mp_cidcnt = cnt;
2945 mrp->mrp_mask |= MRP_PROTECT;
2946 return (DLADM_STATUS_OK);
2949 /* ARGSUSED */
2950 static dladm_status_t
2951 check_allowedcids(dladm_handle_t handle, prop_desc_t *pdp,
2952 datalink_id_t linkid, char **prop_val, uint_t *val_cntp,
2953 uint_t flags, val_desc_t **vdpp, datalink_media_t media)
2955 dladm_status_t status;
2956 mac_dhcpcid_t *cid;
2957 int i;
2958 uint_t val_cnt = *val_cntp;
2959 val_desc_t *vdp = *vdpp;
2961 if (val_cnt > MPT_MAXCID)
2962 return (DLADM_STATUS_BADVALCNT);
2964 for (i = 0; i < val_cnt; i++) {
2965 if ((cid = calloc(1, sizeof (mac_dhcpcid_t))) == NULL) {
2966 status = DLADM_STATUS_NOMEM;
2967 goto fail;
2969 vdp[i].vd_val = (uintptr_t)cid;
2971 status = dladm_str2cid(prop_val[i], cid);
2972 if (status != DLADM_STATUS_OK)
2973 goto fail;
2975 return (DLADM_STATUS_OK);
2977 fail:
2978 for (i = 0; i < val_cnt; i++) {
2979 free((void *)vdp[i].vd_val);
2980 vdp[i].vd_val = NULL;
2982 return (status);
2985 /* ARGSUSED */
2986 static dladm_status_t
2987 get_secondary_macs(dladm_handle_t handle, prop_desc_t *pdp,
2988 datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
2989 datalink_media_t media, uint_t flags, uint_t *perm_flags)
2991 mac_secondary_addr_t sa;
2992 dladm_status_t status;
2993 int i;
2995 status = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags,
2996 perm_flags, &sa, sizeof (sa));
2997 if (status != DLADM_STATUS_OK)
2998 return (status);
3000 if (sa.ms_addrcnt > *val_cnt)
3001 return (DLADM_STATUS_BADVALCNT);
3003 for (i = 0; i < sa.ms_addrcnt; i++) {
3004 if (dladm_aggr_macaddr2str(
3005 (const unsigned char *)&sa.ms_addrs[i], prop_val[i]) ==
3006 NULL) {
3007 *val_cnt = i;
3008 return (DLADM_STATUS_NOMEM);
3011 *val_cnt = sa.ms_addrcnt;
3012 return (DLADM_STATUS_OK);
3015 /* ARGSUSED */
3016 static dladm_status_t
3017 check_secondary_macs(dladm_handle_t handle, prop_desc_t *pdp,
3018 datalink_id_t linkid, char **prop_val, uint_t *val_cntp, uint_t flags,
3019 val_desc_t **vdpp, datalink_media_t media)
3021 dladm_status_t status;
3022 uchar_t *addr;
3023 uint_t len = 0;
3024 int i;
3025 uint_t val_cnt = *val_cntp;
3026 val_desc_t *vdp = *vdpp;
3028 if (val_cnt >= MPT_MAXMACADDR)
3029 return (DLADM_STATUS_BADVALCNT);
3031 for (i = 0; i < val_cnt; i++) {
3032 addr = _link_aton(prop_val[i], (int *)&len);
3033 if (addr == NULL) {
3034 if (len == (uint_t)-1)
3035 status = DLADM_STATUS_MACADDRINVAL;
3036 else
3037 status = DLADM_STATUS_NOMEM;
3038 goto fail;
3041 vdp[i].vd_val = (uintptr_t)addr;
3043 return (DLADM_STATUS_OK);
3045 fail:
3046 for (i = 0; i < val_cnt; i++) {
3047 free((void *)vdp[i].vd_val);
3048 vdp[i].vd_val = NULL;
3050 return (status);
3053 /* ARGSUSED */
3054 static dladm_status_t
3055 set_secondary_macs(dladm_handle_t handle, prop_desc_t *pd, datalink_id_t linkid,
3056 val_desc_t *vdp, uint_t val_cnt, uint_t flags, datalink_media_t media)
3058 dladm_status_t status;
3059 dld_ioc_macprop_t *dip;
3060 int i;
3061 mac_secondary_addr_t msa;
3063 dip = i_dladm_buf_alloc_by_name(0, linkid, "secondary-macs", 0,
3064 &status);
3065 if (dip == NULL)
3066 return (status);
3068 if (vdp->vd_val == 0) {
3069 val_cnt = (uint_t)-1;
3070 } else {
3071 for (i = 0; i < val_cnt; i++) {
3072 bcopy((void *)vdp[i].vd_val, msa.ms_addrs[i],
3073 MAXMACADDRLEN);
3076 msa.ms_addrcnt = val_cnt;
3077 bcopy(&msa, dip->pr_val, dip->pr_valsize);
3079 status = i_dladm_macprop(handle, dip, B_TRUE);
3081 free(dip);
3082 return (status);
3085 /* ARGSUSED */
3086 static dladm_status_t
3087 get_autopush(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
3088 char **prop_val, uint_t *val_cnt, datalink_media_t media,
3089 uint_t flags, uint_t *perm_flags)
3091 struct dlautopush dlap;
3092 int i, len;
3093 dladm_status_t status;
3095 if (flags & DLD_PROP_DEFAULT)
3096 return (DLADM_STATUS_NOTDEFINED);
3098 status = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags,
3099 perm_flags, &dlap, sizeof (dlap));
3100 if (status != DLADM_STATUS_OK)
3101 return (status);
3103 if (dlap.dap_npush == 0) {
3104 *val_cnt = 0;
3105 return (DLADM_STATUS_OK);
3107 for (i = 0, len = 0; i < dlap.dap_npush; i++) {
3108 if (i != 0) {
3109 (void) snprintf(*prop_val + len,
3110 DLADM_PROP_VAL_MAX - len, "%c", AP_DELIMITER);
3111 len += 1;
3113 (void) snprintf(*prop_val + len, DLADM_PROP_VAL_MAX - len,
3114 "%s", dlap.dap_aplist[i]);
3115 len += strlen(dlap.dap_aplist[i]);
3116 if (dlap.dap_anchor - 1 == i) {
3117 (void) snprintf(*prop_val + len,
3118 DLADM_PROP_VAL_MAX - len, "%c%s", AP_DELIMITER,
3119 AP_ANCHOR);
3120 len += (strlen(AP_ANCHOR) + 1);
3123 *val_cnt = 1;
3124 return (DLADM_STATUS_OK);
3128 * Add the specified module to the dlautopush structure; returns a
3129 * DLADM_STATUS_* code.
3131 dladm_status_t
3132 i_dladm_add_ap_module(const char *module, struct dlautopush *dlap)
3134 if ((strlen(module) == 0) || (strlen(module) > FMNAMESZ))
3135 return (DLADM_STATUS_BADVAL);
3137 if (strncasecmp(module, AP_ANCHOR, strlen(AP_ANCHOR)) == 0) {
3139 * We don't allow multiple anchors, and the anchor must
3140 * be after at least one module.
3142 if (dlap->dap_anchor != 0)
3143 return (DLADM_STATUS_BADVAL);
3144 if (dlap->dap_npush == 0)
3145 return (DLADM_STATUS_BADVAL);
3147 dlap->dap_anchor = dlap->dap_npush;
3148 return (DLADM_STATUS_OK);
3150 if (dlap->dap_npush >= MAXAPUSH)
3151 return (DLADM_STATUS_BADVALCNT);
3153 (void) strlcpy(dlap->dap_aplist[dlap->dap_npush++], module,
3154 FMNAMESZ + 1);
3156 return (DLADM_STATUS_OK);
3160 * Currently, both '.' and ' '(space) can be used as the delimiters between
3161 * autopush modules. The former is used in dladm set-linkprop, and the
3162 * latter is used in the autopush(1M) file.
3164 /* ARGSUSED */
3165 static dladm_status_t
3166 check_autopush(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
3167 char **prop_val, uint_t *val_cntp, uint_t flags, val_desc_t **vdpp,
3168 datalink_media_t media)
3170 char *module;
3171 struct dlautopush *dlap;
3172 dladm_status_t status;
3173 char val[DLADM_PROP_VAL_MAX];
3174 char delimiters[4];
3175 uint_t val_cnt = *val_cntp;
3176 val_desc_t *vdp = *vdpp;
3178 if (val_cnt != 1)
3179 return (DLADM_STATUS_BADVALCNT);
3181 if (prop_val != NULL) {
3182 dlap = malloc(sizeof (struct dlautopush));
3183 if (dlap == NULL)
3184 return (DLADM_STATUS_NOMEM);
3186 (void) memset(dlap, 0, sizeof (struct dlautopush));
3187 (void) snprintf(delimiters, 4, " %c\n", AP_DELIMITER);
3188 bcopy(*prop_val, val, DLADM_PROP_VAL_MAX);
3189 module = strtok(val, delimiters);
3190 while (module != NULL) {
3191 status = i_dladm_add_ap_module(module, dlap);
3192 if (status != DLADM_STATUS_OK)
3193 return (status);
3194 module = strtok(NULL, delimiters);
3197 vdp->vd_val = (uintptr_t)dlap;
3198 } else {
3199 vdp->vd_val = 0;
3201 return (DLADM_STATUS_OK);
3204 #define WLDP_BUFSIZE (MAX_BUF_LEN - WIFI_BUF_OFFSET)
3206 /* ARGSUSED */
3207 static dladm_status_t
3208 get_rate_common(dladm_handle_t handle, prop_desc_t *pdp,
3209 datalink_id_t linkid, char **prop_val, uint_t *val_cnt, uint_t id,
3210 uint_t *perm_flags)
3212 wl_rates_t *wrp;
3213 uint_t i;
3214 dladm_status_t status = DLADM_STATUS_OK;
3216 wrp = malloc(WLDP_BUFSIZE);
3217 if (wrp == NULL)
3218 return (DLADM_STATUS_NOMEM);
3220 status = i_dladm_wlan_param(handle, linkid, wrp, id, WLDP_BUFSIZE,
3221 B_FALSE);
3222 if (status != DLADM_STATUS_OK)
3223 goto done;
3225 if (wrp->wl_rates_num > *val_cnt) {
3226 status = DLADM_STATUS_TOOSMALL;
3227 goto done;
3230 if (wrp->wl_rates_rates[0] == 0) {
3231 prop_val[0][0] = '\0';
3232 *val_cnt = 1;
3233 goto done;
3236 for (i = 0; i < wrp->wl_rates_num; i++) {
3237 (void) snprintf(prop_val[i], DLADM_STRSIZE, "%.*f",
3238 wrp->wl_rates_rates[i] % 2,
3239 (float)wrp->wl_rates_rates[i] / 2);
3241 *val_cnt = wrp->wl_rates_num;
3242 *perm_flags = MAC_PROP_PERM_RW;
3244 done:
3245 free(wrp);
3246 return (status);
3249 static dladm_status_t
3250 get_rate(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
3251 char **prop_val, uint_t *val_cnt, datalink_media_t media,
3252 uint_t flags, uint_t *perm_flags)
3254 if (media != DL_WIFI) {
3255 return (get_speed(handle, pdp, linkid, prop_val,
3256 val_cnt, media, flags, perm_flags));
3259 return (get_rate_common(handle, pdp, linkid, prop_val, val_cnt,
3260 MAC_PROP_WL_DESIRED_RATES, perm_flags));
3263 /* ARGSUSED */
3264 static dladm_status_t
3265 get_rate_mod(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
3266 char **prop_val, uint_t *val_cnt, datalink_media_t media,
3267 uint_t flags, uint_t *perm_flags)
3269 switch (media) {
3270 case DL_ETHER:
3272 * Speed for ethernet links is unbounded. E.g., 802.11b
3273 * links can have a speed of 5.5 Gbps.
3275 return (DLADM_STATUS_NOTSUP);
3277 case DL_WIFI:
3278 return (get_rate_common(handle, pdp, linkid, prop_val,
3279 val_cnt, MAC_PROP_WL_SUPPORTED_RATES, perm_flags));
3280 default:
3281 return (DLADM_STATUS_BADARG);
3285 static dladm_status_t
3286 set_wlan_rate(dladm_handle_t handle, datalink_id_t linkid,
3287 dladm_wlan_rates_t *rates)
3289 int i;
3290 uint_t len;
3291 wl_rates_t *wrp;
3292 dladm_status_t status = DLADM_STATUS_OK;
3294 wrp = malloc(WLDP_BUFSIZE);
3295 if (wrp == NULL)
3296 return (DLADM_STATUS_NOMEM);
3298 bzero(wrp, WLDP_BUFSIZE);
3299 for (i = 0; i < rates->wr_cnt; i++)
3300 wrp->wl_rates_rates[i] = rates->wr_rates[i];
3301 wrp->wl_rates_num = rates->wr_cnt;
3303 len = offsetof(wl_rates_t, wl_rates_rates) +
3304 (rates->wr_cnt * sizeof (char)) + WIFI_BUF_OFFSET;
3305 status = i_dladm_wlan_param(handle, linkid, wrp,
3306 MAC_PROP_WL_DESIRED_RATES, len, B_TRUE);
3308 free(wrp);
3309 return (status);
3312 /* ARGSUSED */
3313 static dladm_status_t
3314 set_rate(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
3315 val_desc_t *vdp, uint_t val_cnt, uint_t flags, datalink_media_t media)
3317 dladm_wlan_rates_t rates;
3318 dladm_status_t status;
3321 * can currently set rate on WIFI links only.
3323 if (media != DL_WIFI)
3324 return (DLADM_STATUS_PROPRDONLY);
3326 if (val_cnt != 1)
3327 return (DLADM_STATUS_BADVALCNT);
3329 rates.wr_cnt = 1;
3330 rates.wr_rates[0] = vdp[0].vd_val;
3332 status = set_wlan_rate(handle, linkid, &rates);
3334 return (status);
3337 /* ARGSUSED */
3338 static dladm_status_t
3339 check_rate(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
3340 char **prop_val, uint_t *val_cntp, uint_t flags, val_desc_t **vdpp,
3341 datalink_media_t media)
3343 int i;
3344 uint_t modval_cnt = MAX_SUPPORT_RATES;
3345 char *buf, **modval;
3346 dladm_status_t status;
3347 uint_t perm_flags;
3348 uint_t val_cnt = *val_cntp;
3349 val_desc_t *vdp = *vdpp;
3351 if (val_cnt != 1)
3352 return (DLADM_STATUS_BADVALCNT);
3354 buf = malloc((sizeof (char *) + DLADM_STRSIZE) *
3355 MAX_SUPPORT_RATES);
3356 if (buf == NULL) {
3357 status = DLADM_STATUS_NOMEM;
3358 goto done;
3361 modval = (char **)(void *)buf;
3362 for (i = 0; i < MAX_SUPPORT_RATES; i++) {
3363 modval[i] = buf + sizeof (char *) * MAX_SUPPORT_RATES +
3364 i * DLADM_STRSIZE;
3367 status = get_rate_mod(handle, NULL, linkid, modval, &modval_cnt,
3368 media, 0, &perm_flags);
3369 if (status != DLADM_STATUS_OK)
3370 goto done;
3372 for (i = 0; i < modval_cnt; i++) {
3373 if (strcasecmp(*prop_val, modval[i]) == 0) {
3374 vdp->vd_val = (uintptr_t)(uint_t)
3375 (atof(*prop_val) * 2);
3376 status = DLADM_STATUS_OK;
3377 break;
3380 if (i == modval_cnt)
3381 status = DLADM_STATUS_BADVAL;
3382 done:
3383 free(buf);
3384 return (status);
3387 static dladm_status_t
3388 get_phyconf(dladm_handle_t handle, datalink_id_t linkid, void *buf,
3389 int buflen)
3391 return (i_dladm_wlan_param(handle, linkid, buf, MAC_PROP_WL_PHY_CONFIG,
3392 buflen, B_FALSE));
3395 /* ARGSUSED */
3396 static dladm_status_t
3397 get_channel(dladm_handle_t handle, prop_desc_t *pdp,
3398 datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
3399 datalink_media_t media, uint_t flags, uint_t *perm_flags)
3401 uint32_t channel;
3402 char buf[WLDP_BUFSIZE];
3403 dladm_status_t status;
3404 wl_phy_conf_t wl_phy_conf;
3406 if ((status = get_phyconf(handle, linkid, buf, sizeof (buf)))
3407 != DLADM_STATUS_OK)
3408 return (status);
3410 (void) memcpy(&wl_phy_conf, buf, sizeof (wl_phy_conf));
3411 if (!i_dladm_wlan_convert_chan(&wl_phy_conf, &channel))
3412 return (DLADM_STATUS_NOTFOUND);
3414 (void) snprintf(*prop_val, DLADM_STRSIZE, "%u", channel);
3415 *val_cnt = 1;
3416 *perm_flags = MAC_PROP_PERM_READ;
3417 return (DLADM_STATUS_OK);
3420 /* ARGSUSED */
3421 static dladm_status_t
3422 get_powermode(dladm_handle_t handle, prop_desc_t *pdp,
3423 datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
3424 datalink_media_t media, uint_t flags, uint_t *perm_flags)
3426 wl_ps_mode_t mode;
3427 const char *s;
3428 char buf[WLDP_BUFSIZE];
3429 dladm_status_t status;
3431 if ((status = i_dladm_wlan_param(handle, linkid, buf,
3432 MAC_PROP_WL_POWER_MODE, sizeof (buf), B_FALSE)) != DLADM_STATUS_OK)
3433 return (status);
3435 (void) memcpy(&mode, buf, sizeof (mode));
3436 switch (mode.wl_ps_mode) {
3437 case WL_PM_AM:
3438 s = "off";
3439 break;
3440 case WL_PM_MPS:
3441 s = "max";
3442 break;
3443 case WL_PM_FAST:
3444 s = "fast";
3445 break;
3446 default:
3447 return (DLADM_STATUS_NOTFOUND);
3449 (void) snprintf(*prop_val, DLADM_STRSIZE, "%s", s);
3450 *val_cnt = 1;
3451 *perm_flags = MAC_PROP_PERM_RW;
3452 return (DLADM_STATUS_OK);
3455 /* ARGSUSED */
3456 static dladm_status_t
3457 set_powermode(dladm_handle_t handle, prop_desc_t *pdp,
3458 datalink_id_t linkid, val_desc_t *vdp, uint_t val_cnt, uint_t flags,
3459 datalink_media_t media)
3461 dladm_wlan_powermode_t powermode = vdp->vd_val;
3462 wl_ps_mode_t ps_mode;
3464 if (val_cnt != 1)
3465 return (DLADM_STATUS_BADVALCNT);
3467 (void) memset(&ps_mode, 0xff, sizeof (ps_mode));
3469 switch (powermode) {
3470 case DLADM_WLAN_PM_OFF:
3471 ps_mode.wl_ps_mode = WL_PM_AM;
3472 break;
3473 case DLADM_WLAN_PM_MAX:
3474 ps_mode.wl_ps_mode = WL_PM_MPS;
3475 break;
3476 case DLADM_WLAN_PM_FAST:
3477 ps_mode.wl_ps_mode = WL_PM_FAST;
3478 break;
3479 default:
3480 return (DLADM_STATUS_NOTSUP);
3482 return (i_dladm_wlan_param(handle, linkid, &ps_mode,
3483 MAC_PROP_WL_POWER_MODE, sizeof (ps_mode), B_TRUE));
3486 /* ARGSUSED */
3487 static dladm_status_t
3488 get_radio(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
3489 char **prop_val, uint_t *val_cnt, datalink_media_t media,
3490 uint_t flags, uint_t *perm_flags)
3492 wl_radio_t radio;
3493 const char *s;
3494 char buf[WLDP_BUFSIZE];
3495 dladm_status_t status;
3497 if ((status = i_dladm_wlan_param(handle, linkid, buf,
3498 MAC_PROP_WL_RADIO, sizeof (buf), B_FALSE)) != DLADM_STATUS_OK)
3499 return (status);
3501 (void) memcpy(&radio, buf, sizeof (radio));
3502 switch (radio) {
3503 case B_TRUE:
3504 s = "on";
3505 break;
3506 case B_FALSE:
3507 s = "off";
3508 break;
3509 default:
3510 return (DLADM_STATUS_NOTFOUND);
3512 (void) snprintf(*prop_val, DLADM_STRSIZE, "%s", s);
3513 *val_cnt = 1;
3514 *perm_flags = MAC_PROP_PERM_RW;
3515 return (DLADM_STATUS_OK);
3518 /* ARGSUSED */
3519 static dladm_status_t
3520 set_radio(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
3521 val_desc_t *vdp, uint_t val_cnt, uint_t flags, datalink_media_t media)
3523 dladm_wlan_radio_t radio = vdp->vd_val;
3524 wl_radio_t r;
3526 if (val_cnt != 1)
3527 return (DLADM_STATUS_BADVALCNT);
3529 switch (radio) {
3530 case DLADM_WLAN_RADIO_ON:
3531 r = B_TRUE;
3532 break;
3533 case DLADM_WLAN_RADIO_OFF:
3534 r = B_FALSE;
3535 break;
3536 default:
3537 return (DLADM_STATUS_NOTSUP);
3539 return (i_dladm_wlan_param(handle, linkid, &r, MAC_PROP_WL_RADIO,
3540 sizeof (r), B_TRUE));
3543 /* ARGSUSED */
3544 static dladm_status_t
3545 check_hoplimit(dladm_handle_t handle, prop_desc_t *pdp,
3546 datalink_id_t linkid, char **prop_val, uint_t *val_cntp, uint_t flags,
3547 val_desc_t **vdpp, datalink_media_t media)
3549 int32_t hlim;
3550 char *ep;
3551 uint_t val_cnt = *val_cntp;
3552 val_desc_t *vdp = *vdpp;
3554 if (val_cnt != 1)
3555 return (DLADM_STATUS_BADVALCNT);
3557 errno = 0;
3558 hlim = strtol(*prop_val, &ep, 10);
3559 if (errno != 0 || ep == *prop_val || hlim < 1 ||
3560 hlim > (int32_t)UINT8_MAX)
3561 return (DLADM_STATUS_BADVAL);
3562 vdp->vd_val = hlim;
3563 return (DLADM_STATUS_OK);
3566 /* ARGSUSED */
3567 static dladm_status_t
3568 check_encaplim(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
3569 char **prop_val, uint_t *val_cntp, uint_t flags, val_desc_t **vdpp,
3570 datalink_media_t media)
3572 int32_t elim;
3573 char *ep;
3574 uint_t val_cnt = *val_cntp;
3575 val_desc_t *vdp = *vdpp;
3577 if (media != DL_IPV6)
3578 return (DLADM_STATUS_BADARG);
3580 if (val_cnt != 1)
3581 return (DLADM_STATUS_BADVALCNT);
3583 errno = 0;
3584 elim = strtol(*prop_val, &ep, 10);
3585 if (errno != 0 || ep == *prop_val || elim < 0 ||
3586 elim > (int32_t)UINT8_MAX)
3587 return (DLADM_STATUS_BADVAL);
3588 vdp->vd_val = elim;
3589 return (DLADM_STATUS_OK);
3592 static dladm_status_t
3593 i_dladm_set_linkprop_db(dladm_handle_t handle, datalink_id_t linkid,
3594 const char *prop_name, char **prop_val, uint_t val_cnt)
3596 char buf[MAXLINELEN];
3597 int i;
3598 dladm_conf_t conf;
3599 dladm_status_t status;
3601 status = dladm_open_conf(handle, linkid, &conf);
3602 if (status != DLADM_STATUS_OK)
3603 return (status);
3606 * reset case.
3608 if (val_cnt == 0) {
3609 status = dladm_unset_conf_field(handle, conf, prop_name);
3610 if (status == DLADM_STATUS_OK)
3611 status = dladm_write_conf(handle, conf);
3612 goto done;
3615 buf[0] = '\0';
3616 for (i = 0; i < val_cnt; i++) {
3617 (void) strlcat(buf, prop_val[i], MAXLINELEN);
3618 if (i != val_cnt - 1)
3619 (void) strlcat(buf, ",", MAXLINELEN);
3622 status = dladm_set_conf_field(handle, conf, prop_name, DLADM_TYPE_STR,
3623 buf);
3624 if (status == DLADM_STATUS_OK)
3625 status = dladm_write_conf(handle, conf);
3627 done:
3628 dladm_destroy_conf(handle, conf);
3629 return (status);
3632 static dladm_status_t
3633 i_dladm_get_linkprop_db(dladm_handle_t handle, datalink_id_t linkid,
3634 const char *prop_name, char **prop_val, uint_t *val_cntp)
3636 char buf[MAXLINELEN], *str;
3637 uint_t cnt = 0;
3638 dladm_conf_t conf;
3639 dladm_status_t status;
3641 status = dladm_getsnap_conf(handle, linkid, &conf);
3642 if (status != DLADM_STATUS_OK)
3643 return (status);
3645 status = dladm_get_conf_field(handle, conf, prop_name, buf, MAXLINELEN);
3646 if (status != DLADM_STATUS_OK)
3647 goto done;
3649 str = strtok(buf, ",");
3650 while (str != NULL) {
3651 if (cnt == *val_cntp) {
3652 status = DLADM_STATUS_TOOSMALL;
3653 goto done;
3655 (void) strlcpy(prop_val[cnt++], str, DLADM_PROP_VAL_MAX);
3656 str = strtok(NULL, ",");
3659 *val_cntp = cnt;
3661 done:
3662 dladm_destroy_conf(handle, conf);
3663 return (status);
3667 * Walk persistent private link properties of a link.
3669 static dladm_status_t
3670 i_dladm_walk_linkprop_priv_db(dladm_handle_t handle, datalink_id_t linkid,
3671 void *arg, int (*func)(dladm_handle_t, datalink_id_t, const char *, void *))
3673 dladm_status_t status;
3674 dladm_conf_t conf;
3675 char last_attr[MAXLINKATTRLEN];
3676 char attr[MAXLINKATTRLEN];
3677 char attrval[MAXLINKATTRVALLEN];
3678 size_t attrsz;
3680 if (linkid == DATALINK_INVALID_LINKID || func == NULL)
3681 return (DLADM_STATUS_BADARG);
3683 status = dladm_getsnap_conf(handle, linkid, &conf);
3684 if (status != DLADM_STATUS_OK)
3685 return (status);
3687 last_attr[0] = '\0';
3688 while ((status = dladm_getnext_conf_linkprop(handle, conf, last_attr,
3689 attr, attrval, MAXLINKATTRVALLEN, &attrsz)) == DLADM_STATUS_OK) {
3690 if (attr[0] == '_') {
3691 if (func(handle, linkid, attr, arg) ==
3692 DLADM_WALK_TERMINATE)
3693 break;
3695 (void) strlcpy(last_attr, attr, MAXLINKATTRLEN);
3698 dladm_destroy_conf(handle, conf);
3699 return (DLADM_STATUS_OK);
3702 static link_attr_t *
3703 dladm_name2prop(const char *prop_name)
3705 link_attr_t *p;
3707 for (p = link_attr; p->pp_id != MAC_PROP_PRIVATE; p++) {
3708 if (strcmp(p->pp_name, prop_name) == 0)
3709 break;
3711 return (p);
3714 static link_attr_t *
3715 dladm_id2prop(mac_prop_id_t propid)
3717 link_attr_t *p;
3719 for (p = link_attr; p->pp_id != MAC_PROP_PRIVATE; p++) {
3720 if (p->pp_id == propid)
3721 break;
3723 return (p);
3726 static dld_ioc_macprop_t *
3727 i_dladm_buf_alloc_impl(size_t valsize, datalink_id_t linkid,
3728 const char *prop_name, mac_prop_id_t propid, uint_t flags,
3729 dladm_status_t *status)
3731 int dsize;
3732 dld_ioc_macprop_t *dip;
3734 *status = DLADM_STATUS_OK;
3735 dsize = MAC_PROP_BUFSIZE(valsize);
3736 dip = malloc(dsize);
3737 if (dip == NULL) {
3738 *status = DLADM_STATUS_NOMEM;
3739 return (NULL);
3741 bzero(dip, dsize);
3742 dip->pr_valsize = valsize;
3743 (void) strlcpy(dip->pr_name, prop_name, sizeof (dip->pr_name));
3744 dip->pr_linkid = linkid;
3745 dip->pr_num = propid;
3746 dip->pr_flags = flags;
3747 return (dip);
3750 static dld_ioc_macprop_t *
3751 i_dladm_buf_alloc_by_name(size_t valsize, datalink_id_t linkid,
3752 const char *prop_name, uint_t flags, dladm_status_t *status)
3754 link_attr_t *p;
3756 p = dladm_name2prop(prop_name);
3757 valsize = MAX(p->pp_valsize, valsize);
3758 return (i_dladm_buf_alloc_impl(valsize, linkid, prop_name, p->pp_id,
3759 flags, status));
3762 static dld_ioc_macprop_t *
3763 i_dladm_buf_alloc_by_id(size_t valsize, datalink_id_t linkid,
3764 mac_prop_id_t propid, uint_t flags, dladm_status_t *status)
3766 link_attr_t *p;
3768 p = dladm_id2prop(propid);
3769 valsize = MAX(p->pp_valsize, valsize);
3770 return (i_dladm_buf_alloc_impl(valsize, linkid, p->pp_name, propid,
3771 flags, status));
3774 /* ARGSUSED */
3775 static dladm_status_t
3776 set_public_prop(dladm_handle_t handle, prop_desc_t *pdp,
3777 datalink_id_t linkid, val_desc_t *vdp, uint_t val_cnt, uint_t flags,
3778 datalink_media_t media)
3780 dld_ioc_macprop_t *dip;
3781 dladm_status_t status = DLADM_STATUS_OK;
3782 uint8_t u8;
3783 uint16_t u16;
3784 uint32_t u32;
3785 void *val;
3787 dip = i_dladm_buf_alloc_by_name(0, linkid, pdp->pd_name, 0, &status);
3788 if (dip == NULL)
3789 return (status);
3791 if (pdp->pd_flags & PD_CHECK_ALLOC)
3792 val = (void *)vdp->vd_val;
3793 else {
3795 * Currently all 1/2/4-byte size properties are byte/word/int.
3796 * No need (yet) to distinguish these from arrays of same size.
3798 switch (dip->pr_valsize) {
3799 case 1:
3800 u8 = vdp->vd_val;
3801 val = &u8;
3802 break;
3803 case 2:
3804 u16 = vdp->vd_val;
3805 val = &u16;
3806 break;
3807 case 4:
3808 u32 = vdp->vd_val;
3809 val = &u32;
3810 break;
3811 default:
3812 val = &vdp->vd_val;
3813 break;
3817 if (val != NULL)
3818 (void) memcpy(dip->pr_val, val, dip->pr_valsize);
3819 else
3820 dip->pr_valsize = 0;
3822 status = i_dladm_macprop(handle, dip, B_TRUE);
3824 done:
3825 free(dip);
3826 return (status);
3829 dladm_status_t
3830 i_dladm_macprop(dladm_handle_t handle, void *dip, boolean_t set)
3832 dladm_status_t status = DLADM_STATUS_OK;
3834 if (ioctl(dladm_dld_fd(handle),
3835 (set ? DLDIOC_SETMACPROP : DLDIOC_GETMACPROP), dip))
3836 status = dladm_errno2status(errno);
3838 return (status);
3841 static dladm_status_t
3842 i_dladm_get_public_prop(dladm_handle_t handle, datalink_id_t linkid,
3843 char *prop_name, uint_t flags, uint_t *perm_flags, void *arg, size_t size)
3845 dld_ioc_macprop_t *dip;
3846 dladm_status_t status;
3848 dip = i_dladm_buf_alloc_by_name(0, linkid, prop_name, flags, &status);
3849 if (dip == NULL)
3850 return (DLADM_STATUS_NOMEM);
3852 status = i_dladm_macprop(handle, dip, B_FALSE);
3853 if (status != DLADM_STATUS_OK) {
3854 free(dip);
3855 return (status);
3858 if (perm_flags != NULL)
3859 *perm_flags = dip->pr_perm_flags;
3861 if (arg != NULL)
3862 (void) memcpy(arg, dip->pr_val, size);
3863 free(dip);
3864 return (DLADM_STATUS_OK);
3867 /* ARGSUSED */
3868 static dladm_status_t
3869 check_uint32(dladm_handle_t handle, prop_desc_t *pdp,
3870 datalink_id_t linkid, char **prop_val, uint_t *val_cntp, uint_t flags,
3871 val_desc_t **vp, datalink_media_t media)
3873 uint_t val_cnt = *val_cntp;
3874 val_desc_t *v = *vp;
3876 if (val_cnt != 1)
3877 return (DLADM_STATUS_BADVAL);
3878 v->vd_val = strtoul(prop_val[0], NULL, 0);
3879 return (DLADM_STATUS_OK);
3882 /* ARGSUSED */
3883 static dladm_status_t
3884 get_duplex(dladm_handle_t handle, prop_desc_t *pdp,
3885 datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
3886 datalink_media_t media, uint_t flags, uint_t *perm_flags)
3888 link_duplex_t link_duplex;
3889 dladm_status_t status;
3891 if ((status = dladm_get_single_mac_stat(handle, linkid, "link_duplex",
3892 KSTAT_DATA_UINT32, &link_duplex)) != 0)
3893 return (status);
3895 switch (link_duplex) {
3896 case LINK_DUPLEX_FULL:
3897 (void) strcpy(*prop_val, "full");
3898 break;
3899 case LINK_DUPLEX_HALF:
3900 (void) strcpy(*prop_val, "half");
3901 break;
3902 default:
3903 (void) strcpy(*prop_val, "unknown");
3904 break;
3906 *val_cnt = 1;
3907 return (DLADM_STATUS_OK);
3910 /* ARGSUSED */
3911 static dladm_status_t
3912 get_speed(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
3913 char **prop_val, uint_t *val_cnt, datalink_media_t media, uint_t flags,
3914 uint_t *perm_flags)
3916 uint64_t ifspeed = 0;
3917 dladm_status_t status;
3919 if ((status = dladm_get_single_mac_stat(handle, linkid, "ifspeed",
3920 KSTAT_DATA_UINT64, &ifspeed)) != 0)
3921 return (status);
3923 if ((ifspeed % 1000000) != 0) {
3924 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX,
3925 "%llf", ifspeed / (float)1000000); /* Mbps */
3926 } else {
3927 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX,
3928 "%llu", ifspeed / 1000000); /* Mbps */
3930 *val_cnt = 1;
3931 *perm_flags = MAC_PROP_PERM_READ;
3932 return (DLADM_STATUS_OK);
3935 /* ARGSUSED */
3936 static dladm_status_t
3937 get_link_state(dladm_handle_t handle, prop_desc_t *pdp,
3938 datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
3939 datalink_media_t media, uint_t flags, uint_t *perm_flags)
3941 link_state_t link_state;
3942 dladm_status_t status;
3944 status = dladm_get_state(handle, linkid, &link_state);
3945 if (status != DLADM_STATUS_OK)
3946 return (status);
3948 switch (link_state) {
3949 case LINK_STATE_UP:
3950 (void) strcpy(*prop_val, "up");
3951 break;
3952 case LINK_STATE_DOWN:
3953 (void) strcpy(*prop_val, "down");
3954 break;
3955 default:
3956 (void) strcpy(*prop_val, "unknown");
3957 break;
3959 *val_cnt = 1;
3960 *perm_flags = MAC_PROP_PERM_READ;
3961 return (DLADM_STATUS_OK);
3964 /* ARGSUSED */
3965 static dladm_status_t
3966 get_binary(dladm_handle_t handle, prop_desc_t *pdp,
3967 datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
3968 datalink_media_t media, uint_t flags, uint_t *perm_flags)
3970 dladm_status_t status;
3971 uint_t v = 0;
3973 status = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags,
3974 perm_flags, &v, sizeof (v));
3975 if (status != DLADM_STATUS_OK)
3976 return (status);
3978 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "%d", (uint_t)(v > 0));
3979 *val_cnt = 1;
3980 return (DLADM_STATUS_OK);
3983 /* ARGSUSED */
3984 static dladm_status_t
3985 get_uint32(dladm_handle_t handle, prop_desc_t *pdp,
3986 datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
3987 datalink_media_t media, uint_t flags, uint_t *perm_flags)
3989 dladm_status_t status;
3990 uint32_t v = 0;
3992 status = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags,
3993 perm_flags, &v, sizeof (v));
3994 if (status != DLADM_STATUS_OK)
3995 return (status);
3997 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "%ld", v);
3998 *val_cnt = 1;
3999 return (DLADM_STATUS_OK);
4002 /* ARGSUSED */
4003 static dladm_status_t
4004 get_range(dladm_handle_t handle, prop_desc_t *pdp,
4005 datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
4006 datalink_media_t media, uint_t flags, uint_t *perm_flags)
4008 dld_ioc_macprop_t *dip;
4009 dladm_status_t status = DLADM_STATUS_OK;
4010 size_t sz;
4011 uint_t rcount;
4012 mac_propval_range_t *rangep;
4015 * As caller we don't know number of value ranges, the driver
4016 * supports. To begin with we assume that number to be 1. If the
4017 * buffer size is insufficient, driver returns back with the
4018 * actual count of value ranges. See mac.h for more details.
4020 sz = sizeof (mac_propval_range_t);
4021 rcount = 1;
4022 retry:
4023 if ((dip = i_dladm_buf_alloc_by_name(sz, linkid, pdp->pd_name, flags,
4024 &status)) == NULL)
4025 return (status);
4027 rangep = (mac_propval_range_t *)(void *)&dip->pr_val;
4028 rangep->mpr_count = rcount;
4030 status = i_dladm_macprop(handle, dip, B_FALSE);
4031 if (status != DLADM_STATUS_OK) {
4032 if (status == DLADM_STATUS_TOOSMALL) {
4033 int err;
4035 if ((err = i_dladm_range_size(rangep, &sz, &rcount))
4036 == 0) {
4037 free(dip);
4038 goto retry;
4039 } else {
4040 status = dladm_errno2status(err);
4043 free(dip);
4044 return (status);
4047 if (rangep->mpr_count == 0) {
4048 *val_cnt = 1;
4049 (void) snprintf(prop_val[0], DLADM_PROP_VAL_MAX, "--");
4050 goto done;
4053 switch (rangep->mpr_type) {
4054 case MAC_PROPVAL_UINT32: {
4055 mac_propval_uint32_range_t *ur;
4056 uint_t count = rangep->mpr_count, i;
4058 ur = &rangep->mpr_range_uint32[0];
4060 for (i = 0; i < count; i++, ur++) {
4061 if (ur->mpur_min == ur->mpur_max) {
4062 (void) snprintf(prop_val[i], DLADM_PROP_VAL_MAX,
4063 "%ld", ur->mpur_min);
4064 } else {
4065 (void) snprintf(prop_val[i], DLADM_PROP_VAL_MAX,
4066 "%ld-%ld", ur->mpur_min, ur->mpur_max);
4069 *val_cnt = count;
4070 break;
4072 default:
4073 status = DLADM_STATUS_BADARG;
4074 break;
4076 done:
4077 free(dip);
4078 return (status);
4081 /* ARGSUSED */
4082 static dladm_status_t
4083 get_tagmode(dladm_handle_t handle, prop_desc_t *pdp,
4084 datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
4085 datalink_media_t media, uint_t flags, uint_t *perm_flags)
4087 link_tagmode_t mode;
4088 dladm_status_t status;
4090 status = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags,
4091 perm_flags, &mode, sizeof (mode));
4092 if (status != DLADM_STATUS_OK)
4093 return (status);
4095 switch (mode) {
4096 case LINK_TAGMODE_NORMAL:
4097 (void) strlcpy(*prop_val, "normal", DLADM_PROP_VAL_MAX);
4098 break;
4099 case LINK_TAGMODE_VLANONLY:
4100 (void) strlcpy(*prop_val, "vlanonly", DLADM_PROP_VAL_MAX);
4101 break;
4102 default:
4103 (void) strlcpy(*prop_val, "unknown", DLADM_PROP_VAL_MAX);
4105 *val_cnt = 1;
4106 return (DLADM_STATUS_OK);
4109 /* ARGSUSED */
4110 static dladm_status_t
4111 get_flowctl(dladm_handle_t handle, prop_desc_t *pdp,
4112 datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
4113 datalink_media_t media, uint_t flags, uint_t *perm_flags)
4115 link_flowctrl_t v;
4116 dladm_status_t status;
4118 status = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags,
4119 perm_flags, &v, sizeof (v));
4120 if (status != DLADM_STATUS_OK)
4121 return (status);
4123 switch (v) {
4124 case LINK_FLOWCTRL_NONE:
4125 (void) sprintf(*prop_val, "no");
4126 break;
4127 case LINK_FLOWCTRL_RX:
4128 (void) sprintf(*prop_val, "rx");
4129 break;
4130 case LINK_FLOWCTRL_TX:
4131 (void) sprintf(*prop_val, "tx");
4132 break;
4133 case LINK_FLOWCTRL_BI:
4134 (void) sprintf(*prop_val, "bi");
4135 break;
4137 *val_cnt = 1;
4138 return (DLADM_STATUS_OK);
4142 /* ARGSUSED */
4143 static dladm_status_t
4144 i_dladm_set_private_prop(dladm_handle_t handle, datalink_id_t linkid,
4145 const char *prop_name, char **prop_val, uint_t val_cnt, uint_t flags)
4147 int i, slen;
4148 int bufsize = 0;
4149 dld_ioc_macprop_t *dip = NULL;
4150 uchar_t *dp;
4151 link_attr_t *p;
4152 dladm_status_t status = DLADM_STATUS_OK;
4154 if ((prop_name == NULL && prop_val != NULL) ||
4155 (prop_val != NULL && val_cnt == 0))
4156 return (DLADM_STATUS_BADARG);
4157 p = dladm_name2prop(prop_name);
4158 if (p->pp_id != MAC_PROP_PRIVATE)
4159 return (DLADM_STATUS_BADARG);
4161 if (!(flags & DLADM_OPT_ACTIVE))
4162 return (DLADM_STATUS_OK);
4165 * private properties: all parsing is done in the kernel.
4166 * allocate a enough space for each property + its separator (',').
4168 for (i = 0; i < val_cnt; i++) {
4169 bufsize += strlen(prop_val[i]) + 1;
4172 if (prop_val == NULL) {
4174 * getting default value. so use more buffer space.
4176 bufsize += DLADM_PROP_BUF_CHUNK;
4179 dip = i_dladm_buf_alloc_by_name(bufsize + 1, linkid, prop_name,
4180 (prop_val != NULL ? 0 : DLD_PROP_DEFAULT), &status);
4181 if (dip == NULL)
4182 return (status);
4184 dp = (uchar_t *)dip->pr_val;
4185 slen = 0;
4187 if (prop_val == NULL) {
4188 status = i_dladm_macprop(handle, dip, B_FALSE);
4189 dip->pr_flags = 0;
4190 } else {
4191 for (i = 0; i < val_cnt; i++) {
4192 int plen = 0;
4194 plen = strlen(prop_val[i]);
4195 bcopy(prop_val[i], dp, plen);
4196 slen += plen;
4198 * add a "," separator and update dp.
4200 if (i != (val_cnt -1))
4201 dp[slen++] = ',';
4202 dp += (plen + 1);
4205 if (status == DLADM_STATUS_OK)
4206 status = i_dladm_macprop(handle, dip, B_TRUE);
4208 free(dip);
4209 return (status);
4212 static dladm_status_t
4213 i_dladm_get_priv_prop(dladm_handle_t handle, datalink_id_t linkid,
4214 const char *prop_name, char **prop_val, uint_t *val_cnt,
4215 dladm_prop_type_t type, uint_t dld_flags)
4217 dladm_status_t status = DLADM_STATUS_OK;
4218 dld_ioc_macprop_t *dip = NULL;
4219 link_attr_t *p;
4221 if ((prop_name == NULL && prop_val != NULL) ||
4222 (prop_val != NULL && val_cnt == 0))
4223 return (DLADM_STATUS_BADARG);
4225 p = dladm_name2prop(prop_name);
4226 if (p->pp_id != MAC_PROP_PRIVATE)
4227 return (DLADM_STATUS_BADARG);
4230 * private properties: all parsing is done in the kernel.
4232 dip = i_dladm_buf_alloc_by_name(DLADM_PROP_BUF_CHUNK, linkid, prop_name,
4233 dld_flags, &status);
4234 if (dip == NULL)
4235 return (status);
4237 if ((status = i_dladm_macprop(handle, dip, B_FALSE)) ==
4238 DLADM_STATUS_OK) {
4239 if (type == DLADM_PROP_VAL_PERM) {
4240 (void) dladm_perm2str(dip->pr_perm_flags, *prop_val);
4241 } else if (type == DLADM_PROP_VAL_MODIFIABLE) {
4242 *prop_val[0] = '\0';
4243 } else {
4244 (void) strncpy(*prop_val, dip->pr_val,
4245 DLADM_PROP_VAL_MAX);
4247 *val_cnt = 1;
4248 } else if ((status == DLADM_STATUS_NOTSUP) &&
4249 (type == DLADM_PROP_VAL_CURRENT)) {
4250 status = DLADM_STATUS_NOTFOUND;
4252 free(dip);
4253 return (status);
4257 static dladm_status_t
4258 i_dladm_getset_defval(dladm_handle_t handle, prop_desc_t *pdp,
4259 datalink_id_t linkid, datalink_media_t media, uint_t flags)
4261 dladm_status_t status;
4262 char **prop_vals = NULL, *buf;
4263 size_t bufsize;
4264 uint_t cnt;
4265 int i;
4266 uint_t perm_flags;
4269 * Allocate buffer needed for prop_vals array. We can have at most
4270 * DLADM_MAX_PROP_VALCNT char *prop_vals[] entries, where
4271 * each entry has max size DLADM_PROP_VAL_MAX
4273 bufsize =
4274 (sizeof (char *) + DLADM_PROP_VAL_MAX) * DLADM_MAX_PROP_VALCNT;
4275 buf = malloc(bufsize);
4276 prop_vals = (char **)(void *)buf;
4277 for (i = 0; i < DLADM_MAX_PROP_VALCNT; i++) {
4278 prop_vals[i] = buf +
4279 sizeof (char *) * DLADM_MAX_PROP_VALCNT +
4280 i * DLADM_PROP_VAL_MAX;
4284 * For properties which have pdp->pd_defval.vd_name as a non-empty
4285 * string, the "" itself is used to reset the property (exceptions
4286 * are zone and autopush, which populate vdp->vd_val). So
4287 * libdladm can copy pdp->pd_defval over to the val_desc_t passed
4288 * down on the setprop using the global values in the table. For
4289 * other cases (vd_name is ""), doing reset-linkprop will cause
4290 * libdladm to do a getprop to find the default value and then do
4291 * a setprop to reset the value to default.
4293 status = pdp->pd_get(handle, pdp, linkid, prop_vals, &cnt, media,
4294 DLD_PROP_DEFAULT, &perm_flags);
4295 if (status == DLADM_STATUS_OK) {
4296 if (perm_flags == MAC_PROP_PERM_RW) {
4297 status = i_dladm_set_single_prop(handle, linkid,
4298 pdp->pd_class, media, pdp, prop_vals, cnt, flags);
4300 else
4301 status = DLADM_STATUS_NOTSUP;
4303 free(buf);
4304 return (status);
4307 /* ARGSUSED */
4308 static dladm_status_t
4309 get_stp(dladm_handle_t handle, struct prop_desc *pd, datalink_id_t linkid,
4310 char **prop_val, uint_t *val_cnt, datalink_media_t media, uint_t flags,
4311 uint_t *perm_flags)
4313 const bridge_public_prop_t *bpp;
4314 dladm_status_t retv;
4315 int val, i;
4317 if (flags != 0)
4318 return (DLADM_STATUS_NOTSUP);
4319 *perm_flags = MAC_PROP_PERM_RW;
4320 *val_cnt = 1;
4321 for (bpp = bridge_prop; bpp->bpp_name != NULL; bpp++)
4322 if (strcmp(bpp->bpp_name, pd->pd_name) == 0)
4323 break;
4324 retv = dladm_bridge_get_port_cfg(handle, linkid, bpp->bpp_code, &val);
4325 /* If the daemon isn't running, then return the persistent value */
4326 if (retv == DLADM_STATUS_NOTFOUND) {
4327 if (i_dladm_get_linkprop_db(handle, linkid, pd->pd_name,
4328 prop_val, val_cnt) != DLADM_STATUS_OK)
4329 (void) strlcpy(*prop_val, pd->pd_defval.vd_name,
4330 DLADM_PROP_VAL_MAX);
4331 return (DLADM_STATUS_OK);
4333 if (retv != DLADM_STATUS_OK) {
4334 (void) strlcpy(*prop_val, "?", DLADM_PROP_VAL_MAX);
4335 return (retv);
4337 if (val == pd->pd_defval.vd_val && pd->pd_defval.vd_name[0] != '\0') {
4338 (void) strlcpy(*prop_val, pd->pd_defval.vd_name,
4339 DLADM_PROP_VAL_MAX);
4340 return (DLADM_STATUS_OK);
4342 for (i = 0; i < pd->pd_noptval; i++) {
4343 if (val == pd->pd_optval[i].vd_val) {
4344 (void) strlcpy(*prop_val, pd->pd_optval[i].vd_name,
4345 DLADM_PROP_VAL_MAX);
4346 return (DLADM_STATUS_OK);
4349 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "%u", (unsigned)val);
4350 return (DLADM_STATUS_OK);
4353 /* ARGSUSED1 */
4354 static dladm_status_t
4355 set_stp_prop(dladm_handle_t handle, prop_desc_t *pd, datalink_id_t linkid,
4356 val_desc_t *vdp, uint_t val_cnt, uint_t flags, datalink_media_t media)
4359 * Special case for mcheck: the daemon resets the value to zero, and we
4360 * don't want the daemon to refresh itself; it leads to deadlock.
4362 if (flags & DLADM_OPT_NOREFRESH)
4363 return (DLADM_STATUS_OK);
4365 /* Tell the running daemon, if any */
4366 return (dladm_bridge_refresh(handle, linkid));
4370 * This is used only for stp_priority, stp_cost, and stp_mcheck.
4372 /* ARGSUSED */
4373 static dladm_status_t
4374 check_stp_prop(dladm_handle_t handle, struct prop_desc *pd,
4375 datalink_id_t linkid, char **prop_val, uint_t *val_cntp, uint_t flags,
4376 val_desc_t **vdpp, datalink_media_t media)
4378 char *cp;
4379 boolean_t iscost;
4380 uint_t val_cnt = *val_cntp;
4381 val_desc_t *vdp = *vdpp;
4383 if (val_cnt != 1)
4384 return (DLADM_STATUS_BADVALCNT);
4386 if (prop_val == NULL) {
4387 vdp->vd_val = 0;
4388 } else {
4389 /* Only stp_priority and stp_cost use this function */
4390 iscost = strcmp(pd->pd_name, "stp_cost") == 0;
4392 if (iscost && strcmp(prop_val[0], "auto") == 0) {
4393 /* Illegal value 0 is allowed to mean "automatic" */
4394 vdp->vd_val = 0;
4395 } else {
4396 errno = 0;
4397 vdp->vd_val = strtoul(prop_val[0], &cp, 0);
4398 if (errno != 0 || *cp != '\0')
4399 return (DLADM_STATUS_BADVAL);
4403 if (iscost) {
4404 return (vdp->vd_val > 65535 ? DLADM_STATUS_BADVAL :
4405 DLADM_STATUS_OK);
4406 } else {
4407 if (vdp->vd_val > 255)
4408 return (DLADM_STATUS_BADVAL);
4410 * If the user is setting stp_mcheck non-zero, then (per the
4411 * IEEE management standards and UNH testing) we need to check
4412 * whether this link is part of a bridge that is running RSTP.
4413 * If it's not, then setting the flag is an error. Note that
4414 * errors are intentionally discarded here; it's the value
4415 * that's the problem -- it's not a bad value, merely one that
4416 * can't be used now.
4418 if (strcmp(pd->pd_name, "stp_mcheck") == 0 &&
4419 vdp->vd_val != 0) {
4420 char bridge[MAXLINKNAMELEN];
4421 UID_STP_CFG_T cfg;
4422 dladm_bridge_prot_t brprot;
4424 if (dladm_bridge_getlink(handle, linkid, bridge,
4425 sizeof (bridge)) != DLADM_STATUS_OK ||
4426 dladm_bridge_get_properties(bridge, &cfg,
4427 &brprot) != DLADM_STATUS_OK)
4428 return (DLADM_STATUS_FAILED);
4429 if (cfg.force_version <= 1)
4430 return (DLADM_STATUS_FAILED);
4432 return (DLADM_STATUS_OK);
4436 /* ARGSUSED */
4437 static dladm_status_t
4438 get_bridge_forward(dladm_handle_t handle, struct prop_desc *pd,
4439 datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
4440 datalink_media_t media, uint_t flags, uint_t *perm_flags)
4442 dladm_status_t retv;
4443 uint_t val;
4445 if (flags != 0)
4446 return (DLADM_STATUS_NOTSUP);
4447 *perm_flags = MAC_PROP_PERM_RW;
4448 *val_cnt = 1;
4449 retv = dladm_bridge_get_forwarding(handle, linkid, &val);
4450 if (retv == DLADM_STATUS_NOTFOUND) {
4451 if (i_dladm_get_linkprop_db(handle, linkid, pd->pd_name,
4452 prop_val, val_cnt) != DLADM_STATUS_OK)
4453 (void) strlcpy(*prop_val, pd->pd_defval.vd_name,
4454 DLADM_PROP_VAL_MAX);
4455 return (DLADM_STATUS_OK);
4457 if (retv == DLADM_STATUS_OK)
4458 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "%u", val);
4459 else
4460 (void) strlcpy(*prop_val, "?", DLADM_PROP_VAL_MAX);
4461 return (retv);
4464 /* ARGSUSED */
4465 static dladm_status_t
4466 set_bridge_forward(dladm_handle_t handle, prop_desc_t *pd, datalink_id_t linkid,
4467 val_desc_t *vdp, uint_t val_cnt, uint_t flags, datalink_media_t media)
4469 /* Tell the running daemon, if any */
4470 return (dladm_bridge_refresh(handle, linkid));
4473 /* ARGSUSED */
4474 static dladm_status_t
4475 get_bridge_pvid(dladm_handle_t handle, struct prop_desc *pd,
4476 datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
4477 datalink_media_t media, uint_t flags, uint_t *perm_flags)
4479 dladm_status_t status;
4480 dld_ioc_macprop_t *dip;
4481 uint16_t pvid;
4483 if (flags != 0)
4484 return (DLADM_STATUS_NOTSUP);
4485 *perm_flags = MAC_PROP_PERM_RW;
4486 *val_cnt = 1;
4487 dip = i_dladm_buf_alloc_by_id(sizeof (uint16_t), linkid, MAC_PROP_PVID,
4488 0, &status);
4489 if (dip == NULL)
4490 return (status);
4491 status = i_dladm_macprop(handle, dip, B_FALSE);
4492 if (status == DLADM_STATUS_OK) {
4493 (void) memcpy(&pvid, dip->pr_val, sizeof (pvid));
4494 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "%u", pvid);
4495 } else {
4496 (void) strlcpy(*prop_val, "?", DLADM_PROP_VAL_MAX);
4498 free(dip);
4499 return (status);
4502 /* ARGSUSED */
4503 static dladm_status_t
4504 set_bridge_pvid(dladm_handle_t handle, prop_desc_t *pd, datalink_id_t linkid,
4505 val_desc_t *vdp, uint_t val_cnt, uint_t flags, datalink_media_t media)
4507 dladm_status_t status;
4508 dld_ioc_macprop_t *dip;
4509 uint16_t pvid;
4511 dip = i_dladm_buf_alloc_by_id(sizeof (uint16_t), linkid, MAC_PROP_PVID,
4512 0, &status);
4513 if (dip == NULL)
4514 return (status);
4515 pvid = vdp->vd_val;
4516 (void) memcpy(dip->pr_val, &pvid, sizeof (pvid));
4517 status = i_dladm_macprop(handle, dip, B_TRUE);
4518 free(dip);
4519 if (status != DLADM_STATUS_OK)
4520 return (status);
4522 /* Tell the running daemon, if any */
4523 return (dladm_bridge_refresh(handle, linkid));
4526 /* ARGSUSED */
4527 static dladm_status_t
4528 check_bridge_pvid(dladm_handle_t handle, struct prop_desc *pd,
4529 datalink_id_t linkid, char **prop_val, uint_t *val_cntp, uint_t flags,
4530 val_desc_t **vdpp, datalink_media_t media)
4532 char *cp;
4533 uint_t val_cnt = *val_cntp;
4534 val_desc_t *vdp = *vdpp;
4536 if (val_cnt != 1)
4537 return (DLADM_STATUS_BADVALCNT);
4539 if (prop_val == NULL) {
4540 vdp->vd_val = 1;
4541 } else {
4542 errno = 0;
4543 vdp->vd_val = strtoul(prop_val[0], &cp, 0);
4544 if (errno != 0 || *cp != '\0')
4545 return (DLADM_STATUS_BADVAL);
4548 return (vdp->vd_val > VLAN_ID_MAX ? DLADM_STATUS_BADVAL :
4549 DLADM_STATUS_OK);
4552 dladm_status_t
4553 i_dladm_wlan_param(dladm_handle_t handle, datalink_id_t linkid, void *buf,
4554 mac_prop_id_t cmd, size_t len, boolean_t set)
4556 uint32_t flags;
4557 dladm_status_t status;
4558 uint32_t media;
4559 dld_ioc_macprop_t *dip;
4560 void *dp;
4562 if ((status = dladm_datalink_id2info(handle, linkid, &flags, NULL,
4563 &media, NULL, 0)) != DLADM_STATUS_OK) {
4564 return (status);
4567 if (media != DL_WIFI)
4568 return (DLADM_STATUS_BADARG);
4570 if (!(flags & DLADM_OPT_ACTIVE))
4571 return (DLADM_STATUS_TEMPONLY);
4573 if (len == (MAX_BUF_LEN - WIFI_BUF_OFFSET))
4574 len = MAX_BUF_LEN - sizeof (dld_ioc_macprop_t) - 1;
4576 dip = i_dladm_buf_alloc_by_id(len, linkid, cmd, 0, &status);
4577 if (dip == NULL)
4578 return (DLADM_STATUS_NOMEM);
4580 dp = (uchar_t *)dip->pr_val;
4581 if (set)
4582 (void) memcpy(dp, buf, len);
4584 status = i_dladm_macprop(handle, dip, set);
4585 if (status == DLADM_STATUS_OK) {
4586 if (!set)
4587 (void) memcpy(buf, dp, len);
4590 free(dip);
4591 return (status);
4594 dladm_status_t
4595 dladm_parse_link_props(char *str, dladm_arg_list_t **listp, boolean_t novalues)
4597 return (dladm_parse_args(str, listp, novalues));
4601 * Retrieve the one link property from the database
4603 /*ARGSUSED*/
4604 static int
4605 i_dladm_get_one_prop(dladm_handle_t handle, datalink_id_t linkid,
4606 const char *prop_name, void *arg)
4608 dladm_arg_list_t *proplist = arg;
4609 dladm_arg_info_t *aip = NULL;
4611 aip = &proplist->al_info[proplist->al_count];
4613 * it is fine to point to prop_name since prop_name points to the
4614 * prop_table[n].pd_name.
4616 aip->ai_name = prop_name;
4618 (void) dladm_get_linkprop(handle, linkid, DLADM_PROP_VAL_PERSISTENT,
4619 prop_name, aip->ai_val, &aip->ai_count);
4621 if (aip->ai_count != 0)
4622 proplist->al_count++;
4624 return (DLADM_WALK_CONTINUE);
4629 * Retrieve all link properties for a link from the database and
4630 * return a property list.
4632 dladm_status_t
4633 dladm_link_get_proplist(dladm_handle_t handle, datalink_id_t linkid,
4634 dladm_arg_list_t **listp)
4636 dladm_arg_list_t *list;
4637 dladm_status_t status = DLADM_STATUS_OK;
4639 list = calloc(1, sizeof (dladm_arg_list_t));
4640 if (list == NULL)
4641 return (dladm_errno2status(errno));
4643 status = dladm_walk_linkprop(handle, linkid, list,
4644 i_dladm_get_one_prop);
4646 *listp = list;
4647 return (status);
4651 * Retrieve the named property from a proplist, check the value and
4652 * convert to a kernel structure.
4654 static dladm_status_t
4655 i_dladm_link_proplist_extract_one(dladm_handle_t handle,
4656 dladm_arg_list_t *proplist, const char *name, uint_t flags, void *arg)
4658 dladm_status_t status;
4659 dladm_arg_info_t *aip = NULL;
4660 int i, j;
4662 /* Find named property in proplist */
4663 for (i = 0; i < proplist->al_count; i++) {
4664 aip = &proplist->al_info[i];
4665 if (strcasecmp(aip->ai_name, name) == 0)
4666 break;
4669 /* Property not in list */
4670 if (i == proplist->al_count)
4671 return (DLADM_STATUS_OK);
4673 for (i = 0; i < DLADM_MAX_PROPS; i++) {
4674 prop_desc_t *pdp = &prop_table[i];
4675 val_desc_t *vdp;
4677 vdp = malloc(sizeof (val_desc_t) * aip->ai_count);
4678 if (vdp == NULL)
4679 return (DLADM_STATUS_NOMEM);
4681 if (strcasecmp(aip->ai_name, pdp->pd_name) != 0)
4682 continue;
4684 if (aip->ai_val == NULL)
4685 return (DLADM_STATUS_BADARG);
4687 /* Check property value */
4688 if (pdp->pd_check != NULL) {
4689 status = pdp->pd_check(handle, pdp, 0, aip->ai_val,
4690 &(aip->ai_count), flags, &vdp, 0);
4691 } else {
4692 status = DLADM_STATUS_BADARG;
4695 if (status != DLADM_STATUS_OK)
4696 return (status);
4698 for (j = 0; j < DLADM_MAX_RSRC_PROP; j++) {
4699 resource_prop_t *rpp = &rsrc_prop_table[j];
4701 if (strcasecmp(aip->ai_name, rpp->rp_name) != 0)
4702 continue;
4704 /* Extract kernel structure */
4705 if (rpp->rp_extract != NULL) {
4706 status = rpp->rp_extract(vdp,
4707 aip->ai_count, arg);
4708 } else {
4709 status = DLADM_STATUS_BADARG;
4711 break;
4714 if (status != DLADM_STATUS_OK)
4715 return (status);
4717 break;
4719 return (status);
4723 * Extract properties from a proplist and convert to mac_resource_props_t.
4725 dladm_status_t
4726 dladm_link_proplist_extract(dladm_handle_t handle, dladm_arg_list_t *proplist,
4727 mac_resource_props_t *mrp, uint_t flags)
4729 dladm_status_t status;
4730 int i;
4732 for (i = 0; i < DLADM_MAX_RSRC_PROP; i++) {
4733 status = i_dladm_link_proplist_extract_one(handle,
4734 proplist, rsrc_prop_table[i].rp_name, flags, mrp);
4735 if (status != DLADM_STATUS_OK)
4736 return (status);
4738 return (status);
4741 static const char *
4742 dladm_perm2str(uint_t perm, char *buf)
4744 (void) snprintf(buf, DLADM_STRSIZE, "%c%c",
4745 ((perm & MAC_PROP_PERM_READ) != 0) ? 'r' : '-',
4746 ((perm & MAC_PROP_PERM_WRITE) != 0) ? 'w' : '-');
4747 return (buf);
4750 dladm_status_t
4751 dladm_get_state(dladm_handle_t handle, datalink_id_t linkid,
4752 link_state_t *state)
4754 uint_t perms;
4756 return (i_dladm_get_public_prop(handle, linkid, "state", 0,
4757 &perms, state, sizeof (*state)));
4760 boolean_t
4761 dladm_attr_is_linkprop(const char *name)
4763 /* non-property attribute names */
4764 const char *nonprop[] = {
4765 /* dlmgmtd core attributes */
4766 "name",
4767 "class",
4768 "media",
4769 FPHYMAJ,
4770 FPHYINST,
4771 FDEVNAME,
4773 /* other attributes for vlan, aggr, etc */
4774 DLADM_ATTR_NAMES
4776 boolean_t is_nonprop = B_FALSE;
4777 int i;
4779 for (i = 0; i < sizeof (nonprop) / sizeof (nonprop[0]); i++) {
4780 if (strcmp(name, nonprop[i]) == 0) {
4781 is_nonprop = B_TRUE;
4782 break;
4786 return (!is_nonprop);
4789 dladm_status_t
4790 dladm_linkprop_is_set(dladm_handle_t handle, datalink_id_t linkid,
4791 dladm_prop_type_t type, const char *prop_name, boolean_t *is_set)
4793 char *buf, **propvals;
4794 uint_t valcnt = DLADM_MAX_PROP_VALCNT;
4795 int i;
4796 dladm_status_t status = DLADM_STATUS_OK;
4797 size_t bufsize;
4799 *is_set = B_FALSE;
4801 bufsize = (sizeof (char *) + DLADM_PROP_VAL_MAX) *
4802 DLADM_MAX_PROP_VALCNT;
4803 if ((buf = calloc(1, bufsize)) == NULL)
4804 return (DLADM_STATUS_NOMEM);
4806 propvals = (char **)(void *)buf;
4807 for (i = 0; i < valcnt; i++) {
4808 propvals[i] = buf +
4809 sizeof (char *) * DLADM_MAX_PROP_VALCNT +
4810 i * DLADM_PROP_VAL_MAX;
4813 if (dladm_get_linkprop(handle, linkid, type, prop_name, propvals,
4814 &valcnt) != DLADM_STATUS_OK) {
4815 goto done;
4819 * valcnt is always set to 1 by get_pool(), hence we need to check
4820 * for a non-null string to see if it is set. For protection,
4821 * secondary-macs and allowed-ips, we can check either the *propval
4822 * or the valcnt.
4824 if ((strcmp(prop_name, "pool") == 0 ||
4825 strcmp(prop_name, "protection") == 0 ||
4826 strcmp(prop_name, "secondary-macs") == 0 ||
4827 strcmp(prop_name, "allowed-ips") == 0) &&
4828 (strlen(*propvals) != 0)) {
4829 *is_set = B_TRUE;
4830 } else if ((strcmp(prop_name, "cpus") == 0) && (valcnt != 0)) {
4831 *is_set = B_TRUE;
4832 } else if ((strcmp(prop_name, "_softmac") == 0) && (valcnt != 0) &&
4833 (strcmp(propvals[0], "true") == 0)) {
4834 *is_set = B_TRUE;
4837 done:
4838 if (buf != NULL)
4839 free(buf);
4840 return (status);
4843 /* ARGSUSED */
4844 static dladm_status_t
4845 get_linkmode_prop(dladm_handle_t handle, prop_desc_t *pdp,
4846 datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
4847 datalink_media_t media, uint_t flags, uint_t *perm_flags)
4849 char *s;
4850 uint32_t v;
4851 dladm_status_t status;
4853 status = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags,
4854 perm_flags, &v, sizeof (v));
4855 if (status != DLADM_STATUS_OK)
4856 return (status);
4858 switch (v) {
4859 case DLADM_PART_CM_MODE:
4860 s = "cm";
4861 break;
4862 case DLADM_PART_UD_MODE:
4863 s = "ud";
4864 break;
4865 default:
4866 s = "";
4867 break;
4869 (void) snprintf(prop_val[0], DLADM_STRSIZE, "%s", s);
4871 *val_cnt = 1;
4872 return (DLADM_STATUS_OK);
4875 /*ARGSUSED*/
4876 static dladm_status_t
4877 get_promisc_filtered(dladm_handle_t handle, prop_desc_t *pdp,
4878 datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
4879 datalink_media_t media, uint_t flags, uint_t *perm_flags)
4881 char *s;
4882 dladm_status_t status;
4883 boolean_t filt;
4885 status = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags,
4886 perm_flags, &filt, sizeof (filt));
4887 if (status != DLADM_STATUS_OK)
4888 return (status);
4890 if (filt != 0)
4891 s = link_promisc_filtered_vals[1].vd_name;
4892 else
4893 s = link_promisc_filtered_vals[0].vd_name;
4894 (void) snprintf(prop_val[0], DLADM_STRSIZE, "%s", s);
4896 *val_cnt = 1;
4897 return (DLADM_STATUS_OK);
4900 /* ARGSUSED */
4901 static dladm_status_t
4902 set_promisc_filtered(dladm_handle_t handle, prop_desc_t *pdp,
4903 datalink_id_t linkid, val_desc_t *vdp, uint_t val_cnt, uint_t flags,
4904 datalink_media_t media)
4906 dld_ioc_macprop_t *dip;
4907 dladm_status_t status = DLADM_STATUS_OK;
4909 dip = i_dladm_buf_alloc_by_name(0, linkid, pdp->pd_name,
4910 0, &status);
4912 if (dip == NULL)
4913 return (status);
4915 (void) memcpy(dip->pr_val, &vdp->vd_val, dip->pr_valsize);
4916 status = i_dladm_macprop(handle, dip, B_TRUE);
4918 free(dip);
4919 return (status);