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