2 * WPA Supplicant / dbus-based control interface (P2P)
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.
8 * Alternatively, this software may be distributed under the terms of BSD
11 * See README and COPYING for more details.
16 #include "utils/includes.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"
24 #include "dbus_new_handlers.h"
25 #include "dbus_new_handlers_p2p.h"
26 #include "dbus_dict_helpers.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"
33 #include "../p2p_supplicant.h"
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
42 static int parse_peer_object_path(char *peer_path, u8 addr[ETH_ALEN])
48 p = strrchr(peer_path, '/');
52 return hwaddr_compact_aton(p, addr);
57 * wpas_dbus_error_persistent_group_unknown - Return a new PersistentGroupUnknown
59 * @message: Pointer to incoming dbus message this error refers to
60 * Returns: a dbus error message
62 * Convenience function to create and return an invalid persistent group error.
64 static DBusMessage * wpas_dbus_error_persistent_group_unknown(
67 return dbus_message_new_error(message, WPAS_DBUS_ERROR_NETWORK_UNKNOWN,
68 "There is no such persistent group in "
73 DBusMessage * wpas_dbus_handler_p2p_find(DBusMessage *message,
74 struct wpa_supplicant *wpa_s)
76 struct wpa_dbus_dict_entry entry;
77 DBusMessage *reply = NULL;
79 DBusMessageIter iter_dict;
80 unsigned int timeout = 0;
81 enum p2p_discovery_type type = P2P_FIND_ONLY_SOCIAL;
82 int num_req_dev_types = 0;
84 u8 *req_dev_types = NULL;
86 dbus_message_iter_init(message, &iter);
89 if (!wpa_dbus_dict_open_read(&iter, &iter_dict))
92 while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
93 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
96 if (!os_strcmp(entry.key, "Timeout") &&
97 (entry.type == DBUS_TYPE_INT32)) {
98 timeout = entry.uint32_value;
99 } else if (os_strcmp(entry.key, "RequestedDeviceTypes") == 0) {
100 if ((entry.type != DBUS_TYPE_ARRAY) ||
101 (entry.array_type != WPAS_DBUS_TYPE_BINARRAY))
105 os_malloc(WPS_DEV_TYPE_LEN * entry.array_len);
109 for (i = 0; i < entry.array_len; i++) {
110 if (wpabuf_len(entry.binarray_value[i]) !=
113 os_memcpy(req_dev_types + i * WPS_DEV_TYPE_LEN,
114 wpabuf_head(entry.binarray_value[i]),
118 num_req_dev_types = entry.array_len;
121 wpa_dbus_dict_entry_clear(&entry);
124 wpas_p2p_find(wpa_s, timeout, type, num_req_dev_types, req_dev_types);
125 os_free(req_dev_types);
129 wpa_dbus_dict_entry_clear(&entry);
131 os_free(req_dev_types);
132 reply = wpas_dbus_error_invalid_args(message, entry.key);
137 DBusMessage * wpas_dbus_handler_p2p_stop_find(DBusMessage *message,
138 struct wpa_supplicant *wpa_s)
140 wpas_p2p_stop_find(wpa_s);
145 DBusMessage * wpas_dbus_handler_p2p_rejectpeer(DBusMessage *message,
146 struct wpa_supplicant *wpa_s)
148 DBusMessageIter iter;
149 char *peer_object_path = NULL;
150 u8 peer_addr[ETH_ALEN];
152 dbus_message_iter_init(message, &iter);
153 dbus_message_iter_get_basic(&iter, &peer_object_path);
155 if (parse_peer_object_path(peer_object_path, peer_addr) < 0)
156 return wpas_dbus_error_invalid_args(message, NULL);
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.");
166 DBusMessage * wpas_dbus_handler_p2p_listen(DBusMessage *message,
167 struct wpa_supplicant *wpa_s)
169 dbus_int32_t timeout = 0;
171 if (!dbus_message_get_args(message, NULL, DBUS_TYPE_INT32, &timeout,
173 return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
176 if (wpas_p2p_listen(wpa_s, (unsigned int)timeout))
177 return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
184 DBusMessage * wpas_dbus_handler_p2p_extendedlisten(
185 DBusMessage *message, struct wpa_supplicant *wpa_s)
187 unsigned int period = 0, interval = 0;
188 struct wpa_dbus_dict_entry entry;
189 DBusMessageIter iter;
190 DBusMessageIter iter_dict;
192 dbus_message_iter_init(message, &iter);
195 if (!wpa_dbus_dict_open_read(&iter, &iter_dict))
198 while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
199 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
202 if (!os_strcmp(entry.key, "period") &&
203 (entry.type == DBUS_TYPE_INT32))
204 period = entry.uint32_value;
205 else if (!os_strcmp(entry.key, "interval") &&
206 (entry.type == DBUS_TYPE_INT32))
207 interval = entry.uint32_value;
210 wpa_dbus_dict_entry_clear(&entry);
213 if (wpas_p2p_ext_listen(wpa_s, period, interval))
214 return wpas_dbus_error_unknown_error(
215 message, "failed to initiate a p2p_ext_listen.");
220 wpa_dbus_dict_entry_clear(&entry);
222 return wpas_dbus_error_invalid_args(message, entry.key);
226 DBusMessage * wpas_dbus_handler_p2p_presence_request(
227 DBusMessage *message, struct wpa_supplicant *wpa_s)
229 unsigned int dur1 = 0, int1 = 0, dur2 = 0, int2 = 0;
230 struct wpa_dbus_dict_entry entry;
231 DBusMessageIter iter;
232 DBusMessageIter iter_dict;
234 dbus_message_iter_init(message, &iter);
237 if (!wpa_dbus_dict_open_read(&iter, &iter_dict))
240 while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
241 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
244 if (!os_strcmp(entry.key, "duration1") &&
245 (entry.type == DBUS_TYPE_INT32))
246 dur1 = entry.uint32_value;
247 else if (!os_strcmp(entry.key, "interval1") &&
248 entry.type == DBUS_TYPE_INT32)
249 int1 = entry.uint32_value;
250 else if (!os_strcmp(entry.key, "duration2") &&
251 entry.type == DBUS_TYPE_INT32)
252 dur2 = entry.uint32_value;
253 else if (!os_strcmp(entry.key, "interval2") &&
254 entry.type == DBUS_TYPE_INT32)
255 int2 = entry.uint32_value;
259 wpa_dbus_dict_entry_clear(&entry);
261 if (wpas_p2p_presence_req(wpa_s, dur1, int1, dur2, int2) < 0)
262 return wpas_dbus_error_unknown_error(message,
263 "Failed to invoke presence request.");
268 wpa_dbus_dict_entry_clear(&entry);
270 return wpas_dbus_error_invalid_args(message, entry.key);
274 DBusMessage * wpas_dbus_handler_p2p_group_add(DBusMessage *message,
275 struct wpa_supplicant *wpa_s)
277 DBusMessageIter iter_dict;
278 DBusMessage *reply = NULL;
279 DBusMessageIter iter;
280 struct wpa_dbus_dict_entry entry;
281 char *pg_object_path = NULL;
282 int persistent_group = 0;
285 char *net_id_str = NULL;
286 unsigned int group_id = 0;
287 struct wpa_ssid *ssid;
289 dbus_message_iter_init(message, &iter);
291 if (!wpa_dbus_dict_open_read(&iter, &iter_dict))
294 while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
295 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
298 if (!os_strcmp(entry.key, "persistent") &&
299 (entry.type == DBUS_TYPE_BOOLEAN)) {
300 persistent_group = (entry.bool_value == TRUE) ? 1 : 0;
301 } else if (!os_strcmp(entry.key, "frequency") &&
302 (entry.type == DBUS_TYPE_INT32)) {
303 freq = entry.int32_value;
306 } else if (!os_strcmp(entry.key, "persistent_group_object") &&
307 entry.type == DBUS_TYPE_OBJECT_PATH)
308 pg_object_path = os_strdup(entry.str_value);
312 wpa_dbus_dict_entry_clear(&entry);
315 if (pg_object_path != NULL) {
317 * A persistent group Object Path is defined meaning we want
318 * to re-invoke a persistent group.
321 iface = wpas_dbus_new_decompose_object_path(pg_object_path, 1,
324 os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
326 wpas_dbus_error_invalid_args(message,
331 group_id = strtoul(net_id_str, NULL, 10);
332 if (errno == EINVAL) {
333 reply = wpas_dbus_error_invalid_args(
334 message, pg_object_path);
338 /* Get the SSID structure form the persistant group id */
339 ssid = wpa_config_get_network(wpa_s->conf, group_id);
340 if (ssid == NULL || ssid->disabled != 2)
343 if (wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq)) {
344 reply = wpas_dbus_error_unknown_error(
346 "Failed to reinvoke a persistent group");
349 } else if (wpas_p2p_group_add(wpa_s, persistent_group, freq))
353 os_free(pg_object_path);
358 wpa_dbus_dict_entry_clear(&entry);
360 reply = wpas_dbus_error_invalid_args(message, NULL);
365 DBusMessage * wpas_dbus_handler_p2p_disconnect(DBusMessage *message,
366 struct wpa_supplicant *wpa_s)
368 if (wpas_p2p_disconnect(wpa_s))
369 return wpas_dbus_error_unknown_error(message,
370 "failed to disconnect");
376 DBusMessage * wpas_dbus_handler_p2p_flush(DBusMessage *message,
377 struct wpa_supplicant *wpa_s)
379 os_memset(wpa_s->p2p_auth_invite, 0, ETH_ALEN);
380 wpa_s->force_long_sd = 0;
381 p2p_flush(wpa_s->global->p2p);
387 DBusMessage * wpas_dbus_handler_p2p_connect(DBusMessage *message,
388 struct wpa_supplicant *wpa_s)
390 DBusMessageIter iter_dict;
391 DBusMessage *reply = NULL;
392 DBusMessageIter iter;
393 struct wpa_dbus_dict_entry entry;
394 char *peer_object_path = NULL;
395 int persistent_group = 0;
397 int authorize_only = 0;
402 enum p2p_wps_method wps_method = WPS_NOT_READY;
404 char *err_msg = NULL;
407 dbus_message_iter_init(message, &iter);
409 if (!wpa_dbus_dict_open_read(&iter, &iter_dict))
412 while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
413 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
416 if (!os_strcmp(entry.key, "peer") &&
417 (entry.type == DBUS_TYPE_OBJECT_PATH)) {
418 peer_object_path = os_strdup(entry.str_value);
419 } else if (!os_strcmp(entry.key, "persistent") &&
420 (entry.type == DBUS_TYPE_BOOLEAN)) {
421 persistent_group = (entry.bool_value == TRUE) ? 1 : 0;
422 } else if (!os_strcmp(entry.key, "join") &&
423 (entry.type == DBUS_TYPE_BOOLEAN)) {
424 join = (entry.bool_value == TRUE) ? 1 : 0;
425 } else if (!os_strcmp(entry.key, "authorize_only") &&
426 (entry.type == DBUS_TYPE_BOOLEAN)) {
427 authorize_only = (entry.bool_value == TRUE) ? 1 : 0;
428 } else if (!os_strcmp(entry.key, "frequency") &&
429 (entry.type == DBUS_TYPE_INT32)) {
430 freq = entry.int32_value;
433 } else if (!os_strcmp(entry.key, "go_intent") &&
434 (entry.type == DBUS_TYPE_INT32)) {
435 go_intent = entry.int32_value;
436 if ((go_intent < 0) || (go_intent > 15))
438 } else if (!os_strcmp(entry.key, "wps_method") &&
439 (entry.type == DBUS_TYPE_STRING)) {
440 if (!os_strcmp(entry.str_value, "pbc"))
441 wps_method = WPS_PBC;
442 else if (!os_strcmp(entry.str_value, "pin"))
443 wps_method = WPS_PIN_DISPLAY;
444 else if (!os_strcmp(entry.str_value, "label"))
445 wps_method = WPS_PIN_LABEL;
446 else if (!os_strcmp(entry.str_value, "display"))
447 wps_method = WPS_PIN_DISPLAY;
448 else if (!os_strcmp(entry.str_value, "keypad"))
449 wps_method = WPS_PIN_KEYPAD;
452 } else if (!os_strcmp(entry.key, "pin") &&
453 (entry.type == DBUS_TYPE_STRING)) {
454 pin = os_strdup(entry.str_value);
458 wpa_dbus_dict_entry_clear(&entry);
461 if (!peer_object_path || (wps_method == WPS_NOT_READY) ||
462 (parse_peer_object_path(peer_object_path, addr) < 0) ||
463 (p2p_get_peer_info(wpa_s->global->p2p, addr, 0, NULL, 0) < 0))
467 * Validate the wps_method specified and the pin value.
469 if ((!pin || !pin[0]) &&
470 ((wps_method == WPS_PIN_LABEL) || (wps_method == WPS_PIN_KEYPAD)))
473 new_pin = wpas_p2p_connect(wpa_s, addr, pin, wps_method,
474 persistent_group, join, authorize_only,
478 reply = dbus_message_new_method_return(message);
479 dbus_message_append_args(reply, DBUS_TYPE_INT32,
480 &new_pin, DBUS_TYPE_INVALID);
484 err_msg = "connect failed due to channel "
486 iface = WPAS_DBUS_ERROR_CONNECT_CHANNEL_UNAVAILABLE;
490 err_msg = "connect failed due to unsupported channel.";
491 iface = WPAS_DBUS_ERROR_CONNECT_CHANNEL_UNSUPPORTED;
495 err_msg = "connect failed due to unspecified error.";
496 iface = WPAS_DBUS_ERROR_CONNECT_UNSPECIFIED_ERROR;
502 * Do we need specialized errors corresponding to above
503 * error conditions as against just returning a different
506 reply = dbus_message_new_error(message, iface, err_msg);
510 os_free(peer_object_path);
514 wpa_dbus_dict_entry_clear(&entry);
516 reply = wpas_dbus_error_invalid_args(message, NULL);
521 DBusMessage * wpas_dbus_handler_p2p_invite(DBusMessage *message,
522 struct wpa_supplicant *wpa_s)
524 DBusMessageIter iter_dict;
525 DBusMessage *reply = NULL;
526 DBusMessageIter iter;
527 struct wpa_dbus_dict_entry entry;
528 char *peer_object_path = NULL;
529 char *pg_object_path = NULL;
531 char *net_id_str = NULL;
532 u8 peer_addr[ETH_ALEN];
533 unsigned int group_id = 0;
535 struct wpa_ssid *ssid;
537 dbus_message_iter_init(message, &iter);
539 if (!wpa_dbus_dict_open_read(&iter, &iter_dict))
542 while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
543 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
546 if (!os_strcmp(entry.key, "peer") &&
547 (entry.type == DBUS_TYPE_OBJECT_PATH)) {
548 peer_object_path = os_strdup(entry.str_value);
549 wpa_dbus_dict_entry_clear(&entry);
550 } else if (!os_strcmp(entry.key, "persistent_group_object") &&
551 (entry.type == DBUS_TYPE_OBJECT_PATH)) {
552 pg_object_path = os_strdup(entry.str_value);
554 wpa_dbus_dict_entry_clear(&entry);
556 wpa_dbus_dict_entry_clear(&entry);
561 if (!peer_object_path ||
562 (parse_peer_object_path(peer_object_path, peer_addr) < 0) ||
563 (p2p_get_peer_info(wpa_s->global->p2p,
564 peer_addr, 0, NULL, 0) < 0)) {
570 * A group ID is defined meaning we want to re-invoke a
574 iface = wpas_dbus_new_decompose_object_path(pg_object_path, 1,
577 os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
578 reply = wpas_dbus_error_invalid_args(message,
583 group_id = strtoul(net_id_str, NULL, 10);
584 if (errno == EINVAL) {
585 reply = wpas_dbus_error_invalid_args(
586 message, pg_object_path);
590 /* Get the SSID structure form the persistant group id */
591 ssid = wpa_config_get_network(wpa_s->conf, group_id);
592 if (ssid == NULL || ssid->disabled != 2)
595 if (wpas_p2p_invite(wpa_s, peer_addr, ssid, NULL) < 0) {
596 reply = wpas_dbus_error_unknown_error(
598 "Failed to reinvoke a persistent group");
603 * No group ID means propose to a peer to join my active group
605 if (wpas_p2p_invite_group(wpa_s, wpa_s->ifname,
607 reply = wpas_dbus_error_unknown_error(
608 message, "Failed to join to an active group");
614 os_free(pg_object_path);
615 os_free(peer_object_path);
619 reply = wpas_dbus_error_invalid_args(message, NULL);
624 DBusMessage * wpas_dbus_handler_p2p_prov_disc_req(DBusMessage *message,
625 struct wpa_supplicant *wpa_s)
627 DBusMessageIter iter;
628 char *peer_object_path = NULL;
629 char *config_method = NULL;
630 u8 peer_addr[ETH_ALEN];
632 dbus_message_iter_init(message, &iter);
633 dbus_message_iter_get_basic(&iter, &peer_object_path);
635 if (parse_peer_object_path(peer_object_path, peer_addr) < 0)
636 return wpas_dbus_error_invalid_args(message, NULL);
638 dbus_message_iter_next(&iter);
639 dbus_message_iter_get_basic(&iter, &config_method);
642 * Validation checks on config_method are being duplicated here
643 * to be able to return invalid args reply since the error code
644 * from p2p module are not granular enough (yet).
646 if (os_strcmp(config_method, "display") &&
647 os_strcmp(config_method, "keypad") &&
648 os_strcmp(config_method, "pbc") &&
649 os_strcmp(config_method, "pushbutton"))
650 return wpas_dbus_error_invalid_args(message, NULL);
652 if (wpas_p2p_prov_disc(wpa_s, peer_addr, config_method) < 0)
653 return wpas_dbus_error_unknown_error(message,
654 "Failed to send provision discovery request");
661 * P2P Device property accessor methods.
664 DBusMessage * wpas_dbus_getter_p2p_device_properties(
665 DBusMessage *message, struct wpa_supplicant *wpa_s)
667 DBusMessage *reply = NULL;
668 DBusMessageIter iter, variant_iter, dict_iter;
669 DBusMessageIter iter_secdev_dict_entry, iter_secdev_dict_val,
670 iter_secdev_dict_array;
671 const char *dev_name;
672 int num_vendor_extensions = 0;
674 const struct wpabuf *vendor_ext[P2P_MAX_WPS_VENDOR_EXT];
677 reply = dbus_message_new(DBUS_MESSAGE_TYPE_SIGNAL);
679 reply = dbus_message_new_method_return(message);
684 dbus_message_iter_init_append(reply, &iter);
686 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT,
687 "a{sv}", &variant_iter) ||
688 !wpa_dbus_dict_open_write(&variant_iter, &dict_iter))
692 dev_name = wpa_s->conf->device_name;
694 !wpa_dbus_dict_append_string(&dict_iter, "DeviceName", dev_name))
697 /* Primary device type */
698 if (!wpa_dbus_dict_append_byte_array(&dict_iter, "PrimaryDeviceType",
699 (char *)wpa_s->conf->device_type,
703 /* Secondary device types */
704 if (wpa_s->conf->num_sec_device_types) {
705 if (!wpa_dbus_dict_begin_array(&dict_iter,
706 "SecondaryDeviceTypes",
707 DBUS_TYPE_ARRAY_AS_STRING
708 DBUS_TYPE_BYTE_AS_STRING,
709 &iter_secdev_dict_entry,
710 &iter_secdev_dict_val,
711 &iter_secdev_dict_array))
714 for (i = 0; i < wpa_s->conf->num_sec_device_types; i++)
715 wpa_dbus_dict_bin_array_add_element(
716 &iter_secdev_dict_array,
717 wpa_s->conf->sec_device_type[i],
720 if (!wpa_dbus_dict_end_array(&dict_iter,
721 &iter_secdev_dict_entry,
722 &iter_secdev_dict_val,
723 &iter_secdev_dict_array))
727 /* Vendor Extensions */
728 for (i = 0; i < P2P_MAX_WPS_VENDOR_EXT; i++) {
729 if (wpa_s->conf->wps_vendor_ext[i] == NULL)
731 vendor_ext[num_vendor_extensions++] =
732 wpa_s->conf->wps_vendor_ext[i];
735 if (num_vendor_extensions &&
736 !wpa_dbus_dict_append_wpabuf_array(&dict_iter,
739 num_vendor_extensions))
743 if (!wpa_dbus_dict_append_uint32(&dict_iter, "GOIntent",
744 wpa_s->conf->p2p_go_intent))
747 /* Persistant Reconnect */
748 if (!wpa_dbus_dict_append_bool(&dict_iter, "PersistantReconnect",
749 wpa_s->conf->persistent_reconnect))
752 /* Listen Reg Class */
753 if (!wpa_dbus_dict_append_uint32(&dict_iter, "ListenRegClass",
754 wpa_s->conf->p2p_listen_reg_class))
758 if (!wpa_dbus_dict_append_uint32(&dict_iter, "ListenChannel",
759 wpa_s->conf->p2p_listen_channel))
763 if (!wpa_dbus_dict_append_uint32(&dict_iter, "OperRegClass",
764 wpa_s->conf->p2p_oper_reg_class))
768 if (!wpa_dbus_dict_append_uint32(&dict_iter, "OperChannel",
769 wpa_s->conf->p2p_oper_channel))
773 if (wpa_s->conf->p2p_ssid_postfix &&
774 !wpa_dbus_dict_append_string(&dict_iter, "SsidPostfix",
775 wpa_s->conf->p2p_ssid_postfix))
779 if (!wpa_dbus_dict_append_bool(&dict_iter, "IntraBss",
780 wpa_s->conf->p2p_intra_bss))
784 if (!wpa_dbus_dict_append_uint32(&dict_iter, "GroupIdle",
785 wpa_s->conf->p2p_group_idle))
788 /* Dissasociation low ack */
789 if (!wpa_dbus_dict_append_uint32(&dict_iter, "disassoc_low_ack",
790 wpa_s->conf->disassoc_low_ack))
793 if (!wpa_dbus_dict_close_write(&variant_iter, &dict_iter) ||
794 !dbus_message_iter_close_container(&iter, &variant_iter))
799 dbus_message_unref(reply);
800 return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL);
804 DBusMessage * wpas_dbus_setter_p2p_device_properties(
805 DBusMessage *message, struct wpa_supplicant *wpa_s)
807 DBusMessage *reply = NULL;
808 DBusMessageIter iter, variant_iter;
809 struct wpa_dbus_dict_entry entry = {.type = DBUS_TYPE_STRING };
810 DBusMessageIter iter_dict;
813 dbus_message_iter_init(message, &iter);
815 dbus_message_iter_next(&iter);
816 dbus_message_iter_next(&iter);
818 dbus_message_iter_recurse(&iter, &variant_iter);
820 if (!wpa_dbus_dict_open_read(&variant_iter, &iter_dict))
821 return wpas_dbus_error_invalid_args(message, NULL);
823 while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
824 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
825 return wpas_dbus_error_invalid_args(message, NULL);
827 if (os_strcmp(entry.key, "DeviceName") == 0) {
830 if (entry.type != DBUS_TYPE_STRING)
833 devname = os_strdup(entry.str_value);
835 goto err_no_mem_clear;
837 os_free(wpa_s->conf->device_name);
838 wpa_s->conf->device_name = devname;
840 wpa_s->conf->changed_parameters |=
841 CFG_CHANGED_DEVICE_NAME;
842 } else if (os_strcmp(entry.key, "PrimaryDeviceType") == 0) {
843 if (entry.type != DBUS_TYPE_ARRAY ||
844 entry.array_type != DBUS_TYPE_BYTE ||
845 entry.array_len != WPS_DEV_TYPE_LEN)
848 os_memcpy(wpa_s->conf->device_type,
849 entry.bytearray_value,
851 wpa_s->conf->changed_parameters |=
852 CFG_CHANGED_DEVICE_TYPE;
853 } else if (os_strcmp(entry.key, "SecondaryDeviceTypes") == 0) {
854 if (entry.type != DBUS_TYPE_ARRAY ||
855 entry.array_type != WPAS_DBUS_TYPE_BINARRAY ||
856 entry.array_len > MAX_SEC_DEVICE_TYPES)
859 for (i = 0; i < entry.array_len; i++)
860 if (wpabuf_len(entry.binarray_value[i]) !=
862 goto err_no_mem_clear;
863 for (i = 0; i < entry.array_len; i++)
864 os_memcpy(wpa_s->conf->sec_device_type[i],
865 wpabuf_head(entry.binarray_value[i]),
867 wpa_s->conf->num_sec_device_types = entry.array_len;
868 wpa_s->conf->changed_parameters |=
869 CFG_CHANGED_SEC_DEVICE_TYPE;
870 } else if (os_strcmp(entry.key, "VendorExtension") == 0) {
871 if ((entry.type != DBUS_TYPE_ARRAY) ||
872 (entry.array_type != WPAS_DBUS_TYPE_BINARRAY) ||
873 (entry.array_len > P2P_MAX_WPS_VENDOR_EXT))
876 wpa_s->conf->changed_parameters |=
877 CFG_CHANGED_VENDOR_EXTENSION;
879 for (i = 0; i < P2P_MAX_WPS_VENDOR_EXT; i++) {
880 wpabuf_free(wpa_s->conf->wps_vendor_ext[i]);
881 if (i < entry.array_len) {
882 wpa_s->conf->wps_vendor_ext[i] =
883 entry.binarray_value[i];
884 entry.binarray_value[i] = NULL;
886 wpa_s->conf->wps_vendor_ext[i] = NULL;
888 } else if ((os_strcmp(entry.key, "GOIntent") == 0) &&
889 (entry.type == DBUS_TYPE_UINT32) &&
890 (entry.uint32_value <= 15))
891 wpa_s->conf->p2p_go_intent = entry.uint32_value;
892 else if ((os_strcmp(entry.key, "PersistantReconnect") == 0) &&
893 (entry.type == DBUS_TYPE_BOOLEAN))
894 wpa_s->conf->persistent_reconnect = entry.bool_value;
895 else if ((os_strcmp(entry.key, "ListenRegClass") == 0) &&
896 (entry.type == DBUS_TYPE_UINT32)) {
897 wpa_s->conf->p2p_listen_reg_class = entry.uint32_value;
898 wpa_s->conf->changed_parameters |=
899 CFG_CHANGED_P2P_LISTEN_CHANNEL;
900 } else if ((os_strcmp(entry.key, "ListenChannel") == 0) &&
901 (entry.type == DBUS_TYPE_UINT32)) {
902 wpa_s->conf->p2p_listen_channel = entry.uint32_value;
903 wpa_s->conf->changed_parameters |=
904 CFG_CHANGED_P2P_LISTEN_CHANNEL;
905 } else if ((os_strcmp(entry.key, "OperRegClass") == 0) &&
906 (entry.type == DBUS_TYPE_UINT32)) {
907 wpa_s->conf->p2p_oper_reg_class = entry.uint32_value;
908 wpa_s->conf->changed_parameters |=
909 CFG_CHANGED_P2P_OPER_CHANNEL;
910 } else if ((os_strcmp(entry.key, "OperChannel") == 0) &&
911 (entry.type == DBUS_TYPE_UINT32)) {
912 wpa_s->conf->p2p_oper_channel = entry.uint32_value;
913 wpa_s->conf->changed_parameters |=
914 CFG_CHANGED_P2P_OPER_CHANNEL;
915 } else if (os_strcmp(entry.key, "SsidPostfix") == 0) {
918 if (entry.type != DBUS_TYPE_STRING)
921 postfix = os_strdup(entry.str_value);
923 goto err_no_mem_clear;
925 os_free(wpa_s->conf->p2p_ssid_postfix);
926 wpa_s->conf->p2p_ssid_postfix = postfix;
928 wpa_s->conf->changed_parameters |=
929 CFG_CHANGED_P2P_SSID_POSTFIX;
930 } else if ((os_strcmp(entry.key, "IntraBss") == 0) &&
931 (entry.type == DBUS_TYPE_BOOLEAN)) {
932 wpa_s->conf->p2p_intra_bss = entry.bool_value;
933 wpa_s->conf->changed_parameters |=
934 CFG_CHANGED_P2P_INTRA_BSS;
935 } else if ((os_strcmp(entry.key, "GroupIdle") == 0) &&
936 (entry.type == DBUS_TYPE_UINT32))
937 wpa_s->conf->p2p_group_idle = entry.uint32_value;
938 else if (os_strcmp(entry.key, "disassoc_low_ack") == 0 &&
939 entry.type == DBUS_TYPE_UINT32)
940 wpa_s->conf->disassoc_low_ack = entry.uint32_value;
944 wpa_dbus_dict_entry_clear(&entry);
947 if (wpa_s->conf->changed_parameters) {
948 /* Some changed parameters requires to update config*/
949 wpa_supplicant_update_config(wpa_s);
955 wpa_dbus_dict_entry_clear(&entry);
957 reply = wpas_dbus_error_invalid_args(message, entry.key);
958 wpa_dbus_dict_entry_clear(&entry);
962 wpa_dbus_dict_entry_clear(&entry);
963 return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL);
967 DBusMessage * wpas_dbus_getter_p2p_peers(DBusMessage *message,
968 struct wpa_supplicant *wpa_s)
970 DBusMessage *reply = NULL;
971 struct p2p_data *p2p = wpa_s->global->p2p;
973 int num = 0, out_of_mem = 0;
975 const struct p2p_peer_info *peer_info = NULL;
977 struct dl_list peer_objpath_list;
978 struct peer_objpath_node {
980 char path[WPAS_DBUS_OBJECT_PATH_MAX];
983 char **peer_obj_paths = NULL;
985 dl_list_init(&peer_objpath_list);
987 /* Get the first peer info */
988 peer_info = p2p_get_peer_found(p2p, NULL, next);
990 /* Get next and accumulate them */
992 while (peer_info != NULL) {
993 node = os_zalloc(sizeof(struct peer_objpath_node));
999 addr = peer_info->p2p_device_addr;
1000 os_snprintf(node->path, WPAS_DBUS_OBJECT_PATH_MAX,
1001 "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART
1003 wpa_s->dbus_new_path, MAC2STR(addr));
1004 dl_list_add_tail(&peer_objpath_list, &node->list);
1007 peer_info = p2p_get_peer_found(p2p, addr, next);
1011 * Now construct the peer object paths in a form suitable for
1012 * array_property_getter helper below.
1014 peer_obj_paths = os_zalloc(num * sizeof(char *));
1016 if (!peer_obj_paths) {
1021 dl_list_for_each_safe(node, tmp, &peer_objpath_list,
1022 struct peer_objpath_node, list)
1023 peer_obj_paths[i++] = node->path;
1025 reply = wpas_dbus_simple_array_property_getter(message,
1026 DBUS_TYPE_OBJECT_PATH,
1027 peer_obj_paths, num);
1031 os_free(peer_obj_paths);
1033 dl_list_for_each_safe(node, tmp, &peer_objpath_list,
1034 struct peer_objpath_node, list) {
1035 dl_list_del(&node->list);
1039 reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
1046 enum wpas_p2p_role {
1047 WPAS_P2P_ROLE_DEVICE,
1049 WPAS_P2P_ROLE_CLIENT,
1052 static enum wpas_p2p_role wpas_get_p2p_role(struct wpa_supplicant *wpa_s)
1054 struct wpa_ssid *ssid = wpa_s->current_ssid;
1057 return WPAS_P2P_ROLE_DEVICE;
1058 if (wpa_s->wpa_state != WPA_COMPLETED)
1059 return WPAS_P2P_ROLE_DEVICE;
1061 switch (ssid->mode) {
1062 case WPAS_MODE_P2P_GO:
1063 case WPAS_MODE_P2P_GROUP_FORMATION:
1064 return WPAS_P2P_ROLE_GO;
1065 case WPAS_MODE_INFRA:
1066 if (ssid->p2p_group)
1067 return WPAS_P2P_ROLE_CLIENT;
1068 return WPAS_P2P_ROLE_DEVICE;
1070 return WPAS_P2P_ROLE_DEVICE;
1075 DBusMessage * wpas_dbus_getter_p2p_role(DBusMessage *message,
1076 struct wpa_supplicant *wpa_s)
1080 switch (wpas_get_p2p_role(wpa_s)) {
1081 case WPAS_P2P_ROLE_GO:
1084 case WPAS_P2P_ROLE_CLIENT:
1091 return wpas_dbus_simple_property_getter(message, DBUS_TYPE_STRING,
1096 DBusMessage * wpas_dbus_getter_p2p_group(DBusMessage *message,
1097 struct wpa_supplicant *wpa_s)
1099 if (wpa_s->dbus_groupobj_path == NULL)
1102 return wpas_dbus_simple_property_getter(message,
1103 DBUS_TYPE_OBJECT_PATH,
1104 &wpa_s->dbus_groupobj_path);
1108 DBusMessage * wpas_dbus_getter_p2p_peergo(DBusMessage *message,
1109 struct wpa_supplicant *wpa_s)
1111 char go_peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path;
1113 if (wpas_get_p2p_role(wpa_s) != WPAS_P2P_ROLE_CLIENT)
1116 os_snprintf(go_peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
1117 "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/" COMPACT_MACSTR,
1118 wpa_s->dbus_new_path, MAC2STR(wpa_s->go_dev_addr));
1119 path = go_peer_obj_path;
1120 return wpas_dbus_simple_property_getter(message,
1121 DBUS_TYPE_OBJECT_PATH, &path);
1126 * Peer object properties accessor methods
1129 DBusMessage * wpas_dbus_getter_p2p_peer_properties(
1130 DBusMessage *message, struct peer_handler_args *peer_args)
1132 DBusMessage *reply = NULL;
1133 DBusMessageIter iter, variant_iter, dict_iter;
1134 const struct p2p_peer_info *info = NULL;
1135 char devtype[WPS_DEV_TYPE_BUFSIZE];
1136 const struct wpabuf *vendor_extension[P2P_MAX_WPS_VENDOR_EXT];
1139 /* get the peer info */
1140 info = p2p_get_peer_found(peer_args->wpa_s->global->p2p,
1141 peer_args->p2p_device_addr, 0);
1145 if (message == NULL)
1146 reply = dbus_message_new(DBUS_MESSAGE_TYPE_SIGNAL);
1148 reply = dbus_message_new_method_return(message);
1153 dbus_message_iter_init_append(reply, &iter);
1154 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT,
1155 "a{sv}", &variant_iter) ||
1156 !wpa_dbus_dict_open_write(&variant_iter, &dict_iter))
1159 /* Fill out the dictionary */
1160 wps_dev_type_bin2str(info->pri_dev_type, devtype, sizeof(devtype));
1161 if (!wpa_dbus_dict_append_string(&dict_iter, "DeviceName",
1164 if (!wpa_dbus_dict_append_string(&dict_iter, "PrimaryDeviceType",
1167 if (!wpa_dbus_dict_append_uint16(&dict_iter, "config_method",
1168 info->config_methods))
1170 if (!wpa_dbus_dict_append_int32(&dict_iter, "level",
1173 if (!wpa_dbus_dict_append_byte(&dict_iter, "devicecapability",
1176 if (!wpa_dbus_dict_append_byte(&dict_iter, "groupcapability",
1180 if (info->wps_sec_dev_type_list_len) {
1181 char *sec_dev_types[MAX_SEC_DEVICE_TYPES];
1182 u8 *sec_dev_type_list = NULL;
1183 char secdevtype[WPS_DEV_TYPE_BUFSIZE];
1184 int num_sec_dev_types = 0;
1186 sec_dev_type_list = os_zalloc(info->wps_sec_dev_type_list_len);
1188 if (sec_dev_type_list == NULL)
1191 os_memcpy(sec_dev_type_list, info->wps_sec_dev_type_list,
1192 info->wps_sec_dev_type_list_len);
1194 for (i = 0; i < MAX_SEC_DEVICE_TYPES &&
1195 i < (int) (info->wps_sec_dev_type_list_len /
1198 sec_dev_types[i] = os_zalloc(sizeof(secdevtype));
1200 if (!sec_dev_types[i] ||
1201 wps_dev_type_bin2str(
1202 &sec_dev_type_list[i * WPS_DEV_TYPE_LEN],
1204 sizeof(secdevtype)) == NULL) {
1206 os_free(sec_dev_types[i]);
1207 os_free(sec_dev_type_list);
1211 num_sec_dev_types++;
1214 os_free(sec_dev_type_list);
1216 if (num_sec_dev_types) {
1217 if (!wpa_dbus_dict_append_string_array(&dict_iter,
1218 "SecondaryDeviceTypes",
1219 (const char **)sec_dev_types,
1220 num_sec_dev_types)) {
1221 for (i = 0; i < num_sec_dev_types; i++)
1222 os_free(sec_dev_types[i]);
1226 for (i = 0; i < num_sec_dev_types; i++)
1227 os_free(sec_dev_types[i]);
1231 /* Add WPS vendor extensions attribute */
1232 for (i = 0, num = 0; i < P2P_MAX_WPS_VENDOR_EXT; i++) {
1233 if (info->wps_vendor_ext[i] == NULL)
1235 vendor_extension[num] = info->wps_vendor_ext[i];
1239 if (!wpa_dbus_dict_append_wpabuf_array(&dict_iter, "VendorExtension",
1240 vendor_extension, num))
1243 if (!wpa_dbus_dict_close_write(&variant_iter, &dict_iter) ||
1244 !dbus_message_iter_close_container(&iter, &variant_iter))
1249 dbus_message_unref(reply);
1250 return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL);
1254 DBusMessage * wpas_dbus_getter_p2p_peer_ies(
1255 DBusMessage *message, struct peer_handler_args *peer_args)
1262 * wpas_dbus_getter_persistent_groups - Get array of peristent group objects
1263 * @message: Pointer to incoming dbus message
1264 * @wpa_s: wpa_supplicant structure for a network interface
1265 * Returns: a dbus message containing an array of all persistent group
1266 * dbus object paths.
1268 * Getter for "Networks" property.
1270 DBusMessage * wpas_dbus_getter_persistent_groups(DBusMessage *message,
1271 struct wpa_supplicant *wpa_s)
1273 DBusMessage *reply = NULL;
1274 struct wpa_ssid *ssid;
1276 unsigned int i = 0, num = 0;
1278 if (wpa_s->conf == NULL) {
1279 wpa_printf(MSG_ERROR, "dbus: %s: "
1280 "An error occurred getting persistent groups list",
1282 return wpas_dbus_error_unknown_error(message, NULL);
1285 for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next)
1286 if (network_is_persistent_group(ssid))
1289 paths = os_zalloc(num * sizeof(char *));
1291 return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
1295 /* Loop through configured networks and append object path of each */
1296 for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
1297 if (!network_is_persistent_group(ssid))
1299 paths[i] = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX);
1300 if (paths[i] == NULL) {
1301 reply = dbus_message_new_error(message,
1302 DBUS_ERROR_NO_MEMORY,
1306 /* Construct the object path for this network. */
1307 os_snprintf(paths[i++], WPAS_DBUS_OBJECT_PATH_MAX,
1308 "%s/" WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART "/%d",
1309 wpa_s->dbus_new_path, ssid->id);
1312 reply = wpas_dbus_simple_array_property_getter(message,
1313 DBUS_TYPE_OBJECT_PATH,
1318 os_free(paths[--i]);
1325 * wpas_dbus_getter_persistent_group_properties - Get options for a persistent
1327 * @message: Pointer to incoming dbus message
1328 * @net: wpa_supplicant structure for a network interface and
1329 * wpa_ssid structure for a configured persistent group (internally network)
1330 * Returns: DBus message with network properties or DBus error on failure
1332 * Getter for "Properties" property of a persistent group.
1334 DBusMessage * wpas_dbus_getter_persistent_group_properties(
1335 DBusMessage *message, struct network_handler_args *net)
1338 * Leveraging the fact that persistent group object is still
1339 * represented in same manner as network within.
1341 return wpas_dbus_getter_network_properties(message, net);
1346 * wpas_dbus_setter_persistent_group_properties - Get options for a persistent
1348 * @message: Pointer to incoming dbus message
1349 * @net: wpa_supplicant structure for a network interface and
1350 * wpa_ssid structure for a configured persistent group (internally network)
1351 * Returns: DBus message with network properties or DBus error on failure
1353 * Setter for "Properties" property of a persistent group.
1355 DBusMessage * wpas_dbus_setter_persistent_group_properties(
1356 DBusMessage *message, struct network_handler_args *net)
1358 struct wpa_ssid *ssid = net->ssid;
1359 DBusMessage *reply = NULL;
1360 DBusMessageIter iter, variant_iter;
1362 dbus_message_iter_init(message, &iter);
1364 dbus_message_iter_next(&iter);
1365 dbus_message_iter_next(&iter);
1367 dbus_message_iter_recurse(&iter, &variant_iter);
1370 * Leveraging the fact that persistent group object is still
1371 * represented in same manner as network within.
1373 reply = set_network_properties(message, net->wpa_s, ssid,
1376 wpa_printf(MSG_DEBUG, "dbus control interface couldn't set "
1377 "persistent group properties");
1384 * wpas_dbus_new_iface_add_persistent_group - Add a new configured
1386 * @message: Pointer to incoming dbus message
1387 * @wpa_s: wpa_supplicant structure for a network interface
1388 * Returns: A dbus message containing the object path of the new
1391 * Handler function for "AddPersistentGroup" method call of a P2P Device
1394 DBusMessage * wpas_dbus_handler_add_persistent_group(
1395 DBusMessage *message, struct wpa_supplicant *wpa_s)
1397 DBusMessage *reply = NULL;
1398 DBusMessageIter iter;
1399 struct wpa_ssid *ssid = NULL;
1400 char path_buf[WPAS_DBUS_OBJECT_PATH_MAX], *path = path_buf;
1402 dbus_message_iter_init(message, &iter);
1404 ssid = wpa_config_add_network(wpa_s->conf);
1406 wpa_printf(MSG_ERROR, "dbus: %s: "
1407 "Cannot add new persistent group", __func__);
1408 reply = wpas_dbus_error_unknown_error(
1410 "wpa_supplicant could not add "
1411 "a persistent group on this interface.");
1415 /* Mark the ssid as being a persistent group before the notification */
1417 ssid->p2p_persistent_group = 1;
1418 wpas_notify_persistent_group_added(wpa_s, ssid);
1420 wpa_config_set_network_defaults(ssid);
1422 reply = set_network_properties(message, wpa_s, ssid, &iter);
1424 wpa_printf(MSG_DEBUG, "dbus: %s: "
1425 "Control interface could not set persistent group "
1426 "properties", __func__);
1430 /* Construct the object path for this network. */
1431 os_snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX,
1432 "%s/" WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART "/%d",
1433 wpa_s->dbus_new_path, ssid->id);
1435 reply = dbus_message_new_method_return(message);
1436 if (reply == NULL) {
1437 reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
1441 if (!dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &path,
1442 DBUS_TYPE_INVALID)) {
1443 dbus_message_unref(reply);
1444 reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
1453 wpas_notify_persistent_group_removed(wpa_s, ssid);
1454 wpa_config_remove_network(wpa_s->conf, ssid->id);
1461 * wpas_dbus_handler_remove_persistent_group - Remove a configured persistent
1463 * @message: Pointer to incoming dbus message
1464 * @wpa_s: wpa_supplicant structure for a network interface
1465 * Returns: NULL on success or dbus error on failure
1467 * Handler function for "RemovePersistentGroup" method call of a P2P Device
1470 DBusMessage * wpas_dbus_handler_remove_persistent_group(
1471 DBusMessage *message, struct wpa_supplicant *wpa_s)
1473 DBusMessage *reply = NULL;
1475 char *iface = NULL, *persistent_group_id = NULL;
1477 struct wpa_ssid *ssid;
1479 dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &op,
1483 * Extract the network ID and ensure the network is actually a child of
1486 iface = wpas_dbus_new_decompose_object_path(op, 1,
1487 &persistent_group_id,
1489 if (iface == NULL || os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
1490 reply = wpas_dbus_error_invalid_args(message, op);
1494 id = strtoul(persistent_group_id, NULL, 10);
1495 if (errno == EINVAL) {
1496 reply = wpas_dbus_error_invalid_args(message, op);
1500 ssid = wpa_config_get_network(wpa_s->conf, id);
1502 reply = wpas_dbus_error_persistent_group_unknown(message);
1506 wpas_notify_persistent_group_removed(wpa_s, ssid);
1508 if (wpa_config_remove_network(wpa_s->conf, id) < 0) {
1509 wpa_printf(MSG_ERROR, "dbus: %s: "
1510 "error occurred when removing persistent group %d",
1512 reply = wpas_dbus_error_unknown_error(
1514 "error removing the specified persistent group on "
1521 os_free(persistent_group_id);
1526 static void remove_persistent_group(struct wpa_supplicant *wpa_s,
1527 struct wpa_ssid *ssid)
1529 wpas_notify_persistent_group_removed(wpa_s, ssid);
1531 if (wpa_config_remove_network(wpa_s->conf, ssid->id) < 0) {
1532 wpa_printf(MSG_ERROR, "dbus: %s: "
1533 "error occurred when removing persistent group %d",
1534 __func__, ssid->id);
1541 * wpas_dbus_handler_remove_all_persistent_groups - Remove all configured
1543 * @message: Pointer to incoming dbus message
1544 * @wpa_s: wpa_supplicant structure for a network interface
1545 * Returns: NULL on success or dbus error on failure
1547 * Handler function for "RemoveAllPersistentGroups" method call of a
1548 * P2P Device interface.
1550 DBusMessage * wpas_dbus_handler_remove_all_persistent_groups(
1551 DBusMessage *message, struct wpa_supplicant *wpa_s)
1553 struct wpa_ssid *ssid, *next;
1554 struct wpa_config *config;
1556 config = wpa_s->conf;
1557 ssid = config->ssid;
1560 if (network_is_persistent_group(ssid))
1561 remove_persistent_group(wpa_s, ssid);
1569 * Group object properties accessor methods
1572 DBusMessage * wpas_dbus_getter_p2p_group_members(DBusMessage *message,
1573 struct wpa_supplicant *wpa_s)
1575 DBusMessage *reply = NULL;
1576 struct wpa_ssid *ssid;
1577 unsigned int num_members;
1583 /* Ensure we are a GO */
1584 if (wpa_s->wpa_state != WPA_COMPLETED)
1587 ssid = wpa_s->conf->ssid;
1588 /* At present WPAS P2P_GO mode only applicable for p2p_go */
1589 if (ssid->mode != WPAS_MODE_P2P_GO &&
1590 ssid->mode != WPAS_MODE_AP &&
1591 ssid->mode != WPAS_MODE_P2P_GROUP_FORMATION)
1594 num_members = p2p_get_group_num_members(wpa_s->p2p_group);
1596 paths = os_zalloc(num_members * sizeof(char *));
1601 while ((addr = p2p_iterate_group_members(wpa_s->p2p_group, &next))) {
1602 paths[i] = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX);
1605 os_snprintf(paths[i], WPAS_DBUS_OBJECT_PATH_MAX,
1606 "%s/" WPAS_DBUS_NEW_P2P_GROUPMEMBERS_PART
1608 wpa_s->dbus_groupobj_path, MAC2STR(addr));
1612 reply = wpas_dbus_simple_array_property_getter(message,
1613 DBUS_TYPE_OBJECT_PATH,
1614 paths, num_members);
1616 for (i = 0; i < num_members; i++)
1622 reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL);
1624 for (i = 0; i < num_members; i++)
1632 DBusMessage * wpas_dbus_getter_p2p_group_properties(
1633 DBusMessage *message, struct wpa_supplicant *wpa_s)
1635 DBusMessage *reply = NULL;
1636 DBusMessageIter iter, variant_iter, dict_iter;
1637 struct hostapd_data *hapd = wpa_s->ap_iface->bss[0];
1638 const struct wpabuf *vendor_ext[MAX_WPS_VENDOR_EXTENSIONS];
1639 int num_vendor_ext = 0;
1643 reply = dbus_message_new_error(message, DBUS_ERROR_FAILED,
1648 if (message == NULL)
1649 reply = dbus_message_new(DBUS_MESSAGE_TYPE_SIGNAL);
1651 reply = dbus_message_new_method_return(message);
1656 dbus_message_iter_init_append(reply, &iter);
1658 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT,
1659 "a{sv}", &variant_iter) ||
1660 !wpa_dbus_dict_open_write(&variant_iter, &dict_iter))
1663 /* Parse WPS Vendor Extensions sent in Beacon/Probe Response */
1664 for (i = 0; i < MAX_WPS_VENDOR_EXTENSIONS; i++) {
1665 if (hapd->conf->wps_vendor_ext[i] == NULL)
1667 vendor_ext[num_vendor_ext++] = hapd->conf->wps_vendor_ext[i];
1670 if (!wpa_dbus_dict_append_wpabuf_array(&dict_iter,
1671 "WPSVendorExtensions",
1672 vendor_ext, num_vendor_ext))
1675 if (!wpa_dbus_dict_close_write(&variant_iter, &dict_iter) ||
1676 !dbus_message_iter_close_container(&iter, &variant_iter))
1682 dbus_message_unref(reply);
1683 return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL);
1687 DBusMessage * wpas_dbus_setter_p2p_group_properties(
1688 DBusMessage *message, struct wpa_supplicant *wpa_s)
1690 DBusMessage *reply = NULL;
1691 DBusMessageIter iter, variant_iter;
1692 struct wpa_dbus_dict_entry entry = { .type = DBUS_TYPE_STRING };
1693 DBusMessageIter iter_dict;
1695 struct hostapd_data *hapd = wpa_s->ap_iface->bss[0];
1700 dbus_message_iter_init(message, &iter);
1702 dbus_message_iter_next(&iter);
1703 dbus_message_iter_next(&iter);
1705 dbus_message_iter_recurse(&iter, &variant_iter);
1707 if (!wpa_dbus_dict_open_read(&variant_iter, &iter_dict))
1708 return wpas_dbus_error_invalid_args(message, NULL);
1710 while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
1711 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) {
1712 reply = wpas_dbus_error_invalid_args(message, NULL);
1716 if (os_strcmp(entry.key, "WPSVendorExtensions") == 0) {
1717 if (entry.type != DBUS_TYPE_ARRAY ||
1718 entry.array_type != WPAS_DBUS_TYPE_BINARRAY ||
1719 entry.array_len > MAX_WPS_VENDOR_EXTENSIONS)
1722 for (i = 0; i < MAX_WPS_VENDOR_EXTENSIONS; i++) {
1723 if (i < entry.array_len) {
1724 hapd->conf->wps_vendor_ext[i] =
1725 entry.binarray_value[i];
1726 entry.binarray_value[i] = NULL;
1728 hapd->conf->wps_vendor_ext[i] = NULL;
1731 hostapd_update_wps(hapd);
1735 wpa_dbus_dict_entry_clear(&entry);
1741 reply = wpas_dbus_error_invalid_args(message, entry.key);
1742 wpa_dbus_dict_entry_clear(&entry);
1748 DBusMessage * wpas_dbus_handler_p2p_add_service(DBusMessage *message,
1749 struct wpa_supplicant *wpa_s)
1751 DBusMessageIter iter_dict;
1752 DBusMessage *reply = NULL;
1753 DBusMessageIter iter;
1754 struct wpa_dbus_dict_entry entry;
1757 char *service = NULL;
1758 struct wpabuf *query = NULL;
1759 struct wpabuf *resp = NULL;
1762 dbus_message_iter_init(message, &iter);
1764 if (!wpa_dbus_dict_open_read(&iter, &iter_dict))
1767 if (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
1768 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
1771 if (!os_strcmp(entry.key, "service_type") &&
1772 (entry.type == DBUS_TYPE_STRING)) {
1773 if (!os_strcmp(entry.str_value, "upnp"))
1775 else if (!os_strcmp(entry.str_value, "bonjour"))
1779 wpa_dbus_dict_entry_clear(&entry);
1784 while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
1785 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
1788 if (!os_strcmp(entry.key, "version") &&
1789 entry.type == DBUS_TYPE_INT32)
1790 version = entry.uint32_value;
1791 else if (!os_strcmp(entry.key, "service") &&
1792 entry.type == DBUS_TYPE_STRING)
1793 service = os_strdup(entry.str_value);
1794 wpa_dbus_dict_entry_clear(&entry);
1796 if (version <= 0 || service == NULL)
1799 if (wpas_p2p_service_add_upnp(wpa_s, version, service) != 0)
1803 } else if (bonjour == 1) {
1804 while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
1805 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
1808 if (!os_strcmp(entry.key, "query")) {
1809 if ((entry.type != DBUS_TYPE_ARRAY) ||
1810 (entry.array_type != DBUS_TYPE_BYTE))
1812 query = wpabuf_alloc_copy(
1813 entry.bytearray_value,
1815 } else if (!os_strcmp(entry.key, "response")) {
1816 if ((entry.type != DBUS_TYPE_ARRAY) ||
1817 (entry.array_type != DBUS_TYPE_BYTE))
1819 resp = wpabuf_alloc_copy(entry.bytearray_value,
1823 wpa_dbus_dict_entry_clear(&entry);
1826 if (query == NULL || resp == NULL)
1829 if (wpas_p2p_service_add_bonjour(wpa_s, query, resp) < 0) {
1839 wpa_dbus_dict_entry_clear(&entry);
1841 return wpas_dbus_error_invalid_args(message, NULL);
1845 DBusMessage * wpas_dbus_handler_p2p_delete_service(
1846 DBusMessage *message, struct wpa_supplicant *wpa_s)
1848 DBusMessageIter iter_dict;
1849 DBusMessage *reply = NULL;
1850 DBusMessageIter iter;
1851 struct wpa_dbus_dict_entry entry;
1855 char *service = NULL;
1856 struct wpabuf *query = NULL;
1859 dbus_message_iter_init(message, &iter);
1861 if (!wpa_dbus_dict_open_read(&iter, &iter_dict))
1864 if (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
1865 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
1868 if (!os_strcmp(entry.key, "service_type") &&
1869 (entry.type == DBUS_TYPE_STRING)) {
1870 if (!os_strcmp(entry.str_value, "upnp"))
1872 else if (!os_strcmp(entry.str_value, "bonjour"))
1876 wpa_dbus_dict_entry_clear(&entry);
1880 while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
1881 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
1883 if (!os_strcmp(entry.key, "version") &&
1884 entry.type == DBUS_TYPE_INT32)
1885 version = entry.uint32_value;
1886 else if (!os_strcmp(entry.key, "service") &&
1887 entry.type == DBUS_TYPE_STRING)
1888 service = os_strdup(entry.str_value);
1892 wpa_dbus_dict_entry_clear(&entry);
1895 if (version <= 0 || service == NULL)
1898 ret = wpas_p2p_service_del_upnp(wpa_s, version, service);
1902 } else if (bonjour == 1) {
1903 while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
1904 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
1907 if (!os_strcmp(entry.key, "query")) {
1908 if ((entry.type != DBUS_TYPE_ARRAY) ||
1909 (entry.array_type != DBUS_TYPE_BYTE))
1911 query = wpabuf_alloc_copy(
1912 entry.bytearray_value,
1917 wpa_dbus_dict_entry_clear(&entry);
1923 ret = wpas_p2p_service_del_bonjour(wpa_s, query);
1932 wpa_dbus_dict_entry_clear(&entry);
1934 return wpas_dbus_error_invalid_args(message, NULL);
1938 DBusMessage * wpas_dbus_handler_p2p_flush_service(DBusMessage *message,
1939 struct wpa_supplicant *wpa_s)
1941 wpas_p2p_service_flush(wpa_s);
1946 DBusMessage * wpas_dbus_handler_p2p_service_sd_req(
1947 DBusMessage *message, struct wpa_supplicant *wpa_s)
1949 DBusMessageIter iter_dict;
1950 DBusMessage *reply = NULL;
1951 DBusMessageIter iter;
1952 struct wpa_dbus_dict_entry entry;
1954 char *service = NULL;
1955 char *peer_object_path = NULL;
1956 struct wpabuf *tlv = NULL;
1961 dbus_message_iter_init(message, &iter);
1963 if (!wpa_dbus_dict_open_read(&iter, &iter_dict))
1966 while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
1967 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
1969 if (!os_strcmp(entry.key, "peer_object") &&
1970 entry.type == DBUS_TYPE_OBJECT_PATH) {
1971 peer_object_path = os_strdup(entry.str_value);
1972 } else if (!os_strcmp(entry.key, "service_type") &&
1973 entry.type == DBUS_TYPE_STRING) {
1974 if (!os_strcmp(entry.str_value, "upnp"))
1978 } else if (!os_strcmp(entry.key, "version") &&
1979 entry.type == DBUS_TYPE_INT32) {
1980 version = entry.uint32_value;
1981 } else if (!os_strcmp(entry.key, "service") &&
1982 entry.type == DBUS_TYPE_STRING) {
1983 service = os_strdup(entry.str_value);
1984 } else if (!os_strcmp(entry.key, "tlv")) {
1985 if (entry.type != DBUS_TYPE_ARRAY ||
1986 entry.array_type != DBUS_TYPE_BYTE)
1988 tlv = wpabuf_alloc_copy(entry.bytearray_value,
1993 wpa_dbus_dict_entry_clear(&entry);
1996 if (!peer_object_path ||
1997 (parse_peer_object_path(peer_object_path, addr) < 0) ||
1998 (p2p_get_peer_info(wpa_s->global->p2p, addr, 0, NULL, 0) < 0))
2002 if (version <= 0 || service == NULL)
2005 ref = (unsigned long) wpas_p2p_sd_request_upnp(wpa_s, addr,
2011 ref = (unsigned long)wpas_p2p_sd_request(wpa_s, addr, tlv);
2016 reply = dbus_message_new_method_return(message);
2017 dbus_message_append_args(reply, DBUS_TYPE_UINT64,
2018 &ref, DBUS_TYPE_INVALID);
2020 reply = wpas_dbus_error_unknown_error(
2021 message, "Unable to send SD request");
2025 os_free(peer_object_path);
2028 wpa_dbus_dict_entry_clear(&entry);
2032 reply = wpas_dbus_error_invalid_args(message, NULL);
2037 DBusMessage * wpas_dbus_handler_p2p_service_sd_res(
2038 DBusMessage *message, struct wpa_supplicant *wpa_s)
2040 DBusMessageIter iter_dict;
2041 DBusMessage *reply = NULL;
2042 DBusMessageIter iter;
2043 struct wpa_dbus_dict_entry entry;
2044 char *peer_object_path = NULL;
2045 struct wpabuf *tlv = NULL;
2050 dbus_message_iter_init(message, &iter);
2052 if (!wpa_dbus_dict_open_read(&iter, &iter_dict))
2055 while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
2056 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
2059 if (!os_strcmp(entry.key, "peer_object") &&
2060 entry.type == DBUS_TYPE_OBJECT_PATH) {
2061 peer_object_path = os_strdup(entry.str_value);
2062 } else if (!os_strcmp(entry.key, "frequency") &&
2063 entry.type == DBUS_TYPE_INT32) {
2064 freq = entry.uint32_value;
2065 } else if (!os_strcmp(entry.key, "dialog_token") &&
2066 entry.type == DBUS_TYPE_UINT32) {
2067 dlg_tok = entry.uint32_value;
2068 } else if (!os_strcmp(entry.key, "tlvs")) {
2069 if (entry.type != DBUS_TYPE_ARRAY ||
2070 entry.array_type != DBUS_TYPE_BYTE)
2072 tlv = wpabuf_alloc_copy(entry.bytearray_value,
2077 wpa_dbus_dict_entry_clear(&entry);
2079 if (!peer_object_path ||
2080 (parse_peer_object_path(peer_object_path, addr) < 0) ||
2081 (p2p_get_peer_info(wpa_s->global->p2p, addr, 0, NULL, 0) < 0))
2087 wpas_p2p_sd_response(wpa_s, freq, addr, (u8) dlg_tok, tlv);
2090 os_free(peer_object_path);
2093 wpa_dbus_dict_entry_clear(&entry);
2095 reply = wpas_dbus_error_invalid_args(message, NULL);
2100 DBusMessage * wpas_dbus_handler_p2p_service_sd_cancel_req(
2101 DBusMessage *message, struct wpa_supplicant *wpa_s)
2103 DBusMessageIter iter;
2106 dbus_message_iter_init(message, &iter);
2107 dbus_message_iter_get_basic(&iter, &req);
2112 if (!wpas_p2p_sd_cancel_request(wpa_s, (void *)(unsigned long) req))
2117 return wpas_dbus_error_invalid_args(message, NULL);
2121 DBusMessage * wpas_dbus_handler_p2p_service_update(
2122 DBusMessage *message, struct wpa_supplicant *wpa_s)
2124 wpas_p2p_sd_service_update(wpa_s);
2129 DBusMessage * wpas_dbus_handler_p2p_serv_disc_external(
2130 DBusMessage *message, struct wpa_supplicant *wpa_s)
2132 DBusMessageIter iter;
2135 dbus_message_iter_init(message, &iter);
2136 dbus_message_iter_get_basic(&iter, &ext);
2138 wpa_s->p2p_sd_over_ctrl_iface = ext;