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