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