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