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