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