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