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) 1999 { 2000 uint_t count = r->mpr_count; 2001 2002 *sz = sizeof (mac_propval_range_t); 2003 --count; 2004 2005 switch (r->mpr_type) { 2006 case MAC_PROPVAL_UINT32: 2007 *sz += (count * sizeof (mac_propval_uint32_range_t)); 2008 return (0); 2009 default: 2010 break; 2011 } 2012 *sz = 0; 2013 return (EINVAL); 2014 } 2015 2016 2017 /* ARGSUSED */ 2018 static dladm_status_t 2019 check_rings(dladm_handle_t handle, prop_desc_t *pdp, 2020 datalink_id_t linkid, char **prop_val, uint_t *val_cntp, uint_t flags, 2021 val_desc_t **vp, datalink_media_t media) 2022 { 2023 uint_t val_cnt = *val_cntp; 2024 val_desc_t *v = *vp; 2025 2026 if (val_cnt != 1) 2027 return (DLADM_STATUS_BADVAL); 2028 if (strncasecmp(prop_val[0], "hw", strlen("hw")) == 0) { 2029 v->vd_val = UNSPEC_VAL; 2030 } else if (strncasecmp(prop_val[0], "sw", strlen("sw")) == 0) { 2031 v->vd_val = 0; 2032 } else { 2033 v->vd_val = strtoul(prop_val[0], NULL, 0); 2034 if (v->vd_val == 0) 2035 return (DLADM_STATUS_BADVAL); 2036 } 2037 return (DLADM_STATUS_OK); 2038 } 2039 2040 /* ARGSUSED */ 2041 static dladm_status_t 2042 get_rings_range(dladm_handle_t handle, prop_desc_t *pdp, 2043 datalink_id_t linkid, char **prop_val, uint_t *val_cnt, 2044 datalink_media_t media, uint_t flags, uint_t *perm_flags) 2045 { 2046 dld_ioc_macprop_t *dip; 2047 dladm_status_t status = DLADM_STATUS_OK; 2048 mac_propval_range_t *rangep; 2049 size_t sz; 2050 mac_propval_uint32_range_t *ur; 2051 2052 sz = sizeof (mac_propval_range_t); 2053 2054 if ((dip = i_dladm_buf_alloc_by_name(sz, linkid, pdp->pd_name, flags, 2055 &status)) == NULL) 2056 return (status); 2057 2058 status = i_dladm_macprop(handle, dip, B_FALSE); 2059 if (status != DLADM_STATUS_OK) 2060 return (status); 2061 2062 rangep = (mac_propval_range_t *)(void *)&dip->pr_val; 2063 *val_cnt = 1; 2064 ur = &rangep->mpr_range_uint32[0]; 2065 /* This is the case where the dev doesn't have any rings/groups */ 2066 if (rangep->mpr_count == 0) { 2067 (*prop_val)[0] = '\0'; 2068 /* 2069 * This is the case where the dev supports rings, but static 2070 * grouping. 2071 */ 2072 } else if (ur->mpur_min == ur->mpur_max && 2073 ur->mpur_max == 0) { 2074 (void) snprintf(prop_val[0], DLADM_PROP_VAL_MAX, "sw,hw"); 2075 /* 2076 * This is the case where the dev supports rings and dynamic 2077 * grouping, but has only one value (say 2 rings and 2 groups). 2078 */ 2079 } else if (ur->mpur_min == ur->mpur_max) { 2080 (void) snprintf(prop_val[0], DLADM_PROP_VAL_MAX, "sw,hw,%d", 2081 ur->mpur_min); 2082 /* 2083 * This is the case where the dev supports rings and dynamic 2084 * grouping and has a range of rings. 2085 */ 2086 } else { 2087 (void) snprintf(prop_val[0], DLADM_PROP_VAL_MAX, 2088 "sw,hw,<%ld-%ld>", ur->mpur_min, ur->mpur_max); 2089 } 2090 free(dip); 2091 return (status); 2092 } 2093 2094 2095 /* ARGSUSED */ 2096 static dladm_status_t 2097 get_rxrings(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid, 2098 char **prop_val, uint_t *val_cnt, datalink_media_t media, 2099 uint_t flags, uint_t *perm_flags) 2100 { 2101 mac_resource_props_t mrp; 2102 dladm_status_t status; 2103 uint32_t nrings = 0; 2104 2105 /* 2106 * Get the number of (effective-)rings from the resource property. 2107 */ 2108 if (strcmp(pdp->pd_name, "rxrings-effective") == 0) { 2109 status = i_dladm_get_public_prop(handle, linkid, 2110 "resource-effective", flags, perm_flags, &mrp, 2111 sizeof (mrp)); 2112 } else { 2113 /* 2114 * Get the permissions from the "rxrings" property. 2115 */ 2116 status = i_dladm_get_public_prop(handle, linkid, "rxrings", 2117 flags, perm_flags, NULL, 0); 2118 if (status != DLADM_STATUS_OK) 2119 return (status); 2120 2121 status = i_dladm_get_public_prop(handle, linkid, 2122 "resource", flags, NULL, &mrp, sizeof (mrp)); 2123 } 2124 2125 if (status != DLADM_STATUS_OK) 2126 return (status); 2127 2128 if ((mrp.mrp_mask & MRP_RX_RINGS) == 0) { 2129 *val_cnt = 0; 2130 return (DLADM_STATUS_OK); 2131 } 2132 nrings = mrp.mrp_nrxrings; 2133 *val_cnt = 1; 2134 if (mrp.mrp_mask & MRP_RXRINGS_UNSPEC) 2135 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "hw"); 2136 else if (nrings == 0) 2137 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "sw"); 2138 else 2139 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "%ld", nrings); 2140 return (DLADM_STATUS_OK); 2141 } 2142 2143 /* ARGSUSED */ 2144 dladm_status_t 2145 extract_rxrings(val_desc_t *vdp, uint_t cnt, void *arg) 2146 { 2147 mac_resource_props_t *mrp = (mac_resource_props_t *)arg; 2148 2149 mrp->mrp_nrxrings = 0; 2150 if (vdp->vd_val == RESET_VAL) 2151 mrp->mrp_mask = MRP_RINGS_RESET; 2152 else if (vdp->vd_val == UNSPEC_VAL) 2153 mrp->mrp_mask = MRP_RXRINGS_UNSPEC; 2154 else 2155 mrp->mrp_nrxrings = vdp->vd_val; 2156 mrp->mrp_mask |= MRP_RX_RINGS; 2157 2158 return (DLADM_STATUS_OK); 2159 } 2160 2161 /* ARGSUSED */ 2162 static dladm_status_t 2163 get_txrings(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid, 2164 char **prop_val, uint_t *val_cnt, datalink_media_t media, 2165 uint_t flags, uint_t *perm_flags) 2166 { 2167 mac_resource_props_t mrp; 2168 dladm_status_t status; 2169 uint32_t nrings = 0; 2170 2171 2172 /* 2173 * Get the number of (effective-)rings from the resource property. 2174 */ 2175 if (strcmp(pdp->pd_name, "txrings-effective") == 0) { 2176 status = i_dladm_get_public_prop(handle, linkid, 2177 "resource-effective", flags, perm_flags, &mrp, 2178 sizeof (mrp)); 2179 } else { 2180 /* 2181 * Get the permissions from the "txrings" property. 2182 */ 2183 status = i_dladm_get_public_prop(handle, linkid, "txrings", 2184 flags, perm_flags, NULL, 0); 2185 if (status != DLADM_STATUS_OK) 2186 return (status); 2187 2188 /* 2189 * Get the number of rings from the "resource" property. 2190 */ 2191 status = i_dladm_get_public_prop(handle, linkid, "resource", 2192 flags, NULL, &mrp, sizeof (mrp)); 2193 } 2194 2195 if (status != DLADM_STATUS_OK) 2196 return (status); 2197 2198 if ((mrp.mrp_mask & MRP_TX_RINGS) == 0) { 2199 *val_cnt = 0; 2200 return (DLADM_STATUS_OK); 2201 } 2202 nrings = mrp.mrp_ntxrings; 2203 *val_cnt = 1; 2204 if (mrp.mrp_mask & MRP_TXRINGS_UNSPEC) 2205 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "hw"); 2206 else if (nrings == 0) 2207 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "sw"); 2208 else 2209 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "%ld", nrings); 2210 return (DLADM_STATUS_OK); 2211 } 2212 2213 /* ARGSUSED */ 2214 dladm_status_t 2215 extract_txrings(val_desc_t *vdp, uint_t cnt, void *arg) 2216 { 2217 mac_resource_props_t *mrp = (mac_resource_props_t *)arg; 2218 2219 mrp->mrp_ntxrings = 0; 2220 if (vdp->vd_val == RESET_VAL) 2221 mrp->mrp_mask = MRP_RINGS_RESET; 2222 else if (vdp->vd_val == UNSPEC_VAL) 2223 mrp->mrp_mask = MRP_TXRINGS_UNSPEC; 2224 else 2225 mrp->mrp_ntxrings = vdp->vd_val; 2226 mrp->mrp_mask |= MRP_TX_RINGS; 2227 2228 return (DLADM_STATUS_OK); 2229 } 2230 2231 /* ARGSUSED */ 2232 static dladm_status_t 2233 get_cntavail(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid, 2234 char **prop_val, uint_t *val_cnt, datalink_media_t media, uint_t flags, 2235 uint_t *perm_flags) 2236 { 2237 if (flags & DLD_PROP_DEFAULT) 2238 return (DLADM_STATUS_NOTDEFINED); 2239 2240 return (get_uint32(handle, pdp, linkid, prop_val, val_cnt, media, 2241 flags, perm_flags)); 2242 } 2243 2244 /* ARGSUSED */ 2245 static dladm_status_t 2246 set_resource(dladm_handle_t handle, prop_desc_t *pdp, 2247 datalink_id_t linkid, val_desc_t *vdp, uint_t val_cnt, 2248 uint_t flags, datalink_media_t media) 2249 { 2250 mac_resource_props_t mrp; 2251 dladm_status_t status = DLADM_STATUS_OK; 2252 dld_ioc_macprop_t *dip; 2253 int i; 2254 2255 bzero(&mrp, sizeof (mac_resource_props_t)); 2256 dip = i_dladm_buf_alloc_by_name(0, linkid, "resource", 2257 flags, &status); 2258 2259 if (dip == NULL) 2260 return (status); 2261 2262 for (i = 0; i < DLADM_MAX_RSRC_PROP; i++) { 2263 resource_prop_t *rp = &rsrc_prop_table[i]; 2264 2265 if (strcmp(pdp->pd_name, rp->rp_name) != 0) 2266 continue; 2267 2268 status = rp->rp_extract(vdp, val_cnt, &mrp); 2269 if (status != DLADM_STATUS_OK) 2270 goto done; 2271 2272 break; 2273 } 2274 2275 (void) memcpy(dip->pr_val, &mrp, dip->pr_valsize); 2276 status = i_dladm_macprop(handle, dip, B_TRUE); 2277 2278 done: 2279 free(dip); 2280 return (status); 2281 } 2282 2283 /* ARGSUSED */ 2284 static dladm_status_t 2285 get_protection(dladm_handle_t handle, prop_desc_t *pdp, 2286 datalink_id_t linkid, char **prop_val, uint_t *val_cnt, 2287 datalink_media_t media, uint_t flags, uint_t *perm_flags) 2288 { 2289 mac_resource_props_t mrp; 2290 mac_protect_t *p; 2291 dladm_status_t status; 2292 uint32_t i, cnt = 0, setbits[32]; 2293 2294 status = i_dladm_get_public_prop(handle, linkid, "resource", flags, 2295 perm_flags, &mrp, sizeof (mrp)); 2296 if (status != DLADM_STATUS_OK) 2297 return (status); 2298 2299 p = &mrp.mrp_protect; 2300 if ((mrp.mrp_mask & MRP_PROTECT) == 0) { 2301 *val_cnt = 0; 2302 return (DLADM_STATUS_OK); 2303 } 2304 dladm_find_setbits32(p->mp_types, setbits, &cnt); 2305 if (cnt > *val_cnt) 2306 return (DLADM_STATUS_BADVALCNT); 2307 2308 for (i = 0; i < cnt; i++) 2309 (void) dladm_protect2str(setbits[i], prop_val[i]); 2310 2311 *val_cnt = cnt; 2312 return (DLADM_STATUS_OK); 2313 } 2314 2315 /* ARGSUSED */ 2316 static dladm_status_t 2317 get_allowedips(dladm_handle_t handle, prop_desc_t *pdp, 2318 datalink_id_t linkid, char **prop_val, uint_t *val_cnt, 2319 datalink_media_t media, uint_t flags, uint_t *perm_flags) 2320 { 2321 mac_resource_props_t mrp; 2322 mac_protect_t *p; 2323 dladm_status_t status; 2324 int i; 2325 2326 status = i_dladm_get_public_prop(handle, linkid, "resource", flags, 2327 perm_flags, &mrp, sizeof (mrp)); 2328 if (status != DLADM_STATUS_OK) 2329 return (status); 2330 2331 p = &mrp.mrp_protect; 2332 if (p->mp_ipaddrcnt == 0) { 2333 *val_cnt = 0; 2334 return (DLADM_STATUS_OK); 2335 } 2336 if (p->mp_ipaddrcnt > *val_cnt) 2337 return (DLADM_STATUS_BADVALCNT); 2338 2339 for (i = 0; i < p->mp_ipaddrcnt; i++) { 2340 if (p->mp_ipaddrs[i].ip_version == IPV4_VERSION) { 2341 ipaddr_t v4addr; 2342 2343 v4addr = V4_PART_OF_V6(p->mp_ipaddrs[i].ip_addr); 2344 (void) dladm_ipv4addr2str(&v4addr, prop_val[i]); 2345 } else { 2346 (void) dladm_ipv6addr2str(&p->mp_ipaddrs[i].ip_addr, 2347 prop_val[i]); 2348 } 2349 } 2350 *val_cnt = p->mp_ipaddrcnt; 2351 return (DLADM_STATUS_OK); 2352 } 2353 2354 dladm_status_t 2355 extract_protection(val_desc_t *vdp, uint_t cnt, void *arg) 2356 { 2357 mac_resource_props_t *mrp = arg; 2358 uint32_t types = 0; 2359 int i; 2360 2361 for (i = 0; i < cnt; i++) 2362 types |= (uint32_t)vdp[i].vd_val; 2363 2364 mrp->mrp_protect.mp_types = types; 2365 mrp->mrp_mask |= MRP_PROTECT; 2366 return (DLADM_STATUS_OK); 2367 } 2368 2369 dladm_status_t 2370 extract_allowedips(val_desc_t *vdp, uint_t cnt, void *arg) 2371 { 2372 mac_resource_props_t *mrp = arg; 2373 mac_protect_t *p = &mrp->mrp_protect; 2374 int i; 2375 2376 if (vdp->vd_val == 0) { 2377 cnt = (uint_t)-1; 2378 } else { 2379 for (i = 0; i < cnt; i++) { 2380 bcopy((void *)vdp[i].vd_val, &p->mp_ipaddrs[i], 2381 sizeof (mac_ipaddr_t)); 2382 } 2383 } 2384 p->mp_ipaddrcnt = cnt; 2385 mrp->mrp_mask |= MRP_PROTECT; 2386 return (DLADM_STATUS_OK); 2387 } 2388 2389 static dladm_status_t 2390 check_single_ip(char *buf, mac_ipaddr_t *addr) 2391 { 2392 dladm_status_t status; 2393 ipaddr_t v4addr; 2394 in6_addr_t v6addr; 2395 boolean_t isv4 = B_TRUE; 2396 2397 status = dladm_str2ipv4addr(buf, &v4addr); 2398 if (status == DLADM_STATUS_INVALID_IP) { 2399 status = dladm_str2ipv6addr(buf, &v6addr); 2400 if (status == DLADM_STATUS_OK) 2401 isv4 = B_FALSE; 2402 } 2403 if (status != DLADM_STATUS_OK) 2404 return (status); 2405 2406 if (isv4) { 2407 if (v4addr == INADDR_ANY) 2408 return (DLADM_STATUS_INVALID_IP); 2409 2410 IN6_IPADDR_TO_V4MAPPED(v4addr, &addr->ip_addr); 2411 addr->ip_version = IPV4_VERSION; 2412 } else { 2413 if (IN6_IS_ADDR_UNSPECIFIED(&v6addr)) 2414 return (DLADM_STATUS_INVALID_IP); 2415 2416 addr->ip_addr = v6addr; 2417 addr->ip_version = IPV6_VERSION; 2418 } 2419 return (DLADM_STATUS_OK); 2420 } 2421 2422 /* ARGSUSED */ 2423 static dladm_status_t 2424 check_allowedips(dladm_handle_t handle, prop_desc_t *pdp, 2425 datalink_id_t linkid, char **prop_val, uint_t *val_cntp, uint_t flags, 2426 val_desc_t **vdpp, datalink_media_t media) 2427 { 2428 dladm_status_t status; 2429 mac_ipaddr_t *addr; 2430 int i; 2431 uint_t val_cnt = *val_cntp; 2432 val_desc_t *vdp = *vdpp; 2433 2434 if (val_cnt > MPT_MAXIPADDR) 2435 return (DLADM_STATUS_BADVALCNT); 2436 2437 for (i = 0; i < val_cnt; i++) { 2438 if ((addr = calloc(1, sizeof (mac_ipaddr_t))) == NULL) { 2439 status = DLADM_STATUS_NOMEM; 2440 goto fail; 2441 } 2442 vdp[i].vd_val = (uintptr_t)addr; 2443 2444 status = check_single_ip(prop_val[i], addr); 2445 if (status != DLADM_STATUS_OK) 2446 goto fail; 2447 } 2448 return (DLADM_STATUS_OK); 2449 2450 fail: 2451 for (i = 0; i < val_cnt; i++) { 2452 free((void *)vdp[i].vd_val); 2453 vdp[i].vd_val = NULL; 2454 } 2455 return (status); 2456 } 2457 2458 static void 2459 dladm_cid2str(mac_dhcpcid_t *cid, char *buf) 2460 { 2461 char tmp_buf[DLADM_STRSIZE]; 2462 uint_t hexlen; 2463 2464 switch (cid->dc_form) { 2465 case CIDFORM_TYPED: { 2466 uint16_t duidtype, hwtype; 2467 uint32_t timestamp, ennum; 2468 char *lladdr; 2469 2470 if (cid->dc_len < sizeof (duidtype)) 2471 goto fail; 2472 2473 bcopy(cid->dc_id, &duidtype, sizeof (duidtype)); 2474 duidtype = ntohs(duidtype); 2475 switch (duidtype) { 2476 case DHCPV6_DUID_LLT: { 2477 duid_llt_t llt; 2478 2479 if (cid->dc_len < sizeof (llt)) 2480 goto fail; 2481 2482 bcopy(cid->dc_id, &llt, sizeof (llt)); 2483 hwtype = ntohs(llt.dllt_hwtype); 2484 timestamp = ntohl(llt.dllt_time); 2485 lladdr = _link_ntoa(cid->dc_id + sizeof (llt), 2486 NULL, cid->dc_len - sizeof (llt), IFT_OTHER); 2487 if (lladdr == NULL) 2488 goto fail; 2489 2490 (void) snprintf(buf, DLADM_STRSIZE, "%d.%d.%d.%s", 2491 duidtype, hwtype, timestamp, lladdr); 2492 free(lladdr); 2493 break; 2494 } 2495 case DHCPV6_DUID_EN: { 2496 duid_en_t en; 2497 2498 if (cid->dc_len < sizeof (en)) 2499 goto fail; 2500 2501 bcopy(cid->dc_id, &en, sizeof (en)); 2502 ennum = DHCPV6_GET_ENTNUM(&en); 2503 hexlen = sizeof (tmp_buf); 2504 if (octet_to_hexascii(cid->dc_id + sizeof (en), 2505 cid->dc_len - sizeof (en), tmp_buf, &hexlen) != 0) 2506 goto fail; 2507 2508 (void) snprintf(buf, DLADM_STRSIZE, "%d.%d.%s", 2509 duidtype, ennum, tmp_buf); 2510 break; 2511 } 2512 case DHCPV6_DUID_LL: { 2513 duid_ll_t ll; 2514 2515 if (cid->dc_len < sizeof (ll)) 2516 goto fail; 2517 2518 bcopy(cid->dc_id, &ll, sizeof (ll)); 2519 hwtype = ntohs(ll.dll_hwtype); 2520 lladdr = _link_ntoa(cid->dc_id + sizeof (ll), 2521 NULL, cid->dc_len - sizeof (ll), IFT_OTHER); 2522 if (lladdr == NULL) 2523 goto fail; 2524 2525 (void) snprintf(buf, DLADM_STRSIZE, "%d.%d.%s", 2526 duidtype, hwtype, lladdr); 2527 free(lladdr); 2528 break; 2529 } 2530 default: { 2531 hexlen = sizeof (tmp_buf); 2532 if (octet_to_hexascii(cid->dc_id + sizeof (duidtype), 2533 cid->dc_len - sizeof (duidtype), 2534 tmp_buf, &hexlen) != 0) 2535 goto fail; 2536 2537 (void) snprintf(buf, DLADM_STRSIZE, "%d.%s", 2538 duidtype, tmp_buf); 2539 } 2540 } 2541 break; 2542 } 2543 case CIDFORM_HEX: { 2544 hexlen = sizeof (tmp_buf); 2545 if (octet_to_hexascii(cid->dc_id, cid->dc_len, 2546 tmp_buf, &hexlen) != 0) 2547 goto fail; 2548 2549 (void) snprintf(buf, DLADM_STRSIZE, "0x%s", tmp_buf); 2550 break; 2551 } 2552 case CIDFORM_STR: { 2553 int i; 2554 2555 for (i = 0; i < cid->dc_len; i++) { 2556 if (!isprint(cid->dc_id[i])) 2557 goto fail; 2558 } 2559 (void) snprintf(buf, DLADM_STRSIZE, "%s", cid->dc_id); 2560 break; 2561 } 2562 default: 2563 goto fail; 2564 } 2565 return; 2566 2567 fail: 2568 (void) snprintf(buf, DLADM_STRSIZE, "<unknown>"); 2569 } 2570 2571 static dladm_status_t 2572 dladm_str2cid(char *buf, mac_dhcpcid_t *cid) 2573 { 2574 char *ptr = buf; 2575 char tmp_buf[DLADM_STRSIZE]; 2576 uint_t hexlen, cidlen; 2577 2578 bzero(cid, sizeof (*cid)); 2579 if (isdigit(*ptr) && 2580 ptr[strspn(ptr, "0123456789")] == '.') { 2581 char *cp; 2582 ulong_t duidtype; 2583 ulong_t subtype; 2584 ulong_t timestamp; 2585 uchar_t *lladdr; 2586 int addrlen; 2587 2588 errno = 0; 2589 duidtype = strtoul(ptr, &cp, 0); 2590 if (ptr == cp || errno != 0 || *cp != '.' || 2591 duidtype > USHRT_MAX) 2592 return (DLADM_STATUS_BADARG); 2593 ptr = cp + 1; 2594 2595 if (duidtype != 0 && duidtype <= DHCPV6_DUID_LL) { 2596 errno = 0; 2597 subtype = strtoul(ptr, &cp, 0); 2598 if (ptr == cp || errno != 0 || *cp != '.') 2599 return (DLADM_STATUS_BADARG); 2600 ptr = cp + 1; 2601 } 2602 switch (duidtype) { 2603 case DHCPV6_DUID_LLT: { 2604 duid_llt_t llt; 2605 2606 errno = 0; 2607 timestamp = strtoul(ptr, &cp, 0); 2608 if (ptr == cp || errno != 0 || *cp != '.') 2609 return (DLADM_STATUS_BADARG); 2610 2611 ptr = cp + 1; 2612 lladdr = _link_aton(ptr, &addrlen); 2613 if (lladdr == NULL) 2614 return (DLADM_STATUS_BADARG); 2615 2616 cidlen = sizeof (llt) + addrlen; 2617 if (cidlen > sizeof (cid->dc_id)) { 2618 free(lladdr); 2619 return (DLADM_STATUS_TOOSMALL); 2620 } 2621 llt.dllt_dutype = htons(duidtype); 2622 llt.dllt_hwtype = htons(subtype); 2623 llt.dllt_time = htonl(timestamp); 2624 bcopy(&llt, cid->dc_id, sizeof (llt)); 2625 bcopy(lladdr, cid->dc_id + sizeof (llt), addrlen); 2626 free(lladdr); 2627 break; 2628 } 2629 case DHCPV6_DUID_LL: { 2630 duid_ll_t ll; 2631 2632 lladdr = _link_aton(ptr, &addrlen); 2633 if (lladdr == NULL) 2634 return (DLADM_STATUS_BADARG); 2635 2636 cidlen = sizeof (ll) + addrlen; 2637 if (cidlen > sizeof (cid->dc_id)) { 2638 free(lladdr); 2639 return (DLADM_STATUS_TOOSMALL); 2640 } 2641 ll.dll_dutype = htons(duidtype); 2642 ll.dll_hwtype = htons(subtype); 2643 bcopy(&ll, cid->dc_id, sizeof (ll)); 2644 bcopy(lladdr, cid->dc_id + sizeof (ll), addrlen); 2645 free(lladdr); 2646 break; 2647 } 2648 default: { 2649 hexlen = sizeof (tmp_buf); 2650 if (hexascii_to_octet(ptr, strlen(ptr), 2651 tmp_buf, &hexlen) != 0) 2652 return (DLADM_STATUS_BADARG); 2653 2654 if (duidtype == DHCPV6_DUID_EN) { 2655 duid_en_t en; 2656 2657 en.den_dutype = htons(duidtype); 2658 DHCPV6_SET_ENTNUM(&en, subtype); 2659 2660 cidlen = sizeof (en) + hexlen; 2661 if (cidlen > sizeof (cid->dc_id)) 2662 return (DLADM_STATUS_TOOSMALL); 2663 2664 bcopy(&en, cid->dc_id, sizeof (en)); 2665 bcopy(tmp_buf, cid->dc_id + sizeof (en), 2666 hexlen); 2667 } else { 2668 uint16_t dutype = htons(duidtype); 2669 2670 cidlen = sizeof (dutype) + hexlen; 2671 if (cidlen > sizeof (cid->dc_id)) 2672 return (DLADM_STATUS_TOOSMALL); 2673 2674 bcopy(&dutype, cid->dc_id, sizeof (dutype)); 2675 bcopy(tmp_buf, cid->dc_id + sizeof (dutype), 2676 hexlen); 2677 } 2678 break; 2679 } 2680 } 2681 cid->dc_form = CIDFORM_TYPED; 2682 } else if (strncasecmp("0x", ptr, 2) == 0 && ptr[2] != '\0') { 2683 ptr += 2; 2684 hexlen = sizeof (tmp_buf); 2685 if (hexascii_to_octet(ptr, strlen(ptr), tmp_buf, 2686 &hexlen) != 0) { 2687 return (DLADM_STATUS_BADARG); 2688 } 2689 cidlen = hexlen; 2690 if (cidlen > sizeof (cid->dc_id)) 2691 return (DLADM_STATUS_TOOSMALL); 2692 2693 bcopy(tmp_buf, cid->dc_id, cidlen); 2694 cid->dc_form = CIDFORM_HEX; 2695 } else { 2696 cidlen = strlen(ptr); 2697 if (cidlen > sizeof (cid->dc_id)) 2698 return (DLADM_STATUS_TOOSMALL); 2699 2700 bcopy(ptr, cid->dc_id, cidlen); 2701 cid->dc_form = CIDFORM_STR; 2702 } 2703 cid->dc_len = cidlen; 2704 return (DLADM_STATUS_OK); 2705 } 2706 2707 /* ARGSUSED */ 2708 static dladm_status_t 2709 get_allowedcids(dladm_handle_t handle, prop_desc_t *pdp, 2710 datalink_id_t linkid, char **prop_val, uint_t *val_cnt, 2711 datalink_media_t media, uint_t flags, uint_t *perm_flags) 2712 { 2713 mac_resource_props_t mrp; 2714 mac_protect_t *p; 2715 dladm_status_t status; 2716 int i; 2717 2718 status = i_dladm_get_public_prop(handle, linkid, "resource", flags, 2719 perm_flags, &mrp, sizeof (mrp)); 2720 if (status != DLADM_STATUS_OK) 2721 return (status); 2722 2723 p = &mrp.mrp_protect; 2724 if (p->mp_cidcnt == 0) { 2725 *val_cnt = 0; 2726 return (DLADM_STATUS_OK); 2727 } 2728 if (p->mp_cidcnt > *val_cnt) 2729 return (DLADM_STATUS_BADVALCNT); 2730 2731 for (i = 0; i < p->mp_cidcnt; i++) { 2732 mac_dhcpcid_t *cid = &p->mp_cids[i]; 2733 2734 dladm_cid2str(cid, prop_val[i]); 2735 } 2736 *val_cnt = p->mp_cidcnt; 2737 return (DLADM_STATUS_OK); 2738 } 2739 2740 dladm_status_t 2741 extract_allowedcids(val_desc_t *vdp, uint_t cnt, void *arg) 2742 { 2743 mac_resource_props_t *mrp = arg; 2744 mac_protect_t *p = &mrp->mrp_protect; 2745 int i; 2746 2747 if (vdp->vd_val == 0) { 2748 cnt = (uint_t)-1; 2749 } else { 2750 for (i = 0; i < cnt; i++) { 2751 bcopy((void *)vdp[i].vd_val, &p->mp_cids[i], 2752 sizeof (mac_dhcpcid_t)); 2753 } 2754 } 2755 p->mp_cidcnt = cnt; 2756 mrp->mrp_mask |= MRP_PROTECT; 2757 return (DLADM_STATUS_OK); 2758 } 2759 2760 /* ARGSUSED */ 2761 static dladm_status_t 2762 check_allowedcids(dladm_handle_t handle, prop_desc_t *pdp, 2763 datalink_id_t linkid, char **prop_val, uint_t *val_cntp, 2764 uint_t flags, val_desc_t **vdpp, datalink_media_t media) 2765 { 2766 dladm_status_t status; 2767 mac_dhcpcid_t *cid; 2768 int i; 2769 uint_t val_cnt = *val_cntp; 2770 val_desc_t *vdp = *vdpp; 2771 2772 if (val_cnt > MPT_MAXCID) 2773 return (DLADM_STATUS_BADVALCNT); 2774 2775 for (i = 0; i < val_cnt; i++) { 2776 if ((cid = calloc(1, sizeof (mac_dhcpcid_t))) == NULL) { 2777 status = DLADM_STATUS_NOMEM; 2778 goto fail; 2779 } 2780 vdp[i].vd_val = (uintptr_t)cid; 2781 2782 status = dladm_str2cid(prop_val[i], cid); 2783 if (status != DLADM_STATUS_OK) 2784 goto fail; 2785 } 2786 return (DLADM_STATUS_OK); 2787 2788 fail: 2789 for (i = 0; i < val_cnt; i++) { 2790 free((void *)vdp[i].vd_val); 2791 vdp[i].vd_val = NULL; 2792 } 2793 return (status); 2794 } 2795 2796 /* ARGSUSED */ 2797 static dladm_status_t 2798 get_autopush(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid, 2799 char **prop_val, uint_t *val_cnt, datalink_media_t media, 2800 uint_t flags, uint_t *perm_flags) 2801 { 2802 struct dlautopush dlap; 2803 int i, len; 2804 dladm_status_t status; 2805 2806 if (flags & DLD_PROP_DEFAULT) 2807 return (DLADM_STATUS_NOTDEFINED); 2808 2809 status = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags, 2810 perm_flags, &dlap, sizeof (dlap)); 2811 if (status != DLADM_STATUS_OK) 2812 return (status); 2813 2814 if (dlap.dap_npush == 0) { 2815 *val_cnt = 0; 2816 return (DLADM_STATUS_OK); 2817 } 2818 for (i = 0, len = 0; i < dlap.dap_npush; i++) { 2819 if (i != 0) { 2820 (void) snprintf(*prop_val + len, 2821 DLADM_PROP_VAL_MAX - len, "%c", AP_DELIMITER); 2822 len += 1; 2823 } 2824 (void) snprintf(*prop_val + len, DLADM_PROP_VAL_MAX - len, 2825 "%s", dlap.dap_aplist[i]); 2826 len += strlen(dlap.dap_aplist[i]); 2827 if (dlap.dap_anchor - 1 == i) { 2828 (void) snprintf(*prop_val + len, 2829 DLADM_PROP_VAL_MAX - len, "%c%s", AP_DELIMITER, 2830 AP_ANCHOR); 2831 len += (strlen(AP_ANCHOR) + 1); 2832 } 2833 } 2834 *val_cnt = 1; 2835 return (DLADM_STATUS_OK); 2836 } 2837 2838 /* 2839 * Add the specified module to the dlautopush structure; returns a 2840 * DLADM_STATUS_* code. 2841 */ 2842 dladm_status_t 2843 i_dladm_add_ap_module(const char *module, struct dlautopush *dlap) 2844 { 2845 if ((strlen(module) == 0) || (strlen(module) > FMNAMESZ)) 2846 return (DLADM_STATUS_BADVAL); 2847 2848 if (strncasecmp(module, AP_ANCHOR, strlen(AP_ANCHOR)) == 0) { 2849 /* 2850 * We don't allow multiple anchors, and the anchor must 2851 * be after at least one module. 2852 */ 2853 if (dlap->dap_anchor != 0) 2854 return (DLADM_STATUS_BADVAL); 2855 if (dlap->dap_npush == 0) 2856 return (DLADM_STATUS_BADVAL); 2857 2858 dlap->dap_anchor = dlap->dap_npush; 2859 return (DLADM_STATUS_OK); 2860 } 2861 if (dlap->dap_npush >= MAXAPUSH) 2862 return (DLADM_STATUS_BADVALCNT); 2863 2864 (void) strlcpy(dlap->dap_aplist[dlap->dap_npush++], module, 2865 FMNAMESZ + 1); 2866 2867 return (DLADM_STATUS_OK); 2868 } 2869 2870 /* 2871 * Currently, both '.' and ' '(space) can be used as the delimiters between 2872 * autopush modules. The former is used in dladm set-linkprop, and the 2873 * latter is used in the autopush(1M) file. 2874 */ 2875 /* ARGSUSED */ 2876 static dladm_status_t 2877 check_autopush(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid, 2878 char **prop_val, uint_t *val_cntp, uint_t flags, val_desc_t **vdpp, 2879 datalink_media_t media) 2880 { 2881 char *module; 2882 struct dlautopush *dlap; 2883 dladm_status_t status; 2884 char val[DLADM_PROP_VAL_MAX]; 2885 char delimiters[4]; 2886 uint_t val_cnt = *val_cntp; 2887 val_desc_t *vdp = *vdpp; 2888 2889 if (val_cnt != 1) 2890 return (DLADM_STATUS_BADVALCNT); 2891 2892 if (prop_val != NULL) { 2893 dlap = malloc(sizeof (struct dlautopush)); 2894 if (dlap == NULL) 2895 return (DLADM_STATUS_NOMEM); 2896 2897 (void) memset(dlap, 0, sizeof (struct dlautopush)); 2898 (void) snprintf(delimiters, 4, " %c\n", AP_DELIMITER); 2899 bcopy(*prop_val, val, DLADM_PROP_VAL_MAX); 2900 module = strtok(val, delimiters); 2901 while (module != NULL) { 2902 status = i_dladm_add_ap_module(module, dlap); 2903 if (status != DLADM_STATUS_OK) 2904 return (status); 2905 module = strtok(NULL, delimiters); 2906 } 2907 2908 vdp->vd_val = (uintptr_t)dlap; 2909 } else { 2910 vdp->vd_val = 0; 2911 } 2912 return (DLADM_STATUS_OK); 2913 } 2914 2915 #define WLDP_BUFSIZE (MAX_BUF_LEN - WIFI_BUF_OFFSET) 2916 2917 /* ARGSUSED */ 2918 static dladm_status_t 2919 get_rate_common(dladm_handle_t handle, prop_desc_t *pdp, 2920 datalink_id_t linkid, char **prop_val, uint_t *val_cnt, uint_t id, 2921 uint_t *perm_flags) 2922 { 2923 wl_rates_t *wrp; 2924 uint_t i; 2925 dladm_status_t status = DLADM_STATUS_OK; 2926 2927 wrp = malloc(WLDP_BUFSIZE); 2928 if (wrp == NULL) 2929 return (DLADM_STATUS_NOMEM); 2930 2931 status = i_dladm_wlan_param(handle, linkid, wrp, id, WLDP_BUFSIZE, 2932 B_FALSE); 2933 if (status != DLADM_STATUS_OK) 2934 goto done; 2935 2936 if (wrp->wl_rates_num > *val_cnt) { 2937 status = DLADM_STATUS_TOOSMALL; 2938 goto done; 2939 } 2940 2941 if (wrp->wl_rates_rates[0] == 0) { 2942 prop_val[0][0] = '\0'; 2943 *val_cnt = 1; 2944 goto done; 2945 } 2946 2947 for (i = 0; i < wrp->wl_rates_num; i++) { 2948 (void) snprintf(prop_val[i], DLADM_STRSIZE, "%.*f", 2949 wrp->wl_rates_rates[i] % 2, 2950 (float)wrp->wl_rates_rates[i] / 2); 2951 } 2952 *val_cnt = wrp->wl_rates_num; 2953 *perm_flags = MAC_PROP_PERM_RW; 2954 2955 done: 2956 free(wrp); 2957 return (status); 2958 } 2959 2960 static dladm_status_t 2961 get_rate(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid, 2962 char **prop_val, uint_t *val_cnt, datalink_media_t media, 2963 uint_t flags, uint_t *perm_flags) 2964 { 2965 if (media != DL_WIFI) { 2966 return (get_speed(handle, pdp, linkid, prop_val, 2967 val_cnt, media, flags, perm_flags)); 2968 } 2969 2970 return (get_rate_common(handle, pdp, linkid, prop_val, val_cnt, 2971 MAC_PROP_WL_DESIRED_RATES, perm_flags)); 2972 } 2973 2974 /* ARGSUSED */ 2975 static dladm_status_t 2976 get_rate_mod(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid, 2977 char **prop_val, uint_t *val_cnt, datalink_media_t media, 2978 uint_t flags, uint_t *perm_flags) 2979 { 2980 switch (media) { 2981 case DL_ETHER: 2982 /* 2983 * Speed for ethernet links is unbounded. E.g., 802.11b 2984 * links can have a speed of 5.5 Gbps. 2985 */ 2986 return (DLADM_STATUS_NOTSUP); 2987 2988 case DL_WIFI: 2989 return (get_rate_common(handle, pdp, linkid, prop_val, 2990 val_cnt, MAC_PROP_WL_SUPPORTED_RATES, perm_flags)); 2991 default: 2992 return (DLADM_STATUS_BADARG); 2993 } 2994 } 2995 2996 static dladm_status_t 2997 set_wlan_rate(dladm_handle_t handle, datalink_id_t linkid, 2998 dladm_wlan_rates_t *rates) 2999 { 3000 int i; 3001 uint_t len; 3002 wl_rates_t *wrp; 3003 dladm_status_t status = DLADM_STATUS_OK; 3004 3005 wrp = malloc(WLDP_BUFSIZE); 3006 if (wrp == NULL) 3007 return (DLADM_STATUS_NOMEM); 3008 3009 bzero(wrp, WLDP_BUFSIZE); 3010 for (i = 0; i < rates->wr_cnt; i++) 3011 wrp->wl_rates_rates[i] = rates->wr_rates[i]; 3012 wrp->wl_rates_num = rates->wr_cnt; 3013 3014 len = offsetof(wl_rates_t, wl_rates_rates) + 3015 (rates->wr_cnt * sizeof (char)) + WIFI_BUF_OFFSET; 3016 status = i_dladm_wlan_param(handle, linkid, wrp, 3017 MAC_PROP_WL_DESIRED_RATES, len, B_TRUE); 3018 3019 free(wrp); 3020 return (status); 3021 } 3022 3023 /* ARGSUSED */ 3024 static dladm_status_t 3025 set_rate(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid, 3026 val_desc_t *vdp, uint_t val_cnt, uint_t flags, datalink_media_t media) 3027 { 3028 dladm_wlan_rates_t rates; 3029 dladm_status_t status; 3030 3031 /* 3032 * can currently set rate on WIFI links only. 3033 */ 3034 if (media != DL_WIFI) 3035 return (DLADM_STATUS_PROPRDONLY); 3036 3037 if (val_cnt != 1) 3038 return (DLADM_STATUS_BADVALCNT); 3039 3040 rates.wr_cnt = 1; 3041 rates.wr_rates[0] = vdp[0].vd_val; 3042 3043 status = set_wlan_rate(handle, linkid, &rates); 3044 3045 return (status); 3046 } 3047 3048 /* ARGSUSED */ 3049 static dladm_status_t 3050 check_rate(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid, 3051 char **prop_val, uint_t *val_cntp, uint_t flags, val_desc_t **vdpp, 3052 datalink_media_t media) 3053 { 3054 int i; 3055 uint_t modval_cnt = MAX_SUPPORT_RATES; 3056 char *buf, **modval; 3057 dladm_status_t status; 3058 uint_t perm_flags; 3059 uint_t val_cnt = *val_cntp; 3060 val_desc_t *vdp = *vdpp; 3061 3062 if (val_cnt != 1) 3063 return (DLADM_STATUS_BADVALCNT); 3064 3065 buf = malloc((sizeof (char *) + DLADM_STRSIZE) * 3066 MAX_SUPPORT_RATES); 3067 if (buf == NULL) { 3068 status = DLADM_STATUS_NOMEM; 3069 goto done; 3070 } 3071 3072 modval = (char **)(void *)buf; 3073 for (i = 0; i < MAX_SUPPORT_RATES; i++) { 3074 modval[i] = buf + sizeof (char *) * MAX_SUPPORT_RATES + 3075 i * DLADM_STRSIZE; 3076 } 3077 3078 status = get_rate_mod(handle, NULL, linkid, modval, &modval_cnt, 3079 media, 0, &perm_flags); 3080 if (status != DLADM_STATUS_OK) 3081 goto done; 3082 3083 for (i = 0; i < modval_cnt; i++) { 3084 if (strcasecmp(*prop_val, modval[i]) == 0) { 3085 vdp->vd_val = (uintptr_t)(uint_t) 3086 (atof(*prop_val) * 2); 3087 status = DLADM_STATUS_OK; 3088 break; 3089 } 3090 } 3091 if (i == modval_cnt) 3092 status = DLADM_STATUS_BADVAL; 3093 done: 3094 free(buf); 3095 return (status); 3096 } 3097 3098 static dladm_status_t 3099 get_phyconf(dladm_handle_t handle, datalink_id_t linkid, void *buf, 3100 int buflen) 3101 { 3102 return (i_dladm_wlan_param(handle, linkid, buf, MAC_PROP_WL_PHY_CONFIG, 3103 buflen, B_FALSE)); 3104 } 3105 3106 /* ARGSUSED */ 3107 static dladm_status_t 3108 get_channel(dladm_handle_t handle, prop_desc_t *pdp, 3109 datalink_id_t linkid, char **prop_val, uint_t *val_cnt, 3110 datalink_media_t media, uint_t flags, uint_t *perm_flags) 3111 { 3112 uint32_t channel; 3113 char buf[WLDP_BUFSIZE]; 3114 dladm_status_t status; 3115 wl_phy_conf_t wl_phy_conf; 3116 3117 if ((status = get_phyconf(handle, linkid, buf, sizeof (buf))) 3118 != DLADM_STATUS_OK) 3119 return (status); 3120 3121 (void) memcpy(&wl_phy_conf, buf, sizeof (wl_phy_conf)); 3122 if (!i_dladm_wlan_convert_chan(&wl_phy_conf, &channel)) 3123 return (DLADM_STATUS_NOTFOUND); 3124 3125 (void) snprintf(*prop_val, DLADM_STRSIZE, "%u", channel); 3126 *val_cnt = 1; 3127 *perm_flags = MAC_PROP_PERM_READ; 3128 return (DLADM_STATUS_OK); 3129 } 3130 3131 /* ARGSUSED */ 3132 static dladm_status_t 3133 get_powermode(dladm_handle_t handle, prop_desc_t *pdp, 3134 datalink_id_t linkid, char **prop_val, uint_t *val_cnt, 3135 datalink_media_t media, uint_t flags, uint_t *perm_flags) 3136 { 3137 wl_ps_mode_t mode; 3138 const char *s; 3139 char buf[WLDP_BUFSIZE]; 3140 dladm_status_t status; 3141 3142 if ((status = i_dladm_wlan_param(handle, linkid, buf, 3143 MAC_PROP_WL_POWER_MODE, sizeof (buf), B_FALSE)) != DLADM_STATUS_OK) 3144 return (status); 3145 3146 (void) memcpy(&mode, buf, sizeof (mode)); 3147 switch (mode.wl_ps_mode) { 3148 case WL_PM_AM: 3149 s = "off"; 3150 break; 3151 case WL_PM_MPS: 3152 s = "max"; 3153 break; 3154 case WL_PM_FAST: 3155 s = "fast"; 3156 break; 3157 default: 3158 return (DLADM_STATUS_NOTFOUND); 3159 } 3160 (void) snprintf(*prop_val, DLADM_STRSIZE, "%s", s); 3161 *val_cnt = 1; 3162 *perm_flags = MAC_PROP_PERM_RW; 3163 return (DLADM_STATUS_OK); 3164 } 3165 3166 /* ARGSUSED */ 3167 static dladm_status_t 3168 set_powermode(dladm_handle_t handle, prop_desc_t *pdp, 3169 datalink_id_t linkid, val_desc_t *vdp, uint_t val_cnt, uint_t flags, 3170 datalink_media_t media) 3171 { 3172 dladm_wlan_powermode_t powermode = vdp->vd_val; 3173 wl_ps_mode_t ps_mode; 3174 3175 if (val_cnt != 1) 3176 return (DLADM_STATUS_BADVALCNT); 3177 3178 (void) memset(&ps_mode, 0xff, sizeof (ps_mode)); 3179 3180 switch (powermode) { 3181 case DLADM_WLAN_PM_OFF: 3182 ps_mode.wl_ps_mode = WL_PM_AM; 3183 break; 3184 case DLADM_WLAN_PM_MAX: 3185 ps_mode.wl_ps_mode = WL_PM_MPS; 3186 break; 3187 case DLADM_WLAN_PM_FAST: 3188 ps_mode.wl_ps_mode = WL_PM_FAST; 3189 break; 3190 default: 3191 return (DLADM_STATUS_NOTSUP); 3192 } 3193 return (i_dladm_wlan_param(handle, linkid, &ps_mode, 3194 MAC_PROP_WL_POWER_MODE, sizeof (ps_mode), B_TRUE)); 3195 } 3196 3197 /* ARGSUSED */ 3198 static dladm_status_t 3199 get_radio(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid, 3200 char **prop_val, uint_t *val_cnt, datalink_media_t media, 3201 uint_t flags, uint_t *perm_flags) 3202 { 3203 wl_radio_t radio; 3204 const char *s; 3205 char buf[WLDP_BUFSIZE]; 3206 dladm_status_t status; 3207 3208 if ((status = i_dladm_wlan_param(handle, linkid, buf, 3209 MAC_PROP_WL_RADIO, sizeof (buf), B_FALSE)) != DLADM_STATUS_OK) 3210 return (status); 3211 3212 (void) memcpy(&radio, buf, sizeof (radio)); 3213 switch (radio) { 3214 case B_TRUE: 3215 s = "on"; 3216 break; 3217 case B_FALSE: 3218 s = "off"; 3219 break; 3220 default: 3221 return (DLADM_STATUS_NOTFOUND); 3222 } 3223 (void) snprintf(*prop_val, DLADM_STRSIZE, "%s", s); 3224 *val_cnt = 1; 3225 *perm_flags = MAC_PROP_PERM_RW; 3226 return (DLADM_STATUS_OK); 3227 } 3228 3229 /* ARGSUSED */ 3230 static dladm_status_t 3231 set_radio(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid, 3232 val_desc_t *vdp, uint_t val_cnt, uint_t flags, datalink_media_t media) 3233 { 3234 dladm_wlan_radio_t radio = vdp->vd_val; 3235 wl_radio_t r; 3236 3237 if (val_cnt != 1) 3238 return (DLADM_STATUS_BADVALCNT); 3239 3240 switch (radio) { 3241 case DLADM_WLAN_RADIO_ON: 3242 r = B_TRUE; 3243 break; 3244 case DLADM_WLAN_RADIO_OFF: 3245 r = B_FALSE; 3246 break; 3247 default: 3248 return (DLADM_STATUS_NOTSUP); 3249 } 3250 return (i_dladm_wlan_param(handle, linkid, &r, MAC_PROP_WL_RADIO, 3251 sizeof (r), B_TRUE)); 3252 } 3253 3254 /* ARGSUSED */ 3255 static dladm_status_t 3256 check_hoplimit(dladm_handle_t handle, prop_desc_t *pdp, 3257 datalink_id_t linkid, char **prop_val, uint_t *val_cntp, uint_t flags, 3258 val_desc_t **vdpp, datalink_media_t media) 3259 { 3260 int32_t hlim; 3261 char *ep; 3262 uint_t val_cnt = *val_cntp; 3263 val_desc_t *vdp = *vdpp; 3264 3265 if (val_cnt != 1) 3266 return (DLADM_STATUS_BADVALCNT); 3267 3268 errno = 0; 3269 hlim = strtol(*prop_val, &ep, 10); 3270 if (errno != 0 || ep == *prop_val || hlim < 1 || 3271 hlim > (int32_t)UINT8_MAX) 3272 return (DLADM_STATUS_BADVAL); 3273 vdp->vd_val = hlim; 3274 return (DLADM_STATUS_OK); 3275 } 3276 3277 /* ARGSUSED */ 3278 static dladm_status_t 3279 check_encaplim(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid, 3280 char **prop_val, uint_t *val_cntp, uint_t flags, val_desc_t **vdpp, 3281 datalink_media_t media) 3282 { 3283 int32_t elim; 3284 char *ep; 3285 uint_t val_cnt = *val_cntp; 3286 val_desc_t *vdp = *vdpp; 3287 3288 if (media != DL_IPV6) 3289 return (DLADM_STATUS_BADARG); 3290 3291 if (val_cnt != 1) 3292 return (DLADM_STATUS_BADVALCNT); 3293 3294 errno = 0; 3295 elim = strtol(*prop_val, &ep, 10); 3296 if (errno != 0 || ep == *prop_val || elim < 0 || 3297 elim > (int32_t)UINT8_MAX) 3298 return (DLADM_STATUS_BADVAL); 3299 vdp->vd_val = elim; 3300 return (DLADM_STATUS_OK); 3301 } 3302 3303 static dladm_status_t 3304 i_dladm_set_linkprop_db(dladm_handle_t handle, datalink_id_t linkid, 3305 const char *prop_name, char **prop_val, uint_t val_cnt) 3306 { 3307 char buf[MAXLINELEN]; 3308 int i; 3309 dladm_conf_t conf; 3310 dladm_status_t status; 3311 3312 status = dladm_read_conf(handle, linkid, &conf); 3313 if (status != DLADM_STATUS_OK) 3314 return (status); 3315 3316 /* 3317 * reset case. 3318 */ 3319 if (val_cnt == 0) { 3320 status = dladm_unset_conf_field(handle, conf, prop_name); 3321 if (status == DLADM_STATUS_OK) 3322 status = dladm_write_conf(handle, conf); 3323 goto done; 3324 } 3325 3326 buf[0] = '\0'; 3327 for (i = 0; i < val_cnt; i++) { 3328 (void) strlcat(buf, prop_val[i], MAXLINELEN); 3329 if (i != val_cnt - 1) 3330 (void) strlcat(buf, ",", MAXLINELEN); 3331 } 3332 3333 status = dladm_set_conf_field(handle, conf, prop_name, DLADM_TYPE_STR, 3334 buf); 3335 if (status == DLADM_STATUS_OK) 3336 status = dladm_write_conf(handle, conf); 3337 3338 done: 3339 dladm_destroy_conf(handle, conf); 3340 return (status); 3341 } 3342 3343 static dladm_status_t 3344 i_dladm_get_linkprop_db(dladm_handle_t handle, datalink_id_t linkid, 3345 const char *prop_name, char **prop_val, uint_t *val_cntp) 3346 { 3347 char buf[MAXLINELEN], *str; 3348 uint_t cnt = 0; 3349 dladm_conf_t conf; 3350 dladm_status_t status; 3351 3352 status = dladm_read_conf(handle, linkid, &conf); 3353 if (status != DLADM_STATUS_OK) 3354 return (status); 3355 3356 status = dladm_get_conf_field(handle, conf, prop_name, buf, MAXLINELEN); 3357 if (status != DLADM_STATUS_OK) 3358 goto done; 3359 3360 str = strtok(buf, ","); 3361 while (str != NULL) { 3362 if (cnt == *val_cntp) { 3363 status = DLADM_STATUS_TOOSMALL; 3364 goto done; 3365 } 3366 (void) strlcpy(prop_val[cnt++], str, DLADM_PROP_VAL_MAX); 3367 str = strtok(NULL, ","); 3368 } 3369 3370 *val_cntp = cnt; 3371 3372 done: 3373 dladm_destroy_conf(handle, conf); 3374 return (status); 3375 } 3376 3377 /* 3378 * Walk persistent private link properties of a link. 3379 */ 3380 static dladm_status_t 3381 i_dladm_walk_linkprop_priv_db(dladm_handle_t handle, datalink_id_t linkid, 3382 void *arg, int (*func)(dladm_handle_t, datalink_id_t, const char *, void *)) 3383 { 3384 dladm_status_t status; 3385 dladm_conf_t conf; 3386 char last_attr[MAXLINKATTRLEN]; 3387 char attr[MAXLINKATTRLEN]; 3388 char attrval[MAXLINKATTRVALLEN]; 3389 size_t attrsz; 3390 3391 if (linkid == DATALINK_INVALID_LINKID || func == NULL) 3392 return (DLADM_STATUS_BADARG); 3393 3394 status = dladm_read_conf(handle, linkid, &conf); 3395 if (status != DLADM_STATUS_OK) 3396 return (status); 3397 3398 last_attr[0] = '\0'; 3399 while ((status = dladm_getnext_conf_linkprop(handle, conf, last_attr, 3400 attr, attrval, MAXLINKATTRVALLEN, &attrsz)) == DLADM_STATUS_OK) { 3401 if (attr[0] == '_') { 3402 if (func(handle, linkid, attr, arg) == 3403 DLADM_WALK_TERMINATE) 3404 break; 3405 } 3406 (void) strlcpy(last_attr, attr, MAXLINKATTRLEN); 3407 } 3408 3409 dladm_destroy_conf(handle, conf); 3410 return (DLADM_STATUS_OK); 3411 } 3412 3413 static link_attr_t * 3414 dladm_name2prop(const char *prop_name) 3415 { 3416 link_attr_t *p; 3417 3418 for (p = link_attr; p->pp_id != MAC_PROP_PRIVATE; p++) { 3419 if (strcmp(p->pp_name, prop_name) == 0) 3420 break; 3421 } 3422 return (p); 3423 } 3424 3425 static link_attr_t * 3426 dladm_id2prop(mac_prop_id_t propid) 3427 { 3428 link_attr_t *p; 3429 3430 for (p = link_attr; p->pp_id != MAC_PROP_PRIVATE; p++) { 3431 if (p->pp_id == propid) 3432 break; 3433 } 3434 return (p); 3435 } 3436 3437 static dld_ioc_macprop_t * 3438 i_dladm_buf_alloc_impl(size_t valsize, datalink_id_t linkid, 3439 const char *prop_name, mac_prop_id_t propid, uint_t flags, 3440 dladm_status_t *status) 3441 { 3442 int dsize; 3443 dld_ioc_macprop_t *dip; 3444 3445 *status = DLADM_STATUS_OK; 3446 dsize = MAC_PROP_BUFSIZE(valsize); 3447 dip = malloc(dsize); 3448 if (dip == NULL) { 3449 *status = DLADM_STATUS_NOMEM; 3450 return (NULL); 3451 } 3452 bzero(dip, dsize); 3453 dip->pr_valsize = valsize; 3454 (void) strlcpy(dip->pr_name, prop_name, sizeof (dip->pr_name)); 3455 dip->pr_linkid = linkid; 3456 dip->pr_num = propid; 3457 dip->pr_flags = flags; 3458 return (dip); 3459 } 3460 3461 static dld_ioc_macprop_t * 3462 i_dladm_buf_alloc_by_name(size_t valsize, datalink_id_t linkid, 3463 const char *prop_name, uint_t flags, dladm_status_t *status) 3464 { 3465 link_attr_t *p; 3466 3467 p = dladm_name2prop(prop_name); 3468 valsize = MAX(p->pp_valsize, valsize); 3469 return (i_dladm_buf_alloc_impl(valsize, linkid, prop_name, p->pp_id, 3470 flags, status)); 3471 } 3472 3473 static dld_ioc_macprop_t * 3474 i_dladm_buf_alloc_by_id(size_t valsize, datalink_id_t linkid, 3475 mac_prop_id_t propid, uint_t flags, dladm_status_t *status) 3476 { 3477 link_attr_t *p; 3478 3479 p = dladm_id2prop(propid); 3480 valsize = MAX(p->pp_valsize, valsize); 3481 return (i_dladm_buf_alloc_impl(valsize, linkid, p->pp_name, propid, 3482 flags, status)); 3483 } 3484 3485 /* ARGSUSED */ 3486 static dladm_status_t 3487 set_public_prop(dladm_handle_t handle, prop_desc_t *pdp, 3488 datalink_id_t linkid, val_desc_t *vdp, uint_t val_cnt, uint_t flags, 3489 datalink_media_t media) 3490 { 3491 dld_ioc_macprop_t *dip; 3492 dladm_status_t status = DLADM_STATUS_OK; 3493 uint8_t u8; 3494 uint16_t u16; 3495 uint32_t u32; 3496 void *val; 3497 3498 dip = i_dladm_buf_alloc_by_name(0, linkid, pdp->pd_name, 0, &status); 3499 if (dip == NULL) 3500 return (status); 3501 3502 if (pdp->pd_flags & PD_CHECK_ALLOC) 3503 val = (void *)vdp->vd_val; 3504 else { 3505 /* 3506 * Currently all 1/2/4-byte size properties are byte/word/int. 3507 * No need (yet) to distinguish these from arrays of same size. 3508 */ 3509 switch (dip->pr_valsize) { 3510 case 1: 3511 u8 = vdp->vd_val; 3512 val = &u8; 3513 break; 3514 case 2: 3515 u16 = vdp->vd_val; 3516 val = &u16; 3517 break; 3518 case 4: 3519 u32 = vdp->vd_val; 3520 val = &u32; 3521 break; 3522 default: 3523 val = &vdp->vd_val; 3524 break; 3525 } 3526 } 3527 3528 if (val != NULL) 3529 (void) memcpy(dip->pr_val, val, dip->pr_valsize); 3530 else 3531 dip->pr_valsize = 0; 3532 3533 status = i_dladm_macprop(handle, dip, B_TRUE); 3534 3535 done: 3536 free(dip); 3537 return (status); 3538 } 3539 3540 dladm_status_t 3541 i_dladm_macprop(dladm_handle_t handle, void *dip, boolean_t set) 3542 { 3543 dladm_status_t status = DLADM_STATUS_OK; 3544 3545 if (ioctl(dladm_dld_fd(handle), 3546 (set ? DLDIOC_SETMACPROP : DLDIOC_GETMACPROP), dip)) 3547 status = dladm_errno2status(errno); 3548 3549 return (status); 3550 } 3551 3552 static dladm_status_t 3553 i_dladm_get_public_prop(dladm_handle_t handle, datalink_id_t linkid, 3554 char *prop_name, uint_t flags, uint_t *perm_flags, void *arg, size_t size) 3555 { 3556 dld_ioc_macprop_t *dip; 3557 dladm_status_t status; 3558 3559 dip = i_dladm_buf_alloc_by_name(0, linkid, prop_name, flags, &status); 3560 if (dip == NULL) 3561 return (DLADM_STATUS_NOMEM); 3562 3563 status = i_dladm_macprop(handle, dip, B_FALSE); 3564 if (status != DLADM_STATUS_OK) { 3565 free(dip); 3566 return (status); 3567 } 3568 3569 if (perm_flags != NULL) 3570 *perm_flags = dip->pr_perm_flags; 3571 3572 if (arg != NULL) 3573 (void) memcpy(arg, dip->pr_val, size); 3574 free(dip); 3575 return (DLADM_STATUS_OK); 3576 } 3577 3578 /* ARGSUSED */ 3579 static dladm_status_t 3580 check_uint32(dladm_handle_t handle, prop_desc_t *pdp, 3581 datalink_id_t linkid, char **prop_val, uint_t *val_cntp, uint_t flags, 3582 val_desc_t **vp, datalink_media_t media) 3583 { 3584 uint_t val_cnt = *val_cntp; 3585 val_desc_t *v = *vp; 3586 3587 if (val_cnt != 1) 3588 return (DLADM_STATUS_BADVAL); 3589 v->vd_val = strtoul(prop_val[0], NULL, 0); 3590 return (DLADM_STATUS_OK); 3591 } 3592 3593 /* ARGSUSED */ 3594 static dladm_status_t 3595 get_duplex(dladm_handle_t handle, prop_desc_t *pdp, 3596 datalink_id_t linkid, char **prop_val, uint_t *val_cnt, 3597 datalink_media_t media, uint_t flags, uint_t *perm_flags) 3598 { 3599 link_duplex_t link_duplex; 3600 dladm_status_t status; 3601 3602 if ((status = dladm_get_single_mac_stat(handle, linkid, "link_duplex", 3603 KSTAT_DATA_UINT32, &link_duplex)) != 0) 3604 return (status); 3605 3606 switch (link_duplex) { 3607 case LINK_DUPLEX_FULL: 3608 (void) strcpy(*prop_val, "full"); 3609 break; 3610 case LINK_DUPLEX_HALF: 3611 (void) strcpy(*prop_val, "half"); 3612 break; 3613 default: 3614 (void) strcpy(*prop_val, "unknown"); 3615 break; 3616 } 3617 *val_cnt = 1; 3618 return (DLADM_STATUS_OK); 3619 } 3620 3621 /* ARGSUSED */ 3622 static dladm_status_t 3623 get_speed(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid, 3624 char **prop_val, uint_t *val_cnt, datalink_media_t media, uint_t flags, 3625 uint_t *perm_flags) 3626 { 3627 uint64_t ifspeed = 0; 3628 dladm_status_t status; 3629 3630 if ((status = dladm_get_single_mac_stat(handle, linkid, "ifspeed", 3631 KSTAT_DATA_UINT64, &ifspeed)) != 0) 3632 return (status); 3633 3634 if ((ifspeed % 1000000) != 0) { 3635 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, 3636 "%llf", ifspeed / (float)1000000); /* Mbps */ 3637 } else { 3638 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, 3639 "%llu", ifspeed / 1000000); /* Mbps */ 3640 } 3641 *val_cnt = 1; 3642 *perm_flags = MAC_PROP_PERM_READ; 3643 return (DLADM_STATUS_OK); 3644 } 3645 3646 /* ARGSUSED */ 3647 static dladm_status_t 3648 get_link_state(dladm_handle_t handle, prop_desc_t *pdp, 3649 datalink_id_t linkid, char **prop_val, uint_t *val_cnt, 3650 datalink_media_t media, uint_t flags, uint_t *perm_flags) 3651 { 3652 link_state_t link_state; 3653 dladm_status_t status; 3654 3655 status = dladm_get_state(handle, linkid, &link_state); 3656 if (status != DLADM_STATUS_OK) 3657 return (status); 3658 3659 switch (link_state) { 3660 case LINK_STATE_UP: 3661 (void) strcpy(*prop_val, "up"); 3662 break; 3663 case LINK_STATE_DOWN: 3664 (void) strcpy(*prop_val, "down"); 3665 break; 3666 default: 3667 (void) strcpy(*prop_val, "unknown"); 3668 break; 3669 } 3670 *val_cnt = 1; 3671 *perm_flags = MAC_PROP_PERM_READ; 3672 return (DLADM_STATUS_OK); 3673 } 3674 3675 /* ARGSUSED */ 3676 static dladm_status_t 3677 get_binary(dladm_handle_t handle, prop_desc_t *pdp, 3678 datalink_id_t linkid, char **prop_val, uint_t *val_cnt, 3679 datalink_media_t media, uint_t flags, uint_t *perm_flags) 3680 { 3681 dladm_status_t status; 3682 uint_t v = 0; 3683 3684 status = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags, 3685 perm_flags, &v, sizeof (v)); 3686 if (status != DLADM_STATUS_OK) 3687 return (status); 3688 3689 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "%d", (uint_t)(v > 0)); 3690 *val_cnt = 1; 3691 return (DLADM_STATUS_OK); 3692 } 3693 3694 /* ARGSUSED */ 3695 static dladm_status_t 3696 get_uint32(dladm_handle_t handle, prop_desc_t *pdp, 3697 datalink_id_t linkid, char **prop_val, uint_t *val_cnt, 3698 datalink_media_t media, uint_t flags, uint_t *perm_flags) 3699 { 3700 dladm_status_t status; 3701 uint32_t v = 0; 3702 3703 status = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags, 3704 perm_flags, &v, sizeof (v)); 3705 if (status != DLADM_STATUS_OK) 3706 return (status); 3707 3708 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "%ld", v); 3709 *val_cnt = 1; 3710 return (DLADM_STATUS_OK); 3711 } 3712 3713 /* ARGSUSED */ 3714 static dladm_status_t 3715 get_range(dladm_handle_t handle, prop_desc_t *pdp, 3716 datalink_id_t linkid, char **prop_val, uint_t *val_cnt, 3717 datalink_media_t media, uint_t flags, uint_t *perm_flags) 3718 { 3719 dld_ioc_macprop_t *dip; 3720 dladm_status_t status = DLADM_STATUS_OK; 3721 size_t sz; 3722 mac_propval_range_t *rangep; 3723 3724 sz = sizeof (mac_propval_range_t); 3725 3726 /* 3727 * As caller we don't know number of value ranges, the driver 3728 * supports. To begin with we assume that number to be 1. If the 3729 * buffer size is insufficient, driver returns back with the 3730 * actual count of value ranges. See mac.h for more details. 3731 */ 3732 retry: 3733 if ((dip = i_dladm_buf_alloc_by_name(sz, linkid, pdp->pd_name, flags, 3734 &status)) == NULL) 3735 return (status); 3736 3737 status = i_dladm_macprop(handle, dip, B_FALSE); 3738 if (status != DLADM_STATUS_OK) { 3739 if (status == DLADM_STATUS_TOOSMALL) { 3740 int err; 3741 3742 rangep = (mac_propval_range_t *)(void *)&dip->pr_val; 3743 if ((err = i_dladm_range_size(rangep, &sz)) == 0) { 3744 free(dip); 3745 goto retry; 3746 } else { 3747 status = dladm_errno2status(err); 3748 } 3749 } 3750 free(dip); 3751 return (status); 3752 } 3753 3754 rangep = (mac_propval_range_t *)(void *)&dip->pr_val; 3755 if (rangep->mpr_count == 0) { 3756 *val_cnt = 1; 3757 (void) snprintf(prop_val[0], DLADM_PROP_VAL_MAX, "--"); 3758 goto done; 3759 } 3760 3761 switch (rangep->mpr_type) { 3762 case MAC_PROPVAL_UINT32: { 3763 mac_propval_uint32_range_t *ur; 3764 uint_t count = rangep->mpr_count, i; 3765 3766 ur = &rangep->mpr_range_uint32[0]; 3767 3768 for (i = 0; i < count; i++, ur++) { 3769 if (ur->mpur_min == ur->mpur_max) { 3770 (void) snprintf(prop_val[i], DLADM_PROP_VAL_MAX, 3771 "%ld", ur->mpur_min); 3772 } else { 3773 (void) snprintf(prop_val[i], DLADM_PROP_VAL_MAX, 3774 "%ld-%ld", ur->mpur_min, ur->mpur_max); 3775 } 3776 } 3777 *val_cnt = count; 3778 break; 3779 } 3780 default: 3781 status = DLADM_STATUS_BADARG; 3782 break; 3783 } 3784 done: 3785 free(dip); 3786 return (status); 3787 } 3788 3789 /* ARGSUSED */ 3790 static dladm_status_t 3791 get_tagmode(dladm_handle_t handle, prop_desc_t *pdp, 3792 datalink_id_t linkid, char **prop_val, uint_t *val_cnt, 3793 datalink_media_t media, uint_t flags, uint_t *perm_flags) 3794 { 3795 link_tagmode_t mode; 3796 dladm_status_t status; 3797 3798 status = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags, 3799 perm_flags, &mode, sizeof (mode)); 3800 if (status != DLADM_STATUS_OK) 3801 return (status); 3802 3803 switch (mode) { 3804 case LINK_TAGMODE_NORMAL: 3805 (void) strlcpy(*prop_val, "normal", DLADM_PROP_VAL_MAX); 3806 break; 3807 case LINK_TAGMODE_VLANONLY: 3808 (void) strlcpy(*prop_val, "vlanonly", DLADM_PROP_VAL_MAX); 3809 break; 3810 default: 3811 (void) strlcpy(*prop_val, "unknown", DLADM_PROP_VAL_MAX); 3812 } 3813 *val_cnt = 1; 3814 return (DLADM_STATUS_OK); 3815 } 3816 3817 /* ARGSUSED */ 3818 static dladm_status_t 3819 get_flowctl(dladm_handle_t handle, prop_desc_t *pdp, 3820 datalink_id_t linkid, char **prop_val, uint_t *val_cnt, 3821 datalink_media_t media, uint_t flags, uint_t *perm_flags) 3822 { 3823 link_flowctrl_t v; 3824 dladm_status_t status; 3825 3826 status = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags, 3827 perm_flags, &v, sizeof (v)); 3828 if (status != DLADM_STATUS_OK) 3829 return (status); 3830 3831 switch (v) { 3832 case LINK_FLOWCTRL_NONE: 3833 (void) sprintf(*prop_val, "no"); 3834 break; 3835 case LINK_FLOWCTRL_RX: 3836 (void) sprintf(*prop_val, "rx"); 3837 break; 3838 case LINK_FLOWCTRL_TX: 3839 (void) sprintf(*prop_val, "tx"); 3840 break; 3841 case LINK_FLOWCTRL_BI: 3842 (void) sprintf(*prop_val, "bi"); 3843 break; 3844 } 3845 *val_cnt = 1; 3846 return (DLADM_STATUS_OK); 3847 } 3848 3849 3850 /* ARGSUSED */ 3851 static dladm_status_t 3852 i_dladm_set_private_prop(dladm_handle_t handle, datalink_id_t linkid, 3853 const char *prop_name, char **prop_val, uint_t val_cnt, uint_t flags) 3854 3855 { 3856 int i, slen; 3857 int bufsize = 0; 3858 dld_ioc_macprop_t *dip = NULL; 3859 uchar_t *dp; 3860 link_attr_t *p; 3861 dladm_status_t status = DLADM_STATUS_OK; 3862 3863 if ((prop_name == NULL && prop_val != NULL) || 3864 (prop_val != NULL && val_cnt == 0)) 3865 return (DLADM_STATUS_BADARG); 3866 p = dladm_name2prop(prop_name); 3867 if (p->pp_id != MAC_PROP_PRIVATE) 3868 return (DLADM_STATUS_BADARG); 3869 3870 if (!(flags & DLADM_OPT_ACTIVE)) 3871 return (DLADM_STATUS_OK); 3872 3873 /* 3874 * private properties: all parsing is done in the kernel. 3875 * allocate a enough space for each property + its separator (','). 3876 */ 3877 for (i = 0; i < val_cnt; i++) { 3878 bufsize += strlen(prop_val[i]) + 1; 3879 } 3880 3881 if (prop_val == NULL) { 3882 /* 3883 * getting default value. so use more buffer space. 3884 */ 3885 bufsize += DLADM_PROP_BUF_CHUNK; 3886 } 3887 3888 dip = i_dladm_buf_alloc_by_name(bufsize + 1, linkid, prop_name, 3889 (prop_val != NULL ? 0 : DLD_PROP_DEFAULT), &status); 3890 if (dip == NULL) 3891 return (status); 3892 3893 dp = (uchar_t *)dip->pr_val; 3894 slen = 0; 3895 3896 if (prop_val == NULL) { 3897 status = i_dladm_macprop(handle, dip, B_FALSE); 3898 dip->pr_flags = 0; 3899 } else { 3900 for (i = 0; i < val_cnt; i++) { 3901 int plen = 0; 3902 3903 plen = strlen(prop_val[i]); 3904 bcopy(prop_val[i], dp, plen); 3905 slen += plen; 3906 /* 3907 * add a "," separator and update dp. 3908 */ 3909 if (i != (val_cnt -1)) 3910 dp[slen++] = ','; 3911 dp += (plen + 1); 3912 } 3913 } 3914 if (status == DLADM_STATUS_OK) 3915 status = i_dladm_macprop(handle, dip, B_TRUE); 3916 3917 free(dip); 3918 return (status); 3919 } 3920 3921 static dladm_status_t 3922 i_dladm_get_priv_prop(dladm_handle_t handle, datalink_id_t linkid, 3923 const char *prop_name, char **prop_val, uint_t *val_cnt, 3924 dladm_prop_type_t type, uint_t dld_flags) 3925 { 3926 dladm_status_t status = DLADM_STATUS_OK; 3927 dld_ioc_macprop_t *dip = NULL; 3928 link_attr_t *p; 3929 3930 if ((prop_name == NULL && prop_val != NULL) || 3931 (prop_val != NULL && val_cnt == 0)) 3932 return (DLADM_STATUS_BADARG); 3933 3934 p = dladm_name2prop(prop_name); 3935 if (p->pp_id != MAC_PROP_PRIVATE) 3936 return (DLADM_STATUS_BADARG); 3937 3938 /* 3939 * private properties: all parsing is done in the kernel. 3940 */ 3941 dip = i_dladm_buf_alloc_by_name(DLADM_PROP_BUF_CHUNK, linkid, prop_name, 3942 dld_flags, &status); 3943 if (dip == NULL) 3944 return (status); 3945 3946 if ((status = i_dladm_macprop(handle, dip, B_FALSE)) == 3947 DLADM_STATUS_OK) { 3948 if (type == DLADM_PROP_VAL_PERM) { 3949 (void) dladm_perm2str(dip->pr_perm_flags, *prop_val); 3950 } else if (type == DLADM_PROP_VAL_MODIFIABLE) { 3951 *prop_val[0] = '\0'; 3952 } else { 3953 (void) strncpy(*prop_val, dip->pr_val, 3954 DLADM_PROP_VAL_MAX); 3955 } 3956 *val_cnt = 1; 3957 } else if ((status == DLADM_STATUS_NOTSUP) && 3958 (type == DLADM_PROP_VAL_CURRENT)) { 3959 status = DLADM_STATUS_NOTFOUND; 3960 } 3961 free(dip); 3962 return (status); 3963 } 3964 3965 3966 static dladm_status_t 3967 i_dladm_getset_defval(dladm_handle_t handle, prop_desc_t *pdp, 3968 datalink_id_t linkid, datalink_media_t media, uint_t flags) 3969 { 3970 dladm_status_t status; 3971 char **prop_vals = NULL, *buf; 3972 size_t bufsize; 3973 uint_t cnt; 3974 int i; 3975 uint_t perm_flags; 3976 3977 /* 3978 * Allocate buffer needed for prop_vals array. We can have at most 3979 * DLADM_MAX_PROP_VALCNT char *prop_vals[] entries, where 3980 * each entry has max size DLADM_PROP_VAL_MAX 3981 */ 3982 bufsize = 3983 (sizeof (char *) + DLADM_PROP_VAL_MAX) * DLADM_MAX_PROP_VALCNT; 3984 buf = malloc(bufsize); 3985 prop_vals = (char **)(void *)buf; 3986 for (i = 0; i < DLADM_MAX_PROP_VALCNT; i++) { 3987 prop_vals[i] = buf + 3988 sizeof (char *) * DLADM_MAX_PROP_VALCNT + 3989 i * DLADM_PROP_VAL_MAX; 3990 } 3991 3992 /* 3993 * For properties which have pdp->pd_defval.vd_name as a non-empty 3994 * string, the "" itself is used to reset the property (exceptions 3995 * are zone and autopush, which populate vdp->vd_val). So 3996 * libdladm can copy pdp->pd_defval over to the val_desc_t passed 3997 * down on the setprop using the global values in the table. For 3998 * other cases (vd_name is ""), doing reset-linkprop will cause 3999 * libdladm to do a getprop to find the default value and then do 4000 * a setprop to reset the value to default. 4001 */ 4002 status = pdp->pd_get(handle, pdp, linkid, prop_vals, &cnt, media, 4003 DLD_PROP_DEFAULT, &perm_flags); 4004 if (status == DLADM_STATUS_OK) { 4005 if (perm_flags == MAC_PROP_PERM_RW) { 4006 status = i_dladm_set_single_prop(handle, linkid, 4007 pdp->pd_class, media, pdp, prop_vals, cnt, flags); 4008 } 4009 else 4010 status = DLADM_STATUS_NOTSUP; 4011 } 4012 free(buf); 4013 return (status); 4014 } 4015 4016 /* ARGSUSED */ 4017 static dladm_status_t 4018 get_stp(dladm_handle_t handle, struct prop_desc *pd, datalink_id_t linkid, 4019 char **prop_val, uint_t *val_cnt, datalink_media_t media, uint_t flags, 4020 uint_t *perm_flags) 4021 { 4022 const bridge_public_prop_t *bpp; 4023 dladm_status_t retv; 4024 int val, i; 4025 4026 if (flags != 0) 4027 return (DLADM_STATUS_NOTSUP); 4028 *perm_flags = MAC_PROP_PERM_RW; 4029 *val_cnt = 1; 4030 for (bpp = bridge_prop; bpp->bpp_name != NULL; bpp++) 4031 if (strcmp(bpp->bpp_name, pd->pd_name) == 0) 4032 break; 4033 retv = dladm_bridge_get_port_cfg(handle, linkid, bpp->bpp_code, &val); 4034 /* If the daemon isn't running, then return the persistent value */ 4035 if (retv == DLADM_STATUS_NOTFOUND) { 4036 if (i_dladm_get_linkprop_db(handle, linkid, pd->pd_name, 4037 prop_val, val_cnt) != DLADM_STATUS_OK) 4038 (void) strlcpy(*prop_val, pd->pd_defval.vd_name, 4039 DLADM_PROP_VAL_MAX); 4040 return (DLADM_STATUS_OK); 4041 } 4042 if (retv != DLADM_STATUS_OK) { 4043 (void) strlcpy(*prop_val, "?", DLADM_PROP_VAL_MAX); 4044 return (retv); 4045 } 4046 if (val == pd->pd_defval.vd_val && pd->pd_defval.vd_name[0] != '\0') { 4047 (void) strlcpy(*prop_val, pd->pd_defval.vd_name, 4048 DLADM_PROP_VAL_MAX); 4049 return (DLADM_STATUS_OK); 4050 } 4051 for (i = 0; i < pd->pd_noptval; i++) { 4052 if (val == pd->pd_optval[i].vd_val) { 4053 (void) strlcpy(*prop_val, pd->pd_optval[i].vd_name, 4054 DLADM_PROP_VAL_MAX); 4055 return (DLADM_STATUS_OK); 4056 } 4057 } 4058 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "%u", (unsigned)val); 4059 return (DLADM_STATUS_OK); 4060 } 4061 4062 /* ARGSUSED1 */ 4063 static dladm_status_t 4064 set_stp_prop(dladm_handle_t handle, prop_desc_t *pd, datalink_id_t linkid, 4065 val_desc_t *vdp, uint_t val_cnt, uint_t flags, datalink_media_t media) 4066 { 4067 /* 4068 * Special case for mcheck: the daemon resets the value to zero, and we 4069 * don't want the daemon to refresh itself; it leads to deadlock. 4070 */ 4071 if (flags & DLADM_OPT_NOREFRESH) 4072 return (DLADM_STATUS_OK); 4073 4074 /* Tell the running daemon, if any */ 4075 return (dladm_bridge_refresh(handle, linkid)); 4076 } 4077 4078 /* 4079 * This is used only for stp_priority, stp_cost, and stp_mcheck. 4080 */ 4081 /* ARGSUSED */ 4082 static dladm_status_t 4083 check_stp_prop(dladm_handle_t handle, struct prop_desc *pd, 4084 datalink_id_t linkid, char **prop_val, uint_t *val_cntp, uint_t flags, 4085 val_desc_t **vdpp, datalink_media_t media) 4086 { 4087 char *cp; 4088 boolean_t iscost; 4089 uint_t val_cnt = *val_cntp; 4090 val_desc_t *vdp = *vdpp; 4091 4092 if (val_cnt != 1) 4093 return (DLADM_STATUS_BADVALCNT); 4094 4095 if (prop_val == NULL) { 4096 vdp->vd_val = 0; 4097 } else { 4098 /* Only stp_priority and stp_cost use this function */ 4099 iscost = strcmp(pd->pd_name, "stp_cost") == 0; 4100 4101 if (iscost && strcmp(prop_val[0], "auto") == 0) { 4102 /* Illegal value 0 is allowed to mean "automatic" */ 4103 vdp->vd_val = 0; 4104 } else { 4105 errno = 0; 4106 vdp->vd_val = strtoul(prop_val[0], &cp, 0); 4107 if (errno != 0 || *cp != '\0') 4108 return (DLADM_STATUS_BADVAL); 4109 } 4110 } 4111 4112 if (iscost) { 4113 return (vdp->vd_val > 65535 ? DLADM_STATUS_BADVAL : 4114 DLADM_STATUS_OK); 4115 } else { 4116 if (vdp->vd_val > 255) 4117 return (DLADM_STATUS_BADVAL); 4118 /* 4119 * If the user is setting stp_mcheck non-zero, then (per the 4120 * IEEE management standards and UNH testing) we need to check 4121 * whether this link is part of a bridge that is running RSTP. 4122 * If it's not, then setting the flag is an error. Note that 4123 * errors are intentionally discarded here; it's the value 4124 * that's the problem -- it's not a bad value, merely one that 4125 * can't be used now. 4126 */ 4127 if (strcmp(pd->pd_name, "stp_mcheck") == 0 && 4128 vdp->vd_val != 0) { 4129 char bridge[MAXLINKNAMELEN]; 4130 UID_STP_CFG_T cfg; 4131 dladm_bridge_prot_t brprot; 4132 4133 if (dladm_bridge_getlink(handle, linkid, bridge, 4134 sizeof (bridge)) != DLADM_STATUS_OK || 4135 dladm_bridge_get_properties(bridge, &cfg, 4136 &brprot) != DLADM_STATUS_OK) 4137 return (DLADM_STATUS_FAILED); 4138 if (cfg.force_version <= 1) 4139 return (DLADM_STATUS_FAILED); 4140 } 4141 return (DLADM_STATUS_OK); 4142 } 4143 } 4144 4145 /* ARGSUSED */ 4146 static dladm_status_t 4147 get_bridge_forward(dladm_handle_t handle, struct prop_desc *pd, 4148 datalink_id_t linkid, char **prop_val, uint_t *val_cnt, 4149 datalink_media_t media, uint_t flags, uint_t *perm_flags) 4150 { 4151 dladm_status_t retv; 4152 uint_t val; 4153 4154 if (flags != 0) 4155 return (DLADM_STATUS_NOTSUP); 4156 *perm_flags = MAC_PROP_PERM_RW; 4157 *val_cnt = 1; 4158 retv = dladm_bridge_get_forwarding(handle, linkid, &val); 4159 if (retv == DLADM_STATUS_NOTFOUND) { 4160 if (i_dladm_get_linkprop_db(handle, linkid, pd->pd_name, 4161 prop_val, val_cnt) != DLADM_STATUS_OK) 4162 (void) strlcpy(*prop_val, pd->pd_defval.vd_name, 4163 DLADM_PROP_VAL_MAX); 4164 return (DLADM_STATUS_OK); 4165 } 4166 if (retv == DLADM_STATUS_OK) 4167 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "%u", val); 4168 else 4169 (void) strlcpy(*prop_val, "?", DLADM_PROP_VAL_MAX); 4170 return (retv); 4171 } 4172 4173 /* ARGSUSED */ 4174 static dladm_status_t 4175 set_bridge_forward(dladm_handle_t handle, prop_desc_t *pd, datalink_id_t linkid, 4176 val_desc_t *vdp, uint_t val_cnt, uint_t flags, datalink_media_t media) 4177 { 4178 /* Tell the running daemon, if any */ 4179 return (dladm_bridge_refresh(handle, linkid)); 4180 } 4181 4182 /* ARGSUSED */ 4183 static dladm_status_t 4184 get_bridge_pvid(dladm_handle_t handle, struct prop_desc *pd, 4185 datalink_id_t linkid, char **prop_val, uint_t *val_cnt, 4186 datalink_media_t media, uint_t flags, uint_t *perm_flags) 4187 { 4188 dladm_status_t status; 4189 dld_ioc_macprop_t *dip; 4190 uint16_t pvid; 4191 4192 if (flags != 0) 4193 return (DLADM_STATUS_NOTSUP); 4194 *perm_flags = MAC_PROP_PERM_RW; 4195 *val_cnt = 1; 4196 dip = i_dladm_buf_alloc_by_id(sizeof (uint16_t), linkid, MAC_PROP_PVID, 4197 0, &status); 4198 if (dip == NULL) 4199 return (status); 4200 status = i_dladm_macprop(handle, dip, B_FALSE); 4201 if (status == DLADM_STATUS_OK) { 4202 (void) memcpy(&pvid, dip->pr_val, sizeof (pvid)); 4203 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "%u", pvid); 4204 } else { 4205 (void) strlcpy(*prop_val, "?", DLADM_PROP_VAL_MAX); 4206 } 4207 free(dip); 4208 return (status); 4209 } 4210 4211 /* ARGSUSED */ 4212 static dladm_status_t 4213 set_bridge_pvid(dladm_handle_t handle, prop_desc_t *pd, datalink_id_t linkid, 4214 val_desc_t *vdp, uint_t val_cnt, uint_t flags, datalink_media_t media) 4215 { 4216 dladm_status_t status; 4217 dld_ioc_macprop_t *dip; 4218 uint16_t pvid; 4219 4220 dip = i_dladm_buf_alloc_by_id(sizeof (uint16_t), linkid, MAC_PROP_PVID, 4221 0, &status); 4222 if (dip == NULL) 4223 return (status); 4224 pvid = vdp->vd_val; 4225 (void) memcpy(dip->pr_val, &pvid, sizeof (pvid)); 4226 status = i_dladm_macprop(handle, dip, B_TRUE); 4227 free(dip); 4228 if (status != DLADM_STATUS_OK) 4229 return (status); 4230 4231 /* Tell the running daemon, if any */ 4232 return (dladm_bridge_refresh(handle, linkid)); 4233 } 4234 4235 /* ARGSUSED */ 4236 static dladm_status_t 4237 check_bridge_pvid(dladm_handle_t handle, struct prop_desc *pd, 4238 datalink_id_t linkid, char **prop_val, uint_t *val_cntp, uint_t flags, 4239 val_desc_t **vdpp, datalink_media_t media) 4240 { 4241 char *cp; 4242 uint_t val_cnt = *val_cntp; 4243 val_desc_t *vdp = *vdpp; 4244 4245 if (val_cnt != 1) 4246 return (DLADM_STATUS_BADVALCNT); 4247 4248 if (prop_val == NULL) { 4249 vdp->vd_val = 1; 4250 } else { 4251 errno = 0; 4252 vdp->vd_val = strtoul(prop_val[0], &cp, 0); 4253 if (errno != 0 || *cp != '\0') 4254 return (DLADM_STATUS_BADVAL); 4255 } 4256 4257 return (vdp->vd_val > VLAN_ID_MAX ? DLADM_STATUS_BADVAL : 4258 DLADM_STATUS_OK); 4259 } 4260 4261 dladm_status_t 4262 i_dladm_wlan_param(dladm_handle_t handle, datalink_id_t linkid, void *buf, 4263 mac_prop_id_t cmd, size_t len, boolean_t set) 4264 { 4265 uint32_t flags; 4266 dladm_status_t status; 4267 uint32_t media; 4268 dld_ioc_macprop_t *dip; 4269 void *dp; 4270 4271 if ((status = dladm_datalink_id2info(handle, linkid, &flags, NULL, 4272 &media, NULL, 0)) != DLADM_STATUS_OK) { 4273 return (status); 4274 } 4275 4276 if (media != DL_WIFI) 4277 return (DLADM_STATUS_BADARG); 4278 4279 if (!(flags & DLADM_OPT_ACTIVE)) 4280 return (DLADM_STATUS_TEMPONLY); 4281 4282 if (len == (MAX_BUF_LEN - WIFI_BUF_OFFSET)) 4283 len = MAX_BUF_LEN - sizeof (dld_ioc_macprop_t) - 1; 4284 4285 dip = i_dladm_buf_alloc_by_id(len, linkid, cmd, 0, &status); 4286 if (dip == NULL) 4287 return (DLADM_STATUS_NOMEM); 4288 4289 dp = (uchar_t *)dip->pr_val; 4290 if (set) 4291 (void) memcpy(dp, buf, len); 4292 4293 status = i_dladm_macprop(handle, dip, set); 4294 if (status == DLADM_STATUS_OK) { 4295 if (!set) 4296 (void) memcpy(buf, dp, len); 4297 } 4298 4299 free(dip); 4300 return (status); 4301 } 4302 4303 dladm_status_t 4304 dladm_parse_link_props(char *str, dladm_arg_list_t **listp, boolean_t novalues) 4305 { 4306 return (dladm_parse_args(str, listp, novalues)); 4307 } 4308 4309 /* 4310 * Retrieve the one link property from the database 4311 */ 4312 /*ARGSUSED*/ 4313 static int 4314 i_dladm_get_one_prop(dladm_handle_t handle, datalink_id_t linkid, 4315 const char *prop_name, void *arg) 4316 { 4317 dladm_arg_list_t *proplist = arg; 4318 dladm_arg_info_t *aip = NULL; 4319 4320 aip = &proplist->al_info[proplist->al_count]; 4321 /* 4322 * it is fine to point to prop_name since prop_name points to the 4323 * prop_table[n].pd_name. 4324 */ 4325 aip->ai_name = prop_name; 4326 4327 (void) dladm_get_linkprop(handle, linkid, DLADM_PROP_VAL_PERSISTENT, 4328 prop_name, aip->ai_val, &aip->ai_count); 4329 4330 if (aip->ai_count != 0) 4331 proplist->al_count++; 4332 4333 return (DLADM_WALK_CONTINUE); 4334 } 4335 4336 4337 /* 4338 * Retrieve all link properties for a link from the database and 4339 * return a property list. 4340 */ 4341 dladm_status_t 4342 dladm_link_get_proplist(dladm_handle_t handle, datalink_id_t linkid, 4343 dladm_arg_list_t **listp) 4344 { 4345 dladm_arg_list_t *list; 4346 dladm_status_t status = DLADM_STATUS_OK; 4347 4348 list = calloc(1, sizeof (dladm_arg_list_t)); 4349 if (list == NULL) 4350 return (dladm_errno2status(errno)); 4351 4352 status = dladm_walk_linkprop(handle, linkid, list, 4353 i_dladm_get_one_prop); 4354 4355 *listp = list; 4356 return (status); 4357 } 4358 4359 /* 4360 * Retrieve the named property from a proplist, check the value and 4361 * convert to a kernel structure. 4362 */ 4363 static dladm_status_t 4364 i_dladm_link_proplist_extract_one(dladm_handle_t handle, 4365 dladm_arg_list_t *proplist, const char *name, uint_t flags, void *arg) 4366 { 4367 dladm_status_t status; 4368 dladm_arg_info_t *aip = NULL; 4369 int i, j; 4370 4371 /* Find named property in proplist */ 4372 for (i = 0; i < proplist->al_count; i++) { 4373 aip = &proplist->al_info[i]; 4374 if (strcasecmp(aip->ai_name, name) == 0) 4375 break; 4376 } 4377 4378 /* Property not in list */ 4379 if (i == proplist->al_count) 4380 return (DLADM_STATUS_OK); 4381 4382 for (i = 0; i < DLADM_MAX_PROPS; i++) { 4383 prop_desc_t *pdp = &prop_table[i]; 4384 val_desc_t *vdp; 4385 4386 vdp = malloc(sizeof (val_desc_t) * aip->ai_count); 4387 if (vdp == NULL) 4388 return (DLADM_STATUS_NOMEM); 4389 4390 if (strcasecmp(aip->ai_name, pdp->pd_name) != 0) 4391 continue; 4392 4393 if (aip->ai_val == NULL) 4394 return (DLADM_STATUS_BADARG); 4395 4396 /* Check property value */ 4397 if (pdp->pd_check != NULL) { 4398 status = pdp->pd_check(handle, pdp, 0, aip->ai_val, 4399 &(aip->ai_count), flags, &vdp, 0); 4400 } else { 4401 status = DLADM_STATUS_BADARG; 4402 } 4403 4404 if (status != DLADM_STATUS_OK) 4405 return (status); 4406 4407 for (j = 0; j < DLADM_MAX_RSRC_PROP; j++) { 4408 resource_prop_t *rpp = &rsrc_prop_table[j]; 4409 4410 if (strcasecmp(aip->ai_name, rpp->rp_name) != 0) 4411 continue; 4412 4413 /* Extract kernel structure */ 4414 if (rpp->rp_extract != NULL) { 4415 status = rpp->rp_extract(vdp, 4416 aip->ai_count, arg); 4417 } else { 4418 status = DLADM_STATUS_BADARG; 4419 } 4420 break; 4421 } 4422 4423 if (status != DLADM_STATUS_OK) 4424 return (status); 4425 4426 break; 4427 } 4428 return (status); 4429 } 4430 4431 /* 4432 * Extract properties from a proplist and convert to mac_resource_props_t. 4433 */ 4434 dladm_status_t 4435 dladm_link_proplist_extract(dladm_handle_t handle, dladm_arg_list_t *proplist, 4436 mac_resource_props_t *mrp, uint_t flags) 4437 { 4438 dladm_status_t status; 4439 int i; 4440 4441 for (i = 0; i < DLADM_MAX_RSRC_PROP; i++) { 4442 status = i_dladm_link_proplist_extract_one(handle, 4443 proplist, rsrc_prop_table[i].rp_name, flags, mrp); 4444 if (status != DLADM_STATUS_OK) 4445 return (status); 4446 } 4447 return (status); 4448 } 4449 4450 static const char * 4451 dladm_perm2str(uint_t perm, char *buf) 4452 { 4453 (void) snprintf(buf, DLADM_STRSIZE, "%c%c", 4454 ((perm & MAC_PROP_PERM_READ) != 0) ? 'r' : '-', 4455 ((perm & MAC_PROP_PERM_WRITE) != 0) ? 'w' : '-'); 4456 return (buf); 4457 } 4458 4459 dladm_status_t 4460 dladm_get_state(dladm_handle_t handle, datalink_id_t linkid, 4461 link_state_t *state) 4462 { 4463 uint_t perms; 4464 4465 return (i_dladm_get_public_prop(handle, linkid, "state", 0, 4466 &perms, state, sizeof (*state))); 4467 } 4468 4469 boolean_t 4470 dladm_attr_is_linkprop(const char *name) 4471 { 4472 /* non-property attribute names */ 4473 const char *nonprop[] = { 4474 /* dlmgmtd core attributes */ 4475 "name", 4476 "class", 4477 "media", 4478 FPHYMAJ, 4479 FPHYINST, 4480 FDEVNAME, 4481 4482 /* other attributes for vlan, aggr, etc */ 4483 DLADM_ATTR_NAMES 4484 }; 4485 boolean_t is_nonprop = B_FALSE; 4486 int i; 4487 4488 for (i = 0; i < sizeof (nonprop) / sizeof (nonprop[0]); i++) { 4489 if (strcmp(name, nonprop[i]) == 0) { 4490 is_nonprop = B_TRUE; 4491 break; 4492 } 4493 } 4494 4495 return (!is_nonprop); 4496 } 4497 4498 dladm_status_t 4499 dladm_linkprop_is_set(dladm_handle_t handle, datalink_id_t linkid, 4500 dladm_prop_type_t type, const char *prop_name, boolean_t *is_set) 4501 { 4502 char *buf, **propvals; 4503 uint_t valcnt = DLADM_MAX_PROP_VALCNT; 4504 int i; 4505 dladm_status_t status = DLADM_STATUS_OK; 4506 size_t bufsize; 4507 4508 *is_set = B_FALSE; 4509 4510 bufsize = (sizeof (char *) + DLADM_PROP_VAL_MAX) * 4511 DLADM_MAX_PROP_VALCNT; 4512 if ((buf = calloc(1, bufsize)) == NULL) 4513 return (DLADM_STATUS_NOMEM); 4514 4515 propvals = (char **)(void *)buf; 4516 for (i = 0; i < valcnt; i++) { 4517 propvals[i] = buf + 4518 sizeof (char *) * DLADM_MAX_PROP_VALCNT + 4519 i * DLADM_PROP_VAL_MAX; 4520 } 4521 4522 if (dladm_get_linkprop(handle, linkid, type, prop_name, propvals, 4523 &valcnt) != DLADM_STATUS_OK) { 4524 goto done; 4525 } 4526 4527 /* 4528 * valcnt is always set to 1 by get_pool(), hence we need to check 4529 * for a non-null string to see if it is set. For protection and 4530 * allowed-ips, we can check either the *propval or the valcnt. 4531 */ 4532 if ((strcmp(prop_name, "pool") == 0 || 4533 strcmp(prop_name, "protection") == 0 || 4534 strcmp(prop_name, "allowed-ips") == 0) && 4535 (strlen(*propvals) != 0)) { 4536 *is_set = B_TRUE; 4537 } else if ((strcmp(prop_name, "cpus") == 0) && (valcnt != 0)) { 4538 *is_set = B_TRUE; 4539 } else if ((strcmp(prop_name, "_softmac") == 0) && (valcnt != 0) && 4540 (strcmp(propvals[0], "true") == 0)) { 4541 *is_set = B_TRUE; 4542 } 4543 4544 done: 4545 if (buf != NULL) 4546 free(buf); 4547 return (status); 4548 } 4549 4550 /* ARGSUSED */ 4551 static dladm_status_t 4552 get_linkmode_prop(dladm_handle_t handle, prop_desc_t *pdp, 4553 datalink_id_t linkid, char **prop_val, uint_t *val_cnt, 4554 datalink_media_t media, uint_t flags, uint_t *perm_flags) 4555 { 4556 char *s; 4557 uint32_t v; 4558 dladm_status_t status; 4559 4560 status = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags, 4561 perm_flags, &v, sizeof (v)); 4562 if (status != DLADM_STATUS_OK) 4563 return (status); 4564 4565 switch (v) { 4566 case DLADM_PART_CM_MODE: 4567 s = "cm"; 4568 break; 4569 case DLADM_PART_UD_MODE: 4570 s = "ud"; 4571 break; 4572 default: 4573 s = ""; 4574 break; 4575 } 4576 (void) snprintf(prop_val[0], DLADM_STRSIZE, "%s", s); 4577 4578 *val_cnt = 1; 4579 return (DLADM_STATUS_OK); 4580 } 4581