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