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