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