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 *val_cntp = 1; 849 } else { 850 status = pdp->pd_get(handle, pdp, linkid, prop_val, 851 val_cntp, media, dld_flags, &perm_flags); 852 } 853 854 *prop_val[0] = '\0'; 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 1531 return (DLADM_STATUS_OK); 1532 } 1533 1534 /* ARGSUSED */ 1535 static dladm_status_t 1536 i_dladm_priority_get(dladm_handle_t handle, prop_desc_t *pdp, 1537 datalink_id_t linkid, char **prop_val, uint_t *val_cnt, 1538 datalink_media_t media, uint_t flags, uint_t *perm_flags) 1539 { 1540 dld_ioc_macprop_t *dip; 1541 mac_resource_props_t mrp; 1542 mac_priority_level_t pri; 1543 dladm_status_t status; 1544 1545 dip = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags, 1546 &status, perm_flags); 1547 if (dip == NULL) 1548 return (status); 1549 1550 bcopy(dip->pr_val, &mrp, sizeof (mac_resource_props_t)); 1551 free(dip); 1552 1553 pri = ((mrp.mrp_mask & MRP_PRIORITY) == 0) ? MPL_HIGH : 1554 mrp.mrp_priority; 1555 1556 (void) dladm_pri2str(pri, prop_val[0]); 1557 *val_cnt = 1; 1558 return (DLADM_STATUS_OK); 1559 } 1560 1561 /* ARGSUSED */ 1562 static dladm_status_t 1563 do_check_priority(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid, 1564 char **prop_val, uint_t val_cnt, val_desc_t *vdp, datalink_media_t media) 1565 { 1566 mac_priority_level_t *pri; 1567 dladm_status_t status = DLADM_STATUS_OK; 1568 1569 if (val_cnt != 1) 1570 return (DLADM_STATUS_BADVALCNT); 1571 1572 pri = malloc(sizeof (mac_priority_level_t)); 1573 if (pri == NULL) 1574 return (DLADM_STATUS_NOMEM); 1575 1576 status = dladm_str2pri(*prop_val, pri); 1577 if (status != DLADM_STATUS_OK) { 1578 free(pri); 1579 return (status); 1580 } 1581 1582 if (*pri < MPL_LOW || *pri > MPL_HIGH) { 1583 free(pri); 1584 return (DLADM_STATUS_BADVAL); 1585 } 1586 1587 vdp->vd_val = (uintptr_t)pri; 1588 return (DLADM_STATUS_OK); 1589 } 1590 1591 /* ARGSUSED */ 1592 dladm_status_t 1593 do_extract_priority(val_desc_t *vdp, void *arg, uint_t cnt) 1594 { 1595 mac_resource_props_t *mrp = (mac_resource_props_t *)arg; 1596 1597 bcopy((char *)vdp->vd_val, &mrp->mrp_priority, 1598 sizeof (mac_priority_level_t)); 1599 mrp->mrp_mask |= MRP_PRIORITY; 1600 1601 return (DLADM_STATUS_OK); 1602 } 1603 1604 /* ARGSUSED */ 1605 static dladm_status_t 1606 do_get_autopush(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid, 1607 char **prop_val, uint_t *val_cnt, datalink_media_t media, 1608 uint_t flags, uint_t *perm_flags) 1609 { 1610 struct dlautopush dlap; 1611 int i, len; 1612 dladm_status_t status; 1613 dld_ioc_macprop_t *dip; 1614 1615 if (flags & MAC_PROP_DEFAULT) 1616 return (DLADM_STATUS_NOTDEFINED); 1617 1618 *val_cnt = 1; 1619 dip = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags, 1620 &status, perm_flags); 1621 if (dip == NULL) { 1622 (*prop_val)[0] = '\0'; 1623 return (DLADM_STATUS_OK); 1624 } 1625 (void) memcpy(&dlap, dip->pr_val, sizeof (dlap)); 1626 1627 for (i = 0, len = 0; i < dlap.dap_npush; i++) { 1628 if (i != 0) { 1629 (void) snprintf(*prop_val + len, 1630 DLADM_PROP_VAL_MAX - len, "%c", AP_DELIMITER); 1631 len += 1; 1632 } 1633 (void) snprintf(*prop_val + len, DLADM_PROP_VAL_MAX - len, 1634 "%s", dlap.dap_aplist[i]); 1635 len += strlen(dlap.dap_aplist[i]); 1636 if (dlap.dap_anchor - 1 == i) { 1637 (void) snprintf(*prop_val + len, 1638 DLADM_PROP_VAL_MAX - len, "%c%s", AP_DELIMITER, 1639 AP_ANCHOR); 1640 len += (strlen(AP_ANCHOR) + 1); 1641 } 1642 } 1643 free(dip); 1644 done: 1645 return (DLADM_STATUS_OK); 1646 } 1647 1648 /* 1649 * Add the specified module to the dlautopush structure; returns a 1650 * DLADM_STATUS_* code. 1651 */ 1652 dladm_status_t 1653 i_dladm_add_ap_module(const char *module, struct dlautopush *dlap) 1654 { 1655 if ((strlen(module) == 0) || (strlen(module) > FMNAMESZ)) 1656 return (DLADM_STATUS_BADVAL); 1657 1658 if (strncasecmp(module, AP_ANCHOR, strlen(AP_ANCHOR)) == 0) { 1659 /* 1660 * We don't allow multiple anchors, and the anchor must 1661 * be after at least one module. 1662 */ 1663 if (dlap->dap_anchor != 0) 1664 return (DLADM_STATUS_BADVAL); 1665 if (dlap->dap_npush == 0) 1666 return (DLADM_STATUS_BADVAL); 1667 1668 dlap->dap_anchor = dlap->dap_npush; 1669 return (DLADM_STATUS_OK); 1670 } 1671 if (dlap->dap_npush > MAXAPUSH) 1672 return (DLADM_STATUS_BADVALCNT); 1673 1674 (void) strlcpy(dlap->dap_aplist[dlap->dap_npush++], module, 1675 FMNAMESZ + 1); 1676 1677 return (DLADM_STATUS_OK); 1678 } 1679 1680 /* 1681 * Currently, both '.' and ' '(space) can be used as the delimiters between 1682 * autopush modules. The former is used in dladm set-linkprop, and the 1683 * latter is used in the autopush(1M) file. 1684 */ 1685 /* ARGSUSED */ 1686 static dladm_status_t 1687 do_check_autopush(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid, 1688 char **prop_val, uint_t val_cnt, val_desc_t *vdp, datalink_media_t media) 1689 { 1690 char *module; 1691 struct dlautopush *dlap; 1692 dladm_status_t status; 1693 char val[DLADM_PROP_VAL_MAX]; 1694 char delimiters[4]; 1695 1696 if (val_cnt != 1) 1697 return (DLADM_STATUS_BADVALCNT); 1698 1699 if (prop_val != NULL) { 1700 dlap = malloc(sizeof (struct dlautopush)); 1701 if (dlap == NULL) 1702 return (DLADM_STATUS_NOMEM); 1703 1704 (void) memset(dlap, 0, sizeof (struct dlautopush)); 1705 (void) snprintf(delimiters, 4, " %c\n", AP_DELIMITER); 1706 bcopy(*prop_val, val, DLADM_PROP_VAL_MAX); 1707 module = strtok(val, delimiters); 1708 while (module != NULL) { 1709 status = i_dladm_add_ap_module(module, dlap); 1710 if (status != DLADM_STATUS_OK) 1711 return (status); 1712 module = strtok(NULL, delimiters); 1713 } 1714 1715 vdp->vd_val = (uintptr_t)dlap; 1716 } else { 1717 vdp->vd_val = 0; 1718 } 1719 return (DLADM_STATUS_OK); 1720 } 1721 1722 #define WLDP_BUFSIZE (MAX_BUF_LEN - WIFI_BUF_OFFSET) 1723 1724 /* ARGSUSED */ 1725 static dladm_status_t 1726 do_get_rate_common(dladm_handle_t handle, prop_desc_t *pdp, 1727 datalink_id_t linkid, char **prop_val, uint_t *val_cnt, uint_t id, 1728 uint_t *perm_flags) 1729 { 1730 wl_rates_t *wrp; 1731 uint_t i; 1732 dladm_status_t status = DLADM_STATUS_OK; 1733 1734 wrp = malloc(WLDP_BUFSIZE); 1735 if (wrp == NULL) 1736 return (DLADM_STATUS_NOMEM); 1737 1738 status = i_dladm_wlan_param(handle, linkid, wrp, id, WLDP_BUFSIZE, 1739 B_FALSE); 1740 if (status != DLADM_STATUS_OK) 1741 goto done; 1742 1743 if (wrp->wl_rates_num > *val_cnt) { 1744 status = DLADM_STATUS_TOOSMALL; 1745 goto done; 1746 } 1747 1748 if (wrp->wl_rates_rates[0] == 0) { 1749 prop_val[0][0] = '\0'; 1750 *val_cnt = 1; 1751 goto done; 1752 } 1753 1754 for (i = 0; i < wrp->wl_rates_num; i++) { 1755 (void) snprintf(prop_val[i], DLADM_STRSIZE, "%.*f", 1756 wrp->wl_rates_rates[i] % 2, 1757 (float)wrp->wl_rates_rates[i] / 2); 1758 } 1759 *val_cnt = wrp->wl_rates_num; 1760 *perm_flags = MAC_PROP_PERM_RW; 1761 1762 done: 1763 free(wrp); 1764 return (status); 1765 } 1766 1767 static dladm_status_t 1768 do_get_rate_prop(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid, 1769 char **prop_val, uint_t *val_cnt, datalink_media_t media, 1770 uint_t flags, uint_t *perm_flags) 1771 { 1772 if (media != DL_WIFI) { 1773 return (i_dladm_speed_get(handle, pdp, linkid, prop_val, 1774 val_cnt, flags, perm_flags)); 1775 } 1776 1777 return (do_get_rate_common(handle, pdp, linkid, prop_val, val_cnt, 1778 MAC_PROP_WL_DESIRED_RATES, perm_flags)); 1779 } 1780 1781 /* ARGSUSED */ 1782 static dladm_status_t 1783 do_get_rate_mod(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid, 1784 char **prop_val, uint_t *val_cnt, datalink_media_t media, 1785 uint_t flags, uint_t *perm_flags) 1786 { 1787 switch (media) { 1788 case DL_ETHER: 1789 /* 1790 * Speed for ethernet links is unbounded. E.g., 802.11b 1791 * links can have a speed of 5.5 Gbps. 1792 */ 1793 return (DLADM_STATUS_NOTSUP); 1794 1795 case DL_WIFI: 1796 return (do_get_rate_common(handle, pdp, linkid, prop_val, 1797 val_cnt, MAC_PROP_WL_SUPPORTED_RATES, perm_flags)); 1798 default: 1799 return (DLADM_STATUS_BADARG); 1800 } 1801 } 1802 1803 static dladm_status_t 1804 do_set_rate(dladm_handle_t handle, datalink_id_t linkid, 1805 dladm_wlan_rates_t *rates) 1806 { 1807 int i; 1808 uint_t len; 1809 wl_rates_t *wrp; 1810 dladm_status_t status = DLADM_STATUS_OK; 1811 1812 wrp = malloc(WLDP_BUFSIZE); 1813 if (wrp == NULL) 1814 return (DLADM_STATUS_NOMEM); 1815 1816 bzero(wrp, WLDP_BUFSIZE); 1817 for (i = 0; i < rates->wr_cnt; i++) 1818 wrp->wl_rates_rates[i] = rates->wr_rates[i]; 1819 wrp->wl_rates_num = rates->wr_cnt; 1820 1821 len = offsetof(wl_rates_t, wl_rates_rates) + 1822 (rates->wr_cnt * sizeof (char)) + WIFI_BUF_OFFSET; 1823 status = i_dladm_wlan_param(handle, linkid, wrp, 1824 MAC_PROP_WL_DESIRED_RATES, len, B_TRUE); 1825 1826 free(wrp); 1827 return (status); 1828 } 1829 1830 /* ARGSUSED */ 1831 static dladm_status_t 1832 do_set_rate_prop(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid, 1833 val_desc_t *vdp, uint_t val_cnt, uint_t flags, datalink_media_t media) 1834 { 1835 dladm_wlan_rates_t rates; 1836 dladm_status_t status; 1837 1838 /* 1839 * can currently set rate on WIFI links only. 1840 */ 1841 if (media != DL_WIFI) 1842 return (DLADM_STATUS_PROPRDONLY); 1843 1844 if (val_cnt != 1) 1845 return (DLADM_STATUS_BADVALCNT); 1846 1847 rates.wr_cnt = 1; 1848 rates.wr_rates[0] = vdp[0].vd_val; 1849 1850 status = do_set_rate(handle, linkid, &rates); 1851 1852 done: 1853 return (status); 1854 } 1855 1856 /* ARGSUSED */ 1857 static dladm_status_t 1858 do_check_rate(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid, 1859 char **prop_val, uint_t val_cnt, val_desc_t *vdp, datalink_media_t media) 1860 { 1861 int i; 1862 uint_t modval_cnt = MAX_SUPPORT_RATES; 1863 char *buf, **modval; 1864 dladm_status_t status; 1865 uint_t perm_flags; 1866 1867 if (val_cnt != 1) 1868 return (DLADM_STATUS_BADVALCNT); 1869 1870 buf = malloc((sizeof (char *) + DLADM_STRSIZE) * 1871 MAX_SUPPORT_RATES); 1872 if (buf == NULL) { 1873 status = DLADM_STATUS_NOMEM; 1874 goto done; 1875 } 1876 1877 modval = (char **)(void *)buf; 1878 for (i = 0; i < MAX_SUPPORT_RATES; i++) { 1879 modval[i] = buf + sizeof (char *) * MAX_SUPPORT_RATES + 1880 i * DLADM_STRSIZE; 1881 } 1882 1883 status = do_get_rate_mod(handle, NULL, linkid, modval, &modval_cnt, 1884 media, 0, &perm_flags); 1885 if (status != DLADM_STATUS_OK) 1886 goto done; 1887 1888 for (i = 0; i < modval_cnt; i++) { 1889 if (strcasecmp(*prop_val, modval[i]) == 0) { 1890 vdp->vd_val = (uintptr_t)(uint_t) 1891 (atof(*prop_val) * 2); 1892 status = DLADM_STATUS_OK; 1893 break; 1894 } 1895 } 1896 if (i == modval_cnt) 1897 status = DLADM_STATUS_BADVAL; 1898 done: 1899 free(buf); 1900 return (status); 1901 } 1902 1903 static dladm_status_t 1904 do_get_phyconf(dladm_handle_t handle, datalink_id_t linkid, void *buf, 1905 int buflen) 1906 { 1907 return (i_dladm_wlan_param(handle, linkid, buf, MAC_PROP_WL_PHY_CONFIG, 1908 buflen, B_FALSE)); 1909 } 1910 1911 /* ARGSUSED */ 1912 static dladm_status_t 1913 do_get_channel_prop(dladm_handle_t handle, prop_desc_t *pdp, 1914 datalink_id_t linkid, char **prop_val, uint_t *val_cnt, 1915 datalink_media_t media, uint_t flags, uint_t *perm_flags) 1916 { 1917 uint32_t channel; 1918 char buf[WLDP_BUFSIZE]; 1919 dladm_status_t status = DLADM_STATUS_OK; 1920 wl_phy_conf_t wl_phy_conf; 1921 1922 if ((status = do_get_phyconf(handle, linkid, buf, sizeof (buf))) 1923 != DLADM_STATUS_OK) 1924 goto done; 1925 1926 (void) memcpy(&wl_phy_conf, buf, sizeof (wl_phy_conf)); 1927 if (!i_dladm_wlan_convert_chan(&wl_phy_conf, &channel)) { 1928 status = DLADM_STATUS_NOTFOUND; 1929 goto done; 1930 } 1931 1932 (void) snprintf(*prop_val, DLADM_STRSIZE, "%u", channel); 1933 *val_cnt = 1; 1934 *perm_flags = MAC_PROP_PERM_READ; 1935 done: 1936 return (status); 1937 } 1938 1939 static dladm_status_t 1940 do_get_powermode(dladm_handle_t handle, datalink_id_t linkid, void *buf, 1941 int buflen) 1942 { 1943 return (i_dladm_wlan_param(handle, linkid, buf, MAC_PROP_WL_POWER_MODE, 1944 buflen, B_FALSE)); 1945 } 1946 1947 /* ARGSUSED */ 1948 static dladm_status_t 1949 do_get_powermode_prop(dladm_handle_t handle, prop_desc_t *pdp, 1950 datalink_id_t linkid, char **prop_val, uint_t *val_cnt, 1951 datalink_media_t media, uint_t flags, uint_t *perm_flags) 1952 { 1953 wl_ps_mode_t mode; 1954 const char *s; 1955 char buf[WLDP_BUFSIZE]; 1956 dladm_status_t status = DLADM_STATUS_OK; 1957 1958 if ((status = do_get_powermode(handle, linkid, buf, sizeof (buf))) 1959 != DLADM_STATUS_OK) 1960 goto done; 1961 1962 (void) memcpy(&mode, buf, sizeof (mode)); 1963 switch (mode.wl_ps_mode) { 1964 case WL_PM_AM: 1965 s = "off"; 1966 break; 1967 case WL_PM_MPS: 1968 s = "max"; 1969 break; 1970 case WL_PM_FAST: 1971 s = "fast"; 1972 break; 1973 default: 1974 status = DLADM_STATUS_NOTFOUND; 1975 goto done; 1976 } 1977 (void) snprintf(*prop_val, DLADM_STRSIZE, "%s", s); 1978 *val_cnt = 1; 1979 *perm_flags = MAC_PROP_PERM_RW; 1980 done: 1981 return (status); 1982 } 1983 1984 static dladm_status_t 1985 do_set_powermode(dladm_handle_t handle, datalink_id_t linkid, 1986 dladm_wlan_powermode_t *pm) 1987 { 1988 wl_ps_mode_t ps_mode; 1989 1990 (void) memset(&ps_mode, 0xff, sizeof (ps_mode)); 1991 1992 switch (*pm) { 1993 case DLADM_WLAN_PM_OFF: 1994 ps_mode.wl_ps_mode = WL_PM_AM; 1995 break; 1996 case DLADM_WLAN_PM_MAX: 1997 ps_mode.wl_ps_mode = WL_PM_MPS; 1998 break; 1999 case DLADM_WLAN_PM_FAST: 2000 ps_mode.wl_ps_mode = WL_PM_FAST; 2001 break; 2002 default: 2003 return (DLADM_STATUS_NOTSUP); 2004 } 2005 return (i_dladm_wlan_param(handle, linkid, &ps_mode, 2006 MAC_PROP_WL_POWER_MODE, sizeof (ps_mode), B_TRUE)); 2007 } 2008 2009 /* ARGSUSED */ 2010 static dladm_status_t 2011 do_set_powermode_prop(dladm_handle_t handle, prop_desc_t *pdp, 2012 datalink_id_t linkid, val_desc_t *vdp, uint_t val_cnt, uint_t flags, 2013 datalink_media_t media) 2014 { 2015 dladm_wlan_powermode_t powermode = (dladm_wlan_powermode_t)vdp->vd_val; 2016 dladm_status_t status; 2017 2018 if (val_cnt != 1) 2019 return (DLADM_STATUS_BADVALCNT); 2020 2021 status = do_set_powermode(handle, linkid, &powermode); 2022 2023 return (status); 2024 } 2025 2026 static dladm_status_t 2027 do_get_radio(dladm_handle_t handle, datalink_id_t linkid, void *buf, int buflen) 2028 { 2029 return (i_dladm_wlan_param(handle, linkid, buf, MAC_PROP_WL_RADIO, 2030 buflen, B_FALSE)); 2031 } 2032 2033 /* ARGSUSED */ 2034 static dladm_status_t 2035 do_get_radio_prop(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid, 2036 char **prop_val, uint_t *val_cnt, datalink_media_t media, 2037 uint_t flags, uint_t *perm_flags) 2038 { 2039 wl_radio_t radio; 2040 const char *s; 2041 char buf[WLDP_BUFSIZE]; 2042 dladm_status_t status = DLADM_STATUS_OK; 2043 2044 if ((status = do_get_radio(handle, linkid, buf, sizeof (buf))) 2045 != DLADM_STATUS_OK) 2046 goto done; 2047 2048 (void) memcpy(&radio, buf, sizeof (radio)); 2049 switch (radio) { 2050 case B_TRUE: 2051 s = "on"; 2052 break; 2053 case B_FALSE: 2054 s = "off"; 2055 break; 2056 default: 2057 status = DLADM_STATUS_NOTFOUND; 2058 goto done; 2059 } 2060 (void) snprintf(*prop_val, DLADM_STRSIZE, "%s", s); 2061 *val_cnt = 1; 2062 *perm_flags = MAC_PROP_PERM_RW; 2063 done: 2064 return (status); 2065 } 2066 2067 static dladm_status_t 2068 do_set_radio(dladm_handle_t handle, datalink_id_t linkid, 2069 dladm_wlan_radio_t *radio) 2070 { 2071 wl_radio_t r; 2072 2073 switch (*radio) { 2074 case DLADM_WLAN_RADIO_ON: 2075 r = B_TRUE; 2076 break; 2077 case DLADM_WLAN_RADIO_OFF: 2078 r = B_FALSE; 2079 break; 2080 default: 2081 return (DLADM_STATUS_NOTSUP); 2082 } 2083 return (i_dladm_wlan_param(handle, linkid, &r, MAC_PROP_WL_RADIO, 2084 sizeof (r), B_TRUE)); 2085 } 2086 2087 /* ARGSUSED */ 2088 static dladm_status_t 2089 do_set_radio_prop(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid, 2090 val_desc_t *vdp, uint_t val_cnt, uint_t fags, datalink_media_t media) 2091 { 2092 dladm_wlan_radio_t radio = (dladm_wlan_radio_t)vdp->vd_val; 2093 dladm_status_t status; 2094 2095 if (val_cnt != 1) 2096 return (DLADM_STATUS_BADVALCNT); 2097 2098 status = do_set_radio(handle, linkid, &radio); 2099 2100 return (status); 2101 } 2102 2103 static dladm_status_t 2104 i_dladm_set_linkprop_db(dladm_handle_t handle, datalink_id_t linkid, 2105 const char *prop_name, char **prop_val, uint_t val_cnt) 2106 { 2107 char buf[MAXLINELEN]; 2108 int i; 2109 dladm_conf_t conf; 2110 dladm_status_t status; 2111 2112 status = dladm_read_conf(handle, linkid, &conf); 2113 if (status != DLADM_STATUS_OK) 2114 return (status); 2115 2116 /* 2117 * reset case. 2118 */ 2119 if (val_cnt == 0) { 2120 status = dladm_unset_conf_field(handle, conf, prop_name); 2121 if (status == DLADM_STATUS_OK) 2122 status = dladm_write_conf(handle, conf); 2123 goto done; 2124 } 2125 2126 buf[0] = '\0'; 2127 for (i = 0; i < val_cnt; i++) { 2128 (void) strlcat(buf, prop_val[i], MAXLINELEN); 2129 if (i != val_cnt - 1) 2130 (void) strlcat(buf, ",", MAXLINELEN); 2131 } 2132 2133 status = dladm_set_conf_field(handle, conf, prop_name, DLADM_TYPE_STR, 2134 buf); 2135 if (status == DLADM_STATUS_OK) 2136 status = dladm_write_conf(handle, conf); 2137 2138 done: 2139 dladm_destroy_conf(handle, conf); 2140 return (status); 2141 } 2142 2143 static dladm_status_t 2144 i_dladm_get_linkprop_db(dladm_handle_t handle, datalink_id_t linkid, 2145 const char *prop_name, char **prop_val, uint_t *val_cntp) 2146 { 2147 char buf[MAXLINELEN], *str; 2148 uint_t cnt = 0; 2149 dladm_conf_t conf; 2150 dladm_status_t status; 2151 2152 status = dladm_read_conf(handle, linkid, &conf); 2153 if (status != DLADM_STATUS_OK) 2154 return (status); 2155 2156 status = dladm_get_conf_field(handle, conf, prop_name, buf, MAXLINELEN); 2157 if (status != DLADM_STATUS_OK) 2158 goto done; 2159 2160 str = strtok(buf, ","); 2161 while (str != NULL) { 2162 if (cnt == *val_cntp) { 2163 status = DLADM_STATUS_TOOSMALL; 2164 goto done; 2165 } 2166 (void) strlcpy(prop_val[cnt++], str, DLADM_PROP_VAL_MAX); 2167 str = strtok(NULL, ","); 2168 } 2169 2170 *val_cntp = cnt; 2171 2172 done: 2173 dladm_destroy_conf(handle, conf); 2174 return (status); 2175 } 2176 2177 /* 2178 * Walk persistent private link properties of a link. 2179 */ 2180 static dladm_status_t 2181 i_dladm_walk_linkprop_priv_db(dladm_handle_t handle, datalink_id_t linkid, 2182 void *arg, int (*func)(dladm_handle_t, datalink_id_t, const char *, void *)) 2183 { 2184 dladm_status_t status; 2185 dladm_conf_t conf; 2186 char last_attr[MAXLINKATTRLEN]; 2187 char attr[MAXLINKATTRLEN]; 2188 char attrval[MAXLINKATTRVALLEN]; 2189 size_t attrsz; 2190 2191 if (linkid == DATALINK_INVALID_LINKID || func == NULL) 2192 return (DLADM_STATUS_BADARG); 2193 2194 status = dladm_read_conf(handle, linkid, &conf); 2195 if (status != DLADM_STATUS_OK) 2196 return (status); 2197 2198 last_attr[0] = '\0'; 2199 while ((status = dladm_getnext_conf_linkprop(handle, conf, last_attr, 2200 attr, attrval, MAXLINKATTRVALLEN, &attrsz)) == DLADM_STATUS_OK) { 2201 if (attr[0] == '_') { 2202 if (func(handle, linkid, attr, arg) == 2203 DLADM_WALK_TERMINATE) 2204 break; 2205 } 2206 (void) strlcpy(last_attr, attr, MAXLINKATTRLEN); 2207 } 2208 2209 dladm_destroy_conf(handle, conf); 2210 return (DLADM_STATUS_OK); 2211 } 2212 2213 static link_attr_t * 2214 dladm_name2prop(const char *prop_name) 2215 { 2216 link_attr_t *p; 2217 2218 for (p = link_attr; p->pp_id != MAC_PROP_PRIVATE; p++) { 2219 if (strcmp(p->pp_name, prop_name) == 0) 2220 break; 2221 } 2222 return (p); 2223 } 2224 2225 static link_attr_t * 2226 dladm_id2prop(mac_prop_id_t propid) 2227 { 2228 link_attr_t *p; 2229 2230 for (p = link_attr; p->pp_id != MAC_PROP_PRIVATE; p++) { 2231 if (p->pp_id == propid) 2232 break; 2233 } 2234 return (p); 2235 } 2236 2237 static dld_ioc_macprop_t * 2238 i_dladm_buf_alloc_impl(size_t valsize, datalink_id_t linkid, 2239 const char *prop_name, mac_prop_id_t propid, uint_t flags, 2240 dladm_status_t *status) 2241 { 2242 int dsize; 2243 dld_ioc_macprop_t *dip; 2244 2245 *status = DLADM_STATUS_OK; 2246 dsize = MAC_PROP_BUFSIZE(valsize); 2247 dip = malloc(dsize); 2248 if (dip == NULL) { 2249 *status = DLADM_STATUS_NOMEM; 2250 return (NULL); 2251 } 2252 bzero(dip, dsize); 2253 dip->pr_valsize = valsize; 2254 (void) strlcpy(dip->pr_name, prop_name, sizeof (dip->pr_name)); 2255 dip->pr_version = MAC_PROP_VERSION; 2256 dip->pr_linkid = linkid; 2257 dip->pr_num = propid; 2258 dip->pr_flags = flags; 2259 return (dip); 2260 } 2261 2262 static dld_ioc_macprop_t * 2263 i_dladm_buf_alloc_by_name(size_t valsize, datalink_id_t linkid, 2264 const char *prop_name, uint_t flags, dladm_status_t *status) 2265 { 2266 link_attr_t *p; 2267 2268 p = dladm_name2prop(prop_name); 2269 valsize = MAX(p->pp_valsize, valsize); 2270 return (i_dladm_buf_alloc_impl(valsize, linkid, prop_name, p->pp_id, 2271 flags, status)); 2272 } 2273 2274 static dld_ioc_macprop_t * 2275 i_dladm_buf_alloc_by_id(size_t valsize, datalink_id_t linkid, 2276 mac_prop_id_t propid, uint_t flags, dladm_status_t *status) 2277 { 2278 link_attr_t *p; 2279 2280 p = dladm_id2prop(propid); 2281 valsize = MAX(p->pp_valsize, valsize); 2282 return (i_dladm_buf_alloc_impl(valsize, linkid, p->pp_name, propid, 2283 flags, status)); 2284 } 2285 2286 /* ARGSUSED */ 2287 static dladm_status_t 2288 i_dladm_set_public_prop(dladm_handle_t handle, prop_desc_t *pdp, 2289 datalink_id_t linkid, val_desc_t *vdp, uint_t val_cnt, uint_t flags, 2290 datalink_media_t media) 2291 { 2292 dld_ioc_macprop_t *dip; 2293 dladm_status_t status = DLADM_STATUS_OK; 2294 uint8_t u8; 2295 uint16_t u16; 2296 uint32_t u32; 2297 void *val; 2298 2299 dip = i_dladm_buf_alloc_by_name(0, linkid, pdp->pd_name, 0, &status); 2300 if (dip == NULL) 2301 return (status); 2302 2303 if (pdp->pd_flags & PD_CHECK_ALLOC) 2304 val = (void *)vdp->vd_val; 2305 else { 2306 /* 2307 * Currently all 1/2/4-byte size properties are byte/word/int. 2308 * No need (yet) to distinguish these from arrays of same size. 2309 */ 2310 switch (dip->pr_valsize) { 2311 case 1: 2312 u8 = vdp->vd_val; 2313 val = &u8; 2314 break; 2315 case 2: 2316 u16 = vdp->vd_val; 2317 val = &u16; 2318 break; 2319 case 4: 2320 u32 = vdp->vd_val; 2321 val = &u32; 2322 break; 2323 default: 2324 val = &vdp->vd_val; 2325 break; 2326 } 2327 } 2328 2329 if (val != NULL) 2330 (void) memcpy(dip->pr_val, val, dip->pr_valsize); 2331 else 2332 dip->pr_valsize = 0; 2333 2334 status = i_dladm_macprop(handle, dip, B_TRUE); 2335 2336 done: 2337 free(dip); 2338 return (status); 2339 } 2340 2341 dladm_status_t 2342 i_dladm_macprop(dladm_handle_t handle, void *dip, boolean_t set) 2343 { 2344 dladm_status_t status = DLADM_STATUS_OK; 2345 2346 if (ioctl(dladm_dld_fd(handle), 2347 (set ? DLDIOC_SETMACPROP : DLDIOC_GETMACPROP), dip)) 2348 status = dladm_errno2status(errno); 2349 2350 return (status); 2351 } 2352 2353 static dld_ioc_macprop_t * 2354 i_dladm_get_public_prop(dladm_handle_t handle, datalink_id_t linkid, 2355 char *prop_name, uint_t flags, dladm_status_t *status, uint_t *perm_flags) 2356 { 2357 dld_ioc_macprop_t *dip = NULL; 2358 2359 dip = i_dladm_buf_alloc_by_name(0, linkid, prop_name, flags, status); 2360 if (dip == NULL) 2361 return (NULL); 2362 2363 *status = i_dladm_macprop(handle, dip, B_FALSE); 2364 if (*status != DLADM_STATUS_OK) { 2365 free(dip); 2366 return (NULL); 2367 } 2368 if (perm_flags != NULL) 2369 *perm_flags = dip->pr_perm_flags; 2370 2371 return (dip); 2372 } 2373 2374 /* ARGSUSED */ 2375 static dladm_status_t 2376 i_dladm_defmtu_check(dladm_handle_t handle, prop_desc_t *pdp, 2377 datalink_id_t linkid, char **prop_val, uint_t val_cnt, val_desc_t *v, 2378 datalink_media_t media) 2379 { 2380 if (val_cnt != 1) 2381 return (DLADM_STATUS_BADVAL); 2382 v->vd_val = atoi(prop_val[0]); 2383 return (DLADM_STATUS_OK); 2384 } 2385 2386 /* ARGSUSED */ 2387 static dladm_status_t 2388 i_dladm_duplex_get(dladm_handle_t handle, prop_desc_t *pdp, 2389 datalink_id_t linkid, char **prop_val, uint_t *val_cnt, 2390 datalink_media_t media, uint_t flags, uint_t *perm_flags) 2391 { 2392 link_duplex_t link_duplex; 2393 dladm_status_t status; 2394 2395 if ((status = dladm_get_single_mac_stat(handle, linkid, "link_duplex", 2396 KSTAT_DATA_UINT32, &link_duplex)) != 0) 2397 return (status); 2398 2399 switch (link_duplex) { 2400 case LINK_DUPLEX_FULL: 2401 (void) strcpy(*prop_val, "full"); 2402 break; 2403 case LINK_DUPLEX_HALF: 2404 (void) strcpy(*prop_val, "half"); 2405 break; 2406 default: 2407 (void) strcpy(*prop_val, "unknown"); 2408 break; 2409 } 2410 *val_cnt = 1; 2411 return (DLADM_STATUS_OK); 2412 } 2413 2414 /* ARGSUSED */ 2415 static dladm_status_t 2416 i_dladm_speed_get(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid, 2417 char **prop_val, uint_t *val_cnt, uint_t flags, uint_t *perm_flags) 2418 { 2419 uint64_t ifspeed = 0; 2420 dladm_status_t status; 2421 2422 if ((status = dladm_get_single_mac_stat(handle, linkid, "ifspeed", 2423 KSTAT_DATA_UINT64, &ifspeed)) != 0) 2424 return (status); 2425 2426 if ((ifspeed % 1000000) != 0) { 2427 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, 2428 "%llf", ifspeed / (float)1000000); /* Mbps */ 2429 } else { 2430 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, 2431 "%llu", ifspeed / 1000000); /* Mbps */ 2432 } 2433 *val_cnt = 1; 2434 *perm_flags = MAC_PROP_PERM_READ; 2435 return (DLADM_STATUS_OK); 2436 } 2437 2438 /* ARGSUSED */ 2439 static dladm_status_t 2440 i_dladm_status_get(dladm_handle_t handle, prop_desc_t *pdp, 2441 datalink_id_t linkid, char **prop_val, uint_t *val_cnt, 2442 datalink_media_t media, uint_t flags, uint_t *perm_flags) 2443 { 2444 link_state_t link_state; 2445 dladm_status_t status; 2446 2447 status = i_dladm_get_state(handle, linkid, &link_state); 2448 if (status != DLADM_STATUS_OK) 2449 return (status); 2450 2451 switch (link_state) { 2452 case LINK_STATE_UP: 2453 (void) strcpy(*prop_val, "up"); 2454 break; 2455 case LINK_STATE_DOWN: 2456 (void) strcpy(*prop_val, "down"); 2457 break; 2458 default: 2459 (void) strcpy(*prop_val, "unknown"); 2460 break; 2461 } 2462 *val_cnt = 1; 2463 *perm_flags = MAC_PROP_PERM_READ; 2464 return (DLADM_STATUS_OK); 2465 } 2466 2467 /* ARGSUSED */ 2468 static dladm_status_t 2469 i_dladm_binary_get(dladm_handle_t handle, prop_desc_t *pdp, 2470 datalink_id_t linkid, char **prop_val, uint_t *val_cnt, 2471 datalink_media_t media, uint_t flags, uint_t *perm_flags) 2472 { 2473 dld_ioc_macprop_t *dip; 2474 dladm_status_t status; 2475 2476 dip = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags, 2477 &status, perm_flags); 2478 if (dip == NULL) 2479 return (status); 2480 2481 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "%x", dip->pr_val[0]); 2482 free(dip); 2483 *val_cnt = 1; 2484 return (DLADM_STATUS_OK); 2485 } 2486 2487 /* ARGSUSED */ 2488 static dladm_status_t 2489 i_dladm_uint32_get(dladm_handle_t handle, prop_desc_t *pdp, 2490 datalink_id_t linkid, char **prop_val, uint_t *val_cnt, 2491 datalink_media_t media, uint_t flags, uint_t *perm_flags) 2492 { 2493 dld_ioc_macprop_t *dip; 2494 uint32_t v = 0; 2495 uchar_t *cp; 2496 dladm_status_t status; 2497 2498 dip = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags, 2499 &status, perm_flags); 2500 if (dip == NULL) 2501 return (status); 2502 2503 cp = (uchar_t *)dip->pr_val; 2504 (void) memcpy(&v, cp, sizeof (v)); 2505 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "%ld", v); 2506 free(dip); 2507 *val_cnt = 1; 2508 return (DLADM_STATUS_OK); 2509 } 2510 2511 /* ARGSUSED */ 2512 static dladm_status_t 2513 i_dladm_tagmode_get(dladm_handle_t handle, prop_desc_t *pdp, 2514 datalink_id_t linkid, char **prop_val, uint_t *val_cnt, 2515 datalink_media_t media, uint_t flags, uint_t *perm_flags) 2516 { 2517 dld_ioc_macprop_t *dip; 2518 link_tagmode_t mode; 2519 dladm_status_t status; 2520 2521 dip = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags, 2522 &status, perm_flags); 2523 if (dip == NULL) 2524 return (status); 2525 (void) memcpy(&mode, dip->pr_val, sizeof (mode)); 2526 free(dip); 2527 2528 switch (mode) { 2529 case LINK_TAGMODE_NORMAL: 2530 (void) strlcpy(*prop_val, "normal", DLADM_PROP_VAL_MAX); 2531 break; 2532 case LINK_TAGMODE_VLANONLY: 2533 (void) strlcpy(*prop_val, "vlanonly", DLADM_PROP_VAL_MAX); 2534 break; 2535 default: 2536 (void) strlcpy(*prop_val, "unknown", DLADM_PROP_VAL_MAX); 2537 } 2538 *val_cnt = 1; 2539 return (DLADM_STATUS_OK); 2540 } 2541 2542 /* ARGSUSED */ 2543 static dladm_status_t 2544 i_dladm_flowctl_get(dladm_handle_t handle, prop_desc_t *pdp, 2545 datalink_id_t linkid, char **prop_val, uint_t *val_cnt, 2546 datalink_media_t media, uint_t flags, uint_t *perm_flags) 2547 { 2548 dld_ioc_macprop_t *dip; 2549 link_flowctrl_t v; 2550 dladm_status_t status; 2551 uchar_t *cp; 2552 2553 dip = i_dladm_get_public_prop(handle, linkid, pdp->pd_name, flags, 2554 &status, perm_flags); 2555 if (dip == NULL) 2556 return (status); 2557 2558 cp = (uchar_t *)dip->pr_val; 2559 (void) memcpy(&v, cp, sizeof (v)); 2560 switch (v) { 2561 case LINK_FLOWCTRL_NONE: 2562 (void) sprintf(*prop_val, "no"); 2563 break; 2564 case LINK_FLOWCTRL_RX: 2565 (void) sprintf(*prop_val, "rx"); 2566 break; 2567 case LINK_FLOWCTRL_TX: 2568 (void) sprintf(*prop_val, "tx"); 2569 break; 2570 case LINK_FLOWCTRL_BI: 2571 (void) sprintf(*prop_val, "bi"); 2572 break; 2573 } 2574 free(dip); 2575 *val_cnt = 1; 2576 return (DLADM_STATUS_OK); 2577 } 2578 2579 2580 /* ARGSUSED */ 2581 static dladm_status_t 2582 i_dladm_set_prop(dladm_handle_t handle, datalink_id_t linkid, 2583 const char *prop_name, char **prop_val, uint_t val_cnt, uint_t flags) 2584 2585 { 2586 int i, slen; 2587 int bufsize = 0; 2588 dld_ioc_macprop_t *dip = NULL; 2589 uchar_t *dp; 2590 link_attr_t *p; 2591 dladm_status_t status = DLADM_STATUS_OK; 2592 2593 if ((prop_name == NULL && prop_val != NULL) || 2594 (prop_val != NULL && val_cnt == 0)) 2595 return (DLADM_STATUS_BADARG); 2596 p = dladm_name2prop(prop_name); 2597 if (p->pp_id != MAC_PROP_PRIVATE) 2598 return (DLADM_STATUS_BADARG); 2599 2600 /* 2601 * private properties: all parsing is done in the kernel. 2602 * allocate a enough space for each property + its separator (','). 2603 */ 2604 for (i = 0; i < val_cnt; i++) { 2605 bufsize += strlen(prop_val[i]) + 1; 2606 } 2607 2608 if (prop_val == NULL) { 2609 /* 2610 * getting default value. so use more buffer space. 2611 */ 2612 bufsize += DLADM_PROP_BUF_CHUNK; 2613 } 2614 2615 dip = i_dladm_buf_alloc_by_name(bufsize + 1, linkid, prop_name, 2616 (prop_val != NULL ? 0 : MAC_PROP_DEFAULT), &status); 2617 if (dip == NULL) 2618 return (status); 2619 2620 dp = (uchar_t *)dip->pr_val; 2621 slen = 0; 2622 2623 if (prop_val == NULL) { 2624 status = i_dladm_macprop(handle, dip, B_FALSE); 2625 dip->pr_flags = 0; 2626 } else { 2627 for (i = 0; i < val_cnt; i++) { 2628 int plen = 0; 2629 2630 plen = strlen(prop_val[i]); 2631 bcopy(prop_val[i], dp, plen); 2632 slen += plen; 2633 /* 2634 * add a "," separator and update dp. 2635 */ 2636 if (i != (val_cnt -1)) 2637 dp[slen++] = ','; 2638 dp += (plen + 1); 2639 } 2640 } 2641 if (status == DLADM_STATUS_OK) 2642 status = i_dladm_macprop(handle, dip, B_TRUE); 2643 2644 free(dip); 2645 return (status); 2646 } 2647 2648 static dladm_status_t 2649 i_dladm_get_priv_prop(dladm_handle_t handle, datalink_id_t linkid, 2650 const char *prop_name, char **prop_val, uint_t *val_cnt, 2651 dladm_prop_type_t type, uint_t dld_flags) 2652 { 2653 dladm_status_t status = DLADM_STATUS_OK; 2654 dld_ioc_macprop_t *dip = NULL; 2655 link_attr_t *p; 2656 2657 if ((prop_name == NULL && prop_val != NULL) || 2658 (prop_val != NULL && val_cnt == 0)) 2659 return (DLADM_STATUS_BADARG); 2660 2661 p = dladm_name2prop(prop_name); 2662 if (p->pp_id != MAC_PROP_PRIVATE) 2663 return (DLADM_STATUS_BADARG); 2664 2665 /* 2666 * private properties: all parsing is done in the kernel. 2667 */ 2668 dip = i_dladm_buf_alloc_by_name(DLADM_PROP_BUF_CHUNK, linkid, prop_name, 2669 dld_flags, &status); 2670 if (dip == NULL) 2671 return (status); 2672 2673 if ((status = i_dladm_macprop(handle, dip, B_FALSE)) == 2674 DLADM_STATUS_OK) { 2675 if (type == DLADM_PROP_VAL_PERM) { 2676 (void) dladm_perm2str(dip->pr_perm_flags, *prop_val); 2677 } else if (type == DLADM_PROP_VAL_MODIFIABLE) { 2678 *prop_val[0] = '\0'; 2679 } else { 2680 (void) strncpy(*prop_val, dip->pr_val, 2681 DLADM_PROP_VAL_MAX); 2682 } 2683 *val_cnt = 1; 2684 } else if ((status == DLADM_STATUS_NOTSUP) && 2685 (type == DLADM_PROP_VAL_CURRENT)) { 2686 status = DLADM_STATUS_NOTFOUND; 2687 } 2688 free(dip); 2689 return (status); 2690 } 2691 2692 2693 static dladm_status_t 2694 i_dladm_getset_defval(dladm_handle_t handle, prop_desc_t *pdp, 2695 datalink_id_t linkid, datalink_media_t media, uint_t flags) 2696 { 2697 dladm_status_t status; 2698 char **prop_vals = NULL, *buf; 2699 size_t bufsize; 2700 uint_t cnt; 2701 int i; 2702 uint_t perm_flags; 2703 2704 /* 2705 * Allocate buffer needed for prop_vals array. We can have at most 2706 * DLADM_MAX_PROP_VALCNT char *prop_vals[] entries, where 2707 * each entry has max size DLADM_PROP_VAL_MAX 2708 */ 2709 bufsize = 2710 (sizeof (char *) + DLADM_PROP_VAL_MAX) * DLADM_MAX_PROP_VALCNT; 2711 buf = malloc(bufsize); 2712 prop_vals = (char **)(void *)buf; 2713 for (i = 0; i < DLADM_MAX_PROP_VALCNT; i++) { 2714 prop_vals[i] = buf + 2715 sizeof (char *) * DLADM_MAX_PROP_VALCNT + 2716 i * DLADM_PROP_VAL_MAX; 2717 } 2718 2719 /* 2720 * For properties which have pdp->pd_defval.vd_name as a non-empty 2721 * string, the "" itself is used to reset the property (exceptions 2722 * are zone and autopush, which populate vdp->vd_val). So 2723 * libdladm can copy pdp->pd_defval over to the val_desc_t passed 2724 * down on the setprop using the global values in the table. For 2725 * other cases (vd_name is ""), doing reset-linkprop will cause 2726 * libdladm to do a getprop to find the default value and then do 2727 * a setprop to reset the value to default. 2728 */ 2729 status = pdp->pd_get(handle, pdp, linkid, prop_vals, &cnt, media, 2730 MAC_PROP_DEFAULT, &perm_flags); 2731 if (status == DLADM_STATUS_OK) { 2732 if (perm_flags == MAC_PROP_PERM_RW) { 2733 status = i_dladm_set_single_prop(handle, linkid, 2734 pdp->pd_class, media, pdp, prop_vals, cnt, flags); 2735 } 2736 else 2737 status = DLADM_STATUS_NOTSUP; 2738 } 2739 free(buf); 2740 return (status); 2741 } 2742 2743 int 2744 macprop_to_wifi(mac_prop_id_t wl_prop) 2745 { 2746 switch (wl_prop) { 2747 case MAC_PROP_WL_ESSID: 2748 return (WL_ESSID); 2749 case MAC_PROP_WL_BSSID: 2750 return (WL_BSSID); 2751 case MAC_PROP_WL_BSSTYPE: 2752 return (WL_BSS_TYPE); 2753 case MAC_PROP_WL_LINKSTATUS: 2754 return (WL_LINKSTATUS); 2755 case MAC_PROP_WL_DESIRED_RATES: 2756 return (WL_DESIRED_RATES); 2757 case MAC_PROP_WL_SUPPORTED_RATES: 2758 return (WL_SUPPORTED_RATES); 2759 case MAC_PROP_WL_AUTH_MODE: 2760 return (WL_AUTH_MODE); 2761 case MAC_PROP_WL_ENCRYPTION: 2762 return (WL_ENCRYPTION); 2763 case MAC_PROP_WL_RSSI: 2764 return (WL_RSSI); 2765 case MAC_PROP_WL_PHY_CONFIG: 2766 return (WL_PHY_CONFIG); 2767 case MAC_PROP_WL_CAPABILITY: 2768 return (WL_CAPABILITY); 2769 case MAC_PROP_WL_WPA: 2770 return (WL_WPA); 2771 case MAC_PROP_WL_SCANRESULTS: 2772 return (WL_SCANRESULTS); 2773 case MAC_PROP_WL_POWER_MODE: 2774 return (WL_POWER_MODE); 2775 case MAC_PROP_WL_RADIO: 2776 return (WL_RADIO); 2777 case MAC_PROP_WL_ESS_LIST: 2778 return (WL_ESS_LIST); 2779 case MAC_PROP_WL_KEY_TAB: 2780 return (WL_WEP_KEY_TAB); 2781 case MAC_PROP_WL_CREATE_IBSS: 2782 return (WL_CREATE_IBSS); 2783 case MAC_PROP_WL_SETOPTIE: 2784 return (WL_SETOPTIE); 2785 case MAC_PROP_WL_DELKEY: 2786 return (WL_DELKEY); 2787 case MAC_PROP_WL_KEY: 2788 return (WL_KEY); 2789 case MAC_PROP_WL_MLME: 2790 return (WL_MLME); 2791 default: 2792 return (-1); 2793 } 2794 } 2795 2796 dladm_status_t 2797 i_dladm_wlan_param(dladm_handle_t handle, datalink_id_t linkid, void *buf, 2798 mac_prop_id_t cmd, size_t len, boolean_t set) 2799 { 2800 uint32_t flags; 2801 dladm_status_t status; 2802 uint32_t media; 2803 dld_ioc_macprop_t *dip; 2804 void *dp; 2805 2806 if ((status = dladm_datalink_id2info(handle, linkid, &flags, NULL, 2807 &media, NULL, 0)) != DLADM_STATUS_OK) { 2808 return (status); 2809 } 2810 2811 if (media != DL_WIFI) 2812 return (DLADM_STATUS_BADARG); 2813 2814 if (!(flags & DLADM_OPT_ACTIVE)) 2815 return (DLADM_STATUS_TEMPONLY); 2816 2817 if (len == (MAX_BUF_LEN - WIFI_BUF_OFFSET)) 2818 len = MAX_BUF_LEN - sizeof (dld_ioc_macprop_t) - 1; 2819 2820 dip = i_dladm_buf_alloc_by_id(len, linkid, cmd, 0, &status); 2821 if (dip == NULL) 2822 return (DLADM_STATUS_NOMEM); 2823 2824 dp = (uchar_t *)dip->pr_val; 2825 if (set) 2826 (void) memcpy(dp, buf, len); 2827 2828 status = i_dladm_macprop(handle, dip, set); 2829 if (status == DLADM_STATUS_NOTSUP) { 2830 if (set) { 2831 status = i_dladm_wlan_set_legacy_ioctl(handle, linkid, 2832 buf, len, macprop_to_wifi(cmd)); 2833 } else { 2834 status = i_dladm_wlan_get_legacy_ioctl(handle, linkid, 2835 buf, len, macprop_to_wifi(cmd)); 2836 } 2837 } else if (status == DLADM_STATUS_OK) { 2838 if (!set) 2839 (void) memcpy(buf, dp, len); 2840 } 2841 2842 free(dip); 2843 return (status); 2844 } 2845 2846 static dladm_status_t 2847 i_dladm_wlan_get_legacy_ioctl(dladm_handle_t handle, datalink_id_t linkid, 2848 void *buf, uint_t buflen, uint_t id) 2849 { 2850 wldp_t *gbuf; 2851 dladm_status_t status; 2852 2853 if ((gbuf = malloc(MAX_BUF_LEN)) == NULL) 2854 return (DLADM_STATUS_NOMEM); 2855 2856 (void) memset(gbuf, 0, MAX_BUF_LEN); 2857 status = i_dladm_wlan_legacy_ioctl(handle, linkid, gbuf, id, 2858 MAX_BUF_LEN, WLAN_GET_PARAM, sizeof (wldp_t)); 2859 if (status == DLADM_STATUS_OK) 2860 (void) memcpy(buf, gbuf->wldp_buf, buflen); 2861 2862 free(gbuf); 2863 return (status); 2864 } 2865 2866 static dladm_status_t 2867 i_dladm_wlan_set_legacy_ioctl(dladm_handle_t handle, datalink_id_t linkid, 2868 void *buf, uint_t buflen, uint_t id) 2869 { 2870 wldp_t *gbuf; 2871 dladm_status_t status = DLADM_STATUS_OK; 2872 2873 if ((gbuf = malloc(MAX_BUF_LEN)) == NULL) 2874 return (DLADM_STATUS_NOMEM); 2875 2876 (void) memset(gbuf, 0, MAX_BUF_LEN); 2877 (void) memcpy(gbuf->wldp_buf, buf, buflen); 2878 buflen += WIFI_BUF_OFFSET; 2879 status = i_dladm_wlan_legacy_ioctl(handle, linkid, gbuf, id, buflen, 2880 WLAN_SET_PARAM, buflen); 2881 2882 free(gbuf); 2883 return (status); 2884 } 2885 2886 dladm_status_t 2887 dladm_parse_link_props(char *str, dladm_arg_list_t **listp, boolean_t novalues) 2888 { 2889 return (dladm_parse_args(str, listp, novalues)); 2890 } 2891 2892 /* 2893 * Retrieve the one link property from the database 2894 */ 2895 /*ARGSUSED*/ 2896 static int 2897 i_dladm_get_one_prop(dladm_handle_t handle, datalink_id_t linkid, 2898 const char *prop_name, void *arg) 2899 { 2900 dladm_arg_list_t *proplist = arg; 2901 dladm_arg_info_t *aip = NULL; 2902 2903 aip = &proplist->al_info[proplist->al_count]; 2904 /* 2905 * it is fine to point to prop_name since prop_name points to the 2906 * prop_table[n].pd_name. 2907 */ 2908 aip->ai_name = prop_name; 2909 2910 (void) dladm_get_linkprop(handle, linkid, DLADM_PROP_VAL_PERSISTENT, 2911 prop_name, aip->ai_val, &aip->ai_count); 2912 2913 if (aip->ai_count != 0) 2914 proplist->al_count++; 2915 2916 return (DLADM_WALK_CONTINUE); 2917 } 2918 2919 2920 /* 2921 * Retrieve all link properties for a link from the database and 2922 * return a property list. 2923 */ 2924 dladm_status_t 2925 dladm_link_get_proplist(dladm_handle_t handle, datalink_id_t linkid, 2926 dladm_arg_list_t **listp) 2927 { 2928 dladm_arg_list_t *list; 2929 dladm_status_t status = DLADM_STATUS_OK; 2930 2931 list = calloc(1, sizeof (dladm_arg_list_t)); 2932 if (list == NULL) 2933 return (dladm_errno2status(errno)); 2934 2935 status = dladm_walk_linkprop(handle, linkid, list, 2936 i_dladm_get_one_prop); 2937 2938 *listp = list; 2939 return (status); 2940 } 2941 2942 /* 2943 * Retrieve the named property from a proplist, check the value and 2944 * convert to a kernel structure. 2945 */ 2946 static dladm_status_t 2947 i_dladm_link_proplist_extract_one(dladm_handle_t handle, 2948 dladm_arg_list_t *proplist, const char *name, void *val) 2949 { 2950 dladm_status_t status; 2951 dladm_arg_info_t *aip = NULL; 2952 int i, j; 2953 2954 /* Find named property in proplist */ 2955 for (i = 0; i < proplist->al_count; i++) { 2956 aip = &proplist->al_info[i]; 2957 if (strcasecmp(aip->ai_name, name) == 0) 2958 break; 2959 } 2960 2961 /* Property not in list */ 2962 if (i == proplist->al_count) 2963 return (DLADM_STATUS_OK); 2964 2965 for (i = 0; i < DLADM_MAX_PROPS; i++) { 2966 prop_desc_t *pdp = &prop_table[i]; 2967 val_desc_t *vdp; 2968 2969 vdp = malloc(sizeof (val_desc_t) * aip->ai_count); 2970 if (vdp == NULL) 2971 return (DLADM_STATUS_NOMEM); 2972 2973 if (strcasecmp(aip->ai_name, pdp->pd_name) != 0) 2974 continue; 2975 2976 if (aip->ai_val == NULL) 2977 return (DLADM_STATUS_BADARG); 2978 2979 /* Check property value */ 2980 if (pdp->pd_check != NULL) { 2981 status = pdp->pd_check(handle, pdp, 0, aip->ai_val, 2982 aip->ai_count, vdp, 0); 2983 } else { 2984 status = DLADM_STATUS_BADARG; 2985 } 2986 2987 if (status != DLADM_STATUS_OK) 2988 return (status); 2989 2990 for (j = 0; j < DLADM_MAX_RSRC_PROP; j++) { 2991 resource_prop_t *rpp = &rsrc_prop_table[j]; 2992 2993 if (strcasecmp(aip->ai_name, rpp->rp_name) != 0) 2994 continue; 2995 2996 /* Extract kernel structure */ 2997 if (rpp->rp_extract != NULL) { 2998 status = rpp->rp_extract(vdp, val, 2999 aip->ai_count); 3000 } else { 3001 status = DLADM_STATUS_BADARG; 3002 } 3003 break; 3004 } 3005 3006 if (status != DLADM_STATUS_OK) 3007 return (status); 3008 3009 break; 3010 } 3011 return (status); 3012 } 3013 3014 /* 3015 * Extract properties from a proplist and convert to mac_resource_props_t. 3016 */ 3017 dladm_status_t 3018 dladm_link_proplist_extract(dladm_handle_t handle, dladm_arg_list_t *proplist, 3019 mac_resource_props_t *mrp) 3020 { 3021 dladm_status_t status = DLADM_STATUS_OK; 3022 3023 status = i_dladm_link_proplist_extract_one(handle, proplist, "maxbw", 3024 mrp); 3025 if (status != DLADM_STATUS_OK) 3026 return (status); 3027 status = i_dladm_link_proplist_extract_one(handle, proplist, "priority", 3028 mrp); 3029 if (status != DLADM_STATUS_OK) 3030 return (status); 3031 status = i_dladm_link_proplist_extract_one(handle, proplist, "cpus", 3032 mrp); 3033 if (status != DLADM_STATUS_OK) 3034 return (status); 3035 return (status); 3036 } 3037 3038 static const char * 3039 dladm_perm2str(uint_t perm, char *buf) 3040 { 3041 (void) snprintf(buf, DLADM_STRSIZE, "%c%c", 3042 ((perm & MAC_PROP_PERM_READ) != 0) ? 'r' : '-', 3043 ((perm & MAC_PROP_PERM_WRITE) != 0) ? 'w' : '-'); 3044 return (buf); 3045 } 3046 3047 dladm_status_t 3048 i_dladm_get_state(dladm_handle_t handle, datalink_id_t linkid, 3049 link_state_t *state) 3050 { 3051 dld_ioc_macprop_t *dip; 3052 dladm_status_t status; 3053 uint_t perms; 3054 3055 dip = i_dladm_get_public_prop(handle, linkid, "state", 0, &status, 3056 &perms); 3057 if (status != DLADM_STATUS_OK) 3058 return (status); 3059 (void) memcpy(state, dip->pr_val, sizeof (*state)); 3060 free(dip); 3061 return (status); 3062 } 3063 3064 boolean_t 3065 dladm_attr_is_linkprop(const char *name) 3066 { 3067 /* non-property attribute names */ 3068 const char *nonprop[] = { 3069 /* dlmgmtd core attributes */ 3070 "name", 3071 "class", 3072 "media", 3073 FPHYMAJ, 3074 FPHYINST, 3075 FDEVNAME, 3076 3077 /* other attributes for vlan, aggr, etc */ 3078 DLADM_ATTR_NAMES 3079 }; 3080 boolean_t is_nonprop = B_FALSE; 3081 int i; 3082 3083 for (i = 0; i < sizeof (nonprop) / sizeof (nonprop[0]); i++) { 3084 if (strcmp(name, nonprop[i]) == 0) { 3085 is_nonprop = B_TRUE; 3086 break; 3087 } 3088 } 3089 3090 return (!is_nonprop); 3091 } 3092