1 /* 2 * WPA Supplicant / dbus-based control interface 3 * Copyright (c) 2006, Dan Williams <dcbw (at) redhat.com> and Red Hat, Inc. 4 * Copyright (c) 2009-2010, Witold Sowa <witold.sowa (at) gmail.com> 5 * Copyright (c) 2009, Jouni Malinen <j (at) w1.fi> 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License version 2 as 9 * published by the Free Software Foundation. 10 * 11 * Alternatively, this software may be distributed under the terms of BSD 12 * license. 13 * 14 * See README and COPYING for more details. 15 */ 16 17 #include "includes.h" 18 19 #include "common.h" 20 #include "common/ieee802_11_defs.h" 21 #include "eap_peer/eap_methods.h" 22 #include "eapol_supp/eapol_supp_sm.h" 23 #include "rsn_supp/wpa.h" 24 #include "../config.h" 25 #include "../wpa_supplicant_i.h" 26 #include "../driver_i.h" 27 #include "../notify.h" 28 #include "../bss.h" 29 #include "../scan.h" 30 #include "../ctrl_iface.h" 31 #include "dbus_new_helpers.h" 32 #include "dbus_new.h" 33 #include "dbus_new_handlers.h" 34 #include "dbus_dict_helpers.h" 35 36 extern int wpa_debug_level; 37 extern int wpa_debug_show_keys; 38 extern int wpa_debug_timestamp; 39 40 static const char *debug_strings[] = { 41 "excessive", "msgdump", "debug", "info", "warning", "error", NULL 42 }; 43 44 45 /** 46 * wpas_dbus_error_unknown_error - Return a new InvalidArgs error message 47 * @message: Pointer to incoming dbus message this error refers to 48 * @arg: Optional string appended to error message 49 * Returns: a dbus error message 50 * 51 * Convenience function to create and return an UnknownError 52 */ 53 DBusMessage * wpas_dbus_error_unknown_error(DBusMessage *message, 54 const char *arg) 55 { 56 /* 57 * This function can be called as a result of a failure 58 * within internal getter calls, which will call this function 59 * with a NULL message parameter. However, dbus_message_new_error 60 * looks very unkindly (i.e, abort()) on a NULL message, so 61 * in this case, we should not call it. 62 */ 63 if (message == NULL) { 64 wpa_printf(MSG_INFO, "dbus: wpas_dbus_error_unknown_error " 65 "called with NULL message (arg=%s)", 66 arg ? arg : "N/A"); 67 return NULL; 68 } 69 70 return dbus_message_new_error(message, WPAS_DBUS_ERROR_UNKNOWN_ERROR, 71 arg); 72 } 73 74 75 /** 76 * wpas_dbus_error_iface_unknown - Return a new invalid interface error message 77 * @message: Pointer to incoming dbus message this error refers to 78 * Returns: A dbus error message 79 * 80 * Convenience function to create and return an invalid interface error 81 */ 82 static DBusMessage * wpas_dbus_error_iface_unknown(DBusMessage *message) 83 { 84 return dbus_message_new_error(message, WPAS_DBUS_ERROR_IFACE_UNKNOWN, 85 "wpa_supplicant knows nothing about " 86 "this interface."); 87 } 88 89 90 /** 91 * wpas_dbus_error_network_unknown - Return a new NetworkUnknown error message 92 * @message: Pointer to incoming dbus message this error refers to 93 * Returns: a dbus error message 94 * 95 * Convenience function to create and return an invalid network error 96 */ 97 static DBusMessage * wpas_dbus_error_network_unknown(DBusMessage *message) 98 { 99 return dbus_message_new_error(message, WPAS_DBUS_ERROR_NETWORK_UNKNOWN, 100 "There is no such a network in this " 101 "interface."); 102 } 103 104 105 /** 106 * wpas_dbus_error_invalid_args - Return a new InvalidArgs error message 107 * @message: Pointer to incoming dbus message this error refers to 108 * Returns: a dbus error message 109 * 110 * Convenience function to create and return an invalid options error 111 */ 112 DBusMessage * wpas_dbus_error_invalid_args(DBusMessage *message, 113 const char *arg) 114 { 115 DBusMessage *reply; 116 117 reply = dbus_message_new_error(message, WPAS_DBUS_ERROR_INVALID_ARGS, 118 "Did not receive correct message " 119 "arguments."); 120 if (arg != NULL) 121 dbus_message_append_args(reply, DBUS_TYPE_STRING, &arg, 122 DBUS_TYPE_INVALID); 123 124 return reply; 125 } 126 127 128 static const char *dont_quote[] = { 129 "key_mgmt", "proto", "pairwise", "auth_alg", "group", "eap", 130 "opensc_engine_path", "pkcs11_engine_path", "pkcs11_module_path", 131 "bssid", NULL 132 }; 133 134 static dbus_bool_t should_quote_opt(const char *key) 135 { 136 int i = 0; 137 while (dont_quote[i] != NULL) { 138 if (os_strcmp(key, dont_quote[i]) == 0) 139 return FALSE; 140 i++; 141 } 142 return TRUE; 143 } 144 145 /** 146 * get_iface_by_dbus_path - Get a new network interface 147 * @global: Pointer to global data from wpa_supplicant_init() 148 * @path: Pointer to a dbus object path representing an interface 149 * Returns: Pointer to the interface or %NULL if not found 150 */ 151 static struct wpa_supplicant * get_iface_by_dbus_path( 152 struct wpa_global *global, const char *path) 153 { 154 struct wpa_supplicant *wpa_s; 155 156 for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) { 157 if (os_strcmp(wpa_s->dbus_new_path, path) == 0) 158 return wpa_s; 159 } 160 return NULL; 161 } 162 163 164 /** 165 * set_network_properties - Set properties of a configured network 166 * @wpa_s: wpa_supplicant structure for a network interface 167 * @ssid: wpa_ssid structure for a configured network 168 * @iter: DBus message iterator containing dictionary of network 169 * properties to set. 170 * @error: On failure, an error describing the failure 171 * Returns: TRUE if the request succeeds, FALSE if it failed 172 * 173 * Sets network configuration with parameters given id DBus dictionary 174 */ 175 dbus_bool_t set_network_properties(struct wpa_supplicant *wpa_s, 176 struct wpa_ssid *ssid, 177 DBusMessageIter *iter, 178 DBusError *error) 179 { 180 struct wpa_dbus_dict_entry entry = { .type = DBUS_TYPE_STRING }; 181 DBusMessageIter iter_dict; 182 char *value = NULL; 183 184 if (!wpa_dbus_dict_open_read(iter, &iter_dict, error)) 185 return FALSE; 186 187 while (wpa_dbus_dict_has_dict_entry(&iter_dict)) { 188 size_t size = 50; 189 int ret; 190 191 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) 192 goto error; 193 194 value = NULL; 195 if (entry.type == DBUS_TYPE_ARRAY && 196 entry.array_type == DBUS_TYPE_BYTE) { 197 if (entry.array_len <= 0) 198 goto error; 199 200 size = entry.array_len * 2 + 1; 201 value = os_zalloc(size); 202 if (value == NULL) 203 goto error; 204 205 ret = wpa_snprintf_hex(value, size, 206 (u8 *) entry.bytearray_value, 207 entry.array_len); 208 if (ret <= 0) 209 goto error; 210 } else if (entry.type == DBUS_TYPE_STRING) { 211 if (should_quote_opt(entry.key)) { 212 size = os_strlen(entry.str_value); 213 if (size <= 0) 214 goto error; 215 216 size += 3; 217 value = os_zalloc(size); 218 if (value == NULL) 219 goto error; 220 221 ret = os_snprintf(value, size, "\"%s\"", 222 entry.str_value); 223 if (ret < 0 || (size_t) ret != (size - 1)) 224 goto error; 225 } else { 226 value = os_strdup(entry.str_value); 227 if (value == NULL) 228 goto error; 229 } 230 } else if (entry.type == DBUS_TYPE_UINT32) { 231 value = os_zalloc(size); 232 if (value == NULL) 233 goto error; 234 235 ret = os_snprintf(value, size, "%u", 236 entry.uint32_value); 237 if (ret <= 0) 238 goto error; 239 } else if (entry.type == DBUS_TYPE_INT32) { 240 value = os_zalloc(size); 241 if (value == NULL) 242 goto error; 243 244 ret = os_snprintf(value, size, "%d", 245 entry.int32_value); 246 if (ret <= 0) 247 goto error; 248 } else 249 goto error; 250 251 if (wpa_config_set(ssid, entry.key, value, 0) < 0) 252 goto error; 253 254 if ((os_strcmp(entry.key, "psk") == 0 && 255 value[0] == '"' && ssid->ssid_len) || 256 (strcmp(entry.key, "ssid") == 0 && ssid->passphrase)) 257 wpa_config_update_psk(ssid); 258 else if (os_strcmp(entry.key, "priority") == 0) 259 wpa_config_update_prio_list(wpa_s->conf); 260 261 os_free(value); 262 wpa_dbus_dict_entry_clear(&entry); 263 } 264 265 return TRUE; 266 267 error: 268 os_free(value); 269 wpa_dbus_dict_entry_clear(&entry); 270 dbus_set_error_const(error, DBUS_ERROR_INVALID_ARGS, 271 "invalid message format"); 272 return FALSE; 273 } 274 275 276 /** 277 * wpas_dbus_simple_property_getter - Get basic type property 278 * @iter: Message iter to use when appending arguments 279 * @type: DBus type of property (must be basic type) 280 * @val: pointer to place holding property value 281 * @error: On failure an error describing the failure 282 * Returns: TRUE if the request was successful, FALSE if it failed 283 * 284 * Generic getter for basic type properties. Type is required to be basic. 285 */ 286 dbus_bool_t wpas_dbus_simple_property_getter(DBusMessageIter *iter, 287 const int type, 288 const void *val, 289 DBusError *error) 290 { 291 DBusMessageIter variant_iter; 292 293 if (!dbus_type_is_basic(type)) { 294 dbus_set_error(error, DBUS_ERROR_FAILED, 295 "%s: given type is not basic", __func__); 296 return FALSE; 297 } 298 299 if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, 300 wpa_dbus_type_as_string(type), 301 &variant_iter)) 302 goto error; 303 304 if (!dbus_message_iter_append_basic(&variant_iter, type, val)) 305 goto error; 306 307 if (!dbus_message_iter_close_container(iter, &variant_iter)) 308 goto error; 309 310 return TRUE; 311 312 error: 313 dbus_set_error(error, DBUS_ERROR_FAILED, 314 "%s: error constructing reply", __func__); 315 return FALSE; 316 } 317 318 319 /** 320 * wpas_dbus_simple_property_setter - Set basic type property 321 * @message: Pointer to incoming dbus message 322 * @type: DBus type of property (must be basic type) 323 * @val: pointer to place where value being set will be stored 324 * Returns: TRUE if the request was successful, FALSE if it failed 325 * 326 * Generic setter for basic type properties. Type is required to be basic. 327 */ 328 dbus_bool_t wpas_dbus_simple_property_setter(DBusMessageIter *iter, 329 DBusError *error, 330 const int type, void *val) 331 { 332 DBusMessageIter variant_iter; 333 334 if (!dbus_type_is_basic(type)) { 335 dbus_set_error(error, DBUS_ERROR_FAILED, 336 "%s: given type is not basic", __func__); 337 return FALSE; 338 } 339 340 /* Look at the new value */ 341 dbus_message_iter_recurse(iter, &variant_iter); 342 if (dbus_message_iter_get_arg_type(&variant_iter) != type) { 343 dbus_set_error_const(error, DBUS_ERROR_FAILED, 344 "wrong property type"); 345 return FALSE; 346 } 347 dbus_message_iter_get_basic(&variant_iter, val); 348 349 return TRUE; 350 } 351 352 353 /** 354 * wpas_dbus_simple_array_property_getter - Get array type property 355 * @iter: Pointer to incoming dbus message iterator 356 * @type: DBus type of property array elements (must be basic type) 357 * @array: pointer to array of elements to put into response message 358 * @array_len: length of above array 359 * @error: a pointer to an error to fill on failure 360 * Returns: TRUE if the request succeeded, FALSE if it failed 361 * 362 * Generic getter for array type properties. Array elements type is 363 * required to be basic. 364 */ 365 dbus_bool_t wpas_dbus_simple_array_property_getter(DBusMessageIter *iter, 366 const int type, 367 const void *array, 368 size_t array_len, 369 DBusError *error) 370 { 371 DBusMessageIter variant_iter, array_iter; 372 char type_str[] = "a?"; /* ? will be replaced with subtype letter; */ 373 const char *sub_type_str; 374 size_t element_size, i; 375 376 if (!dbus_type_is_basic(type)) { 377 dbus_set_error(error, DBUS_ERROR_FAILED, 378 "%s: given type is not basic", __func__); 379 return FALSE; 380 } 381 382 sub_type_str = wpa_dbus_type_as_string(type); 383 type_str[1] = sub_type_str[0]; 384 385 if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, 386 type_str, &variant_iter)) { 387 dbus_set_error(error, DBUS_ERROR_FAILED, 388 "%s: failed to construct message 1", __func__); 389 return FALSE; 390 } 391 392 if (!dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY, 393 sub_type_str, &array_iter)) { 394 dbus_set_error(error, DBUS_ERROR_FAILED, 395 "%s: failed to construct message 2", __func__); 396 return FALSE; 397 } 398 399 switch(type) { 400 case DBUS_TYPE_BYTE: 401 case DBUS_TYPE_BOOLEAN: 402 element_size = 1; 403 break; 404 case DBUS_TYPE_INT16: 405 case DBUS_TYPE_UINT16: 406 element_size = sizeof(uint16_t); 407 break; 408 case DBUS_TYPE_INT32: 409 case DBUS_TYPE_UINT32: 410 element_size = sizeof(uint32_t); 411 break; 412 case DBUS_TYPE_INT64: 413 case DBUS_TYPE_UINT64: 414 element_size = sizeof(uint64_t); 415 break; 416 case DBUS_TYPE_DOUBLE: 417 element_size = sizeof(double); 418 break; 419 case DBUS_TYPE_STRING: 420 case DBUS_TYPE_OBJECT_PATH: 421 element_size = sizeof(char *); 422 break; 423 default: 424 dbus_set_error(error, DBUS_ERROR_FAILED, 425 "%s: unknown element type %d", __func__, type); 426 return FALSE; 427 } 428 429 for (i = 0; i < array_len; i++) { 430 dbus_message_iter_append_basic(&array_iter, type, 431 array + i * element_size); 432 } 433 434 if (!dbus_message_iter_close_container(&variant_iter, &array_iter)) { 435 dbus_set_error(error, DBUS_ERROR_FAILED, 436 "%s: failed to construct message 3", __func__); 437 return FALSE; 438 } 439 440 if (!dbus_message_iter_close_container(iter, &variant_iter)) { 441 dbus_set_error(error, DBUS_ERROR_FAILED, 442 "%s: failed to construct message 4", __func__); 443 return FALSE; 444 } 445 446 return TRUE; 447 } 448 449 450 /** 451 * wpas_dbus_handler_create_interface - Request registration of a network iface 452 * @message: Pointer to incoming dbus message 453 * @global: %wpa_supplicant global data structure 454 * Returns: The object path of the new interface object, 455 * or a dbus error message with more information 456 * 457 * Handler function for "CreateInterface" method call. Handles requests 458 * by dbus clients to register a network interface that wpa_supplicant 459 * will manage. 460 */ 461 DBusMessage * wpas_dbus_handler_create_interface(DBusMessage *message, 462 struct wpa_global *global) 463 { 464 DBusMessageIter iter_dict; 465 DBusMessage *reply = NULL; 466 DBusMessageIter iter; 467 struct wpa_dbus_dict_entry entry; 468 char *driver = NULL; 469 char *ifname = NULL; 470 char *confname = NULL; 471 char *bridge_ifname = NULL; 472 473 dbus_message_iter_init(message, &iter); 474 475 if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL)) 476 goto error; 477 while (wpa_dbus_dict_has_dict_entry(&iter_dict)) { 478 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) 479 goto error; 480 if (!strcmp(entry.key, "Driver") && 481 (entry.type == DBUS_TYPE_STRING)) { 482 driver = os_strdup(entry.str_value); 483 wpa_dbus_dict_entry_clear(&entry); 484 if (driver == NULL) 485 goto error; 486 } else if (!strcmp(entry.key, "Ifname") && 487 (entry.type == DBUS_TYPE_STRING)) { 488 ifname = os_strdup(entry.str_value); 489 wpa_dbus_dict_entry_clear(&entry); 490 if (ifname == NULL) 491 goto error; 492 } else if (!strcmp(entry.key, "ConfigFile") && 493 (entry.type == DBUS_TYPE_STRING)) { 494 confname = os_strdup(entry.str_value); 495 wpa_dbus_dict_entry_clear(&entry); 496 if (confname == NULL) 497 goto error; 498 } else if (!strcmp(entry.key, "BridgeIfname") && 499 (entry.type == DBUS_TYPE_STRING)) { 500 bridge_ifname = os_strdup(entry.str_value); 501 wpa_dbus_dict_entry_clear(&entry); 502 if (bridge_ifname == NULL) 503 goto error; 504 } else { 505 wpa_dbus_dict_entry_clear(&entry); 506 goto error; 507 } 508 } 509 510 if (ifname == NULL) 511 goto error; /* Required Ifname argument missing */ 512 513 /* 514 * Try to get the wpa_supplicant record for this iface, return 515 * an error if we already control it. 516 */ 517 if (wpa_supplicant_get_iface(global, ifname) != NULL) { 518 reply = dbus_message_new_error(message, 519 WPAS_DBUS_ERROR_IFACE_EXISTS, 520 "wpa_supplicant already " 521 "controls this interface."); 522 } else { 523 struct wpa_supplicant *wpa_s; 524 struct wpa_interface iface; 525 os_memset(&iface, 0, sizeof(iface)); 526 iface.driver = driver; 527 iface.ifname = ifname; 528 iface.confname = confname; 529 iface.bridge_ifname = bridge_ifname; 530 /* Otherwise, have wpa_supplicant attach to it. */ 531 if ((wpa_s = wpa_supplicant_add_iface(global, &iface))) { 532 const char *path = wpa_s->dbus_new_path; 533 reply = dbus_message_new_method_return(message); 534 dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, 535 &path, DBUS_TYPE_INVALID); 536 } else { 537 reply = wpas_dbus_error_unknown_error( 538 message, "wpa_supplicant couldn't grab this " 539 "interface."); 540 } 541 } 542 543 out: 544 os_free(driver); 545 os_free(ifname); 546 os_free(bridge_ifname); 547 return reply; 548 549 error: 550 reply = wpas_dbus_error_invalid_args(message, NULL); 551 goto out; 552 } 553 554 555 /** 556 * wpas_dbus_handler_remove_interface - Request deregistration of an interface 557 * @message: Pointer to incoming dbus message 558 * @global: wpa_supplicant global data structure 559 * Returns: a dbus message containing a UINT32 indicating success (1) or 560 * failure (0), or returns a dbus error message with more information 561 * 562 * Handler function for "removeInterface" method call. Handles requests 563 * by dbus clients to deregister a network interface that wpa_supplicant 564 * currently manages. 565 */ 566 DBusMessage * wpas_dbus_handler_remove_interface(DBusMessage *message, 567 struct wpa_global *global) 568 { 569 struct wpa_supplicant *wpa_s; 570 char *path; 571 DBusMessage *reply = NULL; 572 573 dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &path, 574 DBUS_TYPE_INVALID); 575 576 wpa_s = get_iface_by_dbus_path(global, path); 577 if (wpa_s == NULL) 578 reply = wpas_dbus_error_iface_unknown(message); 579 else if (wpa_supplicant_remove_iface(global, wpa_s, 0)) { 580 reply = wpas_dbus_error_unknown_error( 581 message, "wpa_supplicant couldn't remove this " 582 "interface."); 583 } 584 585 return reply; 586 } 587 588 589 /** 590 * wpas_dbus_handler_get_interface - Get the object path for an interface name 591 * @message: Pointer to incoming dbus message 592 * @global: %wpa_supplicant global data structure 593 * Returns: The object path of the interface object, 594 * or a dbus error message with more information 595 * 596 * Handler function for "getInterface" method call. 597 */ 598 DBusMessage * wpas_dbus_handler_get_interface(DBusMessage *message, 599 struct wpa_global *global) 600 { 601 DBusMessage *reply = NULL; 602 const char *ifname; 603 const char *path; 604 struct wpa_supplicant *wpa_s; 605 606 dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &ifname, 607 DBUS_TYPE_INVALID); 608 609 wpa_s = wpa_supplicant_get_iface(global, ifname); 610 if (wpa_s == NULL) 611 return wpas_dbus_error_iface_unknown(message); 612 613 path = wpa_s->dbus_new_path; 614 reply = dbus_message_new_method_return(message); 615 if (reply == NULL) 616 return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, 617 NULL); 618 if (!dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &path, 619 DBUS_TYPE_INVALID)) { 620 dbus_message_unref(reply); 621 return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, 622 NULL); 623 } 624 625 return reply; 626 } 627 628 629 /** 630 * wpas_dbus_getter_debug_level - Get debug level 631 * @iter: Pointer to incoming dbus message iter 632 * @error: Location to store error on failure 633 * @user_data: Function specific data 634 * Returns: TRUE on success, FALSE on failure 635 * 636 * Getter for "DebugLevel" property. 637 */ 638 dbus_bool_t wpas_dbus_getter_debug_level(DBusMessageIter *iter, 639 DBusError *error, 640 void *user_data) 641 { 642 const char *str; 643 int idx = wpa_debug_level; 644 645 if (idx < 0) 646 idx = 0; 647 if (idx > 5) 648 idx = 5; 649 str = debug_strings[idx]; 650 return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING, 651 &str, error); 652 } 653 654 655 /** 656 * wpas_dbus_getter_debug_timestamp - Get debug timestamp 657 * @iter: Pointer to incoming dbus message iter 658 * @error: Location to store error on failure 659 * @user_data: Function specific data 660 * Returns: TRUE on success, FALSE on failure 661 * 662 * Getter for "DebugTimestamp" property. 663 */ 664 dbus_bool_t wpas_dbus_getter_debug_timestamp(DBusMessageIter *iter, 665 DBusError *error, 666 void *user_data) 667 { 668 return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN, 669 &wpa_debug_timestamp, error); 670 671 } 672 673 674 /** 675 * wpas_dbus_getter_debug_show_keys - Get debug show keys 676 * @iter: Pointer to incoming dbus message iter 677 * @error: Location to store error on failure 678 * @user_data: Function specific data 679 * Returns: TRUE on success, FALSE on failure 680 * 681 * Getter for "DebugShowKeys" property. 682 */ 683 dbus_bool_t wpas_dbus_getter_debug_show_keys(DBusMessageIter *iter, 684 DBusError *error, 685 void *user_data) 686 { 687 return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN, 688 &wpa_debug_show_keys, error); 689 690 } 691 692 /** 693 * wpas_dbus_setter_debug_level - Set debug level 694 * @iter: Pointer to incoming dbus message iter 695 * @error: Location to store error on failure 696 * @user_data: Function specific data 697 * Returns: TRUE on success, FALSE on failure 698 * 699 * Setter for "DebugLevel" property. 700 */ 701 dbus_bool_t wpas_dbus_setter_debug_level(DBusMessageIter *iter, 702 DBusError *error, void *user_data) 703 { 704 struct wpa_global *global = user_data; 705 const char *str = NULL; 706 int i, val = -1; 707 708 if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_STRING, 709 &str)) 710 return FALSE; 711 712 for (i = 0; debug_strings[i]; i++) 713 if (os_strcmp(debug_strings[i], str) == 0) { 714 val = i; 715 break; 716 } 717 718 if (val < 0 || 719 wpa_supplicant_set_debug_params(global, val, wpa_debug_timestamp, 720 wpa_debug_show_keys)) { 721 dbus_set_error_const(error, DBUS_ERROR_FAILED, "wrong debug " 722 "level value"); 723 return FALSE; 724 } 725 726 return TRUE; 727 } 728 729 730 /** 731 * wpas_dbus_setter_debug_timestamp - Set debug timestamp 732 * @iter: Pointer to incoming dbus message iter 733 * @error: Location to store error on failure 734 * @user_data: Function specific data 735 * Returns: TRUE on success, FALSE on failure 736 * 737 * Setter for "DebugTimestamp" property. 738 */ 739 dbus_bool_t wpas_dbus_setter_debug_timestamp(DBusMessageIter *iter, 740 DBusError *error, 741 void *user_data) 742 { 743 struct wpa_global *global = user_data; 744 dbus_bool_t val; 745 746 if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_BOOLEAN, 747 &val)) 748 return FALSE; 749 750 wpa_supplicant_set_debug_params(global, wpa_debug_level, val ? 1 : 0, 751 wpa_debug_show_keys); 752 return TRUE; 753 } 754 755 756 /** 757 * wpas_dbus_setter_debug_show_keys - Set debug show keys 758 * @iter: Pointer to incoming dbus message iter 759 * @error: Location to store error on failure 760 * @user_data: Function specific data 761 * Returns: TRUE on success, FALSE on failure 762 * 763 * Setter for "DebugShowKeys" property. 764 */ 765 dbus_bool_t wpas_dbus_setter_debug_show_keys(DBusMessageIter *iter, 766 DBusError *error, 767 void *user_data) 768 { 769 struct wpa_global *global = user_data; 770 dbus_bool_t val; 771 772 if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_BOOLEAN, 773 &val)) 774 return FALSE; 775 776 wpa_supplicant_set_debug_params(global, wpa_debug_level, 777 wpa_debug_timestamp, 778 val ? 1 : 0); 779 return TRUE; 780 } 781 782 783 /** 784 * wpas_dbus_getter_interfaces - Request registered interfaces list 785 * @iter: Pointer to incoming dbus message iter 786 * @error: Location to store error on failure 787 * @user_data: Function specific data 788 * Returns: TRUE on success, FALSE on failure 789 * 790 * Getter for "Interfaces" property. Handles requests 791 * by dbus clients to return list of registered interfaces objects 792 * paths 793 */ 794 dbus_bool_t wpas_dbus_getter_interfaces(DBusMessageIter *iter, 795 DBusError *error, 796 void *user_data) 797 { 798 struct wpa_global *global = user_data; 799 struct wpa_supplicant *wpa_s; 800 const char **paths; 801 unsigned int i = 0, num = 0; 802 dbus_bool_t success; 803 804 for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) 805 num++; 806 807 paths = os_zalloc(num * sizeof(char*)); 808 if (!paths) { 809 dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory"); 810 return FALSE; 811 } 812 813 for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) 814 paths[i++] = wpa_s->dbus_new_path; 815 816 success = wpas_dbus_simple_array_property_getter(iter, 817 DBUS_TYPE_OBJECT_PATH, 818 paths, num, error); 819 820 os_free(paths); 821 return success; 822 } 823 824 825 /** 826 * wpas_dbus_getter_eap_methods - Request supported EAP methods list 827 * @iter: Pointer to incoming dbus message iter 828 * @error: Location to store error on failure 829 * @user_data: Function specific data 830 * Returns: TRUE on success, FALSE on failure 831 * 832 * Getter for "EapMethods" property. Handles requests 833 * by dbus clients to return list of strings with supported EAP methods 834 */ 835 dbus_bool_t wpas_dbus_getter_eap_methods(DBusMessageIter *iter, 836 DBusError *error, void *user_data) 837 { 838 char **eap_methods; 839 size_t num_items = 0; 840 dbus_bool_t success; 841 842 eap_methods = eap_get_names_as_string_array(&num_items); 843 if (!eap_methods) { 844 dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory"); 845 return FALSE; 846 } 847 848 success = wpas_dbus_simple_array_property_getter(iter, 849 DBUS_TYPE_STRING, 850 eap_methods, 851 num_items, error); 852 853 while (num_items) 854 os_free(eap_methods[--num_items]); 855 os_free(eap_methods); 856 return success; 857 } 858 859 860 static int wpas_dbus_get_scan_type(DBusMessage *message, DBusMessageIter *var, 861 char **type, DBusMessage **reply) 862 { 863 if (dbus_message_iter_get_arg_type(var) != DBUS_TYPE_STRING) { 864 wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: " 865 "Type must be a string"); 866 *reply = wpas_dbus_error_invalid_args( 867 message, "Wrong Type value type. String required"); 868 return -1; 869 } 870 dbus_message_iter_get_basic(var, type); 871 return 0; 872 } 873 874 875 static int wpas_dbus_get_scan_ssids(DBusMessage *message, DBusMessageIter *var, 876 struct wpa_driver_scan_params *params, 877 DBusMessage **reply) 878 { 879 struct wpa_driver_scan_ssid *ssids = params->ssids; 880 size_t ssids_num = 0; 881 u8 *ssid; 882 DBusMessageIter array_iter, sub_array_iter; 883 char *val; 884 int len; 885 886 if (dbus_message_iter_get_arg_type(var) != DBUS_TYPE_ARRAY) { 887 wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: ssids " 888 "must be an array of arrays of bytes"); 889 *reply = wpas_dbus_error_invalid_args( 890 message, "Wrong SSIDs value type. Array of arrays of " 891 "bytes required"); 892 return -1; 893 } 894 895 dbus_message_iter_recurse(var, &array_iter); 896 897 if (dbus_message_iter_get_arg_type(&array_iter) != DBUS_TYPE_ARRAY || 898 dbus_message_iter_get_element_type(&array_iter) != DBUS_TYPE_BYTE) 899 { 900 wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: ssids " 901 "must be an array of arrays of bytes"); 902 *reply = wpas_dbus_error_invalid_args( 903 message, "Wrong SSIDs value type. Array of arrays of " 904 "bytes required"); 905 return -1; 906 } 907 908 while (dbus_message_iter_get_arg_type(&array_iter) == DBUS_TYPE_ARRAY) 909 { 910 if (ssids_num >= WPAS_MAX_SCAN_SSIDS) { 911 wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: " 912 "Too many ssids specified on scan dbus " 913 "call"); 914 *reply = wpas_dbus_error_invalid_args( 915 message, "Too many ssids specified. Specify " 916 "at most four"); 917 return -1; 918 } 919 920 dbus_message_iter_recurse(&array_iter, &sub_array_iter); 921 922 dbus_message_iter_get_fixed_array(&sub_array_iter, &val, &len); 923 924 if (len > MAX_SSID_LEN) { 925 wpa_printf(MSG_DEBUG, 926 "wpas_dbus_handler_scan[dbus]: " 927 "SSID too long (len=%d max_len=%d)", 928 len, MAX_SSID_LEN); 929 *reply = wpas_dbus_error_invalid_args( 930 message, "Invalid SSID: too long"); 931 return -1; 932 } 933 934 if (len != 0) { 935 ssid = os_malloc(len); 936 if (ssid == NULL) { 937 wpa_printf(MSG_DEBUG, 938 "wpas_dbus_handler_scan[dbus]: " 939 "out of memory. Cannot allocate " 940 "memory for SSID"); 941 *reply = dbus_message_new_error( 942 message, DBUS_ERROR_NO_MEMORY, NULL); 943 return -1; 944 } 945 os_memcpy(ssid, val, len); 946 } else { 947 /* Allow zero-length SSIDs */ 948 ssid = NULL; 949 } 950 951 ssids[ssids_num].ssid = ssid; 952 ssids[ssids_num].ssid_len = len; 953 954 dbus_message_iter_next(&array_iter); 955 ssids_num++; 956 } 957 958 params->num_ssids = ssids_num; 959 return 0; 960 } 961 962 963 static int wpas_dbus_get_scan_ies(DBusMessage *message, DBusMessageIter *var, 964 struct wpa_driver_scan_params *params, 965 DBusMessage **reply) 966 { 967 u8 *ies = NULL, *nies; 968 int ies_len = 0; 969 DBusMessageIter array_iter, sub_array_iter; 970 char *val; 971 int len; 972 973 if (dbus_message_iter_get_arg_type(var) != DBUS_TYPE_ARRAY) { 974 wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: ies must " 975 "be an array of arrays of bytes"); 976 *reply = wpas_dbus_error_invalid_args( 977 message, "Wrong IEs value type. Array of arrays of " 978 "bytes required"); 979 return -1; 980 } 981 982 dbus_message_iter_recurse(var, &array_iter); 983 984 if (dbus_message_iter_get_arg_type(&array_iter) != DBUS_TYPE_ARRAY || 985 dbus_message_iter_get_element_type(&array_iter) != DBUS_TYPE_BYTE) 986 { 987 wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: ies must " 988 "be an array of arrays of bytes"); 989 *reply = wpas_dbus_error_invalid_args( 990 message, "Wrong IEs value type. Array required"); 991 return -1; 992 } 993 994 while (dbus_message_iter_get_arg_type(&array_iter) == DBUS_TYPE_ARRAY) 995 { 996 dbus_message_iter_recurse(&array_iter, &sub_array_iter); 997 998 dbus_message_iter_get_fixed_array(&sub_array_iter, &val, &len); 999 if (len == 0) { 1000 dbus_message_iter_next(&array_iter); 1001 continue; 1002 } 1003 1004 nies = os_realloc(ies, ies_len + len); 1005 if (nies == NULL) { 1006 wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: " 1007 "out of memory. Cannot allocate memory for " 1008 "IE"); 1009 os_free(ies); 1010 *reply = dbus_message_new_error( 1011 message, DBUS_ERROR_NO_MEMORY, NULL); 1012 return -1; 1013 } 1014 ies = nies; 1015 os_memcpy(ies + ies_len, val, len); 1016 ies_len += len; 1017 1018 dbus_message_iter_next(&array_iter); 1019 } 1020 1021 params->extra_ies = ies; 1022 params->extra_ies_len = ies_len; 1023 return 0; 1024 } 1025 1026 1027 static int wpas_dbus_get_scan_channels(DBusMessage *message, 1028 DBusMessageIter *var, 1029 struct wpa_driver_scan_params *params, 1030 DBusMessage **reply) 1031 { 1032 DBusMessageIter array_iter, sub_array_iter; 1033 int *freqs = NULL, *nfreqs; 1034 int freqs_num = 0; 1035 1036 if (dbus_message_iter_get_arg_type(var) != DBUS_TYPE_ARRAY) { 1037 wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: " 1038 "Channels must be an array of structs"); 1039 *reply = wpas_dbus_error_invalid_args( 1040 message, "Wrong Channels value type. Array of structs " 1041 "required"); 1042 return -1; 1043 } 1044 1045 dbus_message_iter_recurse(var, &array_iter); 1046 1047 if (dbus_message_iter_get_arg_type(&array_iter) != DBUS_TYPE_STRUCT) { 1048 wpa_printf(MSG_DEBUG, 1049 "wpas_dbus_handler_scan[dbus]: Channels must be an " 1050 "array of structs"); 1051 *reply = wpas_dbus_error_invalid_args( 1052 message, "Wrong Channels value type. Array of structs " 1053 "required"); 1054 return -1; 1055 } 1056 1057 while (dbus_message_iter_get_arg_type(&array_iter) == DBUS_TYPE_STRUCT) 1058 { 1059 int freq, width; 1060 1061 dbus_message_iter_recurse(&array_iter, &sub_array_iter); 1062 1063 if (dbus_message_iter_get_arg_type(&sub_array_iter) != 1064 DBUS_TYPE_UINT32) { 1065 wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: " 1066 "Channel must by specified by struct of " 1067 "two UINT32s %c", 1068 dbus_message_iter_get_arg_type( 1069 &sub_array_iter)); 1070 *reply = wpas_dbus_error_invalid_args( 1071 message, "Wrong Channel struct. Two UINT32s " 1072 "required"); 1073 os_free(freqs); 1074 return -1; 1075 } 1076 dbus_message_iter_get_basic(&sub_array_iter, &freq); 1077 1078 if (!dbus_message_iter_next(&sub_array_iter) || 1079 dbus_message_iter_get_arg_type(&sub_array_iter) != 1080 DBUS_TYPE_UINT32) { 1081 wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: " 1082 "Channel must by specified by struct of " 1083 "two UINT32s"); 1084 *reply = wpas_dbus_error_invalid_args( 1085 message, 1086 "Wrong Channel struct. Two UINT32s required"); 1087 os_free(freqs); 1088 return -1; 1089 } 1090 1091 dbus_message_iter_get_basic(&sub_array_iter, &width); 1092 1093 #define FREQS_ALLOC_CHUNK 32 1094 if (freqs_num % FREQS_ALLOC_CHUNK == 0) { 1095 nfreqs = os_realloc(freqs, sizeof(int) * 1096 (freqs_num + FREQS_ALLOC_CHUNK)); 1097 if (nfreqs == NULL) 1098 os_free(freqs); 1099 freqs = nfreqs; 1100 } 1101 if (freqs == NULL) { 1102 wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: " 1103 "out of memory. can't allocate memory for " 1104 "freqs"); 1105 *reply = dbus_message_new_error( 1106 message, DBUS_ERROR_NO_MEMORY, NULL); 1107 return -1; 1108 } 1109 1110 freqs[freqs_num] = freq; 1111 1112 freqs_num++; 1113 dbus_message_iter_next(&array_iter); 1114 } 1115 1116 nfreqs = os_realloc(freqs, 1117 sizeof(int) * (freqs_num + 1)); 1118 if (nfreqs == NULL) 1119 os_free(freqs); 1120 freqs = nfreqs; 1121 if (freqs == NULL) { 1122 wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: " 1123 "out of memory. Can't allocate memory for freqs"); 1124 *reply = dbus_message_new_error( 1125 message, DBUS_ERROR_NO_MEMORY, NULL); 1126 return -1; 1127 } 1128 freqs[freqs_num] = 0; 1129 1130 params->freqs = freqs; 1131 return 0; 1132 } 1133 1134 1135 /** 1136 * wpas_dbus_handler_scan - Request a wireless scan on an interface 1137 * @message: Pointer to incoming dbus message 1138 * @wpa_s: wpa_supplicant structure for a network interface 1139 * Returns: NULL indicating success or DBus error message on failure 1140 * 1141 * Handler function for "Scan" method call of a network device. Requests 1142 * that wpa_supplicant perform a wireless scan as soon as possible 1143 * on a particular wireless interface. 1144 */ 1145 DBusMessage * wpas_dbus_handler_scan(DBusMessage *message, 1146 struct wpa_supplicant *wpa_s) 1147 { 1148 DBusMessage *reply = NULL; 1149 DBusMessageIter iter, dict_iter, entry_iter, variant_iter; 1150 char *key = NULL, *type = NULL; 1151 struct wpa_driver_scan_params params; 1152 size_t i; 1153 1154 os_memset(¶ms, 0, sizeof(params)); 1155 1156 dbus_message_iter_init(message, &iter); 1157 1158 dbus_message_iter_recurse(&iter, &dict_iter); 1159 1160 while (dbus_message_iter_get_arg_type(&dict_iter) == 1161 DBUS_TYPE_DICT_ENTRY) { 1162 dbus_message_iter_recurse(&dict_iter, &entry_iter); 1163 dbus_message_iter_get_basic(&entry_iter, &key); 1164 dbus_message_iter_next(&entry_iter); 1165 dbus_message_iter_recurse(&entry_iter, &variant_iter); 1166 1167 if (os_strcmp(key, "Type") == 0) { 1168 if (wpas_dbus_get_scan_type(message, &variant_iter, 1169 &type, &reply) < 0) 1170 goto out; 1171 } else if (os_strcmp(key, "SSIDs") == 0) { 1172 if (wpas_dbus_get_scan_ssids(message, &variant_iter, 1173 ¶ms, &reply) < 0) 1174 goto out; 1175 } else if (os_strcmp(key, "IEs") == 0) { 1176 if (wpas_dbus_get_scan_ies(message, &variant_iter, 1177 ¶ms, &reply) < 0) 1178 goto out; 1179 } else if (os_strcmp(key, "Channels") == 0) { 1180 if (wpas_dbus_get_scan_channels(message, &variant_iter, 1181 ¶ms, &reply) < 0) 1182 goto out; 1183 } else { 1184 wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: " 1185 "Unknown argument %s", key); 1186 reply = wpas_dbus_error_invalid_args(message, key); 1187 goto out; 1188 } 1189 1190 dbus_message_iter_next(&dict_iter); 1191 } 1192 1193 if (!type) { 1194 wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: " 1195 "Scan type not specified"); 1196 reply = wpas_dbus_error_invalid_args(message, key); 1197 goto out; 1198 } 1199 1200 if (!os_strcmp(type, "passive")) { 1201 if (params.num_ssids || params.extra_ies_len) { 1202 wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: " 1203 "SSIDs or IEs specified for passive scan."); 1204 reply = wpas_dbus_error_invalid_args( 1205 message, "You can specify only Channels in " 1206 "passive scan"); 1207 goto out; 1208 } else if (params.freqs && params.freqs[0]) { 1209 wpa_supplicant_trigger_scan(wpa_s, ¶ms); 1210 } else { 1211 wpa_s->scan_req = 2; 1212 wpa_supplicant_req_scan(wpa_s, 0, 0); 1213 } 1214 } else if (!os_strcmp(type, "active")) { 1215 if (!params.num_ssids) { 1216 /* Add wildcard ssid */ 1217 params.num_ssids++; 1218 } 1219 wpa_supplicant_trigger_scan(wpa_s, ¶ms); 1220 } else { 1221 wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: " 1222 "Unknown scan type: %s", type); 1223 reply = wpas_dbus_error_invalid_args(message, 1224 "Wrong scan type"); 1225 goto out; 1226 } 1227 1228 out: 1229 for (i = 0; i < WPAS_MAX_SCAN_SSIDS; i++) 1230 os_free((u8 *) params.ssids[i].ssid); 1231 os_free((u8 *) params.extra_ies); 1232 os_free(params.freqs); 1233 return reply; 1234 } 1235 1236 1237 /* 1238 * wpas_dbus_handler_disconnect - Terminate the current connection 1239 * @message: Pointer to incoming dbus message 1240 * @wpa_s: wpa_supplicant structure for a network interface 1241 * Returns: NotConnected DBus error message if already not connected 1242 * or NULL otherwise. 1243 * 1244 * Handler function for "Disconnect" method call of network interface. 1245 */ 1246 DBusMessage * wpas_dbus_handler_disconnect(DBusMessage *message, 1247 struct wpa_supplicant *wpa_s) 1248 { 1249 if (wpa_s->current_ssid != NULL) { 1250 wpa_s->disconnected = 1; 1251 wpa_supplicant_deauthenticate(wpa_s, 1252 WLAN_REASON_DEAUTH_LEAVING); 1253 1254 return NULL; 1255 } 1256 1257 return dbus_message_new_error(message, WPAS_DBUS_ERROR_NOT_CONNECTED, 1258 "This interface is not connected"); 1259 } 1260 1261 1262 /** 1263 * wpas_dbus_new_iface_add_network - Add a new configured network 1264 * @message: Pointer to incoming dbus message 1265 * @wpa_s: wpa_supplicant structure for a network interface 1266 * Returns: A dbus message containing the object path of the new network 1267 * 1268 * Handler function for "AddNetwork" method call of a network interface. 1269 */ 1270 DBusMessage * wpas_dbus_handler_add_network(DBusMessage *message, 1271 struct wpa_supplicant *wpa_s) 1272 { 1273 DBusMessage *reply = NULL; 1274 DBusMessageIter iter; 1275 struct wpa_ssid *ssid = NULL; 1276 char path_buf[WPAS_DBUS_OBJECT_PATH_MAX], *path = path_buf; 1277 DBusError error; 1278 1279 dbus_message_iter_init(message, &iter); 1280 1281 ssid = wpa_config_add_network(wpa_s->conf); 1282 if (ssid == NULL) { 1283 wpa_printf(MSG_ERROR, "wpas_dbus_handler_add_network[dbus]: " 1284 "can't add new interface."); 1285 reply = wpas_dbus_error_unknown_error( 1286 message, 1287 "wpa_supplicant could not add " 1288 "a network on this interface."); 1289 goto err; 1290 } 1291 wpas_notify_network_added(wpa_s, ssid); 1292 ssid->disabled = 1; 1293 wpa_config_set_network_defaults(ssid); 1294 1295 dbus_error_init(&error); 1296 if (!set_network_properties(wpa_s, ssid, &iter, &error)) { 1297 wpa_printf(MSG_DEBUG, "wpas_dbus_handler_add_network[dbus]:" 1298 "control interface couldn't set network " 1299 "properties"); 1300 reply = wpas_dbus_reply_new_from_error(message, &error, 1301 DBUS_ERROR_INVALID_ARGS, 1302 "Failed to add network"); 1303 dbus_error_free(&error); 1304 goto err; 1305 } 1306 1307 /* Construct the object path for this network. */ 1308 os_snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX, 1309 "%s/" WPAS_DBUS_NEW_NETWORKS_PART "/%d", 1310 wpa_s->dbus_new_path, ssid->id); 1311 1312 reply = dbus_message_new_method_return(message); 1313 if (reply == NULL) { 1314 reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, 1315 NULL); 1316 goto err; 1317 } 1318 if (!dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &path, 1319 DBUS_TYPE_INVALID)) { 1320 dbus_message_unref(reply); 1321 reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, 1322 NULL); 1323 goto err; 1324 } 1325 1326 return reply; 1327 1328 err: 1329 if (ssid) { 1330 wpas_notify_network_removed(wpa_s, ssid); 1331 wpa_config_remove_network(wpa_s->conf, ssid->id); 1332 } 1333 return reply; 1334 } 1335 1336 1337 /** 1338 * wpas_dbus_handler_remove_network - Remove a configured network 1339 * @message: Pointer to incoming dbus message 1340 * @wpa_s: wpa_supplicant structure for a network interface 1341 * Returns: NULL on success or dbus error on failure 1342 * 1343 * Handler function for "RemoveNetwork" method call of a network interface. 1344 */ 1345 DBusMessage * wpas_dbus_handler_remove_network(DBusMessage *message, 1346 struct wpa_supplicant *wpa_s) 1347 { 1348 DBusMessage *reply = NULL; 1349 const char *op; 1350 char *iface = NULL, *net_id = NULL; 1351 int id; 1352 struct wpa_ssid *ssid; 1353 1354 dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &op, 1355 DBUS_TYPE_INVALID); 1356 1357 /* Extract the network ID and ensure the network */ 1358 /* is actually a child of this interface */ 1359 iface = wpas_dbus_new_decompose_object_path(op, 0, &net_id, NULL); 1360 if (iface == NULL || os_strcmp(iface, wpa_s->dbus_new_path) != 0) { 1361 reply = wpas_dbus_error_invalid_args(message, op); 1362 goto out; 1363 } 1364 1365 id = strtoul(net_id, NULL, 10); 1366 if (errno == EINVAL) { 1367 reply = wpas_dbus_error_invalid_args(message, op); 1368 goto out; 1369 } 1370 1371 ssid = wpa_config_get_network(wpa_s->conf, id); 1372 if (ssid == NULL) { 1373 reply = wpas_dbus_error_network_unknown(message); 1374 goto out; 1375 } 1376 1377 wpas_notify_network_removed(wpa_s, ssid); 1378 1379 if (wpa_config_remove_network(wpa_s->conf, id) < 0) { 1380 wpa_printf(MSG_ERROR, 1381 "wpas_dbus_handler_remove_network[dbus]: " 1382 "error occurred when removing network %d", id); 1383 reply = wpas_dbus_error_unknown_error( 1384 message, "error removing the specified network on " 1385 "this interface."); 1386 goto out; 1387 } 1388 1389 if (ssid == wpa_s->current_ssid) 1390 wpa_supplicant_deauthenticate(wpa_s, 1391 WLAN_REASON_DEAUTH_LEAVING); 1392 1393 out: 1394 os_free(iface); 1395 os_free(net_id); 1396 return reply; 1397 } 1398 1399 1400 static void remove_network(void *arg, struct wpa_ssid *ssid) 1401 { 1402 struct wpa_supplicant *wpa_s = arg; 1403 1404 wpas_notify_network_removed(wpa_s, ssid); 1405 1406 if (wpa_config_remove_network(wpa_s->conf, ssid->id) < 0) { 1407 wpa_printf(MSG_ERROR, 1408 "wpas_dbus_handler_remove_all_networks[dbus]: " 1409 "error occurred when removing network %d", 1410 ssid->id); 1411 return; 1412 } 1413 1414 if (ssid == wpa_s->current_ssid) 1415 wpa_supplicant_disassociate(wpa_s, WLAN_REASON_DEAUTH_LEAVING); 1416 } 1417 1418 1419 /** 1420 * wpas_dbus_handler_remove_all_networks - Remove all configured networks 1421 * @message: Pointer to incoming dbus message 1422 * @wpa_s: wpa_supplicant structure for a network interface 1423 * Returns: NULL on success or dbus error on failure 1424 * 1425 * Handler function for "RemoveAllNetworks" method call of a network interface. 1426 */ 1427 DBusMessage * wpas_dbus_handler_remove_all_networks( 1428 DBusMessage *message, struct wpa_supplicant *wpa_s) 1429 { 1430 /* NB: could check for failure and return an error */ 1431 wpa_config_foreach_network(wpa_s->conf, remove_network, wpa_s); 1432 return NULL; 1433 } 1434 1435 1436 /** 1437 * wpas_dbus_handler_select_network - Attempt association with a network 1438 * @message: Pointer to incoming dbus message 1439 * @wpa_s: wpa_supplicant structure for a network interface 1440 * Returns: NULL on success or dbus error on failure 1441 * 1442 * Handler function for "SelectNetwork" method call of network interface. 1443 */ 1444 DBusMessage * wpas_dbus_handler_select_network(DBusMessage *message, 1445 struct wpa_supplicant *wpa_s) 1446 { 1447 DBusMessage *reply = NULL; 1448 const char *op; 1449 char *iface = NULL, *net_id = NULL; 1450 int id; 1451 struct wpa_ssid *ssid; 1452 1453 dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &op, 1454 DBUS_TYPE_INVALID); 1455 1456 /* Extract the network ID and ensure the network */ 1457 /* is actually a child of this interface */ 1458 iface = wpas_dbus_new_decompose_object_path(op, 0, &net_id, NULL); 1459 if (iface == NULL || os_strcmp(iface, wpa_s->dbus_new_path) != 0) { 1460 reply = wpas_dbus_error_invalid_args(message, op); 1461 goto out; 1462 } 1463 1464 id = strtoul(net_id, NULL, 10); 1465 if (errno == EINVAL) { 1466 reply = wpas_dbus_error_invalid_args(message, op); 1467 goto out; 1468 } 1469 1470 ssid = wpa_config_get_network(wpa_s->conf, id); 1471 if (ssid == NULL) { 1472 reply = wpas_dbus_error_network_unknown(message); 1473 goto out; 1474 } 1475 1476 /* Finally, associate with the network */ 1477 wpa_supplicant_select_network(wpa_s, ssid); 1478 1479 out: 1480 os_free(iface); 1481 os_free(net_id); 1482 return reply; 1483 } 1484 1485 1486 /** 1487 * wpas_dbus_handler_network_reply - Reply to a NetworkRequest signal 1488 * @message: Pointer to incoming dbus message 1489 * @wpa_s: wpa_supplicant structure for a network interface 1490 * Returns: NULL on success or dbus error on failure 1491 * 1492 * Handler function for "NetworkReply" method call of network interface. 1493 */ 1494 DBusMessage * wpas_dbus_handler_network_reply(DBusMessage *message, 1495 struct wpa_supplicant *wpa_s) 1496 { 1497 #ifdef IEEE8021X_EAPOL 1498 DBusMessage *reply = NULL; 1499 const char *op, *field, *value; 1500 char *iface = NULL, *net_id = NULL; 1501 int id; 1502 struct wpa_ssid *ssid; 1503 1504 if (!dbus_message_get_args(message, NULL, 1505 DBUS_TYPE_OBJECT_PATH, &op, 1506 DBUS_TYPE_STRING, &field, 1507 DBUS_TYPE_STRING, &value, 1508 DBUS_TYPE_INVALID)) 1509 return wpas_dbus_error_invalid_args(message, NULL); 1510 1511 /* Extract the network ID and ensure the network */ 1512 /* is actually a child of this interface */ 1513 iface = wpas_dbus_new_decompose_object_path(op, 0, &net_id, NULL); 1514 if (iface == NULL || os_strcmp(iface, wpa_s->dbus_new_path) != 0) { 1515 reply = wpas_dbus_error_invalid_args(message, op); 1516 goto out; 1517 } 1518 1519 id = strtoul(net_id, NULL, 10); 1520 if (errno == EINVAL) { 1521 reply = wpas_dbus_error_invalid_args(message, net_id); 1522 goto out; 1523 } 1524 1525 ssid = wpa_config_get_network(wpa_s->conf, id); 1526 if (ssid == NULL) { 1527 reply = wpas_dbus_error_network_unknown(message); 1528 goto out; 1529 } 1530 1531 if (wpa_supplicant_ctrl_iface_ctrl_rsp_handle(wpa_s, ssid, 1532 field, value) < 0) 1533 reply = wpas_dbus_error_invalid_args(message, field); 1534 else { 1535 /* Tell EAP to retry immediately */ 1536 eapol_sm_notify_ctrl_response(wpa_s->eapol); 1537 } 1538 1539 out: 1540 os_free(iface); 1541 os_free(net_id); 1542 return reply; 1543 #else /* IEEE8021X_EAPOL */ 1544 wpa_printf(MSG_DEBUG, "CTRL_IFACE: 802.1X not included"); 1545 return wpas_dbus_error_unknown_error(message, "802.1X not included"); 1546 #endif /* IEEE8021X_EAPOL */ 1547 } 1548 1549 1550 /** 1551 * wpas_dbus_handler_add_blob - Store named binary blob (ie, for certificates) 1552 * @message: Pointer to incoming dbus message 1553 * @wpa_s: %wpa_supplicant data structure 1554 * Returns: A dbus message containing an error on failure or NULL on success 1555 * 1556 * Asks wpa_supplicant to internally store a binary blobs. 1557 */ 1558 DBusMessage * wpas_dbus_handler_add_blob(DBusMessage *message, 1559 struct wpa_supplicant *wpa_s) 1560 { 1561 DBusMessage *reply = NULL; 1562 DBusMessageIter iter, array_iter; 1563 1564 char *blob_name; 1565 u8 *blob_data; 1566 int blob_len; 1567 struct wpa_config_blob *blob = NULL; 1568 1569 dbus_message_iter_init(message, &iter); 1570 dbus_message_iter_get_basic(&iter, &blob_name); 1571 1572 if (wpa_config_get_blob(wpa_s->conf, blob_name)) { 1573 return dbus_message_new_error(message, 1574 WPAS_DBUS_ERROR_BLOB_EXISTS, 1575 NULL); 1576 } 1577 1578 dbus_message_iter_next(&iter); 1579 dbus_message_iter_recurse(&iter, &array_iter); 1580 1581 dbus_message_iter_get_fixed_array(&array_iter, &blob_data, &blob_len); 1582 1583 blob = os_zalloc(sizeof(*blob)); 1584 if (!blob) { 1585 reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, 1586 NULL); 1587 goto err; 1588 } 1589 1590 blob->data = os_malloc(blob_len); 1591 if (!blob->data) { 1592 reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, 1593 NULL); 1594 goto err; 1595 } 1596 os_memcpy(blob->data, blob_data, blob_len); 1597 1598 blob->len = blob_len; 1599 blob->name = os_strdup(blob_name); 1600 if (!blob->name) { 1601 reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, 1602 NULL); 1603 goto err; 1604 } 1605 1606 wpa_config_set_blob(wpa_s->conf, blob); 1607 wpas_notify_blob_added(wpa_s, blob->name); 1608 1609 return reply; 1610 1611 err: 1612 if (blob) { 1613 os_free(blob->name); 1614 os_free(blob->data); 1615 os_free(blob); 1616 } 1617 return reply; 1618 } 1619 1620 1621 /** 1622 * wpas_dbus_handler_get_blob - Get named binary blob (ie, for certificates) 1623 * @message: Pointer to incoming dbus message 1624 * @wpa_s: %wpa_supplicant data structure 1625 * Returns: A dbus message containing array of bytes (blob) 1626 * 1627 * Gets one wpa_supplicant's binary blobs. 1628 */ 1629 DBusMessage * wpas_dbus_handler_get_blob(DBusMessage *message, 1630 struct wpa_supplicant *wpa_s) 1631 { 1632 DBusMessage *reply = NULL; 1633 DBusMessageIter iter, array_iter; 1634 1635 char *blob_name; 1636 const struct wpa_config_blob *blob; 1637 1638 dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &blob_name, 1639 DBUS_TYPE_INVALID); 1640 1641 blob = wpa_config_get_blob(wpa_s->conf, blob_name); 1642 if (!blob) { 1643 return dbus_message_new_error(message, 1644 WPAS_DBUS_ERROR_BLOB_UNKNOWN, 1645 "Blob id not set"); 1646 } 1647 1648 reply = dbus_message_new_method_return(message); 1649 if (!reply) { 1650 reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, 1651 NULL); 1652 goto out; 1653 } 1654 1655 dbus_message_iter_init_append(reply, &iter); 1656 1657 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, 1658 DBUS_TYPE_BYTE_AS_STRING, 1659 &array_iter)) { 1660 dbus_message_unref(reply); 1661 reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, 1662 NULL); 1663 goto out; 1664 } 1665 1666 if (!dbus_message_iter_append_fixed_array(&array_iter, DBUS_TYPE_BYTE, 1667 &(blob->data), blob->len)) { 1668 dbus_message_unref(reply); 1669 reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, 1670 NULL); 1671 goto out; 1672 } 1673 1674 if (!dbus_message_iter_close_container(&iter, &array_iter)) { 1675 dbus_message_unref(reply); 1676 reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, 1677 NULL); 1678 goto out; 1679 } 1680 1681 out: 1682 return reply; 1683 } 1684 1685 1686 /** 1687 * wpas_remove_handler_remove_blob - Remove named binary blob 1688 * @message: Pointer to incoming dbus message 1689 * @wpa_s: %wpa_supplicant data structure 1690 * Returns: NULL on success or dbus error 1691 * 1692 * Asks wpa_supplicant to internally remove a binary blobs. 1693 */ 1694 DBusMessage * wpas_dbus_handler_remove_blob(DBusMessage *message, 1695 struct wpa_supplicant *wpa_s) 1696 { 1697 DBusMessage *reply = NULL; 1698 char *blob_name; 1699 1700 dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &blob_name, 1701 DBUS_TYPE_INVALID); 1702 1703 if (wpa_config_remove_blob(wpa_s->conf, blob_name)) { 1704 return dbus_message_new_error(message, 1705 WPAS_DBUS_ERROR_BLOB_UNKNOWN, 1706 "Blob id not set"); 1707 } 1708 wpas_notify_blob_removed(wpa_s, blob_name); 1709 1710 return reply; 1711 1712 } 1713 1714 /* 1715 * wpas_dbus_handler_flush_bss - Flush the BSS cache 1716 * @message: Pointer to incoming dbus message 1717 * @wpa_s: wpa_supplicant structure for a network interface 1718 * Returns: NULL 1719 * 1720 * Handler function for "FlushBSS" method call of network interface. 1721 */ 1722 DBusMessage * wpas_dbus_handler_flush_bss(DBusMessage *message, 1723 struct wpa_supplicant *wpa_s) 1724 { 1725 dbus_uint32_t age; 1726 1727 dbus_message_get_args(message, NULL, DBUS_TYPE_UINT32, &age, 1728 DBUS_TYPE_INVALID); 1729 1730 if (age == 0) 1731 wpa_bss_flush(wpa_s); 1732 else 1733 wpa_bss_flush_by_age(wpa_s, age); 1734 1735 return NULL; 1736 } 1737 1738 1739 /** 1740 * wpas_dbus_getter_capabilities - Return interface capabilities 1741 * @iter: Pointer to incoming dbus message iter 1742 * @error: Location to store error on failure 1743 * @user_data: Function specific data 1744 * Returns: TRUE on success, FALSE on failure 1745 * 1746 * Getter for "Capabilities" property of an interface. 1747 */ 1748 dbus_bool_t wpas_dbus_getter_capabilities(DBusMessageIter *iter, 1749 DBusError *error, void *user_data) 1750 { 1751 struct wpa_supplicant *wpa_s = user_data; 1752 struct wpa_driver_capa capa; 1753 int res; 1754 DBusMessageIter iter_dict, iter_dict_entry, iter_dict_val, iter_array, 1755 variant_iter; 1756 const char *scans[] = { "active", "passive", "ssid" }; 1757 1758 if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, 1759 "a{sv}", &variant_iter)) 1760 goto nomem; 1761 1762 if (!wpa_dbus_dict_open_write(&variant_iter, &iter_dict)) 1763 goto nomem; 1764 1765 res = wpa_drv_get_capa(wpa_s, &capa); 1766 1767 /***** pairwise cipher */ 1768 if (res < 0) { 1769 const char *args[] = {"ccmp", "tkip", "none"}; 1770 if (!wpa_dbus_dict_append_string_array( 1771 &iter_dict, "Pairwise", args, 1772 sizeof(args) / sizeof(char*))) 1773 goto nomem; 1774 } else { 1775 if (!wpa_dbus_dict_begin_string_array(&iter_dict, "Pairwise", 1776 &iter_dict_entry, 1777 &iter_dict_val, 1778 &iter_array)) 1779 goto nomem; 1780 1781 if (capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) { 1782 if (!wpa_dbus_dict_string_array_add_element( 1783 &iter_array, "ccmp")) 1784 goto nomem; 1785 } 1786 1787 if (capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) { 1788 if (!wpa_dbus_dict_string_array_add_element( 1789 &iter_array, "tkip")) 1790 goto nomem; 1791 } 1792 1793 if (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) { 1794 if (!wpa_dbus_dict_string_array_add_element( 1795 &iter_array, "none")) 1796 goto nomem; 1797 } 1798 1799 if (!wpa_dbus_dict_end_string_array(&iter_dict, 1800 &iter_dict_entry, 1801 &iter_dict_val, 1802 &iter_array)) 1803 goto nomem; 1804 } 1805 1806 /***** group cipher */ 1807 if (res < 0) { 1808 const char *args[] = { 1809 "ccmp", "tkip", "wep104", "wep40" 1810 }; 1811 if (!wpa_dbus_dict_append_string_array( 1812 &iter_dict, "Group", args, 1813 sizeof(args) / sizeof(char*))) 1814 goto nomem; 1815 } else { 1816 if (!wpa_dbus_dict_begin_string_array(&iter_dict, "Group", 1817 &iter_dict_entry, 1818 &iter_dict_val, 1819 &iter_array)) 1820 goto nomem; 1821 1822 if (capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) { 1823 if (!wpa_dbus_dict_string_array_add_element( 1824 &iter_array, "ccmp")) 1825 goto nomem; 1826 } 1827 1828 if (capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) { 1829 if (!wpa_dbus_dict_string_array_add_element( 1830 &iter_array, "tkip")) 1831 goto nomem; 1832 } 1833 1834 if (capa.enc & WPA_DRIVER_CAPA_ENC_WEP104) { 1835 if (!wpa_dbus_dict_string_array_add_element( 1836 &iter_array, "wep104")) 1837 goto nomem; 1838 } 1839 1840 if (capa.enc & WPA_DRIVER_CAPA_ENC_WEP40) { 1841 if (!wpa_dbus_dict_string_array_add_element( 1842 &iter_array, "wep40")) 1843 goto nomem; 1844 } 1845 1846 if (!wpa_dbus_dict_end_string_array(&iter_dict, 1847 &iter_dict_entry, 1848 &iter_dict_val, 1849 &iter_array)) 1850 goto nomem; 1851 } 1852 1853 /***** key management */ 1854 if (res < 0) { 1855 const char *args[] = { 1856 "wpa-psk", "wpa-eap", "ieee8021x", "wpa-none", 1857 #ifdef CONFIG_WPS 1858 "wps", 1859 #endif /* CONFIG_WPS */ 1860 "none" 1861 }; 1862 if (!wpa_dbus_dict_append_string_array( 1863 &iter_dict, "KeyMgmt", args, 1864 sizeof(args) / sizeof(char*))) 1865 goto nomem; 1866 } else { 1867 if (!wpa_dbus_dict_begin_string_array(&iter_dict, "KeyMgmt", 1868 &iter_dict_entry, 1869 &iter_dict_val, 1870 &iter_array)) 1871 goto nomem; 1872 1873 if (!wpa_dbus_dict_string_array_add_element(&iter_array, 1874 "none")) 1875 goto nomem; 1876 1877 if (!wpa_dbus_dict_string_array_add_element(&iter_array, 1878 "ieee8021x")) 1879 goto nomem; 1880 1881 if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA | 1882 WPA_DRIVER_CAPA_KEY_MGMT_WPA2)) { 1883 if (!wpa_dbus_dict_string_array_add_element( 1884 &iter_array, "wpa-eap")) 1885 goto nomem; 1886 1887 if (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FT) 1888 if (!wpa_dbus_dict_string_array_add_element( 1889 &iter_array, "wpa-ft-eap")) 1890 goto nomem; 1891 1892 /* TODO: Ensure that driver actually supports sha256 encryption. */ 1893 #ifdef CONFIG_IEEE80211W 1894 if (!wpa_dbus_dict_string_array_add_element( 1895 &iter_array, "wpa-eap-sha256")) 1896 goto nomem; 1897 #endif /* CONFIG_IEEE80211W */ 1898 } 1899 1900 if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK | 1901 WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) { 1902 if (!wpa_dbus_dict_string_array_add_element( 1903 &iter_array, "wpa-psk")) 1904 goto nomem; 1905 1906 if (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FT_PSK) 1907 if (!wpa_dbus_dict_string_array_add_element( 1908 &iter_array, "wpa-ft-psk")) 1909 goto nomem; 1910 1911 /* TODO: Ensure that driver actually supports sha256 encryption. */ 1912 #ifdef CONFIG_IEEE80211W 1913 if (!wpa_dbus_dict_string_array_add_element( 1914 &iter_array, "wpa-psk-sha256")) 1915 goto nomem; 1916 #endif /* CONFIG_IEEE80211W */ 1917 } 1918 1919 if (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) { 1920 if (!wpa_dbus_dict_string_array_add_element( 1921 &iter_array, "wpa-none")) 1922 goto nomem; 1923 } 1924 1925 1926 #ifdef CONFIG_WPS 1927 if (!wpa_dbus_dict_string_array_add_element(&iter_array, 1928 "wps")) 1929 goto nomem; 1930 #endif /* CONFIG_WPS */ 1931 1932 if (!wpa_dbus_dict_end_string_array(&iter_dict, 1933 &iter_dict_entry, 1934 &iter_dict_val, 1935 &iter_array)) 1936 goto nomem; 1937 } 1938 1939 /***** WPA protocol */ 1940 if (res < 0) { 1941 const char *args[] = { "rsn", "wpa" }; 1942 if (!wpa_dbus_dict_append_string_array( 1943 &iter_dict, "Protocol", args, 1944 sizeof(args) / sizeof(char*))) 1945 goto nomem; 1946 } else { 1947 if (!wpa_dbus_dict_begin_string_array(&iter_dict, "Protocol", 1948 &iter_dict_entry, 1949 &iter_dict_val, 1950 &iter_array)) 1951 goto nomem; 1952 1953 if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA2 | 1954 WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) { 1955 if (!wpa_dbus_dict_string_array_add_element( 1956 &iter_array, "rsn")) 1957 goto nomem; 1958 } 1959 1960 if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA | 1961 WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK)) { 1962 if (!wpa_dbus_dict_string_array_add_element( 1963 &iter_array, "wpa")) 1964 goto nomem; 1965 } 1966 1967 if (!wpa_dbus_dict_end_string_array(&iter_dict, 1968 &iter_dict_entry, 1969 &iter_dict_val, 1970 &iter_array)) 1971 goto nomem; 1972 } 1973 1974 /***** auth alg */ 1975 if (res < 0) { 1976 const char *args[] = { "open", "shared", "leap" }; 1977 if (!wpa_dbus_dict_append_string_array( 1978 &iter_dict, "AuthAlg", args, 1979 sizeof(args) / sizeof(char*))) 1980 goto nomem; 1981 } else { 1982 if (!wpa_dbus_dict_begin_string_array(&iter_dict, "AuthAlg", 1983 &iter_dict_entry, 1984 &iter_dict_val, 1985 &iter_array)) 1986 goto nomem; 1987 1988 if (capa.auth & (WPA_DRIVER_AUTH_OPEN)) { 1989 if (!wpa_dbus_dict_string_array_add_element( 1990 &iter_array, "open")) 1991 goto nomem; 1992 } 1993 1994 if (capa.auth & (WPA_DRIVER_AUTH_SHARED)) { 1995 if (!wpa_dbus_dict_string_array_add_element( 1996 &iter_array, "shared")) 1997 goto nomem; 1998 } 1999 2000 if (capa.auth & (WPA_DRIVER_AUTH_LEAP)) { 2001 if (!wpa_dbus_dict_string_array_add_element( 2002 &iter_array, "leap")) 2003 goto nomem; 2004 } 2005 2006 if (!wpa_dbus_dict_end_string_array(&iter_dict, 2007 &iter_dict_entry, 2008 &iter_dict_val, 2009 &iter_array)) 2010 goto nomem; 2011 } 2012 2013 /***** Scan */ 2014 if (!wpa_dbus_dict_append_string_array(&iter_dict, "Scan", scans, 2015 sizeof(scans) / sizeof(char *))) 2016 goto nomem; 2017 2018 /***** Modes */ 2019 if (!wpa_dbus_dict_begin_string_array(&iter_dict, "Modes", 2020 &iter_dict_entry, 2021 &iter_dict_val, 2022 &iter_array)) 2023 goto nomem; 2024 2025 if (!wpa_dbus_dict_string_array_add_element( 2026 &iter_array, "infrastructure")) 2027 goto nomem; 2028 2029 if (!wpa_dbus_dict_string_array_add_element( 2030 &iter_array, "ad-hoc")) 2031 goto nomem; 2032 2033 if (res >= 0) { 2034 if (capa.flags & (WPA_DRIVER_FLAGS_AP)) { 2035 if (!wpa_dbus_dict_string_array_add_element( 2036 &iter_array, "ap")) 2037 goto nomem; 2038 } 2039 2040 if (capa.flags & (WPA_DRIVER_FLAGS_P2P_CAPABLE)) { 2041 if (!wpa_dbus_dict_string_array_add_element( 2042 &iter_array, "p2p")) 2043 goto nomem; 2044 } 2045 } 2046 2047 if (!wpa_dbus_dict_end_string_array(&iter_dict, 2048 &iter_dict_entry, 2049 &iter_dict_val, 2050 &iter_array)) 2051 goto nomem; 2052 /***** Modes end */ 2053 2054 if (res >= 0) { 2055 dbus_int32_t max_scan_ssid = capa.max_scan_ssids; 2056 2057 if (!wpa_dbus_dict_append_int32(&iter_dict, "MaxScanSSID", 2058 max_scan_ssid)) 2059 goto nomem; 2060 } 2061 2062 if (!wpa_dbus_dict_close_write(&variant_iter, &iter_dict)) 2063 goto nomem; 2064 if (!dbus_message_iter_close_container(iter, &variant_iter)) 2065 goto nomem; 2066 2067 return TRUE; 2068 2069 nomem: 2070 dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory"); 2071 return FALSE; 2072 } 2073 2074 2075 /** 2076 * wpas_dbus_getter_state - Get interface state 2077 * @iter: Pointer to incoming dbus message iter 2078 * @error: Location to store error on failure 2079 * @user_data: Function specific data 2080 * Returns: TRUE on success, FALSE on failure 2081 * 2082 * Getter for "State" property. 2083 */ 2084 dbus_bool_t wpas_dbus_getter_state(DBusMessageIter *iter, DBusError *error, 2085 void *user_data) 2086 { 2087 struct wpa_supplicant *wpa_s = user_data; 2088 const char *str_state; 2089 char *state_ls, *tmp; 2090 dbus_bool_t success = FALSE; 2091 2092 str_state = wpa_supplicant_state_txt(wpa_s->wpa_state); 2093 2094 /* make state string lowercase to fit new DBus API convention 2095 */ 2096 state_ls = tmp = os_strdup(str_state); 2097 if (!tmp) { 2098 dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory"); 2099 return FALSE; 2100 } 2101 while (*tmp) { 2102 *tmp = tolower(*tmp); 2103 tmp++; 2104 } 2105 2106 success = wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING, 2107 &state_ls, error); 2108 2109 os_free(state_ls); 2110 2111 return success; 2112 } 2113 2114 2115 /** 2116 * wpas_dbus_new_iface_get_scanning - Get interface scanning state 2117 * @iter: Pointer to incoming dbus message iter 2118 * @error: Location to store error on failure 2119 * @user_data: Function specific data 2120 * Returns: TRUE on success, FALSE on failure 2121 * 2122 * Getter for "scanning" property. 2123 */ 2124 dbus_bool_t wpas_dbus_getter_scanning(DBusMessageIter *iter, DBusError *error, 2125 void *user_data) 2126 { 2127 struct wpa_supplicant *wpa_s = user_data; 2128 dbus_bool_t scanning = wpa_s->scanning ? TRUE : FALSE; 2129 2130 return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN, 2131 &scanning, error); 2132 } 2133 2134 2135 /** 2136 * wpas_dbus_getter_ap_scan - Control roaming mode 2137 * @iter: Pointer to incoming dbus message iter 2138 * @error: Location to store error on failure 2139 * @user_data: Function specific data 2140 * Returns: TRUE on success, FALSE on failure 2141 * 2142 * Getter function for "ApScan" property. 2143 */ 2144 dbus_bool_t wpas_dbus_getter_ap_scan(DBusMessageIter *iter, DBusError *error, 2145 void *user_data) 2146 { 2147 struct wpa_supplicant *wpa_s = user_data; 2148 dbus_uint32_t ap_scan = wpa_s->conf->ap_scan; 2149 2150 return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT32, 2151 &ap_scan, error); 2152 } 2153 2154 2155 /** 2156 * wpas_dbus_setter_ap_scan - Control roaming mode 2157 * @iter: Pointer to incoming dbus message iter 2158 * @error: Location to store error on failure 2159 * @user_data: Function specific data 2160 * Returns: TRUE on success, FALSE on failure 2161 * 2162 * Setter function for "ApScan" property. 2163 */ 2164 dbus_bool_t wpas_dbus_setter_ap_scan(DBusMessageIter *iter, DBusError *error, 2165 void *user_data) 2166 { 2167 struct wpa_supplicant *wpa_s = user_data; 2168 dbus_uint32_t ap_scan; 2169 2170 if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_UINT32, 2171 &ap_scan)) 2172 return FALSE; 2173 2174 if (wpa_supplicant_set_ap_scan(wpa_s, ap_scan)) { 2175 dbus_set_error_const(error, DBUS_ERROR_FAILED, 2176 "ap_scan must be 0, 1, or 2"); 2177 return FALSE; 2178 } 2179 return TRUE; 2180 } 2181 2182 2183 /** 2184 * wpas_dbus_getter_fast_reauth - Control fast 2185 * reauthentication (TLS session resumption) 2186 * @iter: Pointer to incoming dbus message iter 2187 * @error: Location to store error on failure 2188 * @user_data: Function specific data 2189 * Returns: TRUE on success, FALSE on failure 2190 * 2191 * Getter function for "FastReauth" property. 2192 */ 2193 dbus_bool_t wpas_dbus_getter_fast_reauth(DBusMessageIter *iter, 2194 DBusError *error, 2195 void *user_data) 2196 { 2197 struct wpa_supplicant *wpa_s = user_data; 2198 dbus_bool_t fast_reauth = wpa_s->conf->fast_reauth ? TRUE : FALSE; 2199 2200 return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN, 2201 &fast_reauth, error); 2202 } 2203 2204 2205 /** 2206 * wpas_dbus_setter_fast_reauth - Control fast 2207 * reauthentication (TLS session resumption) 2208 * @iter: Pointer to incoming dbus message iter 2209 * @error: Location to store error on failure 2210 * @user_data: Function specific data 2211 * Returns: TRUE on success, FALSE on failure 2212 * 2213 * Setter function for "FastReauth" property. 2214 */ 2215 dbus_bool_t wpas_dbus_setter_fast_reauth(DBusMessageIter *iter, 2216 DBusError *error, 2217 void *user_data) 2218 { 2219 struct wpa_supplicant *wpa_s = user_data; 2220 dbus_bool_t fast_reauth; 2221 2222 if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_BOOLEAN, 2223 &fast_reauth)) 2224 return FALSE; 2225 2226 wpa_s->conf->fast_reauth = fast_reauth; 2227 return TRUE; 2228 } 2229 2230 2231 /** 2232 * wpas_dbus_getter_bss_expire_age - Get BSS entry expiration age 2233 * @iter: Pointer to incoming dbus message iter 2234 * @error: Location to store error on failure 2235 * @user_data: Function specific data 2236 * Returns: TRUE on success, FALSE on failure 2237 * 2238 * Getter function for "BSSExpireAge" property. 2239 */ 2240 dbus_bool_t wpas_dbus_getter_bss_expire_age(DBusMessageIter *iter, 2241 DBusError *error, 2242 void *user_data) 2243 { 2244 struct wpa_supplicant *wpa_s = user_data; 2245 dbus_uint32_t expire_age = wpa_s->conf->bss_expiration_age; 2246 2247 return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT32, 2248 &expire_age, error); 2249 } 2250 2251 2252 /** 2253 * wpas_dbus_setter_bss_expire_age - Control BSS entry expiration age 2254 * @iter: Pointer to incoming dbus message iter 2255 * @error: Location to store error on failure 2256 * @user_data: Function specific data 2257 * Returns: TRUE on success, FALSE on failure 2258 * 2259 * Setter function for "BSSExpireAge" property. 2260 */ 2261 dbus_bool_t wpas_dbus_setter_bss_expire_age(DBusMessageIter *iter, 2262 DBusError *error, 2263 void *user_data) 2264 { 2265 struct wpa_supplicant *wpa_s = user_data; 2266 dbus_uint32_t expire_age; 2267 2268 if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_UINT32, 2269 &expire_age)) 2270 return FALSE; 2271 2272 if (wpa_supplicant_set_bss_expiration_age(wpa_s, expire_age)) { 2273 dbus_set_error_const(error, DBUS_ERROR_FAILED, 2274 "BSSExpireAge must be >= 10"); 2275 return FALSE; 2276 } 2277 return TRUE; 2278 } 2279 2280 2281 /** 2282 * wpas_dbus_getter_bss_expire_count - Get BSS entry expiration scan count 2283 * @iter: Pointer to incoming dbus message iter 2284 * @error: Location to store error on failure 2285 * @user_data: Function specific data 2286 * Returns: TRUE on success, FALSE on failure 2287 * 2288 * Getter function for "BSSExpireCount" property. 2289 */ 2290 dbus_bool_t wpas_dbus_getter_bss_expire_count(DBusMessageIter *iter, 2291 DBusError *error, 2292 void *user_data) 2293 { 2294 struct wpa_supplicant *wpa_s = user_data; 2295 dbus_uint32_t expire_count = wpa_s->conf->bss_expiration_age; 2296 2297 return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT32, 2298 &expire_count, error); 2299 } 2300 2301 2302 /** 2303 * wpas_dbus_setter_bss_expire_count - Control BSS entry expiration scan count 2304 * @iter: Pointer to incoming dbus message iter 2305 * @error: Location to store error on failure 2306 * @user_data: Function specific data 2307 * Returns: TRUE on success, FALSE on failure 2308 * 2309 * Setter function for "BSSExpireCount" property. 2310 */ 2311 dbus_bool_t wpas_dbus_setter_bss_expire_count(DBusMessageIter *iter, 2312 DBusError *error, 2313 void *user_data) 2314 { 2315 struct wpa_supplicant *wpa_s = user_data; 2316 dbus_uint32_t expire_count; 2317 2318 if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_UINT32, 2319 &expire_count)) 2320 return FALSE; 2321 2322 if (wpa_supplicant_set_bss_expiration_count(wpa_s, expire_count)) { 2323 dbus_set_error_const(error, DBUS_ERROR_FAILED, 2324 "BSSExpireCount must be > 0"); 2325 return FALSE; 2326 } 2327 return TRUE; 2328 } 2329 2330 2331 /** 2332 * wpas_dbus_getter_country - Control country code 2333 * @iter: Pointer to incoming dbus message iter 2334 * @error: Location to store error on failure 2335 * @user_data: Function specific data 2336 * Returns: TRUE on success, FALSE on failure 2337 * 2338 * Getter function for "Country" property. 2339 */ 2340 dbus_bool_t wpas_dbus_getter_country(DBusMessageIter *iter, DBusError *error, 2341 void *user_data) 2342 { 2343 struct wpa_supplicant *wpa_s = user_data; 2344 char country[3]; 2345 char *str = country; 2346 2347 country[0] = wpa_s->conf->country[0]; 2348 country[1] = wpa_s->conf->country[1]; 2349 country[2] = '\0'; 2350 2351 return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING, 2352 &str, error); 2353 } 2354 2355 2356 /** 2357 * wpas_dbus_setter_country - Control country code 2358 * @iter: Pointer to incoming dbus message iter 2359 * @error: Location to store error on failure 2360 * @user_data: Function specific data 2361 * Returns: TRUE on success, FALSE on failure 2362 * 2363 * Setter function for "Country" property. 2364 */ 2365 dbus_bool_t wpas_dbus_setter_country(DBusMessageIter *iter, DBusError *error, 2366 void *user_data) 2367 { 2368 struct wpa_supplicant *wpa_s = user_data; 2369 const char *country; 2370 2371 if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_STRING, 2372 &country)) 2373 return FALSE; 2374 2375 if (!country[0] || !country[1]) { 2376 dbus_set_error_const(error, DBUS_ERROR_FAILED, 2377 "invalid country code"); 2378 return FALSE; 2379 } 2380 2381 if (wpa_s->drv_priv != NULL && wpa_drv_set_country(wpa_s, country)) { 2382 wpa_printf(MSG_DEBUG, "Failed to set country"); 2383 dbus_set_error_const(error, DBUS_ERROR_FAILED, 2384 "failed to set country code"); 2385 return FALSE; 2386 } 2387 2388 wpa_s->conf->country[0] = country[0]; 2389 wpa_s->conf->country[1] = country[1]; 2390 return TRUE; 2391 } 2392 2393 2394 /** 2395 * wpas_dbus_getter_ifname - Get interface name 2396 * @iter: Pointer to incoming dbus message iter 2397 * @error: Location to store error on failure 2398 * @user_data: Function specific data 2399 * Returns: TRUE on success, FALSE on failure 2400 * 2401 * Getter for "Ifname" property. 2402 */ 2403 dbus_bool_t wpas_dbus_getter_ifname(DBusMessageIter *iter, DBusError *error, 2404 void *user_data) 2405 { 2406 struct wpa_supplicant *wpa_s = user_data; 2407 const char *ifname = wpa_s->ifname; 2408 2409 return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING, 2410 &ifname, error); 2411 } 2412 2413 2414 /** 2415 * wpas_dbus_getter_driver - Get interface name 2416 * @iter: Pointer to incoming dbus message iter 2417 * @error: Location to store error on failure 2418 * @user_data: Function specific data 2419 * Returns: TRUE on success, FALSE on failure 2420 * 2421 * Getter for "Driver" property. 2422 */ 2423 dbus_bool_t wpas_dbus_getter_driver(DBusMessageIter *iter, DBusError *error, 2424 void *user_data) 2425 { 2426 struct wpa_supplicant *wpa_s = user_data; 2427 const char *driver; 2428 2429 if (wpa_s->driver == NULL || wpa_s->driver->name == NULL) { 2430 wpa_printf(MSG_DEBUG, "wpas_dbus_getter_driver[dbus]: " 2431 "wpa_s has no driver set"); 2432 dbus_set_error(error, DBUS_ERROR_FAILED, "%s: no driver set", 2433 __func__); 2434 return FALSE; 2435 } 2436 2437 driver = wpa_s->driver->name; 2438 return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING, 2439 &driver, error); 2440 } 2441 2442 2443 /** 2444 * wpas_dbus_getter_current_bss - Get current bss object path 2445 * @iter: Pointer to incoming dbus message iter 2446 * @error: Location to store error on failure 2447 * @user_data: Function specific data 2448 * Returns: TRUE on success, FALSE on failure 2449 * 2450 * Getter for "CurrentBSS" property. 2451 */ 2452 dbus_bool_t wpas_dbus_getter_current_bss(DBusMessageIter *iter, 2453 DBusError *error, 2454 void *user_data) 2455 { 2456 struct wpa_supplicant *wpa_s = user_data; 2457 char path_buf[WPAS_DBUS_OBJECT_PATH_MAX], *bss_obj_path = path_buf; 2458 2459 if (wpa_s->current_bss) 2460 os_snprintf(bss_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, 2461 "%s/" WPAS_DBUS_NEW_BSSIDS_PART "/%u", 2462 wpa_s->dbus_new_path, wpa_s->current_bss->id); 2463 else 2464 os_snprintf(bss_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, "/"); 2465 2466 return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_OBJECT_PATH, 2467 &bss_obj_path, error); 2468 } 2469 2470 2471 /** 2472 * wpas_dbus_getter_current_network - Get current network object path 2473 * @iter: Pointer to incoming dbus message iter 2474 * @error: Location to store error on failure 2475 * @user_data: Function specific data 2476 * Returns: TRUE on success, FALSE on failure 2477 * 2478 * Getter for "CurrentNetwork" property. 2479 */ 2480 dbus_bool_t wpas_dbus_getter_current_network(DBusMessageIter *iter, 2481 DBusError *error, 2482 void *user_data) 2483 { 2484 struct wpa_supplicant *wpa_s = user_data; 2485 char path_buf[WPAS_DBUS_OBJECT_PATH_MAX], *net_obj_path = path_buf; 2486 2487 if (wpa_s->current_ssid) 2488 os_snprintf(net_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, 2489 "%s/" WPAS_DBUS_NEW_NETWORKS_PART "/%u", 2490 wpa_s->dbus_new_path, wpa_s->current_ssid->id); 2491 else 2492 os_snprintf(net_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, "/"); 2493 2494 return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_OBJECT_PATH, 2495 &net_obj_path, error); 2496 } 2497 2498 2499 /** 2500 * wpas_dbus_getter_current_auth_mode - Get current authentication type 2501 * @iter: Pointer to incoming dbus message iter 2502 * @error: Location to store error on failure 2503 * @user_data: Function specific data 2504 * Returns: TRUE on success, FALSE on failure 2505 * 2506 * Getter for "CurrentAuthMode" property. 2507 */ 2508 dbus_bool_t wpas_dbus_getter_current_auth_mode(DBusMessageIter *iter, 2509 DBusError *error, 2510 void *user_data) 2511 { 2512 struct wpa_supplicant *wpa_s = user_data; 2513 const char *eap_mode; 2514 const char *auth_mode; 2515 char eap_mode_buf[WPAS_DBUS_AUTH_MODE_MAX]; 2516 2517 if (wpa_s->wpa_state != WPA_COMPLETED) { 2518 auth_mode = "INACTIVE"; 2519 } else if (wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X || 2520 wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) { 2521 eap_mode = wpa_supplicant_get_eap_mode(wpa_s); 2522 os_snprintf(eap_mode_buf, WPAS_DBUS_AUTH_MODE_MAX, 2523 "EAP-%s", eap_mode); 2524 auth_mode = eap_mode_buf; 2525 2526 } else { 2527 auth_mode = wpa_key_mgmt_txt(wpa_s->key_mgmt, 2528 wpa_s->current_ssid->proto); 2529 } 2530 2531 return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING, 2532 &auth_mode, error); 2533 } 2534 2535 2536 /** 2537 * wpas_dbus_getter_bridge_ifname - Get interface name 2538 * @iter: Pointer to incoming dbus message iter 2539 * @error: Location to store error on failure 2540 * @user_data: Function specific data 2541 * Returns: TRUE on success, FALSE on failure 2542 * 2543 * Getter for "BridgeIfname" property. 2544 */ 2545 dbus_bool_t wpas_dbus_getter_bridge_ifname(DBusMessageIter *iter, 2546 DBusError *error, 2547 void *user_data) 2548 { 2549 struct wpa_supplicant *wpa_s = user_data; 2550 const char *bridge_ifname = wpa_s->bridge_ifname; 2551 return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING, 2552 &bridge_ifname, error); 2553 } 2554 2555 2556 /** 2557 * wpas_dbus_getter_bsss - Get array of BSSs objects 2558 * @iter: Pointer to incoming dbus message iter 2559 * @error: Location to store error on failure 2560 * @user_data: Function specific data 2561 * Returns: TRUE on success, FALSE on failure 2562 * 2563 * Getter for "BSSs" property. 2564 */ 2565 dbus_bool_t wpas_dbus_getter_bsss(DBusMessageIter *iter, DBusError *error, 2566 void *user_data) 2567 { 2568 struct wpa_supplicant *wpa_s = user_data; 2569 struct wpa_bss *bss; 2570 char **paths; 2571 unsigned int i = 0; 2572 dbus_bool_t success = FALSE; 2573 2574 paths = os_zalloc(wpa_s->num_bss * sizeof(char *)); 2575 if (!paths) { 2576 dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory"); 2577 return FALSE; 2578 } 2579 2580 /* Loop through scan results and append each result's object path */ 2581 dl_list_for_each(bss, &wpa_s->bss_id, struct wpa_bss, list_id) { 2582 paths[i] = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX); 2583 if (paths[i] == NULL) { 2584 dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, 2585 "no memory"); 2586 goto out; 2587 } 2588 /* Construct the object path for this BSS. */ 2589 os_snprintf(paths[i++], WPAS_DBUS_OBJECT_PATH_MAX, 2590 "%s/" WPAS_DBUS_NEW_BSSIDS_PART "/%u", 2591 wpa_s->dbus_new_path, bss->id); 2592 } 2593 2594 success = wpas_dbus_simple_array_property_getter(iter, 2595 DBUS_TYPE_OBJECT_PATH, 2596 paths, wpa_s->num_bss, 2597 error); 2598 2599 out: 2600 while (i) 2601 os_free(paths[--i]); 2602 os_free(paths); 2603 return success; 2604 } 2605 2606 2607 /** 2608 * wpas_dbus_getter_networks - Get array of networks objects 2609 * @iter: Pointer to incoming dbus message iter 2610 * @error: Location to store error on failure 2611 * @user_data: Function specific data 2612 * Returns: TRUE on success, FALSE on failure 2613 * 2614 * Getter for "Networks" property. 2615 */ 2616 dbus_bool_t wpas_dbus_getter_networks(DBusMessageIter *iter, DBusError *error, 2617 void *user_data) 2618 { 2619 struct wpa_supplicant *wpa_s = user_data; 2620 struct wpa_ssid *ssid; 2621 char **paths; 2622 unsigned int i = 0, num = 0; 2623 dbus_bool_t success = FALSE; 2624 2625 if (wpa_s->conf == NULL) { 2626 wpa_printf(MSG_ERROR, "%s[dbus]: An error occurred getting " 2627 "networks list.", __func__); 2628 dbus_set_error(error, DBUS_ERROR_FAILED, "%s: an error " 2629 "occurred getting the networks list", __func__); 2630 return FALSE; 2631 } 2632 2633 for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) 2634 if (!network_is_persistent_group(ssid)) 2635 num++; 2636 2637 paths = os_zalloc(num * sizeof(char *)); 2638 if (!paths) { 2639 dbus_set_error(error, DBUS_ERROR_NO_MEMORY, "no memory"); 2640 return FALSE; 2641 } 2642 2643 /* Loop through configured networks and append object path of each */ 2644 for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) { 2645 if (network_is_persistent_group(ssid)) 2646 continue; 2647 paths[i] = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX); 2648 if (paths[i] == NULL) { 2649 dbus_set_error(error, DBUS_ERROR_NO_MEMORY, "no memory"); 2650 goto out; 2651 } 2652 2653 /* Construct the object path for this network. */ 2654 os_snprintf(paths[i++], WPAS_DBUS_OBJECT_PATH_MAX, 2655 "%s/" WPAS_DBUS_NEW_NETWORKS_PART "/%d", 2656 wpa_s->dbus_new_path, ssid->id); 2657 } 2658 2659 success = wpas_dbus_simple_array_property_getter(iter, 2660 DBUS_TYPE_OBJECT_PATH, 2661 paths, num, error); 2662 2663 out: 2664 while (i) 2665 os_free(paths[--i]); 2666 os_free(paths); 2667 return success; 2668 } 2669 2670 2671 /** 2672 * wpas_dbus_getter_blobs - Get all blobs defined for this interface 2673 * @iter: Pointer to incoming dbus message iter 2674 * @error: Location to store error on failure 2675 * @user_data: Function specific data 2676 * Returns: TRUE on success, FALSE on failure 2677 * 2678 * Getter for "Blobs" property. 2679 */ 2680 dbus_bool_t wpas_dbus_getter_blobs(DBusMessageIter *iter, DBusError *error, 2681 void *user_data) 2682 { 2683 struct wpa_supplicant *wpa_s = user_data; 2684 DBusMessageIter variant_iter, dict_iter, entry_iter, array_iter; 2685 struct wpa_config_blob *blob; 2686 2687 if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, 2688 "a{say}", &variant_iter) || 2689 !dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY, 2690 "{say}", &dict_iter)) { 2691 dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory"); 2692 return FALSE; 2693 } 2694 2695 blob = wpa_s->conf->blobs; 2696 while (blob) { 2697 if (!dbus_message_iter_open_container(&dict_iter, 2698 DBUS_TYPE_DICT_ENTRY, 2699 NULL, &entry_iter) || 2700 !dbus_message_iter_append_basic(&entry_iter, 2701 DBUS_TYPE_STRING, 2702 &(blob->name)) || 2703 !dbus_message_iter_open_container(&entry_iter, 2704 DBUS_TYPE_ARRAY, 2705 DBUS_TYPE_BYTE_AS_STRING, 2706 &array_iter) || 2707 !dbus_message_iter_append_fixed_array(&array_iter, 2708 DBUS_TYPE_BYTE, 2709 &(blob->data), 2710 blob->len) || 2711 !dbus_message_iter_close_container(&entry_iter, 2712 &array_iter) || 2713 !dbus_message_iter_close_container(&dict_iter, 2714 &entry_iter)) { 2715 dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, 2716 "no memory"); 2717 return FALSE; 2718 } 2719 2720 blob = blob->next; 2721 } 2722 2723 if (!dbus_message_iter_close_container(&variant_iter, &dict_iter) || 2724 !dbus_message_iter_close_container(iter, &variant_iter)) { 2725 dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory"); 2726 return FALSE; 2727 } 2728 2729 return TRUE; 2730 } 2731 2732 2733 static struct wpa_bss * get_bss_helper(struct bss_handler_args *args, 2734 DBusError *error, const char *func_name) 2735 { 2736 struct wpa_bss *res = wpa_bss_get_id(args->wpa_s, args->id); 2737 2738 if (!res) { 2739 wpa_printf(MSG_ERROR, "%s[dbus]: no bss with id %d found", 2740 func_name, args->id); 2741 dbus_set_error(error, DBUS_ERROR_FAILED, 2742 "%s: BSS %d not found", 2743 func_name, args->id); 2744 } 2745 2746 return res; 2747 } 2748 2749 2750 /** 2751 * wpas_dbus_getter_bss_bssid - Return the BSSID of a BSS 2752 * @iter: Pointer to incoming dbus message iter 2753 * @error: Location to store error on failure 2754 * @user_data: Function specific data 2755 * Returns: TRUE on success, FALSE on failure 2756 * 2757 * Getter for "BSSID" property. 2758 */ 2759 dbus_bool_t wpas_dbus_getter_bss_bssid(DBusMessageIter *iter, DBusError *error, 2760 void *user_data) 2761 { 2762 struct bss_handler_args *args = user_data; 2763 struct wpa_bss *res; 2764 2765 res = get_bss_helper(args, error, __func__); 2766 if (!res) 2767 return FALSE; 2768 2769 return wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE, 2770 res->bssid, ETH_ALEN, 2771 error); 2772 } 2773 2774 2775 /** 2776 * wpas_dbus_getter_bss_ssid - Return the SSID of a BSS 2777 * @iter: Pointer to incoming dbus message iter 2778 * @error: Location to store error on failure 2779 * @user_data: Function specific data 2780 * Returns: TRUE on success, FALSE on failure 2781 * 2782 * Getter for "SSID" property. 2783 */ 2784 dbus_bool_t wpas_dbus_getter_bss_ssid(DBusMessageIter *iter, DBusError *error, 2785 void *user_data) 2786 { 2787 struct bss_handler_args *args = user_data; 2788 struct wpa_bss *res; 2789 2790 res = get_bss_helper(args, error, __func__); 2791 if (!res) 2792 return FALSE; 2793 2794 return wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE, 2795 res->ssid, res->ssid_len, 2796 error); 2797 } 2798 2799 2800 /** 2801 * wpas_dbus_getter_bss_privacy - Return the privacy flag of a BSS 2802 * @iter: Pointer to incoming dbus message iter 2803 * @error: Location to store error on failure 2804 * @user_data: Function specific data 2805 * Returns: TRUE on success, FALSE on failure 2806 * 2807 * Getter for "Privacy" property. 2808 */ 2809 dbus_bool_t wpas_dbus_getter_bss_privacy(DBusMessageIter *iter, 2810 DBusError *error, void *user_data) 2811 { 2812 struct bss_handler_args *args = user_data; 2813 struct wpa_bss *res; 2814 dbus_bool_t privacy; 2815 2816 res = get_bss_helper(args, error, __func__); 2817 if (!res) 2818 return FALSE; 2819 2820 privacy = (res->caps & IEEE80211_CAP_PRIVACY) ? TRUE : FALSE; 2821 return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN, 2822 &privacy, error); 2823 } 2824 2825 2826 /** 2827 * wpas_dbus_getter_bss_mode - Return the mode of a BSS 2828 * @iter: Pointer to incoming dbus message iter 2829 * @error: Location to store error on failure 2830 * @user_data: Function specific data 2831 * Returns: TRUE on success, FALSE on failure 2832 * 2833 * Getter for "Mode" property. 2834 */ 2835 dbus_bool_t wpas_dbus_getter_bss_mode(DBusMessageIter *iter, DBusError *error, 2836 void *user_data) 2837 { 2838 struct bss_handler_args *args = user_data; 2839 struct wpa_bss *res; 2840 const char *mode; 2841 2842 res = get_bss_helper(args, error, __func__); 2843 if (!res) 2844 return FALSE; 2845 2846 if (res->caps & IEEE80211_CAP_IBSS) 2847 mode = "ad-hoc"; 2848 else 2849 mode = "infrastructure"; 2850 2851 return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING, 2852 &mode, error); 2853 } 2854 2855 2856 /** 2857 * wpas_dbus_getter_bss_level - Return the signal strength of a BSS 2858 * @iter: Pointer to incoming dbus message iter 2859 * @error: Location to store error on failure 2860 * @user_data: Function specific data 2861 * Returns: TRUE on success, FALSE on failure 2862 * 2863 * Getter for "Level" property. 2864 */ 2865 dbus_bool_t wpas_dbus_getter_bss_signal(DBusMessageIter *iter, 2866 DBusError *error, void *user_data) 2867 { 2868 struct bss_handler_args *args = user_data; 2869 struct wpa_bss *res; 2870 s16 level; 2871 2872 res = get_bss_helper(args, error, __func__); 2873 if (!res) 2874 return FALSE; 2875 2876 level = (s16) res->level; 2877 return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_INT16, 2878 &level, error); 2879 } 2880 2881 2882 /** 2883 * wpas_dbus_getter_bss_frequency - Return the frequency of a BSS 2884 * @iter: Pointer to incoming dbus message iter 2885 * @error: Location to store error on failure 2886 * @user_data: Function specific data 2887 * Returns: TRUE on success, FALSE on failure 2888 * 2889 * Getter for "Frequency" property. 2890 */ 2891 dbus_bool_t wpas_dbus_getter_bss_frequency(DBusMessageIter *iter, 2892 DBusError *error, void *user_data) 2893 { 2894 struct bss_handler_args *args = user_data; 2895 struct wpa_bss *res; 2896 u16 freq; 2897 2898 res = get_bss_helper(args, error, __func__); 2899 if (!res) 2900 return FALSE; 2901 2902 freq = (u16) res->freq; 2903 return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT16, 2904 &freq, error); 2905 } 2906 2907 2908 static int cmp_u8s_desc(const void *a, const void *b) 2909 { 2910 return (*(u8 *) b - *(u8 *) a); 2911 } 2912 2913 2914 /** 2915 * wpas_dbus_getter_bss_rates - Return available bit rates of a BSS 2916 * @iter: Pointer to incoming dbus message iter 2917 * @error: Location to store error on failure 2918 * @user_data: Function specific data 2919 * Returns: TRUE on success, FALSE on failure 2920 * 2921 * Getter for "Rates" property. 2922 */ 2923 dbus_bool_t wpas_dbus_getter_bss_rates(DBusMessageIter *iter, 2924 DBusError *error, void *user_data) 2925 { 2926 struct bss_handler_args *args = user_data; 2927 struct wpa_bss *res; 2928 u8 *ie_rates = NULL; 2929 u32 *real_rates; 2930 int rates_num, i; 2931 dbus_bool_t success = FALSE; 2932 2933 res = get_bss_helper(args, error, __func__); 2934 if (!res) 2935 return FALSE; 2936 2937 rates_num = wpa_bss_get_bit_rates(res, &ie_rates); 2938 if (rates_num < 0) 2939 return FALSE; 2940 2941 qsort(ie_rates, rates_num, 1, cmp_u8s_desc); 2942 2943 real_rates = os_malloc(sizeof(u32) * rates_num); 2944 if (!real_rates) { 2945 os_free(ie_rates); 2946 dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory"); 2947 return FALSE; 2948 } 2949 2950 for (i = 0; i < rates_num; i++) 2951 real_rates[i] = ie_rates[i] * 500000; 2952 2953 success = wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_UINT32, 2954 real_rates, rates_num, 2955 error); 2956 2957 os_free(ie_rates); 2958 os_free(real_rates); 2959 return success; 2960 } 2961 2962 2963 static dbus_bool_t wpas_dbus_get_bss_security_prop(DBusMessageIter *iter, 2964 struct wpa_ie_data *ie_data, 2965 DBusError *error) 2966 { 2967 DBusMessageIter iter_dict, variant_iter; 2968 const char *group; 2969 const char *pairwise[2]; /* max 2 pairwise ciphers is supported */ 2970 const char *key_mgmt[7]; /* max 7 key managements may be supported */ 2971 int n; 2972 2973 if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, 2974 "a{sv}", &variant_iter)) 2975 goto nomem; 2976 2977 if (!wpa_dbus_dict_open_write(&variant_iter, &iter_dict)) 2978 goto nomem; 2979 2980 /* KeyMgmt */ 2981 n = 0; 2982 if (ie_data->key_mgmt & WPA_KEY_MGMT_PSK) 2983 key_mgmt[n++] = "wpa-psk"; 2984 if (ie_data->key_mgmt & WPA_KEY_MGMT_FT_PSK) 2985 key_mgmt[n++] = "wpa-ft-psk"; 2986 if (ie_data->key_mgmt & WPA_KEY_MGMT_PSK_SHA256) 2987 key_mgmt[n++] = "wpa-psk-sha256"; 2988 if (ie_data->key_mgmt & WPA_KEY_MGMT_IEEE8021X) 2989 key_mgmt[n++] = "wpa-eap"; 2990 if (ie_data->key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) 2991 key_mgmt[n++] = "wpa-ft-eap"; 2992 if (ie_data->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) 2993 key_mgmt[n++] = "wpa-eap-sha256"; 2994 if (ie_data->key_mgmt & WPA_KEY_MGMT_NONE) 2995 key_mgmt[n++] = "wpa-none"; 2996 2997 if (!wpa_dbus_dict_append_string_array(&iter_dict, "KeyMgmt", 2998 key_mgmt, n)) 2999 goto nomem; 3000 3001 /* Group */ 3002 switch (ie_data->group_cipher) { 3003 case WPA_CIPHER_WEP40: 3004 group = "wep40"; 3005 break; 3006 case WPA_CIPHER_TKIP: 3007 group = "tkip"; 3008 break; 3009 case WPA_CIPHER_CCMP: 3010 group = "ccmp"; 3011 break; 3012 case WPA_CIPHER_WEP104: 3013 group = "wep104"; 3014 break; 3015 default: 3016 group = ""; 3017 break; 3018 } 3019 3020 if (!wpa_dbus_dict_append_string(&iter_dict, "Group", group)) 3021 goto nomem; 3022 3023 /* Pairwise */ 3024 n = 0; 3025 if (ie_data->pairwise_cipher & WPA_CIPHER_TKIP) 3026 pairwise[n++] = "tkip"; 3027 if (ie_data->pairwise_cipher & WPA_CIPHER_CCMP) 3028 pairwise[n++] = "ccmp"; 3029 3030 if (!wpa_dbus_dict_append_string_array(&iter_dict, "Pairwise", 3031 pairwise, n)) 3032 goto nomem; 3033 3034 /* Management group (RSN only) */ 3035 if (ie_data->proto == WPA_PROTO_RSN) { 3036 switch (ie_data->mgmt_group_cipher) { 3037 #ifdef CONFIG_IEEE80211W 3038 case WPA_CIPHER_AES_128_CMAC: 3039 group = "aes128cmac"; 3040 break; 3041 #endif /* CONFIG_IEEE80211W */ 3042 default: 3043 group = ""; 3044 break; 3045 } 3046 3047 if (!wpa_dbus_dict_append_string(&iter_dict, "MgmtGroup", 3048 group)) 3049 goto nomem; 3050 } 3051 3052 if (!wpa_dbus_dict_close_write(&variant_iter, &iter_dict)) 3053 goto nomem; 3054 if (!dbus_message_iter_close_container(iter, &variant_iter)) 3055 goto nomem; 3056 3057 return TRUE; 3058 3059 nomem: 3060 dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory"); 3061 return FALSE; 3062 } 3063 3064 3065 /** 3066 * wpas_dbus_getter_bss_wpa - Return the WPA options of a BSS 3067 * @iter: Pointer to incoming dbus message iter 3068 * @error: Location to store error on failure 3069 * @user_data: Function specific data 3070 * Returns: TRUE on success, FALSE on failure 3071 * 3072 * Getter for "WPA" property. 3073 */ 3074 dbus_bool_t wpas_dbus_getter_bss_wpa(DBusMessageIter *iter, DBusError *error, 3075 void *user_data) 3076 { 3077 struct bss_handler_args *args = user_data; 3078 struct wpa_bss *res; 3079 struct wpa_ie_data wpa_data; 3080 const u8 *ie; 3081 3082 res = get_bss_helper(args, error, __func__); 3083 if (!res) 3084 return FALSE; 3085 3086 os_memset(&wpa_data, 0, sizeof(wpa_data)); 3087 ie = wpa_bss_get_vendor_ie(res, WPA_IE_VENDOR_TYPE); 3088 if (ie) { 3089 if (wpa_parse_wpa_ie(ie, 2 + ie[1], &wpa_data) < 0) { 3090 dbus_set_error_const(error, DBUS_ERROR_FAILED, 3091 "failed to parse WPA IE"); 3092 return FALSE; 3093 } 3094 } 3095 3096 return wpas_dbus_get_bss_security_prop(iter, &wpa_data, error); 3097 } 3098 3099 3100 /** 3101 * wpas_dbus_getter_bss_rsn - Return the RSN options of a BSS 3102 * @iter: Pointer to incoming dbus message iter 3103 * @error: Location to store error on failure 3104 * @user_data: Function specific data 3105 * Returns: TRUE on success, FALSE on failure 3106 * 3107 * Getter for "RSN" property. 3108 */ 3109 dbus_bool_t wpas_dbus_getter_bss_rsn(DBusMessageIter *iter, DBusError *error, 3110 void *user_data) 3111 { 3112 struct bss_handler_args *args = user_data; 3113 struct wpa_bss *res; 3114 struct wpa_ie_data wpa_data; 3115 const u8 *ie; 3116 3117 res = get_bss_helper(args, error, __func__); 3118 if (!res) 3119 return FALSE; 3120 3121 os_memset(&wpa_data, 0, sizeof(wpa_data)); 3122 ie = wpa_bss_get_ie(res, WLAN_EID_RSN); 3123 if (ie) { 3124 if (wpa_parse_wpa_ie(ie, 2 + ie[1], &wpa_data) < 0) { 3125 dbus_set_error_const(error, DBUS_ERROR_FAILED, 3126 "failed to parse RSN IE"); 3127 return FALSE; 3128 } 3129 } 3130 3131 return wpas_dbus_get_bss_security_prop(iter, &wpa_data, error); 3132 } 3133 3134 3135 /** 3136 * wpas_dbus_getter_bss_ies - Return all IEs of a BSS 3137 * @iter: Pointer to incoming dbus message iter 3138 * @error: Location to store error on failure 3139 * @user_data: Function specific data 3140 * Returns: TRUE on success, FALSE on failure 3141 * 3142 * Getter for "IEs" property. 3143 */ 3144 dbus_bool_t wpas_dbus_getter_bss_ies(DBusMessageIter *iter, DBusError *error, 3145 void *user_data) 3146 { 3147 struct bss_handler_args *args = user_data; 3148 struct wpa_bss *res; 3149 3150 res = get_bss_helper(args, error, __func__); 3151 if (!res) 3152 return FALSE; 3153 3154 return wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE, 3155 res + 1, res->ie_len, 3156 error); 3157 } 3158 3159 3160 /** 3161 * wpas_dbus_getter_enabled - Check whether network is enabled or disabled 3162 * @iter: Pointer to incoming dbus message iter 3163 * @error: Location to store error on failure 3164 * @user_data: Function specific data 3165 * Returns: TRUE on success, FALSE on failure 3166 * 3167 * Getter for "enabled" property of a configured network. 3168 */ 3169 dbus_bool_t wpas_dbus_getter_enabled(DBusMessageIter *iter, DBusError *error, 3170 void *user_data) 3171 { 3172 struct network_handler_args *net = user_data; 3173 dbus_bool_t enabled = net->ssid->disabled ? FALSE : TRUE; 3174 3175 return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN, 3176 &enabled, error); 3177 } 3178 3179 3180 /** 3181 * wpas_dbus_setter_enabled - Mark a configured network as enabled or disabled 3182 * @iter: Pointer to incoming dbus message iter 3183 * @error: Location to store error on failure 3184 * @user_data: Function specific data 3185 * Returns: TRUE on success, FALSE on failure 3186 * 3187 * Setter for "Enabled" property of a configured network. 3188 */ 3189 dbus_bool_t wpas_dbus_setter_enabled(DBusMessageIter *iter, DBusError *error, 3190 void *user_data) 3191 { 3192 struct network_handler_args *net = user_data; 3193 struct wpa_supplicant *wpa_s; 3194 struct wpa_ssid *ssid; 3195 dbus_bool_t enable; 3196 3197 if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_BOOLEAN, 3198 &enable)) 3199 return FALSE; 3200 3201 wpa_s = net->wpa_s; 3202 ssid = net->ssid; 3203 3204 if (enable) 3205 wpa_supplicant_enable_network(wpa_s, ssid); 3206 else 3207 wpa_supplicant_disable_network(wpa_s, ssid); 3208 3209 return TRUE; 3210 } 3211 3212 3213 /** 3214 * wpas_dbus_getter_network_properties - Get options for a configured network 3215 * @iter: Pointer to incoming dbus message iter 3216 * @error: Location to store error on failure 3217 * @user_data: Function specific data 3218 * Returns: TRUE on success, FALSE on failure 3219 * 3220 * Getter for "Properties" property of a configured network. 3221 */ 3222 dbus_bool_t wpas_dbus_getter_network_properties(DBusMessageIter *iter, 3223 DBusError *error, 3224 void *user_data) 3225 { 3226 struct network_handler_args *net = user_data; 3227 DBusMessageIter variant_iter, dict_iter; 3228 char **iterator; 3229 char **props = wpa_config_get_all(net->ssid, 1); 3230 dbus_bool_t success = FALSE; 3231 3232 if (!props) { 3233 dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory"); 3234 return FALSE; 3235 } 3236 3237 if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, "a{sv}", 3238 &variant_iter) || 3239 !wpa_dbus_dict_open_write(&variant_iter, &dict_iter)) { 3240 dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory"); 3241 goto out; 3242 } 3243 3244 iterator = props; 3245 while (*iterator) { 3246 if (!wpa_dbus_dict_append_string(&dict_iter, *iterator, 3247 *(iterator + 1))) { 3248 dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, 3249 "no memory"); 3250 goto out; 3251 } 3252 iterator += 2; 3253 } 3254 3255 3256 if (!wpa_dbus_dict_close_write(&variant_iter, &dict_iter) || 3257 !dbus_message_iter_close_container(iter, &variant_iter)) { 3258 dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory"); 3259 goto out; 3260 } 3261 3262 success = TRUE; 3263 3264 out: 3265 iterator = props; 3266 while (*iterator) { 3267 os_free(*iterator); 3268 iterator++; 3269 } 3270 os_free(props); 3271 return success; 3272 } 3273 3274 3275 /** 3276 * wpas_dbus_setter_network_properties - Set options for a configured network 3277 * @iter: Pointer to incoming dbus message iter 3278 * @error: Location to store error on failure 3279 * @user_data: Function specific data 3280 * Returns: TRUE on success, FALSE on failure 3281 * 3282 * Setter for "Properties" property of a configured network. 3283 */ 3284 dbus_bool_t wpas_dbus_setter_network_properties(DBusMessageIter *iter, 3285 DBusError *error, 3286 void *user_data) 3287 { 3288 struct network_handler_args *net = user_data; 3289 struct wpa_ssid *ssid = net->ssid; 3290 DBusMessageIter variant_iter; 3291 3292 dbus_message_iter_recurse(iter, &variant_iter); 3293 return set_network_properties(net->wpa_s, ssid, &variant_iter, error); 3294 } 3295