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