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