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 2008 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 60 /* 61 * The linkprop get() callback. 62 * - pd: pointer to the prop_desc_t 63 * - propstrp: a property string array to keep the returned property. 64 * Caller allocated. 65 * - cntp: number of returned properties. 66 * Caller also uses it to indicate how many it expects. 67 */ 68 struct prop_desc; 69 typedef struct prop_desc prop_desc_t; 70 71 typedef dladm_status_t pd_getf_t(prop_desc_t *pdp, 72 datalink_id_t, char **propstp, uint_t *cntp, 73 datalink_media_t, uint_t, uint_t *); 74 75 /* 76 * The linkprop set() callback. 77 * - propval: a val_desc_t array which keeps the property values to be set. 78 * - cnt: number of properties to be set. 79 * - flags: additional flags passed down the system call. 80 * 81 * pd_set takes val_desc_t given by pd_check(), translates it into 82 * a format suitable for kernel consumption. This may require allocation 83 * of ioctl buffers etc. pd_set() may call another common routine (used 84 * by all other pd_sets) which invokes the ioctl. 85 */ 86 typedef dladm_status_t pd_setf_t(prop_desc_t *, datalink_id_t, 87 val_desc_t *propval, uint_t cnt, uint_t flags, 88 datalink_media_t); 89 90 /* 91 * The linkprop check() callback. 92 * - propstrp: property string array which keeps the property to be checked. 93 * - cnt: number of properties. 94 * - propval: return value; the property values of the given property strings. 95 * 96 * pd_check checks that the input values are valid. It does so by 97 * iteraring through the pd_modval list for the property. If 98 * the modifiable values cannot be expressed as a list, a pd_check 99 * specific to this property can be used. If the input values are 100 * verified to be valid, pd_check allocates a val_desc_t and fills it 101 * with either a val_desc_t found on the pd_modval list or something 102 * generated on the fly. 103 */ 104 typedef dladm_status_t pd_checkf_t(prop_desc_t *pdp, datalink_id_t, 105 char **propstrp, uint_t cnt, val_desc_t *propval, 106 datalink_media_t); 107 108 typedef struct link_attr_s { 109 mac_prop_id_t pp_id; 110 size_t pp_valsize; 111 char *pp_name; 112 } link_attr_t; 113 114 static dld_ioc_macprop_t *i_dladm_buf_alloc_by_name(size_t, datalink_id_t, 115 const char *, uint_t, dladm_status_t *); 116 static dld_ioc_macprop_t *i_dladm_buf_alloc_by_id(size_t, datalink_id_t, 117 mac_prop_id_t, uint_t, dladm_status_t *); 118 static dld_ioc_macprop_t *i_dladm_get_public_prop(datalink_id_t, char *, uint_t, 119 dladm_status_t *, uint_t *); 120 121 static dladm_status_t i_dladm_set_prop(datalink_id_t, const char *, char **, 122 uint_t, uint_t); 123 static dladm_status_t i_dladm_get_prop(datalink_id_t, const char *, char **, 124 uint_t *, dladm_prop_type_t, uint_t); 125 static link_attr_t *dladm_name2prop(const char *); 126 static link_attr_t *dladm_id2prop(mac_prop_id_t); 127 128 static pd_getf_t do_get_zone, do_get_autopush, do_get_rate_mod, 129 do_get_rate_prop, do_get_channel_prop, 130 do_get_powermode_prop, do_get_radio_prop, 131 i_dladm_duplex_get, i_dladm_status_get, 132 i_dladm_binary_get, i_dladm_uint32_get, 133 i_dladm_flowctl_get, dld_maxbw_get, dld_cpus_get, 134 dld_priority_get; 135 136 static pd_setf_t do_set_zone, do_set_rate_prop, 137 do_set_powermode_prop, do_set_radio_prop, 138 i_dladm_set_public_prop, do_set_res, do_set_cpus; 139 140 static pd_checkf_t do_check_zone, do_check_autopush, do_check_rate, 141 i_dladm_defmtu_check, do_check_maxbw, do_check_cpus, 142 do_check_priority; 143 144 static dladm_status_t i_dladm_speed_get(prop_desc_t *, datalink_id_t, 145 char **, uint_t *, uint_t, uint_t *); 146 static dladm_status_t i_dladm_wlan_get_legacy_ioctl(datalink_id_t, void *, 147 uint_t, uint_t); 148 static dladm_status_t i_dladm_wlan_set_legacy_ioctl(datalink_id_t, void *, 149 uint_t, uint_t); 150 static dladm_status_t i_dladm_macprop(void *, boolean_t); 151 static const char *dladm_perm2str(uint_t, char *); 152 153 struct prop_desc { 154 /* 155 * link property name 156 */ 157 char *pd_name; 158 159 /* 160 * default property value, can be set to { "", NULL } 161 */ 162 val_desc_t pd_defval; 163 164 /* 165 * list of optional property values, can be NULL. 166 * 167 * This is set to non-NULL if there is a list of possible property 168 * values. pd_optval would point to the array of possible values. 169 */ 170 val_desc_t *pd_optval; 171 172 /* 173 * count of the above optional property values. 0 if pd_optval is NULL. 174 */ 175 uint_t pd_noptval; 176 177 /* 178 * callback to set link property; 179 * set to NULL if this property is read-only 180 */ 181 pd_setf_t *pd_set; 182 183 /* 184 * callback to get modifiable link property 185 */ 186 pd_getf_t *pd_getmod; 187 188 /* 189 * callback to get current link property 190 */ 191 pd_getf_t *pd_get; 192 193 /* 194 * callback to validate link property value, set to NULL if pd_optval 195 * is not NULL. In that case, validate the value by comparing it with 196 * the pd_optval. Return a val_desc_t array pointer if the value is 197 * valid. 198 */ 199 pd_checkf_t *pd_check; 200 201 uint_t pd_flags; 202 #define PD_TEMPONLY 0x1 /* property is temporary only */ 203 #define PD_CHECK_ALLOC 0x2 /* alloc vd_val as part of pd_check */ 204 /* 205 * indicate link classes this property applies to. 206 */ 207 datalink_class_t pd_class; 208 209 /* 210 * indicate link media type this property applies to. 211 */ 212 datalink_media_t pd_dmedia; 213 }; 214 215 #define MAC_PROP_BUFSIZE(v) sizeof (dld_ioc_macprop_t) + (v) - 1 216 217 /* 218 * Supported link properties enumerated in the prop_table[] array are 219 * computed using the callback functions in that array. To compute the 220 * property value, multiple distinct system calls may be needed (e.g., 221 * for wifi speed, we need to issue system calls to get desired/supported 222 * rates). The link_attr[] table enumerates the interfaces to the kernel, 223 * and the type/size of the data passed in the user-kernel interface. 224 */ 225 static link_attr_t link_attr[] = { 226 { MAC_PROP_DUPLEX, sizeof (link_duplex_t), "duplex"}, 227 228 { MAC_PROP_SPEED, sizeof (uint64_t), "speed"}, 229 230 { MAC_PROP_STATUS, sizeof (link_state_t), "state"}, 231 232 { MAC_PROP_AUTONEG, sizeof (uint8_t), "adv_autoneg_cap"}, 233 234 { MAC_PROP_MTU, sizeof (uint32_t), "mtu"}, 235 236 { MAC_PROP_FLOWCTRL, sizeof (link_flowctrl_t), "flowctrl"}, 237 238 { MAC_PROP_ZONE, sizeof (dld_ioc_zid_t), "zone"}, 239 240 { MAC_PROP_AUTOPUSH, sizeof (struct dlautopush), "autopush"}, 241 242 { MAC_PROP_ADV_1000FDX_CAP, sizeof (uint8_t), "adv_1000fdx_cap"}, 243 244 { MAC_PROP_EN_1000FDX_CAP, sizeof (uint8_t), "en_1000fdx_cap"}, 245 246 { MAC_PROP_ADV_1000HDX_CAP, sizeof (uint8_t), "adv_1000hdx_cap"}, 247 248 { MAC_PROP_EN_1000HDX_CAP, sizeof (uint8_t), "en_1000hdx_cap"}, 249 250 { MAC_PROP_ADV_100FDX_CAP, sizeof (uint8_t), "adv_100fdx_cap"}, 251 252 { MAC_PROP_EN_100FDX_CAP, sizeof (uint8_t), "en_100fdx_cap"}, 253 254 { MAC_PROP_ADV_100HDX_CAP, sizeof (uint8_t), "adv_100hdx_cap"}, 255 256 { MAC_PROP_EN_100HDX_CAP, sizeof (uint8_t), "en_100hdx_cap"}, 257 258 { MAC_PROP_ADV_10FDX_CAP, sizeof (uint8_t), "adv_10fdx_cap"}, 259 260 { MAC_PROP_EN_10FDX_CAP, sizeof (uint8_t), "en_10fdx_cap"}, 261 262 { MAC_PROP_ADV_10HDX_CAP, sizeof (uint8_t), "adv_10hdx_cap"}, 263 264 { MAC_PROP_EN_10HDX_CAP, sizeof (uint8_t), "en_10hdx_cap"}, 265 266 { MAC_PROP_WL_ESSID, sizeof (wl_linkstatus_t), "essid"}, 267 268 { MAC_PROP_WL_BSSID, sizeof (wl_bssid_t), "bssid"}, 269 270 { MAC_PROP_WL_BSSTYPE, sizeof (wl_bss_type_t), "bsstype"}, 271 272 { MAC_PROP_WL_LINKSTATUS, sizeof (wl_linkstatus_t), "wl_linkstatus"}, 273 274 /* wl_rates_t has variable length */ 275 { MAC_PROP_WL_DESIRED_RATES, sizeof (wl_rates_t), "desired_rates"}, 276 277 /* wl_rates_t has variable length */ 278 { MAC_PROP_WL_SUPPORTED_RATES, sizeof (wl_rates_t), "supported_rates"}, 279 280 { MAC_PROP_WL_AUTH_MODE, sizeof (wl_authmode_t), "authmode"}, 281 282 { MAC_PROP_WL_ENCRYPTION, sizeof (wl_encryption_t), "encryption"}, 283 284 { MAC_PROP_WL_RSSI, sizeof (wl_rssi_t), "signal"}, 285 286 { MAC_PROP_WL_PHY_CONFIG, sizeof (wl_phy_conf_t), "phy_conf"}, 287 288 { MAC_PROP_WL_CAPABILITY, sizeof (wl_capability_t), "capability"}, 289 290 { MAC_PROP_WL_WPA, sizeof (wl_wpa_t), "wpa"}, 291 292 /* wl_wpa_ess_t has variable length */ 293 { MAC_PROP_WL_SCANRESULTS, sizeof (wl_wpa_ess_t), "scan_results"}, 294 295 { MAC_PROP_WL_POWER_MODE, sizeof (wl_ps_mode_t), "powermode"}, 296 297 { MAC_PROP_WL_RADIO, sizeof (dladm_wlan_radio_t), "wl_radio"}, 298 299 { MAC_PROP_WL_ESS_LIST, sizeof (wl_ess_list_t), "wl_ess_list"}, 300 301 { MAC_PROP_WL_KEY_TAB, sizeof (wl_wep_key_tab_t), "wl_wep_key"}, 302 303 { MAC_PROP_WL_CREATE_IBSS, sizeof (wl_create_ibss_t), "createibss"}, 304 305 /* wl_wpa_ie_t has variable length */ 306 { MAC_PROP_WL_SETOPTIE, sizeof (wl_wpa_ie_t), "set_ie"}, 307 308 { MAC_PROP_WL_DELKEY, sizeof (wl_del_key_t), "wpa_del_key"}, 309 310 { MAC_PROP_WL_KEY, sizeof (wl_key_t), "wl_key"}, 311 312 { MAC_PROP_WL_MLME, sizeof (wl_mlme_t), "mlme"}, 313 314 { MAC_PROP_MAXBW, sizeof (mac_resource_props_t), "maxbw"}, 315 316 { MAC_PROP_PRIO, sizeof (mac_resource_props_t), "priority"}, 317 318 { MAC_PROP_BIND_CPU, sizeof (mac_resource_props_t), "cpus"}, 319 320 { MAC_PROP_PRIVATE, 0, "driver-private"} 321 322 }; 323 324 static val_desc_t link_duplex_vals[] = { 325 { "half", LINK_DUPLEX_HALF }, 326 { "full", LINK_DUPLEX_HALF } 327 }; 328 static val_desc_t link_status_vals[] = { 329 { "up", LINK_STATE_UP }, 330 { "down", LINK_STATE_DOWN } 331 }; 332 static val_desc_t link_01_vals[] = { 333 { "1", 1 }, 334 { "0", 0 } 335 }; 336 static val_desc_t link_flow_vals[] = { 337 { "no", LINK_FLOWCTRL_NONE }, 338 { "tx", LINK_FLOWCTRL_TX }, 339 { "rx", LINK_FLOWCTRL_RX }, 340 { "bi", LINK_FLOWCTRL_BI } 341 }; 342 static val_desc_t link_priority_vals[] = { 343 { "low", MPL_LOW }, 344 { "medium", MPL_MEDIUM }, 345 { "high", MPL_HIGH } 346 }; 347 348 static val_desc_t dladm_wlan_radio_vals[] = { 349 { "on", DLADM_WLAN_RADIO_ON }, 350 { "off", DLADM_WLAN_RADIO_OFF } 351 }; 352 353 static val_desc_t dladm_wlan_powermode_vals[] = { 354 { "off", DLADM_WLAN_PM_OFF }, 355 { "fast", DLADM_WLAN_PM_FAST }, 356 { "max", DLADM_WLAN_PM_MAX } 357 }; 358 359 #define VALCNT(vals) (sizeof ((vals)) / sizeof (val_desc_t)) 360 #define RESET_VAL ((uintptr_t)-1) 361 362 static prop_desc_t prop_table[] = { 363 { "channel", { NULL, 0 }, 364 NULL, 0, NULL, NULL, 365 do_get_channel_prop, NULL, 0, 366 DATALINK_CLASS_PHYS, DL_WIFI }, 367 368 { "powermode", { "off", DLADM_WLAN_PM_OFF }, 369 dladm_wlan_powermode_vals, VALCNT(dladm_wlan_powermode_vals), 370 do_set_powermode_prop, NULL, 371 do_get_powermode_prop, NULL, 0, 372 DATALINK_CLASS_PHYS, DL_WIFI }, 373 374 { "radio", { "on", DLADM_WLAN_RADIO_ON }, 375 dladm_wlan_radio_vals, VALCNT(dladm_wlan_radio_vals), 376 do_set_radio_prop, NULL, 377 do_get_radio_prop, NULL, 0, 378 DATALINK_CLASS_PHYS, DL_WIFI }, 379 380 { "speed", { "", 0 }, NULL, 0, 381 do_set_rate_prop, do_get_rate_mod, 382 do_get_rate_prop, do_check_rate, 0, 383 DATALINK_CLASS_PHYS, DATALINK_ANY_MEDIATYPE }, 384 385 { "autopush", { "", 0 }, NULL, 0, 386 i_dladm_set_public_prop, NULL, 387 do_get_autopush, do_check_autopush, PD_CHECK_ALLOC, 388 DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE }, 389 390 { "zone", { "", 0 }, NULL, 0, 391 do_set_zone, NULL, 392 do_get_zone, do_check_zone, PD_TEMPONLY|PD_CHECK_ALLOC, 393 DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE }, 394 395 { "duplex", { "", 0 }, 396 link_duplex_vals, VALCNT(link_duplex_vals), 397 NULL, NULL, i_dladm_duplex_get, NULL, 398 0, DATALINK_CLASS_PHYS, DL_ETHER }, 399 400 { "state", { "up", LINK_STATE_UP }, 401 link_status_vals, VALCNT(link_status_vals), 402 NULL, NULL, i_dladm_status_get, NULL, 403 0, DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE }, 404 405 { "adv_autoneg_cap", { "1", 1 }, 406 link_01_vals, VALCNT(link_01_vals), 407 i_dladm_set_public_prop, NULL, i_dladm_binary_get, NULL, 408 0, DATALINK_CLASS_PHYS, DL_ETHER }, 409 410 { "mtu", { "", 0 }, NULL, 0, 411 i_dladm_set_public_prop, NULL, i_dladm_uint32_get, 412 i_dladm_defmtu_check, 0, DATALINK_CLASS_ALL, 413 DATALINK_ANY_MEDIATYPE }, 414 415 { "flowctrl", { "", 0 }, 416 link_flow_vals, VALCNT(link_flow_vals), 417 i_dladm_set_public_prop, NULL, i_dladm_flowctl_get, NULL, 418 0, DATALINK_CLASS_PHYS, DL_ETHER }, 419 420 { "adv_1000fdx_cap", { "", 0 }, 421 link_01_vals, VALCNT(link_01_vals), 422 NULL, NULL, i_dladm_binary_get, NULL, 423 0, DATALINK_CLASS_PHYS, DL_ETHER }, 424 425 { "en_1000fdx_cap", { "", 0 }, 426 link_01_vals, VALCNT(link_01_vals), 427 i_dladm_set_public_prop, NULL, i_dladm_binary_get, NULL, 428 0, DATALINK_CLASS_PHYS, DL_ETHER }, 429 430 { "adv_1000hdx_cap", { "", 0 }, 431 link_01_vals, VALCNT(link_01_vals), 432 NULL, NULL, i_dladm_binary_get, NULL, 433 0, DATALINK_CLASS_PHYS, DL_ETHER }, 434 435 { "en_1000hdx_cap", { "", 0 }, 436 link_01_vals, VALCNT(link_01_vals), 437 i_dladm_set_public_prop, NULL, i_dladm_binary_get, NULL, 438 0, DATALINK_CLASS_PHYS, DL_ETHER }, 439 440 { "adv_100fdx_cap", { "", 0 }, 441 link_01_vals, VALCNT(link_01_vals), 442 NULL, NULL, i_dladm_binary_get, NULL, 443 0, DATALINK_CLASS_PHYS, DL_ETHER }, 444 445 { "en_100fdx_cap", { "", 0 }, 446 link_01_vals, VALCNT(link_01_vals), 447 i_dladm_set_public_prop, NULL, i_dladm_binary_get, NULL, 448 0, DATALINK_CLASS_PHYS, DL_ETHER }, 449 450 { "adv_100hdx_cap", { "", 0 }, 451 link_01_vals, VALCNT(link_01_vals), 452 NULL, NULL, i_dladm_binary_get, NULL, 453 0, DATALINK_CLASS_PHYS, DL_ETHER }, 454 455 { "en_100hdx_cap", { "", 0 }, 456 link_01_vals, VALCNT(link_01_vals), 457 i_dladm_set_public_prop, NULL, i_dladm_binary_get, NULL, 458 0, DATALINK_CLASS_PHYS, DL_ETHER }, 459 460 { "adv_10fdx_cap", { "", 0 }, 461 link_01_vals, VALCNT(link_01_vals), 462 NULL, NULL, i_dladm_binary_get, NULL, 463 0, DATALINK_CLASS_PHYS, DL_ETHER }, 464 465 { "en_10fdx_cap", { "", 0 }, 466 link_01_vals, VALCNT(link_01_vals), 467 i_dladm_set_public_prop, NULL, i_dladm_binary_get, NULL, 468 0, DATALINK_CLASS_PHYS, DL_ETHER }, 469 470 { "adv_10hdx_cap", { "", 0 }, 471 link_01_vals, VALCNT(link_01_vals), 472 NULL, NULL, i_dladm_binary_get, NULL, 473 0, DATALINK_CLASS_PHYS, DL_ETHER }, 474 475 { "en_10hdx_cap", { "", 0 }, 476 link_01_vals, VALCNT(link_01_vals), 477 i_dladm_set_public_prop, NULL, i_dladm_binary_get, NULL, 478 0, DATALINK_CLASS_PHYS, DL_ETHER }, 479 480 { "maxbw", { "--", RESET_VAL }, NULL, 0, 481 do_set_res, NULL, 482 dld_maxbw_get, do_check_maxbw, PD_CHECK_ALLOC, 483 DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE }, 484 485 { "cpus", { "--", RESET_VAL }, NULL, 0, 486 do_set_cpus, NULL, 487 dld_cpus_get, do_check_cpus, 0, 488 DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE }, 489 490 { "priority", { "high", RESET_VAL }, 491 link_priority_vals, VALCNT(link_priority_vals), do_set_res, NULL, 492 dld_priority_get, do_check_priority, PD_CHECK_ALLOC, 493 DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE }, 494 }; 495 496 #define DLADM_MAX_PROPS (sizeof (prop_table) / sizeof (prop_desc_t)) 497 498 static resource_prop_t rsrc_prop_table[] = { 499 {"maxbw", do_extract_maxbw}, 500 {"priority", do_extract_priority}, 501 {"cpus", do_extract_cpus} 502 }; 503 #define DLADM_MAX_RSRC_PROP (sizeof (rsrc_prop_table) / \ 504 sizeof (resource_prop_t)) 505 506 /* 507 * when retrieving private properties, we pass down a buffer with 508 * DLADM_PROP_BUF_CHUNK of space for the driver to return the property value. 509 */ 510 #define DLADM_PROP_BUF_CHUNK 1024 511 512 static dladm_status_t i_dladm_set_linkprop_db(datalink_id_t, const char *, 513 char **, uint_t); 514 static dladm_status_t i_dladm_get_linkprop_db(datalink_id_t, const char *, 515 char **, uint_t *); 516 static dladm_status_t i_dladm_set_single_prop(datalink_id_t, datalink_class_t, 517 uint32_t, prop_desc_t *, char **, uint_t, uint_t); 518 static dladm_status_t i_dladm_set_linkprop(datalink_id_t, const char *, 519 char **, uint_t, uint_t); 520 static dladm_status_t i_dladm_getset_defval(prop_desc_t *, datalink_id_t, 521 datalink_media_t, uint_t); 522 523 static dladm_status_t link_proplist_check(dladm_arg_list_t *); 524 525 /* 526 * Unfortunately, MAX_SCAN_SUPPORT_RATES is too small to allow all 527 * rates to be retrieved. However, we cannot increase it at this 528 * time because it will break binary compatibility with unbundled 529 * WiFi drivers and utilities. So for now we define an additional 530 * constant, MAX_SUPPORT_RATES, to allow all rates to be retrieved. 531 */ 532 #define MAX_SUPPORT_RATES 64 533 534 #define AP_ANCHOR "[anchor]" 535 #define AP_DELIMITER '.' 536 537 static dladm_status_t 538 do_check_prop(prop_desc_t *pdp, char **prop_val, uint_t val_cnt, 539 val_desc_t *vdp) 540 { 541 int i, j; 542 dladm_status_t status = DLADM_STATUS_OK; 543 544 for (j = 0; j < val_cnt; j++) { 545 for (i = 0; i < pdp->pd_noptval; i++) { 546 if (strcasecmp(*prop_val, 547 pdp->pd_optval[i].vd_name) == 0) { 548 break; 549 } 550 } 551 if (i == pdp->pd_noptval) { 552 status = DLADM_STATUS_BADVAL; 553 goto done; 554 } 555 (void) memcpy(vdp + j, &pdp->pd_optval[i], sizeof (val_desc_t)); 556 } 557 558 done: 559 return (status); 560 } 561 562 static dladm_status_t 563 i_dladm_set_single_prop(datalink_id_t linkid, datalink_class_t class, 564 uint32_t media, prop_desc_t *pdp, char **prop_val, uint_t val_cnt, 565 uint_t flags) 566 { 567 dladm_status_t status = DLADM_STATUS_OK; 568 val_desc_t *vdp = NULL; 569 boolean_t needfree = B_FALSE; 570 uint_t cnt, i; 571 572 if (!(pdp->pd_class & class)) 573 return (DLADM_STATUS_BADARG); 574 575 if (!DATALINK_MEDIA_ACCEPTED(pdp->pd_dmedia, media)) 576 return (DLADM_STATUS_BADARG); 577 578 if ((flags & DLADM_OPT_PERSIST) && (pdp->pd_flags & PD_TEMPONLY)) 579 return (DLADM_STATUS_TEMPONLY); 580 581 if (!(flags & DLADM_OPT_ACTIVE)) 582 return (DLADM_STATUS_OK); 583 584 if (pdp->pd_set == NULL) 585 return (DLADM_STATUS_PROPRDONLY); 586 587 if (prop_val != NULL) { 588 vdp = malloc(sizeof (val_desc_t) * val_cnt); 589 if (vdp == NULL) 590 return (DLADM_STATUS_NOMEM); 591 592 if (pdp->pd_check != NULL) { 593 needfree = ((pdp->pd_flags & PD_CHECK_ALLOC) != 0); 594 status = pdp->pd_check(pdp, linkid, prop_val, val_cnt, 595 vdp, media); 596 } else if (pdp->pd_optval != NULL) { 597 status = do_check_prop(pdp, prop_val, val_cnt, vdp); 598 } else { 599 status = DLADM_STATUS_BADARG; 600 } 601 602 if (status != DLADM_STATUS_OK) 603 goto done; 604 605 cnt = val_cnt; 606 } else { 607 boolean_t defval = B_FALSE; 608 609 if (pdp->pd_defval.vd_name == NULL) 610 return (DLADM_STATUS_NOTSUP); 611 612 cnt = 1; 613 defval = (strlen(pdp->pd_defval.vd_name) > 0); 614 if ((pdp->pd_flags & PD_CHECK_ALLOC) != 0 || defval) { 615 if ((vdp = malloc(sizeof (val_desc_t))) == NULL) 616 return (DLADM_STATUS_NOMEM); 617 618 if (defval) { 619 (void) memcpy(vdp, &pdp->pd_defval, 620 sizeof (val_desc_t)); 621 } else if (pdp->pd_check != NULL) { 622 status = pdp->pd_check(pdp, linkid, prop_val, 623 cnt, vdp, media); 624 if (status != DLADM_STATUS_OK) 625 goto done; 626 } 627 } else { 628 status = i_dladm_getset_defval(pdp, linkid, 629 media, flags); 630 return (status); 631 } 632 } 633 status = pdp->pd_set(pdp, linkid, vdp, cnt, flags, media); 634 if (needfree) { 635 for (i = 0; i < cnt; i++) 636 free((void *)((val_desc_t *)vdp + i)->vd_val); 637 } 638 done: 639 free(vdp); 640 return (status); 641 } 642 643 static dladm_status_t 644 i_dladm_set_linkprop(datalink_id_t linkid, const char *prop_name, 645 char **prop_val, uint_t val_cnt, uint_t flags) 646 { 647 int i; 648 boolean_t found = B_FALSE; 649 datalink_class_t class; 650 uint32_t media; 651 dladm_status_t status = DLADM_STATUS_OK; 652 653 status = dladm_datalink_id2info(linkid, NULL, &class, &media, NULL, 0); 654 if (status != DLADM_STATUS_OK) 655 return (status); 656 657 for (i = 0; i < DLADM_MAX_PROPS; i++) { 658 prop_desc_t *pdp = &prop_table[i]; 659 dladm_status_t s; 660 661 if (prop_name != NULL && 662 (strcasecmp(prop_name, pdp->pd_name) != 0)) 663 continue; 664 found = B_TRUE; 665 s = i_dladm_set_single_prop(linkid, class, media, pdp, prop_val, 666 val_cnt, flags); 667 668 if (prop_name != NULL) { 669 status = s; 670 break; 671 } else { 672 if (s != DLADM_STATUS_OK && 673 s != DLADM_STATUS_NOTSUP) 674 status = s; 675 } 676 } 677 if (!found) { 678 if (prop_name[0] == '_') { 679 /* other private properties */ 680 status = i_dladm_set_prop(linkid, prop_name, prop_val, 681 val_cnt, flags); 682 } else { 683 status = DLADM_STATUS_NOTFOUND; 684 } 685 } 686 687 return (status); 688 } 689 690 /* 691 * Set/reset link property for specific link 692 */ 693 dladm_status_t 694 dladm_set_linkprop(datalink_id_t linkid, const char *prop_name, char **prop_val, 695 uint_t val_cnt, uint_t flags) 696 { 697 dladm_status_t status = DLADM_STATUS_OK; 698 699 if ((linkid == DATALINK_INVALID_LINKID) || (flags == 0) || 700 (prop_val == NULL && val_cnt > 0) || 701 (prop_val != NULL && val_cnt == 0) || 702 (prop_name == NULL && prop_val != NULL)) { 703 return (DLADM_STATUS_BADARG); 704 } 705 706 status = i_dladm_set_linkprop(linkid, prop_name, prop_val, 707 val_cnt, flags); 708 if (status != DLADM_STATUS_OK) 709 return (status); 710 711 if (flags & DLADM_OPT_PERSIST) { 712 status = i_dladm_set_linkprop_db(linkid, prop_name, 713 prop_val, val_cnt); 714 } 715 return (status); 716 } 717 718 /* 719 * Walk link properties of the given specific link. 720 */ 721 dladm_status_t 722 dladm_walk_linkprop(datalink_id_t linkid, void *arg, 723 int (*func)(datalink_id_t, const char *, void *)) 724 { 725 dladm_status_t status; 726 datalink_class_t class; 727 uint_t media; 728 int i; 729 730 if (linkid == DATALINK_INVALID_LINKID || func == NULL) 731 return (DLADM_STATUS_BADARG); 732 733 status = dladm_datalink_id2info(linkid, NULL, &class, &media, NULL, 0); 734 if (status != DLADM_STATUS_OK) 735 return (status); 736 737 for (i = 0; i < DLADM_MAX_PROPS; i++) { 738 if (!(prop_table[i].pd_class & class)) 739 continue; 740 741 if (!DATALINK_MEDIA_ACCEPTED(prop_table[i].pd_dmedia, media)) 742 continue; 743 744 if (func(linkid, prop_table[i].pd_name, arg) == 745 DLADM_WALK_TERMINATE) { 746 break; 747 } 748 } 749 750 return (DLADM_STATUS_OK); 751 } 752 753 /* 754 * Get linkprop of the given specific link. 755 */ 756 dladm_status_t 757 dladm_get_linkprop(datalink_id_t linkid, dladm_prop_type_t type, 758 const char *prop_name, char **prop_val, uint_t *val_cntp) 759 { 760 dladm_status_t status = DLADM_STATUS_OK; 761 datalink_class_t class; 762 uint_t media; 763 prop_desc_t *pdp; 764 uint_t cnt, dld_flags = 0; 765 int i; 766 uint_t perm_flags; 767 768 if (type == DLADM_PROP_VAL_DEFAULT) 769 dld_flags = MAC_PROP_DEFAULT; 770 771 if (linkid == DATALINK_INVALID_LINKID || prop_name == NULL || 772 prop_val == NULL || val_cntp == NULL || *val_cntp == 0) 773 return (DLADM_STATUS_BADARG); 774 775 for (i = 0; i < DLADM_MAX_PROPS; i++) 776 if (strcasecmp(prop_name, prop_table[i].pd_name) == 0) 777 break; 778 779 if (i == DLADM_MAX_PROPS) { 780 if (prop_name[0] == '_') { 781 /* 782 * private property. 783 */ 784 return (i_dladm_get_prop(linkid, prop_name, 785 prop_val, val_cntp, type, dld_flags)); 786 } else { 787 return (DLADM_STATUS_NOTFOUND); 788 } 789 } 790 791 pdp = &prop_table[i]; 792 793 status = dladm_datalink_id2info(linkid, NULL, &class, &media, NULL, 0); 794 if (status != DLADM_STATUS_OK) 795 return (status); 796 797 if (!(pdp->pd_class & class)) 798 return (DLADM_STATUS_BADARG); 799 800 if (!DATALINK_MEDIA_ACCEPTED(pdp->pd_dmedia, media)) 801 return (DLADM_STATUS_BADARG); 802 803 switch (type) { 804 case DLADM_PROP_VAL_CURRENT: 805 status = pdp->pd_get(pdp, linkid, prop_val, val_cntp, media, 806 dld_flags, &perm_flags); 807 break; 808 809 case DLADM_PROP_VAL_PERM: 810 if (pdp->pd_set == NULL) { 811 perm_flags = MAC_PROP_PERM_READ; 812 *val_cntp = 1; 813 } else { 814 status = pdp->pd_get(pdp, linkid, prop_val, val_cntp, 815 media, dld_flags, &perm_flags); 816 } 817 818 *prop_val[0] = '\0'; 819 if (status == DLADM_STATUS_OK) 820 (void) dladm_perm2str(perm_flags, *prop_val); 821 break; 822 823 case DLADM_PROP_VAL_DEFAULT: 824 /* 825 * If defaults are not defined for the property, 826 * pd_defval.vd_name should be null. If the driver 827 * has to be contacted for the value, vd_name should 828 * be the empty string (""). Otherwise, dladm will 829 * just print whatever is in the table. 830 */ 831 if (pdp->pd_defval.vd_name == NULL) { 832 status = DLADM_STATUS_NOTSUP; 833 break; 834 } 835 836 if (strlen(pdp->pd_defval.vd_name) == 0) { 837 status = pdp->pd_get(pdp, linkid, prop_val, val_cntp, 838 media, dld_flags, &perm_flags); 839 } else { 840 (void) strcpy(*prop_val, pdp->pd_defval.vd_name); 841 } 842 *val_cntp = 1; 843 break; 844 845 case DLADM_PROP_VAL_MODIFIABLE: 846 if (pdp->pd_getmod != NULL) { 847 status = pdp->pd_getmod(pdp, linkid, prop_val, 848 val_cntp, media, dld_flags, &perm_flags); 849 break; 850 } 851 cnt = pdp->pd_noptval; 852 if (cnt == 0) { 853 status = DLADM_STATUS_NOTSUP; 854 } else if (cnt > *val_cntp) { 855 status = DLADM_STATUS_TOOSMALL; 856 } else { 857 for (i = 0; i < cnt; i++) { 858 (void) strcpy(prop_val[i], 859 pdp->pd_optval[i].vd_name); 860 } 861 *val_cntp = cnt; 862 } 863 break; 864 case DLADM_PROP_VAL_PERSISTENT: 865 if (pdp->pd_flags & PD_TEMPONLY) 866 return (DLADM_STATUS_TEMPONLY); 867 status = i_dladm_get_linkprop_db(linkid, prop_name, 868 prop_val, val_cntp); 869 break; 870 default: 871 status = DLADM_STATUS_BADARG; 872 break; 873 } 874 875 return (status); 876 } 877 878 /*ARGSUSED*/ 879 static int 880 i_dladm_init_one_prop(datalink_id_t linkid, const char *prop_name, void *arg) 881 { 882 char *buf, **propvals; 883 uint_t i, valcnt = DLADM_MAX_PROP_VALCNT; 884 885 if ((buf = malloc((sizeof (char *) + DLADM_PROP_VAL_MAX) * 886 DLADM_MAX_PROP_VALCNT)) == NULL) { 887 return (DLADM_WALK_CONTINUE); 888 } 889 890 propvals = (char **)(void *)buf; 891 for (i = 0; i < valcnt; i++) { 892 propvals[i] = buf + 893 sizeof (char *) * DLADM_MAX_PROP_VALCNT + 894 i * DLADM_PROP_VAL_MAX; 895 } 896 897 if (dladm_get_linkprop(linkid, DLADM_PROP_VAL_PERSISTENT, prop_name, 898 propvals, &valcnt) != DLADM_STATUS_OK) { 899 goto done; 900 } 901 902 (void) dladm_set_linkprop(linkid, prop_name, propvals, valcnt, 903 DLADM_OPT_ACTIVE); 904 905 done: 906 if (buf != NULL) 907 free(buf); 908 909 return (DLADM_WALK_CONTINUE); 910 } 911 912 /*ARGSUSED*/ 913 static int 914 i_dladm_init_linkprop(datalink_id_t linkid, void *arg) 915 { 916 datalink_class_t class; 917 dladm_status_t status; 918 919 status = dladm_datalink_id2info(linkid, NULL, &class, NULL, NULL, 0); 920 if (status != DLADM_STATUS_OK) 921 return (DLADM_WALK_TERMINATE); 922 923 if ((class & (DATALINK_CLASS_VNIC | DATALINK_CLASS_VLAN)) == 0) 924 (void) dladm_init_linkprop(linkid, B_TRUE); 925 926 return (DLADM_WALK_CONTINUE); 927 } 928 929 dladm_status_t 930 dladm_init_linkprop(datalink_id_t linkid, boolean_t any_media) 931 { 932 datalink_media_t dmedia; 933 uint32_t media; 934 935 dmedia = any_media ? DATALINK_ANY_MEDIATYPE : DL_WIFI; 936 937 if (linkid == DATALINK_ALL_LINKID) { 938 (void) dladm_walk_datalink_id(i_dladm_init_linkprop, NULL, 939 DATALINK_CLASS_ALL, dmedia, DLADM_OPT_PERSIST); 940 } else if (any_media || ((dladm_datalink_id2info(linkid, NULL, NULL, 941 &media, NULL, 0) == DLADM_STATUS_OK) && 942 DATALINK_MEDIA_ACCEPTED(dmedia, media))) { 943 (void) dladm_walk_linkprop(linkid, NULL, i_dladm_init_one_prop); 944 } 945 return (DLADM_STATUS_OK); 946 } 947 948 /* ARGSUSED */ 949 static dladm_status_t 950 do_get_zone(prop_desc_t *pdp, datalink_id_t linkid, 951 char **prop_val, uint_t *val_cnt, datalink_media_t media, 952 uint_t flags, uint_t *perm_flags) 953 { 954 char zone_name[ZONENAME_MAX]; 955 zoneid_t zid; 956 dladm_status_t status; 957 char *cp; 958 dld_ioc_macprop_t *dip; 959 960 if (flags != 0) 961 return (DLADM_STATUS_NOTSUP); 962 963 dip = i_dladm_get_public_prop(linkid, pdp->pd_name, flags, 964 &status, perm_flags); 965 if (status != DLADM_STATUS_OK) 966 return (status); 967 968 cp = dip->pr_val; 969 (void) memcpy(&zid, cp, sizeof (zid)); 970 free(dip); 971 972 *val_cnt = 1; 973 if (zid != GLOBAL_ZONEID) { 974 if (getzonenamebyid(zid, zone_name, sizeof (zone_name)) < 0) { 975 return (dladm_errno2status(errno)); 976 } 977 978 (void) strncpy(*prop_val, zone_name, DLADM_PROP_VAL_MAX); 979 } else { 980 *prop_val[0] = '\0'; 981 } 982 983 return (DLADM_STATUS_OK); 984 } 985 986 typedef int (*zone_get_devroot_t)(char *, char *, size_t); 987 988 static int 989 i_dladm_get_zone_dev(char *zone_name, char *dev, size_t devlen) 990 { 991 char root[MAXPATHLEN]; 992 zone_get_devroot_t real_zone_get_devroot; 993 void *dlhandle; 994 void *sym; 995 int ret; 996 997 if ((dlhandle = dlopen("libzonecfg.so.1", RTLD_LAZY)) == NULL) 998 return (-1); 999 1000 if ((sym = dlsym(dlhandle, "zone_get_devroot")) == NULL) { 1001 (void) dlclose(dlhandle); 1002 return (-1); 1003 } 1004 1005 real_zone_get_devroot = (zone_get_devroot_t)sym; 1006 1007 if ((ret = real_zone_get_devroot(zone_name, root, sizeof (root))) == 0) 1008 (void) snprintf(dev, devlen, "%s%s", root, "/dev"); 1009 (void) dlclose(dlhandle); 1010 return (ret); 1011 } 1012 1013 static dladm_status_t 1014 i_dladm_update_deventry(zoneid_t zid, datalink_id_t linkid, boolean_t add) 1015 { 1016 char path[MAXPATHLEN]; 1017 char name[MAXLINKNAMELEN]; 1018 di_prof_t prof = NULL; 1019 char zone_name[ZONENAME_MAX]; 1020 dladm_status_t status; 1021 int ret; 1022 1023 if (getzonenamebyid(zid, zone_name, sizeof (zone_name)) < 0) 1024 return (dladm_errno2status(errno)); 1025 if (i_dladm_get_zone_dev(zone_name, path, sizeof (path)) != 0) 1026 return (dladm_errno2status(errno)); 1027 if (di_prof_init(path, &prof) != 0) 1028 return (dladm_errno2status(errno)); 1029 1030 status = dladm_linkid2legacyname(linkid, name, MAXLINKNAMELEN); 1031 if (status != DLADM_STATUS_OK) 1032 goto cleanup; 1033 1034 if (add) 1035 ret = di_prof_add_dev(prof, name); 1036 else 1037 ret = di_prof_add_exclude(prof, name); 1038 1039 if (ret != 0) { 1040 status = dladm_errno2status(errno); 1041 goto cleanup; 1042 } 1043 1044 if (di_prof_commit(prof) != 0) 1045 status = dladm_errno2status(errno); 1046 cleanup: 1047 if (prof) 1048 di_prof_fini(prof); 1049 1050 return (status); 1051 } 1052 1053 /* ARGSUSED */ 1054 static dladm_status_t 1055 do_set_zone(prop_desc_t *pdp, datalink_id_t linkid, val_desc_t *vdp, 1056 uint_t val_cnt, uint_t flags, datalink_media_t media) 1057 { 1058 dladm_status_t status = DLADM_STATUS_OK; 1059 zoneid_t zid_old, zid_new; 1060 char link[MAXLINKNAMELEN]; 1061 char *cp; 1062 dld_ioc_macprop_t *dip; 1063 dld_ioc_zid_t *dzp; 1064 1065 if (val_cnt != 1) 1066 return (DLADM_STATUS_BADVALCNT); 1067 1068 dzp = (dld_ioc_zid_t *)vdp->vd_val; 1069 1070 dip = i_dladm_get_public_prop(linkid, pdp->pd_name, flags, 1071 &status, NULL); 1072 if (status != DLADM_STATUS_OK) 1073 return (status); 1074 1075 cp = dip->pr_val; 1076 (void) memcpy(&zid_old, cp, sizeof (zid_old)); 1077 free(dip); 1078 1079 zid_new = dzp->diz_zid; 1080 (void) strlcpy(link, dzp->diz_link, MAXLINKNAMELEN); 1081 1082 /* Do nothing if setting to current value */ 1083 if (zid_new == zid_old) 1084 return (status); 1085 1086 if (zid_new != GLOBAL_ZONEID) { 1087 /* 1088 * If the new zoneid is the global zone, we could destroy 1089 * the link (in the case of an implicitly-created VLAN) as a 1090 * result of setting the zoneid. In that case, we defer the 1091 * operation to the end of this function to avoid recreating 1092 * the VLAN and getting a different linkid during the rollback 1093 * if other operation fails. 1094 * 1095 * Otherwise, this operation will hold a reference to the 1096 * link and prevent a link renaming, so we need to do it 1097 * before other operations. 1098 */ 1099 status = i_dladm_set_public_prop(pdp, linkid, vdp, val_cnt, 1100 flags, media); 1101 if (status != DLADM_STATUS_OK) 1102 return (status); 1103 } 1104 1105 if (zid_old != GLOBAL_ZONEID) { 1106 if (zone_remove_datalink(zid_old, link) != 0 && 1107 errno != ENXIO) { 1108 status = dladm_errno2status(errno); 1109 goto rollback1; 1110 } 1111 1112 /* 1113 * It is okay to fail to update the /dev entry (some 1114 * vanity-named links do not have a /dev entry). 1115 */ 1116 (void) i_dladm_update_deventry(zid_old, linkid, B_FALSE); 1117 } 1118 1119 if (zid_new != GLOBAL_ZONEID) { 1120 if (zone_add_datalink(zid_new, link) != 0) { 1121 status = dladm_errno2status(errno); 1122 goto rollback2; 1123 } 1124 1125 (void) i_dladm_update_deventry(zid_new, linkid, B_TRUE); 1126 } else { 1127 status = i_dladm_set_public_prop(pdp, linkid, vdp, val_cnt, 1128 flags, media); 1129 if (status != DLADM_STATUS_OK) 1130 goto rollback2; 1131 } 1132 1133 return (DLADM_STATUS_OK); 1134 1135 rollback2: 1136 if (zid_old != GLOBAL_ZONEID) 1137 (void) i_dladm_update_deventry(zid_old, linkid, B_TRUE); 1138 if (zid_old != GLOBAL_ZONEID) 1139 (void) zone_add_datalink(zid_old, link); 1140 rollback1: 1141 if (zid_new != GLOBAL_ZONEID) { 1142 dzp->diz_zid = zid_old; 1143 (void) i_dladm_set_public_prop(pdp, linkid, vdp, val_cnt, 1144 flags, media); 1145 } 1146 1147 return (status); 1148 } 1149 1150 /* ARGSUSED */ 1151 static dladm_status_t 1152 do_check_zone(prop_desc_t *pdp, datalink_id_t linkid, char **prop_val, 1153 uint_t val_cnt, val_desc_t *vdp, datalink_media_t media) 1154 { 1155 char *zone_name; 1156 char linkname[MAXLINKNAMELEN]; 1157 zoneid_t zoneid; 1158 dladm_status_t status = DLADM_STATUS_OK; 1159 dld_ioc_zid_t *dzp; 1160 1161 if (val_cnt != 1) 1162 return (DLADM_STATUS_BADVALCNT); 1163 1164 dzp = malloc(sizeof (dld_ioc_zid_t)); 1165 if (dzp == NULL) 1166 return (DLADM_STATUS_NOMEM); 1167 1168 if ((status = dladm_datalink_id2info(linkid, NULL, NULL, NULL, 1169 linkname, MAXLINKNAMELEN)) != DLADM_STATUS_OK) { 1170 goto done; 1171 } 1172 1173 zone_name = (prop_val != NULL) ? *prop_val : GLOBAL_ZONENAME; 1174 if (strlen(linkname) > MAXLINKNAMELEN) { 1175 status = DLADM_STATUS_BADVAL; 1176 goto done; 1177 } 1178 1179 if ((zoneid = getzoneidbyname(zone_name)) == -1) { 1180 status = DLADM_STATUS_BADVAL; 1181 goto done; 1182 } 1183 1184 if (zoneid != GLOBAL_ZONEID) { 1185 ushort_t flags; 1186 1187 if (zone_getattr(zoneid, ZONE_ATTR_FLAGS, &flags, 1188 sizeof (flags)) < 0) { 1189 status = dladm_errno2status(errno); 1190 goto done; 1191 } 1192 1193 if (!(flags & ZF_NET_EXCL)) { 1194 status = DLADM_STATUS_BADVAL; 1195 goto done; 1196 } 1197 } 1198 1199 (void) memset(dzp, 0, sizeof (dld_ioc_zid_t)); 1200 1201 dzp->diz_zid = zoneid; 1202 (void) strlcpy(dzp->diz_link, linkname, MAXLINKNAMELEN); 1203 1204 vdp->vd_val = (uintptr_t)dzp; 1205 return (DLADM_STATUS_OK); 1206 done: 1207 free(dzp); 1208 return (status); 1209 } 1210 1211 /* ARGSUSED */ 1212 static dladm_status_t 1213 dld_maxbw_get(prop_desc_t *pdp, datalink_id_t linkid, 1214 char **prop_val, uint_t *val_cnt, datalink_media_t media, 1215 uint_t flags, uint_t *perm_flags) 1216 { 1217 dld_ioc_macprop_t *dip; 1218 mac_resource_props_t mrp; 1219 dladm_status_t status; 1220 1221 dip = i_dladm_get_public_prop(linkid, pdp->pd_name, flags, 1222 &status, perm_flags); 1223 if (dip == NULL) 1224 return (status); 1225 1226 bcopy(dip->pr_val, &mrp, sizeof (mac_resource_props_t)); 1227 free(dip); 1228 1229 if ((mrp.mrp_mask & MRP_MAXBW) == 0) { 1230 (*prop_val)[0] = '\0'; 1231 } else { 1232 (void) dladm_bw2str(mrp.mrp_maxbw, prop_val[0]); 1233 } 1234 *val_cnt = 1; 1235 return (DLADM_STATUS_OK); 1236 } 1237 1238 /* ARGSUSED */ 1239 static dladm_status_t 1240 do_check_maxbw(prop_desc_t *pdp, datalink_id_t linkid, char **prop_val, 1241 uint_t val_cnt, val_desc_t *vdp, datalink_media_t media) 1242 { 1243 uint64_t *maxbw; 1244 dladm_status_t status = DLADM_STATUS_OK; 1245 1246 if (val_cnt != 1) 1247 return (DLADM_STATUS_BADVALCNT); 1248 1249 maxbw = malloc(sizeof (uint64_t)); 1250 if (maxbw == NULL) 1251 return (DLADM_STATUS_NOMEM); 1252 1253 status = dladm_str2bw(*prop_val, maxbw); 1254 if (status != DLADM_STATUS_OK) { 1255 free(maxbw); 1256 return (status); 1257 } 1258 1259 if ((*maxbw < MRP_MAXBW_MINVAL) && (*maxbw != 0)) { 1260 free(maxbw); 1261 return (DLADM_STATUS_MINMAXBW); 1262 } 1263 1264 vdp->vd_val = (uintptr_t)maxbw; 1265 return (DLADM_STATUS_OK); 1266 } 1267 1268 /* ARGSUSED */ 1269 dladm_status_t 1270 do_extract_maxbw(val_desc_t *vdp, void *arg, uint_t cnt) 1271 { 1272 mac_resource_props_t *mrp = (mac_resource_props_t *)arg; 1273 1274 bcopy((char *)vdp->vd_val, &mrp->mrp_maxbw, sizeof (uint64_t)); 1275 mrp->mrp_mask |= MRP_MAXBW; 1276 1277 return (DLADM_STATUS_OK); 1278 } 1279 1280 /* ARGSUSED */ 1281 static dladm_status_t 1282 dld_cpus_get(prop_desc_t *pdp, datalink_id_t linkid, 1283 char **prop_val, uint_t *val_cnt, datalink_media_t media, 1284 uint_t flags, uint_t *perm_flags) 1285 { 1286 dld_ioc_macprop_t *dip; 1287 mac_resource_props_t mrp; 1288 int i; 1289 uint32_t ncpus; 1290 uchar_t *cp; 1291 dladm_status_t status; 1292 1293 dip = i_dladm_get_public_prop(linkid, pdp->pd_name, flags, 1294 &status, perm_flags); 1295 if (dip == NULL) 1296 return (status); 1297 1298 cp = (uchar_t *)dip->pr_val; 1299 (void) memcpy(&mrp, cp, sizeof (mac_resource_props_t)); 1300 free(dip); 1301 1302 ncpus = mrp.mrp_ncpus; 1303 1304 if (ncpus > *val_cnt) 1305 return (DLADM_STATUS_TOOSMALL); 1306 1307 if (ncpus == 0) { 1308 (*prop_val)[0] = '\0'; 1309 *val_cnt = 1; 1310 return (DLADM_STATUS_OK); 1311 } 1312 1313 *val_cnt = ncpus; 1314 for (i = 0; i < ncpus; i++) { 1315 (void) snprintf(prop_val[i], DLADM_PROP_VAL_MAX, 1316 "%u", mrp.mrp_cpu[i]); 1317 } 1318 return (DLADM_STATUS_OK); 1319 } 1320 1321 /* ARGSUSED */ 1322 static dladm_status_t 1323 do_set_res(prop_desc_t *pdp, datalink_id_t linkid, val_desc_t *vdp, 1324 uint_t val_cnt, uint_t flags, datalink_media_t media) 1325 { 1326 mac_resource_props_t mrp; 1327 dladm_status_t status = DLADM_STATUS_OK; 1328 dld_ioc_macprop_t *dip; 1329 1330 bzero(&mrp, sizeof (mac_resource_props_t)); 1331 dip = i_dladm_buf_alloc_by_name(0, linkid, pdp->pd_name, 1332 flags, &status); 1333 1334 if (dip == NULL) 1335 return (status); 1336 1337 if (vdp->vd_val == RESET_VAL) { 1338 switch (dip->pr_num) { 1339 case MAC_PROP_MAXBW: 1340 mrp.mrp_maxbw = MRP_MAXBW_RESETVAL; 1341 mrp.mrp_mask = MRP_MAXBW; 1342 break; 1343 case MAC_PROP_PRIO: 1344 mrp.mrp_priority = MPL_RESET; 1345 mrp.mrp_mask = MRP_PRIORITY; 1346 break; 1347 default: 1348 free(dip); 1349 return (DLADM_STATUS_BADARG); 1350 } 1351 } else { 1352 switch (dip->pr_num) { 1353 case MAC_PROP_MAXBW: 1354 bcopy((void *)vdp->vd_val, &mrp.mrp_maxbw, 1355 sizeof (uint64_t)); 1356 mrp.mrp_mask = MRP_MAXBW; 1357 break; 1358 case MAC_PROP_PRIO: 1359 bcopy((void *)vdp->vd_val, &mrp.mrp_priority, 1360 sizeof (mac_priority_level_t)); 1361 mrp.mrp_mask = MRP_PRIORITY; 1362 break; 1363 default: 1364 free(dip); 1365 return (DLADM_STATUS_BADARG); 1366 } 1367 } 1368 1369 (void) memcpy(dip->pr_val, &mrp, dip->pr_valsize); 1370 status = i_dladm_macprop(dip, B_TRUE); 1371 free(dip); 1372 return (status); 1373 } 1374 1375 /* ARGSUSED */ 1376 static dladm_status_t 1377 do_set_cpus(prop_desc_t *pdp, datalink_id_t linkid, val_desc_t *vdp, 1378 uint_t val_cnt, uint_t flags, datalink_media_t media) 1379 { 1380 mac_resource_props_t mrp; 1381 dladm_status_t status; 1382 dld_ioc_macprop_t *dip; 1383 datalink_class_t class; 1384 1385 /* 1386 * CPU bindings can be set on VNIC and regular physical links. 1387 * However VNICs fails the dladm_phys_info test(). So apply 1388 * the phys_info test only on physical links. 1389 */ 1390 if ((status = dladm_datalink_id2info(linkid, NULL, &class, 1391 NULL, NULL, 0)) != DLADM_STATUS_OK) { 1392 return (status); 1393 } 1394 1395 /* 1396 * We set intr_cpu to -1. The interrupt will be retargetted, 1397 * if possible when the setup is complete in MAC. 1398 */ 1399 bzero(&mrp, sizeof (mac_resource_props_t)); 1400 mrp.mrp_mask = MRP_CPUS; 1401 if (vdp != NULL && vdp->vd_val != RESET_VAL) { 1402 mac_resource_props_t *vmrp; 1403 1404 vmrp = (mac_resource_props_t *)vdp->vd_val; 1405 if (vmrp->mrp_ncpus > 0) { 1406 bcopy(vmrp, &mrp, sizeof (mac_resource_props_t)); 1407 mrp.mrp_mask = MRP_CPUS; 1408 } 1409 mrp.mrp_mask |= MRP_CPUS_USERSPEC; 1410 mrp.mrp_fanout_mode = MCM_CPUS; 1411 mrp.mrp_intr_cpu = -1; 1412 } 1413 1414 dip = i_dladm_buf_alloc_by_name(0, linkid, pdp->pd_name, 1415 flags, &status); 1416 if (dip == NULL) 1417 return (status); 1418 1419 (void) memcpy(dip->pr_val, &mrp, dip->pr_valsize); 1420 status = i_dladm_macprop(dip, B_TRUE); 1421 free(dip); 1422 return (status); 1423 } 1424 1425 /* ARGSUSED */ 1426 static dladm_status_t 1427 do_check_cpus(prop_desc_t *pdp, datalink_id_t linkid, char **prop_val, 1428 uint_t val_cnt, val_desc_t *vdp, datalink_media_t media) 1429 { 1430 uint32_t cpuid; 1431 int i, j, rc; 1432 long nproc = sysconf(_SC_NPROCESSORS_CONF); 1433 mac_resource_props_t *mrp; 1434 1435 mrp = malloc(sizeof (mac_resource_props_t)); 1436 if (mrp == NULL) 1437 return (DLADM_STATUS_NOMEM); 1438 1439 for (i = 0; i < val_cnt; i++) { 1440 errno = 0; 1441 cpuid = strtol(prop_val[i], (char **)NULL, 10); 1442 if (errno != 0 || cpuid >= nproc) { 1443 free(mrp); 1444 return (DLADM_STATUS_CPUMAX); 1445 } 1446 rc = p_online(cpuid, P_STATUS); 1447 if (rc < 1) { 1448 free(mrp); 1449 return (DLADM_STATUS_CPUERR); 1450 } 1451 if (rc != P_ONLINE) { 1452 free(mrp); 1453 return (DLADM_STATUS_CPUNOTONLINE); 1454 } 1455 mrp->mrp_cpu[i] = cpuid; 1456 } 1457 mrp->mrp_ncpus = (uint32_t)val_cnt; 1458 1459 /* Check for duplicates */ 1460 for (i = 0; i < val_cnt; i++) { 1461 for (j = 0; j < val_cnt; j++) { 1462 if (i != j && mrp->mrp_cpu[i] == mrp->mrp_cpu[j]) { 1463 free(mrp); 1464 return (DLADM_STATUS_BADARG); 1465 } 1466 } 1467 } 1468 vdp->vd_val = (uintptr_t)mrp; 1469 1470 return (DLADM_STATUS_OK); 1471 } 1472 1473 /* ARGSUSED */ 1474 dladm_status_t 1475 do_extract_cpus(val_desc_t *vdp, void *arg, uint_t cnt) 1476 { 1477 mac_resource_props_t *mrp = (mac_resource_props_t *)arg; 1478 mac_resource_props_t *vmrp = (mac_resource_props_t *)vdp->vd_val; 1479 int i; 1480 1481 for (i = 0; i < vmrp->mrp_ncpus; i++) { 1482 mrp->mrp_cpu[i] = vmrp->mrp_cpu[i]; 1483 } 1484 mrp->mrp_ncpus = vmrp->mrp_ncpus; 1485 mrp->mrp_mask |= (MRP_CPUS|MRP_CPUS_USERSPEC); 1486 mrp->mrp_fanout_mode = MCM_CPUS; 1487 1488 return (DLADM_STATUS_OK); 1489 } 1490 1491 /* ARGSUSED */ 1492 static dladm_status_t 1493 dld_priority_get(prop_desc_t *pdp, datalink_id_t linkid, 1494 char **prop_val, uint_t *val_cnt, datalink_media_t media, 1495 uint_t flags, uint_t *perm_flags) 1496 { 1497 dld_ioc_macprop_t *dip; 1498 mac_resource_props_t mrp; 1499 mac_priority_level_t pri; 1500 dladm_status_t status; 1501 1502 dip = i_dladm_get_public_prop(linkid, pdp->pd_name, flags, 1503 &status, perm_flags); 1504 if (dip == NULL) 1505 return (status); 1506 1507 bcopy(dip->pr_val, &mrp, sizeof (mac_resource_props_t)); 1508 free(dip); 1509 1510 pri = ((mrp.mrp_mask & MRP_PRIORITY) == 0) ? MPL_HIGH : 1511 mrp.mrp_priority; 1512 1513 (void) dladm_pri2str(pri, prop_val[0]); 1514 *val_cnt = 1; 1515 return (DLADM_STATUS_OK); 1516 } 1517 1518 /* ARGSUSED */ 1519 static dladm_status_t 1520 do_check_priority(prop_desc_t *pdp, datalink_id_t linkid, char **prop_val, 1521 uint_t val_cnt, val_desc_t *vdp, datalink_media_t media) 1522 { 1523 mac_priority_level_t *pri; 1524 dladm_status_t status = DLADM_STATUS_OK; 1525 1526 if (val_cnt != 1) 1527 return (DLADM_STATUS_BADVALCNT); 1528 1529 pri = malloc(sizeof (mac_priority_level_t)); 1530 if (pri == NULL) 1531 return (DLADM_STATUS_NOMEM); 1532 1533 status = dladm_str2pri(*prop_val, pri); 1534 if (status != DLADM_STATUS_OK) { 1535 free(pri); 1536 return (status); 1537 } 1538 1539 if (*pri < MPL_LOW || *pri > MPL_HIGH) { 1540 free(pri); 1541 return (DLADM_STATUS_BADVAL); 1542 } 1543 1544 vdp->vd_val = (uintptr_t)pri; 1545 return (DLADM_STATUS_OK); 1546 } 1547 1548 /* ARGSUSED */ 1549 dladm_status_t 1550 do_extract_priority(val_desc_t *vdp, void *arg, uint_t cnt) 1551 { 1552 mac_resource_props_t *mrp = (mac_resource_props_t *)arg; 1553 1554 bcopy((char *)vdp->vd_val, &mrp->mrp_priority, 1555 sizeof (mac_priority_level_t)); 1556 mrp->mrp_mask |= MRP_PRIORITY; 1557 1558 return (DLADM_STATUS_OK); 1559 } 1560 1561 /* ARGSUSED */ 1562 static dladm_status_t 1563 do_get_autopush(prop_desc_t *pdp, datalink_id_t linkid, 1564 char **prop_val, uint_t *val_cnt, datalink_media_t media, 1565 uint_t flags, uint_t *perm_flags) 1566 { 1567 struct dlautopush dlap; 1568 int i, len; 1569 dladm_status_t status; 1570 dld_ioc_macprop_t *dip; 1571 1572 if (flags & MAC_PROP_DEFAULT) 1573 return (DLADM_STATUS_NOTDEFINED); 1574 1575 *val_cnt = 1; 1576 dip = i_dladm_get_public_prop(linkid, pdp->pd_name, flags, 1577 &status, perm_flags); 1578 if (dip == NULL) { 1579 (*prop_val)[0] = '\0'; 1580 return (DLADM_STATUS_OK); 1581 } 1582 (void) memcpy(&dlap, dip->pr_val, sizeof (dlap)); 1583 1584 for (i = 0, len = 0; i < dlap.dap_npush; i++) { 1585 if (i != 0) { 1586 (void) snprintf(*prop_val + len, 1587 DLADM_PROP_VAL_MAX - len, "%c", AP_DELIMITER); 1588 len += 1; 1589 } 1590 (void) snprintf(*prop_val + len, DLADM_PROP_VAL_MAX - len, 1591 "%s", dlap.dap_aplist[i]); 1592 len += strlen(dlap.dap_aplist[i]); 1593 if (dlap.dap_anchor - 1 == i) { 1594 (void) snprintf(*prop_val + len, 1595 DLADM_PROP_VAL_MAX - len, "%c%s", AP_DELIMITER, 1596 AP_ANCHOR); 1597 len += (strlen(AP_ANCHOR) + 1); 1598 } 1599 } 1600 free(dip); 1601 done: 1602 return (DLADM_STATUS_OK); 1603 } 1604 1605 /* 1606 * Add the specified module to the dlautopush structure; returns a 1607 * DLADM_STATUS_* code. 1608 */ 1609 dladm_status_t 1610 i_dladm_add_ap_module(const char *module, struct dlautopush *dlap) 1611 { 1612 if ((strlen(module) == 0) || (strlen(module) > FMNAMESZ)) 1613 return (DLADM_STATUS_BADVAL); 1614 1615 if (strncasecmp(module, AP_ANCHOR, strlen(AP_ANCHOR)) == 0) { 1616 /* 1617 * We don't allow multiple anchors, and the anchor must 1618 * be after at least one module. 1619 */ 1620 if (dlap->dap_anchor != 0) 1621 return (DLADM_STATUS_BADVAL); 1622 if (dlap->dap_npush == 0) 1623 return (DLADM_STATUS_BADVAL); 1624 1625 dlap->dap_anchor = dlap->dap_npush; 1626 return (DLADM_STATUS_OK); 1627 } 1628 if (dlap->dap_npush > MAXAPUSH) 1629 return (DLADM_STATUS_BADVALCNT); 1630 1631 (void) strlcpy(dlap->dap_aplist[dlap->dap_npush++], module, 1632 FMNAMESZ + 1); 1633 1634 return (DLADM_STATUS_OK); 1635 } 1636 1637 /* 1638 * Currently, both '.' and ' '(space) can be used as the delimiters between 1639 * autopush modules. The former is used in dladm set-linkprop, and the 1640 * latter is used in the autopush(1M) file. 1641 */ 1642 /* ARGSUSED */ 1643 static dladm_status_t 1644 do_check_autopush(prop_desc_t *pdp, datalink_id_t linkid, char **prop_val, 1645 uint_t val_cnt, val_desc_t *vdp, datalink_media_t media) 1646 { 1647 char *module; 1648 struct dlautopush *dlap; 1649 dladm_status_t status; 1650 char val[DLADM_PROP_VAL_MAX]; 1651 char delimiters[4]; 1652 1653 if (val_cnt != 1) 1654 return (DLADM_STATUS_BADVALCNT); 1655 1656 if (prop_val != NULL) { 1657 dlap = malloc(sizeof (struct dlautopush)); 1658 if (dlap == NULL) 1659 return (DLADM_STATUS_NOMEM); 1660 1661 (void) memset(dlap, 0, sizeof (struct dlautopush)); 1662 (void) snprintf(delimiters, 4, " %c\n", AP_DELIMITER); 1663 bcopy(*prop_val, val, DLADM_PROP_VAL_MAX); 1664 module = strtok(val, delimiters); 1665 while (module != NULL) { 1666 status = i_dladm_add_ap_module(module, dlap); 1667 if (status != DLADM_STATUS_OK) 1668 return (status); 1669 module = strtok(NULL, delimiters); 1670 } 1671 1672 vdp->vd_val = (uintptr_t)dlap; 1673 } else { 1674 vdp->vd_val = 0; 1675 } 1676 return (DLADM_STATUS_OK); 1677 } 1678 1679 #define WLDP_BUFSIZE (MAX_BUF_LEN - WIFI_BUF_OFFSET) 1680 1681 /* ARGSUSED */ 1682 static dladm_status_t 1683 do_get_rate_common(prop_desc_t *pdp, datalink_id_t linkid, 1684 char **prop_val, uint_t *val_cnt, uint_t id, uint_t *perm_flags) 1685 { 1686 wl_rates_t *wrp; 1687 uint_t i; 1688 dladm_status_t status = DLADM_STATUS_OK; 1689 1690 wrp = malloc(WLDP_BUFSIZE); 1691 if (wrp == NULL) 1692 return (DLADM_STATUS_NOMEM); 1693 1694 status = i_dladm_wlan_param(linkid, wrp, id, WLDP_BUFSIZE, B_FALSE); 1695 if (status != DLADM_STATUS_OK) 1696 goto done; 1697 1698 if (wrp->wl_rates_num > *val_cnt) { 1699 status = DLADM_STATUS_TOOSMALL; 1700 goto done; 1701 } 1702 1703 if (wrp->wl_rates_rates[0] == 0) { 1704 prop_val[0][0] = '\0'; 1705 *val_cnt = 1; 1706 goto done; 1707 } 1708 1709 for (i = 0; i < wrp->wl_rates_num; i++) { 1710 (void) snprintf(prop_val[i], DLADM_STRSIZE, "%.*f", 1711 wrp->wl_rates_rates[i] % 2, 1712 (float)wrp->wl_rates_rates[i] / 2); 1713 } 1714 *val_cnt = wrp->wl_rates_num; 1715 *perm_flags = MAC_PROP_PERM_RW; 1716 1717 done: 1718 free(wrp); 1719 return (status); 1720 } 1721 1722 static dladm_status_t 1723 do_get_rate_prop(prop_desc_t *pdp, datalink_id_t linkid, 1724 char **prop_val, uint_t *val_cnt, datalink_media_t media, 1725 uint_t flags, uint_t *perm_flags) 1726 { 1727 if (media != DL_WIFI) { 1728 return (i_dladm_speed_get(pdp, linkid, prop_val, 1729 val_cnt, flags, perm_flags)); 1730 } 1731 1732 return (do_get_rate_common(pdp, linkid, prop_val, val_cnt, 1733 MAC_PROP_WL_DESIRED_RATES, perm_flags)); 1734 } 1735 1736 /* ARGSUSED */ 1737 static dladm_status_t 1738 do_get_rate_mod(prop_desc_t *pdp, datalink_id_t linkid, 1739 char **prop_val, uint_t *val_cnt, datalink_media_t media, 1740 uint_t flags, uint_t *perm_flags) 1741 { 1742 switch (media) { 1743 case DL_ETHER: 1744 /* 1745 * Speed for ethernet links is unbounded. E.g., 802.11b 1746 * links can have a speed of 5.5 Gbps. 1747 */ 1748 return (DLADM_STATUS_NOTSUP); 1749 1750 case DL_WIFI: 1751 return (do_get_rate_common(pdp, linkid, prop_val, val_cnt, 1752 MAC_PROP_WL_SUPPORTED_RATES, perm_flags)); 1753 default: 1754 return (DLADM_STATUS_BADARG); 1755 } 1756 } 1757 1758 static dladm_status_t 1759 do_set_rate(datalink_id_t linkid, dladm_wlan_rates_t *rates) 1760 { 1761 int i; 1762 uint_t len; 1763 wl_rates_t *wrp; 1764 dladm_status_t status = DLADM_STATUS_OK; 1765 1766 wrp = malloc(WLDP_BUFSIZE); 1767 if (wrp == NULL) 1768 return (DLADM_STATUS_NOMEM); 1769 1770 bzero(wrp, WLDP_BUFSIZE); 1771 for (i = 0; i < rates->wr_cnt; i++) 1772 wrp->wl_rates_rates[i] = rates->wr_rates[i]; 1773 wrp->wl_rates_num = rates->wr_cnt; 1774 1775 len = offsetof(wl_rates_t, wl_rates_rates) + 1776 (rates->wr_cnt * sizeof (char)) + WIFI_BUF_OFFSET; 1777 status = i_dladm_wlan_param(linkid, wrp, MAC_PROP_WL_DESIRED_RATES, 1778 len, B_TRUE); 1779 1780 free(wrp); 1781 return (status); 1782 } 1783 1784 /* ARGSUSED */ 1785 static dladm_status_t 1786 do_set_rate_prop(prop_desc_t *pdp, datalink_id_t linkid, 1787 val_desc_t *vdp, uint_t val_cnt, uint_t flags, datalink_media_t media) 1788 { 1789 dladm_wlan_rates_t rates; 1790 dladm_status_t status; 1791 1792 /* 1793 * can currently set rate on WIFI links only. 1794 */ 1795 if (media != DL_WIFI) 1796 return (DLADM_STATUS_PROPRDONLY); 1797 1798 if (val_cnt != 1) 1799 return (DLADM_STATUS_BADVALCNT); 1800 1801 rates.wr_cnt = 1; 1802 rates.wr_rates[0] = vdp[0].vd_val; 1803 1804 status = do_set_rate(linkid, &rates); 1805 1806 done: 1807 return (status); 1808 } 1809 1810 /* ARGSUSED */ 1811 static dladm_status_t 1812 do_check_rate(prop_desc_t *pdp, datalink_id_t linkid, char **prop_val, 1813 uint_t val_cnt, val_desc_t *vdp, datalink_media_t media) 1814 { 1815 int i; 1816 uint_t modval_cnt = MAX_SUPPORT_RATES; 1817 char *buf, **modval; 1818 dladm_status_t status; 1819 uint_t perm_flags; 1820 1821 if (val_cnt != 1) 1822 return (DLADM_STATUS_BADVALCNT); 1823 1824 buf = malloc((sizeof (char *) + DLADM_STRSIZE) * 1825 MAX_SUPPORT_RATES); 1826 if (buf == NULL) { 1827 status = DLADM_STATUS_NOMEM; 1828 goto done; 1829 } 1830 1831 modval = (char **)(void *)buf; 1832 for (i = 0; i < MAX_SUPPORT_RATES; i++) { 1833 modval[i] = buf + sizeof (char *) * MAX_SUPPORT_RATES + 1834 i * DLADM_STRSIZE; 1835 } 1836 1837 status = do_get_rate_mod(NULL, linkid, modval, &modval_cnt, media, 1838 0, &perm_flags); 1839 if (status != DLADM_STATUS_OK) 1840 goto done; 1841 1842 for (i = 0; i < modval_cnt; i++) { 1843 if (strcasecmp(*prop_val, modval[i]) == 0) { 1844 vdp->vd_val = (uintptr_t)(uint_t) 1845 (atof(*prop_val) * 2); 1846 status = DLADM_STATUS_OK; 1847 break; 1848 } 1849 } 1850 if (i == modval_cnt) 1851 status = DLADM_STATUS_BADVAL; 1852 done: 1853 free(buf); 1854 return (status); 1855 } 1856 1857 static dladm_status_t 1858 do_get_phyconf(datalink_id_t linkid, void *buf, int buflen) 1859 { 1860 return (i_dladm_wlan_param(linkid, buf, MAC_PROP_WL_PHY_CONFIG, 1861 buflen, B_FALSE)); 1862 } 1863 1864 /* ARGSUSED */ 1865 static dladm_status_t 1866 do_get_channel_prop(prop_desc_t *pdp, datalink_id_t linkid, 1867 char **prop_val, uint_t *val_cnt, datalink_media_t media, 1868 uint_t flags, uint_t *perm_flags) 1869 { 1870 uint32_t channel; 1871 char buf[WLDP_BUFSIZE]; 1872 dladm_status_t status = DLADM_STATUS_OK; 1873 wl_phy_conf_t wl_phy_conf; 1874 1875 if ((status = do_get_phyconf(linkid, buf, sizeof (buf))) 1876 != DLADM_STATUS_OK) 1877 goto done; 1878 1879 (void) memcpy(&wl_phy_conf, buf, sizeof (wl_phy_conf)); 1880 if (!i_dladm_wlan_convert_chan(&wl_phy_conf, &channel)) { 1881 status = DLADM_STATUS_NOTFOUND; 1882 goto done; 1883 } 1884 1885 (void) snprintf(*prop_val, DLADM_STRSIZE, "%u", channel); 1886 *val_cnt = 1; 1887 *perm_flags = MAC_PROP_PERM_READ; 1888 done: 1889 return (status); 1890 } 1891 1892 static dladm_status_t 1893 do_get_powermode(datalink_id_t linkid, void *buf, int buflen) 1894 { 1895 return (i_dladm_wlan_param(linkid, buf, MAC_PROP_WL_POWER_MODE, 1896 buflen, B_FALSE)); 1897 } 1898 1899 /* ARGSUSED */ 1900 static dladm_status_t 1901 do_get_powermode_prop(prop_desc_t *pdp, datalink_id_t linkid, 1902 char **prop_val, uint_t *val_cnt, datalink_media_t media, 1903 uint_t flags, uint_t *perm_flags) 1904 { 1905 wl_ps_mode_t mode; 1906 const char *s; 1907 char buf[WLDP_BUFSIZE]; 1908 dladm_status_t status = DLADM_STATUS_OK; 1909 1910 if ((status = do_get_powermode(linkid, buf, sizeof (buf))) 1911 != DLADM_STATUS_OK) 1912 goto done; 1913 1914 (void) memcpy(&mode, buf, sizeof (mode)); 1915 switch (mode.wl_ps_mode) { 1916 case WL_PM_AM: 1917 s = "off"; 1918 break; 1919 case WL_PM_MPS: 1920 s = "max"; 1921 break; 1922 case WL_PM_FAST: 1923 s = "fast"; 1924 break; 1925 default: 1926 status = DLADM_STATUS_NOTFOUND; 1927 goto done; 1928 } 1929 (void) snprintf(*prop_val, DLADM_STRSIZE, "%s", s); 1930 *val_cnt = 1; 1931 *perm_flags = MAC_PROP_PERM_RW; 1932 done: 1933 return (status); 1934 } 1935 1936 static dladm_status_t 1937 do_set_powermode(datalink_id_t linkid, dladm_wlan_powermode_t *pm) 1938 { 1939 wl_ps_mode_t ps_mode; 1940 1941 (void) memset(&ps_mode, 0xff, sizeof (ps_mode)); 1942 1943 switch (*pm) { 1944 case DLADM_WLAN_PM_OFF: 1945 ps_mode.wl_ps_mode = WL_PM_AM; 1946 break; 1947 case DLADM_WLAN_PM_MAX: 1948 ps_mode.wl_ps_mode = WL_PM_MPS; 1949 break; 1950 case DLADM_WLAN_PM_FAST: 1951 ps_mode.wl_ps_mode = WL_PM_FAST; 1952 break; 1953 default: 1954 return (DLADM_STATUS_NOTSUP); 1955 } 1956 return (i_dladm_wlan_param(linkid, &ps_mode, MAC_PROP_WL_POWER_MODE, 1957 sizeof (ps_mode), B_TRUE)); 1958 } 1959 1960 /* ARGSUSED */ 1961 static dladm_status_t 1962 do_set_powermode_prop(prop_desc_t *pdp, datalink_id_t linkid, 1963 val_desc_t *vdp, uint_t val_cnt, uint_t flags, datalink_media_t media) 1964 { 1965 dladm_wlan_powermode_t powermode = (dladm_wlan_powermode_t)vdp->vd_val; 1966 dladm_status_t status; 1967 1968 if (val_cnt != 1) 1969 return (DLADM_STATUS_BADVALCNT); 1970 1971 status = do_set_powermode(linkid, &powermode); 1972 1973 return (status); 1974 } 1975 1976 static dladm_status_t 1977 do_get_radio(datalink_id_t linkid, void *buf, int buflen) 1978 { 1979 return (i_dladm_wlan_param(linkid, buf, MAC_PROP_WL_RADIO, buflen, 1980 B_FALSE)); 1981 } 1982 1983 /* ARGSUSED */ 1984 static dladm_status_t 1985 do_get_radio_prop(prop_desc_t *pdp, datalink_id_t linkid, 1986 char **prop_val, uint_t *val_cnt, datalink_media_t media, 1987 uint_t flags, uint_t *perm_flags) 1988 { 1989 wl_radio_t radio; 1990 const char *s; 1991 char buf[WLDP_BUFSIZE]; 1992 dladm_status_t status = DLADM_STATUS_OK; 1993 1994 if ((status = do_get_radio(linkid, buf, sizeof (buf))) 1995 != DLADM_STATUS_OK) 1996 goto done; 1997 1998 (void) memcpy(&radio, buf, sizeof (radio)); 1999 switch (radio) { 2000 case B_TRUE: 2001 s = "on"; 2002 break; 2003 case B_FALSE: 2004 s = "off"; 2005 break; 2006 default: 2007 status = DLADM_STATUS_NOTFOUND; 2008 goto done; 2009 } 2010 (void) snprintf(*prop_val, DLADM_STRSIZE, "%s", s); 2011 *val_cnt = 1; 2012 *perm_flags = MAC_PROP_PERM_RW; 2013 done: 2014 return (status); 2015 } 2016 2017 static dladm_status_t 2018 do_set_radio(datalink_id_t linkid, dladm_wlan_radio_t *radio) 2019 { 2020 wl_radio_t r; 2021 2022 switch (*radio) { 2023 case DLADM_WLAN_RADIO_ON: 2024 r = B_TRUE; 2025 break; 2026 case DLADM_WLAN_RADIO_OFF: 2027 r = B_FALSE; 2028 break; 2029 default: 2030 return (DLADM_STATUS_NOTSUP); 2031 } 2032 return (i_dladm_wlan_param(linkid, &r, MAC_PROP_WL_RADIO, 2033 sizeof (r), B_TRUE)); 2034 } 2035 2036 /* ARGSUSED */ 2037 static dladm_status_t 2038 do_set_radio_prop(prop_desc_t *pdp, datalink_id_t linkid, 2039 val_desc_t *vdp, uint_t val_cnt, uint_t fags, datalink_media_t media) 2040 { 2041 dladm_wlan_radio_t radio = (dladm_wlan_radio_t)vdp->vd_val; 2042 dladm_status_t status; 2043 2044 if (val_cnt != 1) 2045 return (DLADM_STATUS_BADVALCNT); 2046 2047 status = do_set_radio(linkid, &radio); 2048 2049 return (status); 2050 } 2051 2052 static dladm_status_t 2053 i_dladm_set_linkprop_db(datalink_id_t linkid, const char *prop_name, 2054 char **prop_val, uint_t val_cnt) 2055 { 2056 char buf[MAXLINELEN]; 2057 int i; 2058 dladm_conf_t conf; 2059 dladm_status_t status; 2060 2061 status = dladm_read_conf(linkid, &conf); 2062 if (status != DLADM_STATUS_OK) 2063 return (status); 2064 2065 /* 2066 * reset case. 2067 */ 2068 if (val_cnt == 0) { 2069 status = dladm_unset_conf_field(conf, prop_name); 2070 if (status == DLADM_STATUS_OK) 2071 status = dladm_write_conf(conf); 2072 goto done; 2073 } 2074 2075 buf[0] = '\0'; 2076 for (i = 0; i < val_cnt; i++) { 2077 (void) strlcat(buf, prop_val[i], MAXLINELEN); 2078 if (i != val_cnt - 1) 2079 (void) strlcat(buf, ",", MAXLINELEN); 2080 } 2081 2082 status = dladm_set_conf_field(conf, prop_name, DLADM_TYPE_STR, buf); 2083 if (status == DLADM_STATUS_OK) 2084 status = dladm_write_conf(conf); 2085 2086 done: 2087 dladm_destroy_conf(conf); 2088 return (status); 2089 } 2090 2091 static dladm_status_t 2092 i_dladm_get_linkprop_db(datalink_id_t linkid, const char *prop_name, 2093 char **prop_val, uint_t *val_cntp) 2094 { 2095 char buf[MAXLINELEN], *str; 2096 uint_t cnt = 0; 2097 dladm_conf_t conf; 2098 dladm_status_t status; 2099 2100 status = dladm_read_conf(linkid, &conf); 2101 if (status != DLADM_STATUS_OK) 2102 return (status); 2103 2104 status = dladm_get_conf_field(conf, prop_name, buf, MAXLINELEN); 2105 if (status != DLADM_STATUS_OK) 2106 goto done; 2107 2108 str = strtok(buf, ","); 2109 while (str != NULL) { 2110 if (cnt == *val_cntp) { 2111 status = DLADM_STATUS_TOOSMALL; 2112 goto done; 2113 } 2114 (void) strlcpy(prop_val[cnt++], str, DLADM_PROP_VAL_MAX); 2115 str = strtok(NULL, ","); 2116 } 2117 2118 *val_cntp = cnt; 2119 2120 done: 2121 dladm_destroy_conf(conf); 2122 return (status); 2123 } 2124 2125 static link_attr_t * 2126 dladm_name2prop(const char *prop_name) 2127 { 2128 link_attr_t *p; 2129 2130 for (p = link_attr; p->pp_id != MAC_PROP_PRIVATE; p++) { 2131 if (strcmp(p->pp_name, prop_name) == 0) 2132 break; 2133 } 2134 return (p); 2135 } 2136 2137 static link_attr_t * 2138 dladm_id2prop(mac_prop_id_t propid) 2139 { 2140 link_attr_t *p; 2141 2142 for (p = link_attr; p->pp_id != MAC_PROP_PRIVATE; p++) { 2143 if (p->pp_id == propid) 2144 break; 2145 } 2146 return (p); 2147 } 2148 2149 static dld_ioc_macprop_t * 2150 i_dladm_buf_alloc_impl(size_t valsize, datalink_id_t linkid, 2151 const char *prop_name, mac_prop_id_t propid, uint_t flags, 2152 dladm_status_t *status) 2153 { 2154 int dsize; 2155 dld_ioc_macprop_t *dip; 2156 2157 *status = DLADM_STATUS_OK; 2158 dsize = MAC_PROP_BUFSIZE(valsize); 2159 dip = malloc(dsize); 2160 if (dip == NULL) { 2161 *status = DLADM_STATUS_NOMEM; 2162 return (NULL); 2163 } 2164 bzero(dip, dsize); 2165 dip->pr_valsize = valsize; 2166 (void) strlcpy(dip->pr_name, prop_name, sizeof (dip->pr_name)); 2167 dip->pr_version = MAC_PROP_VERSION; 2168 dip->pr_linkid = linkid; 2169 dip->pr_num = propid; 2170 dip->pr_flags = flags; 2171 return (dip); 2172 } 2173 2174 static dld_ioc_macprop_t * 2175 i_dladm_buf_alloc_by_name(size_t valsize, datalink_id_t linkid, 2176 const char *prop_name, uint_t flags, dladm_status_t *status) 2177 { 2178 link_attr_t *p; 2179 2180 p = dladm_name2prop(prop_name); 2181 valsize = MAX(p->pp_valsize, valsize); 2182 return (i_dladm_buf_alloc_impl(valsize, linkid, prop_name, p->pp_id, 2183 flags, status)); 2184 } 2185 2186 static dld_ioc_macprop_t * 2187 i_dladm_buf_alloc_by_id(size_t valsize, datalink_id_t linkid, 2188 mac_prop_id_t propid, uint_t flags, dladm_status_t *status) 2189 { 2190 link_attr_t *p; 2191 2192 p = dladm_id2prop(propid); 2193 valsize = MAX(p->pp_valsize, valsize); 2194 return (i_dladm_buf_alloc_impl(valsize, linkid, p->pp_name, propid, 2195 flags, status)); 2196 } 2197 2198 /* ARGSUSED */ 2199 static dladm_status_t 2200 i_dladm_set_public_prop(prop_desc_t *pdp, datalink_id_t linkid, 2201 val_desc_t *vdp, uint_t val_cnt, uint_t flags, datalink_media_t media) 2202 { 2203 dld_ioc_macprop_t *dip; 2204 dladm_status_t status = DLADM_STATUS_OK; 2205 uint8_t u8; 2206 uint16_t u16; 2207 uint32_t u32; 2208 void *val; 2209 2210 dip = i_dladm_buf_alloc_by_name(0, linkid, pdp->pd_name, 0, &status); 2211 if (dip == NULL) 2212 return (status); 2213 2214 if (pdp->pd_flags & PD_CHECK_ALLOC) 2215 val = (void *)vdp->vd_val; 2216 else { 2217 /* 2218 * Currently all 1/2/4-byte size properties are byte/word/int. 2219 * No need (yet) to distinguish these from arrays of same size. 2220 */ 2221 switch (dip->pr_valsize) { 2222 case 1: 2223 u8 = vdp->vd_val; 2224 val = &u8; 2225 break; 2226 case 2: 2227 u16 = vdp->vd_val; 2228 val = &u16; 2229 break; 2230 case 4: 2231 u32 = vdp->vd_val; 2232 val = &u32; 2233 break; 2234 default: 2235 val = &vdp->vd_val; 2236 break; 2237 } 2238 } 2239 2240 if (val != NULL) 2241 (void) memcpy(dip->pr_val, val, dip->pr_valsize); 2242 else 2243 dip->pr_valsize = 0; 2244 2245 status = i_dladm_macprop(dip, B_TRUE); 2246 2247 done: 2248 free(dip); 2249 return (status); 2250 } 2251 2252 dladm_status_t 2253 i_dladm_macprop(void *dip, boolean_t set) 2254 { 2255 int fd; 2256 dladm_status_t status = DLADM_STATUS_OK; 2257 2258 if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) { 2259 status = dladm_errno2status(errno); 2260 return (status); 2261 } 2262 if (ioctl(fd, (set ? DLDIOC_SETMACPROP : DLDIOC_GETMACPROP), dip)) 2263 status = dladm_errno2status(errno); 2264 2265 (void) close(fd); 2266 return (status); 2267 } 2268 2269 static dld_ioc_macprop_t * 2270 i_dladm_get_public_prop(datalink_id_t linkid, char *prop_name, uint_t flags, 2271 dladm_status_t *status, uint_t *perm_flags) 2272 { 2273 dld_ioc_macprop_t *dip = NULL; 2274 2275 dip = i_dladm_buf_alloc_by_name(0, linkid, prop_name, flags, status); 2276 if (dip == NULL) 2277 return (NULL); 2278 2279 *status = i_dladm_macprop(dip, B_FALSE); 2280 if (*status != DLADM_STATUS_OK) { 2281 free(dip); 2282 return (NULL); 2283 } 2284 if (perm_flags != NULL) 2285 *perm_flags = dip->pr_perm_flags; 2286 2287 return (dip); 2288 } 2289 2290 /* ARGSUSED */ 2291 static dladm_status_t 2292 i_dladm_defmtu_check(prop_desc_t *pdp, datalink_id_t linkid, 2293 char **prop_val, uint_t val_cnt, val_desc_t *v, datalink_media_t media) 2294 { 2295 if (val_cnt != 1) 2296 return (DLADM_STATUS_BADVAL); 2297 v->vd_val = atoi(prop_val[0]); 2298 return (DLADM_STATUS_OK); 2299 } 2300 2301 /* ARGSUSED */ 2302 static dladm_status_t 2303 i_dladm_duplex_get(prop_desc_t *pdp, datalink_id_t linkid, 2304 char **prop_val, uint_t *val_cnt, datalink_media_t media, 2305 uint_t flags, uint_t *perm_flags) 2306 { 2307 link_duplex_t link_duplex; 2308 dladm_status_t status; 2309 2310 if ((status = dladm_get_single_mac_stat(linkid, "link_duplex", 2311 KSTAT_DATA_UINT32, &link_duplex)) != 0) 2312 return (status); 2313 2314 switch (link_duplex) { 2315 case LINK_DUPLEX_FULL: 2316 (void) strcpy(*prop_val, "full"); 2317 break; 2318 case LINK_DUPLEX_HALF: 2319 (void) strcpy(*prop_val, "half"); 2320 break; 2321 default: 2322 (void) strcpy(*prop_val, "unknown"); 2323 break; 2324 } 2325 *val_cnt = 1; 2326 return (DLADM_STATUS_OK); 2327 } 2328 2329 /* ARGSUSED */ 2330 static dladm_status_t 2331 i_dladm_speed_get(prop_desc_t *pdp, datalink_id_t linkid, 2332 char **prop_val, uint_t *val_cnt, uint_t flags, uint_t *perm_flags) 2333 { 2334 uint64_t ifspeed = 0; 2335 dladm_status_t status; 2336 2337 if ((status = dladm_get_single_mac_stat(linkid, "ifspeed", 2338 KSTAT_DATA_UINT64, &ifspeed)) != 0) 2339 return (status); 2340 2341 if ((ifspeed % 1000000) != 0) { 2342 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, 2343 "%llf", ifspeed / (float)1000000); /* Mbps */ 2344 } else { 2345 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, 2346 "%llu", ifspeed / 1000000); /* Mbps */ 2347 } 2348 *val_cnt = 1; 2349 *perm_flags = MAC_PROP_PERM_READ; 2350 return (DLADM_STATUS_OK); 2351 } 2352 2353 /* ARGSUSED */ 2354 static dladm_status_t 2355 i_dladm_status_get(prop_desc_t *pdp, datalink_id_t linkid, 2356 char **prop_val, uint_t *val_cnt, datalink_media_t media, 2357 uint_t flags, uint_t *perm_flags) 2358 { 2359 link_state_t link_state; 2360 dladm_status_t status; 2361 2362 status = i_dladm_get_state(linkid, &link_state); 2363 if (status != DLADM_STATUS_OK) 2364 return (status); 2365 2366 switch (link_state) { 2367 case LINK_STATE_UP: 2368 (void) strcpy(*prop_val, "up"); 2369 break; 2370 case LINK_STATE_DOWN: 2371 (void) strcpy(*prop_val, "down"); 2372 break; 2373 default: 2374 (void) strcpy(*prop_val, "unknown"); 2375 break; 2376 } 2377 *val_cnt = 1; 2378 *perm_flags = MAC_PROP_PERM_READ; 2379 return (DLADM_STATUS_OK); 2380 } 2381 2382 /* ARGSUSED */ 2383 static dladm_status_t 2384 i_dladm_binary_get(prop_desc_t *pdp, datalink_id_t linkid, 2385 char **prop_val, uint_t *val_cnt, datalink_media_t media, 2386 uint_t flags, uint_t *perm_flags) 2387 { 2388 dld_ioc_macprop_t *dip; 2389 dladm_status_t status; 2390 2391 dip = i_dladm_get_public_prop(linkid, pdp->pd_name, flags, 2392 &status, perm_flags); 2393 if (dip == NULL) 2394 return (status); 2395 2396 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "%x", dip->pr_val[0]); 2397 free(dip); 2398 *val_cnt = 1; 2399 return (DLADM_STATUS_OK); 2400 } 2401 2402 /* ARGSUSED */ 2403 static dladm_status_t 2404 i_dladm_uint32_get(prop_desc_t *pdp, datalink_id_t linkid, 2405 char **prop_val, uint_t *val_cnt, datalink_media_t media, 2406 uint_t flags, uint_t *perm_flags) 2407 { 2408 dld_ioc_macprop_t *dip; 2409 uint32_t v = 0; 2410 uchar_t *cp; 2411 dladm_status_t status; 2412 2413 dip = i_dladm_get_public_prop(linkid, pdp->pd_name, flags, 2414 &status, perm_flags); 2415 if (dip == NULL) 2416 return (status); 2417 2418 cp = (uchar_t *)dip->pr_val; 2419 (void) memcpy(&v, cp, sizeof (v)); 2420 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "%ld", v); 2421 free(dip); 2422 *val_cnt = 1; 2423 return (DLADM_STATUS_OK); 2424 } 2425 2426 /* ARGSUSED */ 2427 static dladm_status_t 2428 i_dladm_flowctl_get(prop_desc_t *pdp, datalink_id_t linkid, 2429 char **prop_val, uint_t *val_cnt, datalink_media_t media, 2430 uint_t flags, uint_t *perm_flags) 2431 { 2432 dld_ioc_macprop_t *dip; 2433 link_flowctrl_t v; 2434 dladm_status_t status; 2435 uchar_t *cp; 2436 2437 dip = i_dladm_get_public_prop(linkid, pdp->pd_name, flags, 2438 &status, perm_flags); 2439 if (dip == NULL) 2440 return (status); 2441 2442 cp = (uchar_t *)dip->pr_val; 2443 (void) memcpy(&v, cp, sizeof (v)); 2444 switch (v) { 2445 case LINK_FLOWCTRL_NONE: 2446 (void) sprintf(*prop_val, "no"); 2447 break; 2448 case LINK_FLOWCTRL_RX: 2449 (void) sprintf(*prop_val, "rx"); 2450 break; 2451 case LINK_FLOWCTRL_TX: 2452 (void) sprintf(*prop_val, "tx"); 2453 break; 2454 case LINK_FLOWCTRL_BI: 2455 (void) sprintf(*prop_val, "bi"); 2456 break; 2457 } 2458 free(dip); 2459 *val_cnt = 1; 2460 return (DLADM_STATUS_OK); 2461 } 2462 2463 2464 /* ARGSUSED */ 2465 static dladm_status_t 2466 i_dladm_set_prop(datalink_id_t linkid, const char *prop_name, 2467 char **prop_val, uint_t val_cnt, uint_t flags) 2468 { 2469 int i, slen; 2470 int bufsize = 0; 2471 dld_ioc_macprop_t *dip = NULL; 2472 uchar_t *dp; 2473 link_attr_t *p; 2474 dladm_status_t status = DLADM_STATUS_OK; 2475 2476 if ((prop_name == NULL && prop_val != NULL) || 2477 (prop_val != NULL && val_cnt == 0)) 2478 return (DLADM_STATUS_BADARG); 2479 p = dladm_name2prop(prop_name); 2480 if (p->pp_id != MAC_PROP_PRIVATE) 2481 return (DLADM_STATUS_BADARG); 2482 2483 /* 2484 * private properties: all parsing is done in the kernel. 2485 * allocate a enough space for each property + its separator (','). 2486 */ 2487 for (i = 0; i < val_cnt; i++) { 2488 bufsize += strlen(prop_val[i]) + 1; 2489 } 2490 2491 if (prop_val == NULL) { 2492 /* 2493 * getting default value. so use more buffer space. 2494 */ 2495 bufsize += DLADM_PROP_BUF_CHUNK; 2496 } 2497 2498 dip = i_dladm_buf_alloc_by_name(bufsize + 1, linkid, prop_name, 2499 (prop_val != NULL ? 0 : MAC_PROP_DEFAULT), &status); 2500 if (dip == NULL) 2501 return (status); 2502 2503 dp = (uchar_t *)dip->pr_val; 2504 slen = 0; 2505 2506 if (prop_val == NULL) { 2507 status = i_dladm_macprop(dip, B_FALSE); 2508 } else { 2509 for (i = 0; i < val_cnt; i++) { 2510 int plen = 0; 2511 2512 plen = strlen(prop_val[i]); 2513 bcopy(prop_val[i], dp, plen); 2514 slen += plen; 2515 /* 2516 * add a "," separator and update dp. 2517 */ 2518 if (i != (val_cnt -1)) 2519 dp[slen++] = ','; 2520 dp += (plen + 1); 2521 } 2522 status = i_dladm_macprop(dip, B_TRUE); 2523 } 2524 2525 free(dip); 2526 return (status); 2527 } 2528 2529 static dladm_status_t 2530 i_dladm_get_prop(datalink_id_t linkid, const char *prop_name, 2531 char **prop_val, uint_t *val_cnt, dladm_prop_type_t type, uint_t dld_flags) 2532 { 2533 dladm_status_t status = DLADM_STATUS_OK; 2534 dld_ioc_macprop_t *dip = NULL; 2535 link_attr_t *p; 2536 char tmp = '\0'; 2537 2538 if ((prop_name == NULL && prop_val != NULL) || 2539 (prop_val != NULL && val_cnt == 0)) 2540 return (DLADM_STATUS_BADARG); 2541 2542 p = dladm_name2prop(prop_name); 2543 if (p->pp_id != MAC_PROP_PRIVATE) 2544 return (DLADM_STATUS_BADARG); 2545 2546 if (type == DLADM_PROP_VAL_MODIFIABLE) { 2547 *prop_val = &tmp; 2548 *val_cnt = 1; 2549 return (DLADM_STATUS_OK); 2550 } 2551 2552 /* 2553 * private properties: all parsing is done in the kernel. 2554 */ 2555 dip = i_dladm_buf_alloc_by_name(DLADM_PROP_BUF_CHUNK, linkid, prop_name, 2556 dld_flags, &status); 2557 if (dip == NULL) 2558 return (status); 2559 2560 if ((status = i_dladm_macprop(dip, B_FALSE)) == DLADM_STATUS_OK) { 2561 if (type == DLADM_PROP_VAL_PERM) { 2562 (void) dladm_perm2str(dip->pr_perm_flags, *prop_val); 2563 } else { 2564 (void) strncpy(*prop_val, dip->pr_val, 2565 DLADM_PROP_VAL_MAX); 2566 } 2567 *val_cnt = 1; 2568 } 2569 free(dip); 2570 return (status); 2571 } 2572 2573 2574 static dladm_status_t 2575 i_dladm_getset_defval(prop_desc_t *pdp, datalink_id_t linkid, 2576 datalink_media_t media, uint_t flags) 2577 { 2578 dladm_status_t status; 2579 char **prop_vals = NULL, *buf; 2580 size_t bufsize; 2581 uint_t cnt; 2582 int i; 2583 uint_t perm_flags; 2584 2585 /* 2586 * Allocate buffer needed for prop_vals array. We can have at most 2587 * DLADM_MAX_PROP_VALCNT char *prop_vals[] entries, where 2588 * each entry has max size DLADM_PROP_VAL_MAX 2589 */ 2590 bufsize = 2591 (sizeof (char *) + DLADM_PROP_VAL_MAX) * DLADM_MAX_PROP_VALCNT; 2592 buf = malloc(bufsize); 2593 prop_vals = (char **)(void *)buf; 2594 for (i = 0; i < DLADM_MAX_PROP_VALCNT; i++) { 2595 prop_vals[i] = buf + 2596 sizeof (char *) * DLADM_MAX_PROP_VALCNT + 2597 i * DLADM_PROP_VAL_MAX; 2598 } 2599 2600 /* 2601 * For properties which have pdp->pd_defval.vd_name as a non-empty 2602 * string, the "" itself is used to reset the property (exceptions 2603 * are zone and autopush, which populate vdp->vd_val). So 2604 * libdladm can copy pdp->pd_defval over to the val_desc_t passed 2605 * down on the setprop using the global values in the table. For 2606 * other cases (vd_name is ""), doing reset-linkprop will cause 2607 * libdladm to do a getprop to find the default value and then do 2608 * a setprop to reset the value to default. 2609 */ 2610 status = pdp->pd_get(pdp, linkid, prop_vals, &cnt, media, 2611 MAC_PROP_DEFAULT, &perm_flags); 2612 if (status == DLADM_STATUS_OK) { 2613 if (perm_flags == MAC_PROP_PERM_RW) { 2614 status = i_dladm_set_single_prop(linkid, pdp->pd_class, 2615 media, pdp, prop_vals, cnt, flags); 2616 } 2617 else 2618 status = DLADM_STATUS_NOTSUP; 2619 } 2620 free(buf); 2621 return (status); 2622 } 2623 2624 int 2625 macprop_to_wifi(mac_prop_id_t wl_prop) 2626 { 2627 switch (wl_prop) { 2628 case MAC_PROP_WL_ESSID: 2629 return (WL_ESSID); 2630 case MAC_PROP_WL_BSSID: 2631 return (WL_BSSID); 2632 case MAC_PROP_WL_BSSTYPE: 2633 return (WL_BSS_TYPE); 2634 case MAC_PROP_WL_LINKSTATUS: 2635 return (WL_LINKSTATUS); 2636 case MAC_PROP_WL_DESIRED_RATES: 2637 return (WL_DESIRED_RATES); 2638 case MAC_PROP_WL_SUPPORTED_RATES: 2639 return (WL_SUPPORTED_RATES); 2640 case MAC_PROP_WL_AUTH_MODE: 2641 return (WL_AUTH_MODE); 2642 case MAC_PROP_WL_ENCRYPTION: 2643 return (WL_ENCRYPTION); 2644 case MAC_PROP_WL_RSSI: 2645 return (WL_RSSI); 2646 case MAC_PROP_WL_PHY_CONFIG: 2647 return (WL_PHY_CONFIG); 2648 case MAC_PROP_WL_CAPABILITY: 2649 return (WL_CAPABILITY); 2650 case MAC_PROP_WL_WPA: 2651 return (WL_WPA); 2652 case MAC_PROP_WL_SCANRESULTS: 2653 return (WL_SCANRESULTS); 2654 case MAC_PROP_WL_POWER_MODE: 2655 return (WL_POWER_MODE); 2656 case MAC_PROP_WL_RADIO: 2657 return (WL_RADIO); 2658 case MAC_PROP_WL_ESS_LIST: 2659 return (WL_ESS_LIST); 2660 case MAC_PROP_WL_KEY_TAB: 2661 return (WL_WEP_KEY_TAB); 2662 case MAC_PROP_WL_CREATE_IBSS: 2663 return (WL_CREATE_IBSS); 2664 case MAC_PROP_WL_SETOPTIE: 2665 return (WL_SETOPTIE); 2666 case MAC_PROP_WL_DELKEY: 2667 return (WL_DELKEY); 2668 case MAC_PROP_WL_KEY: 2669 return (WL_KEY); 2670 case MAC_PROP_WL_MLME: 2671 return (WL_MLME); 2672 default: 2673 return (-1); 2674 } 2675 } 2676 2677 dladm_status_t 2678 i_dladm_wlan_param(datalink_id_t linkid, void *buf, mac_prop_id_t cmd, 2679 size_t len, boolean_t set) 2680 { 2681 uint32_t flags; 2682 dladm_status_t status; 2683 uint32_t media; 2684 dld_ioc_macprop_t *dip; 2685 void *dp; 2686 2687 if ((status = dladm_datalink_id2info(linkid, &flags, NULL, &media, 2688 NULL, 0)) != DLADM_STATUS_OK) { 2689 return (status); 2690 } 2691 2692 if (media != DL_WIFI) 2693 return (DLADM_STATUS_BADARG); 2694 2695 if (!(flags & DLADM_OPT_ACTIVE)) 2696 return (DLADM_STATUS_TEMPONLY); 2697 2698 if (len == (MAX_BUF_LEN - WIFI_BUF_OFFSET)) 2699 len = MAX_BUF_LEN - sizeof (dld_ioc_macprop_t) - 1; 2700 2701 dip = i_dladm_buf_alloc_by_id(len, linkid, cmd, 0, &status); 2702 if (dip == NULL) 2703 return (DLADM_STATUS_NOMEM); 2704 2705 dp = (uchar_t *)dip->pr_val; 2706 if (set) 2707 (void) memcpy(dp, buf, len); 2708 2709 status = i_dladm_macprop(dip, set); 2710 if (status == DLADM_STATUS_NOTSUP) { 2711 if (set) { 2712 status = i_dladm_wlan_set_legacy_ioctl(linkid, 2713 buf, len, macprop_to_wifi(cmd)); 2714 } else { 2715 status = i_dladm_wlan_get_legacy_ioctl(linkid, 2716 buf, len, macprop_to_wifi(cmd)); 2717 } 2718 } else if (status == DLADM_STATUS_OK) { 2719 if (!set) 2720 (void) memcpy(buf, dp, len); 2721 } 2722 2723 free(dip); 2724 return (status); 2725 } 2726 2727 static dladm_status_t 2728 i_dladm_wlan_get_legacy_ioctl(datalink_id_t linkid, void *buf, uint_t buflen, 2729 uint_t id) 2730 { 2731 wldp_t *gbuf; 2732 dladm_status_t status; 2733 2734 if ((gbuf = malloc(MAX_BUF_LEN)) == NULL) 2735 return (DLADM_STATUS_NOMEM); 2736 2737 (void) memset(gbuf, 0, MAX_BUF_LEN); 2738 status = i_dladm_wlan_legacy_ioctl(linkid, gbuf, id, MAX_BUF_LEN, 2739 WLAN_GET_PARAM, sizeof (wldp_t)); 2740 if (status == DLADM_STATUS_OK) 2741 (void) memcpy(buf, gbuf->wldp_buf, buflen); 2742 2743 free(gbuf); 2744 return (status); 2745 } 2746 2747 static dladm_status_t 2748 i_dladm_wlan_set_legacy_ioctl(datalink_id_t linkid, void *buf, uint_t buflen, 2749 uint_t id) 2750 { 2751 wldp_t *gbuf; 2752 dladm_status_t status = DLADM_STATUS_OK; 2753 2754 if ((gbuf = malloc(MAX_BUF_LEN)) == NULL) 2755 return (DLADM_STATUS_NOMEM); 2756 2757 (void) memset(gbuf, 0, MAX_BUF_LEN); 2758 (void) memcpy(gbuf->wldp_buf, buf, buflen); 2759 buflen += WIFI_BUF_OFFSET; 2760 status = i_dladm_wlan_legacy_ioctl(linkid, gbuf, id, buflen, 2761 WLAN_SET_PARAM, buflen); 2762 2763 free(gbuf); 2764 return (status); 2765 } 2766 2767 static dladm_status_t 2768 link_proplist_check(dladm_arg_list_t *proplist) 2769 { 2770 int i, j; 2771 boolean_t matched; 2772 2773 for (i = 0; i < proplist->al_count; i++) { 2774 matched = B_FALSE; 2775 for (j = 0; j < DLADM_MAX_PROPS; j++) { 2776 if (strcmp(proplist->al_info[i].ai_name, 2777 prop_table[j].pd_name) == 0) 2778 matched = B_TRUE; 2779 } 2780 if (!matched) 2781 return (DLADM_STATUS_BADPROP); 2782 } 2783 return (DLADM_STATUS_OK); 2784 } 2785 2786 dladm_status_t 2787 dladm_parse_link_props(char *str, dladm_arg_list_t **listp, boolean_t novalues) 2788 { 2789 dladm_status_t status; 2790 2791 status = dladm_parse_args(str, listp, novalues); 2792 if (status != DLADM_STATUS_OK) 2793 return (status); 2794 2795 status = link_proplist_check(*listp); 2796 if (status != DLADM_STATUS_OK) { 2797 dladm_free_props(*listp); 2798 return (status); 2799 } 2800 2801 return (DLADM_STATUS_OK); 2802 } 2803 2804 /* 2805 * Retrieve the one link property from the database 2806 */ 2807 /*ARGSUSED*/ 2808 static int 2809 i_dladm_get_one_prop(datalink_id_t linkid, const char *prop_name, void *arg) 2810 { 2811 dladm_arg_list_t *proplist = arg; 2812 dladm_arg_info_t *aip = NULL; 2813 2814 aip = &proplist->al_info[proplist->al_count]; 2815 /* 2816 * it is fine to point to prop_name since prop_name points to the 2817 * prop_table[n].pd_name. 2818 */ 2819 aip->ai_name = prop_name; 2820 2821 (void) dladm_get_linkprop(linkid, DLADM_PROP_VAL_PERSISTENT, prop_name, 2822 aip->ai_val, &aip->ai_count); 2823 2824 if (aip->ai_count != 0) 2825 proplist->al_count++; 2826 2827 return (DLADM_WALK_CONTINUE); 2828 } 2829 2830 2831 /* 2832 * Retrieve all link properties for a link from the database and 2833 * return a property list. 2834 */ 2835 dladm_status_t 2836 dladm_link_get_proplist(datalink_id_t linkid, dladm_arg_list_t **listp) 2837 { 2838 dladm_arg_list_t *list; 2839 dladm_status_t status = DLADM_STATUS_OK; 2840 2841 list = calloc(1, sizeof (dladm_arg_list_t)); 2842 if (list == NULL) 2843 return (dladm_errno2status(errno)); 2844 2845 status = dladm_walk_linkprop(linkid, list, i_dladm_get_one_prop); 2846 2847 *listp = list; 2848 return (status); 2849 } 2850 2851 /* 2852 * Retrieve the named property from a proplist, check the value and 2853 * convert to a kernel structure. 2854 */ 2855 static dladm_status_t 2856 i_dladm_link_proplist_extract_one(dladm_arg_list_t *proplist, 2857 const char *name, void *val) 2858 { 2859 dladm_status_t status; 2860 dladm_arg_info_t *aip = NULL; 2861 int i, j; 2862 2863 /* Find named property in proplist */ 2864 for (i = 0; i < proplist->al_count; i++) { 2865 aip = &proplist->al_info[i]; 2866 if (strcasecmp(aip->ai_name, name) == 0) 2867 break; 2868 } 2869 2870 /* Property not in list */ 2871 if (i == proplist->al_count) 2872 return (DLADM_STATUS_OK); 2873 2874 for (i = 0; i < DLADM_MAX_PROPS; i++) { 2875 prop_desc_t *pdp = &prop_table[i]; 2876 val_desc_t *vdp; 2877 2878 vdp = malloc(sizeof (val_desc_t) * aip->ai_count); 2879 if (vdp == NULL) 2880 return (DLADM_STATUS_NOMEM); 2881 2882 if (strcasecmp(aip->ai_name, pdp->pd_name) != 0) 2883 continue; 2884 2885 if (aip->ai_val == NULL) 2886 return (DLADM_STATUS_BADARG); 2887 2888 /* Check property value */ 2889 if (pdp->pd_check != NULL) { 2890 status = pdp->pd_check(pdp, 0, aip->ai_val, 2891 aip->ai_count, vdp, 0); 2892 } else { 2893 status = DLADM_STATUS_BADARG; 2894 } 2895 2896 if (status != DLADM_STATUS_OK) 2897 return (status); 2898 2899 for (j = 0; j < DLADM_MAX_RSRC_PROP; j++) { 2900 resource_prop_t *rpp = &rsrc_prop_table[j]; 2901 2902 if (strcasecmp(aip->ai_name, rpp->rp_name) != 0) 2903 continue; 2904 2905 /* Extract kernel structure */ 2906 if (rpp->rp_extract != NULL) { 2907 status = rpp->rp_extract(vdp, val, 2908 aip->ai_count); 2909 } else { 2910 status = DLADM_STATUS_BADARG; 2911 } 2912 break; 2913 } 2914 2915 if (status != DLADM_STATUS_OK) 2916 return (status); 2917 2918 break; 2919 } 2920 return (status); 2921 } 2922 2923 /* 2924 * Extract properties from a proplist and convert to mac_resource_props_t. 2925 */ 2926 dladm_status_t 2927 dladm_link_proplist_extract(dladm_arg_list_t *proplist, 2928 mac_resource_props_t *mrp) 2929 { 2930 dladm_status_t status = DLADM_STATUS_OK; 2931 2932 status = i_dladm_link_proplist_extract_one(proplist, "maxbw", mrp); 2933 if (status != DLADM_STATUS_OK) 2934 return (status); 2935 status = i_dladm_link_proplist_extract_one(proplist, "priority", mrp); 2936 if (status != DLADM_STATUS_OK) 2937 return (status); 2938 status = i_dladm_link_proplist_extract_one(proplist, "cpus", mrp); 2939 if (status != DLADM_STATUS_OK) 2940 return (status); 2941 return (status); 2942 } 2943 2944 static const char * 2945 dladm_perm2str(uint_t perm, char *buf) 2946 { 2947 (void) snprintf(buf, DLADM_STRSIZE, "%c%c", 2948 ((perm & MAC_PROP_PERM_READ) != 0) ? 'r' : '-', 2949 ((perm & MAC_PROP_PERM_WRITE) != 0) ? 'w' : '-'); 2950 return (buf); 2951 } 2952 2953 dladm_status_t 2954 i_dladm_get_state(datalink_id_t linkid, link_state_t *state) 2955 { 2956 dld_ioc_macprop_t *dip; 2957 dladm_status_t status; 2958 uint_t perms; 2959 2960 dip = i_dladm_get_public_prop(linkid, "state", 0, &status, &perms); 2961 if (status != DLADM_STATUS_OK) 2962 return (status); 2963 (void) memcpy(state, dip->pr_val, sizeof (*state)); 2964 free(dip); 2965 return (status); 2966 } 2967