1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include <stdlib.h> 27 #include <strings.h> 28 #include <errno.h> 29 #include <ctype.h> 30 #include <stddef.h> 31 #include <sys/types.h> 32 #include <sys/stat.h> 33 #include <sys/dld.h> 34 #include <sys/zone.h> 35 #include <fcntl.h> 36 #include <unistd.h> 37 #include <libdevinfo.h> 38 #include <zone.h> 39 #include <libdllink.h> 40 #include <libdladm_impl.h> 41 #include <libdlwlan_impl.h> 42 #include <libdlwlan.h> 43 #include <libdlvlan.h> 44 #include <dlfcn.h> 45 #include <link.h> 46 #include <inet/wifi_ioctl.h> 47 #include <libdladm.h> 48 #include <sys/param.h> 49 #include <inttypes.h> 50 #include <sys/ethernet.h> 51 #include <net/wpa.h> 52 #include <sys/sysmacros.h> 53 54 /* 55 * The linkprop get() callback. 56 * - pd: pointer to the struct prop_desc 57 * - propstrp: a property string array to keep the returned property. 58 * Caller allocated. 59 * - cntp: number of returned properties. 60 * Caller also uses it to indicate how many it expects. 61 */ 62 struct prop_desc; 63 64 typedef dladm_status_t pd_getf_t(struct prop_desc *pd, 65 datalink_id_t, char **propstp, uint_t *cntp, 66 datalink_media_t, uint_t); 67 68 /* 69 * The linkprop set() callback. 70 * - propval: a val_desc_t array which keeps the property values to be set. 71 * - cnt: number of properties to be set. 72 * - flags: additional flags passed down the system call. 73 * 74 * pd_set takes val_desc_t given by pd_check(), translates it into 75 * a format suitable for kernel consumption. This may require allocation 76 * of ioctl buffers etc. pd_set() may call another common routine (used 77 * by all other pd_sets) which invokes the ioctl. 78 */ 79 typedef dladm_status_t pd_setf_t(struct prop_desc *, datalink_id_t, 80 val_desc_t *propval, uint_t cnt, uint_t flags, 81 datalink_media_t); 82 83 84 /* 85 * The linkprop check() callback. 86 * - propstrp: property string array which keeps the property to be checked. 87 * - cnt: number of properties. 88 * - propval: return value; the property values of the given property strings. 89 * 90 * pd_check checks that the input values are valid. It does so by 91 * iteraring through the pd_modval list for the property. If 92 * the modifiable values cannot be expressed as a list, a pd_check 93 * specific to this property can be used. If the input values are 94 * verified to be valid, pd_check allocates a val_desc_t and fills it 95 * with either a val_desc_t found on the pd_modval list or something 96 * generated on the fly. 97 */ 98 typedef dladm_status_t pd_checkf_t(struct prop_desc *pd, 99 datalink_id_t, char **propstrp, 100 uint_t cnt, val_desc_t *propval, 101 datalink_media_t); 102 103 typedef struct link_attr_s { 104 mac_prop_id_t pp_id; 105 size_t pp_valsize; 106 char *pp_name; 107 } link_attr_t; 108 109 static dld_ioc_macprop_t *i_dladm_buf_alloc_by_name(size_t, datalink_id_t, 110 const char *, uint_t, dladm_status_t *); 111 static dld_ioc_macprop_t *i_dladm_buf_alloc_by_id(size_t, datalink_id_t, 112 mac_prop_id_t, uint_t, 113 dladm_status_t *); 114 static dladm_status_t i_dladm_set_prop(datalink_id_t, const char *, char **, 115 uint_t, uint_t); 116 static dladm_status_t i_dladm_get_prop(datalink_id_t, const char *, char **, 117 uint_t *, dladm_prop_type_t, uint_t); 118 static link_attr_t *dladm_name2prop(const char *); 119 static link_attr_t *dladm_id2prop(mac_prop_id_t); 120 static dld_ioc_macprop_t *i_dladm_get_public_prop(datalink_id_t, char *, uint_t, 121 dladm_status_t *); 122 static pd_getf_t do_get_zone, do_get_autopush, do_get_rate_mod, 123 do_get_rate_prop, do_get_channel_prop, 124 do_get_powermode_prop, do_get_radio_prop, 125 i_dladm_duplex_get, i_dladm_status_get, 126 i_dladm_binary_get, i_dladm_uint32_get, 127 i_dladm_flowctl_get; 128 static pd_setf_t do_set_zone, do_set_rate_prop, 129 do_set_powermode_prop, do_set_radio_prop, 130 i_dladm_set_public_prop; 131 static pd_checkf_t do_check_zone, do_check_autopush, do_check_rate, 132 i_dladm_defmtu_check; 133 134 static dladm_status_t i_dladm_speed_get(struct prop_desc *, datalink_id_t, 135 char **, uint_t *, uint_t); 136 static dladm_status_t i_dladm_wlan_get_legacy_ioctl(datalink_id_t, void *, 137 uint_t, uint_t); 138 static dladm_status_t i_dladm_wlan_set_legacy_ioctl(datalink_id_t, void *, 139 uint_t, uint_t); 140 static dladm_status_t i_dladm_macprop(void *, boolean_t); 141 142 typedef struct prop_desc { 143 /* 144 * link property name 145 */ 146 char *pd_name; 147 148 /* 149 * default property value, can be set to { "", NULL } 150 */ 151 val_desc_t pd_defval; 152 153 /* 154 * list of optional property values, can be NULL. 155 * 156 * This is set to non-NULL if there is a list of possible property 157 * values. pd_optval would point to the array of possible values. 158 */ 159 val_desc_t *pd_optval; 160 161 /* 162 * count of the above optional property values. 0 if pd_optval is NULL. 163 */ 164 uint_t pd_noptval; 165 166 /* 167 * callback to set link property; 168 * set to NULL if this property is read-only 169 */ 170 pd_setf_t *pd_set; 171 172 /* 173 * callback to get modifiable link property 174 */ 175 pd_getf_t *pd_getmod; 176 177 /* 178 * callback to get current link property 179 */ 180 pd_getf_t *pd_get; 181 182 /* 183 * callback to validate link property value, set to NULL if pd_optval 184 * is not NULL. In that case, validate the value by comparing it with 185 * the pd_optval. Return a val_desc_t array pointer if the value is 186 * valid. 187 */ 188 pd_checkf_t *pd_check; 189 190 uint_t pd_flags; 191 #define PD_TEMPONLY 0x1 /* property is temporary only */ 192 #define PD_CHECK_ALLOC 0x2 /* alloc vd_val as part of pd_check */ 193 /* 194 * indicate link classes this property applies to. 195 */ 196 datalink_class_t pd_class; 197 198 /* 199 * indicate link media type this property applies to. 200 */ 201 datalink_media_t pd_dmedia; 202 } prop_desc_t; 203 204 #define MAC_PROP_BUFSIZE(v) sizeof (dld_ioc_macprop_t) + (v) - 1 205 206 /* 207 * Supported link properties enumerated in the prop_table[] array are 208 * computed using the callback functions in that array. To compute the 209 * property value, multiple distinct system calls may be needed (e.g., 210 * for wifi speed, we need to issue system calls to get desired/supported 211 * rates). The link_attr[] table enumerates the interfaces to the kernel, 212 * and the type/size of the data passed in the user-kernel interface. 213 */ 214 static link_attr_t link_attr[] = { 215 { MAC_PROP_DUPLEX, sizeof (link_duplex_t), "duplex"}, 216 217 { MAC_PROP_SPEED, sizeof (uint64_t), "speed"}, 218 219 { MAC_PROP_STATUS, sizeof (link_state_t), "state"}, 220 221 { MAC_PROP_AUTONEG, sizeof (uint8_t), "adv_autoneg_cap"}, 222 223 { MAC_PROP_MTU, sizeof (uint32_t), "mtu"}, 224 225 { MAC_PROP_FLOWCTRL, sizeof (link_flowctrl_t), "flowctrl"}, 226 227 { MAC_PROP_ZONE, sizeof (dld_ioc_zid_t), "zone"}, 228 229 { MAC_PROP_AUTOPUSH, sizeof (struct dlautopush), "autopush"}, 230 231 { MAC_PROP_ADV_1000FDX_CAP, sizeof (uint8_t), "adv_1000fdx_cap"}, 232 233 { MAC_PROP_EN_1000FDX_CAP, sizeof (uint8_t), "en_1000fdx_cap"}, 234 235 { MAC_PROP_ADV_1000HDX_CAP, sizeof (uint8_t), "adv_1000hdx_cap"}, 236 237 { MAC_PROP_EN_1000HDX_CAP, sizeof (uint8_t), "en_1000hdx_cap"}, 238 239 { MAC_PROP_ADV_100FDX_CAP, sizeof (uint8_t), "adv_100fdx_cap"}, 240 241 { MAC_PROP_EN_100FDX_CAP, sizeof (uint8_t), "en_100fdx_cap"}, 242 243 { MAC_PROP_ADV_100HDX_CAP, sizeof (uint8_t), "adv_100hdx_cap"}, 244 245 { MAC_PROP_EN_100HDX_CAP, sizeof (uint8_t), "en_100hdx_cap"}, 246 247 { MAC_PROP_ADV_10FDX_CAP, sizeof (uint8_t), "adv_10fdx_cap"}, 248 249 { MAC_PROP_EN_10FDX_CAP, sizeof (uint8_t), "en_10fdx_cap"}, 250 251 { MAC_PROP_ADV_10HDX_CAP, sizeof (uint8_t), "adv_10hdx_cap"}, 252 253 { MAC_PROP_EN_10HDX_CAP, sizeof (uint8_t), "en_10hdx_cap"}, 254 255 { MAC_PROP_WL_ESSID, sizeof (wl_linkstatus_t), "essid"}, 256 257 { MAC_PROP_WL_BSSID, sizeof (wl_bssid_t), "bssid"}, 258 259 { MAC_PROP_WL_BSSTYPE, sizeof (wl_bss_type_t), "bsstype"}, 260 261 { MAC_PROP_WL_LINKSTATUS, sizeof (wl_linkstatus_t), "wl_linkstatus"}, 262 263 /* wl_rates_t has variable length */ 264 { MAC_PROP_WL_DESIRED_RATES, sizeof (wl_rates_t), "desired_rates"}, 265 266 /* wl_rates_t has variable length */ 267 { MAC_PROP_WL_SUPPORTED_RATES, sizeof (wl_rates_t), "supported_rates"}, 268 269 { MAC_PROP_WL_AUTH_MODE, sizeof (wl_authmode_t), "authmode"}, 270 271 { MAC_PROP_WL_ENCRYPTION, sizeof (wl_encryption_t), "encryption"}, 272 273 { MAC_PROP_WL_RSSI, sizeof (wl_rssi_t), "signal"}, 274 275 { MAC_PROP_WL_PHY_CONFIG, sizeof (wl_phy_conf_t), "phy_conf"}, 276 277 { MAC_PROP_WL_CAPABILITY, sizeof (wl_capability_t), "capability"}, 278 279 { MAC_PROP_WL_WPA, sizeof (wl_wpa_t), "wpa"}, 280 281 /* wl_wpa_ess_t has variable length */ 282 { MAC_PROP_WL_SCANRESULTS, sizeof (wl_wpa_ess_t), "scan_results"}, 283 284 { MAC_PROP_WL_POWER_MODE, sizeof (wl_ps_mode_t), "powermode"}, 285 286 { MAC_PROP_WL_RADIO, sizeof (dladm_wlan_radio_t), "wl_radio"}, 287 288 { MAC_PROP_WL_ESS_LIST, sizeof (wl_ess_list_t), "wl_ess_list"}, 289 290 { MAC_PROP_WL_KEY_TAB, sizeof (wl_wep_key_tab_t), "wl_wep_key"}, 291 292 { MAC_PROP_WL_CREATE_IBSS, sizeof (wl_create_ibss_t), "createibss"}, 293 294 /* wl_wpa_ie_t has variable length */ 295 { MAC_PROP_WL_SETOPTIE, sizeof (wl_wpa_ie_t), "set_ie"}, 296 297 { MAC_PROP_WL_DELKEY, sizeof (wl_del_key_t), "wpa_del_key"}, 298 299 { MAC_PROP_WL_KEY, sizeof (wl_key_t), "wl_key"}, 300 301 { MAC_PROP_WL_MLME, sizeof (wl_mlme_t), "mlme"}, 302 303 { MAC_PROP_PRIVATE, 0, "driver-private"} 304 }; 305 306 static val_desc_t link_duplex_vals[] = { 307 { "half", LINK_DUPLEX_HALF }, 308 { "full", LINK_DUPLEX_HALF } 309 }; 310 static val_desc_t link_status_vals[] = { 311 { "up", LINK_STATE_UP }, 312 { "down", LINK_STATE_DOWN } 313 }; 314 static val_desc_t link_01_vals[] = { 315 { "1", 1 }, 316 { "0", 0 } 317 }; 318 static val_desc_t link_flow_vals[] = { 319 { "no", LINK_FLOWCTRL_NONE }, 320 { "tx", LINK_FLOWCTRL_TX }, 321 { "rx", LINK_FLOWCTRL_RX }, 322 { "bi", LINK_FLOWCTRL_BI } 323 }; 324 325 #define VALCNT(vals) (sizeof ((vals)) / sizeof (val_desc_t)) 326 327 static val_desc_t dladm_wlan_radio_vals[] = { 328 { "on", DLADM_WLAN_RADIO_ON }, 329 { "off", DLADM_WLAN_RADIO_OFF } 330 }; 331 332 static val_desc_t dladm_wlan_powermode_vals[] = { 333 { "off", DLADM_WLAN_PM_OFF }, 334 { "fast", DLADM_WLAN_PM_FAST }, 335 { "max", DLADM_WLAN_PM_MAX } 336 }; 337 338 static prop_desc_t prop_table[] = { 339 340 { "channel", { NULL, 0 }, 341 NULL, 0, NULL, NULL, 342 do_get_channel_prop, NULL, 0, 343 DATALINK_CLASS_PHYS, DL_WIFI }, 344 345 { "powermode", { "off", DLADM_WLAN_PM_OFF }, 346 dladm_wlan_powermode_vals, VALCNT(dladm_wlan_powermode_vals), 347 do_set_powermode_prop, NULL, 348 do_get_powermode_prop, NULL, 0, 349 DATALINK_CLASS_PHYS, DL_WIFI }, 350 351 { "radio", { "on", DLADM_WLAN_RADIO_ON }, 352 dladm_wlan_radio_vals, VALCNT(dladm_wlan_radio_vals), 353 do_set_radio_prop, NULL, 354 do_get_radio_prop, NULL, 0, 355 DATALINK_CLASS_PHYS, DL_WIFI }, 356 357 { "speed", { "", 0 }, NULL, 0, 358 do_set_rate_prop, do_get_rate_mod, 359 do_get_rate_prop, do_check_rate, 0, 360 DATALINK_CLASS_PHYS, DATALINK_ANY_MEDIATYPE }, 361 362 { "autopush", { "", 0 }, NULL, 0, 363 i_dladm_set_public_prop, NULL, 364 do_get_autopush, do_check_autopush, PD_CHECK_ALLOC, 365 DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE }, 366 367 { "zone", { "", 0 }, NULL, 0, 368 do_set_zone, NULL, 369 do_get_zone, do_check_zone, PD_TEMPONLY|PD_CHECK_ALLOC, 370 DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE }, 371 372 { "duplex", { "", 0 }, 373 link_duplex_vals, VALCNT(link_duplex_vals), 374 NULL, NULL, i_dladm_duplex_get, NULL, 375 0, DATALINK_CLASS_PHYS, DL_ETHER }, 376 377 { "state", { "up", LINK_STATE_UP }, 378 link_status_vals, VALCNT(link_status_vals), 379 NULL, NULL, i_dladm_status_get, NULL, 380 0, DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE }, 381 382 { "adv_autoneg_cap", { "1", 1 }, 383 link_01_vals, VALCNT(link_01_vals), 384 i_dladm_set_public_prop, NULL, i_dladm_binary_get, NULL, 385 0, DATALINK_CLASS_PHYS, DL_ETHER }, 386 387 { "mtu", { "", 0 }, NULL, 0, 388 i_dladm_set_public_prop, NULL, i_dladm_uint32_get, 389 i_dladm_defmtu_check, 0, DATALINK_CLASS_ALL, 390 DATALINK_ANY_MEDIATYPE }, 391 392 { "flowctrl", { "", 0 }, 393 link_flow_vals, VALCNT(link_flow_vals), 394 i_dladm_set_public_prop, NULL, i_dladm_flowctl_get, NULL, 395 0, DATALINK_CLASS_PHYS, DL_ETHER }, 396 397 { "adv_1000fdx_cap", { "", 0 }, 398 link_01_vals, VALCNT(link_01_vals), 399 NULL, NULL, i_dladm_binary_get, NULL, 400 0, DATALINK_CLASS_PHYS, DL_ETHER }, 401 402 { "en_1000fdx_cap", { "", 0 }, 403 link_01_vals, VALCNT(link_01_vals), 404 i_dladm_set_public_prop, NULL, i_dladm_binary_get, NULL, 405 0, DATALINK_CLASS_PHYS, DL_ETHER }, 406 407 { "adv_1000hdx_cap", { "", 0 }, 408 link_01_vals, VALCNT(link_01_vals), 409 NULL, NULL, i_dladm_binary_get, NULL, 410 0, DATALINK_CLASS_PHYS, DL_ETHER }, 411 412 { "en_1000hdx_cap", { "", 0 }, 413 link_01_vals, VALCNT(link_01_vals), 414 i_dladm_set_public_prop, NULL, i_dladm_binary_get, NULL, 415 0, DATALINK_CLASS_PHYS, DL_ETHER }, 416 417 { "adv_100fdx_cap", { "", 0 }, 418 link_01_vals, VALCNT(link_01_vals), 419 NULL, NULL, i_dladm_binary_get, NULL, 420 0, DATALINK_CLASS_PHYS, DL_ETHER }, 421 422 { "en_100fdx_cap", { "", 0 }, 423 link_01_vals, VALCNT(link_01_vals), 424 i_dladm_set_public_prop, NULL, i_dladm_binary_get, NULL, 425 0, DATALINK_CLASS_PHYS, DL_ETHER }, 426 427 { "adv_100hdx_cap", { "", 0 }, 428 link_01_vals, VALCNT(link_01_vals), 429 NULL, NULL, i_dladm_binary_get, NULL, 430 0, DATALINK_CLASS_PHYS, DL_ETHER }, 431 432 { "en_100hdx_cap", { "", 0 }, 433 link_01_vals, VALCNT(link_01_vals), 434 i_dladm_set_public_prop, NULL, i_dladm_binary_get, NULL, 435 0, DATALINK_CLASS_PHYS, DL_ETHER }, 436 437 { "adv_10fdx_cap", { "", 0 }, 438 link_01_vals, VALCNT(link_01_vals), 439 NULL, NULL, i_dladm_binary_get, NULL, 440 0, DATALINK_CLASS_PHYS, DL_ETHER }, 441 442 { "en_10fdx_cap", { "", 0 }, 443 link_01_vals, VALCNT(link_01_vals), 444 i_dladm_set_public_prop, NULL, i_dladm_binary_get, NULL, 445 0, DATALINK_CLASS_PHYS, DL_ETHER }, 446 447 { "adv_10hdx_cap", { "", 0 }, 448 link_01_vals, VALCNT(link_01_vals), 449 NULL, NULL, i_dladm_binary_get, NULL, 450 0, DATALINK_CLASS_PHYS, DL_ETHER }, 451 452 { "en_10hdx_cap", { "", 0 }, 453 link_01_vals, VALCNT(link_01_vals), 454 i_dladm_set_public_prop, NULL, i_dladm_binary_get, NULL, 455 0, DATALINK_CLASS_PHYS, DL_ETHER } 456 457 }; 458 459 #define DLADM_MAX_PROPS (sizeof (prop_table) / sizeof (prop_desc_t)) 460 461 /* 462 * when retrieving private properties, we pass down a buffer with 463 * DLADM_PROP_BUF_CHUNK of space for the driver to return the property value. 464 */ 465 #define DLADM_PROP_BUF_CHUNK 1024 466 467 static dladm_status_t i_dladm_set_linkprop_db(datalink_id_t, const char *, 468 char **, uint_t); 469 static dladm_status_t i_dladm_get_linkprop_db(datalink_id_t, const char *, 470 char **, uint_t *); 471 static dladm_status_t i_dladm_set_single_prop(datalink_id_t, datalink_class_t, 472 uint32_t, prop_desc_t *, char **, uint_t, uint_t); 473 static dladm_status_t i_dladm_set_linkprop(datalink_id_t, const char *, 474 char **, uint_t, uint_t); 475 static dladm_status_t i_dladm_getset_defval(prop_desc_t *, datalink_id_t, 476 datalink_media_t, uint_t); 477 /* 478 * Unfortunately, MAX_SCAN_SUPPORT_RATES is too small to allow all 479 * rates to be retrieved. However, we cannot increase it at this 480 * time because it will break binary compatibility with unbundled 481 * WiFi drivers and utilities. So for now we define an additional 482 * constant, MAX_SUPPORT_RATES, to allow all rates to be retrieved. 483 */ 484 #define MAX_SUPPORT_RATES 64 485 486 #define AP_ANCHOR "[anchor]" 487 #define AP_DELIMITER '.' 488 489 static dladm_status_t 490 do_check_prop(prop_desc_t *pdp, char **prop_val, uint_t val_cnt, 491 val_desc_t *vdp) 492 { 493 int i, j; 494 dladm_status_t status = DLADM_STATUS_OK; 495 496 for (j = 0; j < val_cnt; j++) { 497 for (i = 0; i < pdp->pd_noptval; i++) { 498 if (strcasecmp(*prop_val, 499 pdp->pd_optval[i].vd_name) == 0) { 500 break; 501 } 502 } 503 if (i == pdp->pd_noptval) { 504 status = DLADM_STATUS_BADVAL; 505 goto done; 506 } 507 (void) memcpy(vdp + j, &pdp->pd_optval[i], sizeof (val_desc_t)); 508 } 509 510 done: 511 return (status); 512 } 513 514 static dladm_status_t 515 i_dladm_set_single_prop(datalink_id_t linkid, datalink_class_t class, 516 uint32_t media, prop_desc_t *pdp, char **prop_val, uint_t val_cnt, 517 uint_t flags) 518 { 519 dladm_status_t status = DLADM_STATUS_OK; 520 val_desc_t *vdp = NULL; 521 boolean_t needfree = B_FALSE; 522 uint_t cnt, i; 523 524 if (!(pdp->pd_class & class)) 525 return (DLADM_STATUS_BADARG); 526 527 if (!DATALINK_MEDIA_ACCEPTED(pdp->pd_dmedia, media)) 528 return (DLADM_STATUS_BADARG); 529 530 if ((flags & DLADM_OPT_PERSIST) && (pdp->pd_flags & PD_TEMPONLY)) 531 return (DLADM_STATUS_TEMPONLY); 532 533 if (!(flags & DLADM_OPT_ACTIVE)) 534 return (DLADM_STATUS_OK); 535 536 if (pdp->pd_set == NULL) 537 return (DLADM_STATUS_PROPRDONLY); 538 539 if (pdp->pd_flags & PD_CHECK_ALLOC) 540 needfree = B_TRUE; 541 else 542 needfree = B_FALSE; 543 if (prop_val != NULL) { 544 vdp = malloc(sizeof (val_desc_t) * val_cnt); 545 if (vdp == NULL) 546 return (DLADM_STATUS_NOMEM); 547 548 549 if (pdp->pd_check != NULL) { 550 status = pdp->pd_check(pdp, linkid, prop_val, val_cnt, 551 vdp, media); 552 } else if (pdp->pd_optval != NULL) { 553 status = do_check_prop(pdp, prop_val, val_cnt, vdp); 554 } else { 555 status = DLADM_STATUS_BADARG; 556 } 557 558 if (status != DLADM_STATUS_OK) 559 goto done; 560 561 cnt = val_cnt; 562 } else { 563 if (pdp->pd_defval.vd_name == NULL) 564 return (DLADM_STATUS_NOTSUP); 565 566 cnt = 1; 567 if ((pdp->pd_flags & PD_CHECK_ALLOC) != 0 || 568 strlen(pdp->pd_defval.vd_name) > 0) { 569 if ((vdp = malloc(sizeof (val_desc_t))) == NULL) 570 return (DLADM_STATUS_NOMEM); 571 572 if (pdp->pd_check != NULL) { 573 status = pdp->pd_check(pdp, linkid, prop_val, 574 cnt, vdp, media); 575 if (status != DLADM_STATUS_OK) 576 goto done; 577 } else { 578 (void) memcpy(vdp, &pdp->pd_defval, 579 sizeof (val_desc_t)); 580 } 581 } else { 582 status = i_dladm_getset_defval(pdp, linkid, 583 media, flags); 584 return (status); 585 } 586 } 587 status = pdp->pd_set(pdp, linkid, vdp, cnt, flags, media); 588 if (needfree) { 589 for (i = 0; i < cnt; i++) 590 free((void *)((val_desc_t *)vdp + i)->vd_val); 591 } 592 done: 593 free(vdp); 594 return (status); 595 } 596 597 static dladm_status_t 598 i_dladm_set_linkprop(datalink_id_t linkid, const char *prop_name, 599 char **prop_val, uint_t val_cnt, uint_t flags) 600 { 601 int i; 602 boolean_t found = B_FALSE; 603 datalink_class_t class; 604 uint32_t media; 605 dladm_status_t status = DLADM_STATUS_OK; 606 607 status = dladm_datalink_id2info(linkid, NULL, &class, &media, NULL, 0); 608 if (status != DLADM_STATUS_OK) 609 return (status); 610 611 for (i = 0; i < DLADM_MAX_PROPS; i++) { 612 prop_desc_t *pdp = &prop_table[i]; 613 dladm_status_t s; 614 615 if (prop_name != NULL && 616 (strcasecmp(prop_name, pdp->pd_name) != 0)) 617 continue; 618 619 found = B_TRUE; 620 s = i_dladm_set_single_prop(linkid, class, media, pdp, prop_val, 621 val_cnt, flags); 622 623 if (prop_name != NULL) { 624 status = s; 625 break; 626 } else { 627 if (s != DLADM_STATUS_OK && 628 s != DLADM_STATUS_NOTSUP) 629 status = s; 630 } 631 } 632 if (!found) { 633 if (prop_name[0] == '_') { 634 /* other private properties */ 635 status = i_dladm_set_prop(linkid, prop_name, prop_val, 636 val_cnt, flags); 637 } else { 638 status = DLADM_STATUS_NOTFOUND; 639 } 640 } 641 642 return (status); 643 } 644 645 /* 646 * Set/reset link property for specific link 647 */ 648 dladm_status_t 649 dladm_set_linkprop(datalink_id_t linkid, const char *prop_name, char **prop_val, 650 uint_t val_cnt, uint_t flags) 651 { 652 dladm_status_t status = DLADM_STATUS_OK; 653 654 if ((linkid == DATALINK_INVALID_LINKID) || (flags == 0) || 655 (prop_val == NULL && val_cnt > 0) || 656 (prop_val != NULL && val_cnt == 0) || 657 (prop_name == NULL && prop_val != NULL)) { 658 return (DLADM_STATUS_BADARG); 659 } 660 661 status = i_dladm_set_linkprop(linkid, prop_name, prop_val, 662 val_cnt, flags); 663 if (status != DLADM_STATUS_OK) 664 return (status); 665 666 if (flags & DLADM_OPT_PERSIST) { 667 status = i_dladm_set_linkprop_db(linkid, prop_name, 668 prop_val, val_cnt); 669 } 670 return (status); 671 } 672 673 /* 674 * Walk link properties of the given specific link. 675 */ 676 dladm_status_t 677 dladm_walk_linkprop(datalink_id_t linkid, void *arg, 678 int (*func)(datalink_id_t, const char *, void *)) 679 { 680 dladm_status_t status; 681 datalink_class_t class; 682 uint_t media; 683 int i; 684 685 if (linkid == DATALINK_INVALID_LINKID || func == NULL) 686 return (DLADM_STATUS_BADARG); 687 688 status = dladm_datalink_id2info(linkid, NULL, &class, &media, NULL, 0); 689 if (status != DLADM_STATUS_OK) 690 return (status); 691 692 for (i = 0; i < DLADM_MAX_PROPS; i++) { 693 if (!(prop_table[i].pd_class & class)) 694 continue; 695 696 if (!DATALINK_MEDIA_ACCEPTED(prop_table[i].pd_dmedia, media)) 697 continue; 698 699 if (func(linkid, prop_table[i].pd_name, arg) == 700 DLADM_WALK_TERMINATE) { 701 break; 702 } 703 } 704 705 return (DLADM_STATUS_OK); 706 } 707 708 /* 709 * Get linkprop of the given specific link. 710 */ 711 dladm_status_t 712 dladm_get_linkprop(datalink_id_t linkid, dladm_prop_type_t type, 713 const char *prop_name, char **prop_val, uint_t *val_cntp) 714 { 715 dladm_status_t status = DLADM_STATUS_OK; 716 datalink_class_t class; 717 uint_t media; 718 prop_desc_t *pdp; 719 uint_t cnt, dld_flags = 0; 720 int i; 721 722 if (type == DLADM_PROP_VAL_DEFAULT) 723 dld_flags = MAC_PROP_DEFAULT; 724 725 if (linkid == DATALINK_INVALID_LINKID || prop_name == NULL || 726 prop_val == NULL || val_cntp == NULL || *val_cntp == 0) 727 return (DLADM_STATUS_BADARG); 728 729 for (i = 0; i < DLADM_MAX_PROPS; i++) 730 if (strcasecmp(prop_name, prop_table[i].pd_name) == 0) 731 break; 732 733 if (i == DLADM_MAX_PROPS) { 734 if (prop_name[0] == '_') { 735 /* 736 * private property. 737 */ 738 return (i_dladm_get_prop(linkid, prop_name, 739 prop_val, val_cntp, type, dld_flags)); 740 } else { 741 return (DLADM_STATUS_NOTFOUND); 742 } 743 } 744 745 pdp = &prop_table[i]; 746 747 status = dladm_datalink_id2info(linkid, NULL, &class, &media, NULL, 0); 748 if (status != DLADM_STATUS_OK) 749 return (status); 750 751 if (!(pdp->pd_class & class)) 752 return (DLADM_STATUS_BADARG); 753 754 if (!DATALINK_MEDIA_ACCEPTED(pdp->pd_dmedia, media)) 755 return (DLADM_STATUS_BADARG); 756 757 switch (type) { 758 case DLADM_PROP_VAL_CURRENT: 759 status = pdp->pd_get(pdp, linkid, prop_val, val_cntp, media, 760 dld_flags); 761 break; 762 763 case DLADM_PROP_VAL_DEFAULT: 764 /* 765 * If defaults are not defined for the property, 766 * pd_defval.vd_name should be null. If the driver 767 * has to be contacted for the value, vd_name should 768 * be the empty string (""). Otherwise, dladm will 769 * just print whatever is in the table. 770 */ 771 if (pdp->pd_defval.vd_name == NULL) { 772 status = DLADM_STATUS_NOTSUP; 773 break; 774 } 775 776 if (strlen(pdp->pd_defval.vd_name) == 0) { 777 status = pdp->pd_get(pdp, linkid, prop_val, val_cntp, 778 media, dld_flags); 779 } else { 780 (void) strcpy(*prop_val, pdp->pd_defval.vd_name); 781 } 782 *val_cntp = 1; 783 break; 784 785 case DLADM_PROP_VAL_MODIFIABLE: 786 if (pdp->pd_getmod != NULL) { 787 status = pdp->pd_getmod(pdp, linkid, prop_val, 788 val_cntp, media, dld_flags); 789 break; 790 } 791 cnt = pdp->pd_noptval; 792 if (cnt == 0) { 793 status = DLADM_STATUS_NOTSUP; 794 } else if (cnt > *val_cntp) { 795 status = DLADM_STATUS_TOOSMALL; 796 } else { 797 for (i = 0; i < cnt; i++) { 798 (void) strcpy(prop_val[i], 799 pdp->pd_optval[i].vd_name); 800 } 801 *val_cntp = cnt; 802 } 803 break; 804 case DLADM_PROP_VAL_PERSISTENT: 805 if (pdp->pd_flags & PD_TEMPONLY) 806 return (DLADM_STATUS_TEMPONLY); 807 status = i_dladm_get_linkprop_db(linkid, prop_name, 808 prop_val, val_cntp); 809 break; 810 default: 811 status = DLADM_STATUS_BADARG; 812 break; 813 } 814 815 return (status); 816 } 817 818 /*ARGSUSED*/ 819 static int 820 i_dladm_init_one_prop(datalink_id_t linkid, const char *prop_name, void *arg) 821 { 822 char *buf, **propvals; 823 uint_t i, valcnt = DLADM_MAX_PROP_VALCNT; 824 825 if ((buf = malloc((sizeof (char *) + DLADM_PROP_VAL_MAX) * 826 DLADM_MAX_PROP_VALCNT)) == NULL) { 827 return (DLADM_WALK_CONTINUE); 828 } 829 830 propvals = (char **)(void *)buf; 831 for (i = 0; i < valcnt; i++) { 832 propvals[i] = buf + 833 sizeof (char *) * DLADM_MAX_PROP_VALCNT + 834 i * DLADM_PROP_VAL_MAX; 835 } 836 837 if (dladm_get_linkprop(linkid, DLADM_PROP_VAL_PERSISTENT, prop_name, 838 propvals, &valcnt) != DLADM_STATUS_OK) { 839 goto done; 840 } 841 842 (void) dladm_set_linkprop(linkid, prop_name, propvals, valcnt, 843 DLADM_OPT_ACTIVE); 844 845 done: 846 if (buf != NULL) 847 free(buf); 848 849 return (DLADM_WALK_CONTINUE); 850 } 851 852 /*ARGSUSED*/ 853 static int 854 i_dladm_init_linkprop(datalink_id_t linkid, void *arg) 855 { 856 (void) dladm_init_linkprop(linkid, B_TRUE); 857 return (DLADM_WALK_CONTINUE); 858 } 859 860 dladm_status_t 861 dladm_init_linkprop(datalink_id_t linkid, boolean_t any_media) 862 { 863 datalink_media_t dmedia; 864 uint32_t media; 865 866 dmedia = any_media ? DATALINK_ANY_MEDIATYPE : DL_WIFI; 867 868 if (linkid == DATALINK_ALL_LINKID) { 869 (void) dladm_walk_datalink_id(i_dladm_init_linkprop, NULL, 870 DATALINK_CLASS_ALL, dmedia, DLADM_OPT_PERSIST); 871 } else if (any_media || ((dladm_datalink_id2info(linkid, NULL, NULL, 872 &media, NULL, 0) == DLADM_STATUS_OK) && 873 DATALINK_MEDIA_ACCEPTED(dmedia, media))) { 874 (void) dladm_walk_linkprop(linkid, NULL, i_dladm_init_one_prop); 875 } 876 return (DLADM_STATUS_OK); 877 } 878 879 /* ARGSUSED */ 880 static dladm_status_t 881 do_get_zone(struct prop_desc *pd, datalink_id_t linkid, 882 char **prop_val, uint_t *val_cnt, datalink_media_t media, uint_t flags) 883 { 884 char zone_name[ZONENAME_MAX]; 885 zoneid_t zid; 886 dladm_status_t status; 887 char *cp; 888 dld_ioc_macprop_t *dip; 889 890 if (flags != 0) 891 return (DLADM_STATUS_NOTSUP); 892 893 dip = i_dladm_get_public_prop(linkid, pd->pd_name, flags, &status); 894 if (status != DLADM_STATUS_OK) 895 return (status); 896 897 cp = dip->pr_val; 898 (void) memcpy(&zid, cp, sizeof (zid)); 899 free(dip); 900 901 *val_cnt = 1; 902 if (zid != GLOBAL_ZONEID) { 903 if (getzonenamebyid(zid, zone_name, sizeof (zone_name)) < 0) 904 return (dladm_errno2status(errno)); 905 906 (void) strncpy(*prop_val, zone_name, DLADM_PROP_VAL_MAX); 907 } else { 908 *prop_val[0] = '\0'; 909 } 910 911 return (DLADM_STATUS_OK); 912 } 913 914 typedef int (*zone_get_devroot_t)(char *, char *, size_t); 915 916 static int 917 i_dladm_get_zone_dev(char *zone_name, char *dev, size_t devlen) 918 { 919 char root[MAXPATHLEN]; 920 zone_get_devroot_t real_zone_get_devroot; 921 void *dlhandle; 922 void *sym; 923 int ret; 924 925 if ((dlhandle = dlopen("libzonecfg.so.1", RTLD_LAZY)) == NULL) 926 return (-1); 927 928 if ((sym = dlsym(dlhandle, "zone_get_devroot")) == NULL) { 929 (void) dlclose(dlhandle); 930 return (-1); 931 } 932 933 real_zone_get_devroot = (zone_get_devroot_t)sym; 934 935 if ((ret = real_zone_get_devroot(zone_name, root, sizeof (root))) == 0) 936 (void) snprintf(dev, devlen, "%s%s", root, "/dev"); 937 (void) dlclose(dlhandle); 938 return (ret); 939 } 940 941 static dladm_status_t 942 i_dladm_update_deventry(zoneid_t zid, datalink_id_t linkid, boolean_t add) 943 { 944 char path[MAXPATHLEN]; 945 char name[MAXLINKNAMELEN]; 946 di_prof_t prof = NULL; 947 char zone_name[ZONENAME_MAX]; 948 dladm_status_t status; 949 int ret; 950 951 if (getzonenamebyid(zid, zone_name, sizeof (zone_name)) < 0) 952 return (dladm_errno2status(errno)); 953 if (i_dladm_get_zone_dev(zone_name, path, sizeof (path)) != 0) 954 return (dladm_errno2status(errno)); 955 if (di_prof_init(path, &prof) != 0) 956 return (dladm_errno2status(errno)); 957 958 status = dladm_linkid2legacyname(linkid, name, MAXLINKNAMELEN); 959 if (status != DLADM_STATUS_OK) 960 goto cleanup; 961 962 if (add) 963 ret = di_prof_add_dev(prof, name); 964 else 965 ret = di_prof_add_exclude(prof, name); 966 967 if (ret != 0) { 968 status = dladm_errno2status(errno); 969 goto cleanup; 970 } 971 972 if (di_prof_commit(prof) != 0) 973 status = dladm_errno2status(errno); 974 cleanup: 975 if (prof) 976 di_prof_fini(prof); 977 978 return (status); 979 } 980 981 /* ARGSUSED */ 982 static dladm_status_t 983 do_set_zone(prop_desc_t *pd, datalink_id_t linkid, val_desc_t *vdp, 984 uint_t val_cnt, uint_t flags, datalink_media_t media) 985 { 986 dladm_status_t status = DLADM_STATUS_OK; 987 zoneid_t zid_old, zid_new; 988 char link[MAXLINKNAMELEN]; 989 char *cp; 990 dld_ioc_macprop_t *dip; 991 dld_ioc_zid_t *dzp; 992 993 if (val_cnt != 1) 994 return (DLADM_STATUS_BADVALCNT); 995 996 dzp = (dld_ioc_zid_t *)vdp->vd_val; 997 998 /* 999 * If diz_is_ppa_hack is set, then an implicit vlan must be created. 1000 * There is no old value to compare against, and vdp->vd_val is 1001 * already populated with the zoneid and linkname in the function 1002 * do_check_zone(). 1003 */ 1004 1005 if (dzp->diz_is_ppa_hack) { 1006 zid_old = GLOBAL_ZONEID; 1007 } else { 1008 dip = i_dladm_get_public_prop(linkid, pd->pd_name, 1009 flags, &status); 1010 if (status != DLADM_STATUS_OK) 1011 return (status); 1012 1013 cp = dip->pr_val; 1014 (void) memcpy(&zid_old, cp, sizeof (zid_old)); 1015 free(dip); 1016 } 1017 1018 zid_new = dzp->diz_zid; 1019 (void) strlcpy(link, dzp->diz_link, MAXLINKNAMELEN); 1020 1021 /* Do nothing if setting to current value */ 1022 if (zid_new == zid_old) 1023 return (status); 1024 1025 if (zid_new != GLOBAL_ZONEID) { 1026 /* 1027 * If the new zoneid is the global zone, we could destroy 1028 * the link (in the case of an implicitly-created VLAN) as a 1029 * result of setting the zoneid. In that case, we defer the 1030 * operation to the end of this function to avoid recreating 1031 * the VLAN and getting a different linkid during the rollback 1032 * if other operation fails. 1033 * 1034 * Otherwise, this operation will hold a reference to the 1035 * link and prevent a link renaming, so we need to do it 1036 * before other operations. 1037 */ 1038 status = i_dladm_set_public_prop(pd, linkid, vdp, val_cnt, 1039 flags, media); 1040 if (status != DLADM_STATUS_OK) 1041 return (status); 1042 } 1043 1044 if (zid_old != GLOBAL_ZONEID) { 1045 if (zone_remove_datalink(zid_old, link) != 0 && 1046 errno != ENXIO) { 1047 status = dladm_errno2status(errno); 1048 goto rollback1; 1049 } 1050 1051 /* 1052 * It is okay to fail to update the /dev entry (some 1053 * vanity-named links do not have a /dev entry). 1054 */ 1055 (void) i_dladm_update_deventry(zid_old, linkid, B_FALSE); 1056 } 1057 1058 if (zid_new != GLOBAL_ZONEID) { 1059 if (zone_add_datalink(zid_new, link) != 0) { 1060 status = dladm_errno2status(errno); 1061 goto rollback2; 1062 } 1063 1064 if (dzp->diz_is_ppa_hack) { 1065 if ((status = dladm_name2info(link, &linkid, NULL, NULL, 1066 NULL)) != DLADM_STATUS_OK) { 1067 return (status); 1068 } 1069 } 1070 1071 (void) i_dladm_update_deventry(zid_new, linkid, B_TRUE); 1072 } else { 1073 status = i_dladm_set_public_prop(pd, linkid, vdp, val_cnt, 1074 flags, media); 1075 if (status != DLADM_STATUS_OK) 1076 goto rollback2; 1077 } 1078 1079 return (DLADM_STATUS_OK); 1080 1081 rollback2: 1082 if (zid_old != GLOBAL_ZONEID) 1083 (void) i_dladm_update_deventry(zid_old, linkid, B_TRUE); 1084 if (zid_old != GLOBAL_ZONEID) 1085 (void) zone_add_datalink(zid_old, link); 1086 rollback1: 1087 if (zid_new != GLOBAL_ZONEID) { 1088 dzp->diz_zid = zid_old; 1089 (void) i_dladm_set_public_prop(pd, linkid, vdp, val_cnt, 1090 flags, media); 1091 } 1092 1093 return (status); 1094 } 1095 1096 /* ARGSUSED */ 1097 static dladm_status_t 1098 do_check_zone(struct prop_desc *pd, datalink_id_t linkid, char **prop_val, 1099 uint_t val_cnt, val_desc_t *vdp, datalink_media_t media) 1100 { 1101 char *zone_name; 1102 char linkname[MAXLINKNAMELEN]; 1103 zoneid_t zoneid; 1104 char *cp; 1105 dladm_status_t status = DLADM_STATUS_OK; 1106 boolean_t is_ppa_hack = B_FALSE; 1107 dld_ioc_zid_t *dzp; 1108 1109 if (val_cnt != 1) 1110 return (DLADM_STATUS_BADVALCNT); 1111 1112 dzp = malloc(sizeof (dld_ioc_zid_t)); 1113 if (dzp == NULL) 1114 return (DLADM_STATUS_NOMEM); 1115 1116 if (prop_val) { 1117 /* 1118 * The prop_val contains zone_name{:linkname}. The linkname is 1119 * present only when the link is a ppa-hacked vlan. 1120 */ 1121 cp = strchr(*prop_val, ':'); 1122 if (cp) { 1123 (void) strlcpy(linkname, cp + 1, MAXLINKNAMELEN); 1124 *cp = '\0'; 1125 is_ppa_hack = B_TRUE; 1126 } else { 1127 status = dladm_datalink_id2info(linkid, NULL, NULL, 1128 NULL, linkname, MAXLINKNAMELEN); 1129 if (status != DLADM_STATUS_OK) { 1130 goto done; 1131 } 1132 } 1133 zone_name = *prop_val; 1134 } else { 1135 zone_name = GLOBAL_ZONENAME; 1136 if ((status = dladm_datalink_id2info(linkid, NULL, NULL, NULL, 1137 linkname, MAXLINKNAMELEN)) != DLADM_STATUS_OK) { 1138 goto done; 1139 } 1140 } 1141 1142 if (strlen(linkname) > MAXLINKNAMELEN) { 1143 status = DLADM_STATUS_BADVAL; 1144 goto done; 1145 } 1146 1147 if ((zoneid = getzoneidbyname(zone_name)) == -1) { 1148 status = DLADM_STATUS_BADVAL; 1149 goto done; 1150 } 1151 1152 if (zoneid != GLOBAL_ZONEID) { 1153 ushort_t flags; 1154 1155 if (zone_getattr(zoneid, ZONE_ATTR_FLAGS, &flags, 1156 sizeof (flags)) < 0) { 1157 status = dladm_errno2status(errno); 1158 goto done; 1159 } 1160 1161 if (!(flags & ZF_NET_EXCL)) { 1162 status = DLADM_STATUS_BADVAL; 1163 goto done; 1164 } 1165 } 1166 1167 (void) memset(dzp, 0, sizeof (dld_ioc_zid_t)); 1168 1169 dzp->diz_zid = zoneid; 1170 (void) strlcpy(dzp->diz_link, linkname, MAXLINKNAMELEN); 1171 dzp->diz_is_ppa_hack = is_ppa_hack; 1172 1173 vdp->vd_val = (uintptr_t)dzp; 1174 return (DLADM_STATUS_OK); 1175 done: 1176 free(dzp); 1177 return (status); 1178 } 1179 1180 /* ARGSUSED */ 1181 static dladm_status_t 1182 do_get_autopush(struct prop_desc *pd, datalink_id_t linkid, 1183 char **prop_val, uint_t *val_cnt, datalink_media_t media, uint_t flags) 1184 { 1185 struct dlautopush dlap; 1186 int i, len; 1187 dladm_status_t status; 1188 dld_ioc_macprop_t *dip; 1189 1190 if (flags & MAC_PROP_DEFAULT) 1191 return (DLADM_STATUS_NOTDEFINED); 1192 1193 *val_cnt = 1; 1194 dip = i_dladm_get_public_prop(linkid, pd->pd_name, flags, &status); 1195 if (dip == NULL) { 1196 (*prop_val)[0] = '\0'; 1197 goto done; 1198 } 1199 (void) memcpy(&dlap, dip->pr_val, sizeof (dlap)); 1200 1201 for (i = 0, len = 0; i < dlap.dap_npush; i++) { 1202 if (i != 0) { 1203 (void) snprintf(*prop_val + len, 1204 DLADM_PROP_VAL_MAX - len, "%c", AP_DELIMITER); 1205 len += 1; 1206 } 1207 (void) snprintf(*prop_val + len, DLADM_PROP_VAL_MAX - len, 1208 "%s", dlap.dap_aplist[i]); 1209 len += strlen(dlap.dap_aplist[i]); 1210 if (dlap.dap_anchor - 1 == i) { 1211 (void) snprintf(*prop_val + len, 1212 DLADM_PROP_VAL_MAX - len, "%c%s", AP_DELIMITER, 1213 AP_ANCHOR); 1214 len += (strlen(AP_ANCHOR) + 1); 1215 } 1216 } 1217 1218 free(dip); 1219 done: 1220 return (DLADM_STATUS_OK); 1221 } 1222 1223 /* 1224 * Add the specified module to the dlautopush structure; returns a 1225 * DLADM_STATUS_* code. 1226 */ 1227 dladm_status_t 1228 i_dladm_add_ap_module(const char *module, struct dlautopush *dlap) 1229 { 1230 if ((strlen(module) == 0) || (strlen(module) > FMNAMESZ)) 1231 return (DLADM_STATUS_BADVAL); 1232 1233 if (strncasecmp(module, AP_ANCHOR, strlen(AP_ANCHOR)) == 0) { 1234 /* 1235 * We don't allow multiple anchors, and the anchor must 1236 * be after at least one module. 1237 */ 1238 if (dlap->dap_anchor != 0) 1239 return (DLADM_STATUS_BADVAL); 1240 if (dlap->dap_npush == 0) 1241 return (DLADM_STATUS_BADVAL); 1242 1243 dlap->dap_anchor = dlap->dap_npush; 1244 return (DLADM_STATUS_OK); 1245 } 1246 if (dlap->dap_npush > MAXAPUSH) 1247 return (DLADM_STATUS_BADVALCNT); 1248 1249 (void) strlcpy(dlap->dap_aplist[dlap->dap_npush++], module, 1250 FMNAMESZ + 1); 1251 1252 return (DLADM_STATUS_OK); 1253 } 1254 1255 /* 1256 * Currently, both '.' and ' '(space) can be used as the delimiters between 1257 * autopush modules. The former is used in dladm set-linkprop, and the 1258 * latter is used in the autopush(1M) file. 1259 */ 1260 /* ARGSUSED */ 1261 static dladm_status_t 1262 do_check_autopush(struct prop_desc *pd, datalink_id_t linkid, char **prop_val, 1263 uint_t val_cnt, val_desc_t *vdp, datalink_media_t media) 1264 { 1265 char *module; 1266 struct dlautopush *dlap; 1267 dladm_status_t status; 1268 char val[DLADM_PROP_VAL_MAX]; 1269 char delimiters[4]; 1270 1271 if (val_cnt != 1) 1272 return (DLADM_STATUS_BADVALCNT); 1273 1274 if (prop_val != NULL) { 1275 dlap = malloc(sizeof (struct dlautopush)); 1276 if (dlap == NULL) 1277 return (DLADM_STATUS_NOMEM); 1278 1279 (void) memset(dlap, 0, sizeof (struct dlautopush)); 1280 (void) snprintf(delimiters, 4, " %c\n", AP_DELIMITER); 1281 bcopy(*prop_val, val, DLADM_PROP_VAL_MAX); 1282 module = strtok(val, delimiters); 1283 while (module != NULL) { 1284 status = i_dladm_add_ap_module(module, dlap); 1285 if (status != DLADM_STATUS_OK) 1286 return (status); 1287 module = strtok(NULL, delimiters); 1288 } 1289 1290 vdp->vd_val = (uintptr_t)dlap; 1291 } else { 1292 vdp->vd_val = 0; 1293 } 1294 return (DLADM_STATUS_OK); 1295 } 1296 1297 #define WLDP_BUFSIZE (MAX_BUF_LEN - WIFI_BUF_OFFSET) 1298 1299 /* ARGSUSED */ 1300 static dladm_status_t 1301 do_get_rate_common(struct prop_desc *pd, datalink_id_t linkid, 1302 char **prop_val, uint_t *val_cnt, uint_t id) 1303 { 1304 wl_rates_t *wrp; 1305 uint_t i; 1306 dladm_status_t status = DLADM_STATUS_OK; 1307 1308 wrp = malloc(WLDP_BUFSIZE); 1309 if (wrp == NULL) 1310 return (DLADM_STATUS_NOMEM); 1311 1312 status = i_dladm_wlan_param(linkid, wrp, id, WLDP_BUFSIZE, B_FALSE); 1313 if (status != DLADM_STATUS_OK) 1314 goto done; 1315 1316 if (wrp->wl_rates_num > *val_cnt) { 1317 status = DLADM_STATUS_TOOSMALL; 1318 goto done; 1319 } 1320 1321 if (wrp->wl_rates_rates[0] == 0) { 1322 prop_val[0][0] = '\0'; 1323 *val_cnt = 1; 1324 goto done; 1325 } 1326 1327 for (i = 0; i < wrp->wl_rates_num; i++) { 1328 (void) snprintf(prop_val[i], DLADM_STRSIZE, "%.*f", 1329 wrp->wl_rates_rates[i] % 2, 1330 (float)wrp->wl_rates_rates[i] / 2); 1331 } 1332 *val_cnt = wrp->wl_rates_num; 1333 1334 done: 1335 free(wrp); 1336 return (status); 1337 } 1338 1339 static dladm_status_t 1340 do_get_rate_prop(struct prop_desc *pd, datalink_id_t linkid, 1341 char **prop_val, uint_t *val_cnt, datalink_media_t media, uint_t flags) 1342 { 1343 if (media != DL_WIFI) 1344 return (i_dladm_speed_get(pd, linkid, prop_val, 1345 val_cnt, flags)); 1346 1347 return (do_get_rate_common(pd, linkid, prop_val, val_cnt, 1348 MAC_PROP_WL_DESIRED_RATES)); 1349 } 1350 1351 /* ARGSUSED */ 1352 static dladm_status_t 1353 do_get_rate_mod(struct prop_desc *pd, datalink_id_t linkid, 1354 char **prop_val, uint_t *val_cnt, datalink_media_t media, uint_t flags) 1355 { 1356 switch (media) { 1357 case DL_ETHER: 1358 /* 1359 * Speed for ethernet links is unbounded. E.g., 802.11b 1360 * links can have a speed of 5.5 Gbps. 1361 */ 1362 return (DLADM_STATUS_NOTSUP); 1363 1364 case DL_WIFI: 1365 return (do_get_rate_common(pd, linkid, prop_val, val_cnt, 1366 MAC_PROP_WL_SUPPORTED_RATES)); 1367 default: 1368 return (DLADM_STATUS_BADARG); 1369 } 1370 } 1371 1372 static dladm_status_t 1373 do_set_rate(datalink_id_t linkid, dladm_wlan_rates_t *rates) 1374 { 1375 int i; 1376 uint_t len; 1377 wl_rates_t *wrp; 1378 dladm_status_t status = DLADM_STATUS_OK; 1379 1380 wrp = malloc(WLDP_BUFSIZE); 1381 if (wrp == NULL) 1382 return (DLADM_STATUS_NOMEM); 1383 1384 bzero(wrp, WLDP_BUFSIZE); 1385 for (i = 0; i < rates->wr_cnt; i++) 1386 wrp->wl_rates_rates[i] = rates->wr_rates[i]; 1387 wrp->wl_rates_num = rates->wr_cnt; 1388 1389 len = offsetof(wl_rates_t, wl_rates_rates) + 1390 (rates->wr_cnt * sizeof (char)) + WIFI_BUF_OFFSET; 1391 status = i_dladm_wlan_param(linkid, wrp, MAC_PROP_WL_DESIRED_RATES, 1392 len, B_TRUE); 1393 1394 free(wrp); 1395 return (status); 1396 } 1397 1398 /* ARGSUSED */ 1399 static dladm_status_t 1400 do_set_rate_prop(prop_desc_t *pd, datalink_id_t linkid, 1401 val_desc_t *vdp, uint_t val_cnt, uint_t flags, datalink_media_t media) 1402 { 1403 dladm_wlan_rates_t rates; 1404 dladm_status_t status; 1405 1406 /* 1407 * can currently set rate on WIFI links only. 1408 */ 1409 if (media != DL_WIFI) 1410 return (DLADM_STATUS_PROPRDONLY); 1411 1412 if (val_cnt != 1) 1413 return (DLADM_STATUS_BADVALCNT); 1414 1415 rates.wr_cnt = 1; 1416 rates.wr_rates[0] = vdp[0].vd_val; 1417 1418 status = do_set_rate(linkid, &rates); 1419 1420 done: 1421 return (status); 1422 } 1423 1424 /* ARGSUSED */ 1425 static dladm_status_t 1426 do_check_rate(struct prop_desc *pd, datalink_id_t linkid, char **prop_val, 1427 uint_t val_cnt, val_desc_t *vdp, datalink_media_t media) 1428 { 1429 int i; 1430 uint_t modval_cnt = MAX_SUPPORT_RATES; 1431 char *buf, **modval; 1432 dladm_status_t status; 1433 1434 if (val_cnt != 1) 1435 return (DLADM_STATUS_BADVALCNT); 1436 1437 buf = malloc((sizeof (char *) + DLADM_STRSIZE) * 1438 MAX_SUPPORT_RATES); 1439 if (buf == NULL) { 1440 status = DLADM_STATUS_NOMEM; 1441 goto done; 1442 } 1443 1444 modval = (char **)(void *)buf; 1445 for (i = 0; i < MAX_SUPPORT_RATES; i++) { 1446 modval[i] = buf + sizeof (char *) * MAX_SUPPORT_RATES + 1447 i * DLADM_STRSIZE; 1448 } 1449 1450 status = do_get_rate_mod(NULL, linkid, modval, &modval_cnt, media, 0); 1451 if (status != DLADM_STATUS_OK) 1452 goto done; 1453 1454 for (i = 0; i < modval_cnt; i++) { 1455 if (strcasecmp(*prop_val, modval[i]) == 0) { 1456 vdp->vd_val = (uintptr_t)(uint_t) 1457 (atof(*prop_val) * 2); 1458 status = DLADM_STATUS_OK; 1459 break; 1460 } 1461 } 1462 if (i == modval_cnt) 1463 status = DLADM_STATUS_BADVAL; 1464 done: 1465 free(buf); 1466 return (status); 1467 } 1468 1469 static dladm_status_t 1470 do_get_phyconf(datalink_id_t linkid, void *buf, int buflen) 1471 { 1472 return (i_dladm_wlan_param(linkid, buf, MAC_PROP_WL_PHY_CONFIG, 1473 buflen, B_FALSE)); 1474 } 1475 1476 /* ARGSUSED */ 1477 static dladm_status_t 1478 do_get_channel_prop(struct prop_desc *pd, datalink_id_t linkid, 1479 char **prop_val, uint_t *val_cnt, datalink_media_t media, uint_t flags) 1480 { 1481 uint32_t channel; 1482 char buf[WLDP_BUFSIZE]; 1483 dladm_status_t status = DLADM_STATUS_OK; 1484 wl_phy_conf_t wl_phy_conf; 1485 1486 if ((status = do_get_phyconf(linkid, buf, sizeof (buf))) 1487 != DLADM_STATUS_OK) 1488 goto done; 1489 1490 (void) memcpy(&wl_phy_conf, buf, sizeof (wl_phy_conf)); 1491 if (!i_dladm_wlan_convert_chan(&wl_phy_conf, &channel)) { 1492 status = DLADM_STATUS_NOTFOUND; 1493 goto done; 1494 } 1495 1496 (void) snprintf(*prop_val, DLADM_STRSIZE, "%u", channel); 1497 *val_cnt = 1; 1498 1499 done: 1500 return (status); 1501 } 1502 1503 static dladm_status_t 1504 do_get_powermode(datalink_id_t linkid, void *buf, int buflen) 1505 { 1506 return (i_dladm_wlan_param(linkid, buf, MAC_PROP_WL_POWER_MODE, 1507 buflen, B_FALSE)); 1508 } 1509 1510 /* ARGSUSED */ 1511 static dladm_status_t 1512 do_get_powermode_prop(struct prop_desc *pd, datalink_id_t linkid, 1513 char **prop_val, uint_t *val_cnt, datalink_media_t media, uint_t flags) 1514 { 1515 wl_ps_mode_t mode; 1516 const char *s; 1517 char buf[WLDP_BUFSIZE]; 1518 dladm_status_t status = DLADM_STATUS_OK; 1519 1520 if ((status = do_get_powermode(linkid, buf, sizeof (buf))) 1521 != DLADM_STATUS_OK) 1522 goto done; 1523 1524 (void) memcpy(&mode, buf, sizeof (mode)); 1525 switch (mode.wl_ps_mode) { 1526 case WL_PM_AM: 1527 s = "off"; 1528 break; 1529 case WL_PM_MPS: 1530 s = "max"; 1531 break; 1532 case WL_PM_FAST: 1533 s = "fast"; 1534 break; 1535 default: 1536 status = DLADM_STATUS_NOTFOUND; 1537 goto done; 1538 } 1539 (void) snprintf(*prop_val, DLADM_STRSIZE, "%s", s); 1540 *val_cnt = 1; 1541 1542 done: 1543 return (status); 1544 } 1545 1546 static dladm_status_t 1547 do_set_powermode(datalink_id_t linkid, dladm_wlan_powermode_t *pm) 1548 { 1549 wl_ps_mode_t ps_mode; 1550 1551 (void) memset(&ps_mode, 0xff, sizeof (ps_mode)); 1552 1553 switch (*pm) { 1554 case DLADM_WLAN_PM_OFF: 1555 ps_mode.wl_ps_mode = WL_PM_AM; 1556 break; 1557 case DLADM_WLAN_PM_MAX: 1558 ps_mode.wl_ps_mode = WL_PM_MPS; 1559 break; 1560 case DLADM_WLAN_PM_FAST: 1561 ps_mode.wl_ps_mode = WL_PM_FAST; 1562 break; 1563 default: 1564 return (DLADM_STATUS_NOTSUP); 1565 } 1566 return (i_dladm_wlan_param(linkid, &ps_mode, MAC_PROP_WL_POWER_MODE, 1567 sizeof (ps_mode), B_TRUE)); 1568 } 1569 1570 /* ARGSUSED */ 1571 static dladm_status_t 1572 do_set_powermode_prop(prop_desc_t *pd, datalink_id_t linkid, 1573 val_desc_t *vdp, uint_t val_cnt, uint_t flags, datalink_media_t media) 1574 { 1575 dladm_wlan_powermode_t powermode = (dladm_wlan_powermode_t)vdp->vd_val; 1576 dladm_status_t status; 1577 1578 if (val_cnt != 1) 1579 return (DLADM_STATUS_BADVALCNT); 1580 1581 status = do_set_powermode(linkid, &powermode); 1582 1583 return (status); 1584 } 1585 1586 static dladm_status_t 1587 do_get_radio(datalink_id_t linkid, void *buf, int buflen) 1588 { 1589 return (i_dladm_wlan_param(linkid, buf, MAC_PROP_WL_RADIO, buflen, 1590 B_FALSE)); 1591 } 1592 1593 /* ARGSUSED */ 1594 static dladm_status_t 1595 do_get_radio_prop(struct prop_desc *pd, datalink_id_t linkid, 1596 char **prop_val, uint_t *val_cnt, datalink_media_t media, uint_t flags) 1597 { 1598 wl_radio_t radio; 1599 const char *s; 1600 char buf[WLDP_BUFSIZE]; 1601 dladm_status_t status = DLADM_STATUS_OK; 1602 1603 if ((status = do_get_radio(linkid, buf, sizeof (buf))) 1604 != DLADM_STATUS_OK) 1605 goto done; 1606 1607 (void) memcpy(&radio, buf, sizeof (radio)); 1608 switch (radio) { 1609 case B_TRUE: 1610 s = "on"; 1611 break; 1612 case B_FALSE: 1613 s = "off"; 1614 break; 1615 default: 1616 status = DLADM_STATUS_NOTFOUND; 1617 goto done; 1618 } 1619 (void) snprintf(*prop_val, DLADM_STRSIZE, "%s", s); 1620 *val_cnt = 1; 1621 1622 done: 1623 return (status); 1624 } 1625 1626 static dladm_status_t 1627 do_set_radio(datalink_id_t linkid, dladm_wlan_radio_t *radio) 1628 { 1629 wl_radio_t r; 1630 1631 switch (*radio) { 1632 case DLADM_WLAN_RADIO_ON: 1633 r = B_TRUE; 1634 break; 1635 case DLADM_WLAN_RADIO_OFF: 1636 r = B_FALSE; 1637 break; 1638 default: 1639 return (DLADM_STATUS_NOTSUP); 1640 } 1641 return (i_dladm_wlan_param(linkid, &r, MAC_PROP_WL_RADIO, 1642 sizeof (r), B_TRUE)); 1643 } 1644 1645 /* ARGSUSED */ 1646 static dladm_status_t 1647 do_set_radio_prop(prop_desc_t *pd, datalink_id_t linkid, 1648 val_desc_t *vdp, uint_t val_cnt, uint_t fags, datalink_media_t media) 1649 { 1650 dladm_wlan_radio_t radio = (dladm_wlan_radio_t)vdp->vd_val; 1651 dladm_status_t status; 1652 1653 if (val_cnt != 1) 1654 return (DLADM_STATUS_BADVALCNT); 1655 1656 status = do_set_radio(linkid, &radio); 1657 1658 return (status); 1659 } 1660 1661 static dladm_status_t 1662 i_dladm_set_linkprop_db(datalink_id_t linkid, const char *prop_name, 1663 char **prop_val, uint_t val_cnt) 1664 { 1665 char buf[MAXLINELEN]; 1666 int i; 1667 dladm_conf_t conf; 1668 dladm_status_t status; 1669 1670 status = dladm_read_conf(linkid, &conf); 1671 if (status != DLADM_STATUS_OK) 1672 return (status); 1673 1674 /* 1675 * reset case. 1676 */ 1677 if (val_cnt == 0) { 1678 status = dladm_unset_conf_field(conf, prop_name); 1679 if (status == DLADM_STATUS_OK) 1680 status = dladm_write_conf(conf); 1681 goto done; 1682 } 1683 1684 buf[0] = '\0'; 1685 for (i = 0; i < val_cnt; i++) { 1686 (void) strlcat(buf, prop_val[i], MAXLINELEN); 1687 if (i != val_cnt - 1) 1688 (void) strlcat(buf, ",", MAXLINELEN); 1689 } 1690 1691 status = dladm_set_conf_field(conf, prop_name, DLADM_TYPE_STR, buf); 1692 if (status == DLADM_STATUS_OK) 1693 status = dladm_write_conf(conf); 1694 1695 done: 1696 dladm_destroy_conf(conf); 1697 return (status); 1698 } 1699 1700 static dladm_status_t 1701 i_dladm_get_linkprop_db(datalink_id_t linkid, const char *prop_name, 1702 char **prop_val, uint_t *val_cntp) 1703 { 1704 char buf[MAXLINELEN], *str; 1705 uint_t cnt = 0; 1706 dladm_conf_t conf; 1707 dladm_status_t status; 1708 1709 status = dladm_read_conf(linkid, &conf); 1710 if (status != DLADM_STATUS_OK) 1711 return (status); 1712 1713 status = dladm_get_conf_field(conf, prop_name, buf, MAXLINELEN); 1714 if (status != DLADM_STATUS_OK) 1715 goto done; 1716 1717 str = strtok(buf, ","); 1718 while (str != NULL) { 1719 if (cnt == *val_cntp) { 1720 status = DLADM_STATUS_TOOSMALL; 1721 goto done; 1722 } 1723 (void) strlcpy(prop_val[cnt++], str, DLADM_PROP_VAL_MAX); 1724 str = strtok(NULL, ","); 1725 } 1726 1727 *val_cntp = cnt; 1728 1729 done: 1730 dladm_destroy_conf(conf); 1731 return (status); 1732 } 1733 1734 static link_attr_t * 1735 dladm_name2prop(const char *prop_name) 1736 { 1737 link_attr_t *p; 1738 1739 for (p = link_attr; p->pp_id != MAC_PROP_PRIVATE; p++) { 1740 if (strcmp(p->pp_name, prop_name) == 0) 1741 break; 1742 } 1743 return (p); 1744 } 1745 1746 static link_attr_t * 1747 dladm_id2prop(mac_prop_id_t propid) 1748 { 1749 link_attr_t *p; 1750 1751 for (p = link_attr; p->pp_id != MAC_PROP_PRIVATE; p++) { 1752 if (p->pp_id == propid) 1753 break; 1754 } 1755 return (p); 1756 } 1757 1758 static dld_ioc_macprop_t * 1759 i_dladm_buf_alloc_impl(size_t valsize, datalink_id_t linkid, 1760 const char *prop_name, mac_prop_id_t propid, uint_t flags, 1761 dladm_status_t *status) 1762 { 1763 int dsize; 1764 dld_ioc_macprop_t *dip; 1765 1766 *status = DLADM_STATUS_OK; 1767 dsize = MAC_PROP_BUFSIZE(valsize); 1768 dip = malloc(dsize); 1769 if (dip == NULL) { 1770 *status = DLADM_STATUS_NOMEM; 1771 return (NULL); 1772 } 1773 bzero(dip, dsize); 1774 dip->pr_valsize = valsize; 1775 (void) strlcpy(dip->pr_name, prop_name, sizeof (dip->pr_name)); 1776 dip->pr_version = MAC_PROP_VERSION; 1777 dip->pr_linkid = linkid; 1778 dip->pr_num = propid; 1779 dip->pr_flags = flags; 1780 return (dip); 1781 } 1782 1783 static dld_ioc_macprop_t * 1784 i_dladm_buf_alloc_by_name(size_t valsize, datalink_id_t linkid, 1785 const char *prop_name, uint_t flags, dladm_status_t *status) 1786 { 1787 link_attr_t *p; 1788 1789 p = dladm_name2prop(prop_name); 1790 valsize = MAX(p->pp_valsize, valsize); 1791 return (i_dladm_buf_alloc_impl(valsize, linkid, prop_name, p->pp_id, 1792 flags, status)); 1793 } 1794 1795 static dld_ioc_macprop_t * 1796 i_dladm_buf_alloc_by_id(size_t valsize, datalink_id_t linkid, 1797 mac_prop_id_t propid, uint_t flags, dladm_status_t *status) 1798 { 1799 link_attr_t *p; 1800 1801 p = dladm_id2prop(propid); 1802 valsize = MAX(p->pp_valsize, valsize); 1803 return (i_dladm_buf_alloc_impl(valsize, linkid, p->pp_name, propid, 1804 flags, status)); 1805 } 1806 1807 /* ARGSUSED */ 1808 static dladm_status_t 1809 i_dladm_set_public_prop(prop_desc_t *pd, datalink_id_t linkid, 1810 val_desc_t *vdp, uint_t val_cnt, uint_t flags, datalink_media_t media) 1811 { 1812 dld_ioc_macprop_t *dip; 1813 dladm_status_t status = DLADM_STATUS_OK; 1814 uint8_t u8; 1815 uint16_t u16; 1816 uint32_t u32; 1817 void *val; 1818 1819 dip = i_dladm_buf_alloc_by_name(0, linkid, pd->pd_name, 0, &status); 1820 if (dip == NULL) 1821 return (status); 1822 1823 if (pd->pd_flags & PD_CHECK_ALLOC) 1824 val = (void *)vdp->vd_val; 1825 else { 1826 /* 1827 * Currently all 1/2/4-byte size properties are byte/word/int. 1828 * No need (yet) to distinguish these from arrays of same size. 1829 */ 1830 switch (dip->pr_valsize) { 1831 case 1: 1832 u8 = vdp->vd_val; 1833 val = &u8; 1834 break; 1835 case 2: 1836 u16 = vdp->vd_val; 1837 val = &u16; 1838 break; 1839 case 4: 1840 u32 = vdp->vd_val; 1841 val = &u32; 1842 break; 1843 default: 1844 val = &vdp->vd_val; 1845 break; 1846 } 1847 } 1848 1849 if (val != NULL) 1850 (void) memcpy(dip->pr_val, val, dip->pr_valsize); 1851 else 1852 dip->pr_valsize = 0; 1853 1854 status = i_dladm_macprop(dip, B_TRUE); 1855 1856 done: 1857 free(dip); 1858 return (status); 1859 } 1860 1861 dladm_status_t 1862 i_dladm_macprop(void *dip, boolean_t set) 1863 { 1864 int fd; 1865 dladm_status_t status = DLADM_STATUS_OK; 1866 1867 if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) { 1868 status = dladm_errno2status(errno); 1869 return (status); 1870 } 1871 if (ioctl(fd, (set ? DLDIOC_SETMACPROP : DLDIOC_GETMACPROP), dip)) 1872 status = dladm_errno2status(errno); 1873 1874 (void) close(fd); 1875 return (status); 1876 } 1877 1878 static dld_ioc_macprop_t * 1879 i_dladm_get_public_prop(datalink_id_t linkid, char *prop_name, uint_t flags, 1880 dladm_status_t *status) 1881 { 1882 dld_ioc_macprop_t *dip = NULL; 1883 1884 dip = i_dladm_buf_alloc_by_name(0, linkid, prop_name, flags, status); 1885 if (dip == NULL) 1886 return (NULL); 1887 1888 *status = i_dladm_macprop(dip, B_FALSE); 1889 if (*status != DLADM_STATUS_OK) { 1890 free(dip); 1891 return (NULL); 1892 } 1893 return (dip); 1894 } 1895 1896 /* ARGSUSED */ 1897 static dladm_status_t 1898 i_dladm_defmtu_check(struct prop_desc *pd, datalink_id_t linkid, 1899 char **prop_val, uint_t val_cnt, val_desc_t *v, datalink_media_t media) 1900 { 1901 if (val_cnt != 1) 1902 return (DLADM_STATUS_BADVAL); 1903 v->vd_val = atoi(prop_val[0]); 1904 return (DLADM_STATUS_OK); 1905 } 1906 1907 /* ARGSUSED */ 1908 static dladm_status_t 1909 i_dladm_duplex_get(struct prop_desc *pd, datalink_id_t linkid, 1910 char **prop_val, uint_t *val_cnt, datalink_media_t media, uint_t flags) 1911 { 1912 link_duplex_t link_duplex; 1913 dladm_status_t status; 1914 1915 if ((status = dladm_get_single_mac_stat(linkid, "link_duplex", 1916 KSTAT_DATA_UINT32, &link_duplex)) != 0) 1917 return (status); 1918 1919 switch (link_duplex) { 1920 case LINK_DUPLEX_FULL: 1921 (void) strcpy(*prop_val, "full"); 1922 break; 1923 case LINK_DUPLEX_HALF: 1924 (void) strcpy(*prop_val, "half"); 1925 break; 1926 default: 1927 (void) strcpy(*prop_val, "unknown"); 1928 break; 1929 } 1930 *val_cnt = 1; 1931 return (DLADM_STATUS_OK); 1932 } 1933 1934 /* ARGSUSED */ 1935 static dladm_status_t 1936 i_dladm_speed_get(struct prop_desc *pd, datalink_id_t linkid, 1937 char **prop_val, uint_t *val_cnt, uint_t flags) 1938 { 1939 uint64_t ifspeed = 0; 1940 dladm_status_t status; 1941 1942 if ((status = dladm_get_single_mac_stat(linkid, "ifspeed", 1943 KSTAT_DATA_UINT64, &ifspeed)) != 0) 1944 return (status); 1945 1946 if ((ifspeed % 1000000) != 0) { 1947 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, 1948 "%llf", ifspeed / (float)1000000); /* Mbps */ 1949 } else { 1950 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, 1951 "%llu", ifspeed / 1000000); /* Mbps */ 1952 } 1953 *val_cnt = 1; 1954 return (DLADM_STATUS_OK); 1955 } 1956 1957 /* ARGSUSED */ 1958 static dladm_status_t 1959 i_dladm_status_get(struct prop_desc *pd, datalink_id_t linkid, 1960 char **prop_val, uint_t *val_cnt, datalink_media_t media, uint_t flags) 1961 { 1962 link_state_t link_state; 1963 dladm_status_t status; 1964 uchar_t *cp; 1965 dld_ioc_macprop_t *dip; 1966 1967 dip = i_dladm_get_public_prop(linkid, pd->pd_name, flags, &status); 1968 if (status != DLADM_STATUS_OK) 1969 return (status); 1970 cp = (uchar_t *)dip->pr_val; 1971 (void) memcpy(&link_state, cp, sizeof (link_state)); 1972 1973 switch (link_state) { 1974 case LINK_STATE_UP: 1975 (void) strcpy(*prop_val, "up"); 1976 break; 1977 case LINK_STATE_DOWN: 1978 (void) strcpy(*prop_val, "down"); 1979 break; 1980 default: 1981 (void) strcpy(*prop_val, "unknown"); 1982 break; 1983 } 1984 *val_cnt = 1; 1985 free(dip); 1986 return (DLADM_STATUS_OK); 1987 } 1988 1989 /* ARGSUSED */ 1990 static dladm_status_t 1991 i_dladm_binary_get(struct prop_desc *pd, datalink_id_t linkid, 1992 char **prop_val, uint_t *val_cnt, datalink_media_t media, uint_t flags) 1993 { 1994 dld_ioc_macprop_t *dip; 1995 dladm_status_t status; 1996 1997 dip = i_dladm_get_public_prop(linkid, pd->pd_name, flags, &status); 1998 if (dip == NULL) 1999 return (status); 2000 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "%x", dip->pr_val[0]); 2001 free(dip); 2002 *val_cnt = 1; 2003 return (DLADM_STATUS_OK); 2004 } 2005 2006 /* ARGSUSED */ 2007 static dladm_status_t 2008 i_dladm_uint32_get(struct prop_desc *pd, datalink_id_t linkid, 2009 char **prop_val, uint_t *val_cnt, datalink_media_t media, uint_t flags) 2010 { 2011 dld_ioc_macprop_t *dip; 2012 uint32_t v = 0; 2013 uchar_t *cp; 2014 dladm_status_t status; 2015 2016 dip = i_dladm_get_public_prop(linkid, pd->pd_name, flags, &status); 2017 if (dip == NULL) 2018 return (status); 2019 cp = (uchar_t *)dip->pr_val; 2020 (void) memcpy(&v, cp, sizeof (v)); 2021 (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "%ld", v); 2022 free(dip); 2023 *val_cnt = 1; 2024 return (DLADM_STATUS_OK); 2025 } 2026 2027 /* ARGSUSED */ 2028 static dladm_status_t 2029 i_dladm_flowctl_get(struct prop_desc *pd, datalink_id_t linkid, 2030 char **prop_val, uint_t *val_cnt, datalink_media_t media, uint_t flags) 2031 { 2032 dld_ioc_macprop_t *dip; 2033 link_flowctrl_t v; 2034 dladm_status_t status; 2035 uchar_t *cp; 2036 2037 dip = i_dladm_get_public_prop(linkid, pd->pd_name, flags, &status); 2038 if (dip == NULL) 2039 return (status); 2040 cp = (uchar_t *)dip->pr_val; 2041 (void) memcpy(&v, cp, sizeof (v)); 2042 switch (v) { 2043 case LINK_FLOWCTRL_NONE: 2044 (void) sprintf(*prop_val, "no"); 2045 break; 2046 case LINK_FLOWCTRL_RX: 2047 (void) sprintf(*prop_val, "rx"); 2048 break; 2049 case LINK_FLOWCTRL_TX: 2050 (void) sprintf(*prop_val, "tx"); 2051 break; 2052 case LINK_FLOWCTRL_BI: 2053 (void) sprintf(*prop_val, "bi"); 2054 break; 2055 } 2056 free(dip); 2057 *val_cnt = 1; 2058 return (DLADM_STATUS_OK); 2059 } 2060 2061 2062 /* ARGSUSED */ 2063 static dladm_status_t 2064 i_dladm_set_prop(datalink_id_t linkid, const char *prop_name, 2065 char **prop_val, uint_t val_cnt, uint_t flags) 2066 { 2067 int i, slen; 2068 int bufsize = 0; 2069 dld_ioc_macprop_t *dip = NULL; 2070 uchar_t *dp; 2071 link_attr_t *p; 2072 dladm_status_t status = DLADM_STATUS_OK; 2073 2074 if ((prop_name == NULL && prop_val != NULL) || 2075 (prop_val != NULL && val_cnt == 0)) 2076 return (DLADM_STATUS_BADARG); 2077 p = dladm_name2prop(prop_name); 2078 if (p->pp_id != MAC_PROP_PRIVATE) 2079 return (DLADM_STATUS_BADARG); 2080 2081 /* 2082 * private properties: all parsing is done in the kernel. 2083 * allocate a enough space for each property + its separator (','). 2084 */ 2085 for (i = 0; i < val_cnt; i++) { 2086 bufsize += strlen(prop_val[i]) + 1; 2087 } 2088 2089 if (prop_val == NULL) { 2090 /* 2091 * getting default value. so use more buffer space. 2092 */ 2093 bufsize += DLADM_PROP_BUF_CHUNK; 2094 } 2095 2096 dip = i_dladm_buf_alloc_by_name(bufsize + 1, linkid, prop_name, 2097 (prop_val != NULL ? 0 : MAC_PROP_DEFAULT), &status); 2098 if (dip == NULL) 2099 return (status); 2100 2101 dp = (uchar_t *)dip->pr_val; 2102 slen = 0; 2103 2104 if (prop_val == NULL) { 2105 status = i_dladm_macprop(dip, B_FALSE); 2106 } else { 2107 for (i = 0; i < val_cnt; i++) { 2108 int plen = 0; 2109 2110 plen = strlen(prop_val[i]); 2111 bcopy(prop_val[i], dp, plen); 2112 slen += plen; 2113 /* 2114 * add a "," separator and update dp. 2115 */ 2116 if (i != (val_cnt -1)) 2117 dp[slen++] = ','; 2118 dp += (plen + 1); 2119 } 2120 status = i_dladm_macprop(dip, B_TRUE); 2121 } 2122 2123 free(dip); 2124 return (status); 2125 } 2126 2127 static dladm_status_t 2128 i_dladm_get_prop(datalink_id_t linkid, const char *prop_name, 2129 char **prop_val, uint_t *val_cnt, dladm_prop_type_t type, uint_t dld_flags) 2130 { 2131 dladm_status_t status = DLADM_STATUS_OK; 2132 dld_ioc_macprop_t *dip = NULL; 2133 link_attr_t *p; 2134 char tmp = '\0'; 2135 2136 if ((prop_name == NULL && prop_val != NULL) || 2137 (prop_val != NULL && val_cnt == 0)) 2138 return (DLADM_STATUS_BADARG); 2139 2140 p = dladm_name2prop(prop_name); 2141 if (p->pp_id != MAC_PROP_PRIVATE) 2142 return (DLADM_STATUS_BADARG); 2143 2144 if (type == DLADM_PROP_VAL_MODIFIABLE) { 2145 *prop_val = &tmp; 2146 *val_cnt = 1; 2147 return (DLADM_STATUS_OK); 2148 } 2149 2150 /* 2151 * private properties: all parsing is done in the kernel. 2152 */ 2153 dip = i_dladm_buf_alloc_by_name(DLADM_PROP_BUF_CHUNK, linkid, prop_name, 2154 dld_flags, &status); 2155 if (dip == NULL) 2156 return (status); 2157 2158 if ((status = i_dladm_macprop(dip, B_FALSE)) == DLADM_STATUS_OK) { 2159 (void) strncpy(*prop_val, dip->pr_val, DLADM_PROP_VAL_MAX); 2160 *val_cnt = 1; 2161 } 2162 free(dip); 2163 return (status); 2164 } 2165 2166 2167 static dladm_status_t 2168 i_dladm_getset_defval(prop_desc_t *pdp, datalink_id_t linkid, 2169 datalink_media_t media, uint_t flags) 2170 { 2171 dladm_status_t status; 2172 char **prop_vals = NULL, *buf; 2173 size_t bufsize; 2174 uint_t cnt; 2175 int i; 2176 2177 /* 2178 * Allocate buffer needed for prop_vals array. We can have at most 2179 * DLADM_MAX_PROP_VALCNT char *prop_vals[] entries, where 2180 * each entry has max size DLADM_PROP_VAL_MAX 2181 */ 2182 bufsize = 2183 (sizeof (char *) + DLADM_PROP_VAL_MAX) * DLADM_MAX_PROP_VALCNT; 2184 buf = malloc(bufsize); 2185 prop_vals = (char **)(void *)buf; 2186 for (i = 0; i < DLADM_MAX_PROP_VALCNT; i++) { 2187 prop_vals[i] = buf + 2188 sizeof (char *) * DLADM_MAX_PROP_VALCNT + 2189 i * DLADM_PROP_VAL_MAX; 2190 } 2191 2192 /* 2193 * For properties which have pdp->pd_defval.vd_name as a non-empty 2194 * string, the "" itself is used to reset the property (exceptions 2195 * are zone and autopush, which populate vdp->vd_val). So 2196 * libdladm can copy pdp->pd_defval over to the val_desc_t passed 2197 * down on the setprop using the global values in the table. For 2198 * other cases (vd_name is ""), doing reset-linkprop will cause 2199 * libdladm to do a getprop to find the default value and then do 2200 * a setprop to reset the value to default. 2201 */ 2202 status = pdp->pd_get(pdp, linkid, prop_vals, &cnt, media, 2203 MAC_PROP_DEFAULT); 2204 if (status == DLADM_STATUS_OK) { 2205 status = i_dladm_set_single_prop(linkid, pdp->pd_class, 2206 media, pdp, prop_vals, cnt, flags); 2207 } 2208 free(buf); 2209 return (status); 2210 } 2211 2212 int 2213 macprop_to_wifi(mac_prop_id_t wl_prop) 2214 { 2215 switch (wl_prop) { 2216 case MAC_PROP_WL_ESSID: 2217 return (WL_ESSID); 2218 case MAC_PROP_WL_BSSID: 2219 return (WL_BSSID); 2220 case MAC_PROP_WL_BSSTYPE: 2221 return (WL_BSS_TYPE); 2222 case MAC_PROP_WL_LINKSTATUS: 2223 return (WL_LINKSTATUS); 2224 case MAC_PROP_WL_DESIRED_RATES: 2225 return (WL_DESIRED_RATES); 2226 case MAC_PROP_WL_SUPPORTED_RATES: 2227 return (WL_SUPPORTED_RATES); 2228 case MAC_PROP_WL_AUTH_MODE: 2229 return (WL_AUTH_MODE); 2230 case MAC_PROP_WL_ENCRYPTION: 2231 return (WL_ENCRYPTION); 2232 case MAC_PROP_WL_RSSI: 2233 return (WL_RSSI); 2234 case MAC_PROP_WL_PHY_CONFIG: 2235 return (WL_PHY_CONFIG); 2236 case MAC_PROP_WL_CAPABILITY: 2237 return (WL_CAPABILITY); 2238 case MAC_PROP_WL_WPA: 2239 return (WL_WPA); 2240 case MAC_PROP_WL_SCANRESULTS: 2241 return (WL_SCANRESULTS); 2242 case MAC_PROP_WL_POWER_MODE: 2243 return (WL_POWER_MODE); 2244 case MAC_PROP_WL_RADIO: 2245 return (WL_RADIO); 2246 case MAC_PROP_WL_ESS_LIST: 2247 return (WL_ESS_LIST); 2248 case MAC_PROP_WL_KEY_TAB: 2249 return (WL_WEP_KEY_TAB); 2250 case MAC_PROP_WL_CREATE_IBSS: 2251 return (WL_CREATE_IBSS); 2252 case MAC_PROP_WL_SETOPTIE: 2253 return (WL_SETOPTIE); 2254 case MAC_PROP_WL_DELKEY: 2255 return (WL_DELKEY); 2256 case MAC_PROP_WL_KEY: 2257 return (WL_KEY); 2258 case MAC_PROP_WL_MLME: 2259 return (WL_MLME); 2260 default: 2261 return (-1); 2262 } 2263 } 2264 2265 dladm_status_t 2266 i_dladm_wlan_param(datalink_id_t linkid, void *buf, mac_prop_id_t cmd, 2267 size_t len, boolean_t set) 2268 { 2269 uint32_t flags; 2270 dladm_status_t status; 2271 uint32_t media; 2272 dld_ioc_macprop_t *dip; 2273 void *dp; 2274 2275 if ((status = dladm_datalink_id2info(linkid, &flags, NULL, &media, 2276 NULL, 0)) != DLADM_STATUS_OK) { 2277 return (status); 2278 } 2279 2280 if (media != DL_WIFI) 2281 return (DLADM_STATUS_BADARG); 2282 2283 if (!(flags & DLADM_OPT_ACTIVE)) 2284 return (DLADM_STATUS_TEMPONLY); 2285 2286 if (len == (MAX_BUF_LEN - WIFI_BUF_OFFSET)) 2287 len = MAX_BUF_LEN - sizeof (dld_ioc_macprop_t) - 1; 2288 2289 dip = i_dladm_buf_alloc_by_id(len, linkid, cmd, 0, &status); 2290 if (dip == NULL) 2291 return (DLADM_STATUS_NOMEM); 2292 2293 dp = (uchar_t *)dip->pr_val; 2294 if (set) 2295 (void) memcpy(dp, buf, len); 2296 2297 status = i_dladm_macprop(dip, set); 2298 if (status == DLADM_STATUS_NOTSUP) { 2299 if (set) { 2300 status = i_dladm_wlan_set_legacy_ioctl(linkid, 2301 buf, len, macprop_to_wifi(cmd)); 2302 } else { 2303 status = i_dladm_wlan_get_legacy_ioctl(linkid, 2304 buf, len, macprop_to_wifi(cmd)); 2305 } 2306 } else if (status == DLADM_STATUS_OK) { 2307 if (!set) 2308 (void) memcpy(buf, dp, len); 2309 } 2310 2311 free(dip); 2312 return (status); 2313 } 2314 2315 static dladm_status_t 2316 i_dladm_wlan_get_legacy_ioctl(datalink_id_t linkid, void *buf, uint_t buflen, 2317 uint_t id) 2318 { 2319 wldp_t *gbuf; 2320 dladm_status_t status; 2321 2322 if ((gbuf = malloc(MAX_BUF_LEN)) == NULL) 2323 return (DLADM_STATUS_NOMEM); 2324 2325 (void) memset(gbuf, 0, MAX_BUF_LEN); 2326 status = i_dladm_wlan_legacy_ioctl(linkid, gbuf, id, MAX_BUF_LEN, 2327 WLAN_GET_PARAM, sizeof (wldp_t)); 2328 if (status == DLADM_STATUS_OK) 2329 (void) memcpy(buf, gbuf->wldp_buf, buflen); 2330 2331 free(gbuf); 2332 return (status); 2333 } 2334 2335 static dladm_status_t 2336 i_dladm_wlan_set_legacy_ioctl(datalink_id_t linkid, void *buf, uint_t buflen, 2337 uint_t id) 2338 { 2339 wldp_t *gbuf; 2340 dladm_status_t status = DLADM_STATUS_OK; 2341 2342 if ((gbuf = malloc(MAX_BUF_LEN)) == NULL) 2343 return (DLADM_STATUS_NOMEM); 2344 2345 (void) memset(gbuf, 0, MAX_BUF_LEN); 2346 (void) memcpy(gbuf->wldp_buf, buf, buflen); 2347 buflen += WIFI_BUF_OFFSET; 2348 status = i_dladm_wlan_legacy_ioctl(linkid, gbuf, id, buflen, 2349 WLAN_SET_PARAM, buflen); 2350 2351 free(gbuf); 2352 return (status); 2353 } 2354