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