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