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 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include <stdlib.h> 27 #include <strings.h> 28 #include <errno.h> 29 #include <ctype.h> 30 #include <stddef.h> 31 #include <sys/types.h> 32 #include <sys/stat.h> 33 #include <sys/dld.h> 34 #include <sys/zone.h> 35 #include <fcntl.h> 36 #include <unistd.h> 37 #include <libdevinfo.h> 38 #include <zone.h> 39 #include <libdllink.h> 40 #include <libdladm_impl.h> 41 #include <libdlwlan_impl.h> 42 #include <libdlwlan.h> 43 #include <libdlvlan.h> 44 #include <libdlvnic.h> 45 #include <libintl.h> 46 #include <dlfcn.h> 47 #include <link.h> 48 #include <inet/wifi_ioctl.h> 49 #include <libdladm.h> 50 #include <libdlstat.h> 51 #include <sys/param.h> 52 #include <sys/debug.h> 53 #include <sys/dld.h> 54 #include <inttypes.h> 55 #include <sys/ethernet.h> 56 #include <inet/iptun.h> 57 #include <net/wpa.h> 58 #include <sys/sysmacros.h> 59 #include <sys/vlan.h> 60 #include <libdlbridge.h> 61 #include <stp_in.h> 62 63 /* 64 * The linkprop get() callback. 65 * - pd: pointer to the prop_desc_t 66 * - propstrp: a property string array to keep the returned property. 67 * Caller allocated. 68 * - cntp: number of returned properties. 69 * Caller also uses it to indicate how many it expects. 70 */ 71 struct prop_desc; 72 typedef struct prop_desc prop_desc_t; 73 74 typedef dladm_status_t pd_getf_t(dladm_handle_t, prop_desc_t *pdp, 75 datalink_id_t, char **propstp, uint_t *cntp, 76 datalink_media_t, uint_t, uint_t *); 77 78 /* 79 * The linkprop set() callback. 80 * - propval: a val_desc_t array which keeps the property values to be set. 81 * - cnt: number of properties to be set. 82 * - flags: additional flags passed down the system call. 83 * 84 * pd_set takes val_desc_t given by pd_check(), translates it into 85 * a format suitable for kernel consumption. This may require allocation 86 * of ioctl buffers etc. pd_set() may call another common routine (used 87 * by all other pd_sets) which invokes the ioctl. 88 */ 89 typedef dladm_status_t pd_setf_t(dladm_handle_t, prop_desc_t *, datalink_id_t, 90 val_desc_t *propval, uint_t cnt, uint_t flags, 91 datalink_media_t); 92 93 /* 94 * The linkprop check() callback. 95 * - propstrp: property string array which keeps the property to be checked. 96 * - cnt: number of properties. 97 * - propval: return value; the property values of the given property strings. 98 * 99 * pd_check checks that the input values are valid. It does so by 100 * iteraring through the pd_modval list for the property. If 101 * the modifiable values cannot be expressed as a list, a pd_check 102 * specific to this property can be used. If the input values are 103 * verified to be valid, pd_check allocates a val_desc_t and fills it 104 * with either a val_desc_t found on the pd_modval list or something 105 * generated on the fly. 106 */ 107 typedef dladm_status_t pd_checkf_t(dladm_handle_t, prop_desc_t *pdp, 108 datalink_id_t, char **propstrp, uint_t cnt, 109 val_desc_t *propval, datalink_media_t); 110 111 typedef struct link_attr_s { 112 mac_prop_id_t pp_id; 113 size_t pp_valsize; 114 char *pp_name; 115 } link_attr_t; 116 117 static dld_ioc_macprop_t *i_dladm_buf_alloc_by_name(size_t, datalink_id_t, 118 const char *, uint_t, dladm_status_t *); 119 static dld_ioc_macprop_t *i_dladm_buf_alloc_by_id(size_t, datalink_id_t, 120 mac_prop_id_t, uint_t, dladm_status_t *); 121 static dld_ioc_macprop_t *i_dladm_get_public_prop(dladm_handle_t, datalink_id_t, 122 char *, uint_t, dladm_status_t *, uint_t *); 123 124 static dladm_status_t i_dladm_set_private_prop(dladm_handle_t, datalink_id_t, 125 const char *, char **, uint_t, uint_t); 126 static dladm_status_t i_dladm_get_priv_prop(dladm_handle_t, datalink_id_t, 127 const char *, char **, uint_t *, dladm_prop_type_t, 128 uint_t); 129 static link_attr_t *dladm_name2prop(const char *); 130 static link_attr_t *dladm_id2prop(mac_prop_id_t); 131 132 static pd_getf_t do_get_zone, do_get_autopush, do_get_rate_mod, 133 do_get_rate_prop, do_get_channel_prop, 134 do_get_powermode_prop, do_get_radio_prop, 135 i_dladm_duplex_get, i_dladm_status_get, 136 i_dladm_binary_get, i_dladm_uint32_get, 137 i_dladm_flowctl_get, i_dladm_maxbw_get, 138 i_dladm_cpus_get, i_dladm_priority_get, 139 i_dladm_tagmode_get, i_dladm_range_get, 140 get_stp_prop, get_bridge_forward, 141 get_bridge_pvid, 142 /* the above need to be renamed to "do_get_xxx" */ 143 do_get_protection; 144 145 static pd_setf_t do_set_zone, do_set_rate_prop, 146 do_set_powermode_prop, do_set_radio_prop, 147 i_dladm_set_public_prop, do_set_res, do_set_cpus, 148 set_stp_prop, set_bridge_forward, set_bridge_pvid, 149 do_set_protection; 150 151 static pd_checkf_t do_check_zone, do_check_autopush, do_check_rate, 152 do_check_hoplimit, do_check_encaplim, 153 i_dladm_uint32_check, do_check_maxbw, do_check_cpus, 154 do_check_priority, check_stp_prop, check_bridge_pvid, 155 do_check_allowedips, do_check_prop; 156 157 static dladm_status_t i_dladm_speed_get(dladm_handle_t, prop_desc_t *, 158 datalink_id_t, char **, uint_t *, uint_t, uint_t *); 159 static dladm_status_t i_dladm_macprop(dladm_handle_t, void *, boolean_t); 160 static const char *dladm_perm2str(uint_t, char *); 161 162 struct prop_desc { 163 /* 164 * link property name 165 */ 166 char *pd_name; 167 168 /* 169 * default property value, can be set to { "", NULL } 170 */ 171 val_desc_t pd_defval; 172 173 /* 174 * list of optional property values, can be NULL. 175 * 176 * This is set to non-NULL if there is a list of possible property 177 * values. pd_optval would point to the array of possible values. 178 */ 179 val_desc_t *pd_optval; 180 181 /* 182 * count of the above optional property values. 0 if pd_optval is NULL. 183 */ 184 uint_t pd_noptval; 185 186 /* 187 * callback to set link property; set to NULL if this property is 188 * read-only and may be called before or after permanent update; see 189 * flags. 190 */ 191 pd_setf_t *pd_set; 192 193 /* 194 * callback to get modifiable link property 195 */ 196 pd_getf_t *pd_getmod; 197 198 /* 199 * callback to get current link property 200 */ 201 pd_getf_t *pd_get; 202 203 /* 204 * callback to validate link property value, set to NULL if pd_optval 205 * is not NULL. In that case, validate the value by comparing it with 206 * the pd_optval. Return a val_desc_t array pointer if the value is 207 * valid. 208 */ 209 pd_checkf_t *pd_check; 210 211 uint_t pd_flags; 212 #define PD_TEMPONLY 0x1 /* property is temporary only */ 213 #define PD_CHECK_ALLOC 0x2 /* alloc vd_val as part of pd_check */ 214 #define PD_AFTER_PERM 0x4 /* pd_set after db update; no temporary */ 215 /* 216 * indicate link classes this property applies to. 217 */ 218 datalink_class_t pd_class; 219 220 /* 221 * indicate link media type this property applies to. 222 */ 223 datalink_media_t pd_dmedia; 224 }; 225 226 #define MAC_PROP_BUFSIZE(v) sizeof (dld_ioc_macprop_t) + (v) - 1 227 228 /* 229 * Supported link properties enumerated in the prop_table[] array are 230 * computed using the callback functions in that array. To compute the 231 * property value, multiple distinct system calls may be needed (e.g., 232 * for wifi speed, we need to issue system calls to get desired/supported 233 * rates). The link_attr[] table enumerates the interfaces to the kernel, 234 * and the type/size of the data passed in the user-kernel interface. 235 */ 236 static link_attr_t link_attr[] = { 237 { MAC_PROP_DUPLEX, sizeof (link_duplex_t), "duplex"}, 238 239 { MAC_PROP_SPEED, sizeof (uint64_t), "speed"}, 240 241 { MAC_PROP_STATUS, sizeof (link_state_t), "state"}, 242 243 { MAC_PROP_AUTONEG, sizeof (uint8_t), "adv_autoneg_cap"}, 244 245 { MAC_PROP_MTU, sizeof (uint32_t), "mtu"}, 246 247 { MAC_PROP_FLOWCTRL, sizeof (link_flowctrl_t), "flowctrl"}, 248 249 { MAC_PROP_ZONE, sizeof (dld_ioc_zid_t), "zone"}, 250 251 { MAC_PROP_AUTOPUSH, sizeof (struct dlautopush), "autopush"}, 252 253 { MAC_PROP_ADV_10GFDX_CAP, sizeof (uint8_t), "adv_10gfdx_cap"}, 254 255 { MAC_PROP_EN_10GFDX_CAP, sizeof (uint8_t), "en_10gfdx_cap"}, 256 257 { MAC_PROP_ADV_1000FDX_CAP, sizeof (uint8_t), "adv_1000fdx_cap"}, 258 259 { MAC_PROP_EN_1000FDX_CAP, sizeof (uint8_t), "en_1000fdx_cap"}, 260 261 { MAC_PROP_ADV_1000HDX_CAP, sizeof (uint8_t), "adv_1000hdx_cap"}, 262 263 { MAC_PROP_EN_1000HDX_CAP, sizeof (uint8_t), "en_1000hdx_cap"}, 264 265 { MAC_PROP_ADV_100FDX_CAP, sizeof (uint8_t), "adv_100fdx_cap"}, 266 267 { MAC_PROP_EN_100FDX_CAP, sizeof (uint8_t), "en_100fdx_cap"}, 268 269 { MAC_PROP_ADV_100HDX_CAP, sizeof (uint8_t), "adv_100hdx_cap"}, 270 271 { MAC_PROP_EN_100HDX_CAP, sizeof (uint8_t), "en_100hdx_cap"}, 272 273 { MAC_PROP_ADV_10FDX_CAP, sizeof (uint8_t), "adv_10fdx_cap"}, 274 275 { MAC_PROP_EN_10FDX_CAP, sizeof (uint8_t), "en_10fdx_cap"}, 276 277 { MAC_PROP_ADV_10HDX_CAP, sizeof (uint8_t), "adv_10hdx_cap"}, 278 279 { MAC_PROP_EN_10HDX_CAP, sizeof (uint8_t), "en_10hdx_cap"}, 280 281 { MAC_PROP_WL_ESSID, sizeof (wl_linkstatus_t), "essid"}, 282 283 { MAC_PROP_WL_BSSID, sizeof (wl_bssid_t), "bssid"}, 284 285 { MAC_PROP_WL_BSSTYPE, sizeof (wl_bss_type_t), "bsstype"}, 286 287 { MAC_PROP_WL_LINKSTATUS, sizeof (wl_linkstatus_t), "wl_linkstatus"}, 288 289 /* wl_rates_t has variable length */ 290 { MAC_PROP_WL_DESIRED_RATES, sizeof (wl_rates_t), "desired_rates"}, 291 292 /* wl_rates_t has variable length */ 293 { MAC_PROP_WL_SUPPORTED_RATES, sizeof (wl_rates_t), "supported_rates"}, 294 295 { MAC_PROP_WL_AUTH_MODE, sizeof (wl_authmode_t), "authmode"}, 296 297 { MAC_PROP_WL_ENCRYPTION, sizeof (wl_encryption_t), "encryption"}, 298 299 { MAC_PROP_WL_RSSI, sizeof (wl_rssi_t), "signal"}, 300 301 { MAC_PROP_WL_PHY_CONFIG, sizeof (wl_phy_conf_t), "phy_conf"}, 302 303 { MAC_PROP_WL_CAPABILITY, sizeof (wl_capability_t), "capability"}, 304 305 { MAC_PROP_WL_WPA, sizeof (wl_wpa_t), "wpa"}, 306 307 /* wl_wpa_ess_t has variable length */ 308 { MAC_PROP_WL_SCANRESULTS, sizeof (wl_wpa_ess_t), "scan_results"}, 309 310 { MAC_PROP_WL_POWER_MODE, sizeof (wl_ps_mode_t), "powermode"}, 311 312 { MAC_PROP_WL_RADIO, sizeof (dladm_wlan_radio_t), "wl_radio"}, 313 314 { MAC_PROP_WL_ESS_LIST, sizeof (wl_ess_list_t), "wl_ess_list"}, 315 316 { MAC_PROP_WL_KEY_TAB, sizeof (wl_wep_key_tab_t), "wl_wep_key"}, 317 318 { MAC_PROP_WL_CREATE_IBSS, sizeof (wl_create_ibss_t), "createibss"}, 319 320 /* wl_wpa_ie_t has variable length */ 321 { MAC_PROP_WL_SETOPTIE, sizeof (wl_wpa_ie_t), "set_ie"}, 322 323 { MAC_PROP_WL_DELKEY, sizeof (wl_del_key_t), "wpa_del_key"}, 324 325 { MAC_PROP_WL_KEY, sizeof (wl_key_t), "wl_key"}, 326 327 { MAC_PROP_WL_MLME, sizeof (wl_mlme_t), "mlme"}, 328 329 { MAC_PROP_MAXBW, sizeof (mac_resource_props_t), "maxbw"}, 330 331 { MAC_PROP_PRIO, sizeof (mac_resource_props_t), "priority"}, 332 333 { MAC_PROP_BIND_CPU, sizeof (mac_resource_props_t), "cpus"}, 334 335 { MAC_PROP_TAGMODE, sizeof (link_tagmode_t), "tagmode"}, 336 337 { MAC_PROP_IPTUN_HOPLIMIT, sizeof (uint32_t), "hoplimit"}, 338 339 { MAC_PROP_IPTUN_ENCAPLIMIT, sizeof (uint32_t), "encaplimit"}, 340 341 { MAC_PROP_PVID, sizeof (uint16_t), "default_tag"}, 342 343 { MAC_PROP_LLIMIT, sizeof (uint32_t), "learn_limit"}, 344 345 { MAC_PROP_LDECAY, sizeof (uint32_t), "learn_decay"}, 346 347 { MAC_PROP_PROTECT, sizeof (mac_resource_props_t), "protection"}, 348 349 { MAC_PROP_PRIVATE, 0, "driver-private"} 350 }; 351 352 typedef struct bridge_public_prop_s { 353 const char *bpp_name; 354 int bpp_code; 355 } bridge_public_prop_t; 356 357 static const bridge_public_prop_t bridge_prop[] = { 358 { "stp", PT_CFG_NON_STP }, 359 { "stp_priority", PT_CFG_PRIO }, 360 { "stp_cost", PT_CFG_COST }, 361 { "stp_edge", PT_CFG_EDGE }, 362 { "stp_p2p", PT_CFG_P2P }, 363 { "stp_mcheck", PT_CFG_MCHECK }, 364 { NULL, 0 } 365 }; 366 367 static val_desc_t link_duplex_vals[] = { 368 { "half", LINK_DUPLEX_HALF }, 369 { "full", LINK_DUPLEX_HALF } 370 }; 371 static val_desc_t link_status_vals[] = { 372 { "up", LINK_STATE_UP }, 373 { "down", LINK_STATE_DOWN } 374 }; 375 static val_desc_t link_01_vals[] = { 376 { "1", 1 }, 377 { "0", 0 } 378 }; 379 static val_desc_t link_flow_vals[] = { 380 { "no", LINK_FLOWCTRL_NONE }, 381 { "tx", LINK_FLOWCTRL_TX }, 382 { "rx", LINK_FLOWCTRL_RX }, 383 { "bi", LINK_FLOWCTRL_BI } 384 }; 385 static val_desc_t link_priority_vals[] = { 386 { "low", MPL_LOW }, 387 { "medium", MPL_MEDIUM }, 388 { "high", MPL_HIGH } 389 }; 390 391 static val_desc_t link_tagmode_vals[] = { 392 { "normal", LINK_TAGMODE_NORMAL }, 393 { "vlanonly", LINK_TAGMODE_VLANONLY } 394 }; 395 396 static val_desc_t link_protect_vals[] = { 397 { "mac-nospoof", MPT_MACNOSPOOF }, 398 { "ip-nospoof", MPT_IPNOSPOOF }, 399 { "restricted", MPT_RESTRICTED } 400 }; 401 402 static val_desc_t dladm_wlan_radio_vals[] = { 403 { "on", DLADM_WLAN_RADIO_ON }, 404 { "off", DLADM_WLAN_RADIO_OFF } 405 }; 406 407 static val_desc_t dladm_wlan_powermode_vals[] = { 408 { "off", DLADM_WLAN_PM_OFF }, 409 { "fast", DLADM_WLAN_PM_FAST }, 410 { "max", DLADM_WLAN_PM_MAX } 411 }; 412 413 static val_desc_t stp_p2p_vals[] = { 414 { "true", P2P_FORCE_TRUE }, 415 { "false", P2P_FORCE_FALSE }, 416 { "auto", P2P_AUTO } 417 }; 418 419 #define VALCNT(vals) (sizeof ((vals)) / sizeof (val_desc_t)) 420 #define RESET_VAL ((uintptr_t)-1) 421 422 static prop_desc_t prop_table[] = { 423 { "channel", { NULL, 0 }, 424 NULL, 0, NULL, NULL, 425 do_get_channel_prop, NULL, 0, 426 DATALINK_CLASS_PHYS, DL_WIFI }, 427 428 { "powermode", { "off", DLADM_WLAN_PM_OFF }, 429 dladm_wlan_powermode_vals, VALCNT(dladm_wlan_powermode_vals), 430 do_set_powermode_prop, NULL, 431 do_get_powermode_prop, NULL, 0, 432 DATALINK_CLASS_PHYS, DL_WIFI }, 433 434 { "radio", { "on", DLADM_WLAN_RADIO_ON }, 435 dladm_wlan_radio_vals, VALCNT(dladm_wlan_radio_vals), 436 do_set_radio_prop, NULL, 437 do_get_radio_prop, NULL, 0, 438 DATALINK_CLASS_PHYS, DL_WIFI }, 439 440 { "speed", { "", 0 }, NULL, 0, 441 do_set_rate_prop, do_get_rate_mod, 442 do_get_rate_prop, do_check_rate, 0, 443 DATALINK_CLASS_PHYS, DATALINK_ANY_MEDIATYPE }, 444 445 { "autopush", { "", 0 }, NULL, 0, 446 i_dladm_set_public_prop, NULL, 447 do_get_autopush, do_check_autopush, PD_CHECK_ALLOC, 448 DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE }, 449 450 { "zone", { "", 0 }, NULL, 0, 451 do_set_zone, NULL, 452 do_get_zone, do_check_zone, PD_TEMPONLY|PD_CHECK_ALLOC, 453 DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE }, 454 455 { "duplex", { "", 0 }, 456 link_duplex_vals, VALCNT(link_duplex_vals), 457 NULL, NULL, i_dladm_duplex_get, NULL, 458 0, DATALINK_CLASS_PHYS, DL_ETHER }, 459 460 { "state", { "up", LINK_STATE_UP }, 461 link_status_vals, VALCNT(link_status_vals), 462 NULL, NULL, i_dladm_status_get, NULL, 463 0, DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE }, 464 465 { "adv_autoneg_cap", { "", 0 }, 466 link_01_vals, VALCNT(link_01_vals), 467 i_dladm_set_public_prop, NULL, i_dladm_binary_get, NULL, 468 0, DATALINK_CLASS_PHYS, DL_ETHER }, 469 470 { "mtu", { "", 0 }, NULL, 0, 471 i_dladm_set_public_prop, i_dladm_range_get, 472 i_dladm_uint32_get, i_dladm_uint32_check, 0, DATALINK_CLASS_ALL, 473 DATALINK_ANY_MEDIATYPE }, 474 475 { "flowctrl", { "", 0 }, 476 link_flow_vals, VALCNT(link_flow_vals), 477 i_dladm_set_public_prop, NULL, i_dladm_flowctl_get, NULL, 478 0, DATALINK_CLASS_PHYS, DL_ETHER }, 479 480 { "adv_10gfdx_cap", { "", 0 }, 481 link_01_vals, VALCNT(link_01_vals), 482 NULL, NULL, i_dladm_binary_get, NULL, 483 0, DATALINK_CLASS_PHYS, DL_ETHER }, 484 485 { "en_10gfdx_cap", { "", 0 }, 486 link_01_vals, VALCNT(link_01_vals), 487 i_dladm_set_public_prop, NULL, i_dladm_binary_get, NULL, 488 0, DATALINK_CLASS_PHYS, DL_ETHER }, 489 490 { "adv_1000fdx_cap", { "", 0 }, 491 link_01_vals, VALCNT(link_01_vals), 492 NULL, NULL, i_dladm_binary_get, NULL, 493 0, DATALINK_CLASS_PHYS, DL_ETHER }, 494 495 { "en_1000fdx_cap", { "", 0 }, 496 link_01_vals, VALCNT(link_01_vals), 497 i_dladm_set_public_prop, NULL, i_dladm_binary_get, NULL, 498 0, DATALINK_CLASS_PHYS, DL_ETHER }, 499 500 { "adv_1000hdx_cap", { "", 0 }, 501 link_01_vals, VALCNT(link_01_vals), 502 NULL, NULL, i_dladm_binary_get, NULL, 503 0, DATALINK_CLASS_PHYS, DL_ETHER }, 504 505 { "en_1000hdx_cap", { "", 0 }, 506 link_01_vals, VALCNT(link_01_vals), 507 i_dladm_set_public_prop, NULL, i_dladm_binary_get, NULL, 508 0, DATALINK_CLASS_PHYS, DL_ETHER }, 509 510 { "adv_100fdx_cap", { "", 0 }, 511 link_01_vals, VALCNT(link_01_vals), 512 NULL, NULL, i_dladm_binary_get, NULL, 513 0, DATALINK_CLASS_PHYS, DL_ETHER }, 514 515 { "en_100fdx_cap", { "", 0 }, 516 link_01_vals, VALCNT(link_01_vals), 517 i_dladm_set_public_prop, NULL, i_dladm_binary_get, NULL, 518 0, DATALINK_CLASS_PHYS, DL_ETHER }, 519 520 { "adv_100hdx_cap", { "", 0 }, 521 link_01_vals, VALCNT(link_01_vals), 522 NULL, NULL, i_dladm_binary_get, NULL, 523 0, DATALINK_CLASS_PHYS, DL_ETHER }, 524 525 { "en_100hdx_cap", { "", 0 }, 526 link_01_vals, VALCNT(link_01_vals), 527 i_dladm_set_public_prop, NULL, i_dladm_binary_get, NULL, 528 0, DATALINK_CLASS_PHYS, DL_ETHER }, 529 530 { "adv_10fdx_cap", { "", 0 }, 531 link_01_vals, VALCNT(link_01_vals), 532 NULL, NULL, i_dladm_binary_get, NULL, 533 0, DATALINK_CLASS_PHYS, DL_ETHER }, 534 535 { "en_10fdx_cap", { "", 0 }, 536 link_01_vals, VALCNT(link_01_vals), 537 i_dladm_set_public_prop, NULL, i_dladm_binary_get, NULL, 538 0, DATALINK_CLASS_PHYS, DL_ETHER }, 539 540 { "adv_10hdx_cap", { "", 0 }, 541 link_01_vals, VALCNT(link_01_vals), 542 NULL, NULL, i_dladm_binary_get, NULL, 543 0, DATALINK_CLASS_PHYS, DL_ETHER }, 544 545 { "en_10hdx_cap", { "", 0 }, 546 link_01_vals, VALCNT(link_01_vals), 547 i_dladm_set_public_prop, NULL, i_dladm_binary_get, NULL, 548 0, DATALINK_CLASS_PHYS, DL_ETHER }, 549 550 { "maxbw", { "--", RESET_VAL }, NULL, 0, 551 do_set_res, NULL, 552 i_dladm_maxbw_get, do_check_maxbw, PD_CHECK_ALLOC, 553 DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE }, 554 555 { "cpus", { "--", RESET_VAL }, NULL, 0, 556 do_set_cpus, NULL, 557 i_dladm_cpus_get, do_check_cpus, 0, 558 DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE }, 559 560 { "priority", { "high", RESET_VAL }, 561 link_priority_vals, VALCNT(link_priority_vals), do_set_res, NULL, 562 i_dladm_priority_get, do_check_priority, PD_CHECK_ALLOC, 563 DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE }, 564 565 { "tagmode", { "vlanonly", LINK_TAGMODE_VLANONLY }, 566 link_tagmode_vals, VALCNT(link_tagmode_vals), 567 i_dladm_set_public_prop, NULL, i_dladm_tagmode_get, 568 NULL, 0, 569 DATALINK_CLASS_PHYS | DATALINK_CLASS_AGGR | DATALINK_CLASS_VNIC, 570 DL_ETHER }, 571 572 { "hoplimit", { "", 0 }, NULL, 0, 573 i_dladm_set_public_prop, i_dladm_range_get, i_dladm_uint32_get, 574 do_check_hoplimit, 0, DATALINK_CLASS_IPTUN, DATALINK_ANY_MEDIATYPE}, 575 576 { "encaplimit", { "", 0 }, NULL, 0, 577 i_dladm_set_public_prop, i_dladm_range_get, i_dladm_uint32_get, 578 do_check_encaplim, 0, DATALINK_CLASS_IPTUN, DL_IPV6}, 579 580 { "forward", { "1", 1 }, 581 link_01_vals, VALCNT(link_01_vals), 582 set_bridge_forward, NULL, get_bridge_forward, NULL, PD_AFTER_PERM, 583 DATALINK_CLASS_ALL & ~DATALINK_CLASS_VNIC, DL_ETHER }, 584 585 { "default_tag", { "1", 1 }, NULL, 0, 586 set_bridge_pvid, NULL, get_bridge_pvid, check_bridge_pvid, 587 0, DATALINK_CLASS_PHYS|DATALINK_CLASS_AGGR| 588 DATALINK_CLASS_ETHERSTUB|DATALINK_CLASS_SIMNET, DL_ETHER }, 589 590 { "learn_limit", { "1000", 1000 }, NULL, 0, 591 i_dladm_set_public_prop, NULL, i_dladm_uint32_get, 592 i_dladm_uint32_check, 0, 593 DATALINK_CLASS_PHYS|DATALINK_CLASS_AGGR| 594 DATALINK_CLASS_ETHERSTUB|DATALINK_CLASS_SIMNET, DL_ETHER }, 595 596 { "learn_decay", { "200", 200 }, NULL, 0, 597 i_dladm_set_public_prop, NULL, i_dladm_uint32_get, 598 i_dladm_uint32_check, 0, 599 DATALINK_CLASS_PHYS|DATALINK_CLASS_AGGR| 600 DATALINK_CLASS_ETHERSTUB|DATALINK_CLASS_SIMNET, DL_ETHER }, 601 602 { "stp", { "1", 1 }, 603 link_01_vals, VALCNT(link_01_vals), 604 set_stp_prop, NULL, get_stp_prop, NULL, PD_AFTER_PERM, 605 DATALINK_CLASS_PHYS|DATALINK_CLASS_AGGR| 606 DATALINK_CLASS_ETHERSTUB|DATALINK_CLASS_SIMNET, DL_ETHER }, 607 608 { "stp_priority", { "128", 128 }, NULL, 0, 609 set_stp_prop, NULL, get_stp_prop, check_stp_prop, PD_AFTER_PERM, 610 DATALINK_CLASS_PHYS|DATALINK_CLASS_AGGR| 611 DATALINK_CLASS_ETHERSTUB|DATALINK_CLASS_SIMNET, DL_ETHER }, 612 613 { "stp_cost", { "auto", 0 }, NULL, 0, 614 set_stp_prop, NULL, get_stp_prop, check_stp_prop, PD_AFTER_PERM, 615 DATALINK_CLASS_PHYS|DATALINK_CLASS_AGGR| 616 DATALINK_CLASS_ETHERSTUB|DATALINK_CLASS_SIMNET, DL_ETHER }, 617 618 { "stp_edge", { "1", 1 }, 619 link_01_vals, VALCNT(link_01_vals), 620 set_stp_prop, NULL, get_stp_prop, NULL, PD_AFTER_PERM, 621 DATALINK_CLASS_PHYS|DATALINK_CLASS_AGGR| 622 DATALINK_CLASS_ETHERSTUB|DATALINK_CLASS_SIMNET, DL_ETHER }, 623 624 { "stp_p2p", { "auto", P2P_AUTO }, 625 stp_p2p_vals, VALCNT(stp_p2p_vals), 626 set_stp_prop, NULL, get_stp_prop, NULL, PD_AFTER_PERM, 627 DATALINK_CLASS_PHYS|DATALINK_CLASS_AGGR| 628 DATALINK_CLASS_ETHERSTUB|DATALINK_CLASS_SIMNET, DL_ETHER }, 629 630 { "stp_mcheck", { "0", 0 }, 631 link_01_vals, VALCNT(link_01_vals), 632 set_stp_prop, NULL, get_stp_prop, check_stp_prop, PD_AFTER_PERM, 633 DATALINK_CLASS_PHYS|DATALINK_CLASS_AGGR| 634 DATALINK_CLASS_ETHERSTUB|DATALINK_CLASS_SIMNET, DL_ETHER }, 635 636 { "protection", { "--", RESET_VAL }, 637 link_protect_vals, VALCNT(link_protect_vals), 638 do_set_protection, NULL, do_get_protection, do_check_prop, 0, 639 DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE }, 640 641 { "allowed-ips", { "--", 0 }, 642 NULL, 0, do_set_protection, NULL, 643 do_get_protection, do_check_allowedips, 0, 644 DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE }, 645 }; 646 647 #define DLADM_MAX_PROPS (sizeof (prop_table) / sizeof (prop_desc_t)) 648 649 static resource_prop_t rsrc_prop_table[] = { 650 {"maxbw", do_extract_maxbw}, 651 {"priority", do_extract_priority}, 652 {"cpus", do_extract_cpus}, 653 {"protection", do_extract_protection}, 654 {"allowed-ips", do_extract_allowedips} 655 }; 656 #define DLADM_MAX_RSRC_PROP (sizeof (rsrc_prop_table) / \ 657 sizeof (resource_prop_t)) 658 659 /* 660 * when retrieving private properties, we pass down a buffer with 661 * DLADM_PROP_BUF_CHUNK of space for the driver to return the property value. 662 */ 663 #define DLADM_PROP_BUF_CHUNK 1024 664 665 static dladm_status_t i_dladm_set_linkprop_db(dladm_handle_t, datalink_id_t, 666 const char *, char **, uint_t); 667 static dladm_status_t i_dladm_get_linkprop_db(dladm_handle_t, datalink_id_t, 668 const char *, char **, uint_t *); 669 static dladm_status_t i_dladm_walk_linkprop_priv_db(dladm_handle_t, 670 datalink_id_t, void *, int (*)(dladm_handle_t, 671 datalink_id_t, const char *, void *)); 672 static dladm_status_t i_dladm_set_single_prop(dladm_handle_t, datalink_id_t, 673 datalink_class_t, uint32_t, prop_desc_t *, char **, 674 uint_t, uint_t); 675 static dladm_status_t i_dladm_set_linkprop(dladm_handle_t, datalink_id_t, 676 const char *, char **, uint_t, uint_t); 677 static dladm_status_t i_dladm_getset_defval(dladm_handle_t, prop_desc_t *, 678 datalink_id_t, datalink_media_t, uint_t); 679 680 /* 681 * Unfortunately, MAX_SCAN_SUPPORT_RATES is too small to allow all 682 * rates to be retrieved. However, we cannot increase it at this 683 * time because it will break binary compatibility with unbundled 684 * WiFi drivers and utilities. So for now we define an additional 685 * constant, MAX_SUPPORT_RATES, to allow all rates to be retrieved. 686 */ 687 #define MAX_SUPPORT_RATES 64 688 689 #define AP_ANCHOR "[anchor]" 690 #define AP_DELIMITER '.' 691 692 /* ARGSUSED */ 693 static dladm_status_t 694 do_check_prop(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid, 695 char **prop_val, uint_t val_cnt, val_desc_t *vdp, datalink_media_t media) 696 { 697 int i, j; 698 699 for (j = 0; j < val_cnt; j++) { 700 for (i = 0; i < pdp->pd_noptval; i++) { 701 if (strcasecmp(prop_val[j], 702 pdp->pd_optval[i].vd_name) == 0) { 703 break; 704 } 705 } 706 if (i == pdp->pd_noptval) 707 return (DLADM_STATUS_BADVAL); 708 709 (void) memcpy(&vdp[j], &pdp->pd_optval[i], sizeof (val_desc_t)); 710 } 711 return (DLADM_STATUS_OK); 712 } 713 714 static dladm_status_t 715 i_dladm_set_single_prop(dladm_handle_t handle, datalink_id_t linkid, 716 datalink_class_t class, uint32_t media, prop_desc_t *pdp, char **prop_val, 717 uint_t val_cnt, uint_t flags) 718 { 719 dladm_status_t status = DLADM_STATUS_OK; 720 val_desc_t *vdp = NULL; 721 boolean_t needfree = B_FALSE; 722 uint_t cnt, i; 723 724 if (!(pdp->pd_class & class)) 725 return (DLADM_STATUS_BADARG); 726 727 if (!DATALINK_MEDIA_ACCEPTED(pdp->pd_dmedia, media)) 728 return (DLADM_STATUS_BADARG); 729 730 if ((flags & DLADM_OPT_PERSIST) && (pdp->pd_flags & PD_TEMPONLY)) 731 return (DLADM_STATUS_TEMPONLY); 732 733 if (!(flags & DLADM_OPT_ACTIVE)) 734 return (DLADM_STATUS_OK); 735 736 if (pdp->pd_set == NULL) 737 return (DLADM_STATUS_PROPRDONLY); 738 739 if (prop_val != NULL) { 740 vdp = malloc(sizeof (val_desc_t) * val_cnt); 741 if (vdp == NULL) 742 return (DLADM_STATUS_NOMEM); 743 744 if (pdp->pd_check != NULL) { 745 needfree = ((pdp->pd_flags & PD_CHECK_ALLOC) != 0); 746 status = pdp->pd_check(handle, pdp, linkid, prop_val, 747 val_cnt, vdp, media); 748 } else if (pdp->pd_optval != NULL) { 749 status = do_check_prop(handle, pdp, linkid, prop_val, 750 val_cnt, vdp, media); 751 } else { 752 status = DLADM_STATUS_BADARG; 753 } 754 755 if (status != DLADM_STATUS_OK) 756 goto done; 757 758 cnt = val_cnt; 759 } else { 760 boolean_t defval = B_FALSE; 761 762 if (pdp->pd_defval.vd_name == NULL) 763 return (DLADM_STATUS_NOTSUP); 764 765 cnt = 1; 766 defval = (strlen(pdp->pd_defval.vd_name) > 0); 767 if ((pdp->pd_flags & PD_CHECK_ALLOC) != 0 || defval) { 768 if ((vdp = malloc(sizeof (val_desc_t))) == NULL) 769 return (DLADM_STATUS_NOMEM); 770 771 if (defval) { 772 (void) memcpy(vdp, &pdp->pd_defval, 773 sizeof (val_desc_t)); 774 } else if (pdp->pd_check != NULL) { 775 status = pdp->pd_check(handle, pdp, linkid, 776 prop_val, cnt, vdp, media); 777 if (status != DLADM_STATUS_OK) 778 goto done; 779 } 780 } else { 781 status = i_dladm_getset_defval(handle, pdp, linkid, 782 media, flags); 783 return (status); 784 } 785 } 786 if (pdp->pd_flags & PD_AFTER_PERM) 787 status = (flags & DLADM_OPT_PERSIST) ? DLADM_STATUS_OK : 788 DLADM_STATUS_PERMONLY; 789 else 790 status = pdp->pd_set(handle, pdp, linkid, vdp, cnt, flags, 791 media); 792 if (needfree) { 793 for (i = 0; i < cnt; i++) 794 free((void *)((val_desc_t *)vdp + i)->vd_val); 795 } 796 done: 797 free(vdp); 798 return (status); 799 } 800 801 static dladm_status_t 802 i_dladm_set_linkprop(dladm_handle_t handle, datalink_id_t linkid, 803 const char *prop_name, char **prop_val, uint_t val_cnt, uint_t flags) 804 { 805 int i; 806 boolean_t found = B_FALSE; 807 datalink_class_t class; 808 uint32_t media; 809 dladm_status_t status = DLADM_STATUS_OK; 810 811 status = dladm_datalink_id2info(handle, linkid, NULL, &class, &media, 812 NULL, 0); 813 if (status != DLADM_STATUS_OK) 814 return (status); 815 816 for (i = 0; i < DLADM_MAX_PROPS; i++) { 817 prop_desc_t *pdp = &prop_table[i]; 818 dladm_status_t s; 819 820 if (prop_name != NULL && 821 (strcasecmp(prop_name, pdp->pd_name) != 0)) 822 continue; 823 found = B_TRUE; 824 s = i_dladm_set_single_prop(handle, linkid, class, media, pdp, 825 prop_val, val_cnt, flags); 826 827 if (prop_name != NULL) { 828 status = s; 829 break; 830 } else { 831 if (s != DLADM_STATUS_OK && 832 s != DLADM_STATUS_NOTSUP) 833 status = s; 834 } 835 } 836 if (!found) { 837 if (prop_name[0] == '_') { 838 /* other private properties */ 839 status = i_dladm_set_private_prop(handle, linkid, 840 prop_name, prop_val, val_cnt, flags); 841 } else { 842 status = DLADM_STATUS_NOTFOUND; 843 } 844 } 845 846 return (status); 847 } 848 849 /* 850 * Set/reset link property for specific link 851 */ 852 dladm_status_t 853 dladm_set_linkprop(dladm_handle_t handle, datalink_id_t linkid, 854 const char *prop_name, char **prop_val, uint_t val_cnt, uint_t flags) 855 { 856 dladm_status_t status = DLADM_STATUS_OK; 857 858 if ((linkid == DATALINK_INVALID_LINKID) || (flags == 0) || 859 (prop_val == NULL && val_cnt > 0) || 860 (prop_val != NULL && val_cnt == 0) || 861 (prop_name == NULL && prop_val != NULL)) { 862 return (DLADM_STATUS_BADARG); 863 } 864 865 /* 866 * Check for valid link property against the flags passed 867 * and set the link property when active flag is passed. 868 */ 869 status = i_dladm_set_linkprop(handle, linkid, prop_name, prop_val, 870 val_cnt, flags); 871 if (status != DLADM_STATUS_OK) 872 return (status); 873 874 if (flags & DLADM_OPT_PERSIST) { 875 status = i_dladm_set_linkprop_db(handle, linkid, prop_name, 876 prop_val, val_cnt); 877 878 if (status == DLADM_STATUS_OK && (flags & DLADM_OPT_ACTIVE)) { 879 prop_desc_t *pdp = prop_table; 880 int i; 881 882 for (i = 0; i < DLADM_MAX_PROPS; i++, pdp++) { 883 if (!(pdp->pd_flags & PD_AFTER_PERM)) 884 continue; 885 if (prop_name != NULL && 886 strcasecmp(prop_name, pdp->pd_name) != 0) 887 continue; 888 status = pdp->pd_set(handle, pdp, linkid, NULL, 889 0, flags, 0); 890 } 891 } 892 } 893 return (status); 894 } 895 896 /* 897 * Walk all link properties of the given specific link. 898 * 899 * Note: this function currently lacks the ability to walk _all_ private 900 * properties if the link, because there is no kernel interface to 901 * retrieve all known private property names. Once such an interface 902 * is added, this function should be fixed accordingly. 903 */ 904 dladm_status_t 905 dladm_walk_linkprop(dladm_handle_t handle, datalink_id_t linkid, void *arg, 906 int (*func)(dladm_handle_t, datalink_id_t, const char *, void *)) 907 { 908 dladm_status_t status; 909 datalink_class_t class; 910 uint_t media; 911 int i; 912 913 if (linkid == DATALINK_INVALID_LINKID || func == NULL) 914 return (DLADM_STATUS_BADARG); 915 916 status = dladm_datalink_id2info(handle, linkid, NULL, &class, &media, 917 NULL, 0); 918 if (status != DLADM_STATUS_OK) 919 return (status); 920 921 /* public */ 922 for (i = 0; i < DLADM_MAX_PROPS; i++) { 923 if (!(prop_table[i].pd_class & class)) 924 continue; 925 926 if (!DATALINK_MEDIA_ACCEPTED(prop_table[i].pd_dmedia, media)) 927 continue; 928 929 if (func(handle, linkid, prop_table[i].pd_name, arg) == 930 DLADM_WALK_TERMINATE) { 931 break; 932 } 933 } 934 935 /* private */ 936 status = i_dladm_walk_linkprop_priv_db(handle, linkid, arg, func); 937 938 return (status); 939 } 940 941 /* 942 * Get linkprop of the given specific link. 943 */ 944 dladm_status_t 945 dladm_get_linkprop(dladm_handle_t handle, datalink_id_t linkid, 946 dladm_prop_type_t type, const char *prop_name, char **prop_val, 947 uint_t *val_cntp) 948 { 949 dladm_status_t status = DLADM_STATUS_OK; 950 datalink_class_t class; 951 uint_t media; 952 prop_desc_t *pdp; 953 uint_t cnt, dld_flags = 0; 954 int i; 955 uint_t perm_flags; 956 957 if (type == DLADM_PROP_VAL_DEFAULT) 958 dld_flags |= MAC_PROP_DEFAULT; 959 else if (type == DLADM_PROP_VAL_MODIFIABLE) 960 dld_flags |= MAC_PROP_POSSIBLE; 961 962 if (linkid == DATALINK_INVALID_LINKID || prop_name == NULL || 963 prop_val == NULL || val_cntp == NULL || *val_cntp == 0) 964 return (DLADM_STATUS_BADARG); 965 966 for (i = 0; i < DLADM_MAX_PROPS; i++) 967 if (strcasecmp(prop_name, prop_table[i].pd_name) == 0) 968 break; 969 970 if (i == DLADM_MAX_PROPS) { 971 if (prop_name[0] == '_') { 972 /* 973 * private property. 974 */ 975 if (type == DLADM_PROP_VAL_PERSISTENT) 976 return (i_dladm_get_linkprop_db(handle, linkid, 977 prop_name, prop_val, val_cntp)); 978 else 979 return (i_dladm_get_priv_prop(handle, linkid, 980 prop_name, prop_val, val_cntp, type, 981 dld_flags)); 982 } else { 983 return (DLADM_STATUS_NOTFOUND); 984 } 985 } 986 987 pdp = &prop_table[i]; 988 989 status = dladm_datalink_id2info(handle, linkid, NULL, &class, &media, 990 NULL, 0); 991 if (status != DLADM_STATUS_OK) 992 return (status); 993 994 if (!(pdp->pd_class & class)) 995 return (DLADM_STATUS_BADARG); 996 997 if (!DATALINK_MEDIA_ACCEPTED(pdp->pd_dmedia, media)) 998 return (DLADM_STATUS_BADARG); 999 1000 switch (type) { 1001 case DLADM_PROP_VAL_CURRENT: 1002 status = pdp->pd_get(handle, pdp, linkid, prop_val, val_cntp, 1003 media, dld_flags, &perm_flags); 1004 break; 1005 1006 case DLADM_PROP_VAL_PERM: 1007 if (pdp->pd_set == NULL) { 1008 perm_flags = MAC_PROP_PERM_READ; 1009 } else { 1010 status = pdp->pd_get(handle, pdp, linkid, prop_val, 1011 val_cntp, media, dld_flags, &perm_flags); 1012 } 1013 1014 *prop_val[0] = '\0'; 1015 *val_cntp = 1; 1016 if (status == DLADM_STATUS_OK) 1017 (void) dladm_perm2str(perm_flags, *prop_val); 1018 break; 1019 1020 case DLADM_PROP_VAL_DEFAULT: 1021 /* 1022 * If defaults are not defined for the property, 1023 * pd_defval.vd_name should be null. If the driver 1024 * has to be contacted for the value, vd_name should 1025 * be the empty string (""). Otherwise, dladm will 1026 * just print whatever is in the table. 1027 */ 1028 if (pdp->pd_defval.vd_name == NULL) { 1029 status = DLADM_STATUS_NOTSUP; 1030 break; 1031 } 1032 1033 if (strlen(pdp->pd_defval.vd_name) == 0) { 1034 status = pdp->pd_get(handle, pdp, linkid, prop_val, 1035 val_cntp, media, dld_flags, &perm_flags); 1036 } else { 1037 (void) strcpy(*prop_val, pdp->pd_defval.vd_name); 1038 } 1039 *val_cntp = 1; 1040 break; 1041 1042 case DLADM_PROP_VAL_MODIFIABLE: 1043 if (pdp->pd_getmod != NULL) { 1044 status = pdp->pd_getmod(handle, pdp, linkid, prop_val, 1045 val_cntp, media, dld_flags, &perm_flags); 1046 break; 1047 } 1048 cnt = pdp->pd_noptval; 1049 if (cnt == 0) { 1050 status = DLADM_STATUS_NOTSUP; 1051 } else if (cnt > *val_cntp) { 1052 status = DLADM_STATUS_TOOSMALL; 1053 } else { 1054 for (i = 0; i < cnt; i++) { 1055 (void) strcpy(prop_val[i], 1056 pdp->pd_optval[i].vd_name); 1057 } 1058 *val_cntp = cnt; 1059 } 1060 break; 1061 case DLADM_PROP_VAL_PERSISTENT: 1062 if (pdp->pd_flags & PD_TEMPONLY) 1063 return (DLADM_STATUS_TEMPONLY); 1064 status = i_dladm_get_linkprop_db(handle, linkid, prop_name, 1065 prop_val, val_cntp); 1066 break; 1067 default: 1068 status = DLADM_STATUS_BADARG; 1069 break; 1070 } 1071 1072 return (status); 1073 } 1074 1075 /* 1076 * Get linkprop of the given specific link and run any possible conversion 1077 * of the values using the check function for the property. Fails if the 1078 * check function doesn't succeed for the property value. 1079 */ 1080 dladm_status_t 1081 dladm_get_linkprop_values(dladm_handle_t handle, datalink_id_t linkid, 1082 dladm_prop_type_t type, const char *prop_name, uint_t *ret_val, 1083 uint_t *val_cntp) 1084 { 1085 dladm_status_t status; 1086 datalink_class_t class; 1087 uint_t media; 1088 prop_desc_t *pdp; 1089 uint_t dld_flags; 1090 int valc, i; 1091 char **prop_val; 1092 uint_t perm_flags; 1093 1094 if (linkid == DATALINK_INVALID_LINKID || prop_name == NULL || 1095 ret_val == NULL || val_cntp == NULL || *val_cntp == 0) 1096 return (DLADM_STATUS_BADARG); 1097 1098 for (pdp = prop_table; pdp < prop_table + DLADM_MAX_PROPS; pdp++) 1099 if (strcasecmp(prop_name, pdp->pd_name) == 0) 1100 break; 1101 1102 if (pdp == prop_table + DLADM_MAX_PROPS) 1103 return (DLADM_STATUS_NOTFOUND); 1104 1105 if (pdp->pd_flags & PD_CHECK_ALLOC) 1106 return (DLADM_STATUS_BADARG); 1107 1108 status = dladm_datalink_id2info(handle, linkid, NULL, &class, &media, 1109 NULL, 0); 1110 if (status != DLADM_STATUS_OK) 1111 return (status); 1112 1113 if (!(pdp->pd_class & class)) 1114 return (DLADM_STATUS_BADARG); 1115 1116 if (!DATALINK_MEDIA_ACCEPTED(pdp->pd_dmedia, media)) 1117 return (DLADM_STATUS_BADARG); 1118 1119 prop_val = malloc(*val_cntp * sizeof (*prop_val) + 1120 *val_cntp * DLADM_PROP_VAL_MAX); 1121 if (prop_val == NULL) 1122 return (DLADM_STATUS_NOMEM); 1123 for (valc = 0; valc < *val_cntp; valc++) 1124 prop_val[valc] = (char *)(prop_val + *val_cntp) + 1125 valc * DLADM_PROP_VAL_MAX; 1126 1127 dld_flags = (type == DLADM_PROP_VAL_DEFAULT) ? MAC_PROP_DEFAULT : 0; 1128 1129 switch (type) { 1130 case DLADM_PROP_VAL_CURRENT: 1131 status = pdp->pd_get(handle, pdp, linkid, prop_val, val_cntp, 1132 media, dld_flags, &perm_flags); 1133 break; 1134 1135 case DLADM_PROP_VAL_DEFAULT: 1136 /* 1137 * If defaults are not defined for the property, 1138 * pd_defval.vd_name should be null. If the driver 1139 * has to be contacted for the value, vd_name should 1140 * be the empty string (""). Otherwise, dladm will 1141 * just print whatever is in the table. 1142 */ 1143 if (pdp->pd_defval.vd_name == NULL) { 1144 status = DLADM_STATUS_NOTSUP; 1145 break; 1146 } 1147 1148 if (pdp->pd_defval.vd_name[0] != '\0') { 1149 *val_cntp = 1; 1150 *ret_val = pdp->pd_defval.vd_val; 1151 free(prop_val); 1152 return (DLADM_STATUS_OK); 1153 } 1154 status = pdp->pd_get(handle, pdp, linkid, prop_val, val_cntp, 1155 media, dld_flags, &perm_flags); 1156 break; 1157 1158 case DLADM_PROP_VAL_PERSISTENT: 1159 if (pdp->pd_flags & PD_TEMPONLY) 1160 status = DLADM_STATUS_TEMPONLY; 1161 else 1162 status = i_dladm_get_linkprop_db(handle, linkid, 1163 prop_name, prop_val, val_cntp); 1164 break; 1165 1166 default: 1167 status = DLADM_STATUS_BADARG; 1168 break; 1169 } 1170 1171 if (status == DLADM_STATUS_OK) { 1172 if (pdp->pd_check != NULL) { 1173 val_desc_t *vdp; 1174 1175 vdp = malloc(sizeof (val_desc_t) * *val_cntp); 1176 if (vdp == NULL) 1177 status = DLADM_STATUS_NOMEM; 1178 else 1179 status = pdp->pd_check(handle, pdp, linkid, 1180 prop_val, *val_cntp, vdp, media); 1181 if (status == DLADM_STATUS_OK) { 1182 for (valc = 0; valc < *val_cntp; valc++) 1183 ret_val[valc] = vdp[valc].vd_val; 1184 } 1185 free(vdp); 1186 } else { 1187 for (valc = 0; valc < *val_cntp; valc++) { 1188 for (i = 0; i < pdp->pd_noptval; i++) { 1189 if (strcmp(pdp->pd_optval[i].vd_name, 1190 prop_val[valc]) == 0) { 1191 ret_val[valc] = 1192 pdp->pd_optval[i].vd_val; 1193 break; 1194 } 1195 } 1196 if (i == pdp->pd_noptval) { 1197 status = DLADM_STATUS_FAILED; 1198 break; 1199 } 1200 } 1201 } 1202 } 1203 1204 free(prop_val); 1205 1206 return (status); 1207 } 1208 1209 /*ARGSUSED*/ 1210 static int 1211 i_dladm_init_one_prop(dladm_handle_t handle, datalink_id_t linkid, 1212 const char *prop_name, void *arg) 1213 { 1214 char *buf, **propvals; 1215 uint_t i, valcnt = DLADM_MAX_PROP_VALCNT; 1216 dladm_status_t status, *retval = arg; 1217 1218 if ((buf = malloc((sizeof (char *) + DLADM_PROP_VAL_MAX) * 1219 DLADM_MAX_PROP_VALCNT)) == NULL) { 1220 return (DLADM_WALK_CONTINUE); 1221 } 1222 1223 propvals = (char **)(void *)buf; 1224 for (i = 0; i < valcnt; i++) { 1225 propvals[i] = buf + 1226 sizeof (char *) * DLADM_MAX_PROP_VALCNT + 1227 i * DLADM_PROP_VAL_MAX; 1228 } 1229 1230 if (dladm_get_linkprop(handle, linkid, DLADM_PROP_VAL_PERSISTENT, 1231 prop_name, propvals, &valcnt) != DLADM_STATUS_OK) { 1232 goto done; 1233 } 1234 1235 status = dladm_set_linkprop(handle, linkid, prop_name, propvals, 1236 valcnt, DLADM_OPT_ACTIVE); 1237 if (status != DLADM_STATUS_OK) 1238 *retval = status; 1239 1240 done: 1241 if (buf != NULL) 1242 free(buf); 1243 1244 return (DLADM_WALK_CONTINUE); 1245 } 1246 1247 /*ARGSUSED*/ 1248 static int 1249 i_dladm_init_linkprop(dladm_handle_t handle, datalink_id_t linkid, void *arg) 1250 { 1251 datalink_class_t class; 1252 dladm_status_t status; 1253 1254 status = dladm_datalink_id2info(handle, linkid, NULL, &class, NULL, 1255 NULL, 0); 1256 if (status != DLADM_STATUS_OK) 1257 return (DLADM_WALK_TERMINATE); 1258 1259 if ((class & (DATALINK_CLASS_VNIC | DATALINK_CLASS_VLAN)) == 0) 1260 (void) dladm_init_linkprop(handle, linkid, B_TRUE); 1261 1262 return (DLADM_WALK_CONTINUE); 1263 } 1264 1265 dladm_status_t 1266 dladm_init_linkprop(dladm_handle_t handle, datalink_id_t linkid, 1267 boolean_t any_media) 1268 { 1269 dladm_status_t status = DLADM_STATUS_OK; 1270 datalink_media_t dmedia; 1271 uint32_t media; 1272 1273 dmedia = any_media ? DATALINK_ANY_MEDIATYPE : DL_WIFI; 1274 1275 if (linkid == DATALINK_ALL_LINKID) { 1276 (void) dladm_walk_datalink_id(i_dladm_init_linkprop, handle, 1277 NULL, DATALINK_CLASS_ALL, dmedia, DLADM_OPT_PERSIST); 1278 } else if (any_media || 1279 ((dladm_datalink_id2info(handle, linkid, NULL, NULL, &media, NULL, 1280 0) == DLADM_STATUS_OK) && 1281 DATALINK_MEDIA_ACCEPTED(dmedia, media))) { 1282 (void) dladm_walk_linkprop(handle, linkid, &status, 1283 i_dladm_init_one_prop); 1284 } 1285 return (status); 1286 } 1287 1288 /* ARGSUSED */ 1289 static dladm_status_t 1290 do_get_zone(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid, 1291 char **prop_val, uint_t *val_cnt, datalink_media_t media, 1292 uint_t flags, uint_t *perm_flags) 1293 { 1294 char zone_name[ZONENAME_MAX]; 1295 zoneid_t zid; 1296 dladm_status_t status; 1297 char *cp; 1298 dld_ioc_macprop_t *dip; 1299 1300 if (flags != 0) 1301 return (DLADM_STATUS_NOTSUP); 1302 1303 dip = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags, 1304 &status, perm_flags); 1305 if (status != DLADM_STATUS_OK) 1306 return (status); 1307 1308 cp = dip->pr_val; 1309 (void) memcpy(&zid, cp, sizeof (zid)); 1310 free(dip); 1311 1312 *val_cnt = 1; 1313 if (zid != GLOBAL_ZONEID) { 1314 if (getzonenamebyid(zid, zone_name, sizeof (zone_name)) < 0) { 1315 return (dladm_errno2status(errno)); 1316 } 1317 1318 (void) strncpy(*prop_val, zone_name, DLADM_PROP_VAL_MAX); 1319 } else { 1320 *prop_val[0] = '\0'; 1321 } 1322 1323 return (DLADM_STATUS_OK); 1324 } 1325 1326 typedef int (*zone_get_devroot_t)(char *, char *, size_t); 1327 1328 static int 1329 i_dladm_get_zone_dev(char *zone_name, char *dev, size_t devlen) 1330 { 1331 char root[MAXPATHLEN]; 1332 zone_get_devroot_t real_zone_get_devroot; 1333 void *dlhandle; 1334 void *sym; 1335 int ret; 1336 1337 if ((dlhandle = dlopen("libzonecfg.so.1", RTLD_LAZY)) == NULL) 1338 return (-1); 1339 1340 if ((sym = dlsym(dlhandle, "zone_get_devroot")) == NULL) { 1341 (void) dlclose(dlhandle); 1342 return (-1); 1343 } 1344 1345 real_zone_get_devroot = (zone_get_devroot_t)sym; 1346 1347 if ((ret = real_zone_get_devroot(zone_name, root, sizeof (root))) == 0) 1348 (void) snprintf(dev, devlen, "%s%s", root, "/dev"); 1349 (void) dlclose(dlhandle); 1350 return (ret); 1351 } 1352 1353 static dladm_status_t 1354 i_dladm_update_deventry(dladm_handle_t handle, zoneid_t zid, 1355 datalink_id_t linkid, boolean_t add) 1356 { 1357 char path[MAXPATHLEN]; 1358 char name[MAXLINKNAMELEN]; 1359 di_prof_t prof = NULL; 1360 char zone_name[ZONENAME_MAX]; 1361 dladm_status_t status; 1362 int ret; 1363 1364 if (getzonenamebyid(zid, zone_name, sizeof (zone_name)) < 0) 1365 return (dladm_errno2status(errno)); 1366 if (i_dladm_get_zone_dev(zone_name, path, sizeof (path)) != 0) 1367 return (dladm_errno2status(errno)); 1368 if (di_prof_init(path, &prof) != 0) 1369 return (dladm_errno2status(errno)); 1370 1371 status = dladm_linkid2legacyname(handle, linkid, name, MAXLINKNAMELEN); 1372 if (status != DLADM_STATUS_OK) 1373 goto cleanup; 1374 1375 if (add) 1376 ret = di_prof_add_dev(prof, name); 1377 else 1378 ret = di_prof_add_exclude(prof, name); 1379 1380 if (ret != 0) { 1381 status = dladm_errno2status(errno); 1382 goto cleanup; 1383 } 1384 1385 if (di_prof_commit(prof) != 0) 1386 status = dladm_errno2status(errno); 1387 cleanup: 1388 if (prof) 1389 di_prof_fini(prof); 1390 1391 return (status); 1392 } 1393 1394 /* ARGSUSED */ 1395 static dladm_status_t 1396 do_set_zone(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid, 1397 val_desc_t *vdp, uint_t val_cnt, uint_t flags, datalink_media_t media) 1398 { 1399 dladm_status_t status = DLADM_STATUS_OK; 1400 zoneid_t zid_old, zid_new; 1401 char *cp; 1402 dld_ioc_macprop_t *dip; 1403 dld_ioc_zid_t *dzp; 1404 1405 if (val_cnt != 1) 1406 return (DLADM_STATUS_BADVALCNT); 1407 1408 dzp = (dld_ioc_zid_t *)vdp->vd_val; 1409 1410 dip = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags, 1411 &status, NULL); 1412 if (status != DLADM_STATUS_OK) 1413 return (status); 1414 1415 cp = dip->pr_val; 1416 (void) memcpy(&zid_old, cp, sizeof (zid_old)); 1417 free(dip); 1418 1419 zid_new = dzp->diz_zid; 1420 if (zid_new == zid_old) 1421 return (DLADM_STATUS_OK); 1422 1423 if ((status = i_dladm_set_public_prop(handle, pdp, linkid, vdp, val_cnt, 1424 flags, media)) != DLADM_STATUS_OK) 1425 return (status); 1426 1427 /* 1428 * It is okay to fail to update the /dev entry (some vanity-named 1429 * links do not have a /dev entry). 1430 */ 1431 if (zid_old != GLOBAL_ZONEID) { 1432 (void) i_dladm_update_deventry(handle, zid_old, linkid, 1433 B_FALSE); 1434 } 1435 if (zid_new != GLOBAL_ZONEID) 1436 (void) i_dladm_update_deventry(handle, zid_new, linkid, B_TRUE); 1437 1438 return (DLADM_STATUS_OK); 1439 } 1440 1441 /* ARGSUSED */ 1442 static dladm_status_t 1443 do_check_zone(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid, 1444 char **prop_val, uint_t val_cnt, val_desc_t *vdp, datalink_media_t media) 1445 { 1446 char *zone_name; 1447 zoneid_t zoneid; 1448 dladm_status_t status = DLADM_STATUS_OK; 1449 dld_ioc_zid_t *dzp; 1450 1451 if (val_cnt != 1) 1452 return (DLADM_STATUS_BADVALCNT); 1453 1454 dzp = malloc(sizeof (dld_ioc_zid_t)); 1455 if (dzp == NULL) 1456 return (DLADM_STATUS_NOMEM); 1457 1458 zone_name = (prop_val != NULL) ? *prop_val : GLOBAL_ZONENAME; 1459 if ((zoneid = getzoneidbyname(zone_name)) == -1) { 1460 status = DLADM_STATUS_BADVAL; 1461 goto done; 1462 } 1463 1464 if (zoneid != GLOBAL_ZONEID) { 1465 ushort_t flags; 1466 1467 if (zone_getattr(zoneid, ZONE_ATTR_FLAGS, &flags, 1468 sizeof (flags)) < 0) { 1469 status = dladm_errno2status(errno); 1470 goto done; 1471 } 1472 1473 if (!(flags & ZF_NET_EXCL)) { 1474 status = DLADM_STATUS_BADVAL; 1475 goto done; 1476 } 1477 } 1478 1479 (void) memset(dzp, 0, sizeof (dld_ioc_zid_t)); 1480 1481 dzp->diz_zid = zoneid; 1482 dzp->diz_linkid = linkid; 1483 1484 vdp->vd_val = (uintptr_t)dzp; 1485 return (DLADM_STATUS_OK); 1486 done: 1487 free(dzp); 1488 return (status); 1489 } 1490 1491 /* ARGSUSED */ 1492 static dladm_status_t 1493 i_dladm_maxbw_get(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid, 1494 char **prop_val, uint_t *val_cnt, datalink_media_t media, 1495 uint_t flags, uint_t *perm_flags) 1496 { 1497 dld_ioc_macprop_t *dip; 1498 mac_resource_props_t mrp; 1499 dladm_status_t status; 1500 1501 dip = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags, 1502 &status, perm_flags); 1503 if (dip == NULL) 1504 return (status); 1505 1506 bcopy(dip->pr_val, &mrp, sizeof (mac_resource_props_t)); 1507 free(dip); 1508 1509 if ((mrp.mrp_mask & MRP_MAXBW) == 0) { 1510 (*prop_val)[0] = '\0'; 1511 } else { 1512 (void) dladm_bw2str(mrp.mrp_maxbw, prop_val[0]); 1513 } 1514 *val_cnt = 1; 1515 return (DLADM_STATUS_OK); 1516 } 1517 1518 /* ARGSUSED */ 1519 static dladm_status_t 1520 do_check_maxbw(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid, 1521 char **prop_val, uint_t val_cnt, val_desc_t *vdp, datalink_media_t media) 1522 { 1523 uint64_t *maxbw; 1524 dladm_status_t status = DLADM_STATUS_OK; 1525 1526 if (val_cnt != 1) 1527 return (DLADM_STATUS_BADVALCNT); 1528 1529 maxbw = malloc(sizeof (uint64_t)); 1530 if (maxbw == NULL) 1531 return (DLADM_STATUS_NOMEM); 1532 1533 status = dladm_str2bw(*prop_val, maxbw); 1534 if (status != DLADM_STATUS_OK) { 1535 free(maxbw); 1536 return (status); 1537 } 1538 1539 if ((*maxbw < MRP_MAXBW_MINVAL) && (*maxbw != 0)) { 1540 free(maxbw); 1541 return (DLADM_STATUS_MINMAXBW); 1542 } 1543 1544 vdp->vd_val = (uintptr_t)maxbw; 1545 return (DLADM_STATUS_OK); 1546 } 1547 1548 /* ARGSUSED */ 1549 dladm_status_t 1550 do_extract_maxbw(val_desc_t *vdp, uint_t cnt, void *arg) 1551 { 1552 mac_resource_props_t *mrp = arg; 1553 1554 bcopy((char *)vdp->vd_val, &mrp->mrp_maxbw, sizeof (uint64_t)); 1555 mrp->mrp_mask |= MRP_MAXBW; 1556 1557 return (DLADM_STATUS_OK); 1558 } 1559 1560 /* ARGSUSED */ 1561 static dladm_status_t 1562 i_dladm_cpus_get(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid, 1563 char **prop_val, uint_t *val_cnt, datalink_media_t media, 1564 uint_t flags, uint_t *perm_flags) 1565 { 1566 dld_ioc_macprop_t *dip; 1567 mac_resource_props_t mrp; 1568 int i; 1569 uint32_t ncpus; 1570 uchar_t *cp; 1571 dladm_status_t status; 1572 1573 dip = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags, 1574 &status, perm_flags); 1575 if (dip == NULL) 1576 return (status); 1577 1578 cp = (uchar_t *)dip->pr_val; 1579 (void) memcpy(&mrp, cp, sizeof (mac_resource_props_t)); 1580 free(dip); 1581 1582 ncpus = mrp.mrp_ncpus; 1583 1584 if (ncpus > *val_cnt) 1585 return (DLADM_STATUS_TOOSMALL); 1586 1587 if (ncpus == 0) { 1588 (*prop_val)[0] = '\0'; 1589 *val_cnt = 1; 1590 return (DLADM_STATUS_OK); 1591 } 1592 1593 *val_cnt = ncpus; 1594 for (i = 0; i < ncpus; i++) { 1595 (void) snprintf(prop_val[i], DLADM_PROP_VAL_MAX, 1596 "%u", mrp.mrp_cpu[i]); 1597 } 1598 return (DLADM_STATUS_OK); 1599 } 1600 1601 /* ARGSUSED */ 1602 static dladm_status_t 1603 do_set_res(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid, 1604 val_desc_t *vdp, uint_t val_cnt, uint_t flags, datalink_media_t media) 1605 { 1606 mac_resource_props_t mrp; 1607 dladm_status_t status = DLADM_STATUS_OK; 1608 dld_ioc_macprop_t *dip; 1609 1610 bzero(&mrp, sizeof (mac_resource_props_t)); 1611 dip = i_dladm_buf_alloc_by_name(0, linkid, pdp->pd_name, 1612 flags, &status); 1613 1614 if (dip == NULL) 1615 return (status); 1616 1617 if (vdp->vd_val == RESET_VAL) { 1618 switch (dip->pr_num) { 1619 case MAC_PROP_MAXBW: 1620 mrp.mrp_maxbw = MRP_MAXBW_RESETVAL; 1621 mrp.mrp_mask = MRP_MAXBW; 1622 break; 1623 case MAC_PROP_PRIO: 1624 mrp.mrp_priority = MPL_RESET; 1625 mrp.mrp_mask = MRP_PRIORITY; 1626 break; 1627 default: 1628 free(dip); 1629 return (DLADM_STATUS_BADARG); 1630 } 1631 } else { 1632 switch (dip->pr_num) { 1633 case MAC_PROP_MAXBW: 1634 bcopy((void *)vdp->vd_val, &mrp.mrp_maxbw, 1635 sizeof (uint64_t)); 1636 mrp.mrp_mask = MRP_MAXBW; 1637 break; 1638 case MAC_PROP_PRIO: 1639 bcopy((void *)vdp->vd_val, &mrp.mrp_priority, 1640 sizeof (mac_priority_level_t)); 1641 mrp.mrp_mask = MRP_PRIORITY; 1642 break; 1643 default: 1644 free(dip); 1645 return (DLADM_STATUS_BADARG); 1646 } 1647 } 1648 1649 (void) memcpy(dip->pr_val, &mrp, dip->pr_valsize); 1650 status = i_dladm_macprop(handle, dip, B_TRUE); 1651 free(dip); 1652 return (status); 1653 } 1654 1655 /* ARGSUSED */ 1656 static dladm_status_t 1657 do_set_cpus(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid, 1658 val_desc_t *vdp, uint_t val_cnt, uint_t flags, datalink_media_t media) 1659 { 1660 mac_resource_props_t mrp; 1661 dladm_status_t status; 1662 dld_ioc_macprop_t *dip; 1663 datalink_class_t class; 1664 1665 /* 1666 * CPU bindings can be set on VNIC and regular physical links. 1667 * However VNICs fails the dladm_phys_info test(). So apply 1668 * the phys_info test only on physical links. 1669 */ 1670 if ((status = dladm_datalink_id2info(handle, linkid, NULL, &class, 1671 NULL, NULL, 0)) != DLADM_STATUS_OK) { 1672 return (status); 1673 } 1674 1675 /* 1676 * We set intr_cpu to -1. The interrupt will be retargetted, 1677 * if possible when the setup is complete in MAC. 1678 */ 1679 bzero(&mrp, sizeof (mac_resource_props_t)); 1680 mrp.mrp_mask = MRP_CPUS; 1681 if (vdp != NULL && vdp->vd_val != RESET_VAL) { 1682 mac_resource_props_t *vmrp; 1683 1684 vmrp = (mac_resource_props_t *)vdp->vd_val; 1685 if (vmrp->mrp_ncpus > 0) { 1686 bcopy(vmrp, &mrp, sizeof (mac_resource_props_t)); 1687 mrp.mrp_mask = MRP_CPUS; 1688 } 1689 mrp.mrp_mask |= MRP_CPUS_USERSPEC; 1690 mrp.mrp_fanout_mode = MCM_CPUS; 1691 mrp.mrp_intr_cpu = -1; 1692 } 1693 1694 dip = i_dladm_buf_alloc_by_name(0, linkid, pdp->pd_name, 1695 flags, &status); 1696 if (dip == NULL) 1697 return (status); 1698 1699 (void) memcpy(dip->pr_val, &mrp, dip->pr_valsize); 1700 status = i_dladm_macprop(handle, dip, B_TRUE); 1701 free(dip); 1702 return (status); 1703 } 1704 1705 /* ARGSUSED */ 1706 static dladm_status_t 1707 do_check_cpus(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid, 1708 char **prop_val, uint_t val_cnt, val_desc_t *vdp, datalink_media_t media) 1709 { 1710 uint32_t cpuid; 1711 int i, j, rc; 1712 long nproc = sysconf(_SC_NPROCESSORS_CONF); 1713 mac_resource_props_t *mrp; 1714 1715 mrp = malloc(sizeof (mac_resource_props_t)); 1716 if (mrp == NULL) 1717 return (DLADM_STATUS_NOMEM); 1718 1719 for (i = 0; i < val_cnt; i++) { 1720 errno = 0; 1721 cpuid = strtol(prop_val[i], (char **)NULL, 10); 1722 if (errno != 0 || cpuid >= nproc) { 1723 free(mrp); 1724 return (DLADM_STATUS_CPUMAX); 1725 } 1726 rc = p_online(cpuid, P_STATUS); 1727 if (rc < 1) { 1728 free(mrp); 1729 return (DLADM_STATUS_CPUERR); 1730 } 1731 if (rc != P_ONLINE) { 1732 free(mrp); 1733 return (DLADM_STATUS_CPUNOTONLINE); 1734 } 1735 mrp->mrp_cpu[i] = cpuid; 1736 } 1737 mrp->mrp_ncpus = (uint32_t)val_cnt; 1738 1739 /* Check for duplicates */ 1740 for (i = 0; i < val_cnt; i++) { 1741 for (j = 0; j < val_cnt; j++) { 1742 if (i != j && mrp->mrp_cpu[i] == mrp->mrp_cpu[j]) { 1743 free(mrp); 1744 return (DLADM_STATUS_BADARG); 1745 } 1746 } 1747 } 1748 vdp->vd_val = (uintptr_t)mrp; 1749 1750 return (DLADM_STATUS_OK); 1751 } 1752 1753 /* ARGSUSED */ 1754 dladm_status_t 1755 do_extract_cpus(val_desc_t *vdp, uint_t cnt, void *arg) 1756 { 1757 mac_resource_props_t *mrp = arg; 1758 mac_resource_props_t *vmrp = (mac_resource_props_t *)vdp->vd_val; 1759 int i; 1760 1761 for (i = 0; i < vmrp->mrp_ncpus; i++) { 1762 mrp->mrp_cpu[i] = vmrp->mrp_cpu[i]; 1763 } 1764 mrp->mrp_ncpus = vmrp->mrp_ncpus; 1765 mrp->mrp_mask |= (MRP_CPUS|MRP_CPUS_USERSPEC); 1766 mrp->mrp_fanout_mode = MCM_CPUS; 1767 mrp->mrp_intr_cpu = -1; 1768 1769 return (DLADM_STATUS_OK); 1770 } 1771 1772 /* ARGSUSED */ 1773 static dladm_status_t 1774 i_dladm_priority_get(dladm_handle_t handle, prop_desc_t *pdp, 1775 datalink_id_t linkid, char **prop_val, uint_t *val_cnt, 1776 datalink_media_t media, uint_t flags, uint_t *perm_flags) 1777 { 1778 dld_ioc_macprop_t *dip; 1779 mac_resource_props_t mrp; 1780 mac_priority_level_t pri; 1781 dladm_status_t status; 1782 1783 dip = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags, 1784 &status, perm_flags); 1785 if (dip == NULL) 1786 return (status); 1787 1788 bcopy(dip->pr_val, &mrp, sizeof (mac_resource_props_t)); 1789 free(dip); 1790 1791 pri = ((mrp.mrp_mask & MRP_PRIORITY) == 0) ? MPL_HIGH : 1792 mrp.mrp_priority; 1793 1794 (void) dladm_pri2str(pri, prop_val[0]); 1795 *val_cnt = 1; 1796 return (DLADM_STATUS_OK); 1797 } 1798 1799 /* ARGSUSED */ 1800 static dladm_status_t 1801 do_check_priority(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid, 1802 char **prop_val, uint_t val_cnt, val_desc_t *vdp, datalink_media_t media) 1803 { 1804 mac_priority_level_t *pri; 1805 dladm_status_t status = DLADM_STATUS_OK; 1806 1807 if (val_cnt != 1) 1808 return (DLADM_STATUS_BADVALCNT); 1809 1810 pri = malloc(sizeof (mac_priority_level_t)); 1811 if (pri == NULL) 1812 return (DLADM_STATUS_NOMEM); 1813 1814 status = dladm_str2pri(*prop_val, pri); 1815 if (status != DLADM_STATUS_OK) { 1816 free(pri); 1817 return (status); 1818 } 1819 1820 if (*pri < MPL_LOW || *pri > MPL_HIGH) { 1821 free(pri); 1822 return (DLADM_STATUS_BADVAL); 1823 } 1824 1825 vdp->vd_val = (uintptr_t)pri; 1826 return (DLADM_STATUS_OK); 1827 } 1828 1829 /* ARGSUSED */ 1830 dladm_status_t 1831 do_extract_priority(val_desc_t *vdp, uint_t cnt, void *arg) 1832 { 1833 mac_resource_props_t *mrp = arg; 1834 1835 bcopy((char *)vdp->vd_val, &mrp->mrp_priority, 1836 sizeof (mac_priority_level_t)); 1837 mrp->mrp_mask |= MRP_PRIORITY; 1838 1839 return (DLADM_STATUS_OK); 1840 } 1841 1842 /* ARGSUSED */ 1843 static dladm_status_t 1844 do_set_protection(dladm_handle_t handle, prop_desc_t *pdp, 1845 datalink_id_t linkid, val_desc_t *vdp, uint_t val_cnt, 1846 uint_t flags, datalink_media_t media) 1847 { 1848 mac_resource_props_t mrp; 1849 dladm_status_t status = DLADM_STATUS_OK; 1850 dld_ioc_macprop_t *dip; 1851 1852 bzero(&mrp, sizeof (mac_resource_props_t)); 1853 dip = i_dladm_buf_alloc_by_name(0, linkid, "protection", 1854 flags, &status); 1855 1856 if (dip == NULL) 1857 return (status); 1858 1859 if (strcmp(pdp->pd_name, "protection") == 0) { 1860 status = do_extract_protection(vdp, val_cnt, &mrp); 1861 if (status != DLADM_STATUS_OK) 1862 goto done; 1863 1864 } else if (strcmp(pdp->pd_name, "allowed-ips") == 0) { 1865 status = do_extract_allowedips(vdp, val_cnt, &mrp); 1866 if (status != DLADM_STATUS_OK) 1867 goto done; 1868 } else { 1869 status = DLADM_STATUS_BADARG; 1870 goto done; 1871 } 1872 1873 (void) memcpy(dip->pr_val, &mrp, dip->pr_valsize); 1874 status = i_dladm_macprop(handle, dip, B_TRUE); 1875 1876 done: 1877 free(dip); 1878 return (status); 1879 } 1880 1881 /* ARGSUSED */ 1882 static dladm_status_t 1883 do_get_protection(dladm_handle_t handle, prop_desc_t *pdp, 1884 datalink_id_t linkid, char **prop_val, uint_t *val_cnt, 1885 datalink_media_t media, uint_t flags, uint_t *perm_flags) 1886 { 1887 dld_ioc_macprop_t *dip; 1888 mac_resource_props_t mrp; 1889 mac_protect_t *p; 1890 dladm_status_t status; 1891 int i; 1892 1893 dip = i_dladm_get_public_prop(handle, linkid, "protection", flags, 1894 &status, perm_flags); 1895 if (dip == NULL) 1896 return (status); 1897 1898 bcopy(dip->pr_val, &mrp, sizeof (mac_resource_props_t)); 1899 free(dip); 1900 1901 p = &mrp.mrp_protect; 1902 if ((mrp.mrp_mask & MRP_PROTECT) != 0 && 1903 strcmp(pdp->pd_name, "protection") == 0) { 1904 uint32_t cnt = 0, setbits[32]; 1905 1906 dladm_find_setbits32(p->mp_types, setbits, &cnt); 1907 if (cnt > *val_cnt) 1908 return (DLADM_STATUS_BADVALCNT); 1909 1910 for (i = 0; i < cnt; i++) 1911 (void) dladm_protect2str(setbits[i], prop_val[i]); 1912 1913 *val_cnt = cnt; 1914 return (DLADM_STATUS_OK); 1915 } 1916 1917 if (p->mp_ipaddrcnt > 0 && 1918 strcmp(pdp->pd_name, "allowed-ips") == 0) { 1919 if (p->mp_ipaddrcnt > *val_cnt) 1920 return (DLADM_STATUS_BADVALCNT); 1921 1922 for (i = 0; i < p->mp_ipaddrcnt; i++) { 1923 (void) dladm_ipv4addr2str(&p->mp_ipaddrs[i], 1924 prop_val[i]); 1925 } 1926 *val_cnt = p->mp_ipaddrcnt; 1927 return (DLADM_STATUS_OK); 1928 } 1929 1930 *val_cnt = 0; 1931 return (DLADM_STATUS_OK); 1932 } 1933 1934 dladm_status_t 1935 do_extract_protection(val_desc_t *vdp, uint_t cnt, void *arg) 1936 { 1937 mac_resource_props_t *mrp = arg; 1938 uint32_t types = 0; 1939 int i; 1940 1941 for (i = 0; i < cnt; i++) 1942 types |= (uint32_t)vdp[i].vd_val; 1943 1944 mrp->mrp_protect.mp_types = types; 1945 mrp->mrp_mask |= MRP_PROTECT; 1946 return (DLADM_STATUS_OK); 1947 } 1948 1949 dladm_status_t 1950 do_extract_allowedips(val_desc_t *vdp, uint_t cnt, void *arg) 1951 { 1952 mac_resource_props_t *mrp = arg; 1953 mac_protect_t *p = &mrp->mrp_protect; 1954 int i; 1955 1956 if (vdp->vd_val == 0) { 1957 cnt = (uint_t)-1; 1958 } else { 1959 for (i = 0; i < cnt; i++) 1960 p->mp_ipaddrs[i] = (ipaddr_t)vdp[i].vd_val; 1961 } 1962 p->mp_ipaddrcnt = cnt; 1963 mrp->mrp_mask |= MRP_PROTECT; 1964 return (DLADM_STATUS_OK); 1965 } 1966 1967 /* ARGSUSED */ 1968 static dladm_status_t 1969 do_check_allowedips(dladm_handle_t handle, prop_desc_t *pdp, 1970 datalink_id_t linkid, char **prop_val, uint_t val_cnt, 1971 val_desc_t *vdp, datalink_media_t media) 1972 { 1973 dladm_status_t status; 1974 ipaddr_t addr; 1975 int i; 1976 1977 if (val_cnt > MPT_MAXIPADDR) 1978 return (DLADM_STATUS_BADVALCNT); 1979 1980 for (i = 0; i < val_cnt; i++) { 1981 status = dladm_str2ipv4addr(prop_val[i], &addr); 1982 if (status != DLADM_STATUS_OK) 1983 return (status); 1984 1985 if (addr == 0) 1986 return (DLADM_STATUS_BADVAL); 1987 1988 vdp[i].vd_val = (uintptr_t)addr; 1989 } 1990 return (DLADM_STATUS_OK); 1991 } 1992 1993 /* ARGSUSED */ 1994 static dladm_status_t 1995 do_get_autopush(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid, 1996 char **prop_val, uint_t *val_cnt, datalink_media_t media, 1997 uint_t flags, uint_t *perm_flags) 1998 { 1999 struct dlautopush dlap; 2000 int i, len; 2001 dladm_status_t status; 2002 dld_ioc_macprop_t *dip; 2003 2004 if (flags & MAC_PROP_DEFAULT) 2005 return (DLADM_STATUS_NOTDEFINED); 2006 2007 *val_cnt = 1; 2008 dip = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags, 2009 &status, perm_flags); 2010 if (dip == NULL) { 2011 (*prop_val)[0] = '\0'; 2012 return (DLADM_STATUS_OK); 2013 } 2014 (void) memcpy(&dlap, dip->pr_val, sizeof (dlap)); 2015 2016 for (i = 0, len = 0; i < dlap.dap_npush; i++) { 2017 if (i != 0) { 2018 (void) snprintf(*prop_val + len, 2019 DLADM_PROP_VAL_MAX - len, "%c", AP_DELIMITER); 2020 len += 1; 2021 } 2022 (void) snprintf(*prop_val + len, DLADM_PROP_VAL_MAX - len, 2023 "%s", dlap.dap_aplist[i]); 2024 len += strlen(dlap.dap_aplist[i]); 2025 if (dlap.dap_anchor - 1 == i) { 2026 (void) snprintf(*prop_val + len, 2027 DLADM_PROP_VAL_MAX - len, "%c%s", AP_DELIMITER, 2028 AP_ANCHOR); 2029 len += (strlen(AP_ANCHOR) + 1); 2030 } 2031 } 2032 free(dip); 2033 done: 2034 return (DLADM_STATUS_OK); 2035 } 2036 2037 /* 2038 * Add the specified module to the dlautopush structure; returns a 2039 * DLADM_STATUS_* code. 2040 */ 2041 dladm_status_t 2042 i_dladm_add_ap_module(const char *module, struct dlautopush *dlap) 2043 { 2044 if ((strlen(module) == 0) || (strlen(module) > FMNAMESZ)) 2045 return (DLADM_STATUS_BADVAL); 2046 2047 if (strncasecmp(module, AP_ANCHOR, strlen(AP_ANCHOR)) == 0) { 2048 /* 2049 * We don't allow multiple anchors, and the anchor must 2050 * be after at least one module. 2051 */ 2052 if (dlap->dap_anchor != 0) 2053 return (DLADM_STATUS_BADVAL); 2054 if (dlap->dap_npush == 0) 2055 return (DLADM_STATUS_BADVAL); 2056 2057 dlap->dap_anchor = dlap->dap_npush; 2058 return (DLADM_STATUS_OK); 2059 } 2060 if (dlap->dap_npush >= MAXAPUSH) 2061 return (DLADM_STATUS_BADVALCNT); 2062 2063 (void) strlcpy(dlap->dap_aplist[dlap->dap_npush++], module, 2064 FMNAMESZ + 1); 2065 2066 return (DLADM_STATUS_OK); 2067 } 2068 2069 /* 2070 * Currently, both '.' and ' '(space) can be used as the delimiters between 2071 * autopush modules. The former is used in dladm set-linkprop, and the 2072 * latter is used in the autopush(1M) file. 2073 */ 2074 /* ARGSUSED */ 2075 static dladm_status_t 2076 do_check_autopush(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid, 2077 char **prop_val, uint_t val_cnt, val_desc_t *vdp, datalink_media_t media) 2078 { 2079 char *module; 2080 struct dlautopush *dlap; 2081 dladm_status_t status; 2082 char val[DLADM_PROP_VAL_MAX]; 2083 char delimiters[4]; 2084 2085 if (val_cnt != 1) 2086 return (DLADM_STATUS_BADVALCNT); 2087 2088 if (prop_val != NULL) { 2089 dlap = malloc(sizeof (struct dlautopush)); 2090 if (dlap == NULL) 2091 return (DLADM_STATUS_NOMEM); 2092 2093 (void) memset(dlap, 0, sizeof (struct dlautopush)); 2094 (void) snprintf(delimiters, 4, " %c\n", AP_DELIMITER); 2095 bcopy(*prop_val, val, DLADM_PROP_VAL_MAX); 2096 module = strtok(val, delimiters); 2097 while (module != NULL) { 2098 status = i_dladm_add_ap_module(module, dlap); 2099 if (status != DLADM_STATUS_OK) 2100 return (status); 2101 module = strtok(NULL, delimiters); 2102 } 2103 2104 vdp->vd_val = (uintptr_t)dlap; 2105 } else { 2106 vdp->vd_val = 0; 2107 } 2108 return (DLADM_STATUS_OK); 2109 } 2110 2111 #define WLDP_BUFSIZE (MAX_BUF_LEN - WIFI_BUF_OFFSET) 2112 2113 /* ARGSUSED */ 2114 static dladm_status_t 2115 do_get_rate_common(dladm_handle_t handle, prop_desc_t *pdp, 2116 datalink_id_t linkid, char **prop_val, uint_t *val_cnt, uint_t id, 2117 uint_t *perm_flags) 2118 { 2119 wl_rates_t *wrp; 2120 uint_t i; 2121 dladm_status_t status = DLADM_STATUS_OK; 2122 2123 wrp = malloc(WLDP_BUFSIZE); 2124 if (wrp == NULL) 2125 return (DLADM_STATUS_NOMEM); 2126 2127 status = i_dladm_wlan_param(handle, linkid, wrp, id, WLDP_BUFSIZE, 2128 B_FALSE); 2129 if (status != DLADM_STATUS_OK) 2130 goto done; 2131 2132 if (wrp->wl_rates_num > *val_cnt) { 2133 status = DLADM_STATUS_TOOSMALL; 2134 goto done; 2135 } 2136 2137 if (wrp->wl_rates_rates[0] == 0) { 2138 prop_val[0][0] = '\0'; 2139 *val_cnt = 1; 2140 goto done; 2141 } 2142 2143 for (i = 0; i < wrp->wl_rates_num; i++) { 2144 (void) snprintf(prop_val[i], DLADM_STRSIZE, "%.*f", 2145 wrp->wl_rates_rates[i] % 2, 2146 (float)wrp->wl_rates_rates[i] / 2); 2147 } 2148 *val_cnt = wrp->wl_rates_num; 2149 *perm_flags = MAC_PROP_PERM_RW; 2150 2151 done: 2152 free(wrp); 2153 return (status); 2154 } 2155 2156 static dladm_status_t 2157 do_get_rate_prop(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid, 2158 char **prop_val, uint_t *val_cnt, datalink_media_t media, 2159 uint_t flags, uint_t *perm_flags) 2160 { 2161 if (media != DL_WIFI) { 2162 return (i_dladm_speed_get(handle, pdp, linkid, prop_val, 2163 val_cnt, flags, perm_flags)); 2164 } 2165 2166 return (do_get_rate_common(handle, pdp, linkid, prop_val, val_cnt, 2167 MAC_PROP_WL_DESIRED_RATES, perm_flags)); 2168 } 2169 2170 /* ARGSUSED */ 2171 static dladm_status_t 2172 do_get_rate_mod(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 switch (media) { 2177 case DL_ETHER: 2178 /* 2179 * Speed for ethernet links is unbounded. E.g., 802.11b 2180 * links can have a speed of 5.5 Gbps. 2181 */ 2182 return (DLADM_STATUS_NOTSUP); 2183 2184 case DL_WIFI: 2185 return (do_get_rate_common(handle, pdp, linkid, prop_val, 2186 val_cnt, MAC_PROP_WL_SUPPORTED_RATES, perm_flags)); 2187 default: 2188 return (DLADM_STATUS_BADARG); 2189 } 2190 } 2191 2192 static dladm_status_t 2193 do_set_rate(dladm_handle_t handle, datalink_id_t linkid, 2194 dladm_wlan_rates_t *rates) 2195 { 2196 int i; 2197 uint_t len; 2198 wl_rates_t *wrp; 2199 dladm_status_t status = DLADM_STATUS_OK; 2200 2201 wrp = malloc(WLDP_BUFSIZE); 2202 if (wrp == NULL) 2203 return (DLADM_STATUS_NOMEM); 2204 2205 bzero(wrp, WLDP_BUFSIZE); 2206 for (i = 0; i < rates->wr_cnt; i++) 2207 wrp->wl_rates_rates[i] = rates->wr_rates[i]; 2208 wrp->wl_rates_num = rates->wr_cnt; 2209 2210 len = offsetof(wl_rates_t, wl_rates_rates) + 2211 (rates->wr_cnt * sizeof (char)) + WIFI_BUF_OFFSET; 2212 status = i_dladm_wlan_param(handle, linkid, wrp, 2213 MAC_PROP_WL_DESIRED_RATES, len, B_TRUE); 2214 2215 free(wrp); 2216 return (status); 2217 } 2218 2219 /* ARGSUSED */ 2220 static dladm_status_t 2221 do_set_rate_prop(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid, 2222 val_desc_t *vdp, uint_t val_cnt, uint_t flags, datalink_media_t media) 2223 { 2224 dladm_wlan_rates_t rates; 2225 dladm_status_t status; 2226 2227 /* 2228 * can currently set rate on WIFI links only. 2229 */ 2230 if (media != DL_WIFI) 2231 return (DLADM_STATUS_PROPRDONLY); 2232 2233 if (val_cnt != 1) 2234 return (DLADM_STATUS_BADVALCNT); 2235 2236 rates.wr_cnt = 1; 2237 rates.wr_rates[0] = vdp[0].vd_val; 2238 2239 status = do_set_rate(handle, linkid, &rates); 2240 2241 done: 2242 return (status); 2243 } 2244 2245 /* ARGSUSED */ 2246 static dladm_status_t 2247 do_check_rate(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid, 2248 char **prop_val, uint_t val_cnt, val_desc_t *vdp, datalink_media_t media) 2249 { 2250 int i; 2251 uint_t modval_cnt = MAX_SUPPORT_RATES; 2252 char *buf, **modval; 2253 dladm_status_t status; 2254 uint_t perm_flags; 2255 2256 if (val_cnt != 1) 2257 return (DLADM_STATUS_BADVALCNT); 2258 2259 buf = malloc((sizeof (char *) + DLADM_STRSIZE) * 2260 MAX_SUPPORT_RATES); 2261 if (buf == NULL) { 2262 status = DLADM_STATUS_NOMEM; 2263 goto done; 2264 } 2265 2266 modval = (char **)(void *)buf; 2267 for (i = 0; i < MAX_SUPPORT_RATES; i++) { 2268 modval[i] = buf + sizeof (char *) * MAX_SUPPORT_RATES + 2269 i * DLADM_STRSIZE; 2270 } 2271 2272 status = do_get_rate_mod(handle, NULL, linkid, modval, &modval_cnt, 2273 media, 0, &perm_flags); 2274 if (status != DLADM_STATUS_OK) 2275 goto done; 2276 2277 for (i = 0; i < modval_cnt; i++) { 2278 if (strcasecmp(*prop_val, modval[i]) == 0) { 2279 vdp->vd_val = (uintptr_t)(uint_t) 2280 (atof(*prop_val) * 2); 2281 status = DLADM_STATUS_OK; 2282 break; 2283 } 2284 } 2285 if (i == modval_cnt) 2286 status = DLADM_STATUS_BADVAL; 2287 done: 2288 free(buf); 2289 return (status); 2290 } 2291 2292 static dladm_status_t 2293 do_get_phyconf(dladm_handle_t handle, datalink_id_t linkid, void *buf, 2294 int buflen) 2295 { 2296 return (i_dladm_wlan_param(handle, linkid, buf, MAC_PROP_WL_PHY_CONFIG, 2297 buflen, B_FALSE)); 2298 } 2299 2300 /* ARGSUSED */ 2301 static dladm_status_t 2302 do_get_channel_prop(dladm_handle_t handle, prop_desc_t *pdp, 2303 datalink_id_t linkid, char **prop_val, uint_t *val_cnt, 2304 datalink_media_t media, uint_t flags, uint_t *perm_flags) 2305 { 2306 uint32_t channel; 2307 char buf[WLDP_BUFSIZE]; 2308 dladm_status_t status = DLADM_STATUS_OK; 2309 wl_phy_conf_t wl_phy_conf; 2310 2311 if ((status = do_get_phyconf(handle, linkid, buf, sizeof (buf))) 2312 != DLADM_STATUS_OK) 2313 goto done; 2314 2315 (void) memcpy(&wl_phy_conf, buf, sizeof (wl_phy_conf)); 2316 if (!i_dladm_wlan_convert_chan(&wl_phy_conf, &channel)) { 2317 status = DLADM_STATUS_NOTFOUND; 2318 goto done; 2319 } 2320 2321 (void) snprintf(*prop_val, DLADM_STRSIZE, "%u", channel); 2322 *val_cnt = 1; 2323 *perm_flags = MAC_PROP_PERM_READ; 2324 done: 2325 return (status); 2326 } 2327 2328 static dladm_status_t 2329 do_get_powermode(dladm_handle_t handle, datalink_id_t linkid, void *buf, 2330 int buflen) 2331 { 2332 return (i_dladm_wlan_param(handle, linkid, buf, MAC_PROP_WL_POWER_MODE, 2333 buflen, B_FALSE)); 2334 } 2335 2336 /* ARGSUSED */ 2337 static dladm_status_t 2338 do_get_powermode_prop(dladm_handle_t handle, prop_desc_t *pdp, 2339 datalink_id_t linkid, char **prop_val, uint_t *val_cnt, 2340 datalink_media_t media, uint_t flags, uint_t *perm_flags) 2341 { 2342 wl_ps_mode_t mode; 2343 const char *s; 2344 char buf[WLDP_BUFSIZE]; 2345 dladm_status_t status = DLADM_STATUS_OK; 2346 2347 if ((status = do_get_powermode(handle, linkid, buf, sizeof (buf))) 2348 != DLADM_STATUS_OK) 2349 goto done; 2350 2351 (void) memcpy(&mode, buf, sizeof (mode)); 2352 switch (mode.wl_ps_mode) { 2353 case WL_PM_AM: 2354 s = "off"; 2355 break; 2356 case WL_PM_MPS: 2357 s = "max"; 2358 break; 2359 case WL_PM_FAST: 2360 s = "fast"; 2361 break; 2362 default: 2363 status = DLADM_STATUS_NOTFOUND; 2364 goto done; 2365 } 2366 (void) snprintf(*prop_val, DLADM_STRSIZE, "%s", s); 2367 *val_cnt = 1; 2368 *perm_flags = MAC_PROP_PERM_RW; 2369 done: 2370 return (status); 2371 } 2372 2373 static dladm_status_t 2374 do_set_powermode(dladm_handle_t handle, datalink_id_t linkid, 2375 dladm_wlan_powermode_t *pm) 2376 { 2377 wl_ps_mode_t ps_mode; 2378 2379 (void) memset(&ps_mode, 0xff, sizeof (ps_mode)); 2380 2381 switch (*pm) { 2382 case DLADM_WLAN_PM_OFF: 2383 ps_mode.wl_ps_mode = WL_PM_AM; 2384 break; 2385 case DLADM_WLAN_PM_MAX: 2386 ps_mode.wl_ps_mode = WL_PM_MPS; 2387 break; 2388 case DLADM_WLAN_PM_FAST: 2389 ps_mode.wl_ps_mode = WL_PM_FAST; 2390 break; 2391 default: 2392 return (DLADM_STATUS_NOTSUP); 2393 } 2394 return (i_dladm_wlan_param(handle, linkid, &ps_mode, 2395 MAC_PROP_WL_POWER_MODE, sizeof (ps_mode), B_TRUE)); 2396 } 2397 2398 /* ARGSUSED */ 2399 static dladm_status_t 2400 do_set_powermode_prop(dladm_handle_t handle, prop_desc_t *pdp, 2401 datalink_id_t linkid, val_desc_t *vdp, uint_t val_cnt, uint_t flags, 2402 datalink_media_t media) 2403 { 2404 dladm_wlan_powermode_t powermode = (dladm_wlan_powermode_t)vdp->vd_val; 2405 dladm_status_t status; 2406 2407 if (val_cnt != 1) 2408 return (DLADM_STATUS_BADVALCNT); 2409 2410 status = do_set_powermode(handle, linkid, &powermode); 2411 2412 return (status); 2413 } 2414 2415 static dladm_status_t 2416 do_get_radio(dladm_handle_t handle, datalink_id_t linkid, void *buf, int buflen) 2417 { 2418 return (i_dladm_wlan_param(handle, linkid, buf, MAC_PROP_WL_RADIO, 2419 buflen, B_FALSE)); 2420 } 2421 2422 /* ARGSUSED */ 2423 static dladm_status_t 2424 do_get_radio_prop(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid, 2425 char **prop_val, uint_t *val_cnt, datalink_media_t media, 2426 uint_t flags, uint_t *perm_flags) 2427 { 2428 wl_radio_t radio; 2429 const char *s; 2430 char buf[WLDP_BUFSIZE]; 2431 dladm_status_t status = DLADM_STATUS_OK; 2432 2433 if ((status = do_get_radio(handle, linkid, buf, sizeof (buf))) 2434 != DLADM_STATUS_OK) 2435 goto done; 2436 2437 (void) memcpy(&radio, buf, sizeof (radio)); 2438 switch (radio) { 2439 case B_TRUE: 2440 s = "on"; 2441 break; 2442 case B_FALSE: 2443 s = "off"; 2444 break; 2445 default: 2446 status = DLADM_STATUS_NOTFOUND; 2447 goto done; 2448 } 2449 (void) snprintf(*prop_val, DLADM_STRSIZE, "%s", s); 2450 *val_cnt = 1; 2451 *perm_flags = MAC_PROP_PERM_RW; 2452 done: 2453 return (status); 2454 } 2455 2456 static dladm_status_t 2457 do_set_radio(dladm_handle_t handle, datalink_id_t linkid, 2458 dladm_wlan_radio_t *radio) 2459 { 2460 wl_radio_t r; 2461 2462 switch (*radio) { 2463 case DLADM_WLAN_RADIO_ON: 2464 r = B_TRUE; 2465 break; 2466 case DLADM_WLAN_RADIO_OFF: 2467 r = B_FALSE; 2468 break; 2469 default: 2470 return (DLADM_STATUS_NOTSUP); 2471 } 2472 return (i_dladm_wlan_param(handle, linkid, &r, MAC_PROP_WL_RADIO, 2473 sizeof (r), B_TRUE)); 2474 } 2475 2476 /* ARGSUSED */ 2477 static dladm_status_t 2478 do_set_radio_prop(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid, 2479 val_desc_t *vdp, uint_t val_cnt, uint_t flags, datalink_media_t media) 2480 { 2481 dladm_wlan_radio_t radio = (dladm_wlan_radio_t)vdp->vd_val; 2482 dladm_status_t status; 2483 2484 if (val_cnt != 1) 2485 return (DLADM_STATUS_BADVALCNT); 2486 2487 status = do_set_radio(handle, linkid, &radio); 2488 2489 return (status); 2490 } 2491 2492 /* ARGSUSED */ 2493 static dladm_status_t 2494 do_check_hoplimit(dladm_handle_t handle, prop_desc_t *pdp, 2495 datalink_id_t linkid, char **prop_val, uint_t val_cnt, val_desc_t *vdp, 2496 datalink_media_t media) 2497 { 2498 int32_t hlim; 2499 char *ep; 2500 2501 if (val_cnt != 1) 2502 return (DLADM_STATUS_BADVALCNT); 2503 2504 errno = 0; 2505 hlim = strtol(*prop_val, &ep, 10); 2506 if (errno != 0 || ep == *prop_val || hlim < 1 || 2507 hlim > (int32_t)UINT8_MAX) 2508 return (DLADM_STATUS_BADVAL); 2509 vdp->vd_val = hlim; 2510 return (DLADM_STATUS_OK); 2511 } 2512 2513 /* ARGSUSED */ 2514 static dladm_status_t 2515 do_check_encaplim(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid, 2516 char **prop_val, uint_t val_cnt, val_desc_t *vdp, datalink_media_t media) 2517 { 2518 int32_t elim; 2519 char *ep; 2520 2521 if (media != DL_IPV6) 2522 return (DLADM_STATUS_BADARG); 2523 2524 if (val_cnt != 1) 2525 return (DLADM_STATUS_BADVALCNT); 2526 2527 errno = 0; 2528 elim = strtol(*prop_val, &ep, 10); 2529 if (errno != 0 || ep == *prop_val || elim < 0 || 2530 elim > (int32_t)UINT8_MAX) 2531 return (DLADM_STATUS_BADVAL); 2532 vdp->vd_val = elim; 2533 return (DLADM_STATUS_OK); 2534 } 2535 2536 static dladm_status_t 2537 i_dladm_set_linkprop_db(dladm_handle_t handle, datalink_id_t linkid, 2538 const char *prop_name, char **prop_val, uint_t val_cnt) 2539 { 2540 char buf[MAXLINELEN]; 2541 int i; 2542 dladm_conf_t conf; 2543 dladm_status_t status; 2544 2545 status = dladm_read_conf(handle, linkid, &conf); 2546 if (status != DLADM_STATUS_OK) 2547 return (status); 2548 2549 /* 2550 * reset case. 2551 */ 2552 if (val_cnt == 0) { 2553 status = dladm_unset_conf_field(handle, conf, prop_name); 2554 if (status == DLADM_STATUS_OK) 2555 status = dladm_write_conf(handle, conf); 2556 goto done; 2557 } 2558 2559 buf[0] = '\0'; 2560 for (i = 0; i < val_cnt; i++) { 2561 (void) strlcat(buf, prop_val[i], MAXLINELEN); 2562 if (i != val_cnt - 1) 2563 (void) strlcat(buf, ",", MAXLINELEN); 2564 } 2565 2566 status = dladm_set_conf_field(handle, conf, prop_name, DLADM_TYPE_STR, 2567 buf); 2568 if (status == DLADM_STATUS_OK) 2569 status = dladm_write_conf(handle, conf); 2570 2571 done: 2572 dladm_destroy_conf(handle, conf); 2573 return (status); 2574 } 2575 2576 static dladm_status_t 2577 i_dladm_get_linkprop_db(dladm_handle_t handle, datalink_id_t linkid, 2578 const char *prop_name, char **prop_val, uint_t *val_cntp) 2579 { 2580 char buf[MAXLINELEN], *str; 2581 uint_t cnt = 0; 2582 dladm_conf_t conf; 2583 dladm_status_t status; 2584 2585 status = dladm_read_conf(handle, linkid, &conf); 2586 if (status != DLADM_STATUS_OK) 2587 return (status); 2588 2589 status = dladm_get_conf_field(handle, conf, prop_name, buf, MAXLINELEN); 2590 if (status != DLADM_STATUS_OK) 2591 goto done; 2592 2593 str = strtok(buf, ","); 2594 while (str != NULL) { 2595 if (cnt == *val_cntp) { 2596 status = DLADM_STATUS_TOOSMALL; 2597 goto done; 2598 } 2599 (void) strlcpy(prop_val[cnt++], str, DLADM_PROP_VAL_MAX); 2600 str = strtok(NULL, ","); 2601 } 2602 2603 *val_cntp = cnt; 2604 2605 done: 2606 dladm_destroy_conf(handle, conf); 2607 return (status); 2608 } 2609 2610 /* 2611 * Walk persistent private link properties of a link. 2612 */ 2613 static dladm_status_t 2614 i_dladm_walk_linkprop_priv_db(dladm_handle_t handle, datalink_id_t linkid, 2615 void *arg, int (*func)(dladm_handle_t, datalink_id_t, const char *, void *)) 2616 { 2617 dladm_status_t status; 2618 dladm_conf_t conf; 2619 char last_attr[MAXLINKATTRLEN]; 2620 char attr[MAXLINKATTRLEN]; 2621 char attrval[MAXLINKATTRVALLEN]; 2622 size_t attrsz; 2623 2624 if (linkid == DATALINK_INVALID_LINKID || func == NULL) 2625 return (DLADM_STATUS_BADARG); 2626 2627 status = dladm_read_conf(handle, linkid, &conf); 2628 if (status != DLADM_STATUS_OK) 2629 return (status); 2630 2631 last_attr[0] = '\0'; 2632 while ((status = dladm_getnext_conf_linkprop(handle, conf, last_attr, 2633 attr, attrval, MAXLINKATTRVALLEN, &attrsz)) == DLADM_STATUS_OK) { 2634 if (attr[0] == '_') { 2635 if (func(handle, linkid, attr, arg) == 2636 DLADM_WALK_TERMINATE) 2637 break; 2638 } 2639 (void) strlcpy(last_attr, attr, MAXLINKATTRLEN); 2640 } 2641 2642 dladm_destroy_conf(handle, conf); 2643 return (DLADM_STATUS_OK); 2644 } 2645 2646 static link_attr_t * 2647 dladm_name2prop(const char *prop_name) 2648 { 2649 link_attr_t *p; 2650 2651 for (p = link_attr; p->pp_id != MAC_PROP_PRIVATE; p++) { 2652 if (strcmp(p->pp_name, prop_name) == 0) 2653 break; 2654 } 2655 return (p); 2656 } 2657 2658 static link_attr_t * 2659 dladm_id2prop(mac_prop_id_t propid) 2660 { 2661 link_attr_t *p; 2662 2663 for (p = link_attr; p->pp_id != MAC_PROP_PRIVATE; p++) { 2664 if (p->pp_id == propid) 2665 break; 2666 } 2667 return (p); 2668 } 2669 2670 static dld_ioc_macprop_t * 2671 i_dladm_buf_alloc_impl(size_t valsize, datalink_id_t linkid, 2672 const char *prop_name, mac_prop_id_t propid, uint_t flags, 2673 dladm_status_t *status) 2674 { 2675 int dsize; 2676 dld_ioc_macprop_t *dip; 2677 2678 *status = DLADM_STATUS_OK; 2679 dsize = MAC_PROP_BUFSIZE(valsize); 2680 dip = malloc(dsize); 2681 if (dip == NULL) { 2682 *status = DLADM_STATUS_NOMEM; 2683 return (NULL); 2684 } 2685 bzero(dip, dsize); 2686 dip->pr_valsize = valsize; 2687 (void) strlcpy(dip->pr_name, prop_name, sizeof (dip->pr_name)); 2688 dip->pr_version = MAC_PROP_VERSION; 2689 dip->pr_linkid = linkid; 2690 dip->pr_num = propid; 2691 dip->pr_flags = flags; 2692 return (dip); 2693 } 2694 2695 static dld_ioc_macprop_t * 2696 i_dladm_buf_alloc_by_name(size_t valsize, datalink_id_t linkid, 2697 const char *prop_name, uint_t flags, dladm_status_t *status) 2698 { 2699 link_attr_t *p; 2700 2701 p = dladm_name2prop(prop_name); 2702 valsize = MAX(p->pp_valsize, valsize); 2703 return (i_dladm_buf_alloc_impl(valsize, linkid, prop_name, p->pp_id, 2704 flags, status)); 2705 } 2706 2707 static dld_ioc_macprop_t * 2708 i_dladm_buf_alloc_by_id(size_t valsize, datalink_id_t linkid, 2709 mac_prop_id_t propid, uint_t flags, dladm_status_t *status) 2710 { 2711 link_attr_t *p; 2712 2713 p = dladm_id2prop(propid); 2714 valsize = MAX(p->pp_valsize, valsize); 2715 return (i_dladm_buf_alloc_impl(valsize, linkid, p->pp_name, propid, 2716 flags, status)); 2717 } 2718 2719 /* ARGSUSED */ 2720 static dladm_status_t 2721 i_dladm_set_public_prop(dladm_handle_t handle, prop_desc_t *pdp, 2722 datalink_id_t linkid, val_desc_t *vdp, uint_t val_cnt, uint_t flags, 2723 datalink_media_t media) 2724 { 2725 dld_ioc_macprop_t *dip; 2726 dladm_status_t status = DLADM_STATUS_OK; 2727 uint8_t u8; 2728 uint16_t u16; 2729 uint32_t u32; 2730 void *val; 2731 2732 dip = i_dladm_buf_alloc_by_name(0, linkid, pdp->pd_name, 0, &status); 2733 if (dip == NULL) 2734 return (status); 2735 2736 if (pdp->pd_flags & PD_CHECK_ALLOC) 2737 val = (void *)vdp->vd_val; 2738 else { 2739 /* 2740 * Currently all 1/2/4-byte size properties are byte/word/int. 2741 * No need (yet) to distinguish these from arrays of same size. 2742 */ 2743 switch (dip->pr_valsize) { 2744 case 1: 2745 u8 = vdp->vd_val; 2746 val = &u8; 2747 break; 2748 case 2: 2749 u16 = vdp->vd_val; 2750 val = &u16; 2751 break; 2752 case 4: 2753 u32 = vdp->vd_val; 2754 val = &u32; 2755 break; 2756 default: 2757 val = &vdp->vd_val; 2758 break; 2759 } 2760 } 2761 2762 if (val != NULL) 2763 (void) memcpy(dip->pr_val, val, dip->pr_valsize); 2764 else 2765 dip->pr_valsize = 0; 2766 2767 status = i_dladm_macprop(handle, dip, B_TRUE); 2768 2769 done: 2770 free(dip); 2771 return (status); 2772 } 2773 2774 dladm_status_t 2775 i_dladm_macprop(dladm_handle_t handle, void *dip, boolean_t set) 2776 { 2777 dladm_status_t status = DLADM_STATUS_OK; 2778 2779 if (ioctl(dladm_dld_fd(handle), 2780 (set ? DLDIOC_SETMACPROP : DLDIOC_GETMACPROP), dip)) 2781 status = dladm_errno2status(errno); 2782 2783 return (status); 2784 } 2785 2786 static dld_ioc_macprop_t * 2787 i_dladm_get_public_prop(dladm_handle_t handle, datalink_id_t linkid, 2788 char *prop_name, uint_t flags, dladm_status_t *status, uint_t *perm_flags) 2789 { 2790 dld_ioc_macprop_t *dip = NULL; 2791 2792 dip = i_dladm_buf_alloc_by_name(0, linkid, prop_name, flags, status); 2793 if (dip == NULL) 2794 return (NULL); 2795 2796 *status = i_dladm_macprop(handle, dip, B_FALSE); 2797 if (*status != DLADM_STATUS_OK) { 2798 free(dip); 2799 return (NULL); 2800 } 2801 if (perm_flags != NULL) 2802 *perm_flags = dip->pr_perm_flags; 2803 2804 return (dip); 2805 } 2806 2807 /* ARGSUSED */ 2808 static dladm_status_t 2809 i_dladm_uint32_check(dladm_handle_t handle, prop_desc_t *pdp, 2810 datalink_id_t linkid, char **prop_val, uint_t val_cnt, val_desc_t *v, 2811 datalink_media_t media) 2812 { 2813 if (val_cnt != 1) 2814 return (DLADM_STATUS_BADVAL); 2815 v->vd_val = strtoul(prop_val[0], NULL, 0); 2816 return (DLADM_STATUS_OK); 2817 } 2818 2819 /* ARGSUSED */ 2820 static dladm_status_t 2821 i_dladm_duplex_get(dladm_handle_t handle, prop_desc_t *pdp, 2822 datalink_id_t linkid, char **prop_val, uint_t *val_cnt, 2823 datalink_media_t media, uint_t flags, uint_t *perm_flags) 2824 { 2825 link_duplex_t link_duplex; 2826 dladm_status_t status; 2827 2828 if ((status = dladm_get_single_mac_stat(handle, linkid, "link_duplex", 2829 KSTAT_DATA_UINT32, &link_duplex)) != 0) 2830 return (status); 2831 2832 switch (link_duplex) { 2833 case LINK_DUPLEX_FULL: 2834 (void) strcpy(*prop_val, "full"); 2835 break; 2836 case LINK_DUPLEX_HALF: 2837 (void) strcpy(*prop_val, "half"); 2838 break; 2839 default: 2840 (void) strcpy(*prop_val, "unknown"); 2841 break; 2842 } 2843 *val_cnt = 1; 2844 return (DLADM_STATUS_OK); 2845 } 2846 2847 /* ARGSUSED */ 2848 static dladm_status_t 2849 i_dladm_speed_get(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid, 2850 char **prop_val, uint_t *val_cnt, uint_t flags, uint_t *perm_flags) 2851 { 2852 uint64_t ifspeed = 0; 2853 dladm_status_t status; 2854 2855 if ((status = dladm_get_single_mac_stat(handle, linkid, "ifspeed", 2856 KSTAT_DATA_UINT64, &ifspeed)) != 0) 2857 return (status); 2858 2859 if ((ifspeed % 1000000) != 0) { 2860 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, 2861 "%llf", ifspeed / (float)1000000); /* Mbps */ 2862 } else { 2863 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, 2864 "%llu", ifspeed / 1000000); /* Mbps */ 2865 } 2866 *val_cnt = 1; 2867 *perm_flags = MAC_PROP_PERM_READ; 2868 return (DLADM_STATUS_OK); 2869 } 2870 2871 /* ARGSUSED */ 2872 static dladm_status_t 2873 i_dladm_status_get(dladm_handle_t handle, prop_desc_t *pdp, 2874 datalink_id_t linkid, char **prop_val, uint_t *val_cnt, 2875 datalink_media_t media, uint_t flags, uint_t *perm_flags) 2876 { 2877 link_state_t link_state; 2878 dladm_status_t status; 2879 2880 status = i_dladm_get_state(handle, linkid, &link_state); 2881 if (status != DLADM_STATUS_OK) 2882 return (status); 2883 2884 switch (link_state) { 2885 case LINK_STATE_UP: 2886 (void) strcpy(*prop_val, "up"); 2887 break; 2888 case LINK_STATE_DOWN: 2889 (void) strcpy(*prop_val, "down"); 2890 break; 2891 default: 2892 (void) strcpy(*prop_val, "unknown"); 2893 break; 2894 } 2895 *val_cnt = 1; 2896 *perm_flags = MAC_PROP_PERM_READ; 2897 return (DLADM_STATUS_OK); 2898 } 2899 2900 /* ARGSUSED */ 2901 static dladm_status_t 2902 i_dladm_binary_get(dladm_handle_t handle, prop_desc_t *pdp, 2903 datalink_id_t linkid, char **prop_val, uint_t *val_cnt, 2904 datalink_media_t media, uint_t flags, uint_t *perm_flags) 2905 { 2906 dld_ioc_macprop_t *dip; 2907 dladm_status_t status; 2908 2909 dip = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags, 2910 &status, perm_flags); 2911 if (dip == NULL) 2912 return (status); 2913 2914 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "%x", dip->pr_val[0]); 2915 free(dip); 2916 *val_cnt = 1; 2917 return (DLADM_STATUS_OK); 2918 } 2919 2920 /* ARGSUSED */ 2921 static dladm_status_t 2922 i_dladm_uint32_get(dladm_handle_t handle, prop_desc_t *pdp, 2923 datalink_id_t linkid, char **prop_val, uint_t *val_cnt, 2924 datalink_media_t media, uint_t flags, uint_t *perm_flags) 2925 { 2926 dld_ioc_macprop_t *dip; 2927 uint32_t v = 0; 2928 uchar_t *cp; 2929 dladm_status_t status; 2930 2931 dip = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags, 2932 &status, perm_flags); 2933 if (dip == NULL) 2934 return (status); 2935 2936 cp = (uchar_t *)dip->pr_val; 2937 (void) memcpy(&v, cp, sizeof (v)); 2938 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "%ld", v); 2939 free(dip); 2940 *val_cnt = 1; 2941 return (DLADM_STATUS_OK); 2942 } 2943 2944 /* 2945 * Determines the size of the structure that needs to be sent to drivers 2946 * for retrieving the property range values. 2947 */ 2948 static int 2949 i_dladm_range_size(mac_propval_range_t *r, size_t *sz) 2950 { 2951 uint_t count = r->mpr_count; 2952 2953 *sz = sizeof (mac_propval_range_t); 2954 --count; 2955 2956 switch (r->mpr_type) { 2957 case MAC_PROPVAL_UINT32: 2958 *sz += (count * sizeof (mac_propval_uint32_range_t)); 2959 return (0); 2960 default: 2961 break; 2962 } 2963 *sz = 0; 2964 return (EINVAL); 2965 } 2966 2967 /* ARGSUSED */ 2968 static dladm_status_t 2969 i_dladm_range_get(dladm_handle_t handle, prop_desc_t *pdp, 2970 datalink_id_t linkid, char **prop_val, uint_t *val_cnt, 2971 datalink_media_t media, uint_t flags, uint_t *perm_flags) 2972 { 2973 dld_ioc_macprop_t *dip; 2974 dladm_status_t status = DLADM_STATUS_OK; 2975 size_t sz; 2976 mac_propval_range_t *rangep; 2977 2978 sz = sizeof (mac_propval_range_t); 2979 2980 /* 2981 * As caller we don't know number of value ranges, the driver 2982 * supports. To begin with we assume that number to be 1. If the 2983 * buffer size is insufficient, driver returns back with the 2984 * actual count of value ranges. See mac.h for more details. 2985 */ 2986 retry: 2987 if ((dip = i_dladm_buf_alloc_by_name(sz, linkid, pdp->pd_name, flags, 2988 &status)) == NULL) 2989 return (status); 2990 2991 status = i_dladm_macprop(handle, dip, B_FALSE); 2992 if (status != DLADM_STATUS_OK) { 2993 if (status == DLADM_STATUS_TOOSMALL) { 2994 int err; 2995 2996 rangep = (mac_propval_range_t *)(void *)&dip->pr_val; 2997 if ((err = i_dladm_range_size(rangep, &sz)) == 0) { 2998 free(dip); 2999 goto retry; 3000 } else { 3001 status = dladm_errno2status(err); 3002 } 3003 } 3004 free(dip); 3005 return (status); 3006 } 3007 rangep = (mac_propval_range_t *)(void *)&dip->pr_val; 3008 3009 switch (rangep->mpr_type) { 3010 case MAC_PROPVAL_UINT32: { 3011 mac_propval_uint32_range_t *ur; 3012 uint_t count = rangep->mpr_count, i; 3013 3014 ur = &rangep->range_uint32[0]; 3015 3016 for (i = 0; i < count; i++, ur++) { 3017 if (ur->mpur_min == ur->mpur_max) { 3018 (void) snprintf(prop_val[i], DLADM_PROP_VAL_MAX, 3019 "%ld", ur->mpur_min); 3020 } else { 3021 (void) snprintf(prop_val[i], DLADM_PROP_VAL_MAX, 3022 "%ld-%ld", ur->mpur_min, ur->mpur_max); 3023 } 3024 } 3025 *val_cnt = count; 3026 break; 3027 } 3028 default: 3029 status = DLADM_STATUS_BADARG; 3030 break; 3031 } 3032 free(dip); 3033 return (status); 3034 } 3035 3036 /* ARGSUSED */ 3037 static dladm_status_t 3038 i_dladm_tagmode_get(dladm_handle_t handle, prop_desc_t *pdp, 3039 datalink_id_t linkid, char **prop_val, uint_t *val_cnt, 3040 datalink_media_t media, uint_t flags, uint_t *perm_flags) 3041 { 3042 dld_ioc_macprop_t *dip; 3043 link_tagmode_t mode; 3044 dladm_status_t status; 3045 3046 dip = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags, 3047 &status, perm_flags); 3048 if (dip == NULL) 3049 return (status); 3050 (void) memcpy(&mode, dip->pr_val, sizeof (mode)); 3051 free(dip); 3052 3053 switch (mode) { 3054 case LINK_TAGMODE_NORMAL: 3055 (void) strlcpy(*prop_val, "normal", DLADM_PROP_VAL_MAX); 3056 break; 3057 case LINK_TAGMODE_VLANONLY: 3058 (void) strlcpy(*prop_val, "vlanonly", DLADM_PROP_VAL_MAX); 3059 break; 3060 default: 3061 (void) strlcpy(*prop_val, "unknown", DLADM_PROP_VAL_MAX); 3062 } 3063 *val_cnt = 1; 3064 return (DLADM_STATUS_OK); 3065 } 3066 3067 /* ARGSUSED */ 3068 static dladm_status_t 3069 i_dladm_flowctl_get(dladm_handle_t handle, prop_desc_t *pdp, 3070 datalink_id_t linkid, char **prop_val, uint_t *val_cnt, 3071 datalink_media_t media, uint_t flags, uint_t *perm_flags) 3072 { 3073 dld_ioc_macprop_t *dip; 3074 link_flowctrl_t v; 3075 dladm_status_t status; 3076 uchar_t *cp; 3077 3078 dip = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags, 3079 &status, perm_flags); 3080 if (dip == NULL) 3081 return (status); 3082 3083 cp = (uchar_t *)dip->pr_val; 3084 (void) memcpy(&v, cp, sizeof (v)); 3085 switch (v) { 3086 case LINK_FLOWCTRL_NONE: 3087 (void) sprintf(*prop_val, "no"); 3088 break; 3089 case LINK_FLOWCTRL_RX: 3090 (void) sprintf(*prop_val, "rx"); 3091 break; 3092 case LINK_FLOWCTRL_TX: 3093 (void) sprintf(*prop_val, "tx"); 3094 break; 3095 case LINK_FLOWCTRL_BI: 3096 (void) sprintf(*prop_val, "bi"); 3097 break; 3098 } 3099 free(dip); 3100 *val_cnt = 1; 3101 return (DLADM_STATUS_OK); 3102 } 3103 3104 3105 /* ARGSUSED */ 3106 static dladm_status_t 3107 i_dladm_set_private_prop(dladm_handle_t handle, datalink_id_t linkid, 3108 const char *prop_name, char **prop_val, uint_t val_cnt, uint_t flags) 3109 3110 { 3111 int i, slen; 3112 int bufsize = 0; 3113 dld_ioc_macprop_t *dip = NULL; 3114 uchar_t *dp; 3115 link_attr_t *p; 3116 dladm_status_t status = DLADM_STATUS_OK; 3117 3118 if ((prop_name == NULL && prop_val != NULL) || 3119 (prop_val != NULL && val_cnt == 0)) 3120 return (DLADM_STATUS_BADARG); 3121 p = dladm_name2prop(prop_name); 3122 if (p->pp_id != MAC_PROP_PRIVATE) 3123 return (DLADM_STATUS_BADARG); 3124 3125 if (!(flags & DLADM_OPT_ACTIVE)) 3126 return (DLADM_STATUS_OK); 3127 3128 /* 3129 * private properties: all parsing is done in the kernel. 3130 * allocate a enough space for each property + its separator (','). 3131 */ 3132 for (i = 0; i < val_cnt; i++) { 3133 bufsize += strlen(prop_val[i]) + 1; 3134 } 3135 3136 if (prop_val == NULL) { 3137 /* 3138 * getting default value. so use more buffer space. 3139 */ 3140 bufsize += DLADM_PROP_BUF_CHUNK; 3141 } 3142 3143 dip = i_dladm_buf_alloc_by_name(bufsize + 1, linkid, prop_name, 3144 (prop_val != NULL ? 0 : MAC_PROP_DEFAULT), &status); 3145 if (dip == NULL) 3146 return (status); 3147 3148 dp = (uchar_t *)dip->pr_val; 3149 slen = 0; 3150 3151 if (prop_val == NULL) { 3152 status = i_dladm_macprop(handle, dip, B_FALSE); 3153 dip->pr_flags = 0; 3154 } else { 3155 for (i = 0; i < val_cnt; i++) { 3156 int plen = 0; 3157 3158 plen = strlen(prop_val[i]); 3159 bcopy(prop_val[i], dp, plen); 3160 slen += plen; 3161 /* 3162 * add a "," separator and update dp. 3163 */ 3164 if (i != (val_cnt -1)) 3165 dp[slen++] = ','; 3166 dp += (plen + 1); 3167 } 3168 } 3169 if (status == DLADM_STATUS_OK) 3170 status = i_dladm_macprop(handle, dip, B_TRUE); 3171 3172 free(dip); 3173 return (status); 3174 } 3175 3176 static dladm_status_t 3177 i_dladm_get_priv_prop(dladm_handle_t handle, datalink_id_t linkid, 3178 const char *prop_name, char **prop_val, uint_t *val_cnt, 3179 dladm_prop_type_t type, uint_t dld_flags) 3180 { 3181 dladm_status_t status = DLADM_STATUS_OK; 3182 dld_ioc_macprop_t *dip = NULL; 3183 link_attr_t *p; 3184 3185 if ((prop_name == NULL && prop_val != NULL) || 3186 (prop_val != NULL && val_cnt == 0)) 3187 return (DLADM_STATUS_BADARG); 3188 3189 p = dladm_name2prop(prop_name); 3190 if (p->pp_id != MAC_PROP_PRIVATE) 3191 return (DLADM_STATUS_BADARG); 3192 3193 /* 3194 * private properties: all parsing is done in the kernel. 3195 */ 3196 dip = i_dladm_buf_alloc_by_name(DLADM_PROP_BUF_CHUNK, linkid, prop_name, 3197 dld_flags, &status); 3198 if (dip == NULL) 3199 return (status); 3200 3201 if ((status = i_dladm_macprop(handle, dip, B_FALSE)) == 3202 DLADM_STATUS_OK) { 3203 if (type == DLADM_PROP_VAL_PERM) { 3204 (void) dladm_perm2str(dip->pr_perm_flags, *prop_val); 3205 } else if (type == DLADM_PROP_VAL_MODIFIABLE) { 3206 *prop_val[0] = '\0'; 3207 } else { 3208 (void) strncpy(*prop_val, dip->pr_val, 3209 DLADM_PROP_VAL_MAX); 3210 } 3211 *val_cnt = 1; 3212 } else if ((status == DLADM_STATUS_NOTSUP) && 3213 (type == DLADM_PROP_VAL_CURRENT)) { 3214 status = DLADM_STATUS_NOTFOUND; 3215 } 3216 free(dip); 3217 return (status); 3218 } 3219 3220 3221 static dladm_status_t 3222 i_dladm_getset_defval(dladm_handle_t handle, prop_desc_t *pdp, 3223 datalink_id_t linkid, datalink_media_t media, uint_t flags) 3224 { 3225 dladm_status_t status; 3226 char **prop_vals = NULL, *buf; 3227 size_t bufsize; 3228 uint_t cnt; 3229 int i; 3230 uint_t perm_flags; 3231 3232 /* 3233 * Allocate buffer needed for prop_vals array. We can have at most 3234 * DLADM_MAX_PROP_VALCNT char *prop_vals[] entries, where 3235 * each entry has max size DLADM_PROP_VAL_MAX 3236 */ 3237 bufsize = 3238 (sizeof (char *) + DLADM_PROP_VAL_MAX) * DLADM_MAX_PROP_VALCNT; 3239 buf = malloc(bufsize); 3240 prop_vals = (char **)(void *)buf; 3241 for (i = 0; i < DLADM_MAX_PROP_VALCNT; i++) { 3242 prop_vals[i] = buf + 3243 sizeof (char *) * DLADM_MAX_PROP_VALCNT + 3244 i * DLADM_PROP_VAL_MAX; 3245 } 3246 3247 /* 3248 * For properties which have pdp->pd_defval.vd_name as a non-empty 3249 * string, the "" itself is used to reset the property (exceptions 3250 * are zone and autopush, which populate vdp->vd_val). So 3251 * libdladm can copy pdp->pd_defval over to the val_desc_t passed 3252 * down on the setprop using the global values in the table. For 3253 * other cases (vd_name is ""), doing reset-linkprop will cause 3254 * libdladm to do a getprop to find the default value and then do 3255 * a setprop to reset the value to default. 3256 */ 3257 status = pdp->pd_get(handle, pdp, linkid, prop_vals, &cnt, media, 3258 MAC_PROP_DEFAULT, &perm_flags); 3259 if (status == DLADM_STATUS_OK) { 3260 if (perm_flags == MAC_PROP_PERM_RW) { 3261 status = i_dladm_set_single_prop(handle, linkid, 3262 pdp->pd_class, media, pdp, prop_vals, cnt, flags); 3263 } 3264 else 3265 status = DLADM_STATUS_NOTSUP; 3266 } 3267 free(buf); 3268 return (status); 3269 } 3270 3271 /* ARGSUSED */ 3272 static dladm_status_t 3273 get_stp_prop(dladm_handle_t handle, struct prop_desc *pd, datalink_id_t linkid, 3274 char **prop_val, uint_t *val_cnt, datalink_media_t media, uint_t flags, 3275 uint_t *perm_flags) 3276 { 3277 const bridge_public_prop_t *bpp; 3278 dladm_status_t retv; 3279 int val, i; 3280 3281 if (flags != 0) 3282 return (DLADM_STATUS_NOTSUP); 3283 *perm_flags = MAC_PROP_PERM_RW; 3284 *val_cnt = 1; 3285 for (bpp = bridge_prop; bpp->bpp_name != NULL; bpp++) 3286 if (strcmp(bpp->bpp_name, pd->pd_name) == 0) 3287 break; 3288 retv = dladm_bridge_get_port_cfg(handle, linkid, bpp->bpp_code, &val); 3289 /* If the daemon isn't running, then return the persistent value */ 3290 if (retv == DLADM_STATUS_NOTFOUND) { 3291 if (i_dladm_get_linkprop_db(handle, linkid, pd->pd_name, 3292 prop_val, val_cnt) != DLADM_STATUS_OK) 3293 (void) strlcpy(*prop_val, pd->pd_defval.vd_name, 3294 DLADM_PROP_VAL_MAX); 3295 return (DLADM_STATUS_OK); 3296 } 3297 if (retv != DLADM_STATUS_OK) { 3298 (void) strlcpy(*prop_val, "?", DLADM_PROP_VAL_MAX); 3299 return (retv); 3300 } 3301 if (val == pd->pd_defval.vd_val && pd->pd_defval.vd_name[0] != '\0') { 3302 (void) strlcpy(*prop_val, pd->pd_defval.vd_name, 3303 DLADM_PROP_VAL_MAX); 3304 return (DLADM_STATUS_OK); 3305 } 3306 for (i = 0; i < pd->pd_noptval; i++) { 3307 if (val == pd->pd_optval[i].vd_val) { 3308 (void) strlcpy(*prop_val, pd->pd_optval[i].vd_name, 3309 DLADM_PROP_VAL_MAX); 3310 return (DLADM_STATUS_OK); 3311 } 3312 } 3313 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "%u", (unsigned)val); 3314 return (DLADM_STATUS_OK); 3315 } 3316 3317 /* ARGSUSED1 */ 3318 static dladm_status_t 3319 set_stp_prop(dladm_handle_t handle, prop_desc_t *pd, datalink_id_t linkid, 3320 val_desc_t *vdp, uint_t val_cnt, uint_t flags, datalink_media_t media) 3321 { 3322 /* 3323 * Special case for mcheck: the daemon resets the value to zero, and we 3324 * don't want the daemon to refresh itself; it leads to deadlock. 3325 */ 3326 if (flags & DLADM_OPT_NOREFRESH) 3327 return (DLADM_STATUS_OK); 3328 3329 /* Tell the running daemon, if any */ 3330 return (dladm_bridge_refresh(handle, linkid)); 3331 } 3332 3333 /* 3334 * This is used only for stp_priority, stp_cost, and stp_mcheck. 3335 */ 3336 /* ARGSUSED */ 3337 static dladm_status_t 3338 check_stp_prop(dladm_handle_t handle, struct prop_desc *pd, 3339 datalink_id_t linkid, char **prop_val, uint_t val_cnt, val_desc_t *vdp, 3340 datalink_media_t media) 3341 { 3342 char *cp; 3343 boolean_t iscost; 3344 3345 if (val_cnt != 1) 3346 return (DLADM_STATUS_BADVALCNT); 3347 3348 if (prop_val == NULL) { 3349 vdp->vd_val = 0; 3350 } else { 3351 /* Only stp_priority and stp_cost use this function */ 3352 iscost = strcmp(pd->pd_name, "stp_cost") == 0; 3353 3354 if (iscost && strcmp(prop_val[0], "auto") == 0) { 3355 /* Illegal value 0 is allowed to mean "automatic" */ 3356 vdp->vd_val = 0; 3357 } else { 3358 errno = 0; 3359 vdp->vd_val = strtoul(prop_val[0], &cp, 0); 3360 if (errno != 0 || *cp != '\0') 3361 return (DLADM_STATUS_BADVAL); 3362 } 3363 } 3364 3365 if (iscost) { 3366 return (vdp->vd_val > 65535 ? DLADM_STATUS_BADVAL : 3367 DLADM_STATUS_OK); 3368 } else { 3369 if (vdp->vd_val > 255) 3370 return (DLADM_STATUS_BADVAL); 3371 /* 3372 * If the user is setting stp_mcheck non-zero, then (per the 3373 * IEEE management standards and UNH testing) we need to check 3374 * whether this link is part of a bridge that is running RSTP. 3375 * If it's not, then setting the flag is an error. Note that 3376 * errors are intentionally discarded here; it's the value 3377 * that's the problem -- it's not a bad value, merely one that 3378 * can't be used now. 3379 */ 3380 if (strcmp(pd->pd_name, "stp_mcheck") == 0 && 3381 vdp->vd_val != 0) { 3382 char bridge[MAXLINKNAMELEN]; 3383 UID_STP_CFG_T cfg; 3384 dladm_bridge_prot_t brprot; 3385 3386 if (dladm_bridge_getlink(handle, linkid, bridge, 3387 sizeof (bridge)) != DLADM_STATUS_OK || 3388 dladm_bridge_get_properties(bridge, &cfg, 3389 &brprot) != DLADM_STATUS_OK) 3390 return (DLADM_STATUS_FAILED); 3391 if (cfg.force_version <= 1) 3392 return (DLADM_STATUS_FAILED); 3393 } 3394 return (DLADM_STATUS_OK); 3395 } 3396 } 3397 3398 /* ARGSUSED */ 3399 static dladm_status_t 3400 get_bridge_forward(dladm_handle_t handle, struct prop_desc *pd, 3401 datalink_id_t linkid, char **prop_val, uint_t *val_cnt, 3402 datalink_media_t media, uint_t flags, uint_t *perm_flags) 3403 { 3404 dladm_status_t retv; 3405 uint_t val; 3406 3407 if (flags != 0) 3408 return (DLADM_STATUS_NOTSUP); 3409 *perm_flags = MAC_PROP_PERM_RW; 3410 *val_cnt = 1; 3411 retv = dladm_bridge_get_forwarding(handle, linkid, &val); 3412 if (retv == DLADM_STATUS_NOTFOUND) { 3413 if (i_dladm_get_linkprop_db(handle, linkid, pd->pd_name, 3414 prop_val, val_cnt) != DLADM_STATUS_OK) 3415 (void) strlcpy(*prop_val, pd->pd_defval.vd_name, 3416 DLADM_PROP_VAL_MAX); 3417 return (DLADM_STATUS_OK); 3418 } 3419 if (retv == DLADM_STATUS_OK) 3420 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "%u", val); 3421 else 3422 (void) strlcpy(*prop_val, "?", DLADM_PROP_VAL_MAX); 3423 return (retv); 3424 } 3425 3426 /* ARGSUSED */ 3427 static dladm_status_t 3428 set_bridge_forward(dladm_handle_t handle, prop_desc_t *pd, datalink_id_t linkid, 3429 val_desc_t *vdp, uint_t val_cnt, uint_t flags, datalink_media_t media) 3430 { 3431 /* Tell the running daemon, if any */ 3432 return (dladm_bridge_refresh(handle, linkid)); 3433 } 3434 3435 /* ARGSUSED */ 3436 static dladm_status_t 3437 get_bridge_pvid(dladm_handle_t handle, struct prop_desc *pd, 3438 datalink_id_t linkid, char **prop_val, uint_t *val_cnt, 3439 datalink_media_t media, uint_t flags, uint_t *perm_flags) 3440 { 3441 dladm_status_t status; 3442 dld_ioc_macprop_t *dip; 3443 uint16_t pvid; 3444 3445 if (flags != 0) 3446 return (DLADM_STATUS_NOTSUP); 3447 *perm_flags = MAC_PROP_PERM_RW; 3448 *val_cnt = 1; 3449 dip = i_dladm_buf_alloc_by_id(sizeof (uint16_t), linkid, MAC_PROP_PVID, 3450 0, &status); 3451 if (dip == NULL) 3452 return (status); 3453 status = i_dladm_macprop(handle, dip, B_FALSE); 3454 if (status == DLADM_STATUS_OK) { 3455 (void) memcpy(&pvid, dip->pr_val, sizeof (pvid)); 3456 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "%u", pvid); 3457 } else { 3458 (void) strlcpy(*prop_val, "?", DLADM_PROP_VAL_MAX); 3459 } 3460 free(dip); 3461 return (status); 3462 } 3463 3464 /* ARGSUSED */ 3465 static dladm_status_t 3466 set_bridge_pvid(dladm_handle_t handle, prop_desc_t *pd, datalink_id_t linkid, 3467 val_desc_t *vdp, uint_t val_cnt, uint_t flags, datalink_media_t media) 3468 { 3469 dladm_status_t status; 3470 dld_ioc_macprop_t *dip; 3471 uint16_t pvid; 3472 3473 dip = i_dladm_buf_alloc_by_id(sizeof (uint16_t), linkid, MAC_PROP_PVID, 3474 0, &status); 3475 if (dip == NULL) 3476 return (status); 3477 pvid = vdp->vd_val; 3478 (void) memcpy(dip->pr_val, &pvid, sizeof (pvid)); 3479 status = i_dladm_macprop(handle, dip, B_TRUE); 3480 free(dip); 3481 if (status != DLADM_STATUS_OK) 3482 return (status); 3483 3484 /* Tell the running daemon, if any */ 3485 return (dladm_bridge_refresh(handle, linkid)); 3486 } 3487 3488 /* ARGSUSED */ 3489 static dladm_status_t 3490 check_bridge_pvid(dladm_handle_t handle, struct prop_desc *pd, 3491 datalink_id_t linkid, char **prop_val, uint_t val_cnt, val_desc_t *vdp, 3492 datalink_media_t media) 3493 { 3494 char *cp; 3495 3496 if (val_cnt != 1) 3497 return (DLADM_STATUS_BADVALCNT); 3498 3499 if (prop_val == NULL) { 3500 vdp->vd_val = 1; 3501 } else { 3502 errno = 0; 3503 vdp->vd_val = strtoul(prop_val[0], &cp, 0); 3504 if (errno != 0 || *cp != '\0') 3505 return (DLADM_STATUS_BADVAL); 3506 } 3507 3508 return (vdp->vd_val > VLAN_ID_MAX ? DLADM_STATUS_BADVAL : 3509 DLADM_STATUS_OK); 3510 } 3511 3512 dladm_status_t 3513 i_dladm_wlan_param(dladm_handle_t handle, datalink_id_t linkid, void *buf, 3514 mac_prop_id_t cmd, size_t len, boolean_t set) 3515 { 3516 uint32_t flags; 3517 dladm_status_t status; 3518 uint32_t media; 3519 dld_ioc_macprop_t *dip; 3520 void *dp; 3521 3522 if ((status = dladm_datalink_id2info(handle, linkid, &flags, NULL, 3523 &media, NULL, 0)) != DLADM_STATUS_OK) { 3524 return (status); 3525 } 3526 3527 if (media != DL_WIFI) 3528 return (DLADM_STATUS_BADARG); 3529 3530 if (!(flags & DLADM_OPT_ACTIVE)) 3531 return (DLADM_STATUS_TEMPONLY); 3532 3533 if (len == (MAX_BUF_LEN - WIFI_BUF_OFFSET)) 3534 len = MAX_BUF_LEN - sizeof (dld_ioc_macprop_t) - 1; 3535 3536 dip = i_dladm_buf_alloc_by_id(len, linkid, cmd, 0, &status); 3537 if (dip == NULL) 3538 return (DLADM_STATUS_NOMEM); 3539 3540 dp = (uchar_t *)dip->pr_val; 3541 if (set) 3542 (void) memcpy(dp, buf, len); 3543 3544 status = i_dladm_macprop(handle, dip, set); 3545 if (status == DLADM_STATUS_OK) { 3546 if (!set) 3547 (void) memcpy(buf, dp, len); 3548 } 3549 3550 free(dip); 3551 return (status); 3552 } 3553 3554 dladm_status_t 3555 dladm_parse_link_props(char *str, dladm_arg_list_t **listp, boolean_t novalues) 3556 { 3557 return (dladm_parse_args(str, listp, novalues)); 3558 } 3559 3560 /* 3561 * Retrieve the one link property from the database 3562 */ 3563 /*ARGSUSED*/ 3564 static int 3565 i_dladm_get_one_prop(dladm_handle_t handle, datalink_id_t linkid, 3566 const char *prop_name, void *arg) 3567 { 3568 dladm_arg_list_t *proplist = arg; 3569 dladm_arg_info_t *aip = NULL; 3570 3571 aip = &proplist->al_info[proplist->al_count]; 3572 /* 3573 * it is fine to point to prop_name since prop_name points to the 3574 * prop_table[n].pd_name. 3575 */ 3576 aip->ai_name = prop_name; 3577 3578 (void) dladm_get_linkprop(handle, linkid, DLADM_PROP_VAL_PERSISTENT, 3579 prop_name, aip->ai_val, &aip->ai_count); 3580 3581 if (aip->ai_count != 0) 3582 proplist->al_count++; 3583 3584 return (DLADM_WALK_CONTINUE); 3585 } 3586 3587 3588 /* 3589 * Retrieve all link properties for a link from the database and 3590 * return a property list. 3591 */ 3592 dladm_status_t 3593 dladm_link_get_proplist(dladm_handle_t handle, datalink_id_t linkid, 3594 dladm_arg_list_t **listp) 3595 { 3596 dladm_arg_list_t *list; 3597 dladm_status_t status = DLADM_STATUS_OK; 3598 3599 list = calloc(1, sizeof (dladm_arg_list_t)); 3600 if (list == NULL) 3601 return (dladm_errno2status(errno)); 3602 3603 status = dladm_walk_linkprop(handle, linkid, list, 3604 i_dladm_get_one_prop); 3605 3606 *listp = list; 3607 return (status); 3608 } 3609 3610 /* 3611 * Retrieve the named property from a proplist, check the value and 3612 * convert to a kernel structure. 3613 */ 3614 static dladm_status_t 3615 i_dladm_link_proplist_extract_one(dladm_handle_t handle, 3616 dladm_arg_list_t *proplist, const char *name, void *arg) 3617 { 3618 dladm_status_t status; 3619 dladm_arg_info_t *aip = NULL; 3620 int i, j; 3621 3622 /* Find named property in proplist */ 3623 for (i = 0; i < proplist->al_count; i++) { 3624 aip = &proplist->al_info[i]; 3625 if (strcasecmp(aip->ai_name, name) == 0) 3626 break; 3627 } 3628 3629 /* Property not in list */ 3630 if (i == proplist->al_count) 3631 return (DLADM_STATUS_OK); 3632 3633 for (i = 0; i < DLADM_MAX_PROPS; i++) { 3634 prop_desc_t *pdp = &prop_table[i]; 3635 val_desc_t *vdp; 3636 3637 vdp = malloc(sizeof (val_desc_t) * aip->ai_count); 3638 if (vdp == NULL) 3639 return (DLADM_STATUS_NOMEM); 3640 3641 if (strcasecmp(aip->ai_name, pdp->pd_name) != 0) 3642 continue; 3643 3644 if (aip->ai_val == NULL) 3645 return (DLADM_STATUS_BADARG); 3646 3647 /* Check property value */ 3648 if (pdp->pd_check != NULL) { 3649 status = pdp->pd_check(handle, pdp, 0, aip->ai_val, 3650 aip->ai_count, vdp, 0); 3651 } else { 3652 status = DLADM_STATUS_BADARG; 3653 } 3654 3655 if (status != DLADM_STATUS_OK) 3656 return (status); 3657 3658 for (j = 0; j < DLADM_MAX_RSRC_PROP; j++) { 3659 resource_prop_t *rpp = &rsrc_prop_table[j]; 3660 3661 if (strcasecmp(aip->ai_name, rpp->rp_name) != 0) 3662 continue; 3663 3664 /* Extract kernel structure */ 3665 if (rpp->rp_extract != NULL) { 3666 status = rpp->rp_extract(vdp, 3667 aip->ai_count, arg); 3668 } else { 3669 status = DLADM_STATUS_BADARG; 3670 } 3671 break; 3672 } 3673 3674 if (status != DLADM_STATUS_OK) 3675 return (status); 3676 3677 break; 3678 } 3679 return (status); 3680 } 3681 3682 /* 3683 * Extract properties from a proplist and convert to mac_resource_props_t. 3684 */ 3685 dladm_status_t 3686 dladm_link_proplist_extract(dladm_handle_t handle, dladm_arg_list_t *proplist, 3687 mac_resource_props_t *mrp) 3688 { 3689 dladm_status_t status; 3690 int i; 3691 3692 for (i = 0; i < DLADM_MAX_RSRC_PROP; i++) { 3693 status = i_dladm_link_proplist_extract_one(handle, 3694 proplist, rsrc_prop_table[i].rp_name, mrp); 3695 if (status != DLADM_STATUS_OK) 3696 return (status); 3697 } 3698 return (status); 3699 } 3700 3701 static const char * 3702 dladm_perm2str(uint_t perm, char *buf) 3703 { 3704 (void) snprintf(buf, DLADM_STRSIZE, "%c%c", 3705 ((perm & MAC_PROP_PERM_READ) != 0) ? 'r' : '-', 3706 ((perm & MAC_PROP_PERM_WRITE) != 0) ? 'w' : '-'); 3707 return (buf); 3708 } 3709 3710 dladm_status_t 3711 i_dladm_get_state(dladm_handle_t handle, datalink_id_t linkid, 3712 link_state_t *state) 3713 { 3714 dld_ioc_macprop_t *dip; 3715 dladm_status_t status; 3716 uint_t perms; 3717 3718 dip = i_dladm_get_public_prop(handle, linkid, "state", 0, &status, 3719 &perms); 3720 if (status != DLADM_STATUS_OK) 3721 return (status); 3722 (void) memcpy(state, dip->pr_val, sizeof (*state)); 3723 free(dip); 3724 return (status); 3725 } 3726 3727 boolean_t 3728 dladm_attr_is_linkprop(const char *name) 3729 { 3730 /* non-property attribute names */ 3731 const char *nonprop[] = { 3732 /* dlmgmtd core attributes */ 3733 "name", 3734 "class", 3735 "media", 3736 FPHYMAJ, 3737 FPHYINST, 3738 FDEVNAME, 3739 3740 /* other attributes for vlan, aggr, etc */ 3741 DLADM_ATTR_NAMES 3742 }; 3743 boolean_t is_nonprop = B_FALSE; 3744 int i; 3745 3746 for (i = 0; i < sizeof (nonprop) / sizeof (nonprop[0]); i++) { 3747 if (strcmp(name, nonprop[i]) == 0) { 3748 is_nonprop = B_TRUE; 3749 break; 3750 } 3751 } 3752 3753 return (!is_nonprop); 3754 } 3755