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