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