1 /* 2 * WPA Supplicant / dbus-based control interface 3 * Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc. 4 * Copyright (c) 2009-2010, Witold Sowa <witold.sowa@gmail.com> 5 * Copyright (c) 2009-2015, Jouni Malinen <j@w1.fi> 6 * 7 * This software may be distributed under the terms of the BSD license. 8 * See README for more details. 9 */ 10 11 #include "includes.h" 12 13 #include "common.h" 14 #include "common/ieee802_11_defs.h" 15 #include "eap_peer/eap_methods.h" 16 #include "eapol_supp/eapol_supp_sm.h" 17 #include "rsn_supp/wpa.h" 18 #include "ap/hostapd.h" 19 #include "ap/sta_info.h" 20 #include "ap/ap_drv_ops.h" 21 #include "../config.h" 22 #include "../wpa_supplicant_i.h" 23 #include "../driver_i.h" 24 #include "../notify.h" 25 #include "../bss.h" 26 #include "../scan.h" 27 #include "../autoscan.h" 28 #include "../ap.h" 29 #include "../interworking.h" 30 #include "dbus_new_helpers.h" 31 #include "dbus_new.h" 32 #include "dbus_new_handlers.h" 33 #include "dbus_dict_helpers.h" 34 #include "dbus_common_i.h" 35 #include "drivers/driver.h" 36 #ifdef CONFIG_MESH 37 #include "ap/hostapd.h" 38 #include "ap/sta_info.h" 39 #endif /* CONFIG_MESH */ 40 41 static const char * const debug_strings[] = { 42 "excessive", "msgdump", "debug", "info", "warning", "error", NULL 43 }; 44 45 46 /** 47 * wpas_dbus_error_unknown_error - Return a new UnknownError error message 48 * @message: Pointer to incoming dbus message this error refers to 49 * @arg: Optional string appended to error message 50 * Returns: a dbus error message 51 * 52 * Convenience function to create and return an UnknownError 53 */ 54 DBusMessage * wpas_dbus_error_unknown_error(DBusMessage *message, 55 const char *arg) 56 { 57 return dbus_message_new_error(message, WPAS_DBUS_ERROR_UNKNOWN_ERROR, 58 arg); 59 } 60 61 62 /** 63 * wpas_dbus_error_iface_unknown - Return a new invalid interface error message 64 * @message: Pointer to incoming dbus message this error refers to 65 * Returns: A dbus error message 66 * 67 * Convenience function to create and return an invalid interface error 68 */ 69 static DBusMessage * wpas_dbus_error_iface_unknown(DBusMessage *message) 70 { 71 return dbus_message_new_error( 72 message, WPAS_DBUS_ERROR_IFACE_UNKNOWN, 73 "wpa_supplicant knows nothing about this interface."); 74 } 75 76 77 /** 78 * wpas_dbus_error_network_unknown - Return a new NetworkUnknown error message 79 * @message: Pointer to incoming dbus message this error refers to 80 * Returns: a dbus error message 81 * 82 * Convenience function to create and return an invalid network error 83 */ 84 static DBusMessage * wpas_dbus_error_network_unknown(DBusMessage *message) 85 { 86 return dbus_message_new_error( 87 message, WPAS_DBUS_ERROR_NETWORK_UNKNOWN, 88 "There is no such a network in this interface."); 89 } 90 91 92 /** 93 * wpas_dbus_error_invalid_args - Return a new InvalidArgs error message 94 * @message: Pointer to incoming dbus message this error refers to 95 * Returns: a dbus error message 96 * 97 * Convenience function to create and return an invalid options error 98 */ 99 DBusMessage * wpas_dbus_error_invalid_args(DBusMessage *message, 100 const char *arg) 101 { 102 DBusMessage *reply; 103 104 reply = dbus_message_new_error( 105 message, WPAS_DBUS_ERROR_INVALID_ARGS, 106 "Did not receive correct message arguments."); 107 if (arg != NULL) 108 dbus_message_append_args(reply, DBUS_TYPE_STRING, &arg, 109 DBUS_TYPE_INVALID); 110 111 return reply; 112 } 113 114 115 /** 116 * wpas_dbus_error_scan_error - Return a new ScanError error message 117 * @message: Pointer to incoming dbus message this error refers to 118 * @error: Optional string to be used as the error message 119 * Returns: a dbus error message 120 * 121 * Convenience function to create and return a scan error 122 */ 123 static DBusMessage * wpas_dbus_error_scan_error(DBusMessage *message, 124 const char *error) 125 { 126 return dbus_message_new_error(message, 127 WPAS_DBUS_ERROR_IFACE_SCAN_ERROR, 128 error); 129 } 130 131 132 DBusMessage * wpas_dbus_error_no_memory(DBusMessage *message) 133 { 134 wpa_printf(MSG_DEBUG, "dbus: Failed to allocate memory"); 135 return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL); 136 } 137 138 139 static const char * const dont_quote[] = { 140 "key_mgmt", "proto", "pairwise", "auth_alg", "group", "eap", 141 "bssid", "scan_freq", "freq_list", "scan_ssid", "bssid_hint", 142 "bssid_ignore", "bssid_accept", /* deprecated aliases */ 143 "bssid_blacklist", "bssid_whitelist", 144 "group_mgmt", 145 "ignore_broadcast_ssid", 146 #ifdef CONFIG_MESH 147 "mesh_basic_rates", 148 #endif /* CONFIG_MESH */ 149 #ifdef CONFIG_P2P 150 "go_p2p_dev_addr", "p2p_client_list", "psk_list", 151 #endif /* CONFIG_P2P */ 152 #ifdef CONFIG_INTERWORKING 153 "roaming_consortium", "required_roaming_consortium", 154 #endif /* CONFIG_INTERWORKING */ 155 "mac_value", NULL 156 }; 157 158 static dbus_bool_t should_quote_opt(const char *key) 159 { 160 int i = 0; 161 162 while (dont_quote[i] != NULL) { 163 if (os_strcmp(key, dont_quote[i]) == 0) 164 return FALSE; 165 i++; 166 } 167 return TRUE; 168 } 169 170 /** 171 * get_iface_by_dbus_path - Get a new network interface 172 * @global: Pointer to global data from wpa_supplicant_init() 173 * @path: Pointer to a dbus object path representing an interface 174 * Returns: Pointer to the interface or %NULL if not found 175 */ 176 static struct wpa_supplicant * get_iface_by_dbus_path( 177 struct wpa_global *global, const char *path) 178 { 179 struct wpa_supplicant *wpa_s; 180 181 for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) { 182 if (wpa_s->dbus_new_path && 183 os_strcmp(wpa_s->dbus_new_path, path) == 0) 184 return wpa_s; 185 } 186 return NULL; 187 } 188 189 190 /** 191 * set_network_properties - Set properties of a configured network 192 * @wpa_s: wpa_supplicant structure for a network interface 193 * @ssid: wpa_ssid structure for a configured network 194 * @iter: DBus message iterator containing dictionary of network 195 * properties to set. 196 * @error: On failure, an error describing the failure 197 * Returns: TRUE if the request succeeds, FALSE if it failed 198 * 199 * Sets network configuration with parameters given id DBus dictionary 200 */ 201 dbus_bool_t set_network_properties(struct wpa_supplicant *wpa_s, 202 struct wpa_ssid *ssid, 203 DBusMessageIter *iter, 204 DBusError *error) 205 { 206 struct wpa_dbus_dict_entry entry = { .type = DBUS_TYPE_STRING }; 207 DBusMessageIter iter_dict; 208 char *value = NULL; 209 bool mac_addr3_set = false; 210 bool mac_value_set = false; 211 212 if (!wpa_dbus_dict_open_read(iter, &iter_dict, error)) 213 return FALSE; 214 215 while (wpa_dbus_dict_has_dict_entry(&iter_dict)) { 216 size_t size = 50; 217 int ret; 218 219 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) 220 goto error; 221 222 value = NULL; 223 if (entry.type == DBUS_TYPE_ARRAY && 224 entry.array_type == DBUS_TYPE_BYTE) { 225 if (entry.array_len <= 0) 226 goto error; 227 228 size = entry.array_len * 2 + 1; 229 value = os_zalloc(size); 230 if (value == NULL) 231 goto error; 232 233 ret = wpa_snprintf_hex(value, size, 234 (u8 *) entry.bytearray_value, 235 entry.array_len); 236 if (ret <= 0) 237 goto error; 238 } else if (entry.type == DBUS_TYPE_STRING) { 239 if (should_quote_opt(entry.key)) { 240 size = os_strlen(entry.str_value); 241 242 size += 3; 243 value = os_zalloc(size); 244 if (value == NULL) 245 goto error; 246 247 ret = os_snprintf(value, size, "\"%s\"", 248 entry.str_value); 249 if (os_snprintf_error(size, ret)) 250 goto error; 251 } else { 252 value = os_strdup(entry.str_value); 253 if (value == NULL) 254 goto error; 255 } 256 } else if (entry.type == DBUS_TYPE_UINT32) { 257 value = os_zalloc(size); 258 if (value == NULL) 259 goto error; 260 261 ret = os_snprintf(value, size, "%u", 262 entry.uint32_value); 263 if (os_snprintf_error(size, ret)) 264 goto error; 265 } else if (entry.type == DBUS_TYPE_INT32) { 266 value = os_zalloc(size); 267 if (value == NULL) 268 goto error; 269 270 ret = os_snprintf(value, size, "%d", 271 entry.int32_value); 272 if (os_snprintf_error(size, ret)) 273 goto error; 274 } else 275 goto error; 276 277 ret = wpa_config_set(ssid, entry.key, value, 0); 278 if (ret < 0) 279 goto error; 280 if (ret == 1) 281 goto skip_update; 282 283 #ifdef CONFIG_BGSCAN 284 if (os_strcmp(entry.key, "bgscan") == 0) { 285 /* 286 * Reset the bgscan parameters for the current network 287 * and continue. There's no need to flush caches for 288 * bgscan parameter changes. 289 */ 290 if (wpa_s->current_ssid == ssid && 291 wpa_s->wpa_state == WPA_COMPLETED) 292 wpa_supplicant_reset_bgscan(wpa_s); 293 os_free(value); 294 value = NULL; 295 wpa_dbus_dict_entry_clear(&entry); 296 continue; 297 } 298 #endif /* CONFIG_BGSCAN */ 299 300 if (os_strcmp(entry.key, "bssid") != 0 && 301 os_strcmp(entry.key, "priority") != 0) 302 wpa_sm_pmksa_cache_flush(wpa_s->wpa, ssid); 303 304 if (wpa_s->current_ssid == ssid || 305 wpa_s->current_ssid == NULL) { 306 /* 307 * Invalidate the EAP session cache if anything in the 308 * current or previously used configuration changes. 309 */ 310 eapol_sm_invalidate_cached_session(wpa_s->eapol); 311 } 312 313 if ((os_strcmp(entry.key, "psk") == 0 && 314 value[0] == '"' && ssid->ssid_len) || 315 (os_strcmp(entry.key, "ssid") == 0 && ssid->passphrase)) 316 wpa_config_update_psk(ssid); 317 else if (os_strcmp(entry.key, "priority") == 0) 318 wpa_config_update_prio_list(wpa_s->conf); 319 320 /* 321 * MAC address policy "3" needs to come with mac_value in 322 * the message so make sure that it is present (checked after 323 * the loop - here we just note what has been supplied). 324 */ 325 if (os_strcmp(entry.key, "mac_addr") == 0 && 326 atoi(value) == 3) 327 mac_addr3_set = true; 328 if (os_strcmp(entry.key, "mac_value") == 0) 329 mac_value_set = true; 330 331 skip_update: 332 os_free(value); 333 value = NULL; 334 wpa_dbus_dict_entry_clear(&entry); 335 } 336 337 if (mac_addr3_set && !mac_value_set) { 338 wpa_printf(MSG_INFO, "dbus: Invalid mac_addr policy config"); 339 dbus_set_error_const(error, DBUS_ERROR_INVALID_ARGS, 340 "Invalid mac_addr policy config"); 341 return FALSE; 342 } 343 344 return TRUE; 345 346 error: 347 os_free(value); 348 wpa_dbus_dict_entry_clear(&entry); 349 dbus_set_error_const(error, DBUS_ERROR_INVALID_ARGS, 350 "invalid message format"); 351 return FALSE; 352 } 353 354 355 static int set_cred_property(struct wpa_cred *cred, 356 struct wpa_dbus_dict_entry *entry) 357 { 358 size_t size; 359 int ret; 360 char *value; 361 362 if (entry->type == DBUS_TYPE_ARRAY && 363 entry->array_type == DBUS_TYPE_STRING) { 364 dbus_uint32_t i; 365 366 if (entry->array_len <= 0) 367 return -1; 368 369 for (i = 0; i < entry->array_len; i++) { 370 if (should_quote_opt(entry->key)) { 371 size = os_strlen(entry->strarray_value[i]); 372 373 size += 3; 374 value = os_zalloc(size); 375 if (!value) 376 return -1; 377 378 ret = os_snprintf(value, size, "\"%s\"", 379 entry->strarray_value[i]); 380 if (os_snprintf_error(size, ret)) { 381 os_free(value); 382 return -1; 383 } 384 } else { 385 value = os_strdup(entry->strarray_value[i]); 386 if (!value) 387 return -1; 388 } 389 390 ret = wpa_config_set_cred(cred, entry->key, value, 0); 391 os_free(value); 392 if (ret < 0) 393 return -1; 394 } 395 return 0; 396 } 397 398 if (entry->type == DBUS_TYPE_ARRAY && 399 entry->array_type == DBUS_TYPE_BYTE) { 400 if (entry->array_len <= 0) 401 return -1; 402 403 size = entry->array_len * 2 + 1; 404 value = os_zalloc(size); 405 if (!value) 406 return -1; 407 408 ret = wpa_snprintf_hex(value, size, 409 (u8 *) entry->bytearray_value, 410 entry->array_len); 411 if (ret <= 0) { 412 os_free(value); 413 return -1; 414 } 415 } else if (entry->type == DBUS_TYPE_STRING) { 416 if (should_quote_opt(entry->key)) { 417 size = os_strlen(entry->str_value); 418 419 size += 3; 420 value = os_zalloc(size); 421 if (!value) 422 return -1; 423 424 ret = os_snprintf(value, size, "\"%s\"", 425 entry->str_value); 426 if (os_snprintf_error(size, ret)) { 427 os_free(value); 428 return -1; 429 } 430 } else { 431 value = os_strdup(entry->str_value); 432 if (!value) 433 return -1; 434 } 435 } else if (entry->type == DBUS_TYPE_UINT32) { 436 size = 50; 437 value = os_zalloc(size); 438 if (!value) 439 return -1; 440 441 ret = os_snprintf(value, size, "%u", entry->uint32_value); 442 if (os_snprintf_error(size, ret)) { 443 os_free(value); 444 return -1; 445 } 446 } else if (entry->type == DBUS_TYPE_INT32) { 447 size = 50; 448 value = os_zalloc(size); 449 if (!value) 450 return -1; 451 452 ret = os_snprintf(value, size, "%d", entry->int32_value); 453 if (os_snprintf_error(size, ret)) { 454 os_free(value); 455 return -1; 456 } 457 } else { 458 return -1; 459 } 460 461 ret = wpa_config_set_cred(cred, entry->key, value, 0); 462 os_free(value); 463 return ret; 464 } 465 466 467 /** 468 * set_cred_properties - Set the properties of a configured credential 469 * @wpa_s: wpa_supplicant structure for a network interface 470 * @cred: wpa_cred structure for a configured credential 471 * @iter: DBus message iterator containing dictionary of network 472 * properties to set. 473 * @error: On failure, an error describing the failure 474 * Returns: TRUE if the request succeeds, FALSE if it failed 475 */ 476 static dbus_bool_t set_cred_properties(struct wpa_supplicant *wpa_s, 477 struct wpa_cred *cred, 478 DBusMessageIter *iter, 479 DBusError *error) 480 { 481 struct wpa_dbus_dict_entry entry = { .type = DBUS_TYPE_STRING }; 482 DBusMessageIter iter_dict; 483 484 if (!wpa_dbus_dict_open_read(iter, &iter_dict, error)) 485 return FALSE; 486 487 while (wpa_dbus_dict_has_dict_entry(&iter_dict)) { 488 int res; 489 490 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) { 491 res = -1; 492 } else { 493 res = set_cred_property(cred, &entry); 494 wpa_dbus_dict_entry_clear(&entry); 495 } 496 497 if (res < 0) { 498 dbus_set_error_const(error, DBUS_ERROR_INVALID_ARGS, 499 "invalid message format"); 500 return FALSE; 501 } 502 } 503 504 return TRUE; 505 } 506 507 508 /** 509 * wpas_dbus_simple_property_getter - Get basic type property 510 * @iter: Message iter to use when appending arguments 511 * @type: DBus type of property (must be basic type) 512 * @val: pointer to place holding property value 513 * @error: On failure an error describing the failure 514 * Returns: TRUE if the request was successful, FALSE if it failed 515 * 516 * Generic getter for basic type properties. Type is required to be basic. 517 */ 518 dbus_bool_t wpas_dbus_simple_property_getter(DBusMessageIter *iter, 519 const int type, 520 const void *val, 521 DBusError *error) 522 { 523 DBusMessageIter variant_iter; 524 525 if (!dbus_type_is_basic(type)) { 526 dbus_set_error(error, DBUS_ERROR_FAILED, 527 "%s: given type is not basic", __func__); 528 return FALSE; 529 } 530 531 if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, 532 wpa_dbus_type_as_string(type), 533 &variant_iter) || 534 !dbus_message_iter_append_basic(&variant_iter, type, val) || 535 !dbus_message_iter_close_container(iter, &variant_iter)) { 536 dbus_set_error(error, DBUS_ERROR_FAILED, 537 "%s: error constructing reply", __func__); 538 return FALSE; 539 } 540 541 return TRUE; 542 } 543 544 545 /** 546 * wpas_dbus_simple_property_setter - Set basic type property 547 * @message: Pointer to incoming dbus message 548 * @type: DBus type of property (must be basic type) 549 * @val: pointer to place where value being set will be stored 550 * Returns: TRUE if the request was successful, FALSE if it failed 551 * 552 * Generic setter for basic type properties. Type is required to be basic. 553 */ 554 dbus_bool_t wpas_dbus_simple_property_setter(DBusMessageIter *iter, 555 DBusError *error, 556 const int type, void *val) 557 { 558 DBusMessageIter variant_iter; 559 560 if (!dbus_type_is_basic(type)) { 561 dbus_set_error(error, DBUS_ERROR_FAILED, 562 "%s: given type is not basic", __func__); 563 return FALSE; 564 } 565 566 /* Look at the new value */ 567 dbus_message_iter_recurse(iter, &variant_iter); 568 if (dbus_message_iter_get_arg_type(&variant_iter) != type) { 569 dbus_set_error_const(error, DBUS_ERROR_FAILED, 570 "wrong property type"); 571 return FALSE; 572 } 573 dbus_message_iter_get_basic(&variant_iter, val); 574 575 return TRUE; 576 } 577 578 579 /** 580 * wpas_dbus_simple_array_property_getter - Get array type property 581 * @iter: Pointer to incoming dbus message iterator 582 * @type: DBus type of property array elements (must be basic type) 583 * @array: pointer to array of elements to put into response message 584 * @array_len: length of above array 585 * @error: a pointer to an error to fill on failure 586 * Returns: TRUE if the request succeeded, FALSE if it failed 587 * 588 * Generic getter for array type properties. Array elements type is 589 * required to be basic. 590 */ 591 dbus_bool_t wpas_dbus_simple_array_property_getter(DBusMessageIter *iter, 592 const int type, 593 const void *array, 594 size_t array_len, 595 DBusError *error) 596 { 597 DBusMessageIter variant_iter, array_iter; 598 char type_str[] = "a?"; /* ? will be replaced with subtype letter; */ 599 const char *sub_type_str; 600 size_t element_size, i; 601 602 if (!dbus_type_is_basic(type)) { 603 dbus_set_error(error, DBUS_ERROR_FAILED, 604 "%s: given type is not basic", __func__); 605 return FALSE; 606 } 607 608 sub_type_str = wpa_dbus_type_as_string(type); 609 type_str[1] = sub_type_str[0]; 610 611 if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, 612 type_str, &variant_iter) || 613 !dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY, 614 sub_type_str, &array_iter)) { 615 dbus_set_error(error, DBUS_ERROR_FAILED, 616 "%s: failed to construct message", __func__); 617 return FALSE; 618 } 619 620 switch (type) { 621 case DBUS_TYPE_BYTE: 622 case DBUS_TYPE_BOOLEAN: 623 element_size = 1; 624 break; 625 case DBUS_TYPE_INT16: 626 case DBUS_TYPE_UINT16: 627 element_size = sizeof(uint16_t); 628 break; 629 case DBUS_TYPE_INT32: 630 case DBUS_TYPE_UINT32: 631 element_size = sizeof(uint32_t); 632 break; 633 case DBUS_TYPE_INT64: 634 case DBUS_TYPE_UINT64: 635 element_size = sizeof(uint64_t); 636 break; 637 case DBUS_TYPE_DOUBLE: 638 element_size = sizeof(double); 639 break; 640 case DBUS_TYPE_STRING: 641 case DBUS_TYPE_OBJECT_PATH: 642 element_size = sizeof(char *); 643 break; 644 default: 645 dbus_set_error(error, DBUS_ERROR_FAILED, 646 "%s: unknown element type %d", __func__, type); 647 return FALSE; 648 } 649 650 for (i = 0; i < array_len; i++) { 651 if (!dbus_message_iter_append_basic(&array_iter, type, 652 (const char *) array + 653 i * element_size)) { 654 dbus_set_error(error, DBUS_ERROR_FAILED, 655 "%s: failed to construct message 2.5", 656 __func__); 657 return FALSE; 658 } 659 } 660 661 if (!dbus_message_iter_close_container(&variant_iter, &array_iter) || 662 !dbus_message_iter_close_container(iter, &variant_iter)) { 663 dbus_set_error(error, DBUS_ERROR_FAILED, 664 "%s: failed to construct message 3", __func__); 665 return FALSE; 666 } 667 668 return TRUE; 669 } 670 671 672 /** 673 * wpas_dbus_simple_array_array_property_getter - Get array array type property 674 * @iter: Pointer to incoming dbus message iterator 675 * @type: DBus type of property array elements (must be basic type) 676 * @array: pointer to array of elements to put into response message 677 * @array_len: length of above array 678 * @error: a pointer to an error to fill on failure 679 * Returns: TRUE if the request succeeded, FALSE if it failed 680 * 681 * Generic getter for array type properties. Array elements type is 682 * required to be basic. 683 */ 684 dbus_bool_t wpas_dbus_simple_array_array_property_getter(DBusMessageIter *iter, 685 const int type, 686 struct wpabuf **array, 687 size_t array_len, 688 DBusError *error) 689 { 690 DBusMessageIter variant_iter, array_iter; 691 char type_str[] = "aa?"; 692 char inner_type_str[] = "a?"; 693 const char *sub_type_str; 694 size_t i; 695 696 if (!dbus_type_is_basic(type)) { 697 dbus_set_error(error, DBUS_ERROR_FAILED, 698 "%s: given type is not basic", __func__); 699 return FALSE; 700 } 701 702 sub_type_str = wpa_dbus_type_as_string(type); 703 type_str[2] = sub_type_str[0]; 704 inner_type_str[1] = sub_type_str[0]; 705 706 if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, 707 type_str, &variant_iter) || 708 !dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY, 709 inner_type_str, &array_iter)) { 710 dbus_set_error(error, DBUS_ERROR_FAILED, 711 "%s: failed to construct message", __func__); 712 return FALSE; 713 } 714 715 for (i = 0; i < array_len && array[i]; i++) { 716 wpa_dbus_dict_bin_array_add_element(&array_iter, 717 wpabuf_head(array[i]), 718 wpabuf_len(array[i])); 719 720 } 721 722 if (!dbus_message_iter_close_container(&variant_iter, &array_iter) || 723 !dbus_message_iter_close_container(iter, &variant_iter)) { 724 dbus_set_error(error, DBUS_ERROR_FAILED, 725 "%s: failed to close message", __func__); 726 return FALSE; 727 } 728 729 return TRUE; 730 } 731 732 733 /** 734 * wpas_dbus_string_property_getter - Get string type property 735 * @iter: Message iter to use when appending arguments 736 * @val: Pointer to place holding property value, can be %NULL 737 * @error: On failure an error describing the failure 738 * Returns: TRUE if the request was successful, FALSE if it failed 739 * 740 * Generic getter for string type properties. %NULL is converted to an empty 741 * string. 742 */ 743 dbus_bool_t wpas_dbus_string_property_getter(DBusMessageIter *iter, 744 const void *val, 745 DBusError *error) 746 { 747 if (!val) 748 val = ""; 749 return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING, 750 &val, error); 751 } 752 753 754 /** 755 * wpas_dbus_handler_create_interface - Request registration of a network iface 756 * @message: Pointer to incoming dbus message 757 * @global: %wpa_supplicant global data structure 758 * Returns: The object path of the new interface object, 759 * or a dbus error message with more information 760 * 761 * Handler function for "CreateInterface" method call. Handles requests 762 * by dbus clients to register a network interface that wpa_supplicant 763 * will manage. 764 */ 765 DBusMessage * wpas_dbus_handler_create_interface(DBusMessage *message, 766 struct wpa_global *global) 767 { 768 DBusMessageIter iter_dict; 769 DBusMessage *reply = NULL; 770 DBusMessageIter iter; 771 struct wpa_dbus_dict_entry entry; 772 char *driver = NULL; 773 char *ifname = NULL; 774 char *confname = NULL; 775 char *bridge_ifname = NULL; 776 bool create_iface = false; 777 u8 *if_addr = NULL; 778 enum wpa_driver_if_type if_type = WPA_IF_STATION; 779 780 dbus_message_iter_init(message, &iter); 781 782 if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL)) 783 goto error; 784 while (wpa_dbus_dict_has_dict_entry(&iter_dict)) { 785 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) 786 goto error; 787 if (os_strcmp(entry.key, "Driver") == 0 && 788 entry.type == DBUS_TYPE_STRING) { 789 os_free(driver); 790 driver = os_strdup(entry.str_value); 791 wpa_dbus_dict_entry_clear(&entry); 792 if (driver == NULL) 793 goto oom; 794 } else if (os_strcmp(entry.key, "Ifname") == 0 && 795 entry.type == DBUS_TYPE_STRING) { 796 os_free(ifname); 797 ifname = os_strdup(entry.str_value); 798 wpa_dbus_dict_entry_clear(&entry); 799 if (ifname == NULL) 800 goto oom; 801 } else if (os_strcmp(entry.key, "ConfigFile") == 0 && 802 entry.type == DBUS_TYPE_STRING) { 803 os_free(confname); 804 confname = os_strdup(entry.str_value); 805 wpa_dbus_dict_entry_clear(&entry); 806 if (confname == NULL) 807 goto oom; 808 } else if (os_strcmp(entry.key, "BridgeIfname") == 0 && 809 entry.type == DBUS_TYPE_STRING) { 810 os_free(bridge_ifname); 811 bridge_ifname = os_strdup(entry.str_value); 812 wpa_dbus_dict_entry_clear(&entry); 813 if (bridge_ifname == NULL) 814 goto oom; 815 } else if (os_strcmp(entry.key, "Create") == 0 && 816 entry.type == DBUS_TYPE_BOOLEAN) { 817 create_iface = entry.bool_value; 818 wpa_dbus_dict_entry_clear(&entry); 819 } else if (os_strcmp(entry.key, "Type") == 0 && 820 entry.type == DBUS_TYPE_STRING) { 821 if (os_strcmp(entry.str_value, "sta") == 0) { 822 if_type = WPA_IF_STATION; 823 } else if (os_strcmp(entry.str_value, "ap") == 0) { 824 if_type = WPA_IF_AP_BSS; 825 } else { 826 wpa_dbus_dict_entry_clear(&entry); 827 goto error; 828 } 829 wpa_dbus_dict_entry_clear(&entry); 830 } else if (os_strcmp(entry.key, "Address") == 0 && 831 entry.type == DBUS_TYPE_STRING) { 832 if_addr = os_malloc(ETH_ALEN); 833 if (if_addr == NULL) { 834 wpa_dbus_dict_entry_clear(&entry); 835 goto oom; 836 } 837 if (hwaddr_aton(entry.str_value, if_addr)) { 838 wpa_dbus_dict_entry_clear(&entry); 839 goto error; 840 } 841 wpa_dbus_dict_entry_clear(&entry); 842 } else { 843 wpa_dbus_dict_entry_clear(&entry); 844 goto error; 845 } 846 } 847 848 if (ifname == NULL) 849 goto error; /* Required Ifname argument missing */ 850 851 /* 852 * Try to get the wpa_supplicant record for this iface, return 853 * an error if we already control it. 854 */ 855 if (wpa_supplicant_get_iface(global, ifname) != NULL) { 856 reply = dbus_message_new_error( 857 message, WPAS_DBUS_ERROR_IFACE_EXISTS, 858 "wpa_supplicant already controls this interface."); 859 } else { 860 struct wpa_supplicant *wpa_s; 861 struct wpa_interface iface; 862 863 if (create_iface) { 864 u8 mac_addr[ETH_ALEN]; 865 866 wpa_printf(MSG_DEBUG, 867 "%s[dbus]: creating an interface '%s'", 868 __func__, ifname); 869 if (!global->ifaces || 870 wpa_drv_if_add(global->ifaces, if_type, ifname, 871 if_addr, NULL, NULL, mac_addr, 872 NULL) < 0) { 873 reply = wpas_dbus_error_unknown_error( 874 message, 875 "interface creation failed."); 876 goto out; 877 } 878 } 879 880 os_memset(&iface, 0, sizeof(iface)); 881 iface.driver = driver; 882 iface.ifname = ifname; 883 iface.confname = confname; 884 iface.bridge_ifname = bridge_ifname; 885 /* Otherwise, have wpa_supplicant attach to it. */ 886 wpa_s = wpa_supplicant_add_iface(global, &iface, NULL); 887 if (wpa_s && wpa_s->dbus_new_path) { 888 const char *path = wpa_s->dbus_new_path; 889 890 wpa_s->added_vif = create_iface; 891 reply = dbus_message_new_method_return(message); 892 dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, 893 &path, DBUS_TYPE_INVALID); 894 } else { 895 reply = wpas_dbus_error_unknown_error( 896 message, 897 "wpa_supplicant couldn't grab this interface."); 898 if (create_iface) { 899 /* wpa_supplicant does not create multi-BSS AP, 900 * so collapse to WPA_IF_STATION to avoid 901 * unwanted clean up in the driver. */ 902 wpa_drv_if_remove(global->ifaces, 903 WPA_IF_STATION, ifname); 904 } 905 } 906 } 907 908 out: 909 os_free(driver); 910 os_free(ifname); 911 os_free(confname); 912 os_free(bridge_ifname); 913 os_free(if_addr); 914 return reply; 915 916 error: 917 reply = wpas_dbus_error_invalid_args(message, NULL); 918 goto out; 919 oom: 920 reply = wpas_dbus_error_no_memory(message); 921 goto out; 922 } 923 924 925 /** 926 * wpas_dbus_handler_remove_interface - Request deregistration of an interface 927 * @message: Pointer to incoming dbus message 928 * @global: wpa_supplicant global data structure 929 * Returns: a dbus message containing a UINT32 indicating success (1) or 930 * failure (0), or returns a dbus error message with more information 931 * 932 * Handler function for "removeInterface" method call. Handles requests 933 * by dbus clients to deregister a network interface that wpa_supplicant 934 * currently manages. 935 */ 936 DBusMessage * wpas_dbus_handler_remove_interface(DBusMessage *message, 937 struct wpa_global *global) 938 { 939 struct wpa_supplicant *wpa_s; 940 char *path; 941 DBusMessage *reply = NULL; 942 bool delete_iface; 943 944 dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &path, 945 DBUS_TYPE_INVALID); 946 947 wpa_s = get_iface_by_dbus_path(global, path); 948 if (!wpa_s) { 949 reply = wpas_dbus_error_iface_unknown(message); 950 goto out; 951 } 952 delete_iface = wpa_s->added_vif; 953 if (wpa_supplicant_remove_iface(global, wpa_s, 0)) { 954 reply = wpas_dbus_error_unknown_error( 955 message, 956 "wpa_supplicant couldn't remove this interface."); 957 goto out; 958 } 959 960 if (delete_iface) { 961 wpa_printf(MSG_DEBUG, "%s[dbus]: deleting the interface '%s'", 962 __func__, wpa_s->ifname); 963 /* wpa_supplicant does not create multi-BSS AP, so collapse to 964 * WPA_IF_STATION to avoid unwanted clean up in the driver. */ 965 if (wpa_drv_if_remove(global->ifaces, WPA_IF_STATION, 966 wpa_s->ifname)) { 967 reply = wpas_dbus_error_unknown_error( 968 message, 969 "wpa_supplicant couldn't delete this interface."); 970 } 971 } 972 973 out: 974 return reply; 975 } 976 977 978 /** 979 * wpas_dbus_handler_get_interface - Get the object path for an interface name 980 * @message: Pointer to incoming dbus message 981 * @global: %wpa_supplicant global data structure 982 * Returns: The object path of the interface object, 983 * or a dbus error message with more information 984 * 985 * Handler function for "getInterface" method call. 986 */ 987 DBusMessage * wpas_dbus_handler_get_interface(DBusMessage *message, 988 struct wpa_global *global) 989 { 990 DBusMessage *reply = NULL; 991 const char *ifname; 992 const char *path; 993 struct wpa_supplicant *wpa_s; 994 995 dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &ifname, 996 DBUS_TYPE_INVALID); 997 998 wpa_s = wpa_supplicant_get_iface(global, ifname); 999 if (wpa_s == NULL || wpa_s->dbus_new_path == NULL) 1000 return wpas_dbus_error_iface_unknown(message); 1001 1002 path = wpa_s->dbus_new_path; 1003 reply = dbus_message_new_method_return(message); 1004 if (reply == NULL) 1005 return wpas_dbus_error_no_memory(message); 1006 if (!dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &path, 1007 DBUS_TYPE_INVALID)) { 1008 dbus_message_unref(reply); 1009 return wpas_dbus_error_no_memory(message); 1010 } 1011 1012 return reply; 1013 } 1014 1015 1016 /** 1017 * wpas_dbus_getter_debug_level - Get debug level 1018 * @iter: Pointer to incoming dbus message iter 1019 * @error: Location to store error on failure 1020 * @user_data: Function specific data 1021 * Returns: TRUE on success, FALSE on failure 1022 * 1023 * Getter for "DebugLevel" property. 1024 */ 1025 dbus_bool_t wpas_dbus_getter_debug_level( 1026 const struct wpa_dbus_property_desc *property_desc, 1027 DBusMessageIter *iter, DBusError *error, void *user_data) 1028 { 1029 const char *str; 1030 int idx = wpa_debug_level; 1031 1032 if (idx < 0) 1033 idx = 0; 1034 if (idx > 5) 1035 idx = 5; 1036 str = debug_strings[idx]; 1037 return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING, 1038 &str, error); 1039 } 1040 1041 1042 /** 1043 * wpas_dbus_getter_debug_timestamp - Get debug timestamp 1044 * @iter: Pointer to incoming dbus message iter 1045 * @error: Location to store error on failure 1046 * @user_data: Function specific data 1047 * Returns: TRUE on success, FALSE on failure 1048 * 1049 * Getter for "DebugTimestamp" property. 1050 */ 1051 dbus_bool_t wpas_dbus_getter_debug_timestamp( 1052 const struct wpa_dbus_property_desc *property_desc, 1053 DBusMessageIter *iter, DBusError *error, void *user_data) 1054 { 1055 dbus_bool_t b = wpa_debug_timestamp ? TRUE : FALSE; 1056 1057 return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN, 1058 &b, error); 1059 1060 } 1061 1062 1063 /** 1064 * wpas_dbus_getter_debug_show_keys - Get debug show keys 1065 * @iter: Pointer to incoming dbus message iter 1066 * @error: Location to store error on failure 1067 * @user_data: Function specific data 1068 * Returns: TRUE on success, FALSE on failure 1069 * 1070 * Getter for "DebugShowKeys" property. 1071 */ 1072 dbus_bool_t wpas_dbus_getter_debug_show_keys( 1073 const struct wpa_dbus_property_desc *property_desc, 1074 DBusMessageIter *iter, DBusError *error, void *user_data) 1075 { 1076 dbus_bool_t b = wpa_debug_show_keys ? TRUE : FALSE; 1077 1078 return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN, 1079 &b, error); 1080 1081 } 1082 1083 /** 1084 * wpas_dbus_setter_debug_level - Set debug level 1085 * @iter: Pointer to incoming dbus message iter 1086 * @error: Location to store error on failure 1087 * @user_data: Function specific data 1088 * Returns: TRUE on success, FALSE on failure 1089 * 1090 * Setter for "DebugLevel" property. 1091 */ 1092 dbus_bool_t wpas_dbus_setter_debug_level( 1093 const struct wpa_dbus_property_desc *property_desc, 1094 DBusMessageIter *iter, DBusError *error, void *user_data) 1095 { 1096 struct wpa_global *global = user_data; 1097 const char *str = NULL; 1098 int i, val = -1; 1099 1100 if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_STRING, 1101 &str)) 1102 return FALSE; 1103 1104 for (i = 0; debug_strings[i]; i++) 1105 if (os_strcmp(debug_strings[i], str) == 0) { 1106 val = i; 1107 break; 1108 } 1109 1110 if (val < 0 || 1111 wpa_supplicant_set_debug_params(global, val, wpa_debug_timestamp, 1112 wpa_debug_show_keys)) { 1113 dbus_set_error_const(error, DBUS_ERROR_FAILED, 1114 "wrong debug level value"); 1115 return FALSE; 1116 } 1117 1118 return TRUE; 1119 } 1120 1121 1122 /** 1123 * wpas_dbus_setter_debug_timestamp - Set debug timestamp 1124 * @iter: Pointer to incoming dbus message iter 1125 * @error: Location to store error on failure 1126 * @user_data: Function specific data 1127 * Returns: TRUE on success, FALSE on failure 1128 * 1129 * Setter for "DebugTimestamp" property. 1130 */ 1131 dbus_bool_t wpas_dbus_setter_debug_timestamp( 1132 const struct wpa_dbus_property_desc *property_desc, 1133 DBusMessageIter *iter, DBusError *error, void *user_data) 1134 { 1135 struct wpa_global *global = user_data; 1136 dbus_bool_t val; 1137 1138 if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_BOOLEAN, 1139 &val)) 1140 return FALSE; 1141 1142 wpa_supplicant_set_debug_params(global, wpa_debug_level, val ? 1 : 0, 1143 wpa_debug_show_keys); 1144 return TRUE; 1145 } 1146 1147 1148 /** 1149 * wpas_dbus_setter_debug_show_keys - Set debug show keys 1150 * @iter: Pointer to incoming dbus message iter 1151 * @error: Location to store error on failure 1152 * @user_data: Function specific data 1153 * Returns: TRUE on success, FALSE on failure 1154 * 1155 * Setter for "DebugShowKeys" property. 1156 */ 1157 dbus_bool_t wpas_dbus_setter_debug_show_keys( 1158 const struct wpa_dbus_property_desc *property_desc, 1159 DBusMessageIter *iter, DBusError *error, void *user_data) 1160 { 1161 struct wpa_global *global = user_data; 1162 dbus_bool_t val; 1163 1164 if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_BOOLEAN, 1165 &val)) 1166 return FALSE; 1167 1168 wpa_supplicant_set_debug_params(global, wpa_debug_level, 1169 wpa_debug_timestamp, 1170 val ? 1 : 0); 1171 return TRUE; 1172 } 1173 1174 1175 /** 1176 * wpas_dbus_getter_interfaces - Request registered interfaces list 1177 * @iter: Pointer to incoming dbus message iter 1178 * @error: Location to store error on failure 1179 * @user_data: Function specific data 1180 * Returns: TRUE on success, FALSE on failure 1181 * 1182 * Getter for "Interfaces" property. Handles requests 1183 * by dbus clients to return list of registered interfaces objects 1184 * paths 1185 */ 1186 dbus_bool_t wpas_dbus_getter_interfaces( 1187 const struct wpa_dbus_property_desc *property_desc, 1188 DBusMessageIter *iter, DBusError *error, void *user_data) 1189 { 1190 struct wpa_global *global = user_data; 1191 struct wpa_supplicant *wpa_s; 1192 const char **paths; 1193 unsigned int i = 0, num = 0; 1194 dbus_bool_t success; 1195 1196 for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) { 1197 if (wpa_s->dbus_new_path) 1198 num++; 1199 } 1200 1201 paths = os_calloc(num, sizeof(char *)); 1202 if (!paths) { 1203 dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory"); 1204 return FALSE; 1205 } 1206 1207 for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) { 1208 if (wpa_s->dbus_new_path) 1209 paths[i++] = wpa_s->dbus_new_path; 1210 } 1211 1212 success = wpas_dbus_simple_array_property_getter(iter, 1213 DBUS_TYPE_OBJECT_PATH, 1214 paths, num, error); 1215 1216 os_free(paths); 1217 return success; 1218 } 1219 1220 1221 /** 1222 * wpas_dbus_getter_eap_methods - Request supported EAP methods list 1223 * @iter: Pointer to incoming dbus message iter 1224 * @error: Location to store error on failure 1225 * @user_data: Function specific data 1226 * Returns: TRUE on success, FALSE on failure 1227 * 1228 * Getter for "EapMethods" property. Handles requests 1229 * by dbus clients to return list of strings with supported EAP methods 1230 */ 1231 dbus_bool_t wpas_dbus_getter_eap_methods( 1232 const struct wpa_dbus_property_desc *property_desc, 1233 DBusMessageIter *iter, DBusError *error, void *user_data) 1234 { 1235 char **eap_methods; 1236 size_t num_items = 0; 1237 dbus_bool_t success; 1238 1239 eap_methods = eap_get_names_as_string_array(&num_items); 1240 if (!eap_methods) { 1241 dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory"); 1242 return FALSE; 1243 } 1244 1245 success = wpas_dbus_simple_array_property_getter(iter, 1246 DBUS_TYPE_STRING, 1247 eap_methods, 1248 num_items, error); 1249 1250 while (num_items) 1251 os_free(eap_methods[--num_items]); 1252 os_free(eap_methods); 1253 return success; 1254 } 1255 1256 1257 /** 1258 * wpas_dbus_getter_global_capabilities - Request supported global capabilities 1259 * @iter: Pointer to incoming dbus message iter 1260 * @error: Location to store error on failure 1261 * @user_data: Function specific data 1262 * Returns: TRUE on success, FALSE on failure 1263 * 1264 * Getter for "Capabilities" property. Handles requests by dbus clients to 1265 * return a list of strings with supported capabilities like AP, RSN IBSS, 1266 * and P2P that are determined at compile time. 1267 */ 1268 dbus_bool_t wpas_dbus_getter_global_capabilities( 1269 const struct wpa_dbus_property_desc *property_desc, 1270 DBusMessageIter *iter, DBusError *error, void *user_data) 1271 { 1272 const char *capabilities[14]; 1273 size_t num_items = 0; 1274 struct wpa_global *global = user_data; 1275 struct wpa_supplicant *wpa_s; 1276 #ifdef CONFIG_FILS 1277 int fils_supported = 0, fils_sk_pfs_supported = 0; 1278 #endif /* CONFIG_FILS */ 1279 int ext_key_id_supported = 0; 1280 1281 for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) { 1282 #ifdef CONFIG_FILS 1283 if (wpa_is_fils_supported(wpa_s)) 1284 fils_supported = 1; 1285 if (wpa_is_fils_sk_pfs_supported(wpa_s)) 1286 fils_sk_pfs_supported = 1; 1287 #endif /* CONFIG_FILS */ 1288 if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_EXTENDED_KEY_ID) 1289 ext_key_id_supported = 1; 1290 } 1291 1292 #ifdef CONFIG_AP 1293 capabilities[num_items++] = "ap"; 1294 #endif /* CONFIG_AP */ 1295 #ifdef CONFIG_IBSS_RSN 1296 capabilities[num_items++] = "ibss-rsn"; 1297 #endif /* CONFIG_IBSS_RSN */ 1298 #ifdef CONFIG_P2P 1299 capabilities[num_items++] = "p2p"; 1300 #endif /* CONFIG_P2P */ 1301 #ifdef CONFIG_INTERWORKING 1302 capabilities[num_items++] = "interworking"; 1303 #endif /* CONFIG_INTERWORKING */ 1304 capabilities[num_items++] = "pmf"; 1305 #ifdef CONFIG_MESH 1306 capabilities[num_items++] = "mesh"; 1307 #endif /* CONFIG_MESH */ 1308 #ifdef CONFIG_FILS 1309 if (fils_supported) 1310 capabilities[num_items++] = "fils"; 1311 if (fils_sk_pfs_supported) 1312 capabilities[num_items++] = "fils_sk_pfs"; 1313 #endif /* CONFIG_FILS */ 1314 #ifdef CONFIG_IEEE80211R 1315 capabilities[num_items++] = "ft"; 1316 #endif /* CONFIG_IEEE80211R */ 1317 #ifdef CONFIG_SHA384 1318 capabilities[num_items++] = "sha384"; 1319 #endif /* CONFIG_SHA384 */ 1320 #ifdef CONFIG_OWE 1321 capabilities[num_items++] = "owe"; 1322 #endif /* CONFIG_OWE */ 1323 #ifdef CONFIG_SUITEB192 1324 capabilities[num_items++] = "suiteb192"; 1325 #endif /* CONFIG_SUITEB192 */ 1326 if (ext_key_id_supported) 1327 capabilities[num_items++] = "extended_key_id"; 1328 #ifndef CONFIG_WEP 1329 capabilities[num_items++] = "wep_disabled"; 1330 #endif /* !CONFIG_WEP */ 1331 1332 return wpas_dbus_simple_array_property_getter(iter, 1333 DBUS_TYPE_STRING, 1334 capabilities, 1335 num_items, error); 1336 } 1337 1338 1339 static int wpas_dbus_get_scan_type(DBusMessage *message, DBusMessageIter *var, 1340 char **type, DBusMessage **reply) 1341 { 1342 if (dbus_message_iter_get_arg_type(var) != DBUS_TYPE_STRING) { 1343 wpa_printf(MSG_DEBUG, "%s[dbus]: Type must be a string", 1344 __func__); 1345 *reply = wpas_dbus_error_invalid_args( 1346 message, "Wrong Type value type. String required"); 1347 return -1; 1348 } 1349 dbus_message_iter_get_basic(var, type); 1350 return 0; 1351 } 1352 1353 1354 static int wpas_dbus_get_scan_ssids(DBusMessage *message, DBusMessageIter *var, 1355 struct wpa_driver_scan_params *params, 1356 DBusMessage **reply) 1357 { 1358 struct wpa_driver_scan_ssid *ssids = params->ssids; 1359 size_t ssids_num = 0; 1360 u8 *ssid; 1361 DBusMessageIter array_iter, sub_array_iter; 1362 char *val; 1363 int len; 1364 1365 if (dbus_message_iter_get_arg_type(var) != DBUS_TYPE_ARRAY) { 1366 wpa_printf(MSG_DEBUG, 1367 "%s[dbus]: ssids must be an array of arrays of bytes", 1368 __func__); 1369 *reply = wpas_dbus_error_invalid_args( 1370 message, 1371 "Wrong SSIDs value type. Array of arrays of bytes required"); 1372 return -1; 1373 } 1374 1375 dbus_message_iter_recurse(var, &array_iter); 1376 1377 if (dbus_message_iter_get_arg_type(&array_iter) != DBUS_TYPE_ARRAY || 1378 dbus_message_iter_get_element_type(&array_iter) != DBUS_TYPE_BYTE) { 1379 wpa_printf(MSG_DEBUG, 1380 "%s[dbus]: ssids must be an array of arrays of bytes", 1381 __func__); 1382 *reply = wpas_dbus_error_invalid_args( 1383 message, 1384 "Wrong SSIDs value type. Array of arrays of bytes required"); 1385 return -1; 1386 } 1387 1388 while (dbus_message_iter_get_arg_type(&array_iter) == DBUS_TYPE_ARRAY) { 1389 if (ssids_num >= WPAS_MAX_SCAN_SSIDS) { 1390 wpa_printf(MSG_DEBUG, 1391 "%s[dbus]: Too many ssids specified on scan dbus call", 1392 __func__); 1393 *reply = wpas_dbus_error_invalid_args( 1394 message, 1395 "Too many ssids specified. Specify at most four"); 1396 return -1; 1397 } 1398 1399 dbus_message_iter_recurse(&array_iter, &sub_array_iter); 1400 1401 dbus_message_iter_get_fixed_array(&sub_array_iter, &val, &len); 1402 1403 if (len > SSID_MAX_LEN) { 1404 wpa_printf(MSG_DEBUG, 1405 "%s[dbus]: SSID too long (len=%d max_len=%d)", 1406 __func__, len, SSID_MAX_LEN); 1407 *reply = wpas_dbus_error_invalid_args( 1408 message, "Invalid SSID: too long"); 1409 return -1; 1410 } 1411 1412 if (len != 0) { 1413 ssid = os_memdup(val, len); 1414 if (ssid == NULL) { 1415 *reply = wpas_dbus_error_no_memory(message); 1416 return -1; 1417 } 1418 } else { 1419 /* Allow zero-length SSIDs */ 1420 ssid = NULL; 1421 } 1422 1423 ssids[ssids_num].ssid = ssid; 1424 ssids[ssids_num].ssid_len = len; 1425 1426 dbus_message_iter_next(&array_iter); 1427 ssids_num++; 1428 } 1429 1430 params->num_ssids = ssids_num; 1431 return 0; 1432 } 1433 1434 1435 static int wpas_dbus_get_scan_ies(DBusMessage *message, DBusMessageIter *var, 1436 struct wpa_driver_scan_params *params, 1437 DBusMessage **reply) 1438 { 1439 u8 *ies = NULL, *nies; 1440 size_t ies_len = 0; 1441 DBusMessageIter array_iter, sub_array_iter; 1442 char *val; 1443 int len; 1444 1445 if (dbus_message_iter_get_arg_type(var) != DBUS_TYPE_ARRAY) { 1446 wpa_printf(MSG_DEBUG, 1447 "%s[dbus]: ies must be an array of arrays of bytes", 1448 __func__); 1449 *reply = wpas_dbus_error_invalid_args( 1450 message, 1451 "Wrong IEs value type. Array of arrays of bytes required"); 1452 return -1; 1453 } 1454 1455 dbus_message_iter_recurse(var, &array_iter); 1456 1457 if (dbus_message_iter_get_arg_type(&array_iter) != DBUS_TYPE_ARRAY || 1458 dbus_message_iter_get_element_type(&array_iter) != DBUS_TYPE_BYTE) { 1459 wpa_printf(MSG_DEBUG, 1460 "%s[dbus]: ies must be an array of arrays of bytes", 1461 __func__); 1462 *reply = wpas_dbus_error_invalid_args( 1463 message, "Wrong IEs value type. Array required"); 1464 return -1; 1465 } 1466 1467 while (dbus_message_iter_get_arg_type(&array_iter) == DBUS_TYPE_ARRAY) { 1468 dbus_message_iter_recurse(&array_iter, &sub_array_iter); 1469 1470 dbus_message_iter_get_fixed_array(&sub_array_iter, &val, &len); 1471 if (len <= 0) { 1472 dbus_message_iter_next(&array_iter); 1473 continue; 1474 } 1475 1476 nies = os_realloc(ies, ies_len + len); 1477 if (nies == NULL) { 1478 os_free(ies); 1479 *reply = wpas_dbus_error_no_memory(message); 1480 return -1; 1481 } 1482 ies = nies; 1483 os_memcpy(ies + ies_len, val, len); 1484 ies_len += len; 1485 1486 dbus_message_iter_next(&array_iter); 1487 } 1488 1489 params->extra_ies = ies; 1490 params->extra_ies_len = ies_len; 1491 return 0; 1492 } 1493 1494 1495 static int wpas_dbus_get_scan_channels(DBusMessage *message, 1496 DBusMessageIter *var, 1497 struct wpa_driver_scan_params *params, 1498 DBusMessage **reply) 1499 { 1500 DBusMessageIter array_iter, sub_array_iter; 1501 int *freqs = NULL, *nfreqs; 1502 size_t freqs_num = 0; 1503 1504 if (dbus_message_iter_get_arg_type(var) != DBUS_TYPE_ARRAY) { 1505 wpa_printf(MSG_DEBUG, 1506 "%s[dbus]: Channels must be an array of structs", 1507 __func__); 1508 *reply = wpas_dbus_error_invalid_args( 1509 message, 1510 "Wrong Channels value type. Array of structs required"); 1511 return -1; 1512 } 1513 1514 dbus_message_iter_recurse(var, &array_iter); 1515 1516 if (dbus_message_iter_get_arg_type(&array_iter) != DBUS_TYPE_STRUCT) { 1517 wpa_printf(MSG_DEBUG, 1518 "%s[dbus]: Channels must be an array of structs", 1519 __func__); 1520 *reply = wpas_dbus_error_invalid_args( 1521 message, 1522 "Wrong Channels value type. Array of structs required"); 1523 return -1; 1524 } 1525 1526 while (dbus_message_iter_get_arg_type(&array_iter) == DBUS_TYPE_STRUCT) 1527 { 1528 int freq, width; 1529 1530 dbus_message_iter_recurse(&array_iter, &sub_array_iter); 1531 1532 if (dbus_message_iter_get_arg_type(&sub_array_iter) != 1533 DBUS_TYPE_UINT32) { 1534 wpa_printf(MSG_DEBUG, 1535 "%s[dbus]: Channel must by specified by struct of two UINT32s %c", 1536 __func__, 1537 dbus_message_iter_get_arg_type( 1538 &sub_array_iter)); 1539 *reply = wpas_dbus_error_invalid_args( 1540 message, 1541 "Wrong Channel struct. Two UINT32s required"); 1542 os_free(freqs); 1543 return -1; 1544 } 1545 dbus_message_iter_get_basic(&sub_array_iter, &freq); 1546 1547 if (!dbus_message_iter_next(&sub_array_iter) || 1548 dbus_message_iter_get_arg_type(&sub_array_iter) != 1549 DBUS_TYPE_UINT32) { 1550 wpa_printf(MSG_DEBUG, 1551 "%s[dbus]: Channel must by specified by struct of two UINT32s", 1552 __func__); 1553 *reply = wpas_dbus_error_invalid_args( 1554 message, 1555 "Wrong Channel struct. Two UINT32s required"); 1556 os_free(freqs); 1557 return -1; 1558 } 1559 1560 dbus_message_iter_get_basic(&sub_array_iter, &width); 1561 1562 #define FREQS_ALLOC_CHUNK 32 1563 if (freqs_num % FREQS_ALLOC_CHUNK == 0) { 1564 nfreqs = os_realloc_array( 1565 freqs, freqs_num + FREQS_ALLOC_CHUNK, 1566 sizeof(int)); 1567 if (nfreqs == NULL) 1568 os_free(freqs); 1569 freqs = nfreqs; 1570 } 1571 if (freqs == NULL) { 1572 *reply = wpas_dbus_error_no_memory(message); 1573 return -1; 1574 } 1575 1576 freqs[freqs_num] = freq; 1577 1578 freqs_num++; 1579 dbus_message_iter_next(&array_iter); 1580 } 1581 1582 nfreqs = os_realloc_array(freqs, freqs_num + 1, sizeof(int)); 1583 if (nfreqs == NULL) 1584 os_free(freqs); 1585 freqs = nfreqs; 1586 if (freqs == NULL) { 1587 *reply = wpas_dbus_error_no_memory(message); 1588 return -1; 1589 } 1590 freqs[freqs_num] = 0; 1591 1592 params->freqs = freqs; 1593 return 0; 1594 } 1595 1596 1597 static int wpas_dbus_get_scan_boolean(DBusMessage *message, 1598 DBusMessageIter *var, 1599 dbus_bool_t *allow, 1600 DBusMessage **reply) 1601 { 1602 if (dbus_message_iter_get_arg_type(var) != DBUS_TYPE_BOOLEAN) { 1603 wpa_printf(MSG_DEBUG, "%s[dbus]: Type must be a boolean", 1604 __func__); 1605 *reply = wpas_dbus_error_invalid_args( 1606 message, "Wrong Type value type. Boolean required"); 1607 return -1; 1608 } 1609 dbus_message_iter_get_basic(var, allow); 1610 return 0; 1611 } 1612 1613 1614 /** 1615 * wpas_dbus_handler_scan - Request a wireless scan on an interface 1616 * @message: Pointer to incoming dbus message 1617 * @wpa_s: wpa_supplicant structure for a network interface 1618 * Returns: NULL indicating success or DBus error message on failure 1619 * 1620 * Handler function for "Scan" method call of a network device. Requests 1621 * that wpa_supplicant perform a wireless scan as soon as possible 1622 * on a particular wireless interface. 1623 */ 1624 DBusMessage * wpas_dbus_handler_scan(DBusMessage *message, 1625 struct wpa_supplicant *wpa_s) 1626 { 1627 DBusMessage *reply = NULL; 1628 DBusMessageIter iter, dict_iter, entry_iter, variant_iter; 1629 char *key = NULL, *type = NULL; 1630 struct wpa_driver_scan_params params; 1631 size_t i; 1632 dbus_bool_t allow_roam = TRUE; 1633 dbus_bool_t non_coloc_6ghz = FALSE; 1634 dbus_bool_t scan_6ghz_only = FALSE; 1635 bool custom_ies = false; 1636 1637 os_memset(¶ms, 0, sizeof(params)); 1638 1639 dbus_message_iter_init(message, &iter); 1640 1641 dbus_message_iter_recurse(&iter, &dict_iter); 1642 1643 while (dbus_message_iter_get_arg_type(&dict_iter) == 1644 DBUS_TYPE_DICT_ENTRY) { 1645 dbus_message_iter_recurse(&dict_iter, &entry_iter); 1646 dbus_message_iter_get_basic(&entry_iter, &key); 1647 dbus_message_iter_next(&entry_iter); 1648 dbus_message_iter_recurse(&entry_iter, &variant_iter); 1649 1650 if (os_strcmp(key, "Type") == 0) { 1651 if (wpas_dbus_get_scan_type(message, &variant_iter, 1652 &type, &reply) < 0) 1653 goto out; 1654 } else if (os_strcmp(key, "SSIDs") == 0) { 1655 if (wpas_dbus_get_scan_ssids(message, &variant_iter, 1656 ¶ms, &reply) < 0) 1657 goto out; 1658 } else if (os_strcmp(key, "IEs") == 0) { 1659 if (wpas_dbus_get_scan_ies(message, &variant_iter, 1660 ¶ms, &reply) < 0) 1661 goto out; 1662 custom_ies = true; 1663 } else if (os_strcmp(key, "Channels") == 0) { 1664 if (wpas_dbus_get_scan_channels(message, &variant_iter, 1665 ¶ms, &reply) < 0) 1666 goto out; 1667 } else if (os_strcmp(key, "AllowRoam") == 0) { 1668 if (wpas_dbus_get_scan_boolean(message, 1669 &variant_iter, 1670 &allow_roam, 1671 &reply) < 0) 1672 goto out; 1673 } else if (os_strcmp(key, "NonColoc6GHz") == 0) { 1674 if (wpas_dbus_get_scan_boolean(message, 1675 &variant_iter, 1676 &non_coloc_6ghz, 1677 &reply) < 0) 1678 goto out; 1679 } else if (os_strcmp(key, "6GHzOnly") == 0) { 1680 if (wpas_dbus_get_scan_boolean(message, 1681 &variant_iter, 1682 &scan_6ghz_only, 1683 &reply) < 0) 1684 goto out; 1685 } else { 1686 wpa_printf(MSG_DEBUG, "%s[dbus]: Unknown argument %s", 1687 __func__, key); 1688 reply = wpas_dbus_error_invalid_args(message, key); 1689 goto out; 1690 } 1691 1692 dbus_message_iter_next(&dict_iter); 1693 } 1694 1695 if (!type) { 1696 wpa_printf(MSG_DEBUG, "%s[dbus]: Scan type not specified", 1697 __func__); 1698 reply = wpas_dbus_error_invalid_args(message, key); 1699 goto out; 1700 } 1701 1702 if (non_coloc_6ghz) 1703 params.non_coloc_6ghz = 1; 1704 1705 if (scan_6ghz_only && !params.freqs) 1706 wpa_add_scan_freqs_list(wpa_s, HOSTAPD_MODE_IEEE80211A, ¶ms, 1707 true, false, false); 1708 1709 if (os_strcmp(type, "passive") == 0) { 1710 if (params.num_ssids || params.extra_ies_len) { 1711 wpa_printf(MSG_DEBUG, 1712 "%s[dbus]: SSIDs or IEs specified for passive scan.", 1713 __func__); 1714 reply = wpas_dbus_error_invalid_args( 1715 message, 1716 "You can specify only Channels in passive scan"); 1717 goto out; 1718 } else { 1719 if (wpa_s->sched_scanning) { 1720 wpa_printf(MSG_DEBUG, 1721 "%s[dbus]: Stop ongoing sched_scan to allow requested scan to proceed", 1722 __func__); 1723 wpa_supplicant_cancel_sched_scan(wpa_s); 1724 } 1725 1726 if (params.freqs && params.freqs[0]) { 1727 wpa_s->last_scan_req = MANUAL_SCAN_REQ; 1728 if (wpa_supplicant_trigger_scan(wpa_s, 1729 ¶ms, 1730 false, false)) { 1731 reply = wpas_dbus_error_scan_error( 1732 message, 1733 "Scan request rejected"); 1734 goto out; 1735 } 1736 } else { 1737 wpa_s->scan_req = MANUAL_SCAN_REQ; 1738 wpa_supplicant_req_scan(wpa_s, 0, 0); 1739 } 1740 } 1741 } else if (os_strcmp(type, "active") == 0) { 1742 if (!params.num_ssids) { 1743 /* Add wildcard ssid */ 1744 params.num_ssids++; 1745 } 1746 #ifdef CONFIG_AUTOSCAN 1747 autoscan_deinit(wpa_s); 1748 #endif /* CONFIG_AUTOSCAN */ 1749 if (wpa_s->sched_scanning) { 1750 wpa_printf(MSG_DEBUG, 1751 "%s[dbus]: Stop ongoing sched_scan to allow requested scan to proceed", 1752 __func__); 1753 wpa_supplicant_cancel_sched_scan(wpa_s); 1754 } 1755 1756 wpa_s->last_scan_req = MANUAL_SCAN_REQ; 1757 if (wpa_supplicant_trigger_scan(wpa_s, ¶ms, !custom_ies, 1758 false)) { 1759 reply = wpas_dbus_error_scan_error( 1760 message, "Scan request rejected"); 1761 goto out; 1762 } 1763 } else { 1764 wpa_printf(MSG_DEBUG, "%s[dbus]: Unknown scan type: %s", 1765 __func__, type); 1766 reply = wpas_dbus_error_invalid_args(message, 1767 "Wrong scan type"); 1768 goto out; 1769 } 1770 1771 if (!allow_roam) 1772 wpa_s->scan_res_handler = scan_only_handler; 1773 1774 out: 1775 for (i = 0; i < WPAS_MAX_SCAN_SSIDS; i++) 1776 os_free((u8 *) params.ssids[i].ssid); 1777 os_free((u8 *) params.extra_ies); 1778 os_free(params.freqs); 1779 return reply; 1780 } 1781 1782 1783 /* 1784 * wpas_dbus_handler_abort_scan - Request an ongoing scan to be aborted 1785 * @message: Pointer to incoming dbus message 1786 * @wpa_s: wpa_supplicant structure for a network interface 1787 * Returns: Abort failed or no scan in progress DBus error message on failure 1788 * or NULL otherwise. 1789 * 1790 * Handler function for "AbortScan" method call of network interface. 1791 */ 1792 DBusMessage * wpas_dbus_handler_abort_scan(DBusMessage *message, 1793 struct wpa_supplicant *wpa_s) 1794 { 1795 if (wpas_abort_ongoing_scan(wpa_s) < 0) 1796 return dbus_message_new_error( 1797 message, WPAS_DBUS_ERROR_IFACE_SCAN_ERROR, 1798 "Abort failed or no scan in progress"); 1799 1800 return NULL; 1801 } 1802 1803 1804 /** 1805 * wpas_dbus_new_iface_add_cred - Add a new credential 1806 * @message: Pointer to incoming dbus message 1807 * @wpa_s: wpa_supplicant structure for a network interface 1808 * Returns: A dbus message containing the object path of the new credential 1809 * 1810 * Handler function for "AddCred" method call of a network interface. 1811 */ 1812 DBusMessage * wpas_dbus_handler_add_cred(DBusMessage *message, 1813 struct wpa_supplicant *wpa_s) 1814 { 1815 DBusMessage *reply = NULL; 1816 DBusMessageIter iter; 1817 struct wpa_cred *cred = NULL; 1818 char path_buf[WPAS_DBUS_OBJECT_PATH_MAX], *path = path_buf; 1819 DBusError error; 1820 1821 dbus_message_iter_init(message, &iter); 1822 1823 if (wpa_s->dbus_new_path) 1824 cred = wpa_config_add_cred(wpa_s->conf); 1825 if (!cred) { 1826 wpa_printf(MSG_ERROR, "%s[dbus]: can't add new credential.", 1827 __func__); 1828 reply = wpas_dbus_error_unknown_error( 1829 message, 1830 "wpa_supplicant could not add a credential on this interface."); 1831 goto err; 1832 } 1833 1834 dbus_error_init(&error); 1835 if (!set_cred_properties(wpa_s, cred, &iter, &error)) { 1836 wpa_printf(MSG_DEBUG, 1837 "%s[dbus]: control interface couldn't set credential properties", 1838 __func__); 1839 reply = wpas_dbus_reply_new_from_error(message, &error, 1840 DBUS_ERROR_INVALID_ARGS, 1841 "Failed to add credential"); 1842 dbus_error_free(&error); 1843 goto err; 1844 } 1845 1846 /* Construct the object path for this network. */ 1847 os_snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX, 1848 "%s/" WPAS_DBUS_NEW_CREDENTIALS_PART "/%d", 1849 wpa_s->dbus_new_path, cred->id); 1850 1851 reply = dbus_message_new_method_return(message); 1852 if (!reply) { 1853 reply = wpas_dbus_error_no_memory(message); 1854 goto err; 1855 } 1856 if (!dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &path, 1857 DBUS_TYPE_INVALID)) { 1858 dbus_message_unref(reply); 1859 reply = wpas_dbus_error_no_memory(message); 1860 goto err; 1861 } 1862 1863 return reply; 1864 1865 err: 1866 if (cred) 1867 wpa_config_remove_cred(wpa_s->conf, cred->id); 1868 return reply; 1869 } 1870 1871 1872 /** 1873 * wpas_dbus_handler_remove_cred - Remove a configured credential 1874 * @message: Pointer to incoming dbus message 1875 * @wpa_s: wpa_supplicant structure for a network interface 1876 * Returns: NULL on success or dbus error on failure 1877 * 1878 * Handler function for "RemoveCred" method call of a network interface. 1879 */ 1880 DBusMessage * wpas_dbus_handler_remove_cred(DBusMessage *message, 1881 struct wpa_supplicant *wpa_s) 1882 { 1883 DBusMessage *reply = NULL; 1884 const char *op; 1885 char *iface, *cred_id; 1886 int id; 1887 struct wpa_cred *cred; 1888 1889 dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &op, 1890 DBUS_TYPE_INVALID); 1891 1892 /* Extract the network ID and ensure the network is actually a child of 1893 * this interface */ 1894 iface = wpas_dbus_new_decompose_object_path( 1895 op, WPAS_DBUS_NEW_CREDENTIALS_PART, &cred_id); 1896 if (!iface || !cred_id || !wpa_s->dbus_new_path || 1897 os_strcmp(iface, wpa_s->dbus_new_path) != 0) { 1898 reply = wpas_dbus_error_invalid_args(message, op); 1899 goto out; 1900 } 1901 1902 errno = 0; 1903 id = strtoul(cred_id, NULL, 10); 1904 if (errno != 0) { 1905 reply = wpas_dbus_error_invalid_args(message, op); 1906 goto out; 1907 } 1908 1909 cred = wpa_config_get_cred(wpa_s->conf, id); 1910 if (!cred) { 1911 wpa_printf(MSG_ERROR, "%s[dbus]: could not find credential %s", 1912 __func__, op); 1913 reply = wpas_dbus_error_invalid_args( 1914 message, "could not find credential"); 1915 goto out; 1916 } 1917 1918 if (wpas_remove_cred(wpa_s, cred) < 0) { 1919 wpa_printf(MSG_ERROR, 1920 "%s[dbus]: error occurred when removing cred %d", 1921 __func__, id); 1922 reply = wpas_dbus_error_unknown_error( 1923 message, 1924 "error removing the specified credential on its interface."); 1925 goto out; 1926 } 1927 1928 out: 1929 os_free(iface); 1930 return reply; 1931 } 1932 1933 1934 /** 1935 * wpas_dbus_handler_remove_all_creds - Remove all the configured credentials 1936 * @message: Pointer to incoming dbus message 1937 * @wpa_s: wpa_supplicant structure for a network interface 1938 * Returns: NULL indicating success or DBus error message on failure 1939 * 1940 * Handler function for "RemoveAllCreds" method call of a network interface. 1941 */ 1942 DBusMessage * wpas_dbus_handler_remove_all_creds(DBusMessage *message, 1943 struct wpa_supplicant *wpa_s) 1944 { 1945 int res; 1946 DBusMessage *reply = NULL; 1947 1948 res = wpas_remove_all_creds(wpa_s); 1949 if (res < 0) { 1950 wpa_printf(MSG_ERROR, 1951 "%s[dbus]: failed to remove all credentials", 1952 __func__); 1953 reply = wpas_dbus_error_unknown_error( 1954 message, "failed to remove all credentials"); 1955 } 1956 1957 return reply; 1958 } 1959 1960 1961 #ifdef CONFIG_INTERWORKING 1962 1963 DBusMessage * 1964 wpas_dbus_handler_interworking_select(DBusMessage *message, 1965 struct wpa_supplicant *wpa_s) 1966 { 1967 int result; 1968 DBusMessage *reply = NULL; 1969 1970 /* Automatic selection is disabled and no constraint on channels */ 1971 result = interworking_select(wpa_s, 0, NULL); 1972 if (result < 0) { 1973 wpa_printf(MSG_ERROR, 1974 "%s[dbus]: failed to start Interworking selection", 1975 __func__); 1976 reply = wpas_dbus_error_scan_error( 1977 message, 1978 "error starting Interworking selection."); 1979 } 1980 1981 return reply; 1982 } 1983 1984 1985 DBusMessage * 1986 wpas_dbus_handler_anqp_get(DBusMessage *message, struct wpa_supplicant *wpa_s) 1987 { 1988 DBusMessageIter iter, iter_dict; 1989 struct wpa_dbus_dict_entry entry; 1990 int ret; 1991 u8 dst_addr[ETH_ALEN]; 1992 bool is_addr_present = false; 1993 unsigned int freq = 0; 1994 #define MAX_ANQP_INFO_ID 100 /* Max info ID count from CLI implementation */ 1995 u16 id[MAX_ANQP_INFO_ID]; 1996 size_t num_id = 0; 1997 u32 subtypes = 0; 1998 u32 mbo_subtypes = 0; 1999 size_t i; 2000 2001 dbus_message_iter_init(message, &iter); 2002 2003 if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL)) 2004 return wpas_dbus_error_invalid_args(message, NULL); 2005 2006 while (wpa_dbus_dict_has_dict_entry(&iter_dict)) { 2007 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) 2008 return wpas_dbus_error_invalid_args(message, NULL); 2009 2010 if (os_strcmp(entry.key, "addr") == 0 && 2011 entry.type == DBUS_TYPE_STRING) { 2012 if (hwaddr_aton(entry.str_value, dst_addr)) { 2013 wpa_printf(MSG_DEBUG, 2014 "%s[dbus]: Invalid address '%s'", 2015 __func__, entry.str_value); 2016 wpa_dbus_dict_entry_clear(&entry); 2017 return wpas_dbus_error_invalid_args( 2018 message, "invalid address"); 2019 } 2020 2021 is_addr_present = true; 2022 } else if (os_strcmp(entry.key, "freq") == 0 && 2023 entry.type == DBUS_TYPE_UINT32) { 2024 freq = entry.uint32_value; 2025 } else if (os_strcmp(entry.key, "ids") == 0 && 2026 entry.type == DBUS_TYPE_ARRAY && 2027 entry.array_type == DBUS_TYPE_UINT16) { 2028 for (i = 0; i < entry.array_len && 2029 num_id < MAX_ANQP_INFO_ID; i++) { 2030 id[num_id] = entry.uint16array_value[i]; 2031 num_id++; 2032 } 2033 } else if (os_strcmp(entry.key, "hs20_ids") == 0 && 2034 entry.type == DBUS_TYPE_ARRAY && 2035 entry.array_type == DBUS_TYPE_BYTE) { 2036 for (i = 0; i < entry.array_len; i++) { 2037 int num = entry.bytearray_value[i]; 2038 2039 if (num <= 0 || num > 31) { 2040 wpa_dbus_dict_entry_clear(&entry); 2041 return wpas_dbus_error_invalid_args( 2042 message, 2043 "invalid HS20 ANQP id"); 2044 } 2045 subtypes |= BIT(num); 2046 } 2047 } else if (os_strcmp(entry.key, "mbo_ids") == 0 && 2048 entry.type == DBUS_TYPE_ARRAY && 2049 entry.array_type == DBUS_TYPE_BYTE) { 2050 for (i = 0; i < entry.array_len; i++) { 2051 int num = entry.bytearray_value[i]; 2052 2053 if (num <= 0 || num > MAX_MBO_ANQP_SUBTYPE) { 2054 wpa_dbus_dict_entry_clear(&entry); 2055 return wpas_dbus_error_invalid_args( 2056 message, "invalid MBO ANQP id"); 2057 } 2058 mbo_subtypes |= BIT(num); 2059 } 2060 } else { 2061 wpa_dbus_dict_entry_clear(&entry); 2062 return wpas_dbus_error_invalid_args( 2063 message, "unsupported parameter"); 2064 } 2065 2066 wpa_dbus_dict_entry_clear(&entry); 2067 } 2068 2069 if (!is_addr_present) { 2070 wpa_printf(MSG_DEBUG, 2071 "%s[dbus]: address not provided", __func__); 2072 return wpas_dbus_error_invalid_args(message, 2073 "address not provided"); 2074 } 2075 2076 ret = anqp_send_req(wpa_s, dst_addr, freq, id, num_id, subtypes, 2077 mbo_subtypes); 2078 if (ret < 0) { 2079 wpa_printf(MSG_ERROR, "%s[dbus]: failed to send ANQP request", 2080 __func__); 2081 return wpas_dbus_error_unknown_error( 2082 message, "error sending ANQP request"); 2083 } 2084 2085 return NULL; 2086 } 2087 2088 #endif /* CONFIG_INTERWORKING */ 2089 2090 2091 /** 2092 * wpas_dbus_handler_signal_poll - Request immediate signal properties 2093 * @message: Pointer to incoming dbus message 2094 * @wpa_s: wpa_supplicant structure for a network interface 2095 * Returns: NULL indicating success or DBus error message on failure 2096 * 2097 * Handler function for "SignalPoll" method call of a network device. Requests 2098 * that wpa_supplicant read signal properties like RSSI, noise, and link 2099 * speed and return them. 2100 */ 2101 DBusMessage * wpas_dbus_handler_signal_poll(DBusMessage *message, 2102 struct wpa_supplicant *wpa_s) 2103 { 2104 struct wpa_signal_info si; 2105 DBusMessage *reply = NULL; 2106 DBusMessageIter iter; 2107 int ret; 2108 2109 ret = wpa_drv_signal_poll(wpa_s, &si); 2110 if (ret) { 2111 return dbus_message_new_error(message, DBUS_ERROR_FAILED, 2112 "Failed to read signal"); 2113 } 2114 2115 reply = dbus_message_new_method_return(message); 2116 if (reply == NULL) 2117 goto nomem; 2118 2119 dbus_message_iter_init_append(reply, &iter); 2120 2121 if (wpas_dbus_new_from_signal_information(&iter, &si) != 0) 2122 goto nomem; 2123 2124 return reply; 2125 2126 nomem: 2127 if (reply) 2128 dbus_message_unref(reply); 2129 return wpas_dbus_error_no_memory(message); 2130 } 2131 2132 2133 /* 2134 * wpas_dbus_handler_disconnect - Terminate the current connection 2135 * @message: Pointer to incoming dbus message 2136 * @wpa_s: wpa_supplicant structure for a network interface 2137 * Returns: NotConnected DBus error message if already not connected 2138 * or NULL otherwise. 2139 * 2140 * Handler function for "Disconnect" method call of network interface. 2141 */ 2142 DBusMessage * wpas_dbus_handler_disconnect(DBusMessage *message, 2143 struct wpa_supplicant *wpa_s) 2144 { 2145 if (wpa_s->current_ssid != NULL) { 2146 wpas_request_disconnection(wpa_s); 2147 return NULL; 2148 } 2149 2150 return dbus_message_new_error(message, WPAS_DBUS_ERROR_NOT_CONNECTED, 2151 "This interface is not connected"); 2152 } 2153 2154 2155 /** 2156 * wpas_dbus_new_iface_add_network - Add a new configured network 2157 * @message: Pointer to incoming dbus message 2158 * @wpa_s: wpa_supplicant structure for a network interface 2159 * Returns: A dbus message containing the object path of the new network 2160 * 2161 * Handler function for "AddNetwork" method call of a network interface. 2162 */ 2163 DBusMessage * wpas_dbus_handler_add_network(DBusMessage *message, 2164 struct wpa_supplicant *wpa_s) 2165 { 2166 DBusMessage *reply = NULL; 2167 DBusMessageIter iter; 2168 struct wpa_ssid *ssid = NULL; 2169 char path_buf[WPAS_DBUS_OBJECT_PATH_MAX], *path = path_buf; 2170 DBusError error; 2171 2172 dbus_message_iter_init(message, &iter); 2173 2174 if (wpa_s->dbus_new_path) 2175 ssid = wpa_supplicant_add_network(wpa_s); 2176 if (ssid == NULL) { 2177 wpa_printf(MSG_ERROR, "%s[dbus]: can't add new interface.", 2178 __func__); 2179 reply = wpas_dbus_error_unknown_error( 2180 message, 2181 "wpa_supplicant could not add a network on this interface."); 2182 goto err; 2183 } 2184 2185 dbus_error_init(&error); 2186 if (!set_network_properties(wpa_s, ssid, &iter, &error)) { 2187 wpa_printf(MSG_DEBUG, 2188 "%s[dbus]: control interface couldn't set network properties", 2189 __func__); 2190 reply = wpas_dbus_reply_new_from_error(message, &error, 2191 DBUS_ERROR_INVALID_ARGS, 2192 "Failed to add network"); 2193 dbus_error_free(&error); 2194 goto err; 2195 } 2196 2197 /* Construct the object path for this network. */ 2198 os_snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX, 2199 "%s/" WPAS_DBUS_NEW_NETWORKS_PART "/%d", 2200 wpa_s->dbus_new_path, ssid->id); 2201 2202 reply = dbus_message_new_method_return(message); 2203 if (reply == NULL) { 2204 reply = wpas_dbus_error_no_memory(message); 2205 goto err; 2206 } 2207 if (!dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &path, 2208 DBUS_TYPE_INVALID)) { 2209 dbus_message_unref(reply); 2210 reply = wpas_dbus_error_no_memory(message); 2211 goto err; 2212 } 2213 2214 return reply; 2215 2216 err: 2217 if (ssid) { 2218 wpas_notify_network_removed(wpa_s, ssid); 2219 wpa_config_remove_network(wpa_s->conf, ssid->id); 2220 } 2221 return reply; 2222 } 2223 2224 2225 /** 2226 * wpas_dbus_handler_reassociate - Reassociate 2227 * @message: Pointer to incoming dbus message 2228 * @wpa_s: wpa_supplicant structure for a network interface 2229 * Returns: InterfaceDisabled DBus error message if disabled 2230 * or NULL otherwise. 2231 * 2232 * Handler function for "Reassociate" method call of network interface. 2233 */ 2234 DBusMessage * wpas_dbus_handler_reassociate(DBusMessage *message, 2235 struct wpa_supplicant *wpa_s) 2236 { 2237 if (wpa_s->wpa_state != WPA_INTERFACE_DISABLED) { 2238 wpas_request_connection(wpa_s); 2239 return NULL; 2240 } 2241 2242 return dbus_message_new_error(message, WPAS_DBUS_ERROR_IFACE_DISABLED, 2243 "This interface is disabled"); 2244 } 2245 2246 2247 /** 2248 * wpas_dbus_handler_expect_disconnect - ExpectDisconnect 2249 * @message: Pointer to incoming dbus message 2250 * @global: %wpa_supplicant global data structure 2251 * Returns: NULL 2252 * 2253 * Handler function for notifying system there will be a expected disconnect. 2254 * This will prevent wpa_supplicant from adding the BSSID to the ignore list 2255 * upon next disconnect. 2256 */ 2257 DBusMessage * wpas_dbus_handler_expect_disconnect(DBusMessage *message, 2258 struct wpa_global *global) 2259 { 2260 struct wpa_supplicant *wpa_s = global->ifaces; 2261 2262 for (; wpa_s; wpa_s = wpa_s->next) 2263 if (wpa_s->wpa_state >= WPA_ASSOCIATED) 2264 wpa_s->own_disconnect_req = 1; 2265 return NULL; 2266 } 2267 2268 2269 /** 2270 * wpas_dbus_handler_reattach - Reattach to current AP 2271 * @message: Pointer to incoming dbus message 2272 * @wpa_s: wpa_supplicant structure for a network interface 2273 * Returns: NotConnected DBus error message if not connected 2274 * or NULL otherwise. 2275 * 2276 * Handler function for "Reattach" method call of network interface. 2277 */ 2278 DBusMessage * wpas_dbus_handler_reattach(DBusMessage *message, 2279 struct wpa_supplicant *wpa_s) 2280 { 2281 if (wpa_s->current_ssid != NULL) { 2282 wpa_s->reattach = 1; 2283 wpas_request_connection(wpa_s); 2284 return NULL; 2285 } 2286 2287 return dbus_message_new_error(message, WPAS_DBUS_ERROR_NOT_CONNECTED, 2288 "This interface is not connected"); 2289 } 2290 2291 2292 /** 2293 * wpas_dbus_handler_reconnect - Reconnect if disconnected 2294 * @message: Pointer to incoming dbus message 2295 * @wpa_s: wpa_supplicant structure for a network interface 2296 * Returns: InterfaceDisabled DBus error message if disabled 2297 * or NULL otherwise. 2298 * 2299 * Handler function for "Reconnect" method call of network interface. 2300 */ 2301 DBusMessage * wpas_dbus_handler_reconnect(DBusMessage *message, 2302 struct wpa_supplicant *wpa_s) 2303 { 2304 if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) { 2305 return dbus_message_new_error(message, 2306 WPAS_DBUS_ERROR_IFACE_DISABLED, 2307 "This interface is disabled"); 2308 } 2309 2310 if (wpa_s->disconnected) 2311 wpas_request_connection(wpa_s); 2312 return NULL; 2313 } 2314 2315 2316 /** 2317 * wpas_dbus_handler_remove_network - Remove a configured network 2318 * @message: Pointer to incoming dbus message 2319 * @wpa_s: wpa_supplicant structure for a network interface 2320 * Returns: NULL on success or dbus error on failure 2321 * 2322 * Handler function for "RemoveNetwork" method call of a network interface. 2323 */ 2324 DBusMessage * wpas_dbus_handler_remove_network(DBusMessage *message, 2325 struct wpa_supplicant *wpa_s) 2326 { 2327 DBusMessage *reply = NULL; 2328 const char *op; 2329 char *iface, *net_id; 2330 int id; 2331 int result; 2332 2333 dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &op, 2334 DBUS_TYPE_INVALID); 2335 2336 /* Extract the network ID and ensure the network */ 2337 /* is actually a child of this interface */ 2338 iface = wpas_dbus_new_decompose_object_path(op, 2339 WPAS_DBUS_NEW_NETWORKS_PART, 2340 &net_id); 2341 if (iface == NULL || net_id == NULL || !wpa_s->dbus_new_path || 2342 os_strcmp(iface, wpa_s->dbus_new_path) != 0) { 2343 reply = wpas_dbus_error_invalid_args(message, op); 2344 goto out; 2345 } 2346 2347 errno = 0; 2348 id = strtoul(net_id, NULL, 10); 2349 if (errno != 0) { 2350 reply = wpas_dbus_error_invalid_args(message, op); 2351 goto out; 2352 } 2353 2354 result = wpa_supplicant_remove_network(wpa_s, id); 2355 if (result == -1) { 2356 reply = wpas_dbus_error_network_unknown(message); 2357 goto out; 2358 } 2359 if (result == -2) { 2360 wpa_printf(MSG_ERROR, 2361 "%s[dbus]: error occurred when removing network %d", 2362 __func__, id); 2363 reply = wpas_dbus_error_unknown_error( 2364 message, 2365 "error removing the specified network on is interface."); 2366 goto out; 2367 } 2368 2369 out: 2370 os_free(iface); 2371 return reply; 2372 } 2373 2374 2375 /** 2376 * wpas_dbus_handler_remove_all_networks - Remove all configured networks 2377 * @message: Pointer to incoming dbus message 2378 * @wpa_s: wpa_supplicant structure for a network interface 2379 * Returns: NULL on success or dbus error on failure 2380 * 2381 * Handler function for "RemoveAllNetworks" method call of a network interface. 2382 */ 2383 DBusMessage * wpas_dbus_handler_remove_all_networks( 2384 DBusMessage *message, struct wpa_supplicant *wpa_s) 2385 { 2386 /* NB: could check for failure and return an error */ 2387 wpa_supplicant_remove_all_networks(wpa_s); 2388 return NULL; 2389 } 2390 2391 2392 /** 2393 * wpas_dbus_handler_select_network - Attempt association with a network 2394 * @message: Pointer to incoming dbus message 2395 * @wpa_s: wpa_supplicant structure for a network interface 2396 * Returns: NULL on success or dbus error on failure 2397 * 2398 * Handler function for "SelectNetwork" method call of network interface. 2399 */ 2400 DBusMessage * wpas_dbus_handler_select_network(DBusMessage *message, 2401 struct wpa_supplicant *wpa_s) 2402 { 2403 DBusMessage *reply = NULL; 2404 const char *op; 2405 char *iface, *net_id; 2406 int id; 2407 struct wpa_ssid *ssid; 2408 2409 dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &op, 2410 DBUS_TYPE_INVALID); 2411 2412 /* Extract the network ID and ensure the network */ 2413 /* is actually a child of this interface */ 2414 iface = wpas_dbus_new_decompose_object_path(op, 2415 WPAS_DBUS_NEW_NETWORKS_PART, 2416 &net_id); 2417 if (iface == NULL || net_id == NULL || !wpa_s->dbus_new_path || 2418 os_strcmp(iface, wpa_s->dbus_new_path) != 0) { 2419 reply = wpas_dbus_error_invalid_args(message, op); 2420 goto out; 2421 } 2422 2423 errno = 0; 2424 id = strtoul(net_id, NULL, 10); 2425 if (errno != 0) { 2426 reply = wpas_dbus_error_invalid_args(message, op); 2427 goto out; 2428 } 2429 2430 ssid = wpa_config_get_network(wpa_s->conf, id); 2431 if (ssid == NULL) { 2432 reply = wpas_dbus_error_network_unknown(message); 2433 goto out; 2434 } 2435 2436 /* Finally, associate with the network */ 2437 wpa_supplicant_select_network(wpa_s, ssid); 2438 2439 out: 2440 os_free(iface); 2441 return reply; 2442 } 2443 2444 2445 /** 2446 * wpas_dbus_handler_network_reply - Reply to a NetworkRequest signal 2447 * @message: Pointer to incoming dbus message 2448 * @wpa_s: wpa_supplicant structure for a network interface 2449 * Returns: NULL on success or dbus error on failure 2450 * 2451 * Handler function for "NetworkReply" method call of network interface. 2452 */ 2453 DBusMessage * wpas_dbus_handler_network_reply(DBusMessage *message, 2454 struct wpa_supplicant *wpa_s) 2455 { 2456 #ifdef IEEE8021X_EAPOL 2457 DBusMessage *reply = NULL; 2458 const char *op, *field, *value; 2459 char *iface, *net_id; 2460 int id; 2461 struct wpa_ssid *ssid; 2462 2463 if (!dbus_message_get_args(message, NULL, 2464 DBUS_TYPE_OBJECT_PATH, &op, 2465 DBUS_TYPE_STRING, &field, 2466 DBUS_TYPE_STRING, &value, 2467 DBUS_TYPE_INVALID)) 2468 return wpas_dbus_error_invalid_args(message, NULL); 2469 2470 /* Extract the network ID and ensure the network */ 2471 /* is actually a child of this interface */ 2472 iface = wpas_dbus_new_decompose_object_path(op, 2473 WPAS_DBUS_NEW_NETWORKS_PART, 2474 &net_id); 2475 if (iface == NULL || net_id == NULL || !wpa_s->dbus_new_path || 2476 os_strcmp(iface, wpa_s->dbus_new_path) != 0) { 2477 reply = wpas_dbus_error_invalid_args(message, op); 2478 goto out; 2479 } 2480 2481 errno = 0; 2482 id = strtoul(net_id, NULL, 10); 2483 if (errno != 0) { 2484 reply = wpas_dbus_error_invalid_args(message, net_id); 2485 goto out; 2486 } 2487 2488 ssid = wpa_config_get_network(wpa_s->conf, id); 2489 if (ssid == NULL) { 2490 reply = wpas_dbus_error_network_unknown(message); 2491 goto out; 2492 } 2493 2494 if (wpa_supplicant_ctrl_iface_ctrl_rsp_handle(wpa_s, ssid, 2495 field, value) < 0) 2496 reply = wpas_dbus_error_invalid_args(message, field); 2497 else { 2498 /* Tell EAP to retry immediately */ 2499 eapol_sm_notify_ctrl_response(wpa_s->eapol); 2500 } 2501 2502 out: 2503 os_free(iface); 2504 return reply; 2505 #else /* IEEE8021X_EAPOL */ 2506 wpa_printf(MSG_DEBUG, "dbus: 802.1X not included"); 2507 return wpas_dbus_error_unknown_error(message, "802.1X not included"); 2508 #endif /* IEEE8021X_EAPOL */ 2509 } 2510 2511 2512 /** 2513 * wpas_dbus_handler_roam - Initiate a roam to another BSS within the ESS 2514 * @message: Pointer to incoming dbus message 2515 * @wpa_s: wpa_supplicant structure for a network interface 2516 * Returns: NULL on success or dbus error on failure 2517 * 2518 * Handler function for "Roam" method call of network interface. 2519 */ 2520 DBusMessage * wpas_dbus_handler_roam(DBusMessage *message, 2521 struct wpa_supplicant *wpa_s) 2522 { 2523 #ifdef CONFIG_NO_SCAN_PROCESSING 2524 return wpas_dbus_error_unknown_error(message, 2525 "scan processing not included"); 2526 #else /* CONFIG_NO_SCAN_PROCESSING */ 2527 u8 bssid[ETH_ALEN]; 2528 struct wpa_bss *bss; 2529 struct wpa_ssid *ssid = wpa_s->current_ssid; 2530 char *addr; 2531 struct wpa_radio_work *already_connecting; 2532 2533 if (!dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &addr, 2534 DBUS_TYPE_INVALID)) 2535 return wpas_dbus_error_invalid_args(message, NULL); 2536 2537 if (hwaddr_aton(addr, bssid)) 2538 return wpas_dbus_error_invalid_args( 2539 message, "Invalid hardware address format"); 2540 2541 wpa_printf(MSG_DEBUG, "dbus: Roam " MACSTR, MAC2STR(bssid)); 2542 2543 if (!ssid) 2544 return dbus_message_new_error( 2545 message, WPAS_DBUS_ERROR_NOT_CONNECTED, 2546 "This interface is not connected"); 2547 2548 bss = wpa_bss_get(wpa_s, bssid, ssid->ssid, ssid->ssid_len); 2549 if (!bss) { 2550 wpa_printf(MSG_DEBUG, "dbus: Roam: Target BSS not found"); 2551 return wpas_dbus_error_invalid_args( 2552 message, "Target BSS not found"); 2553 } 2554 2555 already_connecting = radio_work_pending(wpa_s, "sme-connect"); 2556 wpa_s->reassociate = 1; 2557 wpa_supplicant_connect(wpa_s, bss, ssid); 2558 2559 /* 2560 * Indicate that an explicitly requested roam is in progress so scan 2561 * results that come in before the 'sme-connect' radio work gets 2562 * executed do not override the original connection attempt. 2563 */ 2564 if (!already_connecting && radio_work_pending(wpa_s, "sme-connect")) 2565 wpa_s->roam_in_progress = true; 2566 2567 return NULL; 2568 #endif /* CONFIG_NO_SCAN_PROCESSING */ 2569 } 2570 2571 #ifndef CONFIG_NO_CONFIG_BLOBS 2572 2573 /** 2574 * wpas_dbus_handler_add_blob - Store named binary blob (ie, for certificates) 2575 * @message: Pointer to incoming dbus message 2576 * @wpa_s: %wpa_supplicant data structure 2577 * Returns: A dbus message containing an error on failure or NULL on success 2578 * 2579 * Asks wpa_supplicant to internally store a binary blobs. 2580 */ 2581 DBusMessage * wpas_dbus_handler_add_blob(DBusMessage *message, 2582 struct wpa_supplicant *wpa_s) 2583 { 2584 DBusMessage *reply = NULL; 2585 DBusMessageIter iter, array_iter; 2586 2587 char *blob_name; 2588 u8 *blob_data; 2589 int blob_len; 2590 struct wpa_config_blob *blob = NULL; 2591 2592 dbus_message_iter_init(message, &iter); 2593 dbus_message_iter_get_basic(&iter, &blob_name); 2594 2595 if (wpa_config_get_blob(wpa_s->conf, blob_name)) { 2596 return dbus_message_new_error(message, 2597 WPAS_DBUS_ERROR_BLOB_EXISTS, 2598 NULL); 2599 } 2600 2601 dbus_message_iter_next(&iter); 2602 dbus_message_iter_recurse(&iter, &array_iter); 2603 2604 dbus_message_iter_get_fixed_array(&array_iter, &blob_data, &blob_len); 2605 2606 blob = os_zalloc(sizeof(*blob)); 2607 if (!blob) { 2608 reply = wpas_dbus_error_no_memory(message); 2609 goto err; 2610 } 2611 2612 blob->data = os_memdup(blob_data, blob_len); 2613 blob->name = os_strdup(blob_name); 2614 if (!blob->data || !blob->name) { 2615 reply = wpas_dbus_error_no_memory(message); 2616 goto err; 2617 } 2618 blob->len = blob_len; 2619 2620 wpa_config_set_blob(wpa_s->conf, blob); 2621 wpas_notify_blob_added(wpa_s, blob->name); 2622 2623 return reply; 2624 2625 err: 2626 if (blob) { 2627 os_free(blob->name); 2628 os_free(blob->data); 2629 os_free(blob); 2630 } 2631 return reply; 2632 } 2633 2634 2635 /** 2636 * wpas_dbus_handler_get_blob - Get named binary blob (ie, for certificates) 2637 * @message: Pointer to incoming dbus message 2638 * @wpa_s: %wpa_supplicant data structure 2639 * Returns: A dbus message containing array of bytes (blob) 2640 * 2641 * Gets one wpa_supplicant's binary blobs. 2642 */ 2643 DBusMessage * wpas_dbus_handler_get_blob(DBusMessage *message, 2644 struct wpa_supplicant *wpa_s) 2645 { 2646 DBusMessage *reply = NULL; 2647 DBusMessageIter iter, array_iter; 2648 2649 char *blob_name; 2650 const struct wpa_config_blob *blob; 2651 2652 dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &blob_name, 2653 DBUS_TYPE_INVALID); 2654 2655 blob = wpa_config_get_blob(wpa_s->conf, blob_name); 2656 if (!blob) { 2657 return dbus_message_new_error(message, 2658 WPAS_DBUS_ERROR_BLOB_UNKNOWN, 2659 "Blob id not set"); 2660 } 2661 2662 reply = dbus_message_new_method_return(message); 2663 if (!reply) 2664 return wpas_dbus_error_no_memory(message); 2665 2666 dbus_message_iter_init_append(reply, &iter); 2667 2668 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, 2669 DBUS_TYPE_BYTE_AS_STRING, 2670 &array_iter) || 2671 !dbus_message_iter_append_fixed_array(&array_iter, DBUS_TYPE_BYTE, 2672 &(blob->data), blob->len) || 2673 !dbus_message_iter_close_container(&iter, &array_iter)) { 2674 dbus_message_unref(reply); 2675 reply = wpas_dbus_error_no_memory(message); 2676 } 2677 2678 return reply; 2679 } 2680 2681 2682 /** 2683 * wpas_remove_handler_remove_blob - Remove named binary blob 2684 * @message: Pointer to incoming dbus message 2685 * @wpa_s: %wpa_supplicant data structure 2686 * Returns: NULL on success or dbus error 2687 * 2688 * Asks wpa_supplicant to internally remove a binary blobs. 2689 */ 2690 DBusMessage * wpas_dbus_handler_remove_blob(DBusMessage *message, 2691 struct wpa_supplicant *wpa_s) 2692 { 2693 DBusMessage *reply = NULL; 2694 char *blob_name; 2695 2696 dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &blob_name, 2697 DBUS_TYPE_INVALID); 2698 2699 if (wpa_config_remove_blob(wpa_s->conf, blob_name)) { 2700 return dbus_message_new_error(message, 2701 WPAS_DBUS_ERROR_BLOB_UNKNOWN, 2702 "Blob id not set"); 2703 } 2704 wpas_notify_blob_removed(wpa_s, blob_name); 2705 2706 return reply; 2707 2708 } 2709 2710 #endif /* CONFIG_NO_CONFIG_BLOBS */ 2711 2712 2713 /* 2714 * wpas_dbus_handler_flush_bss - Flush the BSS cache 2715 * @message: Pointer to incoming dbus message 2716 * @wpa_s: wpa_supplicant structure for a network interface 2717 * Returns: NULL 2718 * 2719 * Handler function for "FlushBSS" method call of network interface. 2720 */ 2721 DBusMessage * wpas_dbus_handler_flush_bss(DBusMessage *message, 2722 struct wpa_supplicant *wpa_s) 2723 { 2724 dbus_uint32_t age; 2725 2726 dbus_message_get_args(message, NULL, DBUS_TYPE_UINT32, &age, 2727 DBUS_TYPE_INVALID); 2728 2729 if (age == 0) 2730 wpa_bss_flush(wpa_s); 2731 else 2732 wpa_bss_flush_by_age(wpa_s, age); 2733 2734 return NULL; 2735 } 2736 2737 2738 #ifdef CONFIG_AUTOSCAN 2739 /** 2740 * wpas_dbus_handler_autoscan - Set autoscan parameters for the interface 2741 * @message: Pointer to incoming dbus message 2742 * @wpa_s: wpa_supplicant structure for a network interface 2743 * Returns: NULL 2744 * 2745 * Handler function for "AutoScan" method call of network interface. 2746 */ 2747 DBusMessage * wpas_dbus_handler_autoscan(DBusMessage *message, 2748 struct wpa_supplicant *wpa_s) 2749 { 2750 DBusMessage *reply = NULL; 2751 enum wpa_states state = wpa_s->wpa_state; 2752 char *arg; 2753 2754 dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &arg, 2755 DBUS_TYPE_INVALID); 2756 2757 if (arg != NULL && os_strlen(arg) > 0) { 2758 char *tmp; 2759 2760 tmp = os_strdup(arg); 2761 if (tmp == NULL) { 2762 reply = wpas_dbus_error_no_memory(message); 2763 } else { 2764 os_free(wpa_s->conf->autoscan); 2765 wpa_s->conf->autoscan = tmp; 2766 if (state == WPA_DISCONNECTED || state == WPA_INACTIVE) 2767 autoscan_init(wpa_s, 1); 2768 else if (state == WPA_SCANNING) 2769 wpa_supplicant_reinit_autoscan(wpa_s); 2770 } 2771 } else if (arg != NULL && os_strlen(arg) == 0) { 2772 os_free(wpa_s->conf->autoscan); 2773 wpa_s->conf->autoscan = NULL; 2774 autoscan_deinit(wpa_s); 2775 } else 2776 reply = dbus_message_new_error(message, 2777 DBUS_ERROR_INVALID_ARGS, 2778 NULL); 2779 2780 return reply; 2781 } 2782 #endif /* CONFIG_AUTOSCAN */ 2783 2784 2785 /* 2786 * wpas_dbus_handler_eap_logoff - IEEE 802.1X EAPOL state machine logoff 2787 * @message: Pointer to incoming dbus message 2788 * @wpa_s: wpa_supplicant structure for a network interface 2789 * Returns: NULL 2790 * 2791 * Handler function for "EAPLogoff" method call of network interface. 2792 */ 2793 DBusMessage * wpas_dbus_handler_eap_logoff(DBusMessage *message, 2794 struct wpa_supplicant *wpa_s) 2795 { 2796 eapol_sm_notify_logoff(wpa_s->eapol, TRUE); 2797 return NULL; 2798 } 2799 2800 2801 /* 2802 * wpas_dbus_handler_eap_logon - IEEE 802.1X EAPOL state machine logon 2803 * @message: Pointer to incoming dbus message 2804 * @wpa_s: wpa_supplicant structure for a network interface 2805 * Returns: NULL 2806 * 2807 * Handler function for "EAPLogin" method call of network interface. 2808 */ 2809 DBusMessage * wpas_dbus_handler_eap_logon(DBusMessage *message, 2810 struct wpa_supplicant *wpa_s) 2811 { 2812 eapol_sm_notify_logoff(wpa_s->eapol, FALSE); 2813 return NULL; 2814 } 2815 2816 2817 #ifdef CONFIG_TDLS 2818 2819 static int get_peer_hwaddr_helper(DBusMessage *message, const char *func_name, 2820 u8 *peer_address, DBusMessage **error) 2821 { 2822 const char *peer_string; 2823 2824 *error = NULL; 2825 2826 if (!dbus_message_get_args(message, NULL, 2827 DBUS_TYPE_STRING, &peer_string, 2828 DBUS_TYPE_INVALID)) { 2829 *error = wpas_dbus_error_invalid_args(message, NULL); 2830 return -1; 2831 } 2832 2833 if (hwaddr_aton(peer_string, peer_address)) { 2834 wpa_printf(MSG_DEBUG, "%s: invalid address '%s'", 2835 func_name, peer_string); 2836 *error = wpas_dbus_error_invalid_args( 2837 message, "Invalid hardware address format"); 2838 return -1; 2839 } 2840 2841 return 0; 2842 } 2843 2844 2845 /* 2846 * wpas_dbus_handler_tdls_discover - Discover TDLS peer 2847 * @message: Pointer to incoming dbus message 2848 * @wpa_s: wpa_supplicant structure for a network interface 2849 * Returns: NULL indicating success or DBus error message on failure 2850 * 2851 * Handler function for "TDLSDiscover" method call of network interface. 2852 */ 2853 DBusMessage * wpas_dbus_handler_tdls_discover(DBusMessage *message, 2854 struct wpa_supplicant *wpa_s) 2855 { 2856 u8 peer[ETH_ALEN]; 2857 DBusMessage *error_reply; 2858 int ret; 2859 2860 if (get_peer_hwaddr_helper(message, __func__, peer, &error_reply) < 0) 2861 return error_reply; 2862 2863 wpa_printf(MSG_DEBUG, "DBUS TDLS_DISCOVER " MACSTR, MAC2STR(peer)); 2864 2865 if (wpa_tdls_is_external_setup(wpa_s->wpa)) 2866 ret = wpa_tdls_send_discovery_request(wpa_s->wpa, peer); 2867 else 2868 ret = wpa_drv_tdls_oper(wpa_s, TDLS_DISCOVERY_REQ, peer); 2869 2870 if (ret) { 2871 return wpas_dbus_error_unknown_error( 2872 message, "error performing TDLS discovery"); 2873 } 2874 2875 return NULL; 2876 } 2877 2878 2879 /* 2880 * wpas_dbus_handler_tdls_setup - Setup TDLS session 2881 * @message: Pointer to incoming dbus message 2882 * @wpa_s: wpa_supplicant structure for a network interface 2883 * Returns: NULL indicating success or DBus error message on failure 2884 * 2885 * Handler function for "TDLSSetup" method call of network interface. 2886 */ 2887 DBusMessage * wpas_dbus_handler_tdls_setup(DBusMessage *message, 2888 struct wpa_supplicant *wpa_s) 2889 { 2890 u8 peer[ETH_ALEN]; 2891 DBusMessage *error_reply; 2892 int ret; 2893 2894 if (get_peer_hwaddr_helper(message, __func__, peer, &error_reply) < 0) 2895 return error_reply; 2896 2897 wpa_printf(MSG_DEBUG, "DBUS TDLS_SETUP " MACSTR, MAC2STR(peer)); 2898 2899 wpa_tdls_remove(wpa_s->wpa, peer); 2900 if (wpa_tdls_is_external_setup(wpa_s->wpa)) 2901 ret = wpa_tdls_start(wpa_s->wpa, peer); 2902 else 2903 ret = wpa_drv_tdls_oper(wpa_s, TDLS_SETUP, peer); 2904 2905 if (ret) { 2906 return wpas_dbus_error_unknown_error( 2907 message, "error performing TDLS setup"); 2908 } 2909 2910 return NULL; 2911 } 2912 2913 2914 /* 2915 * wpas_dbus_handler_tdls_status - Return TDLS session status 2916 * @message: Pointer to incoming dbus message 2917 * @wpa_s: wpa_supplicant structure for a network interface 2918 * Returns: A string representing the state of the link to this TDLS peer 2919 * 2920 * Handler function for "TDLSStatus" method call of network interface. 2921 */ 2922 DBusMessage * wpas_dbus_handler_tdls_status(DBusMessage *message, 2923 struct wpa_supplicant *wpa_s) 2924 { 2925 u8 peer[ETH_ALEN]; 2926 DBusMessage *reply; 2927 const char *tdls_status; 2928 2929 if (get_peer_hwaddr_helper(message, __func__, peer, &reply) < 0) 2930 return reply; 2931 2932 wpa_printf(MSG_DEBUG, "DBUS TDLS_STATUS " MACSTR, MAC2STR(peer)); 2933 2934 tdls_status = wpa_tdls_get_link_status(wpa_s->wpa, peer); 2935 2936 reply = dbus_message_new_method_return(message); 2937 dbus_message_append_args(reply, DBUS_TYPE_STRING, 2938 &tdls_status, DBUS_TYPE_INVALID); 2939 return reply; 2940 } 2941 2942 2943 /* 2944 * wpas_dbus_handler_tdls_teardown - Teardown TDLS session 2945 * @message: Pointer to incoming dbus message 2946 * @wpa_s: wpa_supplicant structure for a network interface 2947 * Returns: NULL indicating success or DBus error message on failure 2948 * 2949 * Handler function for "TDLSTeardown" method call of network interface. 2950 */ 2951 DBusMessage * wpas_dbus_handler_tdls_teardown(DBusMessage *message, 2952 struct wpa_supplicant *wpa_s) 2953 { 2954 u8 peer[ETH_ALEN]; 2955 DBusMessage *error_reply; 2956 int ret; 2957 2958 if (get_peer_hwaddr_helper(message, __func__, peer, &error_reply) < 0) 2959 return error_reply; 2960 2961 wpa_printf(MSG_DEBUG, "DBUS TDLS_TEARDOWN " MACSTR, MAC2STR(peer)); 2962 2963 if (wpa_tdls_is_external_setup(wpa_s->wpa)) 2964 ret = wpa_tdls_teardown_link( 2965 wpa_s->wpa, peer, 2966 WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED); 2967 else 2968 ret = wpa_drv_tdls_oper(wpa_s, TDLS_TEARDOWN, peer); 2969 2970 if (ret) { 2971 return wpas_dbus_error_unknown_error( 2972 message, "error performing TDLS teardown"); 2973 } 2974 2975 return NULL; 2976 } 2977 2978 /* 2979 * wpas_dbus_handler_tdls_channel_switch - Enable channel switching with TDLS peer 2980 * @message: Pointer to incoming dbus message 2981 * @wpa_s: wpa_supplicant structure for a network interface 2982 * Returns: NULL indicating success or DBus error message on failure 2983 * 2984 * Handler function for "TDLSChannelSwitch" method call of network interface. 2985 */ 2986 DBusMessage * 2987 wpas_dbus_handler_tdls_channel_switch(DBusMessage *message, 2988 struct wpa_supplicant *wpa_s) 2989 { 2990 DBusMessageIter iter, iter_dict; 2991 struct wpa_dbus_dict_entry entry; 2992 u8 peer[ETH_ALEN]; 2993 struct hostapd_freq_params freq_params; 2994 u8 oper_class = 0; 2995 int ret; 2996 int is_peer_present = 0; 2997 2998 if (!wpa_tdls_is_external_setup(wpa_s->wpa)) { 2999 wpa_printf(MSG_INFO, 3000 "tdls_chanswitch: Only supported with external setup"); 3001 return wpas_dbus_error_unknown_error(message, "TDLS is not using external setup"); 3002 } 3003 3004 os_memset(&freq_params, 0, sizeof(freq_params)); 3005 3006 dbus_message_iter_init(message, &iter); 3007 3008 if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL)) 3009 return wpas_dbus_error_invalid_args(message, NULL); 3010 3011 while (wpa_dbus_dict_has_dict_entry(&iter_dict)) { 3012 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) 3013 return wpas_dbus_error_invalid_args(message, NULL); 3014 3015 if (os_strcmp(entry.key, "PeerAddress") == 0 && 3016 entry.type == DBUS_TYPE_STRING) { 3017 if (hwaddr_aton(entry.str_value, peer)) { 3018 wpa_printf(MSG_DEBUG, 3019 "tdls_chanswitch: Invalid address '%s'", 3020 entry.str_value); 3021 wpa_dbus_dict_entry_clear(&entry); 3022 return wpas_dbus_error_invalid_args(message, 3023 NULL); 3024 } 3025 3026 is_peer_present = 1; 3027 } else if (os_strcmp(entry.key, "OperClass") == 0 && 3028 entry.type == DBUS_TYPE_BYTE) { 3029 oper_class = entry.byte_value; 3030 } else if (os_strcmp(entry.key, "Frequency") == 0 && 3031 entry.type == DBUS_TYPE_UINT32) { 3032 freq_params.freq = entry.uint32_value; 3033 } else if (os_strcmp(entry.key, "SecChannelOffset") == 0 && 3034 entry.type == DBUS_TYPE_UINT32) { 3035 freq_params.sec_channel_offset = entry.uint32_value; 3036 } else if (os_strcmp(entry.key, "CenterFrequency1") == 0 && 3037 entry.type == DBUS_TYPE_UINT32) { 3038 freq_params.center_freq1 = entry.uint32_value; 3039 } else if (os_strcmp(entry.key, "CenterFrequency2") == 0 && 3040 entry.type == DBUS_TYPE_UINT32) { 3041 freq_params.center_freq2 = entry.uint32_value; 3042 } else if (os_strcmp(entry.key, "Bandwidth") == 0 && 3043 entry.type == DBUS_TYPE_UINT32) { 3044 freq_params.bandwidth = entry.uint32_value; 3045 } else if (os_strcmp(entry.key, "HT") == 0 && 3046 entry.type == DBUS_TYPE_BOOLEAN) { 3047 freq_params.ht_enabled = entry.bool_value; 3048 } else if (os_strcmp(entry.key, "VHT") == 0 && 3049 entry.type == DBUS_TYPE_BOOLEAN) { 3050 freq_params.vht_enabled = entry.bool_value; 3051 } else { 3052 wpa_dbus_dict_entry_clear(&entry); 3053 return wpas_dbus_error_invalid_args(message, NULL); 3054 } 3055 3056 wpa_dbus_dict_entry_clear(&entry); 3057 } 3058 3059 if (oper_class == 0) { 3060 wpa_printf(MSG_INFO, 3061 "tdls_chanswitch: Invalid op class provided"); 3062 return wpas_dbus_error_invalid_args( 3063 message, "Invalid op class provided"); 3064 } 3065 3066 if (freq_params.freq == 0) { 3067 wpa_printf(MSG_INFO, 3068 "tdls_chanswitch: Invalid freq provided"); 3069 return wpas_dbus_error_invalid_args(message, 3070 "Invalid freq provided"); 3071 } 3072 3073 if (is_peer_present == 0) { 3074 wpa_printf(MSG_DEBUG, 3075 "tdls_chanswitch: peer address not provided"); 3076 return wpas_dbus_error_invalid_args( 3077 message, "peer address not provided"); 3078 } 3079 3080 wpa_printf(MSG_DEBUG, "dbus: TDLS_CHAN_SWITCH " MACSTR 3081 " OP CLASS %d FREQ %d CENTER1 %d CENTER2 %d BW %d SEC_OFFSET %d%s%s", 3082 MAC2STR(peer), oper_class, freq_params.freq, 3083 freq_params.center_freq1, freq_params.center_freq2, 3084 freq_params.bandwidth, freq_params.sec_channel_offset, 3085 freq_params.ht_enabled ? " HT" : "", 3086 freq_params.vht_enabled ? " VHT" : ""); 3087 3088 ret = wpa_tdls_enable_chan_switch(wpa_s->wpa, peer, oper_class, 3089 &freq_params); 3090 if (ret) 3091 return wpas_dbus_error_unknown_error( 3092 message, "error processing TDLS channel switch"); 3093 3094 return NULL; 3095 } 3096 3097 /* 3098 * wpas_dbus_handler_tdls_cancel_channel_switch - Disable channel switching with TDLS peer 3099 * @message: Pointer to incoming dbus message 3100 * @wpa_s: wpa_supplicant structure for a network interface 3101 * Returns: NULL indicating success or DBus error message on failure 3102 * 3103 * Handler function for "TDLSCancelChannelSwitch" method call of network 3104 * interface. 3105 */ 3106 DBusMessage * 3107 wpas_dbus_handler_tdls_cancel_channel_switch(DBusMessage *message, 3108 struct wpa_supplicant *wpa_s) 3109 { 3110 u8 peer[ETH_ALEN]; 3111 DBusMessage *error_reply; 3112 int ret; 3113 3114 if (get_peer_hwaddr_helper(message, __func__, peer, &error_reply) < 0) 3115 return error_reply; 3116 3117 wpa_printf(MSG_DEBUG, "dbus: TDLS_CANCEL_CHAN_SWITCH " MACSTR, 3118 MAC2STR(peer)); 3119 3120 ret = wpa_tdls_disable_chan_switch(wpa_s->wpa, peer); 3121 if (ret) 3122 return wpas_dbus_error_unknown_error( 3123 message, "error canceling TDLS channel switch"); 3124 3125 return NULL; 3126 } 3127 3128 #endif /* CONFIG_TDLS */ 3129 3130 3131 #ifndef CONFIG_NO_CONFIG_WRITE 3132 /** 3133 * wpas_dbus_handler_save_config - Save configuration to configuration file 3134 * @message: Pointer to incoming dbus message 3135 * @wpa_s: wpa_supplicant structure for a network interface 3136 * Returns: NULL on Success, Otherwise error message 3137 * 3138 * Handler function for "SaveConfig" method call of network interface. 3139 */ 3140 DBusMessage * wpas_dbus_handler_save_config(DBusMessage *message, 3141 struct wpa_supplicant *wpa_s) 3142 { 3143 int ret; 3144 3145 if (!wpa_s->conf->update_config) { 3146 return wpas_dbus_error_unknown_error( 3147 message, 3148 "Not allowed to update configuration (update_config=0)"); 3149 } 3150 3151 ret = wpa_config_write(wpa_s->confname, wpa_s->conf); 3152 if (ret) 3153 return wpas_dbus_error_unknown_error( 3154 message, "Failed to update configuration"); 3155 return NULL; 3156 } 3157 #endif /* CONFIG_NO_CONFIG_WRITE */ 3158 3159 3160 /** 3161 * wpas_dbus_handler_set_pkcs11_engine_and_module_path - Set PKCS #11 engine and module path 3162 * @message: Pointer to incoming dbus message 3163 * @wpa_s: %wpa_supplicant data structure 3164 * Returns: A dbus message containing an error on failure or NULL on success 3165 * 3166 * Sets the PKCS #11 engine and module path. 3167 */ 3168 DBusMessage * wpas_dbus_handler_set_pkcs11_engine_and_module_path( 3169 DBusMessage *message, struct wpa_supplicant *wpa_s) 3170 { 3171 DBusMessageIter iter; 3172 char *value = NULL; 3173 char *pkcs11_engine_path = NULL; 3174 char *pkcs11_module_path = NULL; 3175 3176 dbus_message_iter_init(message, &iter); 3177 dbus_message_iter_get_basic(&iter, &value); 3178 if (value == NULL) { 3179 return dbus_message_new_error( 3180 message, DBUS_ERROR_INVALID_ARGS, 3181 "Invalid pkcs11_engine_path argument"); 3182 } 3183 /* Empty path defaults to NULL */ 3184 if (os_strlen(value)) 3185 pkcs11_engine_path = value; 3186 3187 dbus_message_iter_next(&iter); 3188 dbus_message_iter_get_basic(&iter, &value); 3189 if (value == NULL) { 3190 os_free(pkcs11_engine_path); 3191 return dbus_message_new_error( 3192 message, DBUS_ERROR_INVALID_ARGS, 3193 "Invalid pkcs11_module_path argument"); 3194 } 3195 /* Empty path defaults to NULL */ 3196 if (os_strlen(value)) 3197 pkcs11_module_path = value; 3198 3199 if (wpas_set_pkcs11_engine_and_module_path(wpa_s, pkcs11_engine_path, 3200 pkcs11_module_path)) 3201 return dbus_message_new_error( 3202 message, DBUS_ERROR_FAILED, 3203 "Reinit of the EAPOL state machine with the new PKCS #11 engine and module path failed."); 3204 3205 if (wpa_s->dbus_new_path) { 3206 wpa_dbus_mark_property_changed( 3207 wpa_s->global->dbus, wpa_s->dbus_new_path, 3208 WPAS_DBUS_NEW_IFACE_INTERFACE, "PKCS11EnginePath"); 3209 wpa_dbus_mark_property_changed( 3210 wpa_s->global->dbus, wpa_s->dbus_new_path, 3211 WPAS_DBUS_NEW_IFACE_INTERFACE, "PKCS11ModulePath"); 3212 } 3213 3214 return NULL; 3215 } 3216 3217 3218 /** 3219 * wpas_dbus_getter_capabilities - Return interface capabilities 3220 * @iter: Pointer to incoming dbus message iter 3221 * @error: Location to store error on failure 3222 * @user_data: Function specific data 3223 * Returns: TRUE on success, FALSE on failure 3224 * 3225 * Getter for "Capabilities" property of an interface. 3226 */ 3227 dbus_bool_t wpas_dbus_getter_capabilities( 3228 const struct wpa_dbus_property_desc *property_desc, 3229 DBusMessageIter *iter, DBusError *error, void *user_data) 3230 { 3231 struct wpa_supplicant *wpa_s = user_data; 3232 struct wpa_driver_capa capa; 3233 int res; 3234 DBusMessageIter iter_dict, iter_dict_entry, iter_dict_val, iter_array, 3235 variant_iter; 3236 const char *scans[] = { "active", "passive", "ssid" }; 3237 3238 if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, 3239 "a{sv}", &variant_iter) || 3240 !wpa_dbus_dict_open_write(&variant_iter, &iter_dict)) 3241 goto nomem; 3242 3243 res = wpa_drv_get_capa(wpa_s, &capa); 3244 3245 /***** pairwise cipher */ 3246 if (res < 0) { 3247 #ifdef CONFIG_NO_TKIP 3248 const char *args[] = {"ccmp", "none"}; 3249 #else /* CONFIG_NO_TKIP */ 3250 const char *args[] = {"ccmp", "tkip", "none"}; 3251 #endif /* CONFIG_NO_TKIP */ 3252 3253 if (!wpa_dbus_dict_append_string_array( 3254 &iter_dict, "Pairwise", args, 3255 ARRAY_SIZE(args))) 3256 goto nomem; 3257 } else { 3258 if (!wpa_dbus_dict_begin_string_array(&iter_dict, "Pairwise", 3259 &iter_dict_entry, 3260 &iter_dict_val, 3261 &iter_array) || 3262 ((capa.enc & WPA_DRIVER_CAPA_ENC_CCMP_256) && 3263 !wpa_dbus_dict_string_array_add_element( 3264 &iter_array, "ccmp-256")) || 3265 ((capa.enc & WPA_DRIVER_CAPA_ENC_GCMP_256) && 3266 !wpa_dbus_dict_string_array_add_element( 3267 &iter_array, "gcmp-256")) || 3268 ((capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) && 3269 !wpa_dbus_dict_string_array_add_element( 3270 &iter_array, "ccmp")) || 3271 ((capa.enc & WPA_DRIVER_CAPA_ENC_GCMP) && 3272 !wpa_dbus_dict_string_array_add_element( 3273 &iter_array, "gcmp")) || 3274 #ifndef CONFIG_NO_TKIP 3275 ((capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) && 3276 !wpa_dbus_dict_string_array_add_element( 3277 &iter_array, "tkip")) || 3278 #endif /* CONFIG_NO_TKIP */ 3279 ((capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) && 3280 !wpa_dbus_dict_string_array_add_element( 3281 &iter_array, "none")) || 3282 !wpa_dbus_dict_end_string_array(&iter_dict, 3283 &iter_dict_entry, 3284 &iter_dict_val, 3285 &iter_array)) 3286 goto nomem; 3287 } 3288 3289 /***** group cipher */ 3290 if (res < 0) { 3291 const char *args[] = { 3292 "ccmp", 3293 #ifndef CONFIG_NO_TKIP 3294 "tkip", 3295 #endif /* CONFIG_NO_TKIP */ 3296 #ifdef CONFIG_WEP 3297 "wep104", "wep40" 3298 #endif /* CONFIG_WEP */ 3299 }; 3300 3301 if (!wpa_dbus_dict_append_string_array( 3302 &iter_dict, "Group", args, 3303 ARRAY_SIZE(args))) 3304 goto nomem; 3305 } else { 3306 if (!wpa_dbus_dict_begin_string_array(&iter_dict, "Group", 3307 &iter_dict_entry, 3308 &iter_dict_val, 3309 &iter_array) || 3310 ((capa.enc & WPA_DRIVER_CAPA_ENC_CCMP_256) && 3311 !wpa_dbus_dict_string_array_add_element( 3312 &iter_array, "ccmp-256")) || 3313 ((capa.enc & WPA_DRIVER_CAPA_ENC_GCMP_256) && 3314 !wpa_dbus_dict_string_array_add_element( 3315 &iter_array, "gcmp-256")) || 3316 ((capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) && 3317 !wpa_dbus_dict_string_array_add_element( 3318 &iter_array, "ccmp")) || 3319 ((capa.enc & WPA_DRIVER_CAPA_ENC_GCMP) && 3320 !wpa_dbus_dict_string_array_add_element( 3321 &iter_array, "gcmp")) || 3322 #ifndef CONFIG_NO_TKIP 3323 ((capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) && 3324 !wpa_dbus_dict_string_array_add_element( 3325 &iter_array, "tkip")) || 3326 #endif /* CONFIG_NO_TKIP */ 3327 #ifdef CONFIG_WEP 3328 ((capa.enc & WPA_DRIVER_CAPA_ENC_WEP104) && 3329 !wpa_dbus_dict_string_array_add_element( 3330 &iter_array, "wep104")) || 3331 ((capa.enc & WPA_DRIVER_CAPA_ENC_WEP40) && 3332 !wpa_dbus_dict_string_array_add_element( 3333 &iter_array, "wep40")) || 3334 #endif /* CONFIG_WEP */ 3335 !wpa_dbus_dict_end_string_array(&iter_dict, 3336 &iter_dict_entry, 3337 &iter_dict_val, 3338 &iter_array)) 3339 goto nomem; 3340 } 3341 3342 if (!wpa_dbus_dict_begin_string_array(&iter_dict, "GroupMgmt", 3343 &iter_dict_entry, 3344 &iter_dict_val, 3345 &iter_array) || 3346 (res == 0 && (capa.enc & WPA_DRIVER_CAPA_ENC_BIP) && 3347 !wpa_dbus_dict_string_array_add_element( 3348 &iter_array, "aes-128-cmac")) || 3349 (res == 0 && (capa.enc & WPA_DRIVER_CAPA_ENC_BIP_GMAC_128) && 3350 !wpa_dbus_dict_string_array_add_element( 3351 &iter_array, "bip-gmac-128")) || 3352 (res == 0 && (capa.enc & WPA_DRIVER_CAPA_ENC_BIP_GMAC_256) && 3353 !wpa_dbus_dict_string_array_add_element( 3354 &iter_array, "bip-gmac-256")) || 3355 (res == 0 && (capa.enc & WPA_DRIVER_CAPA_ENC_BIP_CMAC_256) && 3356 !wpa_dbus_dict_string_array_add_element( 3357 &iter_array, "bip-cmac-256")) || 3358 !wpa_dbus_dict_end_string_array(&iter_dict, 3359 &iter_dict_entry, 3360 &iter_dict_val, 3361 &iter_array)) 3362 goto nomem; 3363 3364 /***** key management */ 3365 if (res < 0) { 3366 const char *args[] = { 3367 "wpa-psk", "wpa-eap", "ieee8021x", "wpa-none", 3368 #ifdef CONFIG_WPS 3369 "wps", 3370 #endif /* CONFIG_WPS */ 3371 "none" 3372 }; 3373 if (!wpa_dbus_dict_append_string_array( 3374 &iter_dict, "KeyMgmt", args, 3375 ARRAY_SIZE(args))) 3376 goto nomem; 3377 } else { 3378 if (!wpa_dbus_dict_begin_string_array(&iter_dict, "KeyMgmt", 3379 &iter_dict_entry, 3380 &iter_dict_val, 3381 &iter_array) || 3382 !wpa_dbus_dict_string_array_add_element(&iter_array, 3383 "none") || 3384 !wpa_dbus_dict_string_array_add_element(&iter_array, 3385 "ieee8021x")) 3386 goto nomem; 3387 3388 if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA | 3389 WPA_DRIVER_CAPA_KEY_MGMT_WPA2)) { 3390 if (!wpa_dbus_dict_string_array_add_element( 3391 &iter_array, "wpa-eap")) 3392 goto nomem; 3393 3394 #ifdef CONFIG_IEEE80211R 3395 if ((capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FT) && 3396 !wpa_dbus_dict_string_array_add_element( 3397 &iter_array, "wpa-ft-eap")) 3398 goto nomem; 3399 #endif /* CONFIG_IEEE80211R */ 3400 3401 /* TODO: Ensure that driver actually supports sha256 encryption. */ 3402 if (!wpa_dbus_dict_string_array_add_element( 3403 &iter_array, "wpa-eap-sha256")) 3404 goto nomem; 3405 } 3406 3407 if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK | 3408 WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) { 3409 if (!wpa_dbus_dict_string_array_add_element( 3410 &iter_array, "wpa-psk")) 3411 goto nomem; 3412 3413 #ifdef CONFIG_IEEE80211R 3414 if ((capa.key_mgmt & 3415 WPA_DRIVER_CAPA_KEY_MGMT_FT_PSK) && 3416 !wpa_dbus_dict_string_array_add_element( 3417 &iter_array, "wpa-ft-psk")) 3418 goto nomem; 3419 #endif /* CONFIG_IEEE80211R */ 3420 3421 /* TODO: Ensure that driver actually supports sha256 encryption. */ 3422 if (!wpa_dbus_dict_string_array_add_element( 3423 &iter_array, "wpa-psk-sha256")) 3424 goto nomem; 3425 } 3426 3427 if ((capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) && 3428 !wpa_dbus_dict_string_array_add_element(&iter_array, 3429 "wpa-none")) 3430 goto nomem; 3431 3432 3433 #ifdef CONFIG_WPS 3434 if (!wpa_dbus_dict_string_array_add_element(&iter_array, 3435 "wps")) 3436 goto nomem; 3437 #endif /* CONFIG_WPS */ 3438 3439 #ifdef CONFIG_SAE 3440 if ((capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_SAE) && 3441 !wpa_dbus_dict_string_array_add_element(&iter_array, "sae")) 3442 goto nomem; 3443 #endif /* CONFIG_SAE */ 3444 3445 #ifdef CONFIG_OWE 3446 if ((capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_OWE) && 3447 !wpa_dbus_dict_string_array_add_element(&iter_array, "owe")) 3448 goto nomem; 3449 #endif /* CONFIG_OWE */ 3450 3451 if (!wpa_dbus_dict_end_string_array(&iter_dict, 3452 &iter_dict_entry, 3453 &iter_dict_val, 3454 &iter_array)) 3455 goto nomem; 3456 } 3457 3458 /***** WPA protocol */ 3459 if (res < 0) { 3460 const char *args[] = { "rsn", "wpa" }; 3461 3462 if (!wpa_dbus_dict_append_string_array( 3463 &iter_dict, "Protocol", args, 3464 ARRAY_SIZE(args))) 3465 goto nomem; 3466 } else { 3467 if (!wpa_dbus_dict_begin_string_array(&iter_dict, "Protocol", 3468 &iter_dict_entry, 3469 &iter_dict_val, 3470 &iter_array) || 3471 ((capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA2 | 3472 WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) && 3473 !wpa_dbus_dict_string_array_add_element( 3474 &iter_array, "rsn")) || 3475 ((capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA | 3476 WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK)) && 3477 !wpa_dbus_dict_string_array_add_element( 3478 &iter_array, "wpa")) || 3479 !wpa_dbus_dict_end_string_array(&iter_dict, 3480 &iter_dict_entry, 3481 &iter_dict_val, 3482 &iter_array)) 3483 goto nomem; 3484 } 3485 3486 /***** auth alg */ 3487 if (res < 0) { 3488 const char *args[] = { "open", "shared", "leap" }; 3489 3490 if (!wpa_dbus_dict_append_string_array( 3491 &iter_dict, "AuthAlg", args, 3492 ARRAY_SIZE(args))) 3493 goto nomem; 3494 } else { 3495 if (!wpa_dbus_dict_begin_string_array(&iter_dict, "AuthAlg", 3496 &iter_dict_entry, 3497 &iter_dict_val, 3498 &iter_array)) 3499 goto nomem; 3500 3501 if (((capa.auth & WPA_DRIVER_AUTH_OPEN) && 3502 !wpa_dbus_dict_string_array_add_element( 3503 &iter_array, "open")) || 3504 ((capa.auth & WPA_DRIVER_AUTH_SHARED) && 3505 !wpa_dbus_dict_string_array_add_element( 3506 &iter_array, "shared")) || 3507 ((capa.auth & WPA_DRIVER_AUTH_LEAP) && 3508 !wpa_dbus_dict_string_array_add_element( 3509 &iter_array, "leap")) || 3510 !wpa_dbus_dict_end_string_array(&iter_dict, 3511 &iter_dict_entry, 3512 &iter_dict_val, 3513 &iter_array)) 3514 goto nomem; 3515 } 3516 3517 /***** Scan */ 3518 if (!wpa_dbus_dict_append_string_array(&iter_dict, "Scan", scans, 3519 ARRAY_SIZE(scans))) 3520 goto nomem; 3521 3522 /***** Modes */ 3523 if (!wpa_dbus_dict_begin_string_array(&iter_dict, "Modes", 3524 &iter_dict_entry, 3525 &iter_dict_val, 3526 &iter_array) || 3527 !wpa_dbus_dict_string_array_add_element( 3528 &iter_array, "infrastructure") || 3529 (res >= 0 && (capa.flags & WPA_DRIVER_FLAGS_IBSS) && 3530 !wpa_dbus_dict_string_array_add_element( 3531 &iter_array, "ad-hoc")) || 3532 (res >= 0 && (capa.flags & WPA_DRIVER_FLAGS_AP) && 3533 !wpa_dbus_dict_string_array_add_element( 3534 &iter_array, "ap")) || 3535 (res >= 0 && (capa.flags & WPA_DRIVER_FLAGS_P2P_CAPABLE) && 3536 !wpa_s->conf->p2p_disabled && 3537 !wpa_dbus_dict_string_array_add_element( 3538 &iter_array, "p2p")) || 3539 #ifdef CONFIG_MESH 3540 (res >= 0 && (capa.flags & WPA_DRIVER_FLAGS_MESH) && 3541 !wpa_dbus_dict_string_array_add_element( 3542 &iter_array, "mesh")) || 3543 #endif /* CONFIG_MESH */ 3544 !wpa_dbus_dict_end_string_array(&iter_dict, 3545 &iter_dict_entry, 3546 &iter_dict_val, 3547 &iter_array)) 3548 goto nomem; 3549 /***** Modes end */ 3550 3551 if (res >= 0) { 3552 dbus_int32_t max_scan_ssid = capa.max_scan_ssids; 3553 3554 if (!wpa_dbus_dict_append_int32(&iter_dict, "MaxScanSSID", 3555 max_scan_ssid)) 3556 goto nomem; 3557 } 3558 3559 if (!wpa_dbus_dict_close_write(&variant_iter, &iter_dict) || 3560 !dbus_message_iter_close_container(iter, &variant_iter)) 3561 goto nomem; 3562 3563 return TRUE; 3564 3565 nomem: 3566 dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory"); 3567 return FALSE; 3568 } 3569 3570 3571 /** 3572 * wpas_dbus_getter_state - Get interface state 3573 * @iter: Pointer to incoming dbus message iter 3574 * @error: Location to store error on failure 3575 * @user_data: Function specific data 3576 * Returns: TRUE on success, FALSE on failure 3577 * 3578 * Getter for "State" property. 3579 */ 3580 dbus_bool_t wpas_dbus_getter_state( 3581 const struct wpa_dbus_property_desc *property_desc, 3582 DBusMessageIter *iter, DBusError *error, void *user_data) 3583 { 3584 struct wpa_supplicant *wpa_s = user_data; 3585 const char *str_state; 3586 char *state_ls, *tmp; 3587 dbus_bool_t success = FALSE; 3588 3589 str_state = wpa_supplicant_state_txt(wpa_s->wpa_state); 3590 3591 /* make state string lowercase to fit new DBus API convention 3592 */ 3593 state_ls = tmp = os_strdup(str_state); 3594 if (!tmp) { 3595 dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory"); 3596 return FALSE; 3597 } 3598 while (*tmp) { 3599 *tmp = tolower(*tmp); 3600 tmp++; 3601 } 3602 3603 success = wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING, 3604 &state_ls, error); 3605 3606 os_free(state_ls); 3607 3608 return success; 3609 } 3610 3611 3612 /** 3613 * wpas_dbus_new_iface_get_scanning - Get interface scanning state 3614 * @iter: Pointer to incoming dbus message iter 3615 * @error: Location to store error on failure 3616 * @user_data: Function specific data 3617 * Returns: TRUE on success, FALSE on failure 3618 * 3619 * Getter for "scanning" property. 3620 */ 3621 dbus_bool_t wpas_dbus_getter_scanning( 3622 const struct wpa_dbus_property_desc *property_desc, 3623 DBusMessageIter *iter, DBusError *error, void *user_data) 3624 { 3625 struct wpa_supplicant *wpa_s = user_data; 3626 dbus_bool_t scanning = wpa_s->scanning ? TRUE : FALSE; 3627 3628 return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN, 3629 &scanning, error); 3630 } 3631 3632 3633 /** 3634 * wpas_dbus_getter_ap_scan - Control roaming mode 3635 * @iter: Pointer to incoming dbus message iter 3636 * @error: Location to store error on failure 3637 * @user_data: Function specific data 3638 * Returns: TRUE on success, FALSE on failure 3639 * 3640 * Getter function for "ApScan" property. 3641 */ 3642 dbus_bool_t wpas_dbus_getter_ap_scan( 3643 const struct wpa_dbus_property_desc *property_desc, 3644 DBusMessageIter *iter, DBusError *error, void *user_data) 3645 { 3646 struct wpa_supplicant *wpa_s = user_data; 3647 dbus_uint32_t ap_scan = wpa_s->conf->ap_scan; 3648 3649 return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT32, 3650 &ap_scan, error); 3651 } 3652 3653 3654 /** 3655 * wpas_dbus_setter_ap_scan - Control roaming mode 3656 * @iter: Pointer to incoming dbus message iter 3657 * @error: Location to store error on failure 3658 * @user_data: Function specific data 3659 * Returns: TRUE on success, FALSE on failure 3660 * 3661 * Setter function for "ApScan" property. 3662 */ 3663 dbus_bool_t wpas_dbus_setter_ap_scan( 3664 const struct wpa_dbus_property_desc *property_desc, 3665 DBusMessageIter *iter, DBusError *error, void *user_data) 3666 { 3667 struct wpa_supplicant *wpa_s = user_data; 3668 dbus_uint32_t ap_scan; 3669 3670 if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_UINT32, 3671 &ap_scan)) 3672 return FALSE; 3673 3674 if (wpa_supplicant_set_ap_scan(wpa_s, ap_scan)) { 3675 dbus_set_error_const(error, DBUS_ERROR_FAILED, 3676 "ap_scan must be 0, 1, or 2"); 3677 return FALSE; 3678 } 3679 return TRUE; 3680 } 3681 3682 3683 /** 3684 * wpas_dbus_getter_fast_reauth - Control fast 3685 * reauthentication (TLS session resumption) 3686 * @iter: Pointer to incoming dbus message iter 3687 * @error: Location to store error on failure 3688 * @user_data: Function specific data 3689 * Returns: TRUE on success, FALSE on failure 3690 * 3691 * Getter function for "FastReauth" property. 3692 */ 3693 dbus_bool_t wpas_dbus_getter_fast_reauth( 3694 const struct wpa_dbus_property_desc *property_desc, 3695 DBusMessageIter *iter, DBusError *error, void *user_data) 3696 { 3697 struct wpa_supplicant *wpa_s = user_data; 3698 dbus_bool_t fast_reauth = wpa_s->conf->fast_reauth ? TRUE : FALSE; 3699 3700 return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN, 3701 &fast_reauth, error); 3702 } 3703 3704 3705 /** 3706 * wpas_dbus_setter_fast_reauth - Control fast 3707 * reauthentication (TLS session resumption) 3708 * @iter: Pointer to incoming dbus message iter 3709 * @error: Location to store error on failure 3710 * @user_data: Function specific data 3711 * Returns: TRUE on success, FALSE on failure 3712 * 3713 * Setter function for "FastReauth" property. 3714 */ 3715 dbus_bool_t wpas_dbus_setter_fast_reauth( 3716 const struct wpa_dbus_property_desc *property_desc, 3717 DBusMessageIter *iter, DBusError *error, void *user_data) 3718 { 3719 struct wpa_supplicant *wpa_s = user_data; 3720 dbus_bool_t fast_reauth; 3721 3722 if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_BOOLEAN, 3723 &fast_reauth)) 3724 return FALSE; 3725 3726 wpa_s->conf->fast_reauth = fast_reauth; 3727 return TRUE; 3728 } 3729 3730 3731 /** 3732 * wpas_dbus_getter_disconnect_reason - Get most recent reason for disconnect 3733 * @iter: Pointer to incoming dbus message iter 3734 * @error: Location to store error on failure 3735 * @user_data: Function specific data 3736 * Returns: TRUE on success, FALSE on failure 3737 * 3738 * Getter for "DisconnectReason" property. The reason is negative if it is 3739 * locally generated. 3740 */ 3741 dbus_bool_t wpas_dbus_getter_disconnect_reason( 3742 const struct wpa_dbus_property_desc *property_desc, 3743 DBusMessageIter *iter, DBusError *error, void *user_data) 3744 { 3745 struct wpa_supplicant *wpa_s = user_data; 3746 dbus_int32_t reason = wpa_s->disconnect_reason; 3747 3748 return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_INT32, 3749 &reason, error); 3750 } 3751 3752 3753 /** 3754 * wpas_dbus_getter_auth_status_code - Get most recent auth status code 3755 * @iter: Pointer to incoming dbus message iter 3756 * @error: Location to store error on failure 3757 * @user_data: Function specific data 3758 * Returns: TRUE on success, FALSE on failure 3759 * 3760 * Getter for "AuthStatusCode" property. 3761 */ 3762 dbus_bool_t wpas_dbus_getter_auth_status_code( 3763 const struct wpa_dbus_property_desc *property_desc, 3764 DBusMessageIter *iter, DBusError *error, void *user_data) 3765 { 3766 struct wpa_supplicant *wpa_s = user_data; 3767 dbus_int32_t reason = wpa_s->auth_status_code; 3768 3769 return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_INT32, 3770 &reason, error); 3771 } 3772 3773 3774 /** 3775 * wpas_dbus_getter_assoc_status_code - Get most recent failed assoc status code 3776 * @iter: Pointer to incoming dbus message iter 3777 * @error: Location to store error on failure 3778 * @user_data: Function specific data 3779 * Returns: TRUE on success, FALSE on failure 3780 * 3781 * Getter for "AssocStatusCode" property. 3782 */ 3783 dbus_bool_t wpas_dbus_getter_assoc_status_code( 3784 const struct wpa_dbus_property_desc *property_desc, 3785 DBusMessageIter *iter, DBusError *error, void *user_data) 3786 { 3787 struct wpa_supplicant *wpa_s = user_data; 3788 dbus_int32_t status_code = wpa_s->assoc_status_code; 3789 3790 return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_INT32, 3791 &status_code, error); 3792 } 3793 3794 3795 /** 3796 * wpas_dbus_getter_roam_time - Get most recent roam time 3797 * @iter: Pointer to incoming dbus message iter 3798 * @error: Location to store error on failure 3799 * @user_data: Function specific data 3800 * Returns: TRUE on success, FALSE on failure 3801 * 3802 * Getter for "RoamTime" property. 3803 */ 3804 dbus_bool_t wpas_dbus_getter_roam_time( 3805 const struct wpa_dbus_property_desc *property_desc, 3806 DBusMessageIter *iter, DBusError *error, void *user_data) 3807 { 3808 struct wpa_supplicant *wpa_s = user_data; 3809 dbus_uint32_t roam_time = wpa_s->roam_time.sec * 1000 + 3810 wpa_s->roam_time.usec / 1000; 3811 3812 return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT32, 3813 &roam_time, error); 3814 } 3815 3816 3817 /** 3818 * wpas_dbus_getter_roam_complete - Get most recent roam success or failure 3819 * @iter: Pointer to incoming dbus message iter 3820 * @error: Location to store error on failure 3821 * @user_data: Function specific data 3822 * Returns: TRUE on success, FALSE on failure 3823 * 3824 * Getter for "RoamComplete" property. 3825 */ 3826 dbus_bool_t wpas_dbus_getter_roam_complete( 3827 const struct wpa_dbus_property_desc *property_desc, 3828 DBusMessageIter *iter, DBusError *error, void *user_data) 3829 { 3830 struct wpa_supplicant *wpa_s = user_data; 3831 dbus_bool_t roam_complete = os_reltime_initialized(&wpa_s->roam_time); 3832 3833 return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN, 3834 &roam_complete, error); 3835 } 3836 3837 3838 /** 3839 * wpas_dbus_getter_session_length - Get most recent BSS session length 3840 * @iter: Pointer to incoming dbus message iter 3841 * @error: Location to store error on failure 3842 * @user_data: Function specific data 3843 * Returns: TRUE on success, FALSE on failure 3844 * 3845 * Getter for "SessionLength" property. 3846 */ 3847 dbus_bool_t wpas_dbus_getter_session_length( 3848 const struct wpa_dbus_property_desc *property_desc, 3849 DBusMessageIter *iter, DBusError *error, void *user_data) 3850 { 3851 struct wpa_supplicant *wpa_s = user_data; 3852 dbus_uint32_t session_length = wpa_s->session_length.sec * 1000 + 3853 wpa_s->session_length.usec / 1000; 3854 3855 return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT32, 3856 &session_length, error); 3857 } 3858 3859 3860 /** 3861 * wpas_dbus_getter_bss_tm_status - Get most BSS Transition Management request 3862 * status code 3863 * @iter: Pointer to incoming dbus message iter 3864 * @error: Location to store error on failure 3865 * @user_data: Function specific data 3866 * Returns: TRUE on success, FALSE on failure 3867 * 3868 * Getter for "BSSTMStatus" property. 3869 */ 3870 dbus_bool_t wpas_dbus_getter_bss_tm_status( 3871 const struct wpa_dbus_property_desc *property_desc, 3872 DBusMessageIter *iter, DBusError *error, void *user_data) 3873 { 3874 #ifdef CONFIG_WNM 3875 struct wpa_supplicant *wpa_s = user_data; 3876 dbus_uint32_t bss_tm_status = wpa_s->bss_tm_status; 3877 #else /* CONFIG_WNM */ 3878 dbus_uint32_t bss_tm_status = 0; 3879 #endif /* CONFIG_WNM */ 3880 3881 return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT32, 3882 &bss_tm_status, error); 3883 } 3884 3885 3886 /** 3887 * wpas_dbus_getter_bss_expire_age - Get BSS entry expiration age 3888 * @iter: Pointer to incoming dbus message iter 3889 * @error: Location to store error on failure 3890 * @user_data: Function specific data 3891 * Returns: TRUE on success, FALSE on failure 3892 * 3893 * Getter function for "BSSExpireAge" property. 3894 */ 3895 dbus_bool_t wpas_dbus_getter_bss_expire_age( 3896 const struct wpa_dbus_property_desc *property_desc, 3897 DBusMessageIter *iter, DBusError *error, void *user_data) 3898 { 3899 struct wpa_supplicant *wpa_s = user_data; 3900 dbus_uint32_t expire_age = wpa_s->conf->bss_expiration_age; 3901 3902 return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT32, 3903 &expire_age, error); 3904 } 3905 3906 3907 /** 3908 * wpas_dbus_setter_bss_expire_age - Control BSS entry expiration age 3909 * @iter: Pointer to incoming dbus message iter 3910 * @error: Location to store error on failure 3911 * @user_data: Function specific data 3912 * Returns: TRUE on success, FALSE on failure 3913 * 3914 * Setter function for "BSSExpireAge" property. 3915 */ 3916 dbus_bool_t wpas_dbus_setter_bss_expire_age( 3917 const struct wpa_dbus_property_desc *property_desc, 3918 DBusMessageIter *iter, DBusError *error, void *user_data) 3919 { 3920 struct wpa_supplicant *wpa_s = user_data; 3921 dbus_uint32_t expire_age; 3922 3923 if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_UINT32, 3924 &expire_age)) 3925 return FALSE; 3926 3927 if (wpa_supplicant_set_bss_expiration_age(wpa_s, expire_age)) { 3928 dbus_set_error_const(error, DBUS_ERROR_FAILED, 3929 "BSSExpireAge must be >= 10"); 3930 return FALSE; 3931 } 3932 return TRUE; 3933 } 3934 3935 3936 /** 3937 * wpas_dbus_getter_bss_expire_count - Get BSS entry expiration scan count 3938 * @iter: Pointer to incoming dbus message iter 3939 * @error: Location to store error on failure 3940 * @user_data: Function specific data 3941 * Returns: TRUE on success, FALSE on failure 3942 * 3943 * Getter function for "BSSExpireCount" property. 3944 */ 3945 dbus_bool_t wpas_dbus_getter_bss_expire_count( 3946 const struct wpa_dbus_property_desc *property_desc, 3947 DBusMessageIter *iter, DBusError *error, void *user_data) 3948 { 3949 struct wpa_supplicant *wpa_s = user_data; 3950 dbus_uint32_t expire_count = wpa_s->conf->bss_expiration_scan_count; 3951 3952 return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT32, 3953 &expire_count, error); 3954 } 3955 3956 3957 /** 3958 * wpas_dbus_setter_bss_expire_count - Control BSS entry expiration scan count 3959 * @iter: Pointer to incoming dbus message iter 3960 * @error: Location to store error on failure 3961 * @user_data: Function specific data 3962 * Returns: TRUE on success, FALSE on failure 3963 * 3964 * Setter function for "BSSExpireCount" property. 3965 */ 3966 dbus_bool_t wpas_dbus_setter_bss_expire_count( 3967 const struct wpa_dbus_property_desc *property_desc, 3968 DBusMessageIter *iter, DBusError *error, void *user_data) 3969 { 3970 struct wpa_supplicant *wpa_s = user_data; 3971 dbus_uint32_t expire_count; 3972 3973 if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_UINT32, 3974 &expire_count)) 3975 return FALSE; 3976 3977 if (wpa_supplicant_set_bss_expiration_count(wpa_s, expire_count)) { 3978 dbus_set_error_const(error, DBUS_ERROR_FAILED, 3979 "BSSExpireCount must be > 0"); 3980 return FALSE; 3981 } 3982 return TRUE; 3983 } 3984 3985 3986 /** 3987 * wpas_dbus_getter_country - Control country code 3988 * @iter: Pointer to incoming dbus message iter 3989 * @error: Location to store error on failure 3990 * @user_data: Function specific data 3991 * Returns: TRUE on success, FALSE on failure 3992 * 3993 * Getter function for "Country" property. 3994 */ 3995 dbus_bool_t wpas_dbus_getter_country( 3996 const struct wpa_dbus_property_desc *property_desc, 3997 DBusMessageIter *iter, DBusError *error, void *user_data) 3998 { 3999 struct wpa_supplicant *wpa_s = user_data; 4000 char country[3]; 4001 char *str = country; 4002 4003 country[0] = wpa_s->conf->country[0]; 4004 country[1] = wpa_s->conf->country[1]; 4005 country[2] = '\0'; 4006 4007 return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING, 4008 &str, error); 4009 } 4010 4011 4012 /** 4013 * wpas_dbus_setter_country - Control country code 4014 * @iter: Pointer to incoming dbus message iter 4015 * @error: Location to store error on failure 4016 * @user_data: Function specific data 4017 * Returns: TRUE on success, FALSE on failure 4018 * 4019 * Setter function for "Country" property. 4020 */ 4021 dbus_bool_t wpas_dbus_setter_country( 4022 const struct wpa_dbus_property_desc *property_desc, 4023 DBusMessageIter *iter, DBusError *error, void *user_data) 4024 { 4025 struct wpa_supplicant *wpa_s = user_data; 4026 const char *country; 4027 4028 if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_STRING, 4029 &country)) 4030 return FALSE; 4031 4032 if (!country[0] || !country[1]) { 4033 dbus_set_error_const(error, DBUS_ERROR_FAILED, 4034 "invalid country code"); 4035 return FALSE; 4036 } 4037 4038 if (wpa_s->drv_priv != NULL && wpa_drv_set_country(wpa_s, country)) { 4039 wpa_printf(MSG_DEBUG, "Failed to set country"); 4040 dbus_set_error_const(error, DBUS_ERROR_FAILED, 4041 "failed to set country code"); 4042 return FALSE; 4043 } 4044 4045 wpa_s->conf->country[0] = country[0]; 4046 wpa_s->conf->country[1] = country[1]; 4047 return TRUE; 4048 } 4049 4050 4051 /** 4052 * wpas_dbus_getter_scan_interval - Get scan interval 4053 * @iter: Pointer to incoming dbus message iter 4054 * @error: Location to store error on failure 4055 * @user_data: Function specific data 4056 * Returns: TRUE on success, FALSE on failure 4057 * 4058 * Getter function for "ScanInterval" property. 4059 */ 4060 dbus_bool_t wpas_dbus_getter_scan_interval( 4061 const struct wpa_dbus_property_desc *property_desc, 4062 DBusMessageIter *iter, DBusError *error, void *user_data) 4063 { 4064 struct wpa_supplicant *wpa_s = user_data; 4065 dbus_int32_t scan_interval = wpa_s->scan_interval; 4066 4067 return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_INT32, 4068 &scan_interval, error); 4069 } 4070 4071 4072 /** 4073 * wpas_dbus_setter_scan_interval - Control scan interval 4074 * @iter: Pointer to incoming dbus message iter 4075 * @error: Location to store error on failure 4076 * @user_data: Function specific data 4077 * Returns: TRUE on success, FALSE on failure 4078 * 4079 * Setter function for "ScanInterval" property. 4080 */ 4081 dbus_bool_t wpas_dbus_setter_scan_interval( 4082 const struct wpa_dbus_property_desc *property_desc, 4083 DBusMessageIter *iter, DBusError *error, void *user_data) 4084 { 4085 struct wpa_supplicant *wpa_s = user_data; 4086 dbus_int32_t scan_interval; 4087 4088 if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_INT32, 4089 &scan_interval)) 4090 return FALSE; 4091 4092 if (wpa_supplicant_set_scan_interval(wpa_s, scan_interval)) { 4093 dbus_set_error_const(error, DBUS_ERROR_FAILED, 4094 "scan_interval must be >= 0"); 4095 return FALSE; 4096 } 4097 return TRUE; 4098 } 4099 4100 4101 /** 4102 * wpas_dbus_getter_ifname - Get interface name 4103 * @iter: Pointer to incoming dbus message iter 4104 * @error: Location to store error on failure 4105 * @user_data: Function specific data 4106 * Returns: TRUE on success, FALSE on failure 4107 * 4108 * Getter for "Ifname" property. 4109 */ 4110 dbus_bool_t wpas_dbus_getter_ifname( 4111 const struct wpa_dbus_property_desc *property_desc, 4112 DBusMessageIter *iter, DBusError *error, void *user_data) 4113 { 4114 struct wpa_supplicant *wpa_s = user_data; 4115 4116 return wpas_dbus_string_property_getter(iter, wpa_s->ifname, error); 4117 } 4118 4119 4120 /** 4121 * wpas_dbus_getter_driver - Get interface name 4122 * @iter: Pointer to incoming dbus message iter 4123 * @error: Location to store error on failure 4124 * @user_data: Function specific data 4125 * Returns: TRUE on success, FALSE on failure 4126 * 4127 * Getter for "Driver" property. 4128 */ 4129 dbus_bool_t wpas_dbus_getter_driver( 4130 const struct wpa_dbus_property_desc *property_desc, 4131 DBusMessageIter *iter, DBusError *error, void *user_data) 4132 { 4133 struct wpa_supplicant *wpa_s = user_data; 4134 4135 if (wpa_s->driver == NULL || wpa_s->driver->name == NULL) { 4136 wpa_printf(MSG_DEBUG, "%s[dbus]: wpa_s has no driver set", 4137 __func__); 4138 dbus_set_error(error, DBUS_ERROR_FAILED, "%s: no driver set", 4139 __func__); 4140 return FALSE; 4141 } 4142 4143 return wpas_dbus_string_property_getter(iter, wpa_s->driver->name, 4144 error); 4145 } 4146 4147 4148 /** 4149 * wpas_dbus_getter_current_bss - Get current bss object path 4150 * @iter: Pointer to incoming dbus message iter 4151 * @error: Location to store error on failure 4152 * @user_data: Function specific data 4153 * Returns: TRUE on success, FALSE on failure 4154 * 4155 * Getter for "CurrentBSS" property. 4156 */ 4157 dbus_bool_t wpas_dbus_getter_current_bss( 4158 const struct wpa_dbus_property_desc *property_desc, 4159 DBusMessageIter *iter, DBusError *error, void *user_data) 4160 { 4161 struct wpa_supplicant *wpa_s = user_data; 4162 char path_buf[WPAS_DBUS_OBJECT_PATH_MAX], *bss_obj_path = path_buf; 4163 4164 if (wpa_s->current_bss && wpa_s->dbus_new_path) 4165 os_snprintf(bss_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, 4166 "%s/" WPAS_DBUS_NEW_BSSIDS_PART "/%u", 4167 wpa_s->dbus_new_path, wpa_s->current_bss->id); 4168 else 4169 os_snprintf(bss_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, "/"); 4170 4171 return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_OBJECT_PATH, 4172 &bss_obj_path, error); 4173 } 4174 4175 4176 /** 4177 * wpas_dbus_getter_current_network - Get current network object path 4178 * @iter: Pointer to incoming dbus message iter 4179 * @error: Location to store error on failure 4180 * @user_data: Function specific data 4181 * Returns: TRUE on success, FALSE on failure 4182 * 4183 * Getter for "CurrentNetwork" property. 4184 */ 4185 dbus_bool_t wpas_dbus_getter_current_network( 4186 const struct wpa_dbus_property_desc *property_desc, 4187 DBusMessageIter *iter, DBusError *error, void *user_data) 4188 { 4189 struct wpa_supplicant *wpa_s = user_data; 4190 char path_buf[WPAS_DBUS_OBJECT_PATH_MAX], *net_obj_path = path_buf; 4191 4192 if (wpa_s->current_ssid && wpa_s->dbus_new_path) 4193 os_snprintf(net_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, 4194 "%s/" WPAS_DBUS_NEW_NETWORKS_PART "/%u", 4195 wpa_s->dbus_new_path, wpa_s->current_ssid->id); 4196 else 4197 os_snprintf(net_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, "/"); 4198 4199 return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_OBJECT_PATH, 4200 &net_obj_path, error); 4201 } 4202 4203 4204 /** 4205 * wpas_dbus_getter_current_auth_mode - Get current authentication type 4206 * @iter: Pointer to incoming dbus message iter 4207 * @error: Location to store error on failure 4208 * @user_data: Function specific data 4209 * Returns: TRUE on success, FALSE on failure 4210 * 4211 * Getter for "CurrentAuthMode" property. 4212 */ 4213 dbus_bool_t wpas_dbus_getter_current_auth_mode( 4214 const struct wpa_dbus_property_desc *property_desc, 4215 DBusMessageIter *iter, DBusError *error, void *user_data) 4216 { 4217 struct wpa_supplicant *wpa_s = user_data; 4218 const char *eap_mode; 4219 const char *auth_mode; 4220 char eap_mode_buf[WPAS_DBUS_AUTH_MODE_MAX]; 4221 4222 if (wpa_s->wpa_state <= WPA_SCANNING) { 4223 auth_mode = "INACTIVE"; 4224 } else if (wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X || 4225 wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) { 4226 eap_mode = wpa_supplicant_get_eap_mode(wpa_s); 4227 os_snprintf(eap_mode_buf, WPAS_DBUS_AUTH_MODE_MAX, 4228 "EAP-%s", eap_mode); 4229 auth_mode = eap_mode_buf; 4230 4231 } else if (wpa_s->current_ssid) { 4232 auth_mode = wpa_key_mgmt_txt(wpa_s->key_mgmt, 4233 wpa_s->current_ssid->proto); 4234 } else { 4235 auth_mode = "UNKNOWN"; 4236 } 4237 4238 return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING, 4239 &auth_mode, error); 4240 } 4241 4242 4243 /** 4244 * wpas_dbus_getter_bridge_ifname - Get interface name 4245 * @iter: Pointer to incoming dbus message iter 4246 * @error: Location to store error on failure 4247 * @user_data: Function specific data 4248 * Returns: TRUE on success, FALSE on failure 4249 * 4250 * Getter for "BridgeIfname" property. 4251 */ 4252 dbus_bool_t wpas_dbus_getter_bridge_ifname( 4253 const struct wpa_dbus_property_desc *property_desc, 4254 DBusMessageIter *iter, DBusError *error, void *user_data) 4255 { 4256 struct wpa_supplicant *wpa_s = user_data; 4257 4258 return wpas_dbus_string_property_getter(iter, wpa_s->bridge_ifname, 4259 error); 4260 } 4261 4262 4263 dbus_bool_t wpas_dbus_setter_bridge_ifname( 4264 const struct wpa_dbus_property_desc *property_desc, 4265 DBusMessageIter *iter, DBusError *error, void *user_data) 4266 { 4267 struct wpa_supplicant *wpa_s = user_data; 4268 const char *bridge_ifname = NULL; 4269 const char *msg; 4270 int r; 4271 4272 if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_STRING, 4273 &bridge_ifname)) 4274 return FALSE; 4275 4276 r = wpa_supplicant_update_bridge_ifname(wpa_s, bridge_ifname); 4277 if (r != 0) { 4278 switch (r) { 4279 case -EINVAL: 4280 msg = "invalid interface name"; 4281 break; 4282 case -EBUSY: 4283 msg = "interface is busy"; 4284 break; 4285 case -EIO: 4286 msg = "socket error"; 4287 break; 4288 default: 4289 msg = "unknown error"; 4290 break; 4291 } 4292 dbus_set_error_const(error, DBUS_ERROR_FAILED, msg); 4293 return FALSE; 4294 } 4295 4296 return TRUE; 4297 } 4298 4299 4300 /** 4301 * wpas_dbus_getter_config_file - Get interface configuration file path 4302 * @iter: Pointer to incoming dbus message iter 4303 * @error: Location to store error on failure 4304 * @user_data: Function specific data 4305 * Returns: TRUE on success, FALSE on failure 4306 * 4307 * Getter for "ConfigFile" property. 4308 */ 4309 dbus_bool_t wpas_dbus_getter_config_file( 4310 const struct wpa_dbus_property_desc *property_desc, 4311 DBusMessageIter *iter, DBusError *error, void *user_data) 4312 { 4313 struct wpa_supplicant *wpa_s = user_data; 4314 4315 return wpas_dbus_string_property_getter(iter, wpa_s->confname, error); 4316 } 4317 4318 4319 /** 4320 * wpas_dbus_getter_bsss - Get array of BSSs objects 4321 * @iter: Pointer to incoming dbus message iter 4322 * @error: Location to store error on failure 4323 * @user_data: Function specific data 4324 * Returns: TRUE on success, FALSE on failure 4325 * 4326 * Getter for "BSSs" property. 4327 */ 4328 dbus_bool_t wpas_dbus_getter_bsss( 4329 const struct wpa_dbus_property_desc *property_desc, 4330 DBusMessageIter *iter, DBusError *error, void *user_data) 4331 { 4332 struct wpa_supplicant *wpa_s = user_data; 4333 struct wpa_bss *bss; 4334 char **paths; 4335 unsigned int i = 0; 4336 dbus_bool_t success = FALSE; 4337 4338 if (!wpa_s->dbus_new_path) { 4339 dbus_set_error(error, DBUS_ERROR_FAILED, 4340 "%s: no D-Bus interface", __func__); 4341 return FALSE; 4342 } 4343 4344 paths = os_calloc(wpa_s->num_bss, sizeof(char *)); 4345 if (!paths) { 4346 dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory"); 4347 return FALSE; 4348 } 4349 4350 /* Loop through scan results and append each result's object path */ 4351 dl_list_for_each(bss, &wpa_s->bss_id, struct wpa_bss, list_id) { 4352 paths[i] = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX); 4353 if (paths[i] == NULL) { 4354 dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, 4355 "no memory"); 4356 goto out; 4357 } 4358 /* Construct the object path for this BSS. */ 4359 os_snprintf(paths[i++], WPAS_DBUS_OBJECT_PATH_MAX, 4360 "%s/" WPAS_DBUS_NEW_BSSIDS_PART "/%u", 4361 wpa_s->dbus_new_path, bss->id); 4362 } 4363 4364 success = wpas_dbus_simple_array_property_getter(iter, 4365 DBUS_TYPE_OBJECT_PATH, 4366 paths, wpa_s->num_bss, 4367 error); 4368 4369 out: 4370 while (i) 4371 os_free(paths[--i]); 4372 os_free(paths); 4373 return success; 4374 } 4375 4376 4377 /** 4378 * wpas_dbus_getter_networks - Get array of networks objects 4379 * @iter: Pointer to incoming dbus message iter 4380 * @error: Location to store error on failure 4381 * @user_data: Function specific data 4382 * Returns: TRUE on success, FALSE on failure 4383 * 4384 * Getter for "Networks" property. 4385 */ 4386 dbus_bool_t wpas_dbus_getter_networks( 4387 const struct wpa_dbus_property_desc *property_desc, 4388 DBusMessageIter *iter, DBusError *error, void *user_data) 4389 { 4390 struct wpa_supplicant *wpa_s = user_data; 4391 struct wpa_ssid *ssid; 4392 char **paths; 4393 unsigned int i = 0, num = 0; 4394 dbus_bool_t success = FALSE; 4395 4396 if (!wpa_s->dbus_new_path) { 4397 dbus_set_error(error, DBUS_ERROR_FAILED, 4398 "%s: no D-Bus interface", __func__); 4399 return FALSE; 4400 } 4401 4402 for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) 4403 if (!network_is_persistent_group(ssid)) 4404 num++; 4405 4406 paths = os_calloc(num, sizeof(char *)); 4407 if (!paths) { 4408 dbus_set_error(error, DBUS_ERROR_NO_MEMORY, "no memory"); 4409 return FALSE; 4410 } 4411 4412 /* Loop through configured networks and append object path of each */ 4413 for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) { 4414 if (network_is_persistent_group(ssid)) 4415 continue; 4416 paths[i] = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX); 4417 if (paths[i] == NULL) { 4418 dbus_set_error(error, DBUS_ERROR_NO_MEMORY, 4419 "no memory"); 4420 goto out; 4421 } 4422 4423 /* Construct the object path for this network. */ 4424 os_snprintf(paths[i++], WPAS_DBUS_OBJECT_PATH_MAX, 4425 "%s/" WPAS_DBUS_NEW_NETWORKS_PART "/%d", 4426 wpa_s->dbus_new_path, ssid->id); 4427 } 4428 4429 success = wpas_dbus_simple_array_property_getter(iter, 4430 DBUS_TYPE_OBJECT_PATH, 4431 paths, num, error); 4432 4433 out: 4434 while (i) 4435 os_free(paths[--i]); 4436 os_free(paths); 4437 return success; 4438 } 4439 4440 4441 /** 4442 * wpas_dbus_getter_pkcs11_engine_path - Get PKCS #11 engine path 4443 * @iter: Pointer to incoming dbus message iter 4444 * @error: Location to store error on failure 4445 * @user_data: Function specific data 4446 * Returns: A dbus message containing the PKCS #11 engine path 4447 * 4448 * Getter for "PKCS11EnginePath" property. 4449 */ 4450 dbus_bool_t wpas_dbus_getter_pkcs11_engine_path( 4451 const struct wpa_dbus_property_desc *property_desc, 4452 DBusMessageIter *iter, DBusError *error, void *user_data) 4453 { 4454 4455 #ifndef CONFIG_PKCS11_ENGINE_PATH 4456 struct wpa_supplicant *wpa_s = user_data; 4457 4458 return wpas_dbus_string_property_getter(iter, 4459 wpa_s->conf->pkcs11_engine_path, 4460 error); 4461 #else /* CONFIG_PKCS11_ENGINE_PATH */ 4462 return wpas_dbus_string_property_getter(iter, 4463 CONFIG_PKCS11_ENGINE_PATH, 4464 error); 4465 #endif /* CONFIG_PKCS11_ENGINE_PATH */ 4466 } 4467 4468 4469 /** 4470 * wpas_dbus_getter_pkcs11_module_path - Get PKCS #11 module path 4471 * @iter: Pointer to incoming dbus message iter 4472 * @error: Location to store error on failure 4473 * @user_data: Function specific data 4474 * Returns: A dbus message containing the PKCS #11 module path 4475 * 4476 * Getter for "PKCS11ModulePath" property. 4477 */ 4478 dbus_bool_t wpas_dbus_getter_pkcs11_module_path( 4479 const struct wpa_dbus_property_desc *property_desc, 4480 DBusMessageIter *iter, DBusError *error, void *user_data) 4481 { 4482 #ifndef CONFIG_PKCS11_MODULE_PATH 4483 struct wpa_supplicant *wpa_s = user_data; 4484 4485 return wpas_dbus_string_property_getter(iter, 4486 wpa_s->conf->pkcs11_module_path, 4487 error); 4488 #else /* CONFIG_PKCS11_MODULE_PATH */ 4489 return wpas_dbus_string_property_getter(iter, 4490 CONFIG_PKCS11_MODULE_PATH, 4491 error); 4492 #endif /* CONFIG_PKCS11_MODULE_PATH */ 4493 } 4494 4495 4496 /** 4497 * wpas_dbus_getter_blobs - Get all blobs defined for this interface 4498 * @iter: Pointer to incoming dbus message iter 4499 * @error: Location to store error on failure 4500 * @user_data: Function specific data 4501 * Returns: TRUE on success, FALSE on failure 4502 * 4503 * Getter for "Blobs" property. 4504 */ 4505 dbus_bool_t wpas_dbus_getter_blobs( 4506 const struct wpa_dbus_property_desc *property_desc, 4507 DBusMessageIter *iter, DBusError *error, void *user_data) 4508 { 4509 struct wpa_supplicant *wpa_s = user_data; 4510 DBusMessageIter variant_iter, dict_iter, entry_iter, array_iter; 4511 struct wpa_config_blob *blob; 4512 4513 if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, 4514 "a{say}", &variant_iter) || 4515 !dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY, 4516 "{say}", &dict_iter)) { 4517 dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory"); 4518 return FALSE; 4519 } 4520 4521 blob = wpa_s->conf->blobs; 4522 while (blob) { 4523 if (!dbus_message_iter_open_container(&dict_iter, 4524 DBUS_TYPE_DICT_ENTRY, 4525 NULL, &entry_iter) || 4526 !dbus_message_iter_append_basic(&entry_iter, 4527 DBUS_TYPE_STRING, 4528 &(blob->name)) || 4529 !dbus_message_iter_open_container(&entry_iter, 4530 DBUS_TYPE_ARRAY, 4531 DBUS_TYPE_BYTE_AS_STRING, 4532 &array_iter) || 4533 !dbus_message_iter_append_fixed_array(&array_iter, 4534 DBUS_TYPE_BYTE, 4535 &(blob->data), 4536 blob->len) || 4537 !dbus_message_iter_close_container(&entry_iter, 4538 &array_iter) || 4539 !dbus_message_iter_close_container(&dict_iter, 4540 &entry_iter)) { 4541 dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, 4542 "no memory"); 4543 return FALSE; 4544 } 4545 4546 blob = blob->next; 4547 } 4548 4549 if (!dbus_message_iter_close_container(&variant_iter, &dict_iter) || 4550 !dbus_message_iter_close_container(iter, &variant_iter)) { 4551 dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory"); 4552 return FALSE; 4553 } 4554 4555 return TRUE; 4556 } 4557 4558 4559 dbus_bool_t wpas_dbus_getter_iface_global( 4560 const struct wpa_dbus_property_desc *property_desc, 4561 DBusMessageIter *iter, DBusError *error, void *user_data) 4562 { 4563 struct wpa_supplicant *wpa_s = user_data; 4564 int ret; 4565 char buf[250]; 4566 char *p = buf; 4567 4568 if (!property_desc->data) { 4569 dbus_set_error(error, DBUS_ERROR_INVALID_ARGS, 4570 "Unhandled interface property %s", 4571 property_desc->dbus_property); 4572 return FALSE; 4573 } 4574 4575 ret = wpa_config_get_value(property_desc->data, wpa_s->conf, buf, 4576 sizeof(buf)); 4577 if (ret < 0) 4578 *p = '\0'; 4579 4580 return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING, &p, 4581 error); 4582 } 4583 4584 4585 dbus_bool_t wpas_dbus_setter_iface_global( 4586 const struct wpa_dbus_property_desc *property_desc, 4587 DBusMessageIter *iter, DBusError *error, void *user_data) 4588 { 4589 struct wpa_supplicant *wpa_s = user_data; 4590 const char *new_value = NULL; 4591 char buf[250]; 4592 size_t combined_len; 4593 int wpa_sm_param; 4594 int ret; 4595 4596 if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_STRING, 4597 &new_value)) 4598 return FALSE; 4599 4600 combined_len = os_strlen(property_desc->data) + os_strlen(new_value) + 4601 3; 4602 if (combined_len >= sizeof(buf)) { 4603 dbus_set_error(error, DBUS_ERROR_INVALID_ARGS, 4604 "Interface property %s value too large", 4605 property_desc->dbus_property); 4606 return FALSE; 4607 } 4608 4609 if (!new_value[0]) 4610 new_value = "NULL"; 4611 4612 wpa_sm_param = -1; 4613 if (os_strcmp(property_desc->data, "dot11RSNAConfigPMKLifetime") == 0) 4614 wpa_sm_param = RSNA_PMK_LIFETIME; 4615 else if (os_strcmp(property_desc->data, 4616 "dot11RSNAConfigPMKReauthThreshold") == 0) 4617 wpa_sm_param = RSNA_PMK_REAUTH_THRESHOLD; 4618 else if (os_strcmp(property_desc->data, "dot11RSNAConfigSATimeout") == 0) 4619 wpa_sm_param = RSNA_SA_TIMEOUT; 4620 4621 if (wpa_sm_param != -1) { 4622 char *end; 4623 int val; 4624 4625 val = strtol(new_value, &end, 0); 4626 if (*end) { 4627 dbus_set_error(error, DBUS_ERROR_INVALID_ARGS, 4628 "Invalid value for property %s", 4629 property_desc->dbus_property); 4630 return FALSE; 4631 } 4632 4633 if (wpa_sm_set_param(wpa_s->wpa, wpa_sm_param, val)) { 4634 dbus_set_error(error, DBUS_ERROR_INVALID_ARGS, 4635 "Failed to apply interface property %s", 4636 property_desc->dbus_property); 4637 return FALSE; 4638 } 4639 } 4640 4641 ret = os_snprintf(buf, combined_len, "%s=%s", property_desc->data, 4642 new_value); 4643 if (os_snprintf_error(combined_len, ret)) { 4644 dbus_set_error(error, WPAS_DBUS_ERROR_UNKNOWN_ERROR, 4645 "Failed to construct new interface property %s", 4646 property_desc->dbus_property); 4647 return FALSE; 4648 } 4649 4650 ret = wpa_config_process_global(wpa_s->conf, buf, -1); 4651 if (ret < 0) { 4652 dbus_set_error(error, DBUS_ERROR_INVALID_ARGS, 4653 "Failed to set interface property %s", 4654 property_desc->dbus_property); 4655 return FALSE; 4656 } else if (ret == 0) { 4657 wpa_supplicant_update_config(wpa_s); 4658 } 4659 return TRUE; 4660 } 4661 4662 4663 /** 4664 * wpas_dbus_getter_stas - Get connected stations for an interface 4665 * @iter: Pointer to incoming dbus message iter 4666 * @error: Location to store error on failure 4667 * @user_data: Function specific data 4668 * Returns: a list of stations 4669 * 4670 * Getter for "Stations" property. 4671 */ 4672 dbus_bool_t wpas_dbus_getter_stas( 4673 const struct wpa_dbus_property_desc *property_desc, 4674 DBusMessageIter *iter, DBusError *error, void *user_data) 4675 { 4676 struct wpa_supplicant *wpa_s = user_data; 4677 struct sta_info *sta = NULL; 4678 char **paths = NULL; 4679 unsigned int i = 0, num = 0; 4680 dbus_bool_t success = FALSE; 4681 4682 if (!wpa_s->dbus_new_path) { 4683 dbus_set_error(error, DBUS_ERROR_FAILED, 4684 "%s: no D-Bus interface", __func__); 4685 return FALSE; 4686 } 4687 4688 #ifdef CONFIG_AP 4689 if (wpa_s->ap_iface) { 4690 struct hostapd_data *hapd; 4691 4692 hapd = wpa_s->ap_iface->bss[0]; 4693 sta = hapd->sta_list; 4694 num = hapd->num_sta; 4695 } 4696 #endif /* CONFIG_AP */ 4697 4698 paths = os_calloc(num, sizeof(char *)); 4699 if (!paths) { 4700 dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory"); 4701 return FALSE; 4702 } 4703 4704 /* Loop through scan results and append each result's object path */ 4705 for (; sta; sta = sta->next) { 4706 paths[i] = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX); 4707 if (!paths[i]) { 4708 dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, 4709 "no memory"); 4710 goto out; 4711 } 4712 /* Construct the object path for this BSS. */ 4713 os_snprintf(paths[i++], WPAS_DBUS_OBJECT_PATH_MAX, 4714 "%s/" WPAS_DBUS_NEW_STAS_PART "/" COMPACT_MACSTR, 4715 wpa_s->dbus_new_path, MAC2STR(sta->addr)); 4716 } 4717 4718 success = wpas_dbus_simple_array_property_getter(iter, 4719 DBUS_TYPE_OBJECT_PATH, 4720 paths, num, 4721 error); 4722 4723 out: 4724 while (i) 4725 os_free(paths[--i]); 4726 os_free(paths); 4727 return success; 4728 } 4729 4730 4731 /** 4732 * wpas_dbus_setter_mac_address_randomization_mask - Set masks used for 4733 * MAC address randomization 4734 * @iter: Pointer to incoming dbus message iter 4735 * @error: Location to store error on failure 4736 * @user_data: Function specific data 4737 * Returns: TRUE on success, FALSE on failure 4738 * 4739 * Setter for "MACAddressRandomizationMask" property. 4740 */ 4741 dbus_bool_t wpas_dbus_setter_mac_address_randomization_mask( 4742 const struct wpa_dbus_property_desc *property_desc, 4743 DBusMessageIter *iter, DBusError *error, void *user_data) 4744 { 4745 struct wpa_supplicant *wpa_s = user_data; 4746 DBusMessageIter variant_iter, dict_iter, entry_iter, array_iter; 4747 const char *key; 4748 unsigned int rand_type = 0; 4749 const u8 *mask; 4750 int mask_len; 4751 unsigned int rand_types_to_disable = MAC_ADDR_RAND_ALL; 4752 4753 dbus_message_iter_recurse(iter, &variant_iter); 4754 if (dbus_message_iter_get_arg_type(&variant_iter) != DBUS_TYPE_ARRAY) { 4755 dbus_set_error_const(error, DBUS_ERROR_INVALID_ARGS, 4756 "invalid message format"); 4757 return FALSE; 4758 } 4759 dbus_message_iter_recurse(&variant_iter, &dict_iter); 4760 while (dbus_message_iter_get_arg_type(&dict_iter) == 4761 DBUS_TYPE_DICT_ENTRY) { 4762 dbus_message_iter_recurse(&dict_iter, &entry_iter); 4763 if (dbus_message_iter_get_arg_type(&entry_iter) != 4764 DBUS_TYPE_STRING) { 4765 dbus_set_error(error, DBUS_ERROR_FAILED, 4766 "%s: key not a string", __func__); 4767 return FALSE; 4768 } 4769 dbus_message_iter_get_basic(&entry_iter, &key); 4770 dbus_message_iter_next(&entry_iter); 4771 if (dbus_message_iter_get_arg_type(&entry_iter) != 4772 DBUS_TYPE_ARRAY || 4773 dbus_message_iter_get_element_type(&entry_iter) != 4774 DBUS_TYPE_BYTE) { 4775 dbus_set_error(error, DBUS_ERROR_FAILED, 4776 "%s: mask was not a byte array", 4777 __func__); 4778 return FALSE; 4779 } 4780 dbus_message_iter_recurse(&entry_iter, &array_iter); 4781 dbus_message_iter_get_fixed_array(&array_iter, &mask, 4782 &mask_len); 4783 4784 if (os_strcmp(key, "scan") == 0) { 4785 rand_type = MAC_ADDR_RAND_SCAN; 4786 } else if (os_strcmp(key, "sched_scan") == 0) { 4787 rand_type = MAC_ADDR_RAND_SCHED_SCAN; 4788 } else if (os_strcmp(key, "pno") == 0) { 4789 rand_type = MAC_ADDR_RAND_PNO; 4790 } else { 4791 dbus_set_error(error, DBUS_ERROR_FAILED, 4792 "%s: bad scan type \"%s\"", 4793 __func__, key); 4794 return FALSE; 4795 } 4796 4797 if (mask_len != ETH_ALEN) { 4798 dbus_set_error(error, DBUS_ERROR_FAILED, 4799 "%s: malformed MAC mask given", 4800 __func__); 4801 return FALSE; 4802 } 4803 4804 if (wpas_enable_mac_addr_randomization( 4805 wpa_s, rand_type, wpa_s->perm_addr, mask)) { 4806 dbus_set_error(error, DBUS_ERROR_FAILED, 4807 "%s: failed to set up MAC address randomization for %s", 4808 __func__, key); 4809 return FALSE; 4810 } 4811 4812 wpa_printf(MSG_DEBUG, 4813 "%s: Enabled MAC address randomization for %s with mask: " 4814 MACSTR, wpa_s->ifname, key, MAC2STR(mask)); 4815 rand_types_to_disable &= ~rand_type; 4816 dbus_message_iter_next(&dict_iter); 4817 } 4818 4819 if (rand_types_to_disable && 4820 wpas_disable_mac_addr_randomization(wpa_s, rand_types_to_disable)) { 4821 dbus_set_error(error, DBUS_ERROR_FAILED, 4822 "%s: failed to disable MAC address randomization", 4823 __func__); 4824 return FALSE; 4825 } 4826 4827 return TRUE; 4828 } 4829 4830 4831 dbus_bool_t wpas_dbus_getter_mac_address_randomization_mask( 4832 const struct wpa_dbus_property_desc *property_desc, 4833 DBusMessageIter *iter, DBusError *error, void *user_data) 4834 { 4835 struct wpa_supplicant *wpa_s = user_data; 4836 DBusMessageIter variant_iter, dict_iter, entry_iter, array_iter; 4837 unsigned int i; 4838 u8 mask_buf[ETH_ALEN]; 4839 /* Read docs on dbus_message_iter_append_fixed_array() for why this 4840 * is necessary... */ 4841 u8 *mask = mask_buf; 4842 static const struct { 4843 const char *key; 4844 unsigned int type; 4845 } types[] = { 4846 { "scan", MAC_ADDR_RAND_SCAN }, 4847 { "sched_scan", MAC_ADDR_RAND_SCHED_SCAN }, 4848 { "pno", MAC_ADDR_RAND_PNO } 4849 }; 4850 4851 if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, 4852 "a{say}", &variant_iter) || 4853 !dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY, 4854 "{say}", &dict_iter)) { 4855 dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory"); 4856 return FALSE; 4857 } 4858 4859 for (i = 0; i < ARRAY_SIZE(types); i++) { 4860 if (wpas_mac_addr_rand_scan_get_mask(wpa_s, types[i].type, 4861 mask)) 4862 continue; 4863 4864 if (!dbus_message_iter_open_container(&dict_iter, 4865 DBUS_TYPE_DICT_ENTRY, 4866 NULL, &entry_iter) || 4867 !dbus_message_iter_append_basic(&entry_iter, 4868 DBUS_TYPE_STRING, 4869 &types[i].key) || 4870 !dbus_message_iter_open_container(&entry_iter, 4871 DBUS_TYPE_ARRAY, 4872 DBUS_TYPE_BYTE_AS_STRING, 4873 &array_iter) || 4874 !dbus_message_iter_append_fixed_array(&array_iter, 4875 DBUS_TYPE_BYTE, 4876 &mask, 4877 ETH_ALEN) || 4878 !dbus_message_iter_close_container(&entry_iter, 4879 &array_iter) || 4880 !dbus_message_iter_close_container(&dict_iter, 4881 &entry_iter)) { 4882 dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, 4883 "no memory"); 4884 return FALSE; 4885 } 4886 } 4887 4888 if (!dbus_message_iter_close_container(&variant_iter, &dict_iter) || 4889 !dbus_message_iter_close_container(iter, &variant_iter)) { 4890 dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory"); 4891 return FALSE; 4892 } 4893 4894 return TRUE; 4895 } 4896 4897 4898 /** 4899 * wpas_dbus_getter_mac_address - Get MAC address of an interface 4900 * @iter: Pointer to incoming dbus message iter 4901 * @error: Location to store error on failure 4902 * @user_data: Function specific data 4903 * Returns: a list of stations 4904 * 4905 * Getter for "MACAddress" property. 4906 */ 4907 dbus_bool_t wpas_dbus_getter_mac_address( 4908 const struct wpa_dbus_property_desc *property_desc, 4909 DBusMessageIter *iter, DBusError *error, void *user_data) 4910 { 4911 struct wpa_supplicant *wpa_s = user_data; 4912 4913 return wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE, 4914 wpa_s->own_addr, ETH_ALEN, 4915 error); 4916 } 4917 4918 4919 /** 4920 * wpas_dbus_getter_sta_address - Return the address of a connected station 4921 * @iter: Pointer to incoming dbus message iter 4922 * @error: Location to store error on failure 4923 * @user_data: Function specific data 4924 * Returns: TRUE on success, FALSE on failure 4925 * 4926 * Getter for "Address" property. 4927 */ 4928 dbus_bool_t wpas_dbus_getter_sta_address( 4929 const struct wpa_dbus_property_desc *property_desc, 4930 DBusMessageIter *iter, DBusError *error, void *user_data) 4931 { 4932 #ifdef CONFIG_AP 4933 struct sta_handler_args *args = user_data; 4934 struct sta_info *sta; 4935 4936 sta = ap_get_sta(args->wpa_s->ap_iface->bss[0], args->sta); 4937 if (!sta) 4938 return FALSE; 4939 4940 return wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE, 4941 sta->addr, ETH_ALEN, 4942 error); 4943 #else /* CONFIG_AP */ 4944 return FALSE; 4945 #endif /* CONFIG_AP */ 4946 } 4947 4948 4949 /** 4950 * wpas_dbus_getter_sta_aid - Return the AID of a connected station 4951 * @iter: Pointer to incoming dbus message iter 4952 * @error: Location to store error on failure 4953 * @user_data: Function specific data 4954 * Returns: TRUE on success, FALSE on failure 4955 * 4956 * Getter for "AID" property. 4957 */ 4958 dbus_bool_t wpas_dbus_getter_sta_aid( 4959 const struct wpa_dbus_property_desc *property_desc, 4960 DBusMessageIter *iter, DBusError *error, void *user_data) 4961 { 4962 #ifdef CONFIG_AP 4963 struct sta_handler_args *args = user_data; 4964 struct sta_info *sta; 4965 4966 sta = ap_get_sta(args->wpa_s->ap_iface->bss[0], args->sta); 4967 if (!sta) 4968 return FALSE; 4969 4970 return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT16, 4971 &sta->aid, 4972 error); 4973 #else /* CONFIG_AP */ 4974 return FALSE; 4975 #endif /* CONFIG_AP */ 4976 } 4977 4978 4979 /** 4980 * wpas_dbus_getter_sta_caps - Return the capabilities of a station 4981 * @iter: Pointer to incoming dbus message iter 4982 * @error: Location to store error on failure 4983 * @user_data: Function specific data 4984 * Returns: TRUE on success, FALSE on failure 4985 * 4986 * Getter for "Capabilities" property. 4987 */ 4988 dbus_bool_t wpas_dbus_getter_sta_caps( 4989 const struct wpa_dbus_property_desc *property_desc, 4990 DBusMessageIter *iter, DBusError *error, void *user_data) 4991 { 4992 #ifdef CONFIG_AP 4993 struct sta_handler_args *args = user_data; 4994 struct sta_info *sta; 4995 4996 sta = ap_get_sta(args->wpa_s->ap_iface->bss[0], args->sta); 4997 if (!sta) 4998 return FALSE; 4999 5000 return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT16, 5001 &sta->capability, 5002 error); 5003 #else /* CONFIG_AP */ 5004 return FALSE; 5005 #endif /* CONFIG_AP */ 5006 } 5007 5008 5009 /** 5010 * wpas_dbus_getter_rx_packets - Return the received packets for a station 5011 * @iter: Pointer to incoming dbus message iter 5012 * @error: Location to store error on failure 5013 * @user_data: Function specific data 5014 * Returns: TRUE on success, FALSE on failure 5015 * 5016 * Getter for "RxPackets" property. 5017 */ 5018 dbus_bool_t wpas_dbus_getter_sta_rx_packets( 5019 const struct wpa_dbus_property_desc *property_desc, 5020 DBusMessageIter *iter, DBusError *error, void *user_data) 5021 { 5022 #ifdef CONFIG_AP 5023 struct sta_handler_args *args = user_data; 5024 struct sta_info *sta; 5025 struct hostap_sta_driver_data data; 5026 struct hostapd_data *hapd; 5027 5028 if (!args->wpa_s->ap_iface) 5029 return FALSE; 5030 5031 hapd = args->wpa_s->ap_iface->bss[0]; 5032 sta = ap_get_sta(hapd, args->sta); 5033 if (!sta) 5034 return FALSE; 5035 5036 if (hostapd_drv_read_sta_data(hapd, &data, sta->addr) < 0) 5037 return FALSE; 5038 5039 return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT64, 5040 &data.rx_packets, 5041 error); 5042 #else /* CONFIG_AP */ 5043 return FALSE; 5044 #endif /* CONFIG_AP */ 5045 } 5046 5047 5048 /** 5049 * wpas_dbus_getter_tx_packets - Return the transmitted packets for a station 5050 * @iter: Pointer to incoming dbus message iter 5051 * @error: Location to store error on failure 5052 * @user_data: Function specific data 5053 * Returns: TRUE on success, FALSE on failure 5054 * 5055 * Getter for "TxPackets" property. 5056 */ 5057 dbus_bool_t wpas_dbus_getter_sta_tx_packets( 5058 const struct wpa_dbus_property_desc *property_desc, 5059 DBusMessageIter *iter, DBusError *error, void *user_data) 5060 { 5061 #ifdef CONFIG_AP 5062 struct sta_handler_args *args = user_data; 5063 struct sta_info *sta; 5064 struct hostap_sta_driver_data data; 5065 struct hostapd_data *hapd; 5066 5067 if (!args->wpa_s->ap_iface) 5068 return FALSE; 5069 5070 hapd = args->wpa_s->ap_iface->bss[0]; 5071 sta = ap_get_sta(hapd, args->sta); 5072 if (!sta) 5073 return FALSE; 5074 5075 if (hostapd_drv_read_sta_data(hapd, &data, sta->addr) < 0) 5076 return FALSE; 5077 5078 return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT64, 5079 &data.tx_packets, 5080 error); 5081 #else /* CONFIG_AP */ 5082 return FALSE; 5083 #endif /* CONFIG_AP */ 5084 } 5085 5086 5087 /** 5088 * wpas_dbus_getter_tx_bytes - Return the transmitted bytes for a station 5089 * @iter: Pointer to incoming dbus message iter 5090 * @error: Location to store error on failure 5091 * @user_data: Function specific data 5092 * Returns: TRUE on success, FALSE on failure 5093 * 5094 * Getter for "TxBytes" property. 5095 */ 5096 dbus_bool_t wpas_dbus_getter_sta_tx_bytes( 5097 const struct wpa_dbus_property_desc *property_desc, 5098 DBusMessageIter *iter, DBusError *error, void *user_data) 5099 { 5100 #ifdef CONFIG_AP 5101 struct sta_handler_args *args = user_data; 5102 struct sta_info *sta; 5103 struct hostap_sta_driver_data data; 5104 struct hostapd_data *hapd; 5105 5106 if (!args->wpa_s->ap_iface) 5107 return FALSE; 5108 5109 hapd = args->wpa_s->ap_iface->bss[0]; 5110 sta = ap_get_sta(hapd, args->sta); 5111 if (!sta) 5112 return FALSE; 5113 5114 if (hostapd_drv_read_sta_data(hapd, &data, sta->addr) < 0) 5115 return FALSE; 5116 5117 return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT64, 5118 &data.tx_bytes, 5119 error); 5120 #else /* CONFIG_AP */ 5121 return FALSE; 5122 #endif /* CONFIG_AP */ 5123 } 5124 5125 5126 /** 5127 * wpas_dbus_getter_rx_bytes - Return the received bytes for a station 5128 * @iter: Pointer to incoming dbus message iter 5129 * @error: Location to store error on failure 5130 * @user_data: Function specific data 5131 * Returns: TRUE on success, FALSE on failure 5132 * 5133 * Getter for "RxBytes" property. 5134 */ 5135 dbus_bool_t wpas_dbus_getter_sta_rx_bytes( 5136 const struct wpa_dbus_property_desc *property_desc, 5137 DBusMessageIter *iter, DBusError *error, void *user_data) 5138 { 5139 #ifdef CONFIG_AP 5140 struct sta_handler_args *args = user_data; 5141 struct sta_info *sta; 5142 struct hostap_sta_driver_data data; 5143 struct hostapd_data *hapd; 5144 5145 if (!args->wpa_s->ap_iface) 5146 return FALSE; 5147 5148 hapd = args->wpa_s->ap_iface->bss[0]; 5149 sta = ap_get_sta(hapd, args->sta); 5150 if (!sta) 5151 return FALSE; 5152 5153 if (hostapd_drv_read_sta_data(hapd, &data, sta->addr) < 0) 5154 return FALSE; 5155 5156 return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT64, 5157 &data.rx_bytes, 5158 error); 5159 #else /* CONFIG_AP */ 5160 return FALSE; 5161 #endif /* CONFIG_AP */ 5162 } 5163 5164 5165 static struct wpa_bss * get_bss_helper(struct bss_handler_args *args, 5166 DBusError *error, const char *func_name) 5167 { 5168 struct wpa_bss *res = wpa_bss_get_id(args->wpa_s, args->id); 5169 5170 if (!res) { 5171 wpa_printf(MSG_ERROR, "%s[dbus]: no bss with id %d found", 5172 func_name, args->id); 5173 dbus_set_error(error, DBUS_ERROR_FAILED, 5174 "%s: BSS %d not found", 5175 func_name, args->id); 5176 } 5177 5178 return res; 5179 } 5180 5181 5182 /** 5183 * wpas_dbus_getter_bss_bssid - Return the BSSID of a BSS 5184 * @iter: Pointer to incoming dbus message iter 5185 * @error: Location to store error on failure 5186 * @user_data: Function specific data 5187 * Returns: TRUE on success, FALSE on failure 5188 * 5189 * Getter for "BSSID" property. 5190 */ 5191 dbus_bool_t wpas_dbus_getter_bss_bssid( 5192 const struct wpa_dbus_property_desc *property_desc, 5193 DBusMessageIter *iter, DBusError *error, void *user_data) 5194 { 5195 struct bss_handler_args *args = user_data; 5196 struct wpa_bss *res; 5197 5198 res = get_bss_helper(args, error, __func__); 5199 if (!res) 5200 return FALSE; 5201 5202 return wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE, 5203 res->bssid, ETH_ALEN, 5204 error); 5205 } 5206 5207 5208 /** 5209 * wpas_dbus_getter_bss_ssid - Return the SSID of a BSS 5210 * @iter: Pointer to incoming dbus message iter 5211 * @error: Location to store error on failure 5212 * @user_data: Function specific data 5213 * Returns: TRUE on success, FALSE on failure 5214 * 5215 * Getter for "SSID" property. 5216 */ 5217 dbus_bool_t wpas_dbus_getter_bss_ssid( 5218 const struct wpa_dbus_property_desc *property_desc, 5219 DBusMessageIter *iter, DBusError *error, void *user_data) 5220 { 5221 struct bss_handler_args *args = user_data; 5222 struct wpa_bss *res; 5223 5224 res = get_bss_helper(args, error, __func__); 5225 if (!res) 5226 return FALSE; 5227 5228 return wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE, 5229 res->ssid, res->ssid_len, 5230 error); 5231 } 5232 5233 5234 /** 5235 * wpas_dbus_getter_bss_privacy - Return the privacy flag of a BSS 5236 * @iter: Pointer to incoming dbus message iter 5237 * @error: Location to store error on failure 5238 * @user_data: Function specific data 5239 * Returns: TRUE on success, FALSE on failure 5240 * 5241 * Getter for "Privacy" property. 5242 */ 5243 dbus_bool_t wpas_dbus_getter_bss_privacy( 5244 const struct wpa_dbus_property_desc *property_desc, 5245 DBusMessageIter *iter, DBusError *error, void *user_data) 5246 { 5247 struct bss_handler_args *args = user_data; 5248 struct wpa_bss *res; 5249 dbus_bool_t privacy; 5250 5251 res = get_bss_helper(args, error, __func__); 5252 if (!res) 5253 return FALSE; 5254 5255 privacy = (res->caps & IEEE80211_CAP_PRIVACY) ? TRUE : FALSE; 5256 return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN, 5257 &privacy, error); 5258 } 5259 5260 5261 /** 5262 * wpas_dbus_getter_bss_mode - Return the mode of a BSS 5263 * @iter: Pointer to incoming dbus message iter 5264 * @error: Location to store error on failure 5265 * @user_data: Function specific data 5266 * Returns: TRUE on success, FALSE on failure 5267 * 5268 * Getter for "Mode" property. 5269 */ 5270 dbus_bool_t wpas_dbus_getter_bss_mode( 5271 const struct wpa_dbus_property_desc *property_desc, 5272 DBusMessageIter *iter, DBusError *error, void *user_data) 5273 { 5274 struct bss_handler_args *args = user_data; 5275 struct wpa_bss *res; 5276 const char *mode; 5277 const u8 *mesh; 5278 5279 res = get_bss_helper(args, error, __func__); 5280 if (!res) 5281 return FALSE; 5282 if (bss_is_dmg(res)) { 5283 switch (res->caps & IEEE80211_CAP_DMG_MASK) { 5284 case IEEE80211_CAP_DMG_PBSS: 5285 case IEEE80211_CAP_DMG_IBSS: 5286 mode = "ad-hoc"; 5287 break; 5288 case IEEE80211_CAP_DMG_AP: 5289 mode = "infrastructure"; 5290 break; 5291 default: 5292 mode = ""; 5293 break; 5294 } 5295 } else { 5296 mesh = wpa_bss_get_ie(res, WLAN_EID_MESH_ID); 5297 if (mesh) 5298 mode = "mesh"; 5299 else if (res->caps & IEEE80211_CAP_IBSS) 5300 mode = "ad-hoc"; 5301 else 5302 mode = "infrastructure"; 5303 } 5304 5305 return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING, 5306 &mode, error); 5307 } 5308 5309 5310 /** 5311 * wpas_dbus_getter_bss_level - Return the signal strength of a BSS 5312 * @iter: Pointer to incoming dbus message iter 5313 * @error: Location to store error on failure 5314 * @user_data: Function specific data 5315 * Returns: TRUE on success, FALSE on failure 5316 * 5317 * Getter for "Level" property. 5318 */ 5319 dbus_bool_t wpas_dbus_getter_bss_signal( 5320 const struct wpa_dbus_property_desc *property_desc, 5321 DBusMessageIter *iter, DBusError *error, void *user_data) 5322 { 5323 struct bss_handler_args *args = user_data; 5324 struct wpa_bss *res; 5325 s16 level; 5326 5327 res = get_bss_helper(args, error, __func__); 5328 if (!res) 5329 return FALSE; 5330 5331 level = (s16) res->level; 5332 return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_INT16, 5333 &level, error); 5334 } 5335 5336 5337 /** 5338 * wpas_dbus_getter_bss_frequency - Return the frequency of a BSS 5339 * @iter: Pointer to incoming dbus message iter 5340 * @error: Location to store error on failure 5341 * @user_data: Function specific data 5342 * Returns: TRUE on success, FALSE on failure 5343 * 5344 * Getter for "Frequency" property. 5345 */ 5346 dbus_bool_t wpas_dbus_getter_bss_frequency( 5347 const struct wpa_dbus_property_desc *property_desc, 5348 DBusMessageIter *iter, DBusError *error, void *user_data) 5349 { 5350 struct bss_handler_args *args = user_data; 5351 struct wpa_bss *res; 5352 u16 freq; 5353 5354 res = get_bss_helper(args, error, __func__); 5355 if (!res) 5356 return FALSE; 5357 5358 freq = (u16) res->freq; 5359 return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT16, 5360 &freq, error); 5361 } 5362 5363 5364 static int cmp_u8s_desc(const void *a, const void *b) 5365 { 5366 return (*(u8 *) b - *(u8 *) a); 5367 } 5368 5369 5370 /** 5371 * wpas_dbus_getter_bss_rates - Return available bit rates of a BSS 5372 * @iter: Pointer to incoming dbus message iter 5373 * @error: Location to store error on failure 5374 * @user_data: Function specific data 5375 * Returns: TRUE on success, FALSE on failure 5376 * 5377 * Getter for "Rates" property. 5378 */ 5379 dbus_bool_t wpas_dbus_getter_bss_rates( 5380 const struct wpa_dbus_property_desc *property_desc, 5381 DBusMessageIter *iter, DBusError *error, void *user_data) 5382 { 5383 struct bss_handler_args *args = user_data; 5384 struct wpa_bss *res; 5385 u8 *ie_rates = NULL; 5386 u32 *real_rates; 5387 int rates_num, i; 5388 dbus_bool_t success = FALSE; 5389 5390 res = get_bss_helper(args, error, __func__); 5391 if (!res) 5392 return FALSE; 5393 5394 rates_num = wpa_bss_get_bit_rates(res, &ie_rates); 5395 if (rates_num < 0) 5396 return FALSE; 5397 5398 qsort(ie_rates, rates_num, 1, cmp_u8s_desc); 5399 5400 real_rates = os_malloc(sizeof(u32) * rates_num); 5401 if (!real_rates) { 5402 os_free(ie_rates); 5403 dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory"); 5404 return FALSE; 5405 } 5406 5407 for (i = 0; i < rates_num; i++) 5408 real_rates[i] = ie_rates[i] * 500000; 5409 5410 success = wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_UINT32, 5411 real_rates, rates_num, 5412 error); 5413 5414 os_free(ie_rates); 5415 os_free(real_rates); 5416 return success; 5417 } 5418 5419 5420 static dbus_bool_t wpas_dbus_get_bss_security_prop( 5421 const struct wpa_dbus_property_desc *property_desc, 5422 DBusMessageIter *iter, struct wpa_ie_data *ie_data, DBusError *error) 5423 { 5424 DBusMessageIter iter_dict, variant_iter; 5425 const char *group; 5426 const char *pairwise[5]; /* max 5 pairwise ciphers is supported */ 5427 const char *key_mgmt[19]; /* max 19 key managements may be supported */ 5428 int n; 5429 5430 if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, 5431 "a{sv}", &variant_iter)) 5432 goto nomem; 5433 5434 if (!wpa_dbus_dict_open_write(&variant_iter, &iter_dict)) 5435 goto nomem; 5436 5437 /* 5438 * KeyMgmt 5439 * 5440 * When adding a new entry here, please take care to extend key_mgmt[] 5441 * and keep documentation in doc/dbus.doxygen up to date. 5442 */ 5443 n = 0; 5444 if (ie_data->key_mgmt & WPA_KEY_MGMT_PSK) 5445 key_mgmt[n++] = "wpa-psk"; 5446 if (ie_data->key_mgmt & WPA_KEY_MGMT_FT_PSK) 5447 key_mgmt[n++] = "wpa-ft-psk"; 5448 if (ie_data->key_mgmt & WPA_KEY_MGMT_PSK_SHA256) 5449 key_mgmt[n++] = "wpa-psk-sha256"; 5450 if (ie_data->key_mgmt & WPA_KEY_MGMT_IEEE8021X) 5451 key_mgmt[n++] = "wpa-eap"; 5452 if (ie_data->key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) 5453 key_mgmt[n++] = "wpa-ft-eap"; 5454 if (ie_data->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) 5455 key_mgmt[n++] = "wpa-eap-sha256"; 5456 #ifdef CONFIG_SUITEB 5457 if (ie_data->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B) 5458 key_mgmt[n++] = "wpa-eap-suite-b"; 5459 #endif /* CONFIG_SUITEB */ 5460 #ifdef CONFIG_SUITEB192 5461 if (ie_data->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) 5462 key_mgmt[n++] = "wpa-eap-suite-b-192"; 5463 #endif /* CONFIG_SUITEB192 */ 5464 #ifdef CONFIG_FILS 5465 if (ie_data->key_mgmt & WPA_KEY_MGMT_FILS_SHA256) 5466 key_mgmt[n++] = "wpa-fils-sha256"; 5467 if (ie_data->key_mgmt & WPA_KEY_MGMT_FILS_SHA384) 5468 key_mgmt[n++] = "wpa-fils-sha384"; 5469 if (ie_data->key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA256) 5470 key_mgmt[n++] = "wpa-ft-fils-sha256"; 5471 if (ie_data->key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA384) 5472 key_mgmt[n++] = "wpa-ft-fils-sha384"; 5473 #endif /* CONFIG_FILS */ 5474 #ifdef CONFIG_SAE 5475 if (ie_data->key_mgmt & WPA_KEY_MGMT_SAE) 5476 key_mgmt[n++] = "sae"; 5477 if (ie_data->key_mgmt & WPA_KEY_MGMT_SAE_EXT_KEY) 5478 key_mgmt[n++] = "sae-ext-key"; 5479 if (ie_data->key_mgmt & WPA_KEY_MGMT_FT_SAE) 5480 key_mgmt[n++] = "ft-sae"; 5481 if (ie_data->key_mgmt & WPA_KEY_MGMT_FT_SAE_EXT_KEY) 5482 key_mgmt[n++] = "ft-sae-ext-key"; 5483 #endif /* CONFIG_SAE */ 5484 #ifdef CONFIG_OWE 5485 if (ie_data->key_mgmt & WPA_KEY_MGMT_OWE) 5486 key_mgmt[n++] = "owe"; 5487 #endif /* CONFIG_OWE */ 5488 if (ie_data->key_mgmt & WPA_KEY_MGMT_NONE) 5489 key_mgmt[n++] = "wpa-none"; 5490 #ifdef CONFIG_SHA384 5491 if (ie_data->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA384) 5492 key_mgmt[n++] = "wpa-eap-sha384"; 5493 #endif /* CONFIG_SHA384 */ 5494 5495 if (!wpa_dbus_dict_append_string_array(&iter_dict, "KeyMgmt", 5496 key_mgmt, n)) 5497 goto nomem; 5498 5499 /* Group */ 5500 switch (ie_data->group_cipher) { 5501 #ifdef CONFIG_WEP 5502 case WPA_CIPHER_WEP40: 5503 group = "wep40"; 5504 break; 5505 case WPA_CIPHER_WEP104: 5506 group = "wep104"; 5507 break; 5508 #endif /* CONFIG_WEP */ 5509 #ifndef CONFIG_NO_TKIP 5510 case WPA_CIPHER_TKIP: 5511 group = "tkip"; 5512 break; 5513 #endif /* CONFIG_NO_TKIP */ 5514 case WPA_CIPHER_CCMP: 5515 group = "ccmp"; 5516 break; 5517 case WPA_CIPHER_GCMP: 5518 group = "gcmp"; 5519 break; 5520 case WPA_CIPHER_CCMP_256: 5521 group = "ccmp-256"; 5522 break; 5523 case WPA_CIPHER_GCMP_256: 5524 group = "gcmp-256"; 5525 break; 5526 default: 5527 group = ""; 5528 break; 5529 } 5530 5531 if (!wpa_dbus_dict_append_string(&iter_dict, "Group", group)) 5532 goto nomem; 5533 5534 /* Pairwise */ 5535 n = 0; 5536 #ifndef CONFIG_NO_TKIP 5537 if (ie_data->pairwise_cipher & WPA_CIPHER_TKIP) 5538 pairwise[n++] = "tkip"; 5539 #endif /* CONFIG_NO_TKIP */ 5540 if (ie_data->pairwise_cipher & WPA_CIPHER_CCMP) 5541 pairwise[n++] = "ccmp"; 5542 if (ie_data->pairwise_cipher & WPA_CIPHER_GCMP) 5543 pairwise[n++] = "gcmp"; 5544 if (ie_data->pairwise_cipher & WPA_CIPHER_CCMP_256) 5545 pairwise[n++] = "ccmp-256"; 5546 if (ie_data->pairwise_cipher & WPA_CIPHER_GCMP_256) 5547 pairwise[n++] = "gcmp-256"; 5548 5549 if (!wpa_dbus_dict_append_string_array(&iter_dict, "Pairwise", 5550 pairwise, n)) 5551 goto nomem; 5552 5553 /* Management group (RSN only) */ 5554 if (ie_data->proto == WPA_PROTO_RSN) { 5555 switch (ie_data->mgmt_group_cipher) { 5556 case WPA_CIPHER_AES_128_CMAC: 5557 group = "aes128cmac"; 5558 break; 5559 default: 5560 group = ""; 5561 break; 5562 } 5563 5564 if (!wpa_dbus_dict_append_string(&iter_dict, "MgmtGroup", 5565 group)) 5566 goto nomem; 5567 } 5568 5569 if (!wpa_dbus_dict_close_write(&variant_iter, &iter_dict) || 5570 !dbus_message_iter_close_container(iter, &variant_iter)) 5571 goto nomem; 5572 5573 return TRUE; 5574 5575 nomem: 5576 dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory"); 5577 return FALSE; 5578 } 5579 5580 5581 /** 5582 * wpas_dbus_getter_bss_wpa - Return the WPA options of a BSS 5583 * @iter: Pointer to incoming dbus message iter 5584 * @error: Location to store error on failure 5585 * @user_data: Function specific data 5586 * Returns: TRUE on success, FALSE on failure 5587 * 5588 * Getter for "WPA" property. 5589 */ 5590 dbus_bool_t wpas_dbus_getter_bss_wpa( 5591 const struct wpa_dbus_property_desc *property_desc, 5592 DBusMessageIter *iter, DBusError *error, void *user_data) 5593 { 5594 struct bss_handler_args *args = user_data; 5595 struct wpa_bss *res; 5596 struct wpa_ie_data wpa_data; 5597 const u8 *ie; 5598 5599 res = get_bss_helper(args, error, __func__); 5600 if (!res) 5601 return FALSE; 5602 5603 os_memset(&wpa_data, 0, sizeof(wpa_data)); 5604 ie = wpa_bss_get_vendor_ie(res, WPA_IE_VENDOR_TYPE); 5605 if (ie && wpa_parse_wpa_ie(ie, 2 + ie[1], &wpa_data) < 0) { 5606 dbus_set_error_const(error, DBUS_ERROR_FAILED, 5607 "failed to parse WPA IE"); 5608 return FALSE; 5609 } 5610 5611 return wpas_dbus_get_bss_security_prop(property_desc, iter, &wpa_data, error); 5612 } 5613 5614 5615 /** 5616 * wpas_dbus_getter_bss_rsn - Return the RSN options of a BSS 5617 * @iter: Pointer to incoming dbus message iter 5618 * @error: Location to store error on failure 5619 * @user_data: Function specific data 5620 * Returns: TRUE on success, FALSE on failure 5621 * 5622 * Getter for "RSN" property. 5623 */ 5624 dbus_bool_t wpas_dbus_getter_bss_rsn( 5625 const struct wpa_dbus_property_desc *property_desc, 5626 DBusMessageIter *iter, DBusError *error, void *user_data) 5627 { 5628 struct bss_handler_args *args = user_data; 5629 struct wpa_bss *res; 5630 struct wpa_ie_data wpa_data; 5631 const u8 *ie; 5632 5633 res = get_bss_helper(args, error, __func__); 5634 if (!res) 5635 return FALSE; 5636 5637 os_memset(&wpa_data, 0, sizeof(wpa_data)); 5638 ie = wpa_bss_get_ie(res, WLAN_EID_RSN); 5639 if (ie && wpa_parse_wpa_ie(ie, 2 + ie[1], &wpa_data) < 0) { 5640 dbus_set_error_const(error, DBUS_ERROR_FAILED, 5641 "failed to parse RSN IE"); 5642 return FALSE; 5643 } 5644 5645 return wpas_dbus_get_bss_security_prop(property_desc, iter, &wpa_data, error); 5646 } 5647 5648 5649 /** 5650 * wpas_dbus_getter_bss_wps - Return the WPS options of a BSS 5651 * @iter: Pointer to incoming dbus message iter 5652 * @error: Location to store error on failure 5653 * @user_data: Function specific data 5654 * Returns: TRUE on success, FALSE on failure 5655 * 5656 * Getter for "WPS" property. 5657 */ 5658 dbus_bool_t wpas_dbus_getter_bss_wps( 5659 const struct wpa_dbus_property_desc *property_desc, 5660 DBusMessageIter *iter, DBusError *error, void *user_data) 5661 { 5662 struct bss_handler_args *args = user_data; 5663 struct wpa_bss *res; 5664 #ifdef CONFIG_WPS 5665 struct wpabuf *wps_ie; 5666 #endif /* CONFIG_WPS */ 5667 DBusMessageIter iter_dict, variant_iter; 5668 int wps_support = 0; 5669 const char *type = ""; 5670 5671 res = get_bss_helper(args, error, __func__); 5672 if (!res) 5673 return FALSE; 5674 5675 if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, 5676 "a{sv}", &variant_iter) || 5677 !wpa_dbus_dict_open_write(&variant_iter, &iter_dict)) 5678 goto nomem; 5679 5680 #ifdef CONFIG_WPS 5681 wps_ie = wpa_bss_get_vendor_ie_multi(res, WPS_IE_VENDOR_TYPE); 5682 if (wps_ie) { 5683 wps_support = 1; 5684 if (wps_is_selected_pbc_registrar(wps_ie)) 5685 type = "pbc"; 5686 else if (wps_is_selected_pin_registrar(wps_ie)) 5687 type = "pin"; 5688 5689 wpabuf_free(wps_ie); 5690 } 5691 #endif /* CONFIG_WPS */ 5692 5693 if ((wps_support && !wpa_dbus_dict_append_string(&iter_dict, "Type", type)) || 5694 !wpa_dbus_dict_close_write(&variant_iter, &iter_dict) || 5695 !dbus_message_iter_close_container(iter, &variant_iter)) 5696 goto nomem; 5697 5698 return TRUE; 5699 5700 nomem: 5701 dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory"); 5702 return FALSE; 5703 } 5704 5705 5706 /** 5707 * wpas_dbus_getter_bss_ies - Return all IEs of a BSS 5708 * @iter: Pointer to incoming dbus message iter 5709 * @error: Location to store error on failure 5710 * @user_data: Function specific data 5711 * Returns: TRUE on success, FALSE on failure 5712 * 5713 * Getter for "IEs" property. 5714 */ 5715 dbus_bool_t wpas_dbus_getter_bss_ies( 5716 const struct wpa_dbus_property_desc *property_desc, 5717 DBusMessageIter *iter, DBusError *error, void *user_data) 5718 { 5719 struct bss_handler_args *args = user_data; 5720 struct wpa_bss *res; 5721 5722 res = get_bss_helper(args, error, __func__); 5723 if (!res) 5724 return FALSE; 5725 5726 return wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE, 5727 wpa_bss_ie_ptr(res), 5728 res->ie_len, error); 5729 } 5730 5731 5732 /** 5733 * wpas_dbus_getter_bss_age - Return time in seconds since BSS was last seen 5734 * @iter: Pointer to incoming dbus message iter 5735 * @error: Location to store error on failure 5736 * @user_data: Function specific data 5737 * Returns: TRUE on success, FALSE on failure 5738 * 5739 * Getter for BSS age 5740 */ 5741 dbus_bool_t wpas_dbus_getter_bss_age( 5742 const struct wpa_dbus_property_desc *property_desc, 5743 DBusMessageIter *iter, DBusError *error, void *user_data) 5744 { 5745 struct bss_handler_args *args = user_data; 5746 struct wpa_bss *res; 5747 struct os_reltime now, diff = { 0, 0 }; 5748 u32 age; 5749 5750 res = get_bss_helper(args, error, __func__); 5751 if (!res) 5752 return FALSE; 5753 5754 os_get_reltime(&now); 5755 os_reltime_sub(&now, &res->last_update, &diff); 5756 age = diff.sec > 0 ? diff.sec : 0; 5757 return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT32, &age, 5758 error); 5759 } 5760 5761 5762 /** 5763 * wpas_dbus_getter_bss_anqp - Return all the ANQP fields of a BSS 5764 * @iter: Pointer to incoming dbus message iter 5765 * @error: Location to store error on failure 5766 * @user_data: Function specific data 5767 * Returns: TRUE on success, FALSE on failure 5768 * 5769 * Getter for "ANQP" property. 5770 */ 5771 dbus_bool_t wpas_dbus_getter_bss_anqp( 5772 const struct wpa_dbus_property_desc *property_desc, 5773 DBusMessageIter *iter, DBusError *error, void *user_data) 5774 { 5775 DBusMessageIter iter_dict, variant_iter; 5776 struct bss_handler_args *args = user_data; 5777 struct wpa_bss *bss; 5778 struct wpa_bss_anqp *anqp; 5779 struct wpa_bss_anqp_elem *elem; 5780 5781 bss = get_bss_helper(args, error, __func__); 5782 if (!bss) 5783 return FALSE; 5784 5785 if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, 5786 "a{sv}", &variant_iter) || 5787 !wpa_dbus_dict_open_write(&variant_iter, &iter_dict)) 5788 goto nomem; 5789 5790 anqp = bss->anqp; 5791 if (anqp) { 5792 #ifdef CONFIG_INTERWORKING 5793 if (anqp->capability_list && 5794 !wpa_dbus_dict_append_byte_array( 5795 &iter_dict, "CapabilityList", 5796 wpabuf_head(anqp->capability_list), 5797 wpabuf_len(anqp->capability_list))) 5798 goto nomem; 5799 if (anqp->venue_name && 5800 !wpa_dbus_dict_append_byte_array( 5801 &iter_dict, "VenueName", 5802 wpabuf_head(anqp->venue_name), 5803 wpabuf_len(anqp->venue_name))) 5804 goto nomem; 5805 if (anqp->network_auth_type && 5806 !wpa_dbus_dict_append_byte_array( 5807 &iter_dict, "NetworkAuthType", 5808 wpabuf_head(anqp->network_auth_type), 5809 wpabuf_len(anqp->network_auth_type))) 5810 goto nomem; 5811 if (anqp->roaming_consortium && 5812 !wpa_dbus_dict_append_byte_array( 5813 &iter_dict, "RoamingConsortium", 5814 wpabuf_head(anqp->roaming_consortium), 5815 wpabuf_len(anqp->roaming_consortium))) 5816 goto nomem; 5817 if (anqp->ip_addr_type_availability && 5818 !wpa_dbus_dict_append_byte_array( 5819 &iter_dict, "IPAddrTypeAvailability", 5820 wpabuf_head(anqp->ip_addr_type_availability), 5821 wpabuf_len(anqp->ip_addr_type_availability))) 5822 goto nomem; 5823 if (anqp->nai_realm && 5824 !wpa_dbus_dict_append_byte_array( 5825 &iter_dict, "NAIRealm", 5826 wpabuf_head(anqp->nai_realm), 5827 wpabuf_len(anqp->nai_realm))) 5828 goto nomem; 5829 if (anqp->anqp_3gpp && 5830 !wpa_dbus_dict_append_byte_array( 5831 &iter_dict, "3GPP", 5832 wpabuf_head(anqp->anqp_3gpp), 5833 wpabuf_len(anqp->anqp_3gpp))) 5834 goto nomem; 5835 if (anqp->domain_name && 5836 !wpa_dbus_dict_append_byte_array( 5837 &iter_dict, "DomainName", 5838 wpabuf_head(anqp->domain_name), 5839 wpabuf_len(anqp->domain_name))) 5840 goto nomem; 5841 if (anqp->fils_realm_info && 5842 !wpa_dbus_dict_append_byte_array( 5843 &iter_dict, "FilsRealmInfo", 5844 wpabuf_head(anqp->fils_realm_info), 5845 wpabuf_len(anqp->fils_realm_info))) 5846 goto nomem; 5847 5848 #ifdef CONFIG_HS20 5849 if (anqp->hs20_capability_list && 5850 !wpa_dbus_dict_append_byte_array( 5851 &iter_dict, "HS20CapabilityList", 5852 wpabuf_head(anqp->hs20_capability_list), 5853 wpabuf_len(anqp->hs20_capability_list))) 5854 goto nomem; 5855 if (anqp->hs20_operator_friendly_name && 5856 !wpa_dbus_dict_append_byte_array( 5857 &iter_dict, "HS20OperatorFriendlyName", 5858 wpabuf_head(anqp->hs20_operator_friendly_name), 5859 wpabuf_len(anqp->hs20_operator_friendly_name))) 5860 goto nomem; 5861 if (anqp->hs20_wan_metrics && 5862 !wpa_dbus_dict_append_byte_array( 5863 &iter_dict, "HS20WanMetrics", 5864 wpabuf_head(anqp->hs20_wan_metrics), 5865 wpabuf_len(anqp->hs20_wan_metrics))) 5866 goto nomem; 5867 if (anqp->hs20_connection_capability && 5868 !wpa_dbus_dict_append_byte_array( 5869 &iter_dict, "HS20ConnectionCapability", 5870 wpabuf_head(anqp->hs20_connection_capability), 5871 wpabuf_len(anqp->hs20_connection_capability))) 5872 goto nomem; 5873 if (anqp->hs20_operating_class && 5874 !wpa_dbus_dict_append_byte_array( 5875 &iter_dict, "HS20OperatingClass", 5876 wpabuf_head(anqp->hs20_operating_class), 5877 wpabuf_len(anqp->hs20_operating_class))) 5878 goto nomem; 5879 if (anqp->hs20_osu_providers_list && 5880 !wpa_dbus_dict_append_byte_array( 5881 &iter_dict, "HS20OSUProvidersList", 5882 wpabuf_head(anqp->hs20_osu_providers_list), 5883 wpabuf_len(anqp->hs20_osu_providers_list))) 5884 goto nomem; 5885 if (anqp->hs20_operator_icon_metadata && 5886 !wpa_dbus_dict_append_byte_array( 5887 &iter_dict, "HS20OperatorIconMetadata", 5888 wpabuf_head(anqp->hs20_operator_icon_metadata), 5889 wpabuf_len(anqp->hs20_operator_icon_metadata))) 5890 goto nomem; 5891 if (anqp->hs20_osu_providers_nai_list && 5892 !wpa_dbus_dict_append_byte_array( 5893 &iter_dict, "HS20OSUProvidersNAIList", 5894 wpabuf_head(anqp->hs20_osu_providers_nai_list), 5895 wpabuf_len(anqp->hs20_osu_providers_nai_list))) 5896 goto nomem; 5897 #endif /* CONFIG_HS20 */ 5898 5899 dl_list_for_each(elem, &anqp->anqp_elems, 5900 struct wpa_bss_anqp_elem, list) { 5901 char title[32]; 5902 5903 os_snprintf(title, sizeof(title), "anqp[%u]", 5904 elem->infoid); 5905 if (!wpa_dbus_dict_append_byte_array( 5906 &iter_dict, title, 5907 wpabuf_head(elem->payload), 5908 wpabuf_len(elem->payload))) 5909 goto nomem; 5910 5911 os_snprintf(title, sizeof(title), 5912 "protected-anqp-info[%u]", elem->infoid); 5913 if (!wpa_dbus_dict_append_bool( 5914 &iter_dict, title, 5915 elem->protected_response)) 5916 goto nomem; 5917 } 5918 #endif /* CONFIG_INTERWORKING */ 5919 } 5920 5921 if (!wpa_dbus_dict_close_write(&variant_iter, &iter_dict) || 5922 !dbus_message_iter_close_container(iter, &variant_iter)) 5923 goto nomem; 5924 5925 return TRUE; 5926 5927 nomem: 5928 dbus_set_error(error, DBUS_ERROR_NO_MEMORY, "no memory"); 5929 return FALSE; 5930 } 5931 5932 5933 /** 5934 * wpas_dbus_getter_enabled - Check whether network is enabled or disabled 5935 * @iter: Pointer to incoming dbus message iter 5936 * @error: Location to store error on failure 5937 * @user_data: Function specific data 5938 * Returns: TRUE on success, FALSE on failure 5939 * 5940 * Getter for "enabled" property of a configured network. 5941 */ 5942 dbus_bool_t wpas_dbus_getter_enabled( 5943 const struct wpa_dbus_property_desc *property_desc, 5944 DBusMessageIter *iter, DBusError *error, void *user_data) 5945 { 5946 struct network_handler_args *net = user_data; 5947 dbus_bool_t enabled = net->ssid->disabled ? FALSE : TRUE; 5948 5949 return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN, 5950 &enabled, error); 5951 } 5952 5953 5954 /** 5955 * wpas_dbus_setter_enabled - Mark a configured network as enabled or disabled 5956 * @iter: Pointer to incoming dbus message iter 5957 * @error: Location to store error on failure 5958 * @user_data: Function specific data 5959 * Returns: TRUE on success, FALSE on failure 5960 * 5961 * Setter for "Enabled" property of a configured network. 5962 */ 5963 dbus_bool_t wpas_dbus_setter_enabled( 5964 const struct wpa_dbus_property_desc *property_desc, 5965 DBusMessageIter *iter, DBusError *error, void *user_data) 5966 { 5967 struct network_handler_args *net = user_data; 5968 struct wpa_supplicant *wpa_s; 5969 struct wpa_ssid *ssid; 5970 dbus_bool_t enable; 5971 5972 if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_BOOLEAN, 5973 &enable)) 5974 return FALSE; 5975 5976 wpa_s = net->wpa_s; 5977 ssid = net->ssid; 5978 5979 if (enable) 5980 wpa_supplicant_enable_network(wpa_s, ssid); 5981 else 5982 wpa_supplicant_disable_network(wpa_s, ssid); 5983 5984 return TRUE; 5985 } 5986 5987 5988 /** 5989 * wpas_dbus_getter_network_properties - Get options for a configured network 5990 * @iter: Pointer to incoming dbus message iter 5991 * @error: Location to store error on failure 5992 * @user_data: Function specific data 5993 * Returns: TRUE on success, FALSE on failure 5994 * 5995 * Getter for "Properties" property of a configured network. 5996 */ 5997 dbus_bool_t wpas_dbus_getter_network_properties( 5998 const struct wpa_dbus_property_desc *property_desc, 5999 DBusMessageIter *iter, DBusError *error, void *user_data) 6000 { 6001 struct network_handler_args *net = user_data; 6002 DBusMessageIter variant_iter, dict_iter; 6003 char **iterator; 6004 char **props = wpa_config_get_all(net->ssid, 1); 6005 dbus_bool_t success = FALSE; 6006 6007 if (!props) { 6008 dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory"); 6009 return FALSE; 6010 } 6011 6012 if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, "a{sv}", 6013 &variant_iter) || 6014 !wpa_dbus_dict_open_write(&variant_iter, &dict_iter)) { 6015 dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory"); 6016 goto out; 6017 } 6018 6019 iterator = props; 6020 while (*iterator) { 6021 if (!wpa_dbus_dict_append_string(&dict_iter, *iterator, 6022 *(iterator + 1))) { 6023 dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, 6024 "no memory"); 6025 goto out; 6026 } 6027 iterator += 2; 6028 } 6029 6030 6031 if (!wpa_dbus_dict_close_write(&variant_iter, &dict_iter) || 6032 !dbus_message_iter_close_container(iter, &variant_iter)) { 6033 dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory"); 6034 goto out; 6035 } 6036 6037 success = TRUE; 6038 6039 out: 6040 iterator = props; 6041 while (*iterator) { 6042 os_free(*iterator); 6043 iterator++; 6044 } 6045 os_free(props); 6046 return success; 6047 } 6048 6049 6050 /** 6051 * wpas_dbus_setter_network_properties - Set options for a configured network 6052 * @iter: Pointer to incoming dbus message iter 6053 * @error: Location to store error on failure 6054 * @user_data: Function specific data 6055 * Returns: TRUE on success, FALSE on failure 6056 * 6057 * Setter for "Properties" property of a configured network. 6058 */ 6059 dbus_bool_t wpas_dbus_setter_network_properties( 6060 const struct wpa_dbus_property_desc *property_desc, 6061 DBusMessageIter *iter, DBusError *error, void *user_data) 6062 { 6063 struct network_handler_args *net = user_data; 6064 struct wpa_ssid *ssid = net->ssid; 6065 DBusMessageIter variant_iter; 6066 6067 dbus_message_iter_recurse(iter, &variant_iter); 6068 return set_network_properties(net->wpa_s, ssid, &variant_iter, error); 6069 } 6070 6071 6072 #ifdef CONFIG_AP 6073 6074 DBusMessage * wpas_dbus_handler_subscribe_preq( 6075 DBusMessage *message, struct wpa_supplicant *wpa_s) 6076 { 6077 struct wpas_dbus_priv *priv = wpa_s->global->dbus; 6078 char *name; 6079 6080 if (wpa_s->preq_notify_peer != NULL) { 6081 if (os_strcmp(dbus_message_get_sender(message), 6082 wpa_s->preq_notify_peer) == 0) 6083 return NULL; 6084 6085 return dbus_message_new_error(message, 6086 WPAS_DBUS_ERROR_SUBSCRIPTION_IN_USE, 6087 "Another application is already subscribed"); 6088 } 6089 6090 name = os_strdup(dbus_message_get_sender(message)); 6091 if (!name) 6092 return wpas_dbus_error_no_memory(message); 6093 6094 wpa_s->preq_notify_peer = name; 6095 6096 /* Subscribe to clean up if application closes socket */ 6097 wpas_dbus_subscribe_noc(priv); 6098 6099 /* 6100 * Double-check it's still alive to make sure that we didn't 6101 * miss the NameOwnerChanged signal, e.g. while strdup'ing. 6102 */ 6103 if (!dbus_bus_name_has_owner(priv->con, name, NULL)) { 6104 /* 6105 * Application no longer exists, clean up. 6106 * The return value is irrelevant now. 6107 * 6108 * Need to check if the NameOwnerChanged handling 6109 * already cleaned up because we have processed 6110 * DBus messages while checking if the name still 6111 * has an owner. 6112 */ 6113 if (!wpa_s->preq_notify_peer) 6114 return NULL; 6115 os_free(wpa_s->preq_notify_peer); 6116 wpa_s->preq_notify_peer = NULL; 6117 wpas_dbus_unsubscribe_noc(priv); 6118 } 6119 6120 return NULL; 6121 } 6122 6123 6124 DBusMessage * wpas_dbus_handler_unsubscribe_preq( 6125 DBusMessage *message, struct wpa_supplicant *wpa_s) 6126 { 6127 struct wpas_dbus_priv *priv = wpa_s->global->dbus; 6128 6129 if (!wpa_s->preq_notify_peer) 6130 return dbus_message_new_error(message, 6131 WPAS_DBUS_ERROR_NO_SUBSCRIPTION, 6132 "Not subscribed"); 6133 6134 if (os_strcmp(wpa_s->preq_notify_peer, 6135 dbus_message_get_sender(message))) 6136 return dbus_message_new_error(message, 6137 WPAS_DBUS_ERROR_SUBSCRIPTION_EPERM, 6138 "Can't unsubscribe others"); 6139 6140 os_free(wpa_s->preq_notify_peer); 6141 wpa_s->preq_notify_peer = NULL; 6142 wpas_dbus_unsubscribe_noc(priv); 6143 return NULL; 6144 } 6145 6146 6147 void wpas_dbus_signal_preq(struct wpa_supplicant *wpa_s, 6148 const u8 *addr, const u8 *dst, const u8 *bssid, 6149 const u8 *ie, size_t ie_len, u32 ssi_signal) 6150 { 6151 DBusMessage *msg; 6152 DBusMessageIter iter, dict_iter; 6153 struct wpas_dbus_priv *priv = wpa_s->global->dbus; 6154 6155 /* Do nothing if the control interface is not turned on */ 6156 if (priv == NULL || !wpa_s->dbus_new_path) 6157 return; 6158 6159 if (wpa_s->preq_notify_peer == NULL) 6160 return; 6161 6162 msg = dbus_message_new_signal(wpa_s->dbus_new_path, 6163 WPAS_DBUS_NEW_IFACE_INTERFACE, 6164 "ProbeRequest"); 6165 if (msg == NULL) 6166 return; 6167 6168 dbus_message_set_destination(msg, wpa_s->preq_notify_peer); 6169 6170 dbus_message_iter_init_append(msg, &iter); 6171 6172 if (!wpa_dbus_dict_open_write(&iter, &dict_iter) || 6173 (addr && !wpa_dbus_dict_append_byte_array(&dict_iter, "addr", 6174 (const char *) addr, 6175 ETH_ALEN)) || 6176 (dst && !wpa_dbus_dict_append_byte_array(&dict_iter, "dst", 6177 (const char *) dst, 6178 ETH_ALEN)) || 6179 (bssid && !wpa_dbus_dict_append_byte_array(&dict_iter, "bssid", 6180 (const char *) bssid, 6181 ETH_ALEN)) || 6182 (ie && ie_len && !wpa_dbus_dict_append_byte_array(&dict_iter, "ies", 6183 (const char *) ie, 6184 ie_len)) || 6185 (ssi_signal && !wpa_dbus_dict_append_int32(&dict_iter, "signal", 6186 ssi_signal)) || 6187 !wpa_dbus_dict_close_write(&iter, &dict_iter)) 6188 goto fail; 6189 6190 dbus_connection_send(priv->con, msg, NULL); 6191 goto out; 6192 fail: 6193 wpa_printf(MSG_ERROR, "dbus: Failed to construct signal"); 6194 out: 6195 dbus_message_unref(msg); 6196 } 6197 6198 #endif /* CONFIG_AP */ 6199 6200 6201 DBusMessage * wpas_dbus_handler_vendor_elem_add(DBusMessage *message, 6202 struct wpa_supplicant *wpa_s) 6203 { 6204 u8 *ielems; 6205 int len; 6206 struct ieee802_11_elems elems; 6207 dbus_int32_t frame_id; 6208 DBusMessageIter iter, array; 6209 6210 dbus_message_iter_init(message, &iter); 6211 dbus_message_iter_get_basic(&iter, &frame_id); 6212 if (frame_id < 0 || frame_id >= NUM_VENDOR_ELEM_FRAMES) { 6213 return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS, 6214 "Invalid ID"); 6215 } 6216 6217 dbus_message_iter_next(&iter); 6218 dbus_message_iter_recurse(&iter, &array); 6219 dbus_message_iter_get_fixed_array(&array, &ielems, &len); 6220 if (!ielems || len == 0) { 6221 return dbus_message_new_error( 6222 message, DBUS_ERROR_INVALID_ARGS, "Invalid value"); 6223 } 6224 6225 if (ieee802_11_parse_elems(ielems, len, &elems, 0) == ParseFailed) { 6226 return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS, 6227 "Parse error"); 6228 } 6229 6230 wpa_s = wpas_vendor_elem(wpa_s, frame_id); 6231 if (!wpa_s->vendor_elem[frame_id]) { 6232 wpa_s->vendor_elem[frame_id] = wpabuf_alloc_copy(ielems, len); 6233 wpas_vendor_elem_update(wpa_s); 6234 return NULL; 6235 } 6236 6237 if (wpabuf_resize(&wpa_s->vendor_elem[frame_id], len) < 0) { 6238 return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS, 6239 "Resize error"); 6240 } 6241 6242 wpabuf_put_data(wpa_s->vendor_elem[frame_id], ielems, len); 6243 wpas_vendor_elem_update(wpa_s); 6244 return NULL; 6245 } 6246 6247 6248 DBusMessage * wpas_dbus_handler_vendor_elem_get(DBusMessage *message, 6249 struct wpa_supplicant *wpa_s) 6250 { 6251 DBusMessage *reply; 6252 DBusMessageIter iter, array_iter; 6253 dbus_int32_t frame_id; 6254 const u8 *elem; 6255 size_t elem_len; 6256 6257 dbus_message_iter_init(message, &iter); 6258 dbus_message_iter_get_basic(&iter, &frame_id); 6259 6260 if (frame_id < 0 || frame_id >= NUM_VENDOR_ELEM_FRAMES) { 6261 return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS, 6262 "Invalid ID"); 6263 } 6264 6265 wpa_s = wpas_vendor_elem(wpa_s, frame_id); 6266 if (!wpa_s->vendor_elem[frame_id]) { 6267 return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS, 6268 "ID value does not exist"); 6269 } 6270 6271 reply = dbus_message_new_method_return(message); 6272 if (!reply) 6273 return wpas_dbus_error_no_memory(message); 6274 6275 dbus_message_iter_init_append(reply, &iter); 6276 6277 elem = wpabuf_head_u8(wpa_s->vendor_elem[frame_id]); 6278 elem_len = wpabuf_len(wpa_s->vendor_elem[frame_id]); 6279 6280 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, 6281 DBUS_TYPE_BYTE_AS_STRING, 6282 &array_iter) || 6283 !dbus_message_iter_append_fixed_array(&array_iter, DBUS_TYPE_BYTE, 6284 &elem, elem_len) || 6285 !dbus_message_iter_close_container(&iter, &array_iter)) { 6286 dbus_message_unref(reply); 6287 reply = wpas_dbus_error_no_memory(message); 6288 } 6289 6290 return reply; 6291 } 6292 6293 6294 DBusMessage * wpas_dbus_handler_vendor_elem_remove(DBusMessage *message, 6295 struct wpa_supplicant *wpa_s) 6296 { 6297 u8 *ielems; 6298 int len; 6299 struct ieee802_11_elems elems; 6300 DBusMessageIter iter, array; 6301 dbus_int32_t frame_id; 6302 6303 dbus_message_iter_init(message, &iter); 6304 dbus_message_iter_get_basic(&iter, &frame_id); 6305 if (frame_id < 0 || frame_id >= NUM_VENDOR_ELEM_FRAMES) { 6306 return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS, 6307 "Invalid ID"); 6308 } 6309 6310 dbus_message_iter_next(&iter); 6311 dbus_message_iter_recurse(&iter, &array); 6312 dbus_message_iter_get_fixed_array(&array, &ielems, &len); 6313 if (!ielems || len == 0) { 6314 return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS, 6315 "Invalid value"); 6316 } 6317 6318 wpa_s = wpas_vendor_elem(wpa_s, frame_id); 6319 6320 if (len == 1 && *ielems == '*') { 6321 wpabuf_free(wpa_s->vendor_elem[frame_id]); 6322 wpa_s->vendor_elem[frame_id] = NULL; 6323 wpas_vendor_elem_update(wpa_s); 6324 return NULL; 6325 } 6326 6327 if (!wpa_s->vendor_elem[frame_id]) { 6328 return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS, 6329 "ID value does not exist"); 6330 } 6331 6332 if (ieee802_11_parse_elems(ielems, len, &elems, 0) == ParseFailed) { 6333 return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS, 6334 "Parse error"); 6335 } 6336 6337 if (wpas_vendor_elem_remove(wpa_s, frame_id, ielems, len) == 0) 6338 return NULL; 6339 6340 return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS, 6341 "Not found"); 6342 } 6343 6344 6345 #ifdef CONFIG_MESH 6346 6347 /** 6348 * wpas_dbus_getter_mesh_peers - Get connected mesh peers 6349 * @iter: Pointer to incoming dbus message iter 6350 * @error: Location to store error on failure 6351 * @user_data: Function specific data 6352 * Returns: TRUE on success, FALSE on failure 6353 * 6354 * Getter for "MeshPeers" property. 6355 */ 6356 dbus_bool_t wpas_dbus_getter_mesh_peers( 6357 const struct wpa_dbus_property_desc *property_desc, 6358 DBusMessageIter *iter, DBusError *error, void *user_data) 6359 { 6360 struct wpa_supplicant *wpa_s = user_data; 6361 struct hostapd_data *hapd; 6362 struct sta_info *sta; 6363 DBusMessageIter variant_iter, array_iter; 6364 int i; 6365 DBusMessageIter inner_array_iter; 6366 6367 if (!wpa_s->ifmsh) 6368 return FALSE; 6369 hapd = wpa_s->ifmsh->bss[0]; 6370 6371 if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, 6372 DBUS_TYPE_ARRAY_AS_STRING 6373 DBUS_TYPE_ARRAY_AS_STRING 6374 DBUS_TYPE_BYTE_AS_STRING, 6375 &variant_iter) || 6376 !dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY, 6377 DBUS_TYPE_ARRAY_AS_STRING 6378 DBUS_TYPE_BYTE_AS_STRING, 6379 &array_iter)) 6380 return FALSE; 6381 6382 for (sta = hapd->sta_list; sta; sta = sta->next) { 6383 if (!dbus_message_iter_open_container( 6384 &array_iter, DBUS_TYPE_ARRAY, 6385 DBUS_TYPE_BYTE_AS_STRING, 6386 &inner_array_iter)) 6387 return FALSE; 6388 6389 for (i = 0; i < ETH_ALEN; i++) { 6390 if (!dbus_message_iter_append_basic(&inner_array_iter, 6391 DBUS_TYPE_BYTE, 6392 &(sta->addr[i]))) 6393 return FALSE; 6394 } 6395 6396 if (!dbus_message_iter_close_container( 6397 &array_iter, &inner_array_iter)) 6398 return FALSE; 6399 } 6400 6401 if (!dbus_message_iter_close_container(&variant_iter, &array_iter) || 6402 !dbus_message_iter_close_container(iter, &variant_iter)) 6403 return FALSE; 6404 6405 return TRUE; 6406 } 6407 6408 6409 /** 6410 * wpas_dbus_getter_mesh_group - Get mesh group 6411 * @iter: Pointer to incoming dbus message iter 6412 * @error: Location to store error on failure 6413 * @user_data: Function specific data 6414 * Returns: TRUE on success, FALSE on failure 6415 * 6416 * Getter for "MeshGroup" property. 6417 */ 6418 dbus_bool_t wpas_dbus_getter_mesh_group( 6419 const struct wpa_dbus_property_desc *property_desc, 6420 DBusMessageIter *iter, DBusError *error, void *user_data) 6421 { 6422 struct wpa_supplicant *wpa_s = user_data; 6423 struct wpa_ssid *ssid = wpa_s->current_ssid; 6424 6425 if (!wpa_s->ifmsh || !ssid) 6426 return FALSE; 6427 6428 if (!wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE, 6429 (char *) ssid->ssid, 6430 ssid->ssid_len, error)) { 6431 dbus_set_error(error, DBUS_ERROR_FAILED, 6432 "%s: error constructing reply", __func__); 6433 return FALSE; 6434 } 6435 6436 return TRUE; 6437 } 6438 6439 #endif /* CONFIG_MESH */ 6440 6441 6442 /** 6443 * wpas_dbus_getter_signal_change - Get signal change 6444 * @iter: Pointer to incoming dbus message iter 6445 * @error: Location to store error on failure 6446 * @user_data: Function specific data 6447 * Returns: TRUE on success, FALSE on failure 6448 * 6449 * Getter for "SignalChange" property. 6450 */ 6451 dbus_bool_t wpas_dbus_getter_signal_change( 6452 const struct wpa_dbus_property_desc *property_desc, 6453 DBusMessageIter *iter, DBusError *error, void *user_data) 6454 { 6455 struct wpa_supplicant *wpa_s = user_data; 6456 struct wpa_signal_info si = wpa_s->last_signal_info; 6457 6458 if (wpas_dbus_new_from_signal_information(iter, &si) != 0) { 6459 dbus_set_error(error, DBUS_ERROR_FAILED, 6460 "%s: error constructing reply", __func__); 6461 return FALSE; 6462 } 6463 return TRUE; 6464 } 6465