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