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