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