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