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