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 uint_t 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 uint_t 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 uint_t i; 1239 1240 for (i = 0; i < DLADM_MAX_PROPS; i++) { 1241 if (strcasecmp(prop_name, prop_table[i].pd_name) == 0) { 1242 prop_name = prop_table[i].pd_name; 1243 break; 1244 } 1245 } 1246 } 1247 1248 /* 1249 * Check for valid link property against the flags passed 1250 * and set the link property when active flag is passed. 1251 */ 1252 status = dladm_datalink_id2info(handle, linkid, &link_flags, &class, 1253 &media, NULL, 0); 1254 if (status != DLADM_STATUS_OK) 1255 return (status); 1256 status = i_dladm_set_linkprop(handle, linkid, prop_name, prop_val, 1257 val_cnt, flags, class, media); 1258 if (status != DLADM_STATUS_OK) 1259 return (status); 1260 1261 /* 1262 * Write an entry to the persistent configuration database if 1263 * and only if the user has requested the property to be 1264 * persistent and the link is a persistent link. 1265 */ 1266 if ((flags & DLADM_OPT_PERSIST) && (link_flags & DLMGMT_PERSIST)) { 1267 status = i_dladm_set_linkprop_db(handle, linkid, prop_name, 1268 prop_val, val_cnt); 1269 1270 if (status == DLADM_STATUS_OK && (flags & DLADM_OPT_ACTIVE)) { 1271 prop_desc_t *pdp = prop_table; 1272 uint_t i; 1273 1274 for (i = 0; i < DLADM_MAX_PROPS; i++, pdp++) { 1275 if (!(pdp->pd_flags & PD_AFTER_PERM)) 1276 continue; 1277 if (prop_name != NULL && 1278 prop_name != pdp->pd_name) 1279 continue; 1280 status = pdp->pd_set(handle, pdp, linkid, NULL, 1281 0, flags, 0); 1282 } 1283 } 1284 } 1285 return (status); 1286 } 1287 1288 /* 1289 * Walk all link properties of the given specific link. 1290 * 1291 * Note: this function currently lacks the ability to walk _all_ private 1292 * properties if the link, because there is no kernel interface to 1293 * retrieve all known private property names. Once such an interface 1294 * is added, this function should be fixed accordingly. 1295 */ 1296 dladm_status_t 1297 dladm_walk_linkprop(dladm_handle_t handle, datalink_id_t linkid, void *arg, 1298 int (*func)(dladm_handle_t, datalink_id_t, const char *, void *)) 1299 { 1300 dladm_status_t status; 1301 datalink_class_t class; 1302 uint_t media; 1303 uint_t i; 1304 1305 if (linkid == DATALINK_INVALID_LINKID || func == NULL) 1306 return (DLADM_STATUS_BADARG); 1307 1308 status = dladm_datalink_id2info(handle, linkid, NULL, &class, &media, 1309 NULL, 0); 1310 if (status != DLADM_STATUS_OK) 1311 return (status); 1312 1313 /* public */ 1314 for (i = 0; i < DLADM_MAX_PROPS; i++) { 1315 if (!(prop_table[i].pd_class & class)) 1316 continue; 1317 1318 if (!DATALINK_MEDIA_ACCEPTED(prop_table[i].pd_dmedia, media)) 1319 continue; 1320 1321 if (func(handle, linkid, prop_table[i].pd_name, arg) == 1322 DLADM_WALK_TERMINATE) { 1323 break; 1324 } 1325 } 1326 1327 /* private */ 1328 status = i_dladm_walk_linkprop_priv_db(handle, linkid, arg, func); 1329 1330 return (status); 1331 } 1332 1333 /* 1334 * Get linkprop of the given specific link. 1335 */ 1336 dladm_status_t 1337 dladm_get_linkprop(dladm_handle_t handle, datalink_id_t linkid, 1338 dladm_prop_type_t type, const char *prop_name, char **prop_val, 1339 uint_t *val_cntp) 1340 { 1341 dladm_status_t status = DLADM_STATUS_OK; 1342 datalink_class_t class; 1343 uint_t media; 1344 prop_desc_t *pdp; 1345 uint_t cnt, dld_flags = 0; 1346 uint_t i; 1347 uint_t perm_flags; 1348 1349 if (type == DLADM_PROP_VAL_DEFAULT) 1350 dld_flags |= DLD_PROP_DEFAULT; 1351 else if (type == DLADM_PROP_VAL_MODIFIABLE) 1352 dld_flags |= DLD_PROP_POSSIBLE; 1353 1354 if (linkid == DATALINK_INVALID_LINKID || prop_name == NULL || 1355 prop_val == NULL || val_cntp == NULL || *val_cntp == 0) 1356 return (DLADM_STATUS_BADARG); 1357 1358 for (i = 0; i < DLADM_MAX_PROPS; i++) { 1359 if (strcasecmp(prop_name, prop_table[i].pd_name) == 0) { 1360 prop_name = prop_table[i].pd_name; 1361 break; 1362 } 1363 } 1364 1365 if (i == DLADM_MAX_PROPS) { 1366 if (prop_name[0] == '_') { 1367 /* 1368 * private property. 1369 */ 1370 if (type == DLADM_PROP_VAL_PERSISTENT) 1371 return (i_dladm_get_linkprop_db(handle, linkid, 1372 prop_name, prop_val, val_cntp)); 1373 else 1374 return (i_dladm_get_priv_prop(handle, linkid, 1375 prop_name, prop_val, val_cntp, type, 1376 dld_flags)); 1377 } else { 1378 return (DLADM_STATUS_NOTFOUND); 1379 } 1380 } 1381 1382 pdp = &prop_table[i]; 1383 1384 status = dladm_datalink_id2info(handle, linkid, NULL, &class, &media, 1385 NULL, 0); 1386 if (status != DLADM_STATUS_OK) 1387 return (status); 1388 1389 if (!(pdp->pd_class & class)) 1390 return (DLADM_STATUS_BADARG); 1391 1392 if (!DATALINK_MEDIA_ACCEPTED(pdp->pd_dmedia, media)) 1393 return (DLADM_STATUS_BADARG); 1394 1395 switch (type) { 1396 case DLADM_PROP_VAL_CURRENT: 1397 status = pdp->pd_get(handle, pdp, linkid, prop_val, val_cntp, 1398 media, dld_flags, &perm_flags); 1399 break; 1400 1401 case DLADM_PROP_VAL_PERM: 1402 if (pdp->pd_set == NULL) { 1403 perm_flags = MAC_PROP_PERM_READ; 1404 } else { 1405 status = pdp->pd_get(handle, pdp, linkid, prop_val, 1406 val_cntp, media, dld_flags, &perm_flags); 1407 } 1408 1409 *prop_val[0] = '\0'; 1410 *val_cntp = 1; 1411 if (status == DLADM_STATUS_OK) 1412 (void) dladm_perm2str(perm_flags, *prop_val); 1413 break; 1414 1415 case DLADM_PROP_VAL_DEFAULT: 1416 /* 1417 * If defaults are not defined for the property, 1418 * pd_defval.vd_name should be null. If the driver 1419 * has to be contacted for the value, vd_name should 1420 * be the empty string (""). Otherwise, dladm will 1421 * just print whatever is in the table. 1422 */ 1423 if (pdp->pd_defval.vd_name == NULL) { 1424 status = DLADM_STATUS_NOTSUP; 1425 break; 1426 } 1427 1428 if (strlen(pdp->pd_defval.vd_name) == 0) { 1429 status = pdp->pd_get(handle, pdp, linkid, prop_val, 1430 val_cntp, media, dld_flags, &perm_flags); 1431 } else { 1432 (void) strcpy(*prop_val, pdp->pd_defval.vd_name); 1433 } 1434 *val_cntp = 1; 1435 break; 1436 1437 case DLADM_PROP_VAL_MODIFIABLE: 1438 if (pdp->pd_getmod != NULL) { 1439 status = pdp->pd_getmod(handle, pdp, linkid, prop_val, 1440 val_cntp, media, dld_flags, &perm_flags); 1441 break; 1442 } 1443 cnt = pdp->pd_noptval; 1444 if (cnt == 0) { 1445 status = DLADM_STATUS_NOTSUP; 1446 } else if (cnt > *val_cntp) { 1447 status = DLADM_STATUS_TOOSMALL; 1448 } else { 1449 for (i = 0; i < cnt; i++) { 1450 (void) strcpy(prop_val[i], 1451 pdp->pd_optval[i].vd_name); 1452 } 1453 *val_cntp = cnt; 1454 } 1455 break; 1456 case DLADM_PROP_VAL_PERSISTENT: 1457 if (pdp->pd_flags & PD_TEMPONLY) 1458 return (DLADM_STATUS_TEMPONLY); 1459 status = i_dladm_get_linkprop_db(handle, linkid, prop_name, 1460 prop_val, val_cntp); 1461 break; 1462 default: 1463 status = DLADM_STATUS_BADARG; 1464 break; 1465 } 1466 1467 return (status); 1468 } 1469 1470 /* 1471 * Get linkprop of the given specific link and run any possible conversion 1472 * of the values using the check function for the property. Fails if the 1473 * check function doesn't succeed for the property value. 1474 */ 1475 dladm_status_t 1476 dladm_get_linkprop_values(dladm_handle_t handle, datalink_id_t linkid, 1477 dladm_prop_type_t type, const char *prop_name, uint_t *ret_val, 1478 uint_t *val_cntp) 1479 { 1480 dladm_status_t status; 1481 datalink_class_t class; 1482 uint_t media; 1483 prop_desc_t *pdp; 1484 uint_t dld_flags; 1485 uint_t valc, i; 1486 char **prop_val; 1487 uint_t perm_flags; 1488 1489 if (linkid == DATALINK_INVALID_LINKID || prop_name == NULL || 1490 ret_val == NULL || val_cntp == NULL || *val_cntp == 0) 1491 return (DLADM_STATUS_BADARG); 1492 1493 for (pdp = prop_table; pdp < prop_table + DLADM_MAX_PROPS; pdp++) { 1494 if (strcasecmp(prop_name, pdp->pd_name) == 0) { 1495 prop_name = pdp->pd_name; 1496 break; 1497 } 1498 } 1499 1500 if (pdp == prop_table + DLADM_MAX_PROPS) 1501 return (DLADM_STATUS_NOTFOUND); 1502 1503 if (pdp->pd_flags & PD_CHECK_ALLOC) 1504 return (DLADM_STATUS_BADARG); 1505 1506 status = dladm_datalink_id2info(handle, linkid, NULL, &class, &media, 1507 NULL, 0); 1508 if (status != DLADM_STATUS_OK) 1509 return (status); 1510 1511 if (!(pdp->pd_class & class)) 1512 return (DLADM_STATUS_BADARG); 1513 1514 if (!DATALINK_MEDIA_ACCEPTED(pdp->pd_dmedia, media)) 1515 return (DLADM_STATUS_BADARG); 1516 1517 prop_val = malloc(*val_cntp * sizeof (*prop_val) + 1518 *val_cntp * DLADM_PROP_VAL_MAX); 1519 if (prop_val == NULL) 1520 return (DLADM_STATUS_NOMEM); 1521 for (valc = 0; valc < *val_cntp; valc++) 1522 prop_val[valc] = (char *)(prop_val + *val_cntp) + 1523 valc * DLADM_PROP_VAL_MAX; 1524 1525 dld_flags = (type == DLADM_PROP_VAL_DEFAULT) ? DLD_PROP_DEFAULT : 0; 1526 1527 switch (type) { 1528 case DLADM_PROP_VAL_CURRENT: 1529 status = pdp->pd_get(handle, pdp, linkid, prop_val, val_cntp, 1530 media, dld_flags, &perm_flags); 1531 break; 1532 1533 case DLADM_PROP_VAL_DEFAULT: 1534 /* 1535 * If defaults are not defined for the property, 1536 * pd_defval.vd_name should be null. If the driver 1537 * has to be contacted for the value, vd_name should 1538 * be the empty string (""). Otherwise, dladm will 1539 * just print whatever is in the table. 1540 */ 1541 if (pdp->pd_defval.vd_name == NULL) { 1542 status = DLADM_STATUS_NOTSUP; 1543 break; 1544 } 1545 1546 if (pdp->pd_defval.vd_name[0] != '\0') { 1547 *val_cntp = 1; 1548 *ret_val = pdp->pd_defval.vd_val; 1549 free(prop_val); 1550 return (DLADM_STATUS_OK); 1551 } 1552 status = pdp->pd_get(handle, pdp, linkid, prop_val, val_cntp, 1553 media, dld_flags, &perm_flags); 1554 break; 1555 1556 case DLADM_PROP_VAL_PERSISTENT: 1557 if (pdp->pd_flags & PD_TEMPONLY) 1558 status = DLADM_STATUS_TEMPONLY; 1559 else 1560 status = i_dladm_get_linkprop_db(handle, linkid, 1561 prop_name, prop_val, val_cntp); 1562 break; 1563 1564 default: 1565 status = DLADM_STATUS_BADARG; 1566 break; 1567 } 1568 1569 if (status == DLADM_STATUS_OK) { 1570 if (pdp->pd_check != NULL) { 1571 val_desc_t *vdp; 1572 1573 vdp = malloc(sizeof (val_desc_t) * *val_cntp); 1574 if (vdp == NULL) 1575 status = DLADM_STATUS_NOMEM; 1576 else 1577 status = pdp->pd_check(handle, pdp, linkid, 1578 prop_val, val_cntp, 0, &vdp, media); 1579 if (status == DLADM_STATUS_OK) { 1580 for (valc = 0; valc < *val_cntp; valc++) 1581 ret_val[valc] = vdp[valc].vd_val; 1582 } 1583 free(vdp); 1584 } else { 1585 for (valc = 0; valc < *val_cntp; valc++) { 1586 for (i = 0; i < pdp->pd_noptval; i++) { 1587 if (strcmp(pdp->pd_optval[i].vd_name, 1588 prop_val[valc]) == 0) { 1589 ret_val[valc] = 1590 pdp->pd_optval[i].vd_val; 1591 break; 1592 } 1593 } 1594 if (i == pdp->pd_noptval) { 1595 status = DLADM_STATUS_FAILED; 1596 break; 1597 } 1598 } 1599 } 1600 } 1601 1602 free(prop_val); 1603 1604 return (status); 1605 } 1606 1607 static int 1608 i_dladm_init_one_prop(dladm_handle_t handle, datalink_id_t linkid, 1609 const char *prop_name, void *arg) 1610 { 1611 char *buf, **propvals; 1612 uint_t i, valcnt = DLADM_MAX_PROP_VALCNT; 1613 dladm_status_t status; 1614 dladm_linkprop_args_t *dla = arg; 1615 1616 if ((buf = malloc((sizeof (char *) + DLADM_PROP_VAL_MAX) * 1617 DLADM_MAX_PROP_VALCNT)) == NULL) { 1618 return (DLADM_WALK_CONTINUE); 1619 } 1620 1621 propvals = (char **)(void *)buf; 1622 for (i = 0; i < valcnt; i++) { 1623 propvals[i] = buf + 1624 sizeof (char *) * DLADM_MAX_PROP_VALCNT + 1625 i * DLADM_PROP_VAL_MAX; 1626 } 1627 1628 if (dladm_get_linkprop(handle, linkid, DLADM_PROP_VAL_PERSISTENT, 1629 prop_name, propvals, &valcnt) != DLADM_STATUS_OK) { 1630 goto done; 1631 } 1632 1633 status = dladm_set_linkprop(handle, linkid, prop_name, propvals, 1634 valcnt, dla->dla_flags | DLADM_OPT_ACTIVE); 1635 1636 if (status != DLADM_STATUS_OK) 1637 dla->dla_status = status; 1638 1639 done: 1640 if (buf != NULL) 1641 free(buf); 1642 1643 return (DLADM_WALK_CONTINUE); 1644 } 1645 1646 static int 1647 i_dladm_init_linkprop(dladm_handle_t handle, datalink_id_t linkid, 1648 void *arg __unused) 1649 { 1650 datalink_class_t class; 1651 dladm_status_t status; 1652 1653 status = dladm_datalink_id2info(handle, linkid, NULL, &class, NULL, 1654 NULL, 0); 1655 if (status != DLADM_STATUS_OK) 1656 return (DLADM_WALK_TERMINATE); 1657 1658 if ((class & (DATALINK_CLASS_VNIC | DATALINK_CLASS_VLAN)) == 0) 1659 (void) dladm_init_linkprop(handle, linkid, B_TRUE); 1660 1661 return (DLADM_WALK_CONTINUE); 1662 } 1663 1664 dladm_status_t 1665 dladm_init_linkprop(dladm_handle_t handle, datalink_id_t linkid, 1666 boolean_t any_media) 1667 { 1668 dladm_status_t status = DLADM_STATUS_OK; 1669 datalink_media_t dmedia; 1670 uint32_t media; 1671 dladm_linkprop_args_t *dla; 1672 1673 dmedia = any_media ? DATALINK_ANY_MEDIATYPE : DL_WIFI; 1674 1675 dla = malloc(sizeof (dladm_linkprop_args_t)); 1676 if (dla == NULL) 1677 return (DLADM_STATUS_NOMEM); 1678 dla->dla_flags = DLADM_OPT_BOOT; 1679 dla->dla_status = DLADM_STATUS_OK; 1680 1681 if (linkid == DATALINK_ALL_LINKID) { 1682 (void) dladm_walk_datalink_id(i_dladm_init_linkprop, handle, 1683 NULL, DATALINK_CLASS_ALL, dmedia, DLADM_OPT_PERSIST); 1684 } else if (any_media || 1685 ((dladm_datalink_id2info(handle, linkid, NULL, NULL, &media, NULL, 1686 0) == DLADM_STATUS_OK) && 1687 DATALINK_MEDIA_ACCEPTED(dmedia, media))) { 1688 (void) dladm_walk_linkprop(handle, linkid, (void *)dla, 1689 i_dladm_init_one_prop); 1690 status = dla->dla_status; 1691 } 1692 free(dla); 1693 return (status); 1694 } 1695 1696 static dladm_status_t 1697 get_zone(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid, 1698 char **prop_val, uint_t *val_cnt, datalink_media_t media __unused, 1699 uint_t flags, uint_t *perm_flags) 1700 { 1701 char zone_name[ZONENAME_MAX]; 1702 zoneid_t zid; 1703 dladm_status_t status; 1704 1705 if (flags != 0) 1706 return (DLADM_STATUS_NOTSUP); 1707 1708 status = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags, 1709 perm_flags, &zid, sizeof (zid)); 1710 if (status != DLADM_STATUS_OK) 1711 return (status); 1712 1713 *val_cnt = 1; 1714 if (zid != GLOBAL_ZONEID) { 1715 if (getzonenamebyid(zid, zone_name, sizeof (zone_name)) < 0) { 1716 return (dladm_errno2status(errno)); 1717 } 1718 1719 (void) strncpy(*prop_val, zone_name, DLADM_PROP_VAL_MAX); 1720 } else { 1721 *prop_val[0] = '\0'; 1722 } 1723 1724 return (DLADM_STATUS_OK); 1725 } 1726 1727 typedef int (*zone_get_devroot_t)(char *, char *, size_t); 1728 1729 static int 1730 i_dladm_get_zone_dev(char *zone_name, char *dev, size_t devlen) 1731 { 1732 char root[MAXPATHLEN]; 1733 zone_get_devroot_t real_zone_get_devroot; 1734 void *dlhandle; 1735 void *sym; 1736 int ret; 1737 1738 if ((dlhandle = dlopen("libzonecfg.so.1", RTLD_LAZY)) == NULL) 1739 return (-1); 1740 1741 if ((sym = dlsym(dlhandle, "zone_get_devroot")) == NULL) { 1742 (void) dlclose(dlhandle); 1743 return (-1); 1744 } 1745 1746 real_zone_get_devroot = (zone_get_devroot_t)sym; 1747 1748 if ((ret = real_zone_get_devroot(zone_name, root, sizeof (root))) == 0) 1749 (void) snprintf(dev, devlen, "%s%s", root, "/dev"); 1750 (void) dlclose(dlhandle); 1751 return (ret); 1752 } 1753 1754 static dladm_status_t 1755 i_dladm_update_deventry(dladm_handle_t handle, zoneid_t zid, 1756 datalink_id_t linkid, boolean_t add) 1757 { 1758 char path[MAXPATHLEN]; 1759 char name[MAXLINKNAMELEN]; 1760 di_prof_t prof = NULL; 1761 char zone_name[ZONENAME_MAX]; 1762 dladm_status_t status; 1763 int ret; 1764 1765 if (getzonenamebyid(zid, zone_name, sizeof (zone_name)) < 0) 1766 return (dladm_errno2status(errno)); 1767 if (i_dladm_get_zone_dev(zone_name, path, sizeof (path)) != 0) 1768 return (dladm_errno2status(errno)); 1769 if (di_prof_init(path, &prof) != 0) 1770 return (dladm_errno2status(errno)); 1771 1772 status = dladm_linkid2legacyname(handle, linkid, name, MAXLINKNAMELEN); 1773 if (status != DLADM_STATUS_OK) 1774 goto cleanup; 1775 1776 if (add) 1777 ret = di_prof_add_dev(prof, name); 1778 else 1779 ret = di_prof_add_exclude(prof, name); 1780 1781 if (ret != 0) { 1782 status = dladm_errno2status(errno); 1783 goto cleanup; 1784 } 1785 1786 if (di_prof_commit(prof) != 0) 1787 status = dladm_errno2status(errno); 1788 cleanup: 1789 if (prof) 1790 di_prof_fini(prof); 1791 1792 return (status); 1793 } 1794 1795 static dladm_status_t 1796 set_zone(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid, 1797 val_desc_t *vdp, uint_t val_cnt, uint_t flags, datalink_media_t media) 1798 { 1799 dladm_status_t status = DLADM_STATUS_OK; 1800 zoneid_t zid_old, zid_new; 1801 dld_ioc_zid_t *dzp; 1802 1803 if (val_cnt != 1) 1804 return (DLADM_STATUS_BADVALCNT); 1805 1806 dzp = (dld_ioc_zid_t *)vdp->vd_val; 1807 1808 status = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags, 1809 NULL, &zid_old, sizeof (zid_old)); 1810 if (status != DLADM_STATUS_OK) 1811 return (status); 1812 1813 zid_new = dzp->diz_zid; 1814 if (zid_new == zid_old) 1815 return (DLADM_STATUS_OK); 1816 1817 if ((status = set_public_prop(handle, pdp, linkid, vdp, val_cnt, 1818 flags, media)) != DLADM_STATUS_OK) 1819 return (status); 1820 1821 /* 1822 * It is okay to fail to update the /dev entry (some vanity-named 1823 * links do not have a /dev entry). 1824 */ 1825 if (zid_old != GLOBAL_ZONEID) { 1826 (void) i_dladm_update_deventry(handle, zid_old, linkid, 1827 B_FALSE); 1828 } 1829 if (zid_new != GLOBAL_ZONEID) 1830 (void) i_dladm_update_deventry(handle, zid_new, linkid, B_TRUE); 1831 1832 return (DLADM_STATUS_OK); 1833 } 1834 1835 static dladm_status_t 1836 check_zone(dladm_handle_t handle __unused, prop_desc_t *pdp __unused, 1837 datalink_id_t linkid, char **prop_val, uint_t *val_cntp, 1838 uint_t flags __unused, val_desc_t **vdpp, datalink_media_t media __unused) 1839 { 1840 char *zone_name; 1841 zoneid_t zoneid; 1842 dladm_status_t status = DLADM_STATUS_OK; 1843 dld_ioc_zid_t *dzp; 1844 uint_t val_cnt = *val_cntp; 1845 val_desc_t *vdp = *vdpp; 1846 1847 if (val_cnt != 1) 1848 return (DLADM_STATUS_BADVALCNT); 1849 1850 dzp = malloc(sizeof (dld_ioc_zid_t)); 1851 if (dzp == NULL) 1852 return (DLADM_STATUS_NOMEM); 1853 1854 zone_name = (prop_val != NULL) ? *prop_val : GLOBAL_ZONENAME; 1855 if ((zoneid = getzoneidbyname(zone_name)) == -1) { 1856 status = DLADM_STATUS_BADVAL; 1857 goto done; 1858 } 1859 1860 if (zoneid != GLOBAL_ZONEID) { 1861 ushort_t flags; 1862 1863 if (zone_getattr(zoneid, ZONE_ATTR_FLAGS, &flags, 1864 sizeof (flags)) < 0) { 1865 status = dladm_errno2status(errno); 1866 goto done; 1867 } 1868 1869 if (!(flags & ZF_NET_EXCL)) { 1870 status = DLADM_STATUS_BADVAL; 1871 goto done; 1872 } 1873 } 1874 1875 (void) memset(dzp, 0, sizeof (dld_ioc_zid_t)); 1876 1877 dzp->diz_zid = zoneid; 1878 dzp->diz_linkid = linkid; 1879 1880 vdp->vd_val = (uintptr_t)dzp; 1881 return (DLADM_STATUS_OK); 1882 done: 1883 free(dzp); 1884 return (status); 1885 } 1886 1887 static dladm_status_t 1888 get_maxbw(dladm_handle_t handle, prop_desc_t *pdp __unused, 1889 datalink_id_t linkid, char **prop_val, uint_t *val_cnt, 1890 datalink_media_t media __unused, uint_t flags, uint_t *perm_flags) 1891 { 1892 mac_resource_props_t mrp; 1893 dladm_status_t status; 1894 1895 status = i_dladm_get_public_prop(handle, linkid, "resource", flags, 1896 perm_flags, &mrp, sizeof (mrp)); 1897 if (status != DLADM_STATUS_OK) 1898 return (status); 1899 1900 if ((mrp.mrp_mask & MRP_MAXBW) == 0) { 1901 *val_cnt = 0; 1902 return (DLADM_STATUS_OK); 1903 } 1904 1905 (void) dladm_bw2str(mrp.mrp_maxbw, prop_val[0]); 1906 *val_cnt = 1; 1907 return (DLADM_STATUS_OK); 1908 } 1909 1910 static dladm_status_t 1911 check_maxbw(dladm_handle_t handle __unused, prop_desc_t *pdp __unused, 1912 datalink_id_t linkid __unused, char **prop_val, uint_t *val_cntp, 1913 uint_t flags __unused, val_desc_t **vdpp, datalink_media_t media __unused) 1914 { 1915 uint64_t *maxbw; 1916 dladm_status_t status = DLADM_STATUS_OK; 1917 uint_t val_cnt = *val_cntp; 1918 val_desc_t *vdp = *vdpp; 1919 1920 if (val_cnt != 1) 1921 return (DLADM_STATUS_BADVALCNT); 1922 1923 maxbw = malloc(sizeof (uint64_t)); 1924 if (maxbw == NULL) 1925 return (DLADM_STATUS_NOMEM); 1926 1927 status = dladm_str2bw(*prop_val, maxbw); 1928 if (status != DLADM_STATUS_OK) { 1929 free(maxbw); 1930 return (status); 1931 } 1932 1933 if ((*maxbw < MRP_MAXBW_MINVAL) && (*maxbw != 0)) { 1934 free(maxbw); 1935 return (DLADM_STATUS_MINMAXBW); 1936 } 1937 1938 vdp->vd_val = (uintptr_t)maxbw; 1939 return (DLADM_STATUS_OK); 1940 } 1941 1942 dladm_status_t 1943 extract_maxbw(val_desc_t *vdp, uint_t cnt __unused, void *arg) 1944 { 1945 mac_resource_props_t *mrp = arg; 1946 1947 if (vdp->vd_val == RESET_VAL) { 1948 mrp->mrp_maxbw = MRP_MAXBW_RESETVAL; 1949 } else { 1950 bcopy((char *)vdp->vd_val, &mrp->mrp_maxbw, sizeof (uint64_t)); 1951 } 1952 mrp->mrp_mask |= MRP_MAXBW; 1953 1954 return (DLADM_STATUS_OK); 1955 } 1956 1957 static dladm_status_t 1958 get_cpus(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid, 1959 char **prop_val, uint_t *val_cnt, datalink_media_t media __unused, 1960 uint_t flags, uint_t *perm_flags) 1961 { 1962 dladm_status_t status; 1963 mac_resource_props_t mrp; 1964 mac_propval_range_t *pv_range; 1965 int err; 1966 1967 if (strcmp(pdp->pd_name, "cpus-effective") == 0) { 1968 status = i_dladm_get_public_prop(handle, linkid, 1969 "resource-effective", flags, perm_flags, &mrp, 1970 sizeof (mrp)); 1971 } else { 1972 status = i_dladm_get_public_prop(handle, linkid, 1973 "resource", flags, perm_flags, &mrp, sizeof (mrp)); 1974 } 1975 1976 if (status != DLADM_STATUS_OK) 1977 return (status); 1978 1979 if (mrp.mrp_ncpus > *val_cnt) 1980 return (DLADM_STATUS_TOOSMALL); 1981 1982 if (mrp.mrp_ncpus == 0) { 1983 *val_cnt = 0; 1984 return (DLADM_STATUS_OK); 1985 } 1986 1987 /* Sort CPU list and convert it to a mac_propval_range */ 1988 status = dladm_list2range(mrp.mrp_cpu, mrp.mrp_ncpus, 1989 MAC_PROPVAL_UINT32, &pv_range); 1990 if (status != DLADM_STATUS_OK) 1991 return (status); 1992 1993 /* Write CPU ranges and individual CPUs */ 1994 err = dladm_range2strs(pv_range, prop_val); 1995 if (err != 0) { 1996 free(pv_range); 1997 return (dladm_errno2status(err)); 1998 } 1999 2000 *val_cnt = pv_range->mpr_count; 2001 free(pv_range); 2002 2003 return (DLADM_STATUS_OK); 2004 } 2005 2006 static dladm_status_t 2007 check_cpus(dladm_handle_t handle, prop_desc_t *pdp __unused, 2008 datalink_id_t linkid, char **prop_val, uint_t *val_cntp, 2009 uint_t flags __unused, val_desc_t **vdpp, datalink_media_t media __unused) 2010 { 2011 int rc; 2012 uint_t i, j; 2013 long nproc = sysconf(_SC_NPROCESSORS_CONF); 2014 mac_resource_props_t mrp; 2015 mac_propval_range_t *pv_range; 2016 uint_t perm_flags; 2017 uint32_t ncpus; 2018 uint32_t *cpus = mrp.mrp_cpu; 2019 val_desc_t *vdp = *vdpp; 2020 val_desc_t *newvdp = NULL; 2021 uint_t val_cnt = *val_cntp; 2022 dladm_status_t status = DLADM_STATUS_OK; 2023 2024 /* Get the current pool property */ 2025 status = i_dladm_get_public_prop(handle, linkid, "resource", 0, 2026 &perm_flags, &mrp, sizeof (mrp)); 2027 2028 if (status == DLADM_STATUS_OK) { 2029 /* Can't set cpus if a pool is set */ 2030 if (strlen(mrp.mrp_pool) != 0) 2031 return (DLADM_STATUS_POOLCPU); 2032 } 2033 2034 /* Read ranges and convert to mac_propval_range */ 2035 status = dladm_strs2range(prop_val, val_cnt, MAC_PROPVAL_UINT32, 2036 &pv_range); 2037 if (status != DLADM_STATUS_OK) 2038 goto done1; 2039 2040 /* Convert mac_propval_range to a single CPU list */ 2041 ncpus = MRP_NCPUS; 2042 status = dladm_range2list(pv_range, cpus, &ncpus); 2043 if (status != DLADM_STATUS_OK) 2044 goto done1; 2045 2046 /* 2047 * If a range of CPUs was entered, update value count and reallocate 2048 * the array of val_desc_t's. The array allocated was sized for 2049 * indvidual elements, but needs to be reallocated to accomodate the 2050 * expanded list of CPUs. 2051 */ 2052 if (val_cnt < ncpus) { 2053 newvdp = calloc(*val_cntp, sizeof (val_desc_t)); 2054 if (newvdp == NULL) { 2055 status = DLADM_STATUS_NOMEM; 2056 goto done1; 2057 } 2058 vdp = newvdp; 2059 } 2060 2061 /* Check if all CPUs in the list are online */ 2062 for (i = 0; i < ncpus; i++) { 2063 if (cpus[i] >= (uint32_t)nproc) { 2064 status = DLADM_STATUS_BADCPUID; 2065 goto done2; 2066 } 2067 2068 rc = p_online(cpus[i], P_STATUS); 2069 if (rc < 1) { 2070 status = DLADM_STATUS_CPUERR; 2071 goto done2; 2072 } 2073 2074 if (rc != P_ONLINE) { 2075 status = DLADM_STATUS_CPUNOTONLINE; 2076 goto done2; 2077 } 2078 2079 vdp[i].vd_val = (uintptr_t)cpus[i]; 2080 } 2081 2082 /* Check for duplicate CPUs */ 2083 for (i = 0; i < *val_cntp; i++) { 2084 for (j = 0; j < *val_cntp; j++) { 2085 if (i != j && vdp[i].vd_val == vdp[j].vd_val) { 2086 status = DLADM_STATUS_BADVAL; 2087 goto done2; 2088 } 2089 } 2090 } 2091 2092 /* Update *val_cntp and *vdpp if everything was OK */ 2093 if (val_cnt < ncpus) { 2094 *val_cntp = ncpus; 2095 free(*vdpp); 2096 *vdpp = newvdp; 2097 } 2098 2099 status = DLADM_STATUS_OK; 2100 goto done1; 2101 2102 done2: 2103 free(newvdp); 2104 done1: 2105 free(pv_range); 2106 return (status); 2107 } 2108 2109 dladm_status_t 2110 extract_cpus(val_desc_t *vdp, uint_t cnt, void *arg) 2111 { 2112 mac_resource_props_t *mrp = arg; 2113 uint_t i; 2114 2115 if (vdp[0].vd_val == RESET_VAL) { 2116 bzero(&mrp->mrp_cpus, sizeof (mac_cpus_t)); 2117 mrp->mrp_mask |= MRP_CPUS; 2118 return (DLADM_STATUS_OK); 2119 } 2120 2121 for (i = 0; i < cnt; i++) 2122 mrp->mrp_cpu[i] = (uint32_t)vdp[i].vd_val; 2123 2124 mrp->mrp_ncpus = cnt; 2125 mrp->mrp_mask |= (MRP_CPUS|MRP_CPUS_USERSPEC); 2126 mrp->mrp_fanout_mode = MCM_CPUS; 2127 mrp->mrp_rx_intr_cpu = -1; 2128 2129 return (DLADM_STATUS_OK); 2130 } 2131 2132 /* 2133 * Get the pool datalink property from the kernel. This is used 2134 * for both the user specified pool and effective pool properties. 2135 */ 2136 static dladm_status_t 2137 get_pool(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid, 2138 char **prop_val, uint_t *val_cnt, datalink_media_t media __unused, 2139 uint_t flags, uint_t *perm_flags) 2140 { 2141 mac_resource_props_t mrp; 2142 dladm_status_t status; 2143 2144 if (strcmp(pdp->pd_name, "pool-effective") == 0) { 2145 status = i_dladm_get_public_prop(handle, linkid, 2146 "resource-effective", flags, perm_flags, &mrp, 2147 sizeof (mrp)); 2148 } else { 2149 status = i_dladm_get_public_prop(handle, linkid, 2150 "resource", flags, perm_flags, &mrp, sizeof (mrp)); 2151 } 2152 2153 if (status != DLADM_STATUS_OK) 2154 return (status); 2155 2156 if (strlen(mrp.mrp_pool) == 0) { 2157 (*prop_val)[0] = '\0'; 2158 } else { 2159 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, 2160 "%s", mrp.mrp_pool); 2161 } 2162 *val_cnt = 1; 2163 2164 return (DLADM_STATUS_OK); 2165 } 2166 2167 static dladm_status_t 2168 check_pool(dladm_handle_t handle, prop_desc_t *pdp __unused, 2169 datalink_id_t linkid, char **prop_val, uint_t *val_cntp __unused, 2170 uint_t flags, val_desc_t **vdpp, datalink_media_t media __unused) 2171 { 2172 pool_conf_t *poolconf; 2173 pool_t *pool; 2174 mac_resource_props_t mrp; 2175 dladm_status_t status; 2176 uint_t perm_flags; 2177 char *poolname; 2178 val_desc_t *vdp = *vdpp; 2179 2180 /* Get the current cpus property */ 2181 status = i_dladm_get_public_prop(handle, linkid, "resource", 0, 2182 &perm_flags, &mrp, sizeof (mrp)); 2183 2184 if (status == DLADM_STATUS_OK) { 2185 /* Can't set pool if cpus are set */ 2186 if (mrp.mrp_ncpus != 0) 2187 return (DLADM_STATUS_POOLCPU); 2188 } 2189 2190 poolname = malloc(sizeof (mrp.mrp_pool)); 2191 if (poolname == NULL) 2192 return (DLADM_STATUS_NOMEM); 2193 2194 /* Check for pool's availability if not booting */ 2195 if ((flags & DLADM_OPT_BOOT) == 0) { 2196 2197 /* Allocate and open pool configuration */ 2198 if ((poolconf = pool_conf_alloc()) == NULL) 2199 return (DLADM_STATUS_BADVAL); 2200 2201 if (pool_conf_open(poolconf, pool_dynamic_location(), PO_RDONLY) 2202 != PO_SUCCESS) { 2203 pool_conf_free(poolconf); 2204 return (DLADM_STATUS_BADVAL); 2205 } 2206 2207 /* Look for pool name */ 2208 if ((pool = pool_get_pool(poolconf, *prop_val)) == NULL) { 2209 pool_conf_free(poolconf); 2210 return (DLADM_STATUS_BADVAL); 2211 } 2212 2213 pool_conf_free(poolconf); 2214 free(pool); 2215 } 2216 2217 (void) strlcpy(poolname, *prop_val, sizeof (mrp.mrp_pool)); 2218 vdp->vd_val = (uintptr_t)poolname; 2219 2220 return (DLADM_STATUS_OK); 2221 } 2222 2223 dladm_status_t 2224 extract_pool(val_desc_t *vdp, uint_t cnt __unused, void *arg) 2225 { 2226 mac_resource_props_t *mrp = (mac_resource_props_t *)arg; 2227 2228 if (vdp->vd_val == RESET_VAL) { 2229 bzero(&mrp->mrp_pool, sizeof (mrp->mrp_pool)); 2230 mrp->mrp_mask |= MRP_POOL; 2231 return (DLADM_STATUS_OK); 2232 } 2233 2234 (void) strlcpy(mrp->mrp_pool, (char *)vdp->vd_val, 2235 sizeof (mrp->mrp_pool)); 2236 mrp->mrp_mask |= MRP_POOL; 2237 /* 2238 * Use MCM_CPUS since the fanout count is not user specified 2239 * and will be determined by the cpu list generated from the 2240 * pool. 2241 */ 2242 mrp->mrp_fanout_mode = MCM_CPUS; 2243 2244 return (DLADM_STATUS_OK); 2245 } 2246 2247 static dladm_status_t 2248 get_priority(dladm_handle_t handle, prop_desc_t *pdp __unused, 2249 datalink_id_t linkid, char **prop_val, uint_t *val_cnt, 2250 datalink_media_t media __unused, uint_t flags, uint_t *perm_flags) 2251 { 2252 mac_resource_props_t mrp; 2253 mac_priority_level_t pri; 2254 dladm_status_t status; 2255 2256 status = i_dladm_get_public_prop(handle, linkid, "resource", flags, 2257 perm_flags, &mrp, sizeof (mrp)); 2258 if (status != DLADM_STATUS_OK) 2259 return (status); 2260 2261 pri = ((mrp.mrp_mask & MRP_PRIORITY) == 0) ? MPL_HIGH : 2262 mrp.mrp_priority; 2263 2264 (void) dladm_pri2str(pri, prop_val[0]); 2265 *val_cnt = 1; 2266 return (DLADM_STATUS_OK); 2267 } 2268 2269 dladm_status_t 2270 extract_priority(val_desc_t *vdp, uint_t cnt, void *arg) 2271 { 2272 mac_resource_props_t *mrp = arg; 2273 2274 if (cnt != 1) 2275 return (DLADM_STATUS_BADVAL); 2276 2277 mrp->mrp_priority = (mac_priority_level_t)vdp->vd_val; 2278 mrp->mrp_mask |= MRP_PRIORITY; 2279 2280 return (DLADM_STATUS_OK); 2281 } 2282 2283 /* 2284 * Determines the size of the structure that needs to be sent to drivers 2285 * for retrieving the property range values. 2286 */ 2287 static int 2288 i_dladm_range_size(mac_propval_range_t *r, size_t *sz, uint_t *rcount) 2289 { 2290 uint_t count = r->mpr_count; 2291 2292 *sz = sizeof (mac_propval_range_t); 2293 *rcount = count; 2294 --count; 2295 2296 switch (r->mpr_type) { 2297 case MAC_PROPVAL_UINT32: 2298 *sz += (count * sizeof (mac_propval_uint32_range_t)); 2299 return (0); 2300 default: 2301 break; 2302 } 2303 *sz = 0; 2304 *rcount = 0; 2305 return (EINVAL); 2306 } 2307 2308 2309 static dladm_status_t 2310 check_rings(dladm_handle_t handle __unused, prop_desc_t *pdp __unused, 2311 datalink_id_t linkid __unused, char **prop_val, uint_t *val_cntp, 2312 uint_t flags __unused, val_desc_t **vp, datalink_media_t media __unused) 2313 { 2314 uint_t val_cnt = *val_cntp; 2315 val_desc_t *v = *vp; 2316 2317 if (val_cnt != 1) 2318 return (DLADM_STATUS_BADVAL); 2319 if (strncasecmp(prop_val[0], "hw", strlen("hw")) == 0) { 2320 v->vd_val = UNSPEC_VAL; 2321 } else if (strncasecmp(prop_val[0], "sw", strlen("sw")) == 0) { 2322 v->vd_val = 0; 2323 } else { 2324 v->vd_val = strtoul(prop_val[0], NULL, 0); 2325 if (v->vd_val == 0) 2326 return (DLADM_STATUS_BADVAL); 2327 } 2328 return (DLADM_STATUS_OK); 2329 } 2330 2331 static dladm_status_t 2332 get_rings_range(dladm_handle_t handle, prop_desc_t *pdp, 2333 datalink_id_t linkid, char **prop_val, uint_t *val_cnt, 2334 datalink_media_t media __unused, uint_t flags, uint_t *perm_flags __unused) 2335 { 2336 dld_ioc_macprop_t *dip; 2337 dladm_status_t status = DLADM_STATUS_OK; 2338 mac_propval_range_t *rangep; 2339 size_t sz; 2340 mac_propval_uint32_range_t *ur; 2341 2342 sz = sizeof (mac_propval_range_t); 2343 2344 if ((dip = i_dladm_buf_alloc_by_name(sz, linkid, pdp->pd_name, flags, 2345 &status)) == NULL) 2346 return (status); 2347 2348 status = i_dladm_macprop(handle, dip, B_FALSE); 2349 if (status != DLADM_STATUS_OK) 2350 return (status); 2351 2352 rangep = (mac_propval_range_t *)(void *)&dip->pr_val; 2353 *val_cnt = 1; 2354 ur = &rangep->mpr_range_uint32[0]; 2355 /* This is the case where the dev doesn't have any rings/groups */ 2356 if (rangep->mpr_count == 0) { 2357 (*prop_val)[0] = '\0'; 2358 /* 2359 * This is the case where the dev supports rings, but static 2360 * grouping. 2361 */ 2362 } else if (ur->mpur_min == ur->mpur_max && 2363 ur->mpur_max == 0) { 2364 (void) snprintf(prop_val[0], DLADM_PROP_VAL_MAX, "sw,hw"); 2365 /* 2366 * This is the case where the dev supports rings and dynamic 2367 * grouping, but has only one value (say 2 rings and 2 groups). 2368 */ 2369 } else if (ur->mpur_min == ur->mpur_max) { 2370 (void) snprintf(prop_val[0], DLADM_PROP_VAL_MAX, "sw,hw,%d", 2371 ur->mpur_min); 2372 /* 2373 * This is the case where the dev supports rings and dynamic 2374 * grouping and has a range of rings. 2375 */ 2376 } else { 2377 (void) snprintf(prop_val[0], DLADM_PROP_VAL_MAX, 2378 "sw,hw,<%ld-%ld>", ur->mpur_min, ur->mpur_max); 2379 } 2380 free(dip); 2381 return (status); 2382 } 2383 2384 2385 static dladm_status_t 2386 get_rxrings(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid, 2387 char **prop_val, uint_t *val_cnt, datalink_media_t media __unused, 2388 uint_t flags, uint_t *perm_flags) 2389 { 2390 mac_resource_props_t mrp; 2391 dladm_status_t status; 2392 uint32_t nrings = 0; 2393 2394 /* 2395 * Get the number of (effective-)rings from the resource property. 2396 */ 2397 if (strcmp(pdp->pd_name, "rxrings-effective") == 0) { 2398 status = i_dladm_get_public_prop(handle, linkid, 2399 "resource-effective", flags, perm_flags, &mrp, 2400 sizeof (mrp)); 2401 } else { 2402 /* 2403 * Get the permissions from the "rxrings" property. 2404 */ 2405 status = i_dladm_get_public_prop(handle, linkid, "rxrings", 2406 flags, perm_flags, NULL, 0); 2407 if (status != DLADM_STATUS_OK) 2408 return (status); 2409 2410 status = i_dladm_get_public_prop(handle, linkid, 2411 "resource", flags, NULL, &mrp, sizeof (mrp)); 2412 } 2413 2414 if (status != DLADM_STATUS_OK) 2415 return (status); 2416 2417 if ((mrp.mrp_mask & MRP_RX_RINGS) == 0) { 2418 *val_cnt = 0; 2419 return (DLADM_STATUS_OK); 2420 } 2421 nrings = mrp.mrp_nrxrings; 2422 *val_cnt = 1; 2423 if (mrp.mrp_mask & MRP_RXRINGS_UNSPEC) 2424 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "hw"); 2425 else if (nrings == 0) 2426 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "sw"); 2427 else 2428 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "%ld", nrings); 2429 return (DLADM_STATUS_OK); 2430 } 2431 2432 dladm_status_t 2433 extract_rxrings(val_desc_t *vdp, uint_t cnt __unused, void *arg) 2434 { 2435 mac_resource_props_t *mrp = (mac_resource_props_t *)arg; 2436 2437 mrp->mrp_nrxrings = 0; 2438 if (vdp->vd_val == RESET_VAL) 2439 mrp->mrp_mask = MRP_RINGS_RESET; 2440 else if (vdp->vd_val == UNSPEC_VAL) 2441 mrp->mrp_mask = MRP_RXRINGS_UNSPEC; 2442 else 2443 mrp->mrp_nrxrings = vdp->vd_val; 2444 mrp->mrp_mask |= MRP_RX_RINGS; 2445 2446 return (DLADM_STATUS_OK); 2447 } 2448 2449 static dladm_status_t 2450 get_txrings(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid, 2451 char **prop_val, uint_t *val_cnt, datalink_media_t media __unused, 2452 uint_t flags, uint_t *perm_flags) 2453 { 2454 mac_resource_props_t mrp; 2455 dladm_status_t status; 2456 uint32_t nrings = 0; 2457 2458 2459 /* 2460 * Get the number of (effective-)rings from the resource property. 2461 */ 2462 if (strcmp(pdp->pd_name, "txrings-effective") == 0) { 2463 status = i_dladm_get_public_prop(handle, linkid, 2464 "resource-effective", flags, perm_flags, &mrp, 2465 sizeof (mrp)); 2466 } else { 2467 /* 2468 * Get the permissions from the "txrings" property. 2469 */ 2470 status = i_dladm_get_public_prop(handle, linkid, "txrings", 2471 flags, perm_flags, NULL, 0); 2472 if (status != DLADM_STATUS_OK) 2473 return (status); 2474 2475 /* 2476 * Get the number of rings from the "resource" property. 2477 */ 2478 status = i_dladm_get_public_prop(handle, linkid, "resource", 2479 flags, NULL, &mrp, sizeof (mrp)); 2480 } 2481 2482 if (status != DLADM_STATUS_OK) 2483 return (status); 2484 2485 if ((mrp.mrp_mask & MRP_TX_RINGS) == 0) { 2486 *val_cnt = 0; 2487 return (DLADM_STATUS_OK); 2488 } 2489 nrings = mrp.mrp_ntxrings; 2490 *val_cnt = 1; 2491 if (mrp.mrp_mask & MRP_TXRINGS_UNSPEC) 2492 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "hw"); 2493 else if (nrings == 0) 2494 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "sw"); 2495 else 2496 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "%ld", nrings); 2497 return (DLADM_STATUS_OK); 2498 } 2499 2500 dladm_status_t 2501 extract_txrings(val_desc_t *vdp, uint_t cnt __unused, void *arg) 2502 { 2503 mac_resource_props_t *mrp = (mac_resource_props_t *)arg; 2504 2505 mrp->mrp_ntxrings = 0; 2506 if (vdp->vd_val == RESET_VAL) 2507 mrp->mrp_mask = MRP_RINGS_RESET; 2508 else if (vdp->vd_val == UNSPEC_VAL) 2509 mrp->mrp_mask = MRP_TXRINGS_UNSPEC; 2510 else 2511 mrp->mrp_ntxrings = vdp->vd_val; 2512 mrp->mrp_mask |= MRP_TX_RINGS; 2513 2514 return (DLADM_STATUS_OK); 2515 } 2516 2517 static dladm_status_t 2518 get_cntavail(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid, 2519 char **prop_val, uint_t *val_cnt, datalink_media_t media, uint_t flags, 2520 uint_t *perm_flags) 2521 { 2522 if (flags & DLD_PROP_DEFAULT) 2523 return (DLADM_STATUS_NOTDEFINED); 2524 2525 return (get_uint32(handle, pdp, linkid, prop_val, val_cnt, media, 2526 flags, perm_flags)); 2527 } 2528 2529 static dladm_status_t 2530 set_resource(dladm_handle_t handle, prop_desc_t *pdp __unused, 2531 datalink_id_t linkid, val_desc_t *vdp, uint_t val_cnt, 2532 uint_t flags, datalink_media_t media __unused) 2533 { 2534 mac_resource_props_t mrp; 2535 dladm_status_t status = DLADM_STATUS_OK; 2536 dld_ioc_macprop_t *dip; 2537 uint_t i; 2538 2539 bzero(&mrp, sizeof (mac_resource_props_t)); 2540 dip = i_dladm_buf_alloc_by_name(0, linkid, "resource", 2541 flags, &status); 2542 2543 if (dip == NULL) 2544 return (status); 2545 2546 for (i = 0; i < DLADM_MAX_RSRC_PROP; i++) { 2547 resource_prop_t *rp = &rsrc_prop_table[i]; 2548 2549 if (strcmp(pdp->pd_name, rp->rp_name) != 0) 2550 continue; 2551 2552 status = rp->rp_extract(vdp, val_cnt, &mrp); 2553 if (status != DLADM_STATUS_OK) 2554 goto done; 2555 2556 break; 2557 } 2558 2559 (void) memcpy(dip->pr_val, &mrp, dip->pr_valsize); 2560 status = i_dladm_macprop(handle, dip, B_TRUE); 2561 2562 done: 2563 free(dip); 2564 return (status); 2565 } 2566 2567 static dladm_status_t 2568 get_protection(dladm_handle_t handle, prop_desc_t *pdp __unused, 2569 datalink_id_t linkid, char **prop_val, uint_t *val_cnt, 2570 datalink_media_t media __unused, uint_t flags, uint_t *perm_flags) 2571 { 2572 mac_resource_props_t mrp; 2573 mac_protect_t *p; 2574 dladm_status_t status; 2575 uint32_t i, cnt = 0, setbits[32]; 2576 2577 status = i_dladm_get_public_prop(handle, linkid, "resource", flags, 2578 perm_flags, &mrp, sizeof (mrp)); 2579 if (status != DLADM_STATUS_OK) 2580 return (status); 2581 2582 p = &mrp.mrp_protect; 2583 if ((mrp.mrp_mask & MRP_PROTECT) == 0) { 2584 *val_cnt = 0; 2585 return (DLADM_STATUS_OK); 2586 } 2587 dladm_find_setbits32(p->mp_types, setbits, &cnt); 2588 if (cnt > *val_cnt) 2589 return (DLADM_STATUS_BADVALCNT); 2590 2591 for (i = 0; i < cnt; i++) 2592 (void) dladm_protect2str(setbits[i], prop_val[i]); 2593 2594 *val_cnt = cnt; 2595 return (DLADM_STATUS_OK); 2596 } 2597 2598 static dladm_status_t 2599 get_allowedips(dladm_handle_t handle, prop_desc_t *pdp __unused, 2600 datalink_id_t linkid, char **prop_val, uint_t *val_cnt, 2601 datalink_media_t media __unused, uint_t flags, uint_t *perm_flags) 2602 { 2603 mac_resource_props_t mrp; 2604 mac_protect_t *p; 2605 dladm_status_t status; 2606 uint_t i; 2607 2608 status = i_dladm_get_public_prop(handle, linkid, "resource", flags, 2609 perm_flags, &mrp, sizeof (mrp)); 2610 if (status != DLADM_STATUS_OK) 2611 return (status); 2612 2613 p = &mrp.mrp_protect; 2614 if (p->mp_ipaddrcnt == 0) { 2615 *val_cnt = 0; 2616 return (DLADM_STATUS_OK); 2617 } 2618 if (p->mp_ipaddrcnt > *val_cnt) 2619 return (DLADM_STATUS_BADVALCNT); 2620 2621 for (i = 0; i < p->mp_ipaddrcnt; i++) { 2622 int len; 2623 if (p->mp_ipaddrs[i].ip_version == IPV4_VERSION) { 2624 ipaddr_t v4addr; 2625 2626 v4addr = V4_PART_OF_V6(p->mp_ipaddrs[i].ip_addr); 2627 (void) dladm_ipv4addr2str(&v4addr, prop_val[i]); 2628 } else { 2629 (void) dladm_ipv6addr2str(&p->mp_ipaddrs[i].ip_addr, 2630 prop_val[i]); 2631 } 2632 len = strlen(prop_val[i]); 2633 (void) sprintf(prop_val[i] + len, "/%d", 2634 p->mp_ipaddrs[i].ip_netmask); 2635 } 2636 *val_cnt = p->mp_ipaddrcnt; 2637 return (DLADM_STATUS_OK); 2638 } 2639 2640 dladm_status_t 2641 extract_protection(val_desc_t *vdp, uint_t cnt, void *arg) 2642 { 2643 mac_resource_props_t *mrp = arg; 2644 uint32_t types = 0; 2645 uint_t i; 2646 2647 for (i = 0; i < cnt; i++) 2648 types |= (uint32_t)vdp[i].vd_val; 2649 2650 mrp->mrp_protect.mp_types = types; 2651 mrp->mrp_mask |= MRP_PROTECT; 2652 return (DLADM_STATUS_OK); 2653 } 2654 2655 dladm_status_t 2656 extract_allowedips(val_desc_t *vdp, uint_t cnt, void *arg) 2657 { 2658 mac_resource_props_t *mrp = arg; 2659 mac_protect_t *p = &mrp->mrp_protect; 2660 uint_t i; 2661 2662 if (vdp->vd_val == 0) { 2663 cnt = (uint_t)-1; 2664 } else { 2665 for (i = 0; i < cnt; i++) { 2666 bcopy((void *)vdp[i].vd_val, &p->mp_ipaddrs[i], 2667 sizeof (mac_ipaddr_t)); 2668 } 2669 } 2670 p->mp_ipaddrcnt = cnt; 2671 mrp->mrp_mask |= MRP_PROTECT; 2672 return (DLADM_STATUS_OK); 2673 } 2674 2675 static dladm_status_t 2676 check_single_ip(char *buf, mac_ipaddr_t *addr) 2677 { 2678 dladm_status_t status; 2679 ipaddr_t v4addr; 2680 in6_addr_t v6addr; 2681 boolean_t isv4 = B_TRUE; 2682 char *p; 2683 uint32_t mask = 0; 2684 2685 /* 2686 * If the IP address is in CIDR format, parse the bits component 2687 * seperately. An address in this style will be used to indicate an 2688 * entire subnet, so it must be a network number with no host address. 2689 */ 2690 if ((p = strchr(buf, '/')) != NULL) { 2691 char *end = NULL; 2692 2693 *p++ = '\0'; 2694 if (!isdigit(*p)) 2695 return (DLADM_STATUS_INVALID_IP); 2696 mask = strtol(p, &end, 10); 2697 if (end != NULL && *end != '\0') 2698 return (DLADM_STATUS_INVALID_IP); 2699 if (mask > 128|| mask < 1) 2700 return (DLADM_STATUS_INVALID_IP); 2701 } 2702 2703 status = dladm_str2ipv4addr(buf, &v4addr); 2704 if (status == DLADM_STATUS_INVALID_IP) { 2705 status = dladm_str2ipv6addr(buf, &v6addr); 2706 if (status == DLADM_STATUS_OK) 2707 isv4 = B_FALSE; 2708 } 2709 if (status != DLADM_STATUS_OK) 2710 return (status); 2711 2712 if (isv4) { 2713 if (v4addr == INADDR_ANY) 2714 return (DLADM_STATUS_INVALID_IP); 2715 2716 IN6_IPADDR_TO_V4MAPPED(v4addr, &addr->ip_addr); 2717 addr->ip_version = IPV4_VERSION; 2718 if (p != NULL) { 2719 uint32_t smask; 2720 2721 /* 2722 * Validate the netmask is in the proper range for v4 2723 */ 2724 if (mask > 32 || mask < 1) 2725 return (DLADM_STATUS_INVALID_IP); 2726 2727 /* 2728 * We have a CIDR style address, confirm that only the 2729 * network number is set. 2730 */ 2731 smask = 0xFFFFFFFFu << (32 - mask); 2732 if (htonl(v4addr) & ~smask) 2733 return (DLADM_STATUS_INVALID_IP); 2734 } else { 2735 mask = 32; 2736 } 2737 addr->ip_netmask = mask; 2738 } else { 2739 if (IN6_IS_ADDR_UNSPECIFIED(&v6addr)) 2740 return (DLADM_STATUS_INVALID_IP); 2741 2742 if (IN6_IS_ADDR_V4MAPPED_ANY(&v6addr)) 2743 return (DLADM_STATUS_INVALID_IP); 2744 2745 if (p != NULL) { 2746 int i, off, high; 2747 2748 /* 2749 * Note that the address in our buffer is stored in 2750 * network byte order. 2751 */ 2752 off = 0; 2753 for (i = 3; i >= 0; i--) { 2754 high = ffsl(ntohl(v6addr._S6_un._S6_u32[i])); 2755 if (high != 0) 2756 break; 2757 off += 32; 2758 } 2759 off += high; 2760 if (128 - off >= (int)mask) 2761 return (DLADM_STATUS_INVALID_IP); 2762 } else { 2763 mask = 128; 2764 } 2765 2766 addr->ip_addr = v6addr; 2767 addr->ip_version = IPV6_VERSION; 2768 addr->ip_netmask = mask; 2769 } 2770 return (DLADM_STATUS_OK); 2771 } 2772 2773 static dladm_status_t 2774 check_allowedips(dladm_handle_t handle __unused, prop_desc_t *pdp __unused, 2775 datalink_id_t linkid __unused, char **prop_val, uint_t *val_cntp, 2776 uint_t flags __unused, val_desc_t **vdpp, datalink_media_t media __unused) 2777 { 2778 dladm_status_t status; 2779 mac_ipaddr_t *addr; 2780 uint_t i; 2781 uint_t val_cnt = *val_cntp; 2782 val_desc_t *vdp = *vdpp; 2783 2784 if (val_cnt > MPT_MAXIPADDR) 2785 return (DLADM_STATUS_BADVALCNT); 2786 2787 for (i = 0; i < val_cnt; i++) { 2788 if ((addr = calloc(1, sizeof (mac_ipaddr_t))) == NULL) { 2789 status = DLADM_STATUS_NOMEM; 2790 goto fail; 2791 } 2792 vdp[i].vd_val = (uintptr_t)addr; 2793 2794 status = check_single_ip(prop_val[i], addr); 2795 if (status != DLADM_STATUS_OK) 2796 goto fail; 2797 } 2798 return (DLADM_STATUS_OK); 2799 2800 fail: 2801 for (i = 0; i < val_cnt; i++) { 2802 free((void *)vdp[i].vd_val); 2803 vdp[i].vd_val = 0; 2804 } 2805 return (status); 2806 } 2807 2808 static void 2809 dladm_cid2str(mac_dhcpcid_t *cid, char *buf) 2810 { 2811 char tmp_buf[DLADM_STRSIZE]; 2812 uint_t hexlen; 2813 2814 switch (cid->dc_form) { 2815 case CIDFORM_TYPED: { 2816 uint16_t duidtype, hwtype; 2817 uint32_t timestamp, ennum; 2818 char *lladdr; 2819 2820 if (cid->dc_len < sizeof (duidtype)) 2821 goto fail; 2822 2823 bcopy(cid->dc_id, &duidtype, sizeof (duidtype)); 2824 duidtype = ntohs(duidtype); 2825 switch (duidtype) { 2826 case DHCPV6_DUID_LLT: { 2827 duid_llt_t llt; 2828 2829 if (cid->dc_len < sizeof (llt)) 2830 goto fail; 2831 2832 bcopy(cid->dc_id, &llt, sizeof (llt)); 2833 hwtype = ntohs(llt.dllt_hwtype); 2834 timestamp = ntohl(llt.dllt_time); 2835 lladdr = _link_ntoa(cid->dc_id + sizeof (llt), 2836 NULL, cid->dc_len - sizeof (llt), IFT_OTHER); 2837 if (lladdr == NULL) 2838 goto fail; 2839 2840 (void) snprintf(buf, DLADM_STRSIZE, "%d.%d.%d.%s", 2841 duidtype, hwtype, timestamp, lladdr); 2842 free(lladdr); 2843 break; 2844 } 2845 case DHCPV6_DUID_EN: { 2846 duid_en_t en; 2847 2848 if (cid->dc_len < sizeof (en)) 2849 goto fail; 2850 2851 bcopy(cid->dc_id, &en, sizeof (en)); 2852 ennum = DHCPV6_GET_ENTNUM(&en); 2853 hexlen = sizeof (tmp_buf); 2854 if (octet_to_hexascii(cid->dc_id + sizeof (en), 2855 cid->dc_len - sizeof (en), tmp_buf, &hexlen) != 0) 2856 goto fail; 2857 2858 (void) snprintf(buf, DLADM_STRSIZE, "%d.%d.%s", 2859 duidtype, ennum, tmp_buf); 2860 break; 2861 } 2862 case DHCPV6_DUID_LL: { 2863 duid_ll_t ll; 2864 2865 if (cid->dc_len < sizeof (ll)) 2866 goto fail; 2867 2868 bcopy(cid->dc_id, &ll, sizeof (ll)); 2869 hwtype = ntohs(ll.dll_hwtype); 2870 lladdr = _link_ntoa(cid->dc_id + sizeof (ll), 2871 NULL, cid->dc_len - sizeof (ll), IFT_OTHER); 2872 if (lladdr == NULL) 2873 goto fail; 2874 2875 (void) snprintf(buf, DLADM_STRSIZE, "%d.%d.%s", 2876 duidtype, hwtype, lladdr); 2877 free(lladdr); 2878 break; 2879 } 2880 default: { 2881 hexlen = sizeof (tmp_buf); 2882 if (octet_to_hexascii(cid->dc_id + sizeof (duidtype), 2883 cid->dc_len - sizeof (duidtype), 2884 tmp_buf, &hexlen) != 0) 2885 goto fail; 2886 2887 (void) snprintf(buf, DLADM_STRSIZE, "%d.%s", 2888 duidtype, tmp_buf); 2889 } 2890 } 2891 break; 2892 } 2893 case CIDFORM_HEX: { 2894 hexlen = sizeof (tmp_buf); 2895 if (octet_to_hexascii(cid->dc_id, cid->dc_len, 2896 tmp_buf, &hexlen) != 0) 2897 goto fail; 2898 2899 (void) snprintf(buf, DLADM_STRSIZE, "0x%s", tmp_buf); 2900 break; 2901 } 2902 case CIDFORM_STR: { 2903 uint_t i; 2904 2905 for (i = 0; i < cid->dc_len; i++) { 2906 if (!isprint(cid->dc_id[i])) 2907 goto fail; 2908 } 2909 (void) snprintf(buf, DLADM_STRSIZE, "%s", cid->dc_id); 2910 break; 2911 } 2912 default: 2913 goto fail; 2914 } 2915 return; 2916 2917 fail: 2918 (void) snprintf(buf, DLADM_STRSIZE, "<unknown>"); 2919 } 2920 2921 static dladm_status_t 2922 dladm_str2cid(char *buf, mac_dhcpcid_t *cid) 2923 { 2924 char *ptr = buf; 2925 char tmp_buf[DLADM_STRSIZE]; 2926 uint_t hexlen, cidlen; 2927 2928 bzero(cid, sizeof (*cid)); 2929 if (isdigit(*ptr) && 2930 ptr[strspn(ptr, "0123456789")] == '.') { 2931 char *cp; 2932 ulong_t duidtype; 2933 ulong_t subtype = 0; 2934 ulong_t timestamp; 2935 uchar_t *lladdr; 2936 int addrlen; 2937 2938 errno = 0; 2939 duidtype = strtoul(ptr, &cp, 0); 2940 if (ptr == cp || errno != 0 || *cp != '.' || 2941 duidtype > USHRT_MAX) 2942 return (DLADM_STATUS_BADARG); 2943 ptr = cp + 1; 2944 2945 if (duidtype != 0 && duidtype <= DHCPV6_DUID_LL) { 2946 errno = 0; 2947 subtype = strtoul(ptr, &cp, 0); 2948 if (ptr == cp || errno != 0 || *cp != '.') 2949 return (DLADM_STATUS_BADARG); 2950 ptr = cp + 1; 2951 } 2952 switch (duidtype) { 2953 case DHCPV6_DUID_LLT: { 2954 duid_llt_t llt; 2955 2956 errno = 0; 2957 timestamp = strtoul(ptr, &cp, 0); 2958 if (ptr == cp || errno != 0 || *cp != '.') 2959 return (DLADM_STATUS_BADARG); 2960 2961 ptr = cp + 1; 2962 lladdr = _link_aton(ptr, &addrlen); 2963 if (lladdr == NULL) 2964 return (DLADM_STATUS_BADARG); 2965 2966 cidlen = sizeof (llt) + addrlen; 2967 if (cidlen > sizeof (cid->dc_id)) { 2968 free(lladdr); 2969 return (DLADM_STATUS_TOOSMALL); 2970 } 2971 llt.dllt_dutype = htons(duidtype); 2972 llt.dllt_hwtype = htons(subtype); 2973 llt.dllt_time = htonl(timestamp); 2974 bcopy(&llt, cid->dc_id, sizeof (llt)); 2975 bcopy(lladdr, cid->dc_id + sizeof (llt), addrlen); 2976 free(lladdr); 2977 break; 2978 } 2979 case DHCPV6_DUID_LL: { 2980 duid_ll_t ll; 2981 2982 lladdr = _link_aton(ptr, &addrlen); 2983 if (lladdr == NULL) 2984 return (DLADM_STATUS_BADARG); 2985 2986 cidlen = sizeof (ll) + addrlen; 2987 if (cidlen > sizeof (cid->dc_id)) { 2988 free(lladdr); 2989 return (DLADM_STATUS_TOOSMALL); 2990 } 2991 ll.dll_dutype = htons(duidtype); 2992 ll.dll_hwtype = htons(subtype); 2993 bcopy(&ll, cid->dc_id, sizeof (ll)); 2994 bcopy(lladdr, cid->dc_id + sizeof (ll), addrlen); 2995 free(lladdr); 2996 break; 2997 } 2998 default: { 2999 hexlen = sizeof (tmp_buf); 3000 if (hexascii_to_octet(ptr, strlen(ptr), 3001 tmp_buf, &hexlen) != 0) 3002 return (DLADM_STATUS_BADARG); 3003 3004 if (duidtype == DHCPV6_DUID_EN) { 3005 duid_en_t en; 3006 3007 en.den_dutype = htons(duidtype); 3008 DHCPV6_SET_ENTNUM(&en, subtype); 3009 3010 cidlen = sizeof (en) + hexlen; 3011 if (cidlen > sizeof (cid->dc_id)) 3012 return (DLADM_STATUS_TOOSMALL); 3013 3014 bcopy(&en, cid->dc_id, sizeof (en)); 3015 bcopy(tmp_buf, cid->dc_id + sizeof (en), 3016 hexlen); 3017 } else { 3018 uint16_t dutype = htons(duidtype); 3019 3020 cidlen = sizeof (dutype) + hexlen; 3021 if (cidlen > sizeof (cid->dc_id)) 3022 return (DLADM_STATUS_TOOSMALL); 3023 3024 bcopy(&dutype, cid->dc_id, sizeof (dutype)); 3025 bcopy(tmp_buf, cid->dc_id + sizeof (dutype), 3026 hexlen); 3027 } 3028 break; 3029 } 3030 } 3031 cid->dc_form = CIDFORM_TYPED; 3032 } else if (strncasecmp("0x", ptr, 2) == 0 && ptr[2] != '\0') { 3033 ptr += 2; 3034 hexlen = sizeof (tmp_buf); 3035 if (hexascii_to_octet(ptr, strlen(ptr), tmp_buf, 3036 &hexlen) != 0) { 3037 return (DLADM_STATUS_BADARG); 3038 } 3039 cidlen = hexlen; 3040 if (cidlen > sizeof (cid->dc_id)) 3041 return (DLADM_STATUS_TOOSMALL); 3042 3043 bcopy(tmp_buf, cid->dc_id, cidlen); 3044 cid->dc_form = CIDFORM_HEX; 3045 } else { 3046 cidlen = strlen(ptr); 3047 if (cidlen > sizeof (cid->dc_id)) 3048 return (DLADM_STATUS_TOOSMALL); 3049 3050 bcopy(ptr, cid->dc_id, cidlen); 3051 cid->dc_form = CIDFORM_STR; 3052 } 3053 cid->dc_len = cidlen; 3054 return (DLADM_STATUS_OK); 3055 } 3056 3057 static dladm_status_t 3058 get_allowedcids(dladm_handle_t handle, prop_desc_t *pdp __unused, 3059 datalink_id_t linkid, char **prop_val, uint_t *val_cnt, 3060 datalink_media_t media __unused, uint_t flags, uint_t *perm_flags) 3061 { 3062 mac_resource_props_t mrp; 3063 mac_protect_t *p; 3064 dladm_status_t status; 3065 uint_t i; 3066 3067 status = i_dladm_get_public_prop(handle, linkid, "resource", flags, 3068 perm_flags, &mrp, sizeof (mrp)); 3069 if (status != DLADM_STATUS_OK) 3070 return (status); 3071 3072 p = &mrp.mrp_protect; 3073 if (p->mp_cidcnt == 0) { 3074 *val_cnt = 0; 3075 return (DLADM_STATUS_OK); 3076 } 3077 if (p->mp_cidcnt > *val_cnt) 3078 return (DLADM_STATUS_BADVALCNT); 3079 3080 for (i = 0; i < p->mp_cidcnt; i++) { 3081 mac_dhcpcid_t *cid = &p->mp_cids[i]; 3082 3083 dladm_cid2str(cid, prop_val[i]); 3084 } 3085 *val_cnt = p->mp_cidcnt; 3086 return (DLADM_STATUS_OK); 3087 } 3088 3089 dladm_status_t 3090 extract_allowedcids(val_desc_t *vdp, uint_t cnt, void *arg) 3091 { 3092 mac_resource_props_t *mrp = arg; 3093 mac_protect_t *p = &mrp->mrp_protect; 3094 uint_t i; 3095 3096 if (vdp->vd_val == 0) { 3097 cnt = (uint_t)-1; 3098 } else { 3099 for (i = 0; i < cnt; i++) { 3100 bcopy((void *)vdp[i].vd_val, &p->mp_cids[i], 3101 sizeof (mac_dhcpcid_t)); 3102 } 3103 } 3104 p->mp_cidcnt = cnt; 3105 mrp->mrp_mask |= MRP_PROTECT; 3106 return (DLADM_STATUS_OK); 3107 } 3108 3109 static dladm_status_t 3110 check_allowedcids(dladm_handle_t handle __unused, prop_desc_t *pdp __unused, 3111 datalink_id_t linkid __unused, char **prop_val, uint_t *val_cntp, 3112 uint_t flags __unused, val_desc_t **vdpp, datalink_media_t media __unused) 3113 { 3114 dladm_status_t status; 3115 mac_dhcpcid_t *cid; 3116 uint_t i; 3117 uint_t val_cnt = *val_cntp; 3118 val_desc_t *vdp = *vdpp; 3119 3120 if (val_cnt > MPT_MAXCID) 3121 return (DLADM_STATUS_BADVALCNT); 3122 3123 for (i = 0; i < val_cnt; i++) { 3124 if ((cid = calloc(1, sizeof (mac_dhcpcid_t))) == NULL) { 3125 status = DLADM_STATUS_NOMEM; 3126 goto fail; 3127 } 3128 vdp[i].vd_val = (uintptr_t)cid; 3129 3130 status = dladm_str2cid(prop_val[i], cid); 3131 if (status != DLADM_STATUS_OK) 3132 goto fail; 3133 } 3134 return (DLADM_STATUS_OK); 3135 3136 fail: 3137 for (i = 0; i < val_cnt; i++) { 3138 free((void *)vdp[i].vd_val); 3139 vdp[i].vd_val = 0; 3140 } 3141 return (status); 3142 } 3143 3144 static dladm_status_t 3145 get_secondary_macs(dladm_handle_t handle, prop_desc_t *pdp, 3146 datalink_id_t linkid, char **prop_val, uint_t *val_cnt, 3147 datalink_media_t media __unused, uint_t flags, uint_t *perm_flags) 3148 { 3149 mac_secondary_addr_t sa; 3150 dladm_status_t status; 3151 uint_t i; 3152 3153 status = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags, 3154 perm_flags, &sa, sizeof (sa)); 3155 if (status != DLADM_STATUS_OK) 3156 return (status); 3157 3158 if (sa.ms_addrcnt > *val_cnt) 3159 return (DLADM_STATUS_BADVALCNT); 3160 3161 for (i = 0; i < sa.ms_addrcnt; i++) { 3162 if (dladm_aggr_macaddr2str( 3163 (const unsigned char *)&sa.ms_addrs[i], prop_val[i]) == 3164 NULL) { 3165 *val_cnt = i; 3166 return (DLADM_STATUS_NOMEM); 3167 } 3168 } 3169 *val_cnt = sa.ms_addrcnt; 3170 return (DLADM_STATUS_OK); 3171 } 3172 3173 static dladm_status_t 3174 check_secondary_macs(dladm_handle_t handle __unused, prop_desc_t *pdp __unused, 3175 datalink_id_t linkid __unused, char **prop_val, uint_t *val_cntp, 3176 uint_t flags __unused, val_desc_t **vdpp, datalink_media_t media __unused) 3177 { 3178 dladm_status_t status; 3179 uchar_t *addr; 3180 uint_t len = 0; 3181 uint_t i; 3182 uint_t val_cnt = *val_cntp; 3183 val_desc_t *vdp = *vdpp; 3184 3185 if (val_cnt >= MPT_MAXMACADDR) 3186 return (DLADM_STATUS_BADVALCNT); 3187 3188 for (i = 0; i < val_cnt; i++) { 3189 addr = _link_aton(prop_val[i], (int *)&len); 3190 if (addr == NULL) { 3191 if (len == (uint_t)-1) 3192 status = DLADM_STATUS_MACADDRINVAL; 3193 else 3194 status = DLADM_STATUS_NOMEM; 3195 goto fail; 3196 } 3197 3198 vdp[i].vd_val = (uintptr_t)addr; 3199 } 3200 return (DLADM_STATUS_OK); 3201 3202 fail: 3203 for (i = 0; i < val_cnt; i++) { 3204 free((void *)vdp[i].vd_val); 3205 vdp[i].vd_val = 0; 3206 } 3207 return (status); 3208 } 3209 3210 static dladm_status_t 3211 set_secondary_macs(dladm_handle_t handle, prop_desc_t *pd __unused, 3212 datalink_id_t linkid, val_desc_t *vdp, uint_t val_cnt, 3213 uint_t flags __unused, datalink_media_t media __unused) 3214 { 3215 dladm_status_t status; 3216 dld_ioc_macprop_t *dip; 3217 uint_t i; 3218 mac_secondary_addr_t msa; 3219 3220 dip = i_dladm_buf_alloc_by_name(0, linkid, "secondary-macs", 0, 3221 &status); 3222 if (dip == NULL) 3223 return (status); 3224 3225 if (vdp->vd_val == 0) { 3226 val_cnt = (uint_t)-1; 3227 } else { 3228 for (i = 0; i < val_cnt; i++) { 3229 bcopy((void *)vdp[i].vd_val, msa.ms_addrs[i], 3230 MAXMACADDRLEN); 3231 } 3232 } 3233 msa.ms_addrcnt = val_cnt; 3234 bcopy(&msa, dip->pr_val, dip->pr_valsize); 3235 3236 status = i_dladm_macprop(handle, dip, B_TRUE); 3237 3238 free(dip); 3239 return (status); 3240 } 3241 3242 static dladm_status_t 3243 get_autopush(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid, 3244 char **prop_val, uint_t *val_cnt, datalink_media_t media __unused, 3245 uint_t flags, uint_t *perm_flags) 3246 { 3247 struct dlautopush dlap; 3248 int len; 3249 uint_t i; 3250 dladm_status_t status; 3251 3252 if (flags & DLD_PROP_DEFAULT) 3253 return (DLADM_STATUS_NOTDEFINED); 3254 3255 status = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags, 3256 perm_flags, &dlap, sizeof (dlap)); 3257 if (status != DLADM_STATUS_OK) 3258 return (status); 3259 3260 if (dlap.dap_npush == 0) { 3261 *val_cnt = 0; 3262 return (DLADM_STATUS_OK); 3263 } 3264 for (i = 0, len = 0; i < dlap.dap_npush; i++) { 3265 if (i != 0) { 3266 (void) snprintf(*prop_val + len, 3267 DLADM_PROP_VAL_MAX - len, "%c", AP_DELIMITER); 3268 len += 1; 3269 } 3270 (void) snprintf(*prop_val + len, DLADM_PROP_VAL_MAX - len, 3271 "%s", dlap.dap_aplist[i]); 3272 len += strlen(dlap.dap_aplist[i]); 3273 if (dlap.dap_anchor - 1 == i) { 3274 (void) snprintf(*prop_val + len, 3275 DLADM_PROP_VAL_MAX - len, "%c%s", AP_DELIMITER, 3276 AP_ANCHOR); 3277 len += (strlen(AP_ANCHOR) + 1); 3278 } 3279 } 3280 *val_cnt = 1; 3281 return (DLADM_STATUS_OK); 3282 } 3283 3284 /* 3285 * Add the specified module to the dlautopush structure; returns a 3286 * DLADM_STATUS_* code. 3287 */ 3288 dladm_status_t 3289 i_dladm_add_ap_module(const char *module, struct dlautopush *dlap) 3290 { 3291 if ((strlen(module) == 0) || (strlen(module) > FMNAMESZ)) 3292 return (DLADM_STATUS_BADVAL); 3293 3294 if (strncasecmp(module, AP_ANCHOR, strlen(AP_ANCHOR)) == 0) { 3295 /* 3296 * We don't allow multiple anchors, and the anchor must 3297 * be after at least one module. 3298 */ 3299 if (dlap->dap_anchor != 0) 3300 return (DLADM_STATUS_BADVAL); 3301 if (dlap->dap_npush == 0) 3302 return (DLADM_STATUS_BADVAL); 3303 3304 dlap->dap_anchor = dlap->dap_npush; 3305 return (DLADM_STATUS_OK); 3306 } 3307 if (dlap->dap_npush >= MAXAPUSH) 3308 return (DLADM_STATUS_BADVALCNT); 3309 3310 (void) strlcpy(dlap->dap_aplist[dlap->dap_npush++], module, 3311 FMNAMESZ + 1); 3312 3313 return (DLADM_STATUS_OK); 3314 } 3315 3316 /* 3317 * Currently, both '.' and ' '(space) can be used as the delimiters between 3318 * autopush modules. The former is used in dladm set-linkprop, and the 3319 * latter is used in the autopush(8) file. 3320 */ 3321 static dladm_status_t 3322 check_autopush(dladm_handle_t handle __unused, prop_desc_t *pdp __unused, 3323 datalink_id_t linkid __unused, char **prop_val, uint_t *val_cntp, 3324 uint_t flags __unused, val_desc_t **vdpp, datalink_media_t media __unused) 3325 { 3326 char *module; 3327 struct dlautopush *dlap; 3328 dladm_status_t status; 3329 char val[DLADM_PROP_VAL_MAX]; 3330 char delimiters[4]; 3331 uint_t val_cnt = *val_cntp; 3332 val_desc_t *vdp = *vdpp; 3333 3334 if (val_cnt != 1) 3335 return (DLADM_STATUS_BADVALCNT); 3336 3337 if (prop_val != NULL) { 3338 dlap = malloc(sizeof (struct dlautopush)); 3339 if (dlap == NULL) 3340 return (DLADM_STATUS_NOMEM); 3341 3342 (void) memset(dlap, 0, sizeof (struct dlautopush)); 3343 (void) snprintf(delimiters, 4, " %c\n", AP_DELIMITER); 3344 bcopy(*prop_val, val, DLADM_PROP_VAL_MAX); 3345 module = strtok(val, delimiters); 3346 while (module != NULL) { 3347 status = i_dladm_add_ap_module(module, dlap); 3348 if (status != DLADM_STATUS_OK) 3349 return (status); 3350 module = strtok(NULL, delimiters); 3351 } 3352 3353 vdp->vd_val = (uintptr_t)dlap; 3354 } else { 3355 vdp->vd_val = 0; 3356 } 3357 return (DLADM_STATUS_OK); 3358 } 3359 3360 #define WLDP_BUFSIZE (MAX_BUF_LEN - WIFI_BUF_OFFSET) 3361 3362 static dladm_status_t 3363 get_rate_common(dladm_handle_t handle, prop_desc_t *pdp __unused, 3364 datalink_id_t linkid, char **prop_val, uint_t *val_cnt, uint_t id, 3365 uint_t *perm_flags) 3366 { 3367 wl_rates_t *wrp; 3368 uint_t i; 3369 dladm_status_t status = DLADM_STATUS_OK; 3370 3371 wrp = malloc(WLDP_BUFSIZE); 3372 if (wrp == NULL) 3373 return (DLADM_STATUS_NOMEM); 3374 3375 status = i_dladm_wlan_param(handle, linkid, wrp, id, WLDP_BUFSIZE, 3376 B_FALSE); 3377 if (status != DLADM_STATUS_OK) 3378 goto done; 3379 3380 if (wrp->wl_rates_num > *val_cnt) { 3381 status = DLADM_STATUS_TOOSMALL; 3382 goto done; 3383 } 3384 3385 if (wrp->wl_rates_rates[0] == 0) { 3386 prop_val[0][0] = '\0'; 3387 *val_cnt = 1; 3388 goto done; 3389 } 3390 3391 for (i = 0; i < wrp->wl_rates_num; i++) { 3392 (void) snprintf(prop_val[i], DLADM_STRSIZE, "%.*f", 3393 wrp->wl_rates_rates[i] % 2, 3394 (float)wrp->wl_rates_rates[i] / 2); 3395 } 3396 *val_cnt = wrp->wl_rates_num; 3397 *perm_flags = MAC_PROP_PERM_RW; 3398 3399 done: 3400 free(wrp); 3401 return (status); 3402 } 3403 3404 static dladm_status_t 3405 get_rate(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid, 3406 char **prop_val, uint_t *val_cnt, datalink_media_t media, 3407 uint_t flags, uint_t *perm_flags) 3408 { 3409 if (media != DL_WIFI) { 3410 return (get_speed(handle, pdp, linkid, prop_val, 3411 val_cnt, media, flags, perm_flags)); 3412 } 3413 3414 return (get_rate_common(handle, pdp, linkid, prop_val, val_cnt, 3415 MAC_PROP_WL_DESIRED_RATES, perm_flags)); 3416 } 3417 3418 static dladm_status_t 3419 get_rate_mod(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid, 3420 char **prop_val, uint_t *val_cnt, datalink_media_t media, 3421 uint_t flags __unused, uint_t *perm_flags) 3422 { 3423 switch (media) { 3424 case DL_ETHER: 3425 /* 3426 * Speed for ethernet links is unbounded. E.g., 802.11b 3427 * links can have a speed of 5.5 Gbps. 3428 */ 3429 return (DLADM_STATUS_NOTSUP); 3430 3431 case DL_WIFI: 3432 return (get_rate_common(handle, pdp, linkid, prop_val, 3433 val_cnt, MAC_PROP_WL_SUPPORTED_RATES, perm_flags)); 3434 default: 3435 return (DLADM_STATUS_BADARG); 3436 } 3437 } 3438 3439 static dladm_status_t 3440 set_wlan_rate(dladm_handle_t handle, datalink_id_t linkid, 3441 dladm_wlan_rates_t *rates) 3442 { 3443 int i; 3444 uint_t len; 3445 wl_rates_t *wrp; 3446 dladm_status_t status = DLADM_STATUS_OK; 3447 3448 wrp = malloc(WLDP_BUFSIZE); 3449 if (wrp == NULL) 3450 return (DLADM_STATUS_NOMEM); 3451 3452 bzero(wrp, WLDP_BUFSIZE); 3453 for (i = 0; i < rates->wr_cnt; i++) 3454 wrp->wl_rates_rates[i] = rates->wr_rates[i]; 3455 wrp->wl_rates_num = rates->wr_cnt; 3456 3457 len = offsetof(wl_rates_t, wl_rates_rates) + 3458 (rates->wr_cnt * sizeof (char)) + WIFI_BUF_OFFSET; 3459 status = i_dladm_wlan_param(handle, linkid, wrp, 3460 MAC_PROP_WL_DESIRED_RATES, len, B_TRUE); 3461 3462 free(wrp); 3463 return (status); 3464 } 3465 3466 static dladm_status_t 3467 set_rate(dladm_handle_t handle, prop_desc_t *pdp __unused, 3468 datalink_id_t linkid, val_desc_t *vdp, uint_t val_cnt, 3469 uint_t flags __unused, datalink_media_t media) 3470 { 3471 dladm_wlan_rates_t rates; 3472 dladm_status_t status; 3473 3474 /* 3475 * can currently set rate on WIFI links only. 3476 */ 3477 if (media != DL_WIFI) 3478 return (DLADM_STATUS_PROPRDONLY); 3479 3480 if (val_cnt != 1) 3481 return (DLADM_STATUS_BADVALCNT); 3482 3483 rates.wr_cnt = 1; 3484 rates.wr_rates[0] = vdp[0].vd_val; 3485 3486 status = set_wlan_rate(handle, linkid, &rates); 3487 3488 return (status); 3489 } 3490 3491 static dladm_status_t 3492 check_rate(dladm_handle_t handle, prop_desc_t *pdp __unused, 3493 datalink_id_t linkid, char **prop_val, uint_t *val_cntp, 3494 uint_t flags __unused, 3495 val_desc_t **vdpp, datalink_media_t media) 3496 { 3497 uint_t i; 3498 uint_t modval_cnt = MAX_SUPPORT_RATES; 3499 char *buf, **modval; 3500 dladm_status_t status; 3501 uint_t perm_flags; 3502 uint_t val_cnt = *val_cntp; 3503 val_desc_t *vdp = *vdpp; 3504 3505 if (val_cnt != 1) 3506 return (DLADM_STATUS_BADVALCNT); 3507 3508 buf = malloc((sizeof (char *) + DLADM_STRSIZE) * 3509 MAX_SUPPORT_RATES); 3510 if (buf == NULL) { 3511 status = DLADM_STATUS_NOMEM; 3512 goto done; 3513 } 3514 3515 modval = (char **)(void *)buf; 3516 for (i = 0; i < MAX_SUPPORT_RATES; i++) { 3517 modval[i] = buf + sizeof (char *) * MAX_SUPPORT_RATES + 3518 i * DLADM_STRSIZE; 3519 } 3520 3521 status = get_rate_mod(handle, NULL, linkid, modval, &modval_cnt, 3522 media, 0, &perm_flags); 3523 if (status != DLADM_STATUS_OK) 3524 goto done; 3525 3526 for (i = 0; i < modval_cnt; i++) { 3527 if (strcasecmp(*prop_val, modval[i]) == 0) { 3528 vdp->vd_val = (uintptr_t)(uint_t) 3529 (atof(*prop_val) * 2); 3530 status = DLADM_STATUS_OK; 3531 break; 3532 } 3533 } 3534 if (i == modval_cnt) 3535 status = DLADM_STATUS_BADVAL; 3536 done: 3537 free(buf); 3538 return (status); 3539 } 3540 3541 static dladm_status_t 3542 get_phyconf(dladm_handle_t handle, datalink_id_t linkid, void *buf, 3543 int buflen) 3544 { 3545 return (i_dladm_wlan_param(handle, linkid, buf, MAC_PROP_WL_PHY_CONFIG, 3546 buflen, B_FALSE)); 3547 } 3548 3549 static dladm_status_t 3550 get_channel(dladm_handle_t handle, prop_desc_t *pdp __unused, 3551 datalink_id_t linkid, char **prop_val, uint_t *val_cnt, 3552 datalink_media_t media __unused, uint_t flags __unused, uint_t *perm_flags) 3553 { 3554 uint32_t channel; 3555 char buf[WLDP_BUFSIZE]; 3556 dladm_status_t status; 3557 wl_phy_conf_t wl_phy_conf; 3558 3559 if ((status = get_phyconf(handle, linkid, buf, sizeof (buf))) 3560 != DLADM_STATUS_OK) 3561 return (status); 3562 3563 (void) memcpy(&wl_phy_conf, buf, sizeof (wl_phy_conf)); 3564 if (!i_dladm_wlan_convert_chan(&wl_phy_conf, &channel)) 3565 return (DLADM_STATUS_NOTFOUND); 3566 3567 (void) snprintf(*prop_val, DLADM_STRSIZE, "%u", channel); 3568 *val_cnt = 1; 3569 *perm_flags = MAC_PROP_PERM_READ; 3570 return (DLADM_STATUS_OK); 3571 } 3572 3573 static dladm_status_t 3574 get_powermode(dladm_handle_t handle, prop_desc_t *pdp __unused, 3575 datalink_id_t linkid, char **prop_val, uint_t *val_cnt, 3576 datalink_media_t media __unused, uint_t flags __unused, uint_t *perm_flags) 3577 { 3578 wl_ps_mode_t mode; 3579 const char *s; 3580 char buf[WLDP_BUFSIZE]; 3581 dladm_status_t status; 3582 3583 if ((status = i_dladm_wlan_param(handle, linkid, buf, 3584 MAC_PROP_WL_POWER_MODE, sizeof (buf), B_FALSE)) != DLADM_STATUS_OK) 3585 return (status); 3586 3587 (void) memcpy(&mode, buf, sizeof (mode)); 3588 switch (mode.wl_ps_mode) { 3589 case WL_PM_AM: 3590 s = "off"; 3591 break; 3592 case WL_PM_MPS: 3593 s = "max"; 3594 break; 3595 case WL_PM_FAST: 3596 s = "fast"; 3597 break; 3598 default: 3599 return (DLADM_STATUS_NOTFOUND); 3600 } 3601 (void) snprintf(*prop_val, DLADM_STRSIZE, "%s", s); 3602 *val_cnt = 1; 3603 *perm_flags = MAC_PROP_PERM_RW; 3604 return (DLADM_STATUS_OK); 3605 } 3606 3607 static dladm_status_t 3608 set_powermode(dladm_handle_t handle, prop_desc_t *pdp __unused, 3609 datalink_id_t linkid, val_desc_t *vdp, uint_t val_cnt, 3610 uint_t flags __unused, datalink_media_t media __unused) 3611 { 3612 dladm_wlan_powermode_t powermode = vdp->vd_val; 3613 wl_ps_mode_t ps_mode; 3614 3615 if (val_cnt != 1) 3616 return (DLADM_STATUS_BADVALCNT); 3617 3618 (void) memset(&ps_mode, 0xff, sizeof (ps_mode)); 3619 3620 switch (powermode) { 3621 case DLADM_WLAN_PM_OFF: 3622 ps_mode.wl_ps_mode = WL_PM_AM; 3623 break; 3624 case DLADM_WLAN_PM_MAX: 3625 ps_mode.wl_ps_mode = WL_PM_MPS; 3626 break; 3627 case DLADM_WLAN_PM_FAST: 3628 ps_mode.wl_ps_mode = WL_PM_FAST; 3629 break; 3630 default: 3631 return (DLADM_STATUS_NOTSUP); 3632 } 3633 return (i_dladm_wlan_param(handle, linkid, &ps_mode, 3634 MAC_PROP_WL_POWER_MODE, sizeof (ps_mode), B_TRUE)); 3635 } 3636 3637 static dladm_status_t 3638 get_radio(dladm_handle_t handle, prop_desc_t *pdp __unused, 3639 datalink_id_t linkid, char **prop_val, uint_t *val_cnt, 3640 datalink_media_t media __unused, uint_t flags __unused, uint_t *perm_flags) 3641 { 3642 wl_radio_t radio; 3643 const char *s; 3644 char buf[WLDP_BUFSIZE]; 3645 dladm_status_t status; 3646 3647 if ((status = i_dladm_wlan_param(handle, linkid, buf, 3648 MAC_PROP_WL_RADIO, sizeof (buf), B_FALSE)) != DLADM_STATUS_OK) 3649 return (status); 3650 3651 (void) memcpy(&radio, buf, sizeof (radio)); 3652 switch (radio) { 3653 case B_TRUE: 3654 s = "on"; 3655 break; 3656 case B_FALSE: 3657 s = "off"; 3658 break; 3659 default: 3660 return (DLADM_STATUS_NOTFOUND); 3661 } 3662 (void) snprintf(*prop_val, DLADM_STRSIZE, "%s", s); 3663 *val_cnt = 1; 3664 *perm_flags = MAC_PROP_PERM_RW; 3665 return (DLADM_STATUS_OK); 3666 } 3667 3668 static dladm_status_t 3669 set_radio(dladm_handle_t handle, prop_desc_t *pdp __unused, 3670 datalink_id_t linkid, val_desc_t *vdp, uint_t val_cnt, 3671 uint_t flags __unused, datalink_media_t media __unused) 3672 { 3673 dladm_wlan_radio_t radio = vdp->vd_val; 3674 wl_radio_t r; 3675 3676 if (val_cnt != 1) 3677 return (DLADM_STATUS_BADVALCNT); 3678 3679 switch (radio) { 3680 case DLADM_WLAN_RADIO_ON: 3681 r = B_TRUE; 3682 break; 3683 case DLADM_WLAN_RADIO_OFF: 3684 r = B_FALSE; 3685 break; 3686 default: 3687 return (DLADM_STATUS_NOTSUP); 3688 } 3689 return (i_dladm_wlan_param(handle, linkid, &r, MAC_PROP_WL_RADIO, 3690 sizeof (r), B_TRUE)); 3691 } 3692 3693 static dladm_status_t 3694 check_hoplimit(dladm_handle_t handle __unused, prop_desc_t *pdp __unused, 3695 datalink_id_t linkid __unused, char **prop_val, uint_t *val_cntp, 3696 uint_t flags __unused, val_desc_t **vdpp, datalink_media_t media __unused) 3697 { 3698 int32_t hlim; 3699 char *ep; 3700 uint_t val_cnt = *val_cntp; 3701 val_desc_t *vdp = *vdpp; 3702 3703 if (val_cnt != 1) 3704 return (DLADM_STATUS_BADVALCNT); 3705 3706 errno = 0; 3707 hlim = strtol(*prop_val, &ep, 10); 3708 if (errno != 0 || ep == *prop_val || hlim < 1 || 3709 hlim > (int32_t)UINT8_MAX) 3710 return (DLADM_STATUS_BADVAL); 3711 vdp->vd_val = hlim; 3712 return (DLADM_STATUS_OK); 3713 } 3714 3715 static dladm_status_t 3716 check_encaplim(dladm_handle_t handle __unused, prop_desc_t *pdp __unused, 3717 datalink_id_t linkid __unused, char **prop_val, uint_t *val_cntp, 3718 uint_t flags __unused, val_desc_t **vdpp, datalink_media_t media) 3719 { 3720 int32_t elim; 3721 char *ep; 3722 uint_t val_cnt = *val_cntp; 3723 val_desc_t *vdp = *vdpp; 3724 3725 if (media != DL_IPV6) 3726 return (DLADM_STATUS_BADARG); 3727 3728 if (val_cnt != 1) 3729 return (DLADM_STATUS_BADVALCNT); 3730 3731 errno = 0; 3732 elim = strtol(*prop_val, &ep, 10); 3733 if (errno != 0 || ep == *prop_val || elim < 0 || 3734 elim > (int32_t)UINT8_MAX) 3735 return (DLADM_STATUS_BADVAL); 3736 vdp->vd_val = elim; 3737 return (DLADM_STATUS_OK); 3738 } 3739 3740 static dladm_status_t 3741 i_dladm_set_linkprop_db(dladm_handle_t handle, datalink_id_t linkid, 3742 const char *prop_name, char **prop_val, uint_t val_cnt) 3743 { 3744 char buf[MAXLINELEN]; 3745 uint_t i; 3746 dladm_conf_t conf; 3747 dladm_status_t status; 3748 3749 status = dladm_open_conf(handle, linkid, &conf); 3750 if (status != DLADM_STATUS_OK) 3751 return (status); 3752 3753 /* 3754 * reset case. 3755 */ 3756 if (val_cnt == 0) { 3757 status = dladm_unset_conf_field(handle, conf, prop_name); 3758 if (status == DLADM_STATUS_OK) 3759 status = dladm_write_conf(handle, conf); 3760 goto done; 3761 } 3762 3763 buf[0] = '\0'; 3764 for (i = 0; i < val_cnt; i++) { 3765 (void) strlcat(buf, prop_val[i], MAXLINELEN); 3766 if (i != val_cnt - 1) 3767 (void) strlcat(buf, ",", MAXLINELEN); 3768 } 3769 3770 status = dladm_set_conf_field(handle, conf, prop_name, DLADM_TYPE_STR, 3771 buf); 3772 if (status == DLADM_STATUS_OK) 3773 status = dladm_write_conf(handle, conf); 3774 3775 done: 3776 dladm_destroy_conf(handle, conf); 3777 return (status); 3778 } 3779 3780 static dladm_status_t 3781 i_dladm_get_linkprop_db(dladm_handle_t handle, datalink_id_t linkid, 3782 const char *prop_name, char **prop_val, uint_t *val_cntp) 3783 { 3784 char buf[MAXLINELEN], *str; 3785 uint_t cnt = 0; 3786 dladm_conf_t conf; 3787 dladm_status_t status; 3788 3789 status = dladm_getsnap_conf(handle, linkid, &conf); 3790 if (status != DLADM_STATUS_OK) 3791 return (status); 3792 3793 status = dladm_get_conf_field(handle, conf, prop_name, buf, MAXLINELEN); 3794 if (status != DLADM_STATUS_OK) 3795 goto done; 3796 3797 str = strtok(buf, ","); 3798 while (str != NULL) { 3799 if (cnt == *val_cntp) { 3800 status = DLADM_STATUS_TOOSMALL; 3801 goto done; 3802 } 3803 (void) strlcpy(prop_val[cnt++], str, DLADM_PROP_VAL_MAX); 3804 str = strtok(NULL, ","); 3805 } 3806 3807 *val_cntp = cnt; 3808 3809 done: 3810 dladm_destroy_conf(handle, conf); 3811 return (status); 3812 } 3813 3814 /* 3815 * Walk persistent private link properties of a link. 3816 */ 3817 static dladm_status_t 3818 i_dladm_walk_linkprop_priv_db(dladm_handle_t handle, datalink_id_t linkid, 3819 void *arg, int (*func)(dladm_handle_t, datalink_id_t, const char *, void *)) 3820 { 3821 dladm_status_t status; 3822 dladm_conf_t conf; 3823 char last_attr[MAXLINKATTRLEN]; 3824 char attr[MAXLINKATTRLEN]; 3825 char attrval[MAXLINKATTRVALLEN]; 3826 size_t attrsz; 3827 3828 if (linkid == DATALINK_INVALID_LINKID || func == NULL) 3829 return (DLADM_STATUS_BADARG); 3830 3831 status = dladm_getsnap_conf(handle, linkid, &conf); 3832 if (status != DLADM_STATUS_OK) 3833 return (status); 3834 3835 last_attr[0] = '\0'; 3836 while ((status = dladm_getnext_conf_linkprop(handle, conf, last_attr, 3837 attr, attrval, MAXLINKATTRVALLEN, &attrsz)) == DLADM_STATUS_OK) { 3838 if (attr[0] == '_') { 3839 if (func(handle, linkid, attr, arg) == 3840 DLADM_WALK_TERMINATE) 3841 break; 3842 } 3843 (void) strlcpy(last_attr, attr, MAXLINKATTRLEN); 3844 } 3845 3846 dladm_destroy_conf(handle, conf); 3847 return (DLADM_STATUS_OK); 3848 } 3849 3850 static link_attr_t * 3851 dladm_name2prop(const char *prop_name) 3852 { 3853 link_attr_t *p; 3854 3855 for (p = link_attr; p->pp_id != MAC_PROP_PRIVATE; p++) { 3856 if (strcmp(p->pp_name, prop_name) == 0) 3857 break; 3858 } 3859 return (p); 3860 } 3861 3862 static link_attr_t * 3863 dladm_id2prop(mac_prop_id_t propid) 3864 { 3865 link_attr_t *p; 3866 3867 for (p = link_attr; p->pp_id != MAC_PROP_PRIVATE; p++) { 3868 if (p->pp_id == propid) 3869 break; 3870 } 3871 return (p); 3872 } 3873 3874 static dld_ioc_macprop_t * 3875 i_dladm_buf_alloc_impl(size_t valsize, datalink_id_t linkid, 3876 const char *prop_name, mac_prop_id_t propid, uint_t flags, 3877 dladm_status_t *status) 3878 { 3879 int dsize; 3880 dld_ioc_macprop_t *dip; 3881 3882 *status = DLADM_STATUS_OK; 3883 dsize = MAC_PROP_BUFSIZE(valsize); 3884 dip = malloc(dsize); 3885 if (dip == NULL) { 3886 *status = DLADM_STATUS_NOMEM; 3887 return (NULL); 3888 } 3889 bzero(dip, dsize); 3890 dip->pr_valsize = valsize; 3891 (void) strlcpy(dip->pr_name, prop_name, sizeof (dip->pr_name)); 3892 dip->pr_linkid = linkid; 3893 dip->pr_num = propid; 3894 dip->pr_flags = flags; 3895 return (dip); 3896 } 3897 3898 static dld_ioc_macprop_t * 3899 i_dladm_buf_alloc_by_name(size_t valsize, datalink_id_t linkid, 3900 const char *prop_name, uint_t flags, dladm_status_t *status) 3901 { 3902 link_attr_t *p; 3903 3904 p = dladm_name2prop(prop_name); 3905 valsize = MAX(p->pp_valsize, valsize); 3906 return (i_dladm_buf_alloc_impl(valsize, linkid, prop_name, p->pp_id, 3907 flags, status)); 3908 } 3909 3910 static dld_ioc_macprop_t * 3911 i_dladm_buf_alloc_by_id(size_t valsize, datalink_id_t linkid, 3912 mac_prop_id_t propid, uint_t flags, dladm_status_t *status) 3913 { 3914 link_attr_t *p; 3915 3916 p = dladm_id2prop(propid); 3917 valsize = MAX(p->pp_valsize, valsize); 3918 return (i_dladm_buf_alloc_impl(valsize, linkid, p->pp_name, propid, 3919 flags, status)); 3920 } 3921 3922 static dladm_status_t 3923 set_public_prop(dladm_handle_t handle, prop_desc_t *pdp, 3924 datalink_id_t linkid, val_desc_t *vdp, uint_t val_cnt __unused, 3925 uint_t flags __unused, datalink_media_t media __unused) 3926 { 3927 dld_ioc_macprop_t *dip; 3928 dladm_status_t status = DLADM_STATUS_OK; 3929 uint8_t u8; 3930 uint16_t u16; 3931 uint32_t u32; 3932 void *val; 3933 3934 dip = i_dladm_buf_alloc_by_name(0, linkid, pdp->pd_name, 0, &status); 3935 if (dip == NULL) 3936 return (status); 3937 3938 if (pdp->pd_flags & PD_CHECK_ALLOC) 3939 val = (void *)vdp->vd_val; 3940 else { 3941 /* 3942 * Currently all 1/2/4-byte size properties are byte/word/int. 3943 * No need (yet) to distinguish these from arrays of same size. 3944 */ 3945 switch (dip->pr_valsize) { 3946 case 1: 3947 u8 = vdp->vd_val; 3948 val = &u8; 3949 break; 3950 case 2: 3951 u16 = vdp->vd_val; 3952 val = &u16; 3953 break; 3954 case 4: 3955 u32 = vdp->vd_val; 3956 val = &u32; 3957 break; 3958 default: 3959 val = &vdp->vd_val; 3960 break; 3961 } 3962 } 3963 3964 if (val != NULL) 3965 (void) memcpy(dip->pr_val, val, dip->pr_valsize); 3966 else 3967 dip->pr_valsize = 0; 3968 3969 status = i_dladm_macprop(handle, dip, B_TRUE); 3970 3971 free(dip); 3972 return (status); 3973 } 3974 3975 static dladm_status_t 3976 set_public_bitprop(dladm_handle_t handle, prop_desc_t *pdp, 3977 datalink_id_t linkid, val_desc_t *vdp, uint_t val_cnt, uint_t flags, 3978 datalink_media_t media) 3979 { 3980 uint_t i, j; 3981 val_desc_t vd = { 0 }; 3982 3983 if ((pdp->pd_flags & PD_CHECK_ALLOC) != 0) 3984 return (DLADM_STATUS_BADARG); 3985 3986 for (i = 0; i < val_cnt; i++) { 3987 for (j = 0; j < pdp->pd_noptval; j++) { 3988 if (strcasecmp(vdp[i].vd_name, 3989 pdp->pd_optval[j].vd_name) == 0) { 3990 vd.vd_val |= pdp->pd_optval[j].vd_val; 3991 break; 3992 } 3993 } 3994 } 3995 3996 if (vd.vd_val == 0) 3997 return (DLADM_STATUS_BADARG); 3998 3999 return (set_public_prop(handle, pdp, linkid, &vd, 1, flags, media)); 4000 } 4001 4002 dladm_status_t 4003 i_dladm_macprop(dladm_handle_t handle, void *dip, boolean_t set) 4004 { 4005 dladm_status_t status = DLADM_STATUS_OK; 4006 4007 if (ioctl(dladm_dld_fd(handle), 4008 (set ? DLDIOC_SETMACPROP : DLDIOC_GETMACPROP), dip)) 4009 status = dladm_errno2status(errno); 4010 4011 return (status); 4012 } 4013 4014 static dladm_status_t 4015 i_dladm_get_public_prop(dladm_handle_t handle, datalink_id_t linkid, 4016 char *prop_name, uint_t flags, uint_t *perm_flags, void *arg, size_t size) 4017 { 4018 dld_ioc_macprop_t *dip; 4019 dladm_status_t status; 4020 4021 dip = i_dladm_buf_alloc_by_name(0, linkid, prop_name, flags, &status); 4022 if (dip == NULL) 4023 return (DLADM_STATUS_NOMEM); 4024 4025 status = i_dladm_macprop(handle, dip, B_FALSE); 4026 if (status != DLADM_STATUS_OK) { 4027 free(dip); 4028 return (status); 4029 } 4030 4031 if (perm_flags != NULL) 4032 *perm_flags = dip->pr_perm_flags; 4033 4034 if (arg != NULL) 4035 (void) memcpy(arg, dip->pr_val, size); 4036 free(dip); 4037 return (DLADM_STATUS_OK); 4038 } 4039 4040 static dladm_status_t 4041 check_uint32(dladm_handle_t handle __unused, prop_desc_t *pdp __unused, 4042 datalink_id_t linkid __unused, char **prop_val, uint_t *val_cntp, 4043 uint_t flags __unused, val_desc_t **vp, datalink_media_t media __unused) 4044 { 4045 uint_t val_cnt = *val_cntp; 4046 val_desc_t *v = *vp; 4047 4048 if (val_cnt != 1) 4049 return (DLADM_STATUS_BADVAL); 4050 v->vd_val = strtoul(prop_val[0], NULL, 0); 4051 return (DLADM_STATUS_OK); 4052 } 4053 4054 static dladm_status_t 4055 get_duplex(dladm_handle_t handle, prop_desc_t *pdp __unused, 4056 datalink_id_t linkid, char **prop_val, uint_t *val_cnt, 4057 datalink_media_t media __unused, uint_t flags __unused, 4058 uint_t *perm_flags __unused) 4059 { 4060 link_duplex_t link_duplex; 4061 dladm_status_t status; 4062 4063 if ((status = dladm_get_single_mac_stat(handle, linkid, "link_duplex", 4064 KSTAT_DATA_UINT32, &link_duplex)) != 0) 4065 return (status); 4066 4067 switch (link_duplex) { 4068 case LINK_DUPLEX_FULL: 4069 (void) strcpy(*prop_val, "full"); 4070 break; 4071 case LINK_DUPLEX_HALF: 4072 (void) strcpy(*prop_val, "half"); 4073 break; 4074 default: 4075 (void) strcpy(*prop_val, "unknown"); 4076 break; 4077 } 4078 *val_cnt = 1; 4079 return (DLADM_STATUS_OK); 4080 } 4081 4082 static dladm_status_t 4083 get_speed(dladm_handle_t handle, prop_desc_t *pdp __unused, 4084 datalink_id_t linkid, char **prop_val, uint_t *val_cnt, 4085 datalink_media_t media __unused, uint_t flags __unused, 4086 uint_t *perm_flags) 4087 { 4088 uint64_t ifspeed = 0; 4089 dladm_status_t status; 4090 4091 if ((status = dladm_get_single_mac_stat(handle, linkid, "ifspeed", 4092 KSTAT_DATA_UINT64, &ifspeed)) != 0) 4093 return (status); 4094 4095 if ((ifspeed % 1000000) != 0) { 4096 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, 4097 "%llf", ifspeed / (float)1000000); /* Mbps */ 4098 } else { 4099 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, 4100 "%llu", ifspeed / 1000000); /* Mbps */ 4101 } 4102 *val_cnt = 1; 4103 *perm_flags = MAC_PROP_PERM_READ; 4104 return (DLADM_STATUS_OK); 4105 } 4106 4107 static dladm_status_t 4108 get_link_state(dladm_handle_t handle, prop_desc_t *pdp __unused, 4109 datalink_id_t linkid, char **prop_val, uint_t *val_cnt, 4110 datalink_media_t media __unused, uint_t flags __unused, uint_t *perm_flags) 4111 { 4112 link_state_t link_state; 4113 dladm_status_t status; 4114 4115 status = dladm_get_state(handle, linkid, &link_state); 4116 if (status != DLADM_STATUS_OK) 4117 return (status); 4118 4119 switch (link_state) { 4120 case LINK_STATE_UP: 4121 (void) strcpy(*prop_val, "up"); 4122 break; 4123 case LINK_STATE_DOWN: 4124 (void) strcpy(*prop_val, "down"); 4125 break; 4126 default: 4127 (void) strcpy(*prop_val, "unknown"); 4128 break; 4129 } 4130 *val_cnt = 1; 4131 *perm_flags = MAC_PROP_PERM_READ; 4132 return (DLADM_STATUS_OK); 4133 } 4134 4135 static dladm_status_t 4136 get_binary(dladm_handle_t handle, prop_desc_t *pdp, 4137 datalink_id_t linkid, char **prop_val, uint_t *val_cnt, 4138 datalink_media_t media __unused, uint_t flags, uint_t *perm_flags) 4139 { 4140 dladm_status_t status; 4141 uint_t v = 0; 4142 4143 status = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags, 4144 perm_flags, &v, sizeof (v)); 4145 if (status != DLADM_STATUS_OK) 4146 return (status); 4147 4148 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "%d", (uint_t)(v > 0)); 4149 *val_cnt = 1; 4150 return (DLADM_STATUS_OK); 4151 } 4152 4153 static dladm_status_t 4154 get_uint32(dladm_handle_t handle, prop_desc_t *pdp, 4155 datalink_id_t linkid, char **prop_val, uint_t *val_cnt, 4156 datalink_media_t media __unused, uint_t flags, uint_t *perm_flags) 4157 { 4158 dladm_status_t status; 4159 uint32_t v = 0; 4160 4161 status = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags, 4162 perm_flags, &v, sizeof (v)); 4163 if (status != DLADM_STATUS_OK) 4164 return (status); 4165 4166 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "%ld", v); 4167 *val_cnt = 1; 4168 return (DLADM_STATUS_OK); 4169 } 4170 4171 static dladm_status_t 4172 get_range(dladm_handle_t handle, prop_desc_t *pdp, 4173 datalink_id_t linkid, char **prop_val, uint_t *val_cnt, 4174 datalink_media_t media __unused, uint_t flags, uint_t *perm_flags __unused) 4175 { 4176 dld_ioc_macprop_t *dip; 4177 dladm_status_t status = DLADM_STATUS_OK; 4178 size_t sz; 4179 uint_t rcount; 4180 mac_propval_range_t *rangep; 4181 4182 /* 4183 * As caller we don't know number of value ranges, the driver 4184 * supports. To begin with we assume that number to be 1. If the 4185 * buffer size is insufficient, driver returns back with the 4186 * actual count of value ranges. See mac.h for more details. 4187 */ 4188 sz = sizeof (mac_propval_range_t); 4189 rcount = 1; 4190 retry: 4191 if ((dip = i_dladm_buf_alloc_by_name(sz, linkid, pdp->pd_name, flags, 4192 &status)) == NULL) 4193 return (status); 4194 4195 rangep = (mac_propval_range_t *)(void *)&dip->pr_val; 4196 rangep->mpr_count = rcount; 4197 4198 status = i_dladm_macprop(handle, dip, B_FALSE); 4199 if (status != DLADM_STATUS_OK) { 4200 if (status == DLADM_STATUS_TOOSMALL) { 4201 int err; 4202 4203 if ((err = i_dladm_range_size(rangep, &sz, &rcount)) 4204 == 0) { 4205 free(dip); 4206 goto retry; 4207 } else { 4208 status = dladm_errno2status(err); 4209 } 4210 } 4211 free(dip); 4212 return (status); 4213 } 4214 4215 if (rangep->mpr_count == 0) { 4216 *val_cnt = 1; 4217 (void) snprintf(prop_val[0], DLADM_PROP_VAL_MAX, "--"); 4218 goto done; 4219 } 4220 4221 switch (rangep->mpr_type) { 4222 case MAC_PROPVAL_UINT32: { 4223 mac_propval_uint32_range_t *ur; 4224 uint_t count = rangep->mpr_count, i; 4225 4226 ur = &rangep->mpr_range_uint32[0]; 4227 4228 for (i = 0; i < count; i++, ur++) { 4229 if (ur->mpur_min == ur->mpur_max) { 4230 (void) snprintf(prop_val[i], DLADM_PROP_VAL_MAX, 4231 "%ld", ur->mpur_min); 4232 } else { 4233 (void) snprintf(prop_val[i], DLADM_PROP_VAL_MAX, 4234 "%ld-%ld", ur->mpur_min, ur->mpur_max); 4235 } 4236 } 4237 *val_cnt = count; 4238 break; 4239 } 4240 default: 4241 status = DLADM_STATUS_BADARG; 4242 break; 4243 } 4244 done: 4245 free(dip); 4246 return (status); 4247 } 4248 4249 static dladm_status_t 4250 get_tagmode(dladm_handle_t handle, prop_desc_t *pdp, 4251 datalink_id_t linkid, char **prop_val, uint_t *val_cnt, 4252 datalink_media_t media __unused, uint_t flags, uint_t *perm_flags) 4253 { 4254 link_tagmode_t mode; 4255 dladm_status_t status; 4256 4257 status = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags, 4258 perm_flags, &mode, sizeof (mode)); 4259 if (status != DLADM_STATUS_OK) 4260 return (status); 4261 4262 switch (mode) { 4263 case LINK_TAGMODE_NORMAL: 4264 (void) strlcpy(*prop_val, "normal", DLADM_PROP_VAL_MAX); 4265 break; 4266 case LINK_TAGMODE_VLANONLY: 4267 (void) strlcpy(*prop_val, "vlanonly", DLADM_PROP_VAL_MAX); 4268 break; 4269 default: 4270 (void) strlcpy(*prop_val, "unknown", DLADM_PROP_VAL_MAX); 4271 } 4272 *val_cnt = 1; 4273 return (DLADM_STATUS_OK); 4274 } 4275 4276 static dladm_status_t 4277 get_flowctl(dladm_handle_t handle, prop_desc_t *pdp, 4278 datalink_id_t linkid, char **prop_val, uint_t *val_cnt, 4279 datalink_media_t media __unused, uint_t flags, uint_t *perm_flags) 4280 { 4281 link_flowctrl_t v; 4282 dladm_status_t status; 4283 4284 status = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags, 4285 perm_flags, &v, sizeof (v)); 4286 if (status != DLADM_STATUS_OK) 4287 return (status); 4288 4289 switch (v) { 4290 case LINK_FLOWCTRL_NONE: 4291 (void) sprintf(*prop_val, "no"); 4292 break; 4293 case LINK_FLOWCTRL_RX: 4294 (void) sprintf(*prop_val, "rx"); 4295 break; 4296 case LINK_FLOWCTRL_TX: 4297 (void) sprintf(*prop_val, "tx"); 4298 break; 4299 case LINK_FLOWCTRL_BI: 4300 (void) sprintf(*prop_val, "bi"); 4301 break; 4302 } 4303 *val_cnt = 1; 4304 return (DLADM_STATUS_OK); 4305 } 4306 4307 static dladm_status_t 4308 get_bits(dladm_handle_t handle, prop_desc_t *pdp, 4309 datalink_id_t linkid, char **prop_val, uint_t *val_cnt, 4310 datalink_media_t media __unused, uint_t flags, uint_t *perm_flags) 4311 { 4312 uint32_t v; 4313 dladm_status_t status; 4314 uint_t i, cnt; 4315 4316 status = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags, 4317 perm_flags, &v, sizeof (v)); 4318 if (status != DLADM_STATUS_OK) 4319 return (status); 4320 4321 cnt = 0; 4322 for (i = 0; cnt < *val_cnt && i < pdp->pd_noptval; i++) { 4323 if ((v & pdp->pd_optval[i].vd_val) != 0) { 4324 (void) snprintf(prop_val[cnt++], DLADM_STRSIZE, 4325 pdp->pd_optval[i].vd_name); 4326 } 4327 } 4328 4329 if (i < pdp->pd_noptval) 4330 return (DLADM_STATUS_BADVALCNT); 4331 4332 *val_cnt = cnt; 4333 return (DLADM_STATUS_OK); 4334 } 4335 4336 static dladm_status_t 4337 i_dladm_set_private_prop(dladm_handle_t handle, datalink_id_t linkid, 4338 const char *prop_name, char **prop_val, uint_t val_cnt, uint_t flags) 4339 { 4340 uint_t i; 4341 int slen; 4342 int bufsize = 0; 4343 dld_ioc_macprop_t *dip = NULL; 4344 uchar_t *dp; 4345 link_attr_t *p; 4346 dladm_status_t status = DLADM_STATUS_OK; 4347 4348 if ((prop_name == NULL && prop_val != NULL) || 4349 (prop_val != NULL && val_cnt == 0)) 4350 return (DLADM_STATUS_BADARG); 4351 p = dladm_name2prop(prop_name); 4352 if (p->pp_id != MAC_PROP_PRIVATE) 4353 return (DLADM_STATUS_BADARG); 4354 4355 if (!(flags & DLADM_OPT_ACTIVE)) 4356 return (DLADM_STATUS_OK); 4357 4358 /* 4359 * private properties: all parsing is done in the kernel. 4360 * allocate a enough space for each property + its separator (','). 4361 */ 4362 for (i = 0; i < val_cnt; i++) { 4363 bufsize += strlen(prop_val[i]) + 1; 4364 } 4365 4366 if (prop_val == NULL) { 4367 /* 4368 * getting default value. so use more buffer space. 4369 */ 4370 bufsize += DLADM_PROP_BUF_CHUNK; 4371 } 4372 4373 dip = i_dladm_buf_alloc_by_name(bufsize + 1, linkid, prop_name, 4374 (prop_val != NULL ? 0 : DLD_PROP_DEFAULT), &status); 4375 if (dip == NULL) 4376 return (status); 4377 4378 dp = (uchar_t *)dip->pr_val; 4379 slen = 0; 4380 4381 if (prop_val == NULL) { 4382 status = i_dladm_macprop(handle, dip, B_FALSE); 4383 dip->pr_flags = 0; 4384 } else { 4385 for (i = 0; i < val_cnt; i++) { 4386 int plen = 0; 4387 4388 plen = strlen(prop_val[i]); 4389 bcopy(prop_val[i], dp, plen); 4390 slen += plen; 4391 /* 4392 * add a "," separator and update dp. 4393 */ 4394 if (i != (val_cnt - 1)) 4395 dp[slen++] = ','; 4396 dp += (plen + 1); 4397 } 4398 } 4399 if (status == DLADM_STATUS_OK) 4400 status = i_dladm_macprop(handle, dip, B_TRUE); 4401 4402 free(dip); 4403 return (status); 4404 } 4405 4406 static dladm_status_t 4407 i_dladm_get_priv_prop(dladm_handle_t handle, datalink_id_t linkid, 4408 const char *prop_name, char **prop_val, uint_t *val_cnt, 4409 dladm_prop_type_t type, uint_t dld_flags) 4410 { 4411 dladm_status_t status = DLADM_STATUS_OK; 4412 dld_ioc_macprop_t *dip = NULL; 4413 link_attr_t *p; 4414 4415 if ((prop_name == NULL && prop_val != NULL) || 4416 (prop_val != NULL && val_cnt == 0)) 4417 return (DLADM_STATUS_BADARG); 4418 4419 p = dladm_name2prop(prop_name); 4420 if (p->pp_id != MAC_PROP_PRIVATE) 4421 return (DLADM_STATUS_BADARG); 4422 4423 /* 4424 * private properties: all parsing is done in the kernel. 4425 */ 4426 dip = i_dladm_buf_alloc_by_name(DLADM_PROP_BUF_CHUNK, linkid, prop_name, 4427 dld_flags, &status); 4428 if (dip == NULL) 4429 return (status); 4430 4431 if ((status = i_dladm_macprop(handle, dip, B_FALSE)) == 4432 DLADM_STATUS_OK) { 4433 if (type == DLADM_PROP_VAL_PERM) { 4434 (void) dladm_perm2str(dip->pr_perm_flags, *prop_val); 4435 } else if (type == DLADM_PROP_VAL_MODIFIABLE) { 4436 *prop_val[0] = '\0'; 4437 } else { 4438 (void) strncpy(*prop_val, dip->pr_val, 4439 DLADM_PROP_VAL_MAX); 4440 } 4441 *val_cnt = 1; 4442 } else if ((status == DLADM_STATUS_NOTSUP) && 4443 (type == DLADM_PROP_VAL_CURRENT)) { 4444 status = DLADM_STATUS_NOTFOUND; 4445 } 4446 free(dip); 4447 return (status); 4448 } 4449 4450 4451 static dladm_status_t 4452 i_dladm_getset_defval(dladm_handle_t handle, prop_desc_t *pdp, 4453 datalink_id_t linkid, datalink_media_t media, uint_t flags) 4454 { 4455 dladm_status_t status; 4456 char **prop_vals = NULL, *buf; 4457 size_t bufsize; 4458 uint_t cnt; 4459 int i; 4460 uint_t perm_flags; 4461 4462 /* 4463 * Allocate buffer needed for prop_vals array. We can have at most 4464 * DLADM_MAX_PROP_VALCNT char *prop_vals[] entries, where 4465 * each entry has max size DLADM_PROP_VAL_MAX 4466 */ 4467 bufsize = 4468 (sizeof (char *) + DLADM_PROP_VAL_MAX) * DLADM_MAX_PROP_VALCNT; 4469 buf = malloc(bufsize); 4470 prop_vals = (char **)(void *)buf; 4471 for (i = 0; i < DLADM_MAX_PROP_VALCNT; i++) { 4472 prop_vals[i] = buf + 4473 sizeof (char *) * DLADM_MAX_PROP_VALCNT + 4474 i * DLADM_PROP_VAL_MAX; 4475 } 4476 4477 /* 4478 * For properties which have pdp->pd_defval.vd_name as a non-empty 4479 * string, the "" itself is used to reset the property (exceptions 4480 * are zone and autopush, which populate vdp->vd_val). So 4481 * libdladm can copy pdp->pd_defval over to the val_desc_t passed 4482 * down on the setprop using the global values in the table. For 4483 * other cases (vd_name is ""), doing reset-linkprop will cause 4484 * libdladm to do a getprop to find the default value and then do 4485 * a setprop to reset the value to default. 4486 */ 4487 status = pdp->pd_get(handle, pdp, linkid, prop_vals, &cnt, media, 4488 DLD_PROP_DEFAULT, &perm_flags); 4489 if (status == DLADM_STATUS_OK) { 4490 if (perm_flags == MAC_PROP_PERM_RW) { 4491 status = i_dladm_set_single_prop(handle, linkid, 4492 pdp->pd_class, media, pdp, prop_vals, cnt, flags); 4493 } 4494 else 4495 status = DLADM_STATUS_NOTSUP; 4496 } 4497 free(buf); 4498 return (status); 4499 } 4500 4501 static dladm_status_t 4502 get_stp(dladm_handle_t handle, struct prop_desc *pd, datalink_id_t linkid, 4503 char **prop_val, uint_t *val_cnt, datalink_media_t media __unused, 4504 uint_t flags, uint_t *perm_flags) 4505 { 4506 const bridge_public_prop_t *bpp; 4507 dladm_status_t retv; 4508 int val; 4509 uint_t i; 4510 4511 if (flags != 0) 4512 return (DLADM_STATUS_NOTSUP); 4513 *perm_flags = MAC_PROP_PERM_RW; 4514 *val_cnt = 1; 4515 for (bpp = bridge_prop; bpp->bpp_name != NULL; bpp++) 4516 if (strcmp(bpp->bpp_name, pd->pd_name) == 0) 4517 break; 4518 retv = dladm_bridge_get_port_cfg(handle, linkid, bpp->bpp_code, &val); 4519 /* If the daemon isn't running, then return the persistent value */ 4520 if (retv == DLADM_STATUS_NOTFOUND) { 4521 if (i_dladm_get_linkprop_db(handle, linkid, pd->pd_name, 4522 prop_val, val_cnt) != DLADM_STATUS_OK) 4523 (void) strlcpy(*prop_val, pd->pd_defval.vd_name, 4524 DLADM_PROP_VAL_MAX); 4525 return (DLADM_STATUS_OK); 4526 } 4527 if (retv != DLADM_STATUS_OK) { 4528 (void) strlcpy(*prop_val, "?", DLADM_PROP_VAL_MAX); 4529 return (retv); 4530 } 4531 if ((uintptr_t)val == pd->pd_defval.vd_val && 4532 pd->pd_defval.vd_name[0] != '\0') { 4533 (void) strlcpy(*prop_val, pd->pd_defval.vd_name, 4534 DLADM_PROP_VAL_MAX); 4535 return (DLADM_STATUS_OK); 4536 } 4537 for (i = 0; i < pd->pd_noptval; i++) { 4538 if ((uintptr_t)val == pd->pd_optval[i].vd_val) { 4539 (void) strlcpy(*prop_val, pd->pd_optval[i].vd_name, 4540 DLADM_PROP_VAL_MAX); 4541 return (DLADM_STATUS_OK); 4542 } 4543 } 4544 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "%u", (unsigned)val); 4545 return (DLADM_STATUS_OK); 4546 } 4547 4548 static dladm_status_t 4549 set_stp_prop(dladm_handle_t handle, prop_desc_t *pd __unused, 4550 datalink_id_t linkid, val_desc_t *vdp __unused, uint_t val_cnt __unused, 4551 uint_t flags, datalink_media_t media __unused) 4552 { 4553 /* 4554 * Special case for mcheck: the daemon resets the value to zero, and we 4555 * don't want the daemon to refresh itself; it leads to deadlock. 4556 */ 4557 if (flags & DLADM_OPT_NOREFRESH) 4558 return (DLADM_STATUS_OK); 4559 4560 /* Tell the running daemon, if any */ 4561 return (dladm_bridge_refresh(handle, linkid)); 4562 } 4563 4564 /* 4565 * This is used only for stp_priority, stp_cost, and stp_mcheck. 4566 */ 4567 static dladm_status_t 4568 check_stp_prop(dladm_handle_t handle, struct prop_desc *pd, 4569 datalink_id_t linkid, char **prop_val, uint_t *val_cntp, 4570 uint_t flags __unused, val_desc_t **vdpp, datalink_media_t media __unused) 4571 { 4572 char *cp; 4573 boolean_t iscost = B_FALSE; 4574 uint_t val_cnt = *val_cntp; 4575 val_desc_t *vdp = *vdpp; 4576 4577 if (val_cnt != 1) 4578 return (DLADM_STATUS_BADVALCNT); 4579 4580 if (prop_val == NULL) { 4581 vdp->vd_val = 0; 4582 } else { 4583 /* Only stp_priority and stp_cost use this function */ 4584 iscost = strcmp(pd->pd_name, "stp_cost") == 0; 4585 4586 if (iscost && strcmp(prop_val[0], "auto") == 0) { 4587 /* Illegal value 0 is allowed to mean "automatic" */ 4588 vdp->vd_val = 0; 4589 } else { 4590 errno = 0; 4591 vdp->vd_val = strtoul(prop_val[0], &cp, 0); 4592 if (errno != 0 || *cp != '\0') 4593 return (DLADM_STATUS_BADVAL); 4594 } 4595 } 4596 4597 if (iscost) { 4598 return (vdp->vd_val > 65535 ? DLADM_STATUS_BADVAL : 4599 DLADM_STATUS_OK); 4600 } else { 4601 if (vdp->vd_val > 255) 4602 return (DLADM_STATUS_BADVAL); 4603 /* 4604 * If the user is setting stp_mcheck non-zero, then (per the 4605 * IEEE management standards and UNH testing) we need to check 4606 * whether this link is part of a bridge that is running RSTP. 4607 * If it's not, then setting the flag is an error. Note that 4608 * errors are intentionally discarded here; it's the value 4609 * that's the problem -- it's not a bad value, merely one that 4610 * can't be used now. 4611 */ 4612 if (strcmp(pd->pd_name, "stp_mcheck") == 0 && 4613 vdp->vd_val != 0) { 4614 char bridge[MAXLINKNAMELEN]; 4615 UID_STP_CFG_T cfg; 4616 dladm_bridge_prot_t brprot; 4617 4618 if (dladm_bridge_getlink(handle, linkid, bridge, 4619 sizeof (bridge)) != DLADM_STATUS_OK || 4620 dladm_bridge_get_properties(bridge, &cfg, 4621 &brprot) != DLADM_STATUS_OK) 4622 return (DLADM_STATUS_FAILED); 4623 if (cfg.force_version <= 1) 4624 return (DLADM_STATUS_FAILED); 4625 } 4626 return (DLADM_STATUS_OK); 4627 } 4628 } 4629 4630 static dladm_status_t 4631 get_bridge_forward(dladm_handle_t handle, struct prop_desc *pd, 4632 datalink_id_t linkid, char **prop_val, uint_t *val_cnt, 4633 datalink_media_t media __unused, uint_t flags, uint_t *perm_flags) 4634 { 4635 dladm_status_t retv; 4636 uint_t val; 4637 4638 if (flags != 0) 4639 return (DLADM_STATUS_NOTSUP); 4640 *perm_flags = MAC_PROP_PERM_RW; 4641 *val_cnt = 1; 4642 retv = dladm_bridge_get_forwarding(handle, linkid, &val); 4643 if (retv == DLADM_STATUS_NOTFOUND) { 4644 if (i_dladm_get_linkprop_db(handle, linkid, pd->pd_name, 4645 prop_val, val_cnt) != DLADM_STATUS_OK) 4646 (void) strlcpy(*prop_val, pd->pd_defval.vd_name, 4647 DLADM_PROP_VAL_MAX); 4648 return (DLADM_STATUS_OK); 4649 } 4650 if (retv == DLADM_STATUS_OK) 4651 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "%u", val); 4652 else 4653 (void) strlcpy(*prop_val, "?", DLADM_PROP_VAL_MAX); 4654 return (retv); 4655 } 4656 4657 static dladm_status_t 4658 set_bridge_forward(dladm_handle_t handle, prop_desc_t *pd __unused, 4659 datalink_id_t linkid, val_desc_t *vdp __unused, uint_t val_cnt __unused, 4660 uint_t flags __unused, datalink_media_t media __unused) 4661 { 4662 /* Tell the running daemon, if any */ 4663 return (dladm_bridge_refresh(handle, linkid)); 4664 } 4665 4666 static dladm_status_t 4667 get_bridge_pvid(dladm_handle_t handle, struct prop_desc *pd __unused, 4668 datalink_id_t linkid, char **prop_val, uint_t *val_cnt, 4669 datalink_media_t media __unused, uint_t flags, uint_t *perm_flags) 4670 { 4671 dladm_status_t status; 4672 dld_ioc_macprop_t *dip; 4673 uint16_t pvid; 4674 4675 if (flags != 0) 4676 return (DLADM_STATUS_NOTSUP); 4677 *perm_flags = MAC_PROP_PERM_RW; 4678 *val_cnt = 1; 4679 dip = i_dladm_buf_alloc_by_id(sizeof (uint16_t), linkid, MAC_PROP_PVID, 4680 0, &status); 4681 if (dip == NULL) 4682 return (status); 4683 status = i_dladm_macprop(handle, dip, B_FALSE); 4684 if (status == DLADM_STATUS_OK) { 4685 (void) memcpy(&pvid, dip->pr_val, sizeof (pvid)); 4686 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "%u", pvid); 4687 } else { 4688 (void) strlcpy(*prop_val, "?", DLADM_PROP_VAL_MAX); 4689 } 4690 free(dip); 4691 return (status); 4692 } 4693 4694 static dladm_status_t 4695 set_bridge_pvid(dladm_handle_t handle, prop_desc_t *pd __unused, 4696 datalink_id_t linkid, val_desc_t *vdp, uint_t val_cnt __unused, 4697 uint_t flags __unused, datalink_media_t media __unused) 4698 { 4699 dladm_status_t status; 4700 dld_ioc_macprop_t *dip; 4701 uint16_t pvid; 4702 4703 dip = i_dladm_buf_alloc_by_id(sizeof (uint16_t), linkid, MAC_PROP_PVID, 4704 0, &status); 4705 if (dip == NULL) 4706 return (status); 4707 pvid = vdp->vd_val; 4708 (void) memcpy(dip->pr_val, &pvid, sizeof (pvid)); 4709 status = i_dladm_macprop(handle, dip, B_TRUE); 4710 free(dip); 4711 if (status != DLADM_STATUS_OK) 4712 return (status); 4713 4714 /* Tell the running daemon, if any */ 4715 return (dladm_bridge_refresh(handle, linkid)); 4716 } 4717 4718 static dladm_status_t 4719 check_bridge_pvid(dladm_handle_t handle __unused, struct prop_desc *pd __unused, 4720 datalink_id_t linkid __unused, char **prop_val, uint_t *val_cntp, 4721 uint_t flags __unused, val_desc_t **vdpp, datalink_media_t media __unused) 4722 { 4723 char *cp; 4724 uint_t val_cnt = *val_cntp; 4725 val_desc_t *vdp = *vdpp; 4726 4727 if (val_cnt != 1) 4728 return (DLADM_STATUS_BADVALCNT); 4729 4730 if (prop_val == NULL) { 4731 vdp->vd_val = 1; 4732 } else { 4733 errno = 0; 4734 vdp->vd_val = strtoul(prop_val[0], &cp, 0); 4735 if (errno != 0 || *cp != '\0') 4736 return (DLADM_STATUS_BADVAL); 4737 } 4738 4739 return (vdp->vd_val > VLAN_ID_MAX ? DLADM_STATUS_BADVAL : 4740 DLADM_STATUS_OK); 4741 } 4742 4743 dladm_status_t 4744 i_dladm_wlan_param(dladm_handle_t handle, datalink_id_t linkid, void *buf, 4745 mac_prop_id_t cmd, size_t len, boolean_t set) 4746 { 4747 uint32_t flags; 4748 dladm_status_t status; 4749 uint32_t media; 4750 dld_ioc_macprop_t *dip; 4751 void *dp; 4752 4753 if ((status = dladm_datalink_id2info(handle, linkid, &flags, NULL, 4754 &media, NULL, 0)) != DLADM_STATUS_OK) { 4755 return (status); 4756 } 4757 4758 if (media != DL_WIFI) 4759 return (DLADM_STATUS_BADARG); 4760 4761 if (!(flags & DLADM_OPT_ACTIVE)) 4762 return (DLADM_STATUS_TEMPONLY); 4763 4764 if (len == (MAX_BUF_LEN - WIFI_BUF_OFFSET)) 4765 len = MAX_BUF_LEN - sizeof (dld_ioc_macprop_t) - 1; 4766 4767 dip = i_dladm_buf_alloc_by_id(len, linkid, cmd, 0, &status); 4768 if (dip == NULL) 4769 return (DLADM_STATUS_NOMEM); 4770 4771 dp = (uchar_t *)dip->pr_val; 4772 if (set) 4773 (void) memcpy(dp, buf, len); 4774 4775 status = i_dladm_macprop(handle, dip, set); 4776 if (status == DLADM_STATUS_OK) { 4777 if (!set) 4778 (void) memcpy(buf, dp, len); 4779 } 4780 4781 free(dip); 4782 return (status); 4783 } 4784 4785 dladm_status_t 4786 dladm_parse_link_props(char *str, dladm_arg_list_t **listp, boolean_t novalues) 4787 { 4788 return (dladm_parse_args(str, listp, novalues)); 4789 } 4790 4791 /* 4792 * Retrieve the one link property from the database 4793 */ 4794 static int 4795 i_dladm_get_one_prop(dladm_handle_t handle, datalink_id_t linkid, 4796 const char *prop_name, void *arg) 4797 { 4798 dladm_arg_list_t *proplist = arg; 4799 dladm_arg_info_t *aip = NULL; 4800 4801 aip = &proplist->al_info[proplist->al_count]; 4802 /* 4803 * it is fine to point to prop_name since prop_name points to the 4804 * prop_table[n].pd_name. 4805 */ 4806 aip->ai_name = prop_name; 4807 4808 (void) dladm_get_linkprop(handle, linkid, DLADM_PROP_VAL_PERSISTENT, 4809 prop_name, aip->ai_val, &aip->ai_count); 4810 4811 if (aip->ai_count != 0) 4812 proplist->al_count++; 4813 4814 return (DLADM_WALK_CONTINUE); 4815 } 4816 4817 4818 /* 4819 * Retrieve all link properties for a link from the database and 4820 * return a property list. 4821 */ 4822 dladm_status_t 4823 dladm_link_get_proplist(dladm_handle_t handle, datalink_id_t linkid, 4824 dladm_arg_list_t **listp) 4825 { 4826 dladm_arg_list_t *list; 4827 dladm_status_t status = DLADM_STATUS_OK; 4828 4829 list = calloc(1, sizeof (dladm_arg_list_t)); 4830 if (list == NULL) 4831 return (dladm_errno2status(errno)); 4832 4833 status = dladm_walk_linkprop(handle, linkid, list, 4834 i_dladm_get_one_prop); 4835 4836 *listp = list; 4837 return (status); 4838 } 4839 4840 /* 4841 * Retrieve the named property from a proplist, check the value and 4842 * convert to a kernel structure. 4843 */ 4844 static dladm_status_t 4845 i_dladm_link_proplist_extract_one(dladm_handle_t handle, 4846 dladm_arg_list_t *proplist, const char *name, uint_t flags, void *arg) 4847 { 4848 dladm_status_t status = DLADM_STATUS_OK; 4849 dladm_arg_info_t *aip = NULL; 4850 uint_t i, j; 4851 4852 /* Find named property in proplist */ 4853 for (i = 0; i < proplist->al_count; i++) { 4854 aip = &proplist->al_info[i]; 4855 if (strcasecmp(aip->ai_name, name) == 0) 4856 break; 4857 } 4858 4859 /* Property not in list */ 4860 if (i == proplist->al_count) 4861 return (status); 4862 4863 if (aip->ai_val[0] == NULL) 4864 return (DLADM_STATUS_BADARG); 4865 4866 for (i = 0; i < DLADM_MAX_PROPS; i++) { 4867 prop_desc_t *pdp = &prop_table[i]; 4868 val_desc_t *vdp; 4869 4870 vdp = malloc(sizeof (val_desc_t) * aip->ai_count); 4871 if (vdp == NULL) 4872 return (DLADM_STATUS_NOMEM); 4873 4874 if (strcasecmp(aip->ai_name, pdp->pd_name) != 0) 4875 continue; 4876 4877 /* Check property value */ 4878 if (pdp->pd_check != NULL) { 4879 status = pdp->pd_check(handle, pdp, 0, aip->ai_val, 4880 &(aip->ai_count), flags, &vdp, 0); 4881 } else { 4882 status = DLADM_STATUS_BADARG; 4883 } 4884 4885 if (status != DLADM_STATUS_OK) 4886 return (status); 4887 4888 for (j = 0; j < DLADM_MAX_RSRC_PROP; j++) { 4889 resource_prop_t *rpp = &rsrc_prop_table[j]; 4890 4891 if (strcasecmp(aip->ai_name, rpp->rp_name) != 0) 4892 continue; 4893 4894 /* Extract kernel structure */ 4895 if (rpp->rp_extract != NULL) { 4896 status = rpp->rp_extract(vdp, 4897 aip->ai_count, arg); 4898 } else { 4899 status = DLADM_STATUS_BADARG; 4900 } 4901 break; 4902 } 4903 4904 if (status != DLADM_STATUS_OK) 4905 return (status); 4906 4907 break; 4908 } 4909 return (status); 4910 } 4911 4912 /* 4913 * Extract properties from a proplist and convert to mac_resource_props_t. 4914 */ 4915 dladm_status_t 4916 dladm_link_proplist_extract(dladm_handle_t handle, dladm_arg_list_t *proplist, 4917 mac_resource_props_t *mrp, uint_t flags) 4918 { 4919 dladm_status_t status; 4920 uint_t i; 4921 4922 for (i = 0; i < DLADM_MAX_RSRC_PROP; i++) { 4923 status = i_dladm_link_proplist_extract_one(handle, 4924 proplist, rsrc_prop_table[i].rp_name, flags, mrp); 4925 if (status != DLADM_STATUS_OK) 4926 return (status); 4927 } 4928 return (status); 4929 } 4930 4931 static const char * 4932 dladm_perm2str(uint_t perm, char *buf) 4933 { 4934 (void) snprintf(buf, DLADM_STRSIZE, "%c%c", 4935 ((perm & MAC_PROP_PERM_READ) != 0) ? 'r' : '-', 4936 ((perm & MAC_PROP_PERM_WRITE) != 0) ? 'w' : '-'); 4937 return (buf); 4938 } 4939 4940 dladm_status_t 4941 dladm_get_state(dladm_handle_t handle, datalink_id_t linkid, 4942 link_state_t *state) 4943 { 4944 uint_t perms; 4945 4946 return (i_dladm_get_public_prop(handle, linkid, "state", 0, 4947 &perms, state, sizeof (*state))); 4948 } 4949 4950 boolean_t 4951 dladm_attr_is_linkprop(const char *name) 4952 { 4953 /* non-property attribute names */ 4954 const char *nonprop[] = { 4955 /* dlmgmtd core attributes */ 4956 "name", 4957 "class", 4958 "media", 4959 FPHYMAJ, 4960 FPHYINST, 4961 FDEVNAME, 4962 4963 /* other attributes for vlan, aggr, etc */ 4964 DLADM_ATTR_NAMES 4965 }; 4966 boolean_t is_nonprop = B_FALSE; 4967 uint_t i; 4968 4969 for (i = 0; i < sizeof (nonprop) / sizeof (nonprop[0]); i++) { 4970 if (strcmp(name, nonprop[i]) == 0) { 4971 is_nonprop = B_TRUE; 4972 break; 4973 } 4974 } 4975 4976 return (!is_nonprop); 4977 } 4978 4979 dladm_status_t 4980 dladm_linkprop_is_set(dladm_handle_t handle, datalink_id_t linkid, 4981 dladm_prop_type_t type, const char *prop_name, boolean_t *is_set) 4982 { 4983 char *buf, **propvals; 4984 uint_t valcnt = DLADM_MAX_PROP_VALCNT; 4985 uint_t i; 4986 dladm_status_t status = DLADM_STATUS_OK; 4987 size_t bufsize; 4988 4989 *is_set = B_FALSE; 4990 4991 bufsize = (sizeof (char *) + DLADM_PROP_VAL_MAX) * 4992 DLADM_MAX_PROP_VALCNT; 4993 if ((buf = calloc(1, bufsize)) == NULL) 4994 return (DLADM_STATUS_NOMEM); 4995 4996 propvals = (char **)(void *)buf; 4997 for (i = 0; i < valcnt; i++) { 4998 propvals[i] = buf + 4999 sizeof (char *) * DLADM_MAX_PROP_VALCNT + 5000 i * DLADM_PROP_VAL_MAX; 5001 } 5002 5003 if (dladm_get_linkprop(handle, linkid, type, prop_name, propvals, 5004 &valcnt) != DLADM_STATUS_OK) { 5005 goto done; 5006 } 5007 5008 /* 5009 * valcnt is always set to 1 by get_pool(), hence we need to check 5010 * for a non-null string to see if it is set. For protection, 5011 * secondary-macs and allowed-ips, we can check either the *propval 5012 * or the valcnt. 5013 */ 5014 if ((strcmp(prop_name, "pool") == 0 || 5015 strcmp(prop_name, "protection") == 0 || 5016 strcmp(prop_name, "secondary-macs") == 0 || 5017 strcmp(prop_name, "allowed-ips") == 0) && 5018 (strlen(*propvals) != 0)) { 5019 *is_set = B_TRUE; 5020 } else if ((strcmp(prop_name, "cpus") == 0) && (valcnt != 0)) { 5021 *is_set = B_TRUE; 5022 } else if ((strcmp(prop_name, "_softmac") == 0) && (valcnt != 0) && 5023 (strcmp(propvals[0], "true") == 0)) { 5024 *is_set = B_TRUE; 5025 } 5026 5027 done: 5028 if (buf != NULL) 5029 free(buf); 5030 return (status); 5031 } 5032 5033 static dladm_status_t 5034 get_linkmode_prop(dladm_handle_t handle, prop_desc_t *pdp, 5035 datalink_id_t linkid, char **prop_val, uint_t *val_cnt, 5036 datalink_media_t media __unused, uint_t flags, uint_t *perm_flags) 5037 { 5038 char *s; 5039 uint32_t v; 5040 dladm_status_t status; 5041 5042 status = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags, 5043 perm_flags, &v, sizeof (v)); 5044 if (status != DLADM_STATUS_OK) 5045 return (status); 5046 5047 switch (v) { 5048 case DLADM_PART_CM_MODE: 5049 s = "cm"; 5050 break; 5051 case DLADM_PART_UD_MODE: 5052 s = "ud"; 5053 break; 5054 default: 5055 s = ""; 5056 break; 5057 } 5058 (void) snprintf(prop_val[0], DLADM_STRSIZE, "%s", s); 5059 5060 *val_cnt = 1; 5061 return (DLADM_STATUS_OK); 5062 } 5063 5064 static dladm_status_t 5065 get_promisc_filtered(dladm_handle_t handle, prop_desc_t *pdp, 5066 datalink_id_t linkid, char **prop_val, uint_t *val_cnt, 5067 datalink_media_t media __unused, uint_t flags, uint_t *perm_flags) 5068 { 5069 char *s; 5070 dladm_status_t status; 5071 boolean_t filt; 5072 5073 status = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags, 5074 perm_flags, &filt, sizeof (filt)); 5075 if (status != DLADM_STATUS_OK) 5076 return (status); 5077 5078 if (filt != 0) 5079 s = link_promisc_filtered_vals[1].vd_name; 5080 else 5081 s = link_promisc_filtered_vals[0].vd_name; 5082 (void) snprintf(prop_val[0], DLADM_STRSIZE, "%s", s); 5083 5084 *val_cnt = 1; 5085 return (DLADM_STATUS_OK); 5086 } 5087 5088 static dladm_status_t 5089 set_promisc_filtered(dladm_handle_t handle, prop_desc_t *pdp, 5090 datalink_id_t linkid, val_desc_t *vdp, uint_t val_cnt __unused, 5091 uint_t flags __unused, datalink_media_t media __unused) 5092 { 5093 dld_ioc_macprop_t *dip; 5094 dladm_status_t status = DLADM_STATUS_OK; 5095 5096 dip = i_dladm_buf_alloc_by_name(0, linkid, pdp->pd_name, 5097 0, &status); 5098 5099 if (dip == NULL) 5100 return (status); 5101 5102 (void) memcpy(dip->pr_val, &vdp->vd_val, dip->pr_valsize); 5103 status = i_dladm_macprop(handle, dip, B_TRUE); 5104 5105 free(dip); 5106 return (status); 5107 } 5108 5109 static dladm_status_t 5110 get_media(dladm_handle_t handle, prop_desc_t *pdp, 5111 datalink_id_t linkid, char **prop_val, uint_t *val_cnt, 5112 datalink_media_t media, uint_t flags, uint_t *perm_flags) 5113 { 5114 dladm_status_t status = DLADM_STATUS_OK; 5115 uint32_t raw_val; 5116 val_desc_t *descs; 5117 size_t desc_count; 5118 5119 if (*val_cnt == 0) 5120 return (DLADM_STATUS_TOOSMALL); 5121 5122 status = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags, 5123 perm_flags, &raw_val, sizeof (raw_val)); 5124 if (status != DLADM_STATUS_OK) 5125 return (status); 5126 5127 /* 5128 * To translate the property into a string we need to know the actual 5129 * datalink_media_t type to use as these values are media-type specific. 5130 */ 5131 switch (media) { 5132 case DL_ETHER: 5133 descs = dladm_ether_media_vals; 5134 desc_count = VALCNT(dladm_ether_media_vals); 5135 break; 5136 default: 5137 descs = NULL; 5138 desc_count = 0; 5139 break; 5140 } 5141 5142 *val_cnt = 1; 5143 for (size_t i = 0; i < desc_count; i++) { 5144 if (descs[i].vd_val == raw_val) { 5145 (void) strlcpy(prop_val[0], descs[i].vd_name, 5146 DLADM_PROP_VAL_MAX); 5147 return (DLADM_STATUS_OK); 5148 } 5149 } 5150 5151 (void) snprintf(prop_val[0], DLADM_STRSIZE, "unknown (0x%x)", 5152 raw_val); 5153 return (DLADM_STATUS_OK); 5154 } 5155