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