1/* 2 * WPA Supplicant / dbus-based control interface (P2P) 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License version 2 as 6 * published by the Free Software Foundation. 7 * 8 * Alternatively, this software may be distributed under the terms of BSD 9 * license. 10 * 11 * See README and COPYING for more details. 12 */ 13 14#include "includes.h" 15 16#include "utils/includes.h" 17#include "common.h" 18#include "../config.h" 19#include "../wpa_supplicant_i.h" 20#include "../wps_supplicant.h" 21#include "../notify.h" 22#include "dbus_new_helpers.h" 23#include "dbus_new.h" 24#include "dbus_new_handlers.h" 25#include "dbus_new_handlers_p2p.h" 26#include "dbus_dict_helpers.h" 27#include "p2p/p2p.h" 28#include "common/ieee802_11_defs.h" 29#include "ap/hostapd.h" 30#include "ap/ap_config.h" 31#include "ap/wps_hostapd.h" 32 33#include "../p2p_supplicant.h" 34 35/** 36 * Parses out the mac address from the peer object path. 37 * @peer_path - object path of the form 38 * /fi/w1/wpa_supplicant1/Interfaces/n/Peers/00112233445566 (no colons) 39 * @addr - out param must be of ETH_ALEN size 40 * Returns 0 if valid (including MAC), -1 otherwise 41 */ 42static int parse_peer_object_path(char *peer_path, u8 addr[ETH_ALEN]) 43{ 44 char *p; 45 46 if (!peer_path) 47 return -1; 48 p = strrchr(peer_path, '/'); 49 if (!p) 50 return -1; 51 p++; 52 return hwaddr_compact_aton(p, addr); 53} 54 55 56/** 57 * wpas_dbus_error_persistent_group_unknown - Return a new PersistentGroupUnknown 58 * error message 59 * @message: Pointer to incoming dbus message this error refers to 60 * Returns: a dbus error message 61 * 62 * Convenience function to create and return an invalid persistent group error. 63 */ 64static DBusMessage * wpas_dbus_error_persistent_group_unknown( 65 DBusMessage *message) 66{ 67 return dbus_message_new_error(message, WPAS_DBUS_ERROR_NETWORK_UNKNOWN, 68 "There is no such persistent group in " 69 "this P2P device."); 70} 71 72 73DBusMessage *wpas_dbus_handler_p2p_find(DBusMessage * message, 74 struct wpa_supplicant * wpa_s) 75{ 76 struct wpa_dbus_dict_entry entry; 77 DBusMessage *reply = NULL; 78 DBusMessageIter iter; 79 DBusMessageIter iter_dict; 80 unsigned int timeout = 0; 81 unsigned int searchonly = 0; 82 enum p2p_discovery_type type = P2P_FIND_ONLY_SOCIAL; 83 int num_req_dev_types = 0; 84 unsigned int i; 85 u8 *req_dev_types = NULL; 86 87 dbus_message_iter_init(message, &iter); 88 89 if (!wpa_dbus_dict_open_read(&iter, &iter_dict)) 90 goto error; 91 92 while (wpa_dbus_dict_has_dict_entry(&iter_dict)) { 93 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) 94 goto error; 95 96 if (!os_strcmp(entry.key, "Timeout") && 97 (entry.type == DBUS_TYPE_INT32)) { 98 timeout = entry.uint32_value; 99 } else if (!os_strcmp(entry.key, "SearchOnly") && 100 (entry.type == DBUS_TYPE_BOOLEAN)) { 101 searchonly = (entry.bool_value == TRUE) ? 1 : 0; 102 } else if (os_strcmp(entry.key, "RequestedDeviceTypes") == 0) { 103 if ((entry.type != DBUS_TYPE_ARRAY) || 104 (entry.array_type != WPAS_DBUS_TYPE_BINARRAY)) 105 goto error_clear; 106 107 req_dev_types = 108 os_malloc(WPS_DEV_TYPE_LEN * entry.array_len); 109 if (!req_dev_types) 110 goto error_clear; 111 112 for (i = 0; i < entry.array_len; i++) { 113 if (wpabuf_len(entry.binarray_value[i]) != 114 WPS_DEV_TYPE_LEN) 115 goto error_clear; 116 os_memcpy(req_dev_types + i * WPS_DEV_TYPE_LEN, 117 wpabuf_head(entry.binarray_value[i]), 118 WPS_DEV_TYPE_LEN); 119 } 120 121 num_req_dev_types = entry.array_len; 122 } else 123 goto error_clear; 124 wpa_dbus_dict_entry_clear(&entry); 125 } 126 127 wpas_p2p_find(wpa_s, timeout, type, num_req_dev_types, req_dev_types); 128 return reply; 129 130error_clear: 131 os_free(req_dev_types); 132 wpa_dbus_dict_entry_clear(&entry); 133error: 134 reply = wpas_dbus_error_invalid_args(message, entry.key); 135 return reply; 136} 137 138DBusMessage *wpas_dbus_handler_p2p_stop_find(DBusMessage * message, 139 struct wpa_supplicant * wpa_s) 140{ 141 wpas_p2p_stop_find(wpa_s); 142 return NULL; 143} 144 145DBusMessage *wpas_dbus_handler_p2p_rejectpeer(DBusMessage * message, 146 struct wpa_supplicant * wpa_s) 147{ 148 DBusMessageIter iter; 149 char *peer_object_path = NULL; 150 u8 peer_addr[ETH_ALEN]; 151 152 dbus_message_iter_init(message, &iter); 153 dbus_message_iter_get_basic(&iter, &peer_object_path); 154 155 if (parse_peer_object_path(peer_object_path, peer_addr) < 0) 156 return wpas_dbus_error_invalid_args(message, NULL); 157 158 if (wpas_p2p_reject(wpa_s, peer_addr) < 0) 159 return wpas_dbus_error_unknown_error(message, 160 "Failed to call wpas_p2p_reject method."); 161 162 return NULL; 163} 164 165DBusMessage *wpas_dbus_handler_p2p_listen(DBusMessage * message, 166 struct wpa_supplicant * wpa_s) 167{ 168 dbus_int32_t timeout = 0; 169 170 if (!dbus_message_get_args(message, NULL, DBUS_TYPE_INT32, &timeout, 171 DBUS_TYPE_INVALID)) 172 return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, 173 NULL); 174 175 if (wpas_p2p_listen(wpa_s, (unsigned int)timeout)) 176 return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, 177 NULL); 178 179 return NULL; 180} 181 182DBusMessage *wpas_dbus_handler_p2p_extendedlisten(DBusMessage * message, 183 struct wpa_supplicant * wpa_s) 184{ 185 unsigned int period = 0, interval = 0; 186 struct wpa_dbus_dict_entry entry; 187 DBusMessageIter iter; 188 DBusMessageIter iter_dict; 189 190 dbus_message_iter_init(message, &iter); 191 192 if (!wpa_dbus_dict_open_read(&iter, &iter_dict)) 193 goto error; 194 195 while (wpa_dbus_dict_has_dict_entry(&iter_dict)) { 196 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) 197 goto error; 198 199 if (!strcmp(entry.key, "period") && 200 (entry.type == DBUS_TYPE_INT32)) 201 period = entry.uint32_value; 202 else if (!strcmp(entry.key, "interval") && 203 (entry.type == DBUS_TYPE_INT32)) 204 interval = entry.uint32_value; 205 else 206 goto error_clear; 207 wpa_dbus_dict_entry_clear(&entry); 208 } 209 210 if (wpas_p2p_ext_listen(wpa_s, period, interval)) 211 return wpas_dbus_error_unknown_error(message, 212 "failed to initiate a p2p_ext_listen."); 213 214 return NULL; 215 216error_clear: 217 wpa_dbus_dict_entry_clear(&entry); 218error: 219 return wpas_dbus_error_invalid_args(message, entry.key); 220} 221 222DBusMessage *wpas_dbus_handler_p2p_presence_request(DBusMessage * message, 223 struct wpa_supplicant * 224 wpa_s) 225{ 226 unsigned int dur1 = 0, int1 = 0, dur2 = 0, int2 = 0; 227 struct wpa_dbus_dict_entry entry; 228 DBusMessageIter iter; 229 DBusMessageIter iter_dict; 230 231 dbus_message_iter_init(message, &iter); 232 233 if (!wpa_dbus_dict_open_read(&iter, &iter_dict)) 234 goto error; 235 236 while (wpa_dbus_dict_has_dict_entry(&iter_dict)) { 237 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) 238 goto error; 239 240 if (!strcmp(entry.key, "duration1") && 241 (entry.type == DBUS_TYPE_INT32)) 242 dur1 = entry.uint32_value; 243 else if (!strcmp(entry.key, "interval1") && 244 entry.type == DBUS_TYPE_INT32) 245 int1 = entry.uint32_value; 246 else if (!strcmp(entry.key, "duration2") && 247 entry.type == DBUS_TYPE_INT32) 248 dur2 = entry.uint32_value; 249 else if (!strcmp(entry.key, "interval2") && 250 entry.type == DBUS_TYPE_INT32) 251 int2 = entry.uint32_value; 252 else 253 goto error_clear; 254 255 wpa_dbus_dict_entry_clear(&entry); 256 } 257 if (wpas_p2p_presence_req(wpa_s, dur1, int1, dur2, int2) < 0) 258 return wpas_dbus_error_unknown_error(message, 259 "Failed to invoke presence request."); 260 261 return NULL; 262 263error_clear: 264 wpa_dbus_dict_entry_clear(&entry); 265error: 266 return wpas_dbus_error_invalid_args(message, entry.key); 267} 268 269DBusMessage *wpas_dbus_handler_p2p_group_add(DBusMessage * message, 270 struct wpa_supplicant * wpa_s) 271{ 272 DBusMessageIter iter_dict; 273 DBusMessage *reply = NULL; 274 DBusMessageIter iter; 275 struct wpa_dbus_dict_entry entry; 276 char *pg_object_path = NULL; 277 int persistent_group = 0; 278 int freq = 0; 279 char *iface = NULL; 280 char *net_id_str = NULL; 281 unsigned int group_id = 0; 282 struct wpa_ssid *ssid; 283 284 dbus_message_iter_init(message, &iter); 285 286 if (!wpa_dbus_dict_open_read(&iter, &iter_dict)) 287 goto inv_args; 288 289 while (wpa_dbus_dict_has_dict_entry(&iter_dict)) { 290 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) 291 goto inv_args; 292 293 if (!strcmp(entry.key, "persistent") && 294 (entry.type == DBUS_TYPE_BOOLEAN)) { 295 persistent_group = (entry.bool_value == TRUE) ? 1 : 0; 296 } else if (!strcmp(entry.key, "frequency") && 297 (entry.type == DBUS_TYPE_INT32)) { 298 freq = entry.int32_value; 299 if (freq <= 0) 300 goto inv_args_clear; 301 } else if (!strcmp(entry.key, "persistent_group_object") && 302 entry.type == DBUS_TYPE_OBJECT_PATH) 303 pg_object_path = os_strdup(entry.str_value); 304 else 305 goto inv_args_clear; 306 307 wpa_dbus_dict_entry_clear(&entry); 308 } 309 310 if (pg_object_path != NULL) { 311 /* 312 * A persistent group Object Path is defined meaning we want 313 * to re-invoke a persistent group. 314 */ 315 316 iface = wpas_dbus_new_decompose_object_path(pg_object_path, 1, 317 &net_id_str, NULL); 318 if (iface == NULL || 319 os_strcmp(iface, wpa_s->dbus_new_path) != 0) { 320 reply = 321 wpas_dbus_error_invalid_args(message, 322 pg_object_path); 323 goto out; 324 } 325 326 group_id = strtoul(net_id_str, NULL, 10); 327 if (errno == EINVAL) { 328 reply = wpas_dbus_error_invalid_args( 329 message, pg_object_path); 330 goto out; 331 } 332 333 /* Get the SSID structure form the persistant group id */ 334 ssid = wpa_config_get_network(wpa_s->conf, group_id); 335 if (ssid == NULL || ssid->disabled != 2) 336 goto inv_args; 337 338 if (wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq)) { 339 reply = wpas_dbus_error_unknown_error(message, 340 "Failed to reinvoke a persistent group"); 341 goto out; 342 } 343 } else if (wpas_p2p_group_add(wpa_s, persistent_group, freq)) 344 goto inv_args; 345 346out: 347 os_free(pg_object_path); 348 os_free(net_id_str); 349 os_free(iface); 350 return reply; 351inv_args_clear: 352 wpa_dbus_dict_entry_clear(&entry); 353inv_args: 354 reply = wpas_dbus_error_invalid_args(message, NULL); 355 goto out; 356} 357 358DBusMessage *wpas_dbus_handler_p2p_disconnect(DBusMessage *message, 359 struct wpa_supplicant *wpa_s) 360{ 361 if (wpas_p2p_disconnect(wpa_s)) 362 return wpas_dbus_error_unknown_error(message, 363 "failed to disconnect"); 364 365 return NULL; 366} 367 368DBusMessage *wpas_dbus_handler_p2p_flush(DBusMessage * message, 369 struct wpa_supplicant * wpa_s) 370{ 371 os_memset(wpa_s->p2p_auth_invite, 0, ETH_ALEN); 372 wpa_s->force_long_sd = 0; 373 p2p_flush(wpa_s->global->p2p); 374 375 return NULL; 376} 377 378DBusMessage *wpas_dbus_handler_p2p_connect(DBusMessage * message, 379 struct wpa_supplicant * wpa_s) 380{ 381 DBusMessageIter iter_dict; 382 DBusMessage *reply = NULL; 383 DBusMessageIter iter; 384 struct wpa_dbus_dict_entry entry; 385 char *peer_object_path = NULL; 386 int persistent_group = 0; 387 int join = 0; 388 int authorize_only = 0; 389 int go_intent = -1; 390 int freq = 0; 391 u8 addr[ETH_ALEN]; 392 char *pin = NULL; 393 enum p2p_wps_method wps_method = WPS_NOT_READY; 394 int new_pin; 395 char *err_msg = NULL; 396 char *iface = NULL; 397 398 dbus_message_iter_init(message, &iter); 399 400 if (!wpa_dbus_dict_open_read(&iter, &iter_dict)) 401 goto inv_args; 402 403 while (wpa_dbus_dict_has_dict_entry(&iter_dict)) { 404 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) 405 goto inv_args; 406 407 if (!strcmp(entry.key, "peer") && 408 (entry.type == DBUS_TYPE_OBJECT_PATH)) { 409 peer_object_path = os_strdup(entry.str_value); 410 } else if (!strcmp(entry.key, "persistent") && 411 (entry.type == DBUS_TYPE_BOOLEAN)) { 412 persistent_group = (entry.bool_value == TRUE) ? 1 : 0; 413 } else if (!strcmp(entry.key, "join") && 414 (entry.type == DBUS_TYPE_BOOLEAN)) { 415 join = (entry.bool_value == TRUE) ? 1 : 0; 416 } else if (!strcmp(entry.key, "authorize_only") && 417 (entry.type == DBUS_TYPE_BOOLEAN)) { 418 authorize_only = (entry.bool_value == TRUE) ? 1 : 0; 419 } else if (!strcmp(entry.key, "frequency") && 420 (entry.type == DBUS_TYPE_INT32)) { 421 freq = entry.int32_value; 422 if (freq <= 0) 423 goto inv_args_clear; 424 } else if (!strcmp(entry.key, "go_intent") && 425 (entry.type == DBUS_TYPE_INT32)) { 426 go_intent = entry.int32_value; 427 if ((go_intent < 0) || (go_intent > 15)) 428 goto inv_args_clear; 429 } else if (!strcmp(entry.key, "wps_method") && 430 (entry.type == DBUS_TYPE_STRING)) { 431 if (!strcmp(entry.str_value, "pbc")) 432 wps_method = WPS_PBC; 433 else if (!strcmp(entry.str_value, "pin")) 434 wps_method = WPS_PIN_DISPLAY; 435 else if (!strcmp(entry.str_value, "label")) 436 wps_method = WPS_PIN_LABEL; 437 else if (!strcmp(entry.str_value, "display")) 438 wps_method = WPS_PIN_DISPLAY; 439 else if (!strcmp(entry.str_value, "keypad")) 440 wps_method = WPS_PIN_KEYPAD; 441 else 442 goto inv_args_clear; 443 } else if (!strcmp(entry.key, "pin") && 444 (entry.type == DBUS_TYPE_STRING)) { 445 pin = os_strdup(entry.str_value); 446 } else 447 goto inv_args_clear; 448 449 wpa_dbus_dict_entry_clear(&entry); 450 } 451 452 if (!peer_object_path || (wps_method == WPS_NOT_READY) || 453 (parse_peer_object_path(peer_object_path, addr) < 0) || 454 (p2p_get_peer_info(wpa_s->global->p2p, addr, 0, NULL, 0) < 0)) { 455 reply = wpas_dbus_error_invalid_args(message, NULL); 456 goto inv_args; 457 } 458 459 /* 460 * Validate the wps_method specified and the pin value. 461 */ 462 if ((!pin || !pin[0]) && 463 ((wps_method == WPS_PIN_LABEL) || (wps_method == WPS_PIN_KEYPAD))) 464 goto inv_args; 465 466 new_pin = wpas_p2p_connect(wpa_s, addr, pin, wps_method, 467 persistent_group, join, authorize_only, 468 go_intent, freq); 469 470 if (new_pin >= 0) { 471 reply = dbus_message_new_method_return(message); 472 dbus_message_append_args(reply, DBUS_TYPE_INT32, 473 &new_pin, DBUS_TYPE_INVALID); 474 } else { 475 switch (new_pin) { 476 case -2: 477 err_msg = "connect failed due to" 478 " channel unavailability."; 479 iface = WPAS_DBUS_ERROR_CONNECT_CHANNEL_UNAVAILABLE; 480 break; 481 482 case -3: 483 err_msg = "connect failed due to" 484 " unsupported channel."; 485 iface = WPAS_DBUS_ERROR_CONNECT_CHANNEL_UNSUPPORTED; 486 break; 487 488 default: 489 err_msg = "connect failed due to" 490 " unspecified error."; 491 iface = WPAS_DBUS_ERROR_CONNECT_UNSPECIFIED_ERROR; 492 break; 493 } 494 /* 495 * TODO:: 496 * Do we need specialized errors corresponding to above 497 * error conditions as against just returning a different 498 * error message? 499 */ 500 reply = dbus_message_new_error(message, iface, err_msg); 501 } 502 503out: 504 os_free(peer_object_path); 505 os_free(pin); 506 return reply; 507inv_args_clear: 508 wpa_dbus_dict_entry_clear(&entry); 509inv_args: 510 reply = wpas_dbus_error_invalid_args(message, NULL); 511 goto out; 512} 513 514DBusMessage *wpas_dbus_handler_p2p_invite(DBusMessage * message, 515 struct wpa_supplicant *wpa_s) 516{ 517 DBusMessageIter iter_dict; 518 DBusMessage *reply = NULL; 519 DBusMessageIter iter; 520 struct wpa_dbus_dict_entry entry; 521 char *peer_object_path = NULL; 522 char *pg_object_path = NULL; 523 char *iface = NULL; 524 char *net_id_str = NULL; 525 u8 peer_addr[ETH_ALEN]; 526 unsigned int group_id = 0; 527 int persistent = 0; 528 struct wpa_ssid *ssid; 529 530 dbus_message_iter_init(message, &iter); 531 532 if (!wpa_dbus_dict_open_read(&iter, &iter_dict)) 533 goto err; 534 535 while (wpa_dbus_dict_has_dict_entry(&iter_dict)) { 536 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) 537 goto err; 538 539 if (!strcmp(entry.key, "peer") && 540 (entry.type == DBUS_TYPE_OBJECT_PATH)) { 541 peer_object_path = os_strdup(entry.str_value); 542 wpa_dbus_dict_entry_clear(&entry); 543 } else if (!strcmp(entry.key, "persistent_group_object") && 544 (entry.type == DBUS_TYPE_OBJECT_PATH)) { 545 pg_object_path = os_strdup(entry.str_value); 546 persistent = 1; 547 wpa_dbus_dict_entry_clear(&entry); 548 } else { 549 wpa_dbus_dict_entry_clear(&entry); 550 goto err; 551 } 552 } 553 554 if (!peer_object_path || 555 (parse_peer_object_path(peer_object_path, peer_addr) < 0) || 556 (p2p_get_peer_info(wpa_s->global->p2p, 557 peer_addr, 0, NULL, 0) < 0)) { 558 goto err; 559 } 560 561 if (persistent) { 562 /* 563 * A group ID is defined meaning we want to re-invoke a 564 * persisatnt group 565 */ 566 567 iface = wpas_dbus_new_decompose_object_path(pg_object_path, 1, 568 &net_id_str, NULL); 569 if (iface == NULL || 570 os_strcmp(iface, wpa_s->dbus_new_path) != 0) { 571 reply = 572 wpas_dbus_error_invalid_args(message, 573 pg_object_path); 574 goto out; 575 } 576 577 group_id = strtoul(net_id_str, NULL, 10); 578 if (errno == EINVAL) { 579 reply = wpas_dbus_error_invalid_args( 580 message, pg_object_path); 581 goto out; 582 } 583 584 /* Get the SSID structure form the persistant group id */ 585 ssid = wpa_config_get_network(wpa_s->conf, group_id); 586 if (ssid == NULL || ssid->disabled != 2) 587 goto err; 588 589 if (wpas_p2p_invite(wpa_s, peer_addr, ssid, NULL) < 0) { 590 reply = wpas_dbus_error_unknown_error( 591 message, 592 "Failed to reinvoke a persistent group"); 593 goto out; 594 } 595 } else { 596 /* 597 * No group ID means propose to a peer to join my active group 598 */ 599 if (wpas_p2p_invite_group(wpa_s, wpa_s->ifname, 600 peer_addr, NULL)) { 601 reply = wpas_dbus_error_unknown_error( 602 message, 603 "Failed to join to an active group"); 604 goto out; 605 } 606 } 607 608out: 609 os_free(pg_object_path); 610 os_free(peer_object_path); 611 return reply; 612 613err: 614 reply = wpas_dbus_error_invalid_args(message, NULL); 615 goto out; 616} 617 618DBusMessage *wpas_dbus_handler_p2p_prov_disc_req(DBusMessage * message, 619 struct wpa_supplicant *wpa_s) 620{ 621 DBusMessageIter iter; 622 char *peer_object_path = NULL; 623 char *config_method = NULL; 624 u8 peer_addr[ETH_ALEN]; 625 626 dbus_message_iter_init(message, &iter); 627 dbus_message_iter_get_basic(&iter, &peer_object_path); 628 629 if (parse_peer_object_path(peer_object_path, peer_addr) < 0) 630 return wpas_dbus_error_invalid_args(message, NULL); 631 632 dbus_message_iter_next(&iter); 633 dbus_message_iter_get_basic(&iter, &config_method); 634 635 /* 636 * Validation checks on config_method are being duplicated here 637 * to be able to return invalid args reply since the error code 638 * from p2p module are not granular enough (yet). 639 */ 640 if (os_strcmp(config_method, "display") && 641 os_strcmp(config_method, "keypad") && 642 os_strcmp(config_method, "pbc") && 643 os_strcmp(config_method, "pushbutton")) 644 return wpas_dbus_error_invalid_args(message, NULL); 645 646 if (wpas_p2p_prov_disc(wpa_s, peer_addr, config_method) < 0) 647 return wpas_dbus_error_unknown_error(message, 648 "Failed to send provision discovery request"); 649 650 return NULL; 651} 652 653/* 654 * P2P Device property accessor methods. 655 */ 656 657DBusMessage *wpas_dbus_getter_p2p_device_properties(DBusMessage * message, 658 struct wpa_supplicant * 659 wpa_s) 660{ 661 DBusMessage *reply = NULL; 662 DBusMessageIter iter, variant_iter, dict_iter; 663 DBusMessageIter iter_secdev_dict_entry, iter_secdev_dict_val, 664 iter_secdev_dict_array; 665 const char *dev_name; 666 int num_vendor_extensions = 0; 667 int i; 668 const struct wpabuf *vendor_ext[P2P_MAX_WPS_VENDOR_EXT]; 669 670 if (message == NULL) 671 reply = dbus_message_new(DBUS_MESSAGE_TYPE_SIGNAL); 672 else 673 reply = dbus_message_new_method_return(message); 674 675 if (!reply) 676 goto err_no_mem; 677 678 dbus_message_iter_init_append(reply, &iter); 679 680 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT, 681 "a{sv}", &variant_iter) || 682 !wpa_dbus_dict_open_write(&variant_iter, &dict_iter)) 683 goto err_no_mem; 684 685 /* DeviceName */ 686 dev_name = wpa_s->conf->device_name; 687 if (dev_name && 688 !wpa_dbus_dict_append_string(&dict_iter, "DeviceName", dev_name)) 689 goto err_no_mem; 690 691 /* Primary device type */ 692 if (!wpa_dbus_dict_append_byte_array(&dict_iter, "PrimaryDeviceType", 693 (char *)wpa_s->conf->device_type, 694 WPS_DEV_TYPE_LEN)) 695 goto err_no_mem; 696 697 /* Secondary device types */ 698 if (wpa_s->conf->num_sec_device_types) { 699 if (!wpa_dbus_dict_begin_array(&dict_iter, 700 "SecondaryDeviceTypes", 701 DBUS_TYPE_ARRAY_AS_STRING 702 DBUS_TYPE_BYTE_AS_STRING, 703 &iter_secdev_dict_entry, 704 &iter_secdev_dict_val, 705 &iter_secdev_dict_array)) 706 goto err_no_mem; 707 708 for (i = 0; i < wpa_s->conf->num_sec_device_types; i++) 709 wpa_dbus_dict_bin_array_add_element( 710 &iter_secdev_dict_array, 711 wpa_s->conf->sec_device_type[i], 712 WPS_DEV_TYPE_LEN); 713 714 if (!wpa_dbus_dict_end_array(&dict_iter, 715 &iter_secdev_dict_entry, 716 &iter_secdev_dict_val, 717 &iter_secdev_dict_array)) 718 goto err_no_mem; 719 } 720 721 /* Vendor Extensions */ 722 for (i = 0; i < P2P_MAX_WPS_VENDOR_EXT; i++) { 723 if (wpa_s->conf->wps_vendor_ext[i] == NULL) 724 continue; 725 vendor_ext[num_vendor_extensions++] = 726 wpa_s->conf->wps_vendor_ext[i]; 727 } 728 729 if (num_vendor_extensions && 730 !wpa_dbus_dict_append_wpabuf_array(&dict_iter, 731 "VendorExtension", 732 vendor_ext, 733 num_vendor_extensions)) 734 goto err_no_mem; 735 736 /* GO Intent */ 737 if (!wpa_dbus_dict_append_uint32(&dict_iter, "GOIntent", 738 wpa_s->conf->p2p_go_intent)) 739 goto err_no_mem; 740 741 /* Persistant Reconnect */ 742 if (!wpa_dbus_dict_append_bool(&dict_iter, "PersistantReconnect", 743 wpa_s->conf->persistent_reconnect)) 744 goto err_no_mem; 745 746 /* Listen Reg Class */ 747 if (!wpa_dbus_dict_append_uint32(&dict_iter, "ListenRegClass", 748 wpa_s->conf->p2p_listen_reg_class)) 749 goto err_no_mem; 750 751 /* Listen Channel */ 752 if (!wpa_dbus_dict_append_uint32(&dict_iter, "ListenChannel", 753 wpa_s->conf->p2p_listen_channel)) 754 goto err_no_mem; 755 756 /* Oper Reg Class */ 757 if (!wpa_dbus_dict_append_uint32(&dict_iter, "OperRegClass", 758 wpa_s->conf->p2p_oper_reg_class)) 759 goto err_no_mem; 760 761 /* Oper Channel */ 762 if (!wpa_dbus_dict_append_uint32(&dict_iter, "OperChannel", 763 wpa_s->conf->p2p_oper_channel)) 764 goto err_no_mem; 765 766 /* SSID Postfix */ 767 if (wpa_s->conf->p2p_ssid_postfix && 768 !wpa_dbus_dict_append_string(&dict_iter, "SsidPostfix", 769 wpa_s->conf->p2p_ssid_postfix)) 770 goto err_no_mem; 771 772 /* Intra Bss */ 773 if (!wpa_dbus_dict_append_bool(&dict_iter, "IntraBss", 774 wpa_s->conf->p2p_intra_bss)) 775 goto err_no_mem; 776 777 /* Group Idle */ 778 if (!wpa_dbus_dict_append_uint32(&dict_iter, "GroupIdle", 779 wpa_s->conf->p2p_group_idle)) 780 goto err_no_mem; 781 782 /* Dissasociation low ack */ 783 if (!wpa_dbus_dict_append_uint32(&dict_iter, "disassoc_low_ack", 784 wpa_s->conf->disassoc_low_ack)) 785 goto err_no_mem; 786 787 if (!wpa_dbus_dict_close_write(&variant_iter, &dict_iter) || 788 !dbus_message_iter_close_container(&iter, &variant_iter)) 789 goto err_no_mem; 790 791 return reply; 792err_no_mem: 793 dbus_message_unref(reply); 794 return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL); 795} 796 797DBusMessage *wpas_dbus_setter_p2p_device_properties(DBusMessage * message, 798 struct wpa_supplicant * 799 wpa_s) 800{ 801 DBusMessage *reply = NULL; 802 DBusMessageIter iter, variant_iter; 803 struct wpa_dbus_dict_entry entry = {.type = DBUS_TYPE_STRING }; 804 DBusMessageIter iter_dict; 805 unsigned int i; 806 807 dbus_message_iter_init(message, &iter); 808 809 dbus_message_iter_next(&iter); 810 dbus_message_iter_next(&iter); 811 812 dbus_message_iter_recurse(&iter, &variant_iter); 813 814 if (!wpa_dbus_dict_open_read(&variant_iter, &iter_dict)) 815 return wpas_dbus_error_invalid_args(message, NULL); 816 817 while (wpa_dbus_dict_has_dict_entry(&iter_dict)) { 818 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) 819 return wpas_dbus_error_invalid_args(message, NULL); 820 821 if (os_strcmp(entry.key, "DeviceName") == 0) { 822 char *devname; 823 824 if (entry.type != DBUS_TYPE_STRING) 825 goto error_clear; 826 827 devname = os_strdup(entry.str_value); 828 if (devname == NULL) 829 goto err_no_mem_clear; 830 831 os_free(wpa_s->conf->device_name); 832 wpa_s->conf->device_name = devname; 833 834 wpa_s->conf->changed_parameters |= 835 CFG_CHANGED_DEVICE_NAME; 836 } else if (os_strcmp(entry.key, "PrimaryDeviceType") == 0) { 837 if (entry.type != DBUS_TYPE_ARRAY || 838 entry.array_type != DBUS_TYPE_BYTE || 839 entry.array_len != WPS_DEV_TYPE_LEN) 840 goto error_clear; 841 842 os_memcpy(wpa_s->conf->device_type, 843 entry.bytearray_value, 844 WPS_DEV_TYPE_LEN); 845 wpa_s->conf->changed_parameters |= 846 CFG_CHANGED_DEVICE_TYPE; 847 } else if (os_strcmp(entry.key, "SecondaryDeviceTypes") == 0) { 848 if (entry.type != DBUS_TYPE_ARRAY || 849 entry.array_type != WPAS_DBUS_TYPE_BINARRAY || 850 entry.array_len > MAX_SEC_DEVICE_TYPES) 851 goto error; 852 853 for (i = 0; i < entry.array_len; i++) 854 if (wpabuf_len(entry.binarray_value[i]) != WPS_DEV_TYPE_LEN) 855 goto err_no_mem_clear; 856 for (i = 0; i < entry.array_len; i++) 857 os_memcpy(wpa_s->conf->sec_device_type[i], 858 wpabuf_head(entry.binarray_value[i]), 859 WPS_DEV_TYPE_LEN); 860 wpa_s->conf->num_sec_device_types = entry.array_len; 861 wpa_s->conf->changed_parameters |= 862 CFG_CHANGED_SEC_DEVICE_TYPE; 863 } else if (os_strcmp(entry.key, "VendorExtension") == 0) { 864 if ((entry.type != DBUS_TYPE_ARRAY) || 865 (entry.array_type != WPAS_DBUS_TYPE_BINARRAY) || 866 (entry.array_len > P2P_MAX_WPS_VENDOR_EXT)) 867 goto error_clear; 868 869 wpa_s->conf->changed_parameters |= 870 CFG_CHANGED_VENDOR_EXTENSION; 871 872 for (i = 0; i < P2P_MAX_WPS_VENDOR_EXT; i++) { 873 wpabuf_free(wpa_s->conf->wps_vendor_ext[i]); 874 if (i < entry.array_len) { 875 wpa_s->conf->wps_vendor_ext[i] = 876 entry.binarray_value[i]; 877 entry.binarray_value[i] = NULL; 878 } else 879 wpa_s->conf->wps_vendor_ext[i] = NULL; 880 } 881 } else if ((os_strcmp(entry.key, "GOIntent") == 0) && 882 (entry.type == DBUS_TYPE_UINT32) && 883 (entry.uint32_value <= 15)) 884 wpa_s->conf->p2p_go_intent = entry.uint32_value; 885 886 else if ((os_strcmp(entry.key, "PersistantReconnect") == 0) && 887 (entry.type == DBUS_TYPE_BOOLEAN)) 888 wpa_s->conf->persistent_reconnect = entry.bool_value; 889 890 else if ((os_strcmp(entry.key, "ListenRegClass") == 0) && 891 (entry.type == DBUS_TYPE_UINT32)) { 892 wpa_s->conf->p2p_listen_reg_class = entry.uint32_value; 893 wpa_s->conf->changed_parameters |= 894 CFG_CHANGED_P2P_LISTEN_CHANNEL; 895 } else if ((os_strcmp(entry.key, "ListenChannel") == 0) && 896 (entry.type == DBUS_TYPE_UINT32)) { 897 wpa_s->conf->p2p_listen_channel = entry.uint32_value; 898 wpa_s->conf->changed_parameters |= 899 CFG_CHANGED_P2P_LISTEN_CHANNEL; 900 } else if ((os_strcmp(entry.key, "OperRegClass") == 0) && 901 (entry.type == DBUS_TYPE_UINT32)) { 902 wpa_s->conf->p2p_oper_reg_class = entry.uint32_value; 903 wpa_s->conf->changed_parameters |= 904 CFG_CHANGED_P2P_OPER_CHANNEL; 905 } else if ((os_strcmp(entry.key, "OperChannel") == 0) && 906 (entry.type == DBUS_TYPE_UINT32)) { 907 wpa_s->conf->p2p_oper_channel = entry.uint32_value; 908 wpa_s->conf->changed_parameters |= 909 CFG_CHANGED_P2P_OPER_CHANNEL; 910 } else if (os_strcmp(entry.key, "SsidPostfix") == 0) { 911 char *postfix; 912 913 if (entry.type != DBUS_TYPE_STRING) 914 goto error_clear; 915 916 postfix = os_strdup(entry.str_value); 917 if (!postfix) 918 goto err_no_mem_clear; 919 920 os_free(wpa_s->conf->p2p_ssid_postfix); 921 wpa_s->conf->p2p_ssid_postfix = postfix; 922 923 wpa_s->conf->changed_parameters |= 924 CFG_CHANGED_P2P_SSID_POSTFIX; 925 } else if ((os_strcmp(entry.key, "IntraBss") == 0) && 926 (entry.type == DBUS_TYPE_BOOLEAN)) { 927 wpa_s->conf->p2p_intra_bss = entry.bool_value; 928 wpa_s->conf->changed_parameters |= 929 CFG_CHANGED_P2P_INTRA_BSS; 930 } else if ((os_strcmp(entry.key, "GroupIdle") == 0) && 931 (entry.type == DBUS_TYPE_UINT32)) 932 wpa_s->conf->p2p_group_idle = entry.uint32_value; 933 else if (os_strcmp(entry.key, "disassoc_low_ack") == 0 && 934 entry.type == DBUS_TYPE_UINT32) 935 wpa_s->conf->disassoc_low_ack = entry.uint32_value; 936 else 937 goto error_clear; 938 939 wpa_dbus_dict_entry_clear(&entry); 940 } 941 942 if (wpa_s->conf->changed_parameters) { 943 /* Some changed parameters requires to update config*/ 944 wpa_supplicant_update_config(wpa_s); 945 } 946 947 return reply; 948 949 error_clear: 950 wpa_dbus_dict_entry_clear(&entry); 951 error: 952 reply = wpas_dbus_error_invalid_args(message, entry.key); 953 wpa_dbus_dict_entry_clear(&entry); 954 955 return reply; 956 err_no_mem_clear: 957 wpa_dbus_dict_entry_clear(&entry); 958 return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL); 959} 960 961DBusMessage *wpas_dbus_getter_p2p_peers(DBusMessage * message, 962 struct wpa_supplicant * wpa_s) 963{ 964 DBusMessage *reply = NULL; 965 struct p2p_data *p2p = wpa_s->global->p2p; 966 int next = 0, i = 0; 967 int num = 0, out_of_mem = 0; 968 const u8 *addr; 969 const struct p2p_peer_info *peer_info = NULL; 970 971 struct dl_list peer_objpath_list; 972 struct peer_objpath_node { 973 struct dl_list list; 974 char path[WPAS_DBUS_OBJECT_PATH_MAX]; 975 } *node, *tmp; 976 977 char **peer_obj_paths = NULL; 978 979 dl_list_init(&peer_objpath_list); 980 981 /* Get the first peer info */ 982 peer_info = p2p_get_peer_found(p2p, NULL, next); 983 984 /* Get next and accumulate them */ 985 next = 1; 986 while (peer_info != NULL) { 987 node = os_zalloc(sizeof(struct peer_objpath_node)); 988 if (!node) { 989 out_of_mem = 1; 990 goto error; 991 } 992 993 addr = peer_info->p2p_device_addr; 994 os_snprintf(node->path, WPAS_DBUS_OBJECT_PATH_MAX, 995 "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART 996 "/" COMPACT_MACSTR, 997 wpa_s->dbus_new_path, MAC2STR(addr)); 998 dl_list_add_tail(&peer_objpath_list, &node->list); 999 num++; 1000 1001 peer_info = p2p_get_peer_found(p2p, addr, next); 1002 } 1003 1004 /* 1005 * Now construct the peer object paths in a form suitable for 1006 * array_property_getter helper below. 1007 */ 1008 peer_obj_paths = os_zalloc(num * sizeof(char *)); 1009 1010 if (!peer_obj_paths) { 1011 out_of_mem = 1; 1012 goto error; 1013 } 1014 1015 dl_list_for_each_safe(node, tmp, &peer_objpath_list, 1016 struct peer_objpath_node, list) 1017 peer_obj_paths[i++] = node->path; 1018 1019 reply = wpas_dbus_simple_array_property_getter(message, 1020 DBUS_TYPE_OBJECT_PATH, 1021 peer_obj_paths, num); 1022 1023error: 1024 if (peer_obj_paths) 1025 os_free(peer_obj_paths); 1026 1027 dl_list_for_each_safe(node, tmp, &peer_objpath_list, 1028 struct peer_objpath_node, list) { 1029 dl_list_del(&node->list); 1030 os_free(node); 1031 } 1032 if (out_of_mem) 1033 reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, 1034 NULL); 1035 1036 return reply; 1037} 1038 1039enum wpas_p2p_role { 1040 WPAS_P2P_ROLE_DEVICE, 1041 WPAS_P2P_ROLE_GO, 1042 WPAS_P2P_ROLE_CLIENT, 1043}; 1044 1045static enum wpas_p2p_role wpas_get_p2p_role(struct wpa_supplicant *wpa_s) 1046{ 1047 struct wpa_ssid *ssid = wpa_s->current_ssid; 1048 1049 if (!ssid) 1050 return WPAS_P2P_ROLE_DEVICE; 1051 if (wpa_s->wpa_state != WPA_COMPLETED) 1052 return WPAS_P2P_ROLE_DEVICE; 1053 1054 switch (ssid->mode) { 1055 case WPAS_MODE_P2P_GO: 1056 case WPAS_MODE_P2P_GROUP_FORMATION: 1057 return WPAS_P2P_ROLE_GO; 1058 case WPAS_MODE_INFRA: 1059 if (ssid->p2p_group) 1060 return WPAS_P2P_ROLE_CLIENT; 1061 return WPAS_P2P_ROLE_DEVICE; 1062 default: 1063 return WPAS_P2P_ROLE_DEVICE; 1064 } 1065} 1066 1067DBusMessage *wpas_dbus_getter_p2p_role(DBusMessage * message, 1068 struct wpa_supplicant * wpa_s) 1069{ 1070 char *str; 1071 1072 switch (wpas_get_p2p_role(wpa_s)) { 1073 case WPAS_P2P_ROLE_GO: 1074 str = "GO"; 1075 break; 1076 case WPAS_P2P_ROLE_CLIENT: 1077 str = "client"; 1078 break; 1079 default: 1080 str = "device"; 1081 } 1082 1083 return wpas_dbus_simple_property_getter(message, DBUS_TYPE_STRING, 1084 &str); 1085} 1086 1087DBusMessage *wpas_dbus_getter_p2p_group(DBusMessage * message, 1088 struct wpa_supplicant * wpa_s) 1089{ 1090 if (wpa_s->dbus_groupobj_path == NULL) 1091 return NULL; 1092 1093 return wpas_dbus_simple_property_getter(message, 1094 DBUS_TYPE_OBJECT_PATH, 1095 &wpa_s->dbus_groupobj_path); 1096} 1097 1098DBusMessage *wpas_dbus_getter_p2p_peergo(DBusMessage * message, 1099 struct wpa_supplicant * wpa_s) 1100{ 1101 char go_peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path; 1102 1103 if (wpas_get_p2p_role(wpa_s) != WPAS_P2P_ROLE_CLIENT) 1104 return NULL; 1105 1106 os_snprintf(go_peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, 1107 "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/" COMPACT_MACSTR, 1108 wpa_s->dbus_new_path, MAC2STR(wpa_s->go_dev_addr)); 1109 path = go_peer_obj_path; 1110 return wpas_dbus_simple_property_getter(message, 1111 DBUS_TYPE_OBJECT_PATH, &path); 1112} 1113 1114/* 1115 * Peer object properties accessor methods 1116 */ 1117 1118DBusMessage *wpas_dbus_getter_p2p_peer_properties(DBusMessage * message, 1119 struct peer_handler_args * 1120 peer_args) 1121{ 1122 DBusMessage *reply = NULL; 1123 DBusMessageIter iter, variant_iter, dict_iter; 1124 const struct p2p_peer_info *info = NULL; 1125 char devtype[WPS_DEV_TYPE_BUFSIZE]; 1126 1127 /* get the peer info */ 1128 info = p2p_get_peer_found(peer_args->wpa_s->global->p2p, 1129 peer_args->p2p_device_addr, 0); 1130 if (info == NULL) 1131 return NULL; 1132 1133 if (message == NULL) 1134 reply = dbus_message_new(DBUS_MESSAGE_TYPE_SIGNAL); 1135 else 1136 reply = dbus_message_new_method_return(message); 1137 1138 if (!reply) 1139 goto err_no_mem; 1140 1141 dbus_message_iter_init_append(reply, &iter); 1142 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT, 1143 "a{sv}", &variant_iter) || 1144 !wpa_dbus_dict_open_write(&variant_iter, &dict_iter)) 1145 goto err_no_mem; 1146 1147 /* Fill out the dictionary */ 1148 wps_dev_type_bin2str(info->pri_dev_type, devtype, sizeof(devtype)); 1149 if (!wpa_dbus_dict_append_string(&dict_iter, "DeviceName", 1150 info->device_name)) 1151 goto err_no_mem; 1152 if (!wpa_dbus_dict_append_string(&dict_iter, "PrimaryDeviceType", 1153 devtype)) 1154 goto err_no_mem; 1155 if (!wpa_dbus_dict_append_uint16(&dict_iter, "config_method", 1156 info->config_methods)) 1157 goto err_no_mem; 1158 if (!wpa_dbus_dict_append_int32(&dict_iter, "level", 1159 info->level)) 1160 goto err_no_mem; 1161 if (!wpa_dbus_dict_append_byte(&dict_iter, "devicecapability", 1162 info->dev_capab)) 1163 goto err_no_mem; 1164 if (!wpa_dbus_dict_append_byte(&dict_iter, "groupcapability", 1165 info->group_capab)) 1166 goto err_no_mem; 1167 1168 if (info->wps_sec_dev_type_list_len) { 1169 char *sec_dev_types[MAX_SEC_DEVICE_TYPES]; 1170 u8 *sec_dev_type_list = NULL; 1171 char secdevtype[WPS_DEV_TYPE_BUFSIZE]; 1172 int num_sec_dev_types = 0; 1173 int i; 1174 1175 sec_dev_type_list = os_zalloc(info->wps_sec_dev_type_list_len); 1176 1177 if (sec_dev_type_list == NULL) 1178 goto err_no_mem; 1179 1180 os_memcpy(sec_dev_type_list, info->wps_sec_dev_type_list, 1181 info->wps_sec_dev_type_list_len); 1182 1183 for (i = 0; i < MAX_SEC_DEVICE_TYPES && 1184 i < (int) (info->wps_sec_dev_type_list_len / 1185 WPS_DEV_TYPE_LEN); 1186 i++) { 1187 sec_dev_types[i] = os_zalloc(sizeof(secdevtype)); 1188 1189 if (!sec_dev_types[i] || 1190 wps_dev_type_bin2str( 1191 &sec_dev_type_list[i * 1192 WPS_DEV_TYPE_LEN], 1193 sec_dev_types[i], 1194 sizeof(secdevtype)) == NULL) { 1195 while (--i >= 0) 1196 os_free(sec_dev_types[i]); 1197 os_free(sec_dev_type_list); 1198 goto err_no_mem; 1199 } 1200 1201 num_sec_dev_types++; 1202 } 1203 1204 os_free(sec_dev_type_list); 1205 1206 if (num_sec_dev_types) { 1207 if (!wpa_dbus_dict_append_string_array(&dict_iter, 1208 "SecondaryDeviceTypes", 1209 (const char **)sec_dev_types, 1210 num_sec_dev_types)) { 1211 for (i = 0; i < num_sec_dev_types; i++) 1212 os_free(sec_dev_types[i]); 1213 goto err_no_mem; 1214 } 1215 1216 for (i = 0; i < num_sec_dev_types; i++) 1217 os_free(sec_dev_types[i]); 1218 } 1219 } 1220 1221 { 1222 /* Add WPS vendor extensions attribute */ 1223 const struct wpabuf *vendor_extension[P2P_MAX_WPS_VENDOR_EXT]; 1224 int i, num = 0; 1225 1226 for (i = 0; i < P2P_MAX_WPS_VENDOR_EXT; i++) { 1227 if (info->wps_vendor_ext[i] == NULL) 1228 continue; 1229 vendor_extension[num] = info->wps_vendor_ext[i]; 1230 num++; 1231 } 1232 1233 if (!wpa_dbus_dict_append_wpabuf_array( 1234 &dict_iter, "VendorExtension", 1235 vendor_extension, num)) 1236 goto err_no_mem; 1237 } 1238 1239 if (!wpa_dbus_dict_close_write(&variant_iter, &dict_iter) || 1240 !dbus_message_iter_close_container(&iter, &variant_iter)) 1241 goto err_no_mem; 1242 1243 return reply; 1244err_no_mem: 1245 dbus_message_unref(reply); 1246 return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL); 1247} 1248 1249DBusMessage *wpas_dbus_getter_p2p_peer_ies(DBusMessage * message, 1250 struct peer_handler_args * peer_args) 1251{ 1252 return NULL; 1253} 1254 1255 1256/** 1257 * wpas_dbus_getter_persistent_groups - Get array of peristent group objects 1258 * @message: Pointer to incoming dbus message 1259 * @wpa_s: wpa_supplicant structure for a network interface 1260 * Returns: a dbus message containing an array of all persistent group 1261 * dbus object paths. 1262 * 1263 * Getter for "Networks" property. 1264 */ 1265DBusMessage * wpas_dbus_getter_persistent_groups(DBusMessage *message, 1266 struct wpa_supplicant *wpa_s) 1267{ 1268 DBusMessage *reply = NULL; 1269 struct wpa_ssid *ssid; 1270 char **paths; 1271 unsigned int i = 0, num = 0; 1272 1273 if (wpa_s->conf == NULL) { 1274 wpa_printf(MSG_ERROR, "dbus: %s: " 1275 "An error occurred getting persistent groups list", 1276 __func__); 1277 return wpas_dbus_error_unknown_error(message, NULL); 1278 } 1279 1280 for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) 1281 if (network_is_persistent_group(ssid)) 1282 num++; 1283 1284 paths = os_zalloc(num * sizeof(char *)); 1285 if (!paths) { 1286 return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, 1287 NULL); 1288 } 1289 1290 /* Loop through configured networks and append object path of each */ 1291 for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) { 1292 if (!network_is_persistent_group(ssid)) 1293 continue; 1294 paths[i] = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX); 1295 if (paths[i] == NULL) { 1296 reply = dbus_message_new_error(message, 1297 DBUS_ERROR_NO_MEMORY, 1298 NULL); 1299 goto out; 1300 } 1301 /* Construct the object path for this network. */ 1302 os_snprintf(paths[i++], WPAS_DBUS_OBJECT_PATH_MAX, 1303 "%s/" WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART "/%d", 1304 wpa_s->dbus_new_path, ssid->id); 1305 } 1306 1307 reply = wpas_dbus_simple_array_property_getter(message, 1308 DBUS_TYPE_OBJECT_PATH, 1309 paths, num); 1310 1311out: 1312 while (i) 1313 os_free(paths[--i]); 1314 os_free(paths); 1315 return reply; 1316} 1317 1318 1319/** 1320 * wpas_dbus_getter_persistent_group_properties - Get options for a persistent 1321 * group 1322 * @message: Pointer to incoming dbus message 1323 * @net: wpa_supplicant structure for a network interface and 1324 * wpa_ssid structure for a configured persistent group (internally network) 1325 * Returns: DBus message with network properties or DBus error on failure 1326 * 1327 * Getter for "Properties" property of a persistent group. 1328 */ 1329DBusMessage * wpas_dbus_getter_persistent_group_properties( 1330 DBusMessage *message, struct network_handler_args *net) 1331{ 1332 /* 1333 * Leveraging the fact that persistent group object is still 1334 * represented in same manner as network within. 1335 */ 1336 return wpas_dbus_getter_network_properties(message, net); 1337} 1338 1339 1340/** 1341 * wpas_dbus_setter_persistent_group_properties - Get options for a persistent 1342 * group 1343 * @message: Pointer to incoming dbus message 1344 * @net: wpa_supplicant structure for a network interface and 1345 * wpa_ssid structure for a configured persistent group (internally network) 1346 * Returns: DBus message with network properties or DBus error on failure 1347 * 1348 * Setter for "Properties" property of a persistent group. 1349 */ 1350DBusMessage * wpas_dbus_setter_persistent_group_properties( 1351 DBusMessage *message, struct network_handler_args *net) 1352{ 1353 struct wpa_ssid *ssid = net->ssid; 1354 DBusMessage *reply = NULL; 1355 DBusMessageIter iter, variant_iter; 1356 1357 dbus_message_iter_init(message, &iter); 1358 1359 dbus_message_iter_next(&iter); 1360 dbus_message_iter_next(&iter); 1361 1362 dbus_message_iter_recurse(&iter, &variant_iter); 1363 1364 /* 1365 * Leveraging the fact that persistent group object is still 1366 * represented in same manner as network within. 1367 */ 1368 reply = set_network_properties(message, net->wpa_s, ssid, 1369 &variant_iter); 1370 if (reply) 1371 wpa_printf(MSG_DEBUG, "dbus control interface couldn't set " 1372 "persistent group properties"); 1373 1374 return reply; 1375} 1376 1377 1378/** 1379 * wpas_dbus_new_iface_add_persistent_group - Add a new configured 1380 * persistent_group 1381 * @message: Pointer to incoming dbus message 1382 * @wpa_s: wpa_supplicant structure for a network interface 1383 * Returns: A dbus message containing the object path of the new 1384 * persistent group 1385 * 1386 * Handler function for "AddPersistentGroup" method call of a P2P Device 1387 * interface. 1388 */ 1389DBusMessage * wpas_dbus_handler_add_persistent_group( 1390 DBusMessage *message, struct wpa_supplicant *wpa_s) 1391{ 1392 DBusMessage *reply = NULL; 1393 DBusMessageIter iter; 1394 struct wpa_ssid *ssid = NULL; 1395 char path_buf[WPAS_DBUS_OBJECT_PATH_MAX], *path = path_buf; 1396 1397 dbus_message_iter_init(message, &iter); 1398 1399 ssid = wpa_config_add_network(wpa_s->conf); 1400 if (ssid == NULL) { 1401 wpa_printf(MSG_ERROR, "dbus: %s: " 1402 "Cannot add new persistent group", __func__); 1403 reply = wpas_dbus_error_unknown_error( 1404 message, 1405 "wpa_supplicant could not add " 1406 "a persistent group on this interface."); 1407 goto err; 1408 } 1409 1410 /* Mark the ssid as being a persistent group before the notification */ 1411 ssid->disabled = 2; 1412 ssid->p2p_persistent_group = 1; 1413 wpas_notify_persistent_group_added(wpa_s, ssid); 1414 1415 wpa_config_set_network_defaults(ssid); 1416 1417 reply = set_network_properties(message, wpa_s, ssid, &iter); 1418 if (reply) { 1419 wpa_printf(MSG_DEBUG, "dbus: %s: " 1420 "Control interface could not set persistent group " 1421 "properties", __func__); 1422 goto err; 1423 } 1424 1425 /* Construct the object path for this network. */ 1426 os_snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX, 1427 "%s/" WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART "/%d", 1428 wpa_s->dbus_new_path, ssid->id); 1429 1430 reply = dbus_message_new_method_return(message); 1431 if (reply == NULL) { 1432 reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, 1433 NULL); 1434 goto err; 1435 } 1436 if (!dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &path, 1437 DBUS_TYPE_INVALID)) { 1438 dbus_message_unref(reply); 1439 reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, 1440 NULL); 1441 goto err; 1442 } 1443 1444 return reply; 1445 1446err: 1447 if (ssid) { 1448 wpas_notify_persistent_group_removed(wpa_s, ssid); 1449 wpa_config_remove_network(wpa_s->conf, ssid->id); 1450 } 1451 return reply; 1452} 1453 1454 1455/** 1456 * wpas_dbus_handler_remove_persistent_group - Remove a configured persistent 1457 * group 1458 * @message: Pointer to incoming dbus message 1459 * @wpa_s: wpa_supplicant structure for a network interface 1460 * Returns: NULL on success or dbus error on failure 1461 * 1462 * Handler function for "RemovePersistentGroup" method call of a P2P Device 1463 * interface. 1464 */ 1465DBusMessage * wpas_dbus_handler_remove_persistent_group( 1466 DBusMessage *message, struct wpa_supplicant *wpa_s) 1467{ 1468 DBusMessage *reply = NULL; 1469 const char *op; 1470 char *iface = NULL, *persistent_group_id = NULL; 1471 int id; 1472 struct wpa_ssid *ssid; 1473 1474 dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &op, 1475 DBUS_TYPE_INVALID); 1476 1477 /* 1478 * Extract the network ID and ensure the network is actually a child of 1479 * this interface. 1480 */ 1481 iface = wpas_dbus_new_decompose_object_path(op, 1, 1482 &persistent_group_id, 1483 NULL); 1484 if (iface == NULL || os_strcmp(iface, wpa_s->dbus_new_path) != 0) { 1485 reply = wpas_dbus_error_invalid_args(message, op); 1486 goto out; 1487 } 1488 1489 id = strtoul(persistent_group_id, NULL, 10); 1490 if (errno == EINVAL) { 1491 reply = wpas_dbus_error_invalid_args(message, op); 1492 goto out; 1493 } 1494 1495 ssid = wpa_config_get_network(wpa_s->conf, id); 1496 if (ssid == NULL) { 1497 reply = wpas_dbus_error_persistent_group_unknown(message); 1498 goto out; 1499 } 1500 1501 wpas_notify_persistent_group_removed(wpa_s, ssid); 1502 1503 if (wpa_config_remove_network(wpa_s->conf, id) < 0) { 1504 wpa_printf(MSG_ERROR, "dbus: %s: " 1505 "error occurred when removing persistent group %d", 1506 __func__, id); 1507 reply = wpas_dbus_error_unknown_error( 1508 message, 1509 "error removing the specified persistent group on " 1510 "this interface."); 1511 goto out; 1512 } 1513 1514out: 1515 os_free(iface); 1516 os_free(persistent_group_id); 1517 return reply; 1518} 1519 1520 1521static void remove_persistent_group(struct wpa_supplicant *wpa_s, 1522 struct wpa_ssid *ssid) 1523{ 1524 wpas_notify_persistent_group_removed(wpa_s, ssid); 1525 1526 if (wpa_config_remove_network(wpa_s->conf, ssid->id) < 0) { 1527 wpa_printf(MSG_ERROR, "dbus: %s: " 1528 "error occurred when removing persistent group %d", 1529 __func__, ssid->id); 1530 return; 1531 } 1532} 1533 1534 1535/** 1536 * wpas_dbus_handler_remove_all_persistent_groups - Remove all configured 1537 * persistent groups 1538 * @message: Pointer to incoming dbus message 1539 * @wpa_s: wpa_supplicant structure for a network interface 1540 * Returns: NULL on success or dbus error on failure 1541 * 1542 * Handler function for "RemoveAllPersistentGroups" method call of a 1543 * P2P Device interface. 1544 */ 1545DBusMessage * wpas_dbus_handler_remove_all_persistent_groups( 1546 DBusMessage *message, struct wpa_supplicant *wpa_s) 1547{ 1548 struct wpa_ssid *ssid, *next; 1549 struct wpa_config *config; 1550 1551 config = wpa_s->conf; 1552 ssid = config->ssid; 1553 while (ssid) { 1554 next = ssid->next; 1555 if (network_is_persistent_group(ssid)) 1556 remove_persistent_group(wpa_s, ssid); 1557 ssid = next; 1558 } 1559 return NULL; 1560} 1561 1562 1563/* 1564 * Group object properties accessor methods 1565 */ 1566 1567DBusMessage *wpas_dbus_getter_p2p_group_members(DBusMessage * message, 1568 struct wpa_supplicant * wpa_s) 1569{ 1570 DBusMessage *reply = NULL; 1571 struct wpa_ssid *ssid; 1572 unsigned int num_members; 1573 char **paths; 1574 unsigned int i; 1575 void *next = NULL; 1576 const u8 *addr; 1577 1578 /* Ensure we are a GO */ 1579 if (wpa_s->wpa_state != WPA_COMPLETED) 1580 goto out; 1581 1582 ssid = wpa_s->conf->ssid; 1583 /* At present WPAS P2P_GO mode only applicable for p2p_go */ 1584 if (ssid->mode != WPAS_MODE_P2P_GO && 1585 ssid->mode != WPAS_MODE_AP && 1586 ssid->mode != WPAS_MODE_P2P_GROUP_FORMATION) 1587 goto out; 1588 1589 num_members = p2p_get_group_num_members(wpa_s->p2p_group); 1590 1591 paths = os_zalloc(num_members * sizeof(char *)); 1592 if (!paths) 1593 goto out_of_memory; 1594 1595 i = 0; 1596 while ((addr = p2p_iterate_group_members(wpa_s->p2p_group, &next))) { 1597 paths[i] = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX); 1598 if (!paths[i]) 1599 goto out_of_memory; 1600 os_snprintf(paths[i], WPAS_DBUS_OBJECT_PATH_MAX, 1601 "%s/" WPAS_DBUS_NEW_P2P_GROUPMEMBERS_PART 1602 "/" COMPACT_MACSTR, 1603 wpa_s->dbus_groupobj_path, MAC2STR(addr)); 1604 i++; 1605 } 1606 1607 reply = wpas_dbus_simple_array_property_getter(message, 1608 DBUS_TYPE_OBJECT_PATH, 1609 paths, num_members); 1610 1611out_free: 1612 for (i = 0; i < num_members; i++) 1613 os_free(paths[i]); 1614 os_free(paths); 1615out: 1616 return reply; 1617out_of_memory: 1618 reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL); 1619 goto out_free; 1620} 1621 1622 1623DBusMessage *wpas_dbus_getter_p2p_group_properties( 1624 DBusMessage *message, 1625 struct wpa_supplicant *wpa_s) 1626{ 1627 DBusMessage *reply = NULL; 1628 DBusMessageIter iter, variant_iter, dict_iter; 1629 struct hostapd_data *hapd = wpa_s->ap_iface->bss[0]; 1630 const struct wpabuf *vendor_ext[MAX_WPS_VENDOR_EXTENSIONS]; 1631 int num_vendor_ext = 0; 1632 int i; 1633 1634 if (!hapd) { 1635 reply = dbus_message_new_error(message, DBUS_ERROR_FAILED, 1636 NULL); 1637 return reply; 1638 } 1639 1640 if (message == NULL) 1641 reply = dbus_message_new(DBUS_MESSAGE_TYPE_SIGNAL); 1642 else 1643 reply = dbus_message_new_method_return(message); 1644 1645 if (!reply) 1646 goto err_no_mem; 1647 1648 dbus_message_iter_init_append(reply, &iter); 1649 1650 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT, 1651 "a{sv}", &variant_iter) || 1652 !wpa_dbus_dict_open_write(&variant_iter, &dict_iter)) 1653 goto err_no_mem; 1654 1655 /* Parse WPS Vendor Extensions sent in Beacon/Probe Response */ 1656 for (i = 0; i < MAX_WPS_VENDOR_EXTENSIONS; i++) { 1657 if (hapd->conf->wps_vendor_ext[i] == NULL) 1658 continue; 1659 vendor_ext[num_vendor_ext++] = hapd->conf->wps_vendor_ext[i]; 1660 } 1661 1662 if (!wpa_dbus_dict_append_wpabuf_array(&dict_iter, 1663 "WPSVendorExtensions", 1664 vendor_ext, num_vendor_ext)) 1665 goto err_no_mem; 1666 1667 if (!wpa_dbus_dict_close_write(&variant_iter, &dict_iter) || 1668 !dbus_message_iter_close_container(&iter, &variant_iter)) 1669 goto err_no_mem; 1670 1671 return reply; 1672 1673err_no_mem: 1674 dbus_message_unref(reply); 1675 return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL); 1676} 1677 1678DBusMessage *wpas_dbus_setter_p2p_group_properties( 1679 DBusMessage *message, 1680 struct wpa_supplicant *wpa_s) 1681{ 1682 DBusMessage *reply = NULL; 1683 DBusMessageIter iter, variant_iter; 1684 struct wpa_dbus_dict_entry entry = {.type = DBUS_TYPE_STRING }; 1685 DBusMessageIter iter_dict; 1686 unsigned int i; 1687 1688 struct hostapd_data *hapd = wpa_s->ap_iface->bss[0]; 1689 1690 if (!hapd) 1691 goto error; 1692 1693 dbus_message_iter_init(message, &iter); 1694 1695 dbus_message_iter_next(&iter); 1696 dbus_message_iter_next(&iter); 1697 1698 dbus_message_iter_recurse(&iter, &variant_iter); 1699 1700 if (!wpa_dbus_dict_open_read(&variant_iter, &iter_dict)) 1701 return wpas_dbus_error_invalid_args(message, NULL); 1702 1703 while (wpa_dbus_dict_has_dict_entry(&iter_dict)) { 1704 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) { 1705 reply = wpas_dbus_error_invalid_args(message, NULL); 1706 break; 1707 } 1708 1709 if (os_strcmp(entry.key, "WPSVendorExtensions") == 0) { 1710 if (entry.type != DBUS_TYPE_ARRAY || 1711 entry.array_type != WPAS_DBUS_TYPE_BINARRAY || 1712 entry.array_len > MAX_WPS_VENDOR_EXTENSIONS) 1713 goto error; 1714 1715 for (i = 0; i < MAX_WPS_VENDOR_EXTENSIONS; i++) { 1716 if (i < entry.array_len) { 1717 hapd->conf->wps_vendor_ext[i] = 1718 entry.binarray_value[i]; 1719 entry.binarray_value[i] = NULL; 1720 } else 1721 hapd->conf->wps_vendor_ext[i] = NULL; 1722 } 1723 1724 hostapd_update_wps(hapd); 1725 } else 1726 goto error; 1727 1728 wpa_dbus_dict_entry_clear(&entry); 1729 } 1730 1731 return reply; 1732 1733error: 1734 reply = wpas_dbus_error_invalid_args(message, entry.key); 1735 wpa_dbus_dict_entry_clear(&entry); 1736 1737 return reply; 1738} 1739 1740DBusMessage *wpas_dbus_handler_p2p_add_service(DBusMessage * message, 1741 struct wpa_supplicant * wpa_s) 1742{ 1743 DBusMessageIter iter_dict; 1744 DBusMessage *reply = NULL; 1745 DBusMessageIter iter; 1746 struct wpa_dbus_dict_entry entry; 1747 int upnp = 0; 1748 int bonjour = 0; 1749 char *service = NULL; 1750 struct wpabuf *query = NULL; 1751 struct wpabuf *resp = NULL; 1752 u8 version = 0; 1753 1754 dbus_message_iter_init(message, &iter); 1755 1756 if (!wpa_dbus_dict_open_read(&iter, &iter_dict)) 1757 goto error; 1758 1759 if (wpa_dbus_dict_has_dict_entry(&iter_dict)) { 1760 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) 1761 goto error; 1762 1763 if (!strcmp(entry.key, "service_type") && 1764 (entry.type == DBUS_TYPE_STRING)) { 1765 if (!strcmp(entry.str_value, "upnp")) 1766 upnp = 1; 1767 else if (!strcmp(entry.str_value, "bonjour")) 1768 bonjour = 1; 1769 else 1770 goto error_clear; 1771 wpa_dbus_dict_entry_clear(&entry); 1772 } 1773 } 1774 1775 if (upnp == 1) { 1776 while (wpa_dbus_dict_has_dict_entry(&iter_dict)) { 1777 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) 1778 goto error; 1779 1780 if (!strcmp(entry.key, "version") && 1781 entry.type == DBUS_TYPE_INT32) 1782 version = entry.uint32_value; 1783 else if (!strcmp(entry.key, "service") && 1784 entry.type == DBUS_TYPE_STRING) 1785 service = os_strdup(entry.str_value); 1786 wpa_dbus_dict_entry_clear(&entry); 1787 } 1788 if (version <= 0 || service == NULL) 1789 goto error; 1790 1791 if (wpas_p2p_service_add_upnp(wpa_s, version, service) != 0) 1792 goto error; 1793 1794 os_free(service); 1795 } else if (bonjour == 1) { 1796 while (wpa_dbus_dict_has_dict_entry(&iter_dict)) { 1797 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) 1798 goto error; 1799 1800 if (!strcmp(entry.key, "query")) { 1801 if ((entry.type != DBUS_TYPE_ARRAY) || 1802 (entry.array_type != DBUS_TYPE_BYTE)) 1803 goto error_clear; 1804 query = wpabuf_alloc_copy(entry.bytearray_value, 1805 entry.array_len); 1806 } else if (!strcmp(entry.key, "response")) { 1807 if ((entry.type != DBUS_TYPE_ARRAY) || 1808 (entry.array_type != DBUS_TYPE_BYTE)) 1809 goto error_clear; 1810 resp = wpabuf_alloc_copy(entry.bytearray_value, 1811 entry.array_len); 1812 } 1813 1814 wpa_dbus_dict_entry_clear(&entry); 1815 } 1816 1817 if (query == NULL || resp == NULL) 1818 goto error; 1819 1820 if (wpas_p2p_service_add_bonjour(wpa_s, query, resp) < 0) { 1821 wpabuf_free(query); 1822 wpabuf_free(resp); 1823 goto error; 1824 } 1825 } else 1826 goto error; 1827 1828 return reply; 1829error_clear: 1830 wpa_dbus_dict_entry_clear(&entry); 1831error: 1832 return wpas_dbus_error_invalid_args(message, NULL); 1833} 1834 1835DBusMessage *wpas_dbus_handler_p2p_delete_service(DBusMessage * message, 1836 struct wpa_supplicant * wpa_s) 1837{ 1838 DBusMessageIter iter_dict; 1839 DBusMessage *reply = NULL; 1840 DBusMessageIter iter; 1841 struct wpa_dbus_dict_entry entry; 1842 int upnp = 0; 1843 int bonjour = 0; 1844 int ret = 0; 1845 char *service = NULL; 1846 struct wpabuf *query = NULL; 1847 u8 version = 0; 1848 1849 dbus_message_iter_init(message, &iter); 1850 1851 if (!wpa_dbus_dict_open_read(&iter, &iter_dict)) 1852 goto error; 1853 1854 if (wpa_dbus_dict_has_dict_entry(&iter_dict)) { 1855 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) 1856 goto error; 1857 1858 if (!strcmp(entry.key, "service_type") && 1859 (entry.type == DBUS_TYPE_STRING)) { 1860 if (!strcmp(entry.str_value, "upnp")) 1861 upnp = 1; 1862 else if (!strcmp(entry.str_value, "bonjour")) 1863 bonjour = 1; 1864 else 1865 goto error_clear; 1866 wpa_dbus_dict_entry_clear(&entry); 1867 } 1868 } 1869 if (upnp == 1) { 1870 while (wpa_dbus_dict_has_dict_entry(&iter_dict)) { 1871 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) 1872 goto error; 1873 if (!strcmp(entry.key, "version") && 1874 entry.type == DBUS_TYPE_INT32) 1875 version = entry.uint32_value; 1876 else if (!strcmp(entry.key, "service") && 1877 entry.type == DBUS_TYPE_STRING) 1878 service = os_strdup(entry.str_value); 1879 else 1880 goto error_clear; 1881 1882 wpa_dbus_dict_entry_clear(&entry); 1883 } 1884 1885 if (version <= 0 || service == NULL) 1886 goto error; 1887 1888 ret = wpas_p2p_service_del_upnp(wpa_s, version, service); 1889 os_free(service); 1890 if (ret != 0) 1891 goto error; 1892 } else if (bonjour == 1) { 1893 while (wpa_dbus_dict_has_dict_entry(&iter_dict)) { 1894 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) 1895 goto error; 1896 1897 if (!strcmp(entry.key, "query")) { 1898 if ((entry.type != DBUS_TYPE_ARRAY) || 1899 (entry.array_type != DBUS_TYPE_BYTE)) 1900 goto error_clear; 1901 query = wpabuf_alloc_copy(entry.bytearray_value, 1902 entry.array_len); 1903 } else 1904 goto error_clear; 1905 1906 wpa_dbus_dict_entry_clear(&entry); 1907 } 1908 1909 if (query == NULL) 1910 goto error; 1911 1912 ret = wpas_p2p_service_del_bonjour(wpa_s, query); 1913 if (ret != 0) 1914 goto error; 1915 wpabuf_free(query); 1916 } else 1917 goto error; 1918 1919 return reply; 1920error_clear: 1921 wpa_dbus_dict_entry_clear(&entry); 1922error: 1923 return wpas_dbus_error_invalid_args(message, NULL); 1924} 1925 1926DBusMessage *wpas_dbus_handler_p2p_flush_service(DBusMessage * message, 1927 struct wpa_supplicant * wpa_s) 1928{ 1929 wpas_p2p_service_flush(wpa_s); 1930 return NULL; 1931} 1932 1933DBusMessage *wpas_dbus_handler_p2p_service_sd_req(DBusMessage * message, 1934 struct wpa_supplicant * wpa_s) 1935{ 1936 DBusMessageIter iter_dict; 1937 DBusMessage *reply = NULL; 1938 DBusMessageIter iter; 1939 struct wpa_dbus_dict_entry entry; 1940 int upnp = 0; 1941 char *service = NULL; 1942 char *peer_object_path = NULL; 1943 struct wpabuf *tlv = NULL; 1944 u8 version = 0; 1945 u64 ref = 0; 1946 u8 addr[ETH_ALEN]; 1947 1948 dbus_message_iter_init(message, &iter); 1949 1950 if (!wpa_dbus_dict_open_read(&iter, &iter_dict)) 1951 goto error; 1952 1953 while (wpa_dbus_dict_has_dict_entry(&iter_dict)) { 1954 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) 1955 goto error; 1956 if (!strcmp(entry.key, "peer_object") && 1957 entry.type == DBUS_TYPE_OBJECT_PATH) { 1958 peer_object_path = os_strdup(entry.str_value); 1959 } else if (!strcmp(entry.key, "service_type") && 1960 entry.type == DBUS_TYPE_STRING) { 1961 if (!strcmp(entry.str_value, "upnp")) 1962 upnp = 1; 1963 else 1964 goto error_clear; 1965 } else if (!strcmp(entry.key, "version") && 1966 entry.type == DBUS_TYPE_INT32) { 1967 version = entry.uint32_value; 1968 } else if (!strcmp(entry.key, "service") && 1969 entry.type == DBUS_TYPE_STRING) { 1970 service = os_strdup(entry.str_value); 1971 } else if (!strcmp(entry.key, "tlv")) { 1972 if (entry.type != DBUS_TYPE_ARRAY || 1973 entry.array_type != DBUS_TYPE_BYTE) 1974 goto error_clear; 1975 tlv = wpabuf_alloc_copy(entry.bytearray_value, 1976 entry.array_len); 1977 } else 1978 goto error_clear; 1979 1980 wpa_dbus_dict_entry_clear(&entry); 1981 } 1982 1983 if (!peer_object_path || 1984 (parse_peer_object_path(peer_object_path, addr) < 0) || 1985 (p2p_get_peer_info(wpa_s->global->p2p, addr, 0, NULL, 0) < 0)) 1986 goto error; 1987 1988 if (upnp == 1) { 1989 if (version <= 0 || service == NULL) 1990 goto error; 1991 1992 ref = (unsigned long)wpas_p2p_sd_request_upnp(wpa_s, addr, 1993 version, service); 1994 } else { 1995 if (tlv == NULL) 1996 goto error; 1997 ref = (unsigned long)wpas_p2p_sd_request(wpa_s, addr, tlv); 1998 wpabuf_free(tlv); 1999 } 2000 2001 if (ref != 0) { 2002 reply = dbus_message_new_method_return(message); 2003 dbus_message_append_args(reply, DBUS_TYPE_UINT64, 2004 &ref, DBUS_TYPE_INVALID); 2005 } else { 2006 reply = wpas_dbus_error_unknown_error(message, 2007 "Unable to send SD request"); 2008 } 2009out: 2010 os_free(service); 2011 os_free(peer_object_path); 2012 return reply; 2013error_clear: 2014 wpa_dbus_dict_entry_clear(&entry); 2015error: 2016 if (tlv) 2017 wpabuf_free(tlv); 2018 reply = wpas_dbus_error_invalid_args(message, NULL); 2019 goto out; 2020} 2021 2022DBusMessage *wpas_dbus_handler_p2p_service_sd_res( 2023 DBusMessage *message, struct wpa_supplicant *wpa_s) 2024{ 2025 DBusMessageIter iter_dict; 2026 DBusMessage *reply = NULL; 2027 DBusMessageIter iter; 2028 struct wpa_dbus_dict_entry entry; 2029 char *peer_object_path = NULL; 2030 struct wpabuf *tlv = NULL; 2031 int freq = 0; 2032 int dlg_tok = 0; 2033 u8 addr[ETH_ALEN]; 2034 2035 dbus_message_iter_init(message, &iter); 2036 2037 if (!wpa_dbus_dict_open_read(&iter, &iter_dict)) 2038 goto error; 2039 2040 while (wpa_dbus_dict_has_dict_entry(&iter_dict)) { 2041 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) 2042 goto error; 2043 2044 if (!strcmp(entry.key, "peer_object") && 2045 entry.type == DBUS_TYPE_OBJECT_PATH) { 2046 peer_object_path = os_strdup(entry.str_value); 2047 } else if (!strcmp(entry.key, "frequency") && 2048 entry.type == DBUS_TYPE_INT32) { 2049 freq = entry.uint32_value; 2050 } else if (!strcmp(entry.key, "dialog_token") && 2051 entry.type == DBUS_TYPE_UINT32) { 2052 dlg_tok = entry.uint32_value; 2053 } else if (!strcmp(entry.key, "tlvs")) { 2054 if (entry.type != DBUS_TYPE_ARRAY || 2055 entry.array_type != DBUS_TYPE_BYTE) 2056 goto error_clear; 2057 tlv = wpabuf_alloc_copy(entry.bytearray_value, 2058 entry.array_len); 2059 } else 2060 goto error_clear; 2061 2062 wpa_dbus_dict_entry_clear(&entry); 2063 } 2064 if (!peer_object_path || 2065 (parse_peer_object_path(peer_object_path, addr) < 0) || 2066 (p2p_get_peer_info(wpa_s->global->p2p, addr, 0, NULL, 0) < 0)) 2067 goto error; 2068 2069 if (tlv == NULL) 2070 goto error; 2071 2072 wpas_p2p_sd_response(wpa_s, freq, addr, (u8) dlg_tok, tlv); 2073 wpabuf_free(tlv); 2074out: 2075 os_free(peer_object_path); 2076 return reply; 2077error_clear: 2078 wpa_dbus_dict_entry_clear(&entry); 2079error: 2080 reply = wpas_dbus_error_invalid_args(message, NULL); 2081 goto out; 2082} 2083 2084DBusMessage *wpas_dbus_handler_p2p_service_sd_cancel_req(DBusMessage * message, struct wpa_supplicant 2085 *wpa_s) 2086{ 2087 DBusMessageIter iter; 2088 u64 req = 0; 2089 2090 dbus_message_iter_init(message, &iter); 2091 dbus_message_iter_get_basic(&iter, &req); 2092 2093 if (req == 0) 2094 goto error; 2095 2096 if (!wpas_p2p_sd_cancel_request(wpa_s, (void *)(unsigned long)req)) 2097 goto error; 2098 2099 return NULL; 2100error: 2101 return wpas_dbus_error_invalid_args(message, NULL); 2102} 2103 2104DBusMessage *wpas_dbus_handler_p2p_service_update(DBusMessage * message, 2105 struct wpa_supplicant * wpa_s) 2106{ 2107 wpas_p2p_sd_service_update(wpa_s); 2108 return NULL; 2109} 2110 2111DBusMessage *wpas_dbus_handler_p2p_serv_disc_external(DBusMessage * message, 2112 struct wpa_supplicant * 2113 wpa_s) 2114{ 2115 DBusMessageIter iter; 2116 int ext = 0; 2117 2118 dbus_message_iter_init(message, &iter); 2119 dbus_message_iter_get_basic(&iter, &ext); 2120 2121 wpa_s->p2p_sd_over_ctrl_iface = ext; 2122 2123 return NULL; 2124 2125} 2126