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