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