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 unsigned int searchonly = 0;
82 enum p2p_discovery_type type = P2P_FIND_ONLY_SOCIAL;
83 int num_req_dev_types = 0;
85 u8 *req_dev_types = NULL;
87 dbus_message_iter_init(message, &iter);
90 if (!wpa_dbus_dict_open_read(&iter, &iter_dict))
93 while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
94 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
97 if (!os_strcmp(entry.key, "Timeout") &&
98 (entry.type == DBUS_TYPE_INT32)) {
99 timeout = entry.uint32_value;
100 } else if (!os_strcmp(entry.key, "SearchOnly") &&
101 (entry.type == DBUS_TYPE_BOOLEAN)) {
102 searchonly = (entry.bool_value == TRUE) ? 1 : 0;
103 } else if (os_strcmp(entry.key, "RequestedDeviceTypes") == 0) {
104 if ((entry.type != DBUS_TYPE_ARRAY) ||
105 (entry.array_type != WPAS_DBUS_TYPE_BINARRAY))
109 os_malloc(WPS_DEV_TYPE_LEN * entry.array_len);
113 for (i = 0; i < entry.array_len; i++) {
114 if (wpabuf_len(entry.binarray_value[i]) !=
117 os_memcpy(req_dev_types + i * WPS_DEV_TYPE_LEN,
118 wpabuf_head(entry.binarray_value[i]),
122 num_req_dev_types = entry.array_len;
125 wpa_dbus_dict_entry_clear(&entry);
128 wpas_p2p_find(wpa_s, timeout, type, num_req_dev_types, req_dev_types);
132 os_free(req_dev_types);
133 wpa_dbus_dict_entry_clear(&entry);
135 reply = wpas_dbus_error_invalid_args(message, entry.key);
140 DBusMessage * wpas_dbus_handler_p2p_stop_find(DBusMessage *message,
141 struct wpa_supplicant *wpa_s)
143 wpas_p2p_stop_find(wpa_s);
148 DBusMessage * wpas_dbus_handler_p2p_rejectpeer(DBusMessage *message,
149 struct wpa_supplicant *wpa_s)
151 DBusMessageIter iter;
152 char *peer_object_path = NULL;
153 u8 peer_addr[ETH_ALEN];
155 dbus_message_iter_init(message, &iter);
156 dbus_message_iter_get_basic(&iter, &peer_object_path);
158 if (parse_peer_object_path(peer_object_path, peer_addr) < 0)
159 return wpas_dbus_error_invalid_args(message, NULL);
161 if (wpas_p2p_reject(wpa_s, peer_addr) < 0)
162 return wpas_dbus_error_unknown_error(message,
163 "Failed to call wpas_p2p_reject method.");
169 DBusMessage * wpas_dbus_handler_p2p_listen(DBusMessage *message,
170 struct wpa_supplicant *wpa_s)
172 dbus_int32_t timeout = 0;
174 if (!dbus_message_get_args(message, NULL, DBUS_TYPE_INT32, &timeout,
176 return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
179 if (wpas_p2p_listen(wpa_s, (unsigned int)timeout))
180 return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
187 DBusMessage * wpas_dbus_handler_p2p_extendedlisten(
188 DBusMessage *message, struct wpa_supplicant *wpa_s)
190 unsigned int period = 0, interval = 0;
191 struct wpa_dbus_dict_entry entry;
192 DBusMessageIter iter;
193 DBusMessageIter iter_dict;
195 dbus_message_iter_init(message, &iter);
198 if (!wpa_dbus_dict_open_read(&iter, &iter_dict))
201 while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
202 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
205 if (!os_strcmp(entry.key, "period") &&
206 (entry.type == DBUS_TYPE_INT32))
207 period = entry.uint32_value;
208 else if (!os_strcmp(entry.key, "interval") &&
209 (entry.type == DBUS_TYPE_INT32))
210 interval = entry.uint32_value;
213 wpa_dbus_dict_entry_clear(&entry);
216 if (wpas_p2p_ext_listen(wpa_s, period, interval))
217 return wpas_dbus_error_unknown_error(
218 message, "failed to initiate a p2p_ext_listen.");
223 wpa_dbus_dict_entry_clear(&entry);
225 return wpas_dbus_error_invalid_args(message, entry.key);
229 DBusMessage * wpas_dbus_handler_p2p_presence_request(
230 DBusMessage *message, struct wpa_supplicant *wpa_s)
232 unsigned int dur1 = 0, int1 = 0, dur2 = 0, int2 = 0;
233 struct wpa_dbus_dict_entry entry;
234 DBusMessageIter iter;
235 DBusMessageIter iter_dict;
237 dbus_message_iter_init(message, &iter);
240 if (!wpa_dbus_dict_open_read(&iter, &iter_dict))
243 while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
244 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
247 if (!os_strcmp(entry.key, "duration1") &&
248 (entry.type == DBUS_TYPE_INT32))
249 dur1 = entry.uint32_value;
250 else if (!os_strcmp(entry.key, "interval1") &&
251 entry.type == DBUS_TYPE_INT32)
252 int1 = entry.uint32_value;
253 else if (!os_strcmp(entry.key, "duration2") &&
254 entry.type == DBUS_TYPE_INT32)
255 dur2 = entry.uint32_value;
256 else if (!os_strcmp(entry.key, "interval2") &&
257 entry.type == DBUS_TYPE_INT32)
258 int2 = entry.uint32_value;
262 wpa_dbus_dict_entry_clear(&entry);
264 if (wpas_p2p_presence_req(wpa_s, dur1, int1, dur2, int2) < 0)
265 return wpas_dbus_error_unknown_error(message,
266 "Failed to invoke presence request.");
271 wpa_dbus_dict_entry_clear(&entry);
273 return wpas_dbus_error_invalid_args(message, entry.key);
277 DBusMessage * wpas_dbus_handler_p2p_group_add(DBusMessage *message,
278 struct wpa_supplicant *wpa_s)
280 DBusMessageIter iter_dict;
281 DBusMessage *reply = NULL;
282 DBusMessageIter iter;
283 struct wpa_dbus_dict_entry entry;
284 char *pg_object_path = NULL;
285 int persistent_group = 0;
288 char *net_id_str = NULL;
289 unsigned int group_id = 0;
290 struct wpa_ssid *ssid;
292 dbus_message_iter_init(message, &iter);
294 if (!wpa_dbus_dict_open_read(&iter, &iter_dict))
297 while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
298 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
301 if (!os_strcmp(entry.key, "persistent") &&
302 (entry.type == DBUS_TYPE_BOOLEAN)) {
303 persistent_group = (entry.bool_value == TRUE) ? 1 : 0;
304 } else if (!os_strcmp(entry.key, "frequency") &&
305 (entry.type == DBUS_TYPE_INT32)) {
306 freq = entry.int32_value;
309 } else if (!os_strcmp(entry.key, "persistent_group_object") &&
310 entry.type == DBUS_TYPE_OBJECT_PATH)
311 pg_object_path = os_strdup(entry.str_value);
315 wpa_dbus_dict_entry_clear(&entry);
318 if (pg_object_path != NULL) {
320 * A persistent group Object Path is defined meaning we want
321 * to re-invoke a persistent group.
324 iface = wpas_dbus_new_decompose_object_path(pg_object_path, 1,
327 os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
329 wpas_dbus_error_invalid_args(message,
334 group_id = strtoul(net_id_str, NULL, 10);
335 if (errno == EINVAL) {
336 reply = wpas_dbus_error_invalid_args(
337 message, pg_object_path);
341 /* Get the SSID structure form the persistant group id */
342 ssid = wpa_config_get_network(wpa_s->conf, group_id);
343 if (ssid == NULL || ssid->disabled != 2)
346 if (wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq)) {
347 reply = wpas_dbus_error_unknown_error(
349 "Failed to reinvoke a persistent group");
352 } else if (wpas_p2p_group_add(wpa_s, persistent_group, freq))
356 os_free(pg_object_path);
361 wpa_dbus_dict_entry_clear(&entry);
363 reply = wpas_dbus_error_invalid_args(message, NULL);
368 DBusMessage * wpas_dbus_handler_p2p_disconnect(DBusMessage *message,
369 struct wpa_supplicant *wpa_s)
371 if (wpas_p2p_disconnect(wpa_s))
372 return wpas_dbus_error_unknown_error(message,
373 "failed to disconnect");
379 DBusMessage * wpas_dbus_handler_p2p_flush(DBusMessage *message,
380 struct wpa_supplicant *wpa_s)
382 os_memset(wpa_s->p2p_auth_invite, 0, ETH_ALEN);
383 wpa_s->force_long_sd = 0;
384 p2p_flush(wpa_s->global->p2p);
390 DBusMessage * wpas_dbus_handler_p2p_connect(DBusMessage *message,
391 struct wpa_supplicant *wpa_s)
393 DBusMessageIter iter_dict;
394 DBusMessage *reply = NULL;
395 DBusMessageIter iter;
396 struct wpa_dbus_dict_entry entry;
397 char *peer_object_path = NULL;
398 int persistent_group = 0;
400 int authorize_only = 0;
405 enum p2p_wps_method wps_method = WPS_NOT_READY;
407 char *err_msg = NULL;
410 dbus_message_iter_init(message, &iter);
412 if (!wpa_dbus_dict_open_read(&iter, &iter_dict))
415 while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
416 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
419 if (!os_strcmp(entry.key, "peer") &&
420 (entry.type == DBUS_TYPE_OBJECT_PATH)) {
421 peer_object_path = os_strdup(entry.str_value);
422 } else if (!os_strcmp(entry.key, "persistent") &&
423 (entry.type == DBUS_TYPE_BOOLEAN)) {
424 persistent_group = (entry.bool_value == TRUE) ? 1 : 0;
425 } else if (!os_strcmp(entry.key, "join") &&
426 (entry.type == DBUS_TYPE_BOOLEAN)) {
427 join = (entry.bool_value == TRUE) ? 1 : 0;
428 } else if (!os_strcmp(entry.key, "authorize_only") &&
429 (entry.type == DBUS_TYPE_BOOLEAN)) {
430 authorize_only = (entry.bool_value == TRUE) ? 1 : 0;
431 } else if (!os_strcmp(entry.key, "frequency") &&
432 (entry.type == DBUS_TYPE_INT32)) {
433 freq = entry.int32_value;
436 } else if (!os_strcmp(entry.key, "go_intent") &&
437 (entry.type == DBUS_TYPE_INT32)) {
438 go_intent = entry.int32_value;
439 if ((go_intent < 0) || (go_intent > 15))
441 } else if (!os_strcmp(entry.key, "wps_method") &&
442 (entry.type == DBUS_TYPE_STRING)) {
443 if (!os_strcmp(entry.str_value, "pbc"))
444 wps_method = WPS_PBC;
445 else if (!os_strcmp(entry.str_value, "pin"))
446 wps_method = WPS_PIN_DISPLAY;
447 else if (!os_strcmp(entry.str_value, "label"))
448 wps_method = WPS_PIN_LABEL;
449 else if (!os_strcmp(entry.str_value, "display"))
450 wps_method = WPS_PIN_DISPLAY;
451 else if (!os_strcmp(entry.str_value, "keypad"))
452 wps_method = WPS_PIN_KEYPAD;
455 } else if (!os_strcmp(entry.key, "pin") &&
456 (entry.type == DBUS_TYPE_STRING)) {
457 pin = os_strdup(entry.str_value);
461 wpa_dbus_dict_entry_clear(&entry);
464 if (!peer_object_path || (wps_method == WPS_NOT_READY) ||
465 (parse_peer_object_path(peer_object_path, addr) < 0) ||
466 (p2p_get_peer_info(wpa_s->global->p2p, addr, 0, NULL, 0) < 0))
470 * Validate the wps_method specified and the pin value.
472 if ((!pin || !pin[0]) &&
473 ((wps_method == WPS_PIN_LABEL) || (wps_method == WPS_PIN_KEYPAD)))
476 new_pin = wpas_p2p_connect(wpa_s, addr, pin, wps_method,
477 persistent_group, join, authorize_only,
481 reply = dbus_message_new_method_return(message);
482 dbus_message_append_args(reply, DBUS_TYPE_INT32,
483 &new_pin, DBUS_TYPE_INVALID);
487 err_msg = "connect failed due to"
488 " channel unavailability.";
489 iface = WPAS_DBUS_ERROR_CONNECT_CHANNEL_UNAVAILABLE;
493 err_msg = "connect failed due to"
494 " unsupported channel.";
495 iface = WPAS_DBUS_ERROR_CONNECT_CHANNEL_UNSUPPORTED;
499 err_msg = "connect failed due to"
500 " unspecified error.";
501 iface = WPAS_DBUS_ERROR_CONNECT_UNSPECIFIED_ERROR;
506 * Do we need specialized errors corresponding to above
507 * error conditions as against just returning a different
510 reply = dbus_message_new_error(message, iface, err_msg);
514 os_free(peer_object_path);
518 wpa_dbus_dict_entry_clear(&entry);
520 reply = wpas_dbus_error_invalid_args(message, NULL);
525 DBusMessage * wpas_dbus_handler_p2p_invite(DBusMessage *message,
526 struct wpa_supplicant *wpa_s)
528 DBusMessageIter iter_dict;
529 DBusMessage *reply = NULL;
530 DBusMessageIter iter;
531 struct wpa_dbus_dict_entry entry;
532 char *peer_object_path = NULL;
533 char *pg_object_path = NULL;
535 char *net_id_str = NULL;
536 u8 peer_addr[ETH_ALEN];
537 unsigned int group_id = 0;
539 struct wpa_ssid *ssid;
541 dbus_message_iter_init(message, &iter);
543 if (!wpa_dbus_dict_open_read(&iter, &iter_dict))
546 while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
547 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
550 if (!os_strcmp(entry.key, "peer") &&
551 (entry.type == DBUS_TYPE_OBJECT_PATH)) {
552 peer_object_path = os_strdup(entry.str_value);
553 wpa_dbus_dict_entry_clear(&entry);
554 } else if (!os_strcmp(entry.key, "persistent_group_object") &&
555 (entry.type == DBUS_TYPE_OBJECT_PATH)) {
556 pg_object_path = os_strdup(entry.str_value);
558 wpa_dbus_dict_entry_clear(&entry);
560 wpa_dbus_dict_entry_clear(&entry);
565 if (!peer_object_path ||
566 (parse_peer_object_path(peer_object_path, peer_addr) < 0) ||
567 (p2p_get_peer_info(wpa_s->global->p2p,
568 peer_addr, 0, NULL, 0) < 0)) {
574 * A group ID is defined meaning we want to re-invoke a
578 iface = wpas_dbus_new_decompose_object_path(pg_object_path, 1,
581 os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
582 reply = wpas_dbus_error_invalid_args(message,
587 group_id = strtoul(net_id_str, NULL, 10);
588 if (errno == EINVAL) {
589 reply = wpas_dbus_error_invalid_args(
590 message, pg_object_path);
594 /* Get the SSID structure form the persistant group id */
595 ssid = wpa_config_get_network(wpa_s->conf, group_id);
596 if (ssid == NULL || ssid->disabled != 2)
599 if (wpas_p2p_invite(wpa_s, peer_addr, ssid, NULL) < 0) {
600 reply = wpas_dbus_error_unknown_error(
602 "Failed to reinvoke a persistent group");
607 * No group ID means propose to a peer to join my active group
609 if (wpas_p2p_invite_group(wpa_s, wpa_s->ifname,
611 reply = wpas_dbus_error_unknown_error(
612 message, "Failed to join to an active group");
618 os_free(pg_object_path);
619 os_free(peer_object_path);
623 reply = wpas_dbus_error_invalid_args(message, NULL);
628 DBusMessage * wpas_dbus_handler_p2p_prov_disc_req(DBusMessage *message,
629 struct wpa_supplicant *wpa_s)
631 DBusMessageIter iter;
632 char *peer_object_path = NULL;
633 char *config_method = NULL;
634 u8 peer_addr[ETH_ALEN];
636 dbus_message_iter_init(message, &iter);
637 dbus_message_iter_get_basic(&iter, &peer_object_path);
639 if (parse_peer_object_path(peer_object_path, peer_addr) < 0)
640 return wpas_dbus_error_invalid_args(message, NULL);
642 dbus_message_iter_next(&iter);
643 dbus_message_iter_get_basic(&iter, &config_method);
646 * Validation checks on config_method are being duplicated here
647 * to be able to return invalid args reply since the error code
648 * from p2p module are not granular enough (yet).
650 if (os_strcmp(config_method, "display") &&
651 os_strcmp(config_method, "keypad") &&
652 os_strcmp(config_method, "pbc") &&
653 os_strcmp(config_method, "pushbutton"))
654 return wpas_dbus_error_invalid_args(message, NULL);
656 if (wpas_p2p_prov_disc(wpa_s, peer_addr, config_method) < 0)
657 return wpas_dbus_error_unknown_error(message,
658 "Failed to send provision discovery request");
665 * P2P Device property accessor methods.
668 DBusMessage * wpas_dbus_getter_p2p_device_properties(
669 DBusMessage *message, struct wpa_supplicant *wpa_s)
671 DBusMessage *reply = NULL;
672 DBusMessageIter iter, variant_iter, dict_iter;
673 DBusMessageIter iter_secdev_dict_entry, iter_secdev_dict_val,
674 iter_secdev_dict_array;
675 const char *dev_name;
676 int num_vendor_extensions = 0;
678 const struct wpabuf *vendor_ext[P2P_MAX_WPS_VENDOR_EXT];
681 reply = dbus_message_new(DBUS_MESSAGE_TYPE_SIGNAL);
683 reply = dbus_message_new_method_return(message);
688 dbus_message_iter_init_append(reply, &iter);
690 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT,
691 "a{sv}", &variant_iter) ||
692 !wpa_dbus_dict_open_write(&variant_iter, &dict_iter))
696 dev_name = wpa_s->conf->device_name;
698 !wpa_dbus_dict_append_string(&dict_iter, "DeviceName", dev_name))
701 /* Primary device type */
702 if (!wpa_dbus_dict_append_byte_array(&dict_iter, "PrimaryDeviceType",
703 (char *)wpa_s->conf->device_type,
707 /* Secondary device types */
708 if (wpa_s->conf->num_sec_device_types) {
709 if (!wpa_dbus_dict_begin_array(&dict_iter,
710 "SecondaryDeviceTypes",
711 DBUS_TYPE_ARRAY_AS_STRING
712 DBUS_TYPE_BYTE_AS_STRING,
713 &iter_secdev_dict_entry,
714 &iter_secdev_dict_val,
715 &iter_secdev_dict_array))
718 for (i = 0; i < wpa_s->conf->num_sec_device_types; i++)
719 wpa_dbus_dict_bin_array_add_element(
720 &iter_secdev_dict_array,
721 wpa_s->conf->sec_device_type[i],
724 if (!wpa_dbus_dict_end_array(&dict_iter,
725 &iter_secdev_dict_entry,
726 &iter_secdev_dict_val,
727 &iter_secdev_dict_array))
731 /* Vendor Extensions */
732 for (i = 0; i < P2P_MAX_WPS_VENDOR_EXT; i++) {
733 if (wpa_s->conf->wps_vendor_ext[i] == NULL)
735 vendor_ext[num_vendor_extensions++] =
736 wpa_s->conf->wps_vendor_ext[i];
739 if (num_vendor_extensions &&
740 !wpa_dbus_dict_append_wpabuf_array(&dict_iter,
743 num_vendor_extensions))
747 if (!wpa_dbus_dict_append_uint32(&dict_iter, "GOIntent",
748 wpa_s->conf->p2p_go_intent))
751 /* Persistant Reconnect */
752 if (!wpa_dbus_dict_append_bool(&dict_iter, "PersistantReconnect",
753 wpa_s->conf->persistent_reconnect))
756 /* Listen Reg Class */
757 if (!wpa_dbus_dict_append_uint32(&dict_iter, "ListenRegClass",
758 wpa_s->conf->p2p_listen_reg_class))
762 if (!wpa_dbus_dict_append_uint32(&dict_iter, "ListenChannel",
763 wpa_s->conf->p2p_listen_channel))
767 if (!wpa_dbus_dict_append_uint32(&dict_iter, "OperRegClass",
768 wpa_s->conf->p2p_oper_reg_class))
772 if (!wpa_dbus_dict_append_uint32(&dict_iter, "OperChannel",
773 wpa_s->conf->p2p_oper_channel))
777 if (wpa_s->conf->p2p_ssid_postfix &&
778 !wpa_dbus_dict_append_string(&dict_iter, "SsidPostfix",
779 wpa_s->conf->p2p_ssid_postfix))
783 if (!wpa_dbus_dict_append_bool(&dict_iter, "IntraBss",
784 wpa_s->conf->p2p_intra_bss))
788 if (!wpa_dbus_dict_append_uint32(&dict_iter, "GroupIdle",
789 wpa_s->conf->p2p_group_idle))
792 /* Dissasociation low ack */
793 if (!wpa_dbus_dict_append_uint32(&dict_iter, "disassoc_low_ack",
794 wpa_s->conf->disassoc_low_ack))
797 if (!wpa_dbus_dict_close_write(&variant_iter, &dict_iter) ||
798 !dbus_message_iter_close_container(&iter, &variant_iter))
803 dbus_message_unref(reply);
804 return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL);
808 DBusMessage * wpas_dbus_setter_p2p_device_properties(
809 DBusMessage *message, struct wpa_supplicant *wpa_s)
811 DBusMessage *reply = NULL;
812 DBusMessageIter iter, variant_iter;
813 struct wpa_dbus_dict_entry entry = {.type = DBUS_TYPE_STRING };
814 DBusMessageIter iter_dict;
817 dbus_message_iter_init(message, &iter);
819 dbus_message_iter_next(&iter);
820 dbus_message_iter_next(&iter);
822 dbus_message_iter_recurse(&iter, &variant_iter);
824 if (!wpa_dbus_dict_open_read(&variant_iter, &iter_dict))
825 return wpas_dbus_error_invalid_args(message, NULL);
827 while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
828 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
829 return wpas_dbus_error_invalid_args(message, NULL);
831 if (os_strcmp(entry.key, "DeviceName") == 0) {
834 if (entry.type != DBUS_TYPE_STRING)
837 devname = os_strdup(entry.str_value);
839 goto err_no_mem_clear;
841 os_free(wpa_s->conf->device_name);
842 wpa_s->conf->device_name = devname;
844 wpa_s->conf->changed_parameters |=
845 CFG_CHANGED_DEVICE_NAME;
846 } else if (os_strcmp(entry.key, "PrimaryDeviceType") == 0) {
847 if (entry.type != DBUS_TYPE_ARRAY ||
848 entry.array_type != DBUS_TYPE_BYTE ||
849 entry.array_len != WPS_DEV_TYPE_LEN)
852 os_memcpy(wpa_s->conf->device_type,
853 entry.bytearray_value,
855 wpa_s->conf->changed_parameters |=
856 CFG_CHANGED_DEVICE_TYPE;
857 } else if (os_strcmp(entry.key, "SecondaryDeviceTypes") == 0) {
858 if (entry.type != DBUS_TYPE_ARRAY ||
859 entry.array_type != WPAS_DBUS_TYPE_BINARRAY ||
860 entry.array_len > MAX_SEC_DEVICE_TYPES)
863 for (i = 0; i < entry.array_len; i++)
864 if (wpabuf_len(entry.binarray_value[i]) !=
866 goto err_no_mem_clear;
867 for (i = 0; i < entry.array_len; i++)
868 os_memcpy(wpa_s->conf->sec_device_type[i],
869 wpabuf_head(entry.binarray_value[i]),
871 wpa_s->conf->num_sec_device_types = entry.array_len;
872 wpa_s->conf->changed_parameters |=
873 CFG_CHANGED_SEC_DEVICE_TYPE;
874 } else if (os_strcmp(entry.key, "VendorExtension") == 0) {
875 if ((entry.type != DBUS_TYPE_ARRAY) ||
876 (entry.array_type != WPAS_DBUS_TYPE_BINARRAY) ||
877 (entry.array_len > P2P_MAX_WPS_VENDOR_EXT))
880 wpa_s->conf->changed_parameters |=
881 CFG_CHANGED_VENDOR_EXTENSION;
883 for (i = 0; i < P2P_MAX_WPS_VENDOR_EXT; i++) {
884 wpabuf_free(wpa_s->conf->wps_vendor_ext[i]);
885 if (i < entry.array_len) {
886 wpa_s->conf->wps_vendor_ext[i] =
887 entry.binarray_value[i];
888 entry.binarray_value[i] = NULL;
890 wpa_s->conf->wps_vendor_ext[i] = NULL;
892 } else if ((os_strcmp(entry.key, "GOIntent") == 0) &&
893 (entry.type == DBUS_TYPE_UINT32) &&
894 (entry.uint32_value <= 15))
895 wpa_s->conf->p2p_go_intent = entry.uint32_value;
896 else if ((os_strcmp(entry.key, "PersistantReconnect") == 0) &&
897 (entry.type == DBUS_TYPE_BOOLEAN))
898 wpa_s->conf->persistent_reconnect = entry.bool_value;
899 else if ((os_strcmp(entry.key, "ListenRegClass") == 0) &&
900 (entry.type == DBUS_TYPE_UINT32)) {
901 wpa_s->conf->p2p_listen_reg_class = entry.uint32_value;
902 wpa_s->conf->changed_parameters |=
903 CFG_CHANGED_P2P_LISTEN_CHANNEL;
904 } else if ((os_strcmp(entry.key, "ListenChannel") == 0) &&
905 (entry.type == DBUS_TYPE_UINT32)) {
906 wpa_s->conf->p2p_listen_channel = entry.uint32_value;
907 wpa_s->conf->changed_parameters |=
908 CFG_CHANGED_P2P_LISTEN_CHANNEL;
909 } else if ((os_strcmp(entry.key, "OperRegClass") == 0) &&
910 (entry.type == DBUS_TYPE_UINT32)) {
911 wpa_s->conf->p2p_oper_reg_class = entry.uint32_value;
912 wpa_s->conf->changed_parameters |=
913 CFG_CHANGED_P2P_OPER_CHANNEL;
914 } else if ((os_strcmp(entry.key, "OperChannel") == 0) &&
915 (entry.type == DBUS_TYPE_UINT32)) {
916 wpa_s->conf->p2p_oper_channel = entry.uint32_value;
917 wpa_s->conf->changed_parameters |=
918 CFG_CHANGED_P2P_OPER_CHANNEL;
919 } else if (os_strcmp(entry.key, "SsidPostfix") == 0) {
922 if (entry.type != DBUS_TYPE_STRING)
925 postfix = os_strdup(entry.str_value);
927 goto err_no_mem_clear;
929 os_free(wpa_s->conf->p2p_ssid_postfix);
930 wpa_s->conf->p2p_ssid_postfix = postfix;
932 wpa_s->conf->changed_parameters |=
933 CFG_CHANGED_P2P_SSID_POSTFIX;
934 } else if ((os_strcmp(entry.key, "IntraBss") == 0) &&
935 (entry.type == DBUS_TYPE_BOOLEAN)) {
936 wpa_s->conf->p2p_intra_bss = entry.bool_value;
937 wpa_s->conf->changed_parameters |=
938 CFG_CHANGED_P2P_INTRA_BSS;
939 } else if ((os_strcmp(entry.key, "GroupIdle") == 0) &&
940 (entry.type == DBUS_TYPE_UINT32))
941 wpa_s->conf->p2p_group_idle = entry.uint32_value;
942 else if (os_strcmp(entry.key, "disassoc_low_ack") == 0 &&
943 entry.type == DBUS_TYPE_UINT32)
944 wpa_s->conf->disassoc_low_ack = entry.uint32_value;
948 wpa_dbus_dict_entry_clear(&entry);
951 if (wpa_s->conf->changed_parameters) {
952 /* Some changed parameters requires to update config*/
953 wpa_supplicant_update_config(wpa_s);
959 wpa_dbus_dict_entry_clear(&entry);
961 reply = wpas_dbus_error_invalid_args(message, entry.key);
962 wpa_dbus_dict_entry_clear(&entry);
966 wpa_dbus_dict_entry_clear(&entry);
967 return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL);
971 DBusMessage * wpas_dbus_getter_p2p_peers(DBusMessage *message,
972 struct wpa_supplicant *wpa_s)
974 DBusMessage *reply = NULL;
975 struct p2p_data *p2p = wpa_s->global->p2p;
977 int num = 0, out_of_mem = 0;
979 const struct p2p_peer_info *peer_info = NULL;
981 struct dl_list peer_objpath_list;
982 struct peer_objpath_node {
984 char path[WPAS_DBUS_OBJECT_PATH_MAX];
987 char **peer_obj_paths = NULL;
989 dl_list_init(&peer_objpath_list);
991 /* Get the first peer info */
992 peer_info = p2p_get_peer_found(p2p, NULL, next);
994 /* Get next and accumulate them */
996 while (peer_info != NULL) {
997 node = os_zalloc(sizeof(struct peer_objpath_node));
1003 addr = peer_info->p2p_device_addr;
1004 os_snprintf(node->path, WPAS_DBUS_OBJECT_PATH_MAX,
1005 "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART
1007 wpa_s->dbus_new_path, MAC2STR(addr));
1008 dl_list_add_tail(&peer_objpath_list, &node->list);
1011 peer_info = p2p_get_peer_found(p2p, addr, next);
1015 * Now construct the peer object paths in a form suitable for
1016 * array_property_getter helper below.
1018 peer_obj_paths = os_zalloc(num * sizeof(char *));
1020 if (!peer_obj_paths) {
1025 dl_list_for_each_safe(node, tmp, &peer_objpath_list,
1026 struct peer_objpath_node, list)
1027 peer_obj_paths[i++] = node->path;
1029 reply = wpas_dbus_simple_array_property_getter(message,
1030 DBUS_TYPE_OBJECT_PATH,
1031 peer_obj_paths, num);
1035 os_free(peer_obj_paths);
1037 dl_list_for_each_safe(node, tmp, &peer_objpath_list,
1038 struct peer_objpath_node, list) {
1039 dl_list_del(&node->list);
1043 reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
1050 enum wpas_p2p_role {
1051 WPAS_P2P_ROLE_DEVICE,
1053 WPAS_P2P_ROLE_CLIENT,
1056 static enum wpas_p2p_role wpas_get_p2p_role(struct wpa_supplicant *wpa_s)
1058 struct wpa_ssid *ssid = wpa_s->current_ssid;
1061 return WPAS_P2P_ROLE_DEVICE;
1062 if (wpa_s->wpa_state != WPA_COMPLETED)
1063 return WPAS_P2P_ROLE_DEVICE;
1065 switch (ssid->mode) {
1066 case WPAS_MODE_P2P_GO:
1067 case WPAS_MODE_P2P_GROUP_FORMATION:
1068 return WPAS_P2P_ROLE_GO;
1069 case WPAS_MODE_INFRA:
1070 if (ssid->p2p_group)
1071 return WPAS_P2P_ROLE_CLIENT;
1072 return WPAS_P2P_ROLE_DEVICE;
1074 return WPAS_P2P_ROLE_DEVICE;
1079 DBusMessage * wpas_dbus_getter_p2p_role(DBusMessage *message,
1080 struct wpa_supplicant *wpa_s)
1084 switch (wpas_get_p2p_role(wpa_s)) {
1085 case WPAS_P2P_ROLE_GO:
1088 case WPAS_P2P_ROLE_CLIENT:
1095 return wpas_dbus_simple_property_getter(message, DBUS_TYPE_STRING,
1100 DBusMessage * wpas_dbus_getter_p2p_group(DBusMessage *message,
1101 struct wpa_supplicant *wpa_s)
1103 if (wpa_s->dbus_groupobj_path == NULL)
1106 return wpas_dbus_simple_property_getter(message,
1107 DBUS_TYPE_OBJECT_PATH,
1108 &wpa_s->dbus_groupobj_path);
1112 DBusMessage * wpas_dbus_getter_p2p_peergo(DBusMessage *message,
1113 struct wpa_supplicant *wpa_s)
1115 char go_peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path;
1117 if (wpas_get_p2p_role(wpa_s) != WPAS_P2P_ROLE_CLIENT)
1120 os_snprintf(go_peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
1121 "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/" COMPACT_MACSTR,
1122 wpa_s->dbus_new_path, MAC2STR(wpa_s->go_dev_addr));
1123 path = go_peer_obj_path;
1124 return wpas_dbus_simple_property_getter(message,
1125 DBUS_TYPE_OBJECT_PATH, &path);
1130 * Peer object properties accessor methods
1133 DBusMessage * wpas_dbus_getter_p2p_peer_properties(
1134 DBusMessage *message, struct peer_handler_args *peer_args)
1136 DBusMessage *reply = NULL;
1137 DBusMessageIter iter, variant_iter, dict_iter;
1138 const struct p2p_peer_info *info = NULL;
1139 char devtype[WPS_DEV_TYPE_BUFSIZE];
1140 const struct wpabuf *vendor_extension[P2P_MAX_WPS_VENDOR_EXT];
1143 /* get the peer info */
1144 info = p2p_get_peer_found(peer_args->wpa_s->global->p2p,
1145 peer_args->p2p_device_addr, 0);
1149 if (message == NULL)
1150 reply = dbus_message_new(DBUS_MESSAGE_TYPE_SIGNAL);
1152 reply = dbus_message_new_method_return(message);
1157 dbus_message_iter_init_append(reply, &iter);
1158 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT,
1159 "a{sv}", &variant_iter) ||
1160 !wpa_dbus_dict_open_write(&variant_iter, &dict_iter))
1163 /* Fill out the dictionary */
1164 wps_dev_type_bin2str(info->pri_dev_type, devtype, sizeof(devtype));
1165 if (!wpa_dbus_dict_append_string(&dict_iter, "DeviceName",
1168 if (!wpa_dbus_dict_append_string(&dict_iter, "PrimaryDeviceType",
1171 if (!wpa_dbus_dict_append_uint16(&dict_iter, "config_method",
1172 info->config_methods))
1174 if (!wpa_dbus_dict_append_int32(&dict_iter, "level",
1177 if (!wpa_dbus_dict_append_byte(&dict_iter, "devicecapability",
1180 if (!wpa_dbus_dict_append_byte(&dict_iter, "groupcapability",
1184 if (info->wps_sec_dev_type_list_len) {
1185 char *sec_dev_types[MAX_SEC_DEVICE_TYPES];
1186 u8 *sec_dev_type_list = NULL;
1187 char secdevtype[WPS_DEV_TYPE_BUFSIZE];
1188 int num_sec_dev_types = 0;
1190 sec_dev_type_list = os_zalloc(info->wps_sec_dev_type_list_len);
1192 if (sec_dev_type_list == NULL)
1195 os_memcpy(sec_dev_type_list, info->wps_sec_dev_type_list,
1196 info->wps_sec_dev_type_list_len);
1198 for (i = 0; i < MAX_SEC_DEVICE_TYPES &&
1199 i < (int) (info->wps_sec_dev_type_list_len /
1202 sec_dev_types[i] = os_zalloc(sizeof(secdevtype));
1204 if (!sec_dev_types[i] ||
1205 wps_dev_type_bin2str(
1206 &sec_dev_type_list[i * WPS_DEV_TYPE_LEN],
1208 sizeof(secdevtype)) == NULL) {
1210 os_free(sec_dev_types[i]);
1211 os_free(sec_dev_type_list);
1215 num_sec_dev_types++;
1218 os_free(sec_dev_type_list);
1220 if (num_sec_dev_types) {
1221 if (!wpa_dbus_dict_append_string_array(&dict_iter,
1222 "SecondaryDeviceTypes",
1223 (const char **)sec_dev_types,
1224 num_sec_dev_types)) {
1225 for (i = 0; i < num_sec_dev_types; i++)
1226 os_free(sec_dev_types[i]);
1230 for (i = 0; i < num_sec_dev_types; i++)
1231 os_free(sec_dev_types[i]);
1235 /* Add WPS vendor extensions attribute */
1236 for (i = 0, num = 0; i < P2P_MAX_WPS_VENDOR_EXT; i++) {
1237 if (info->wps_vendor_ext[i] == NULL)
1239 vendor_extension[num] = info->wps_vendor_ext[i];
1243 if (!wpa_dbus_dict_append_wpabuf_array(&dict_iter, "VendorExtension",
1244 vendor_extension, num))
1247 if (!wpa_dbus_dict_close_write(&variant_iter, &dict_iter) ||
1248 !dbus_message_iter_close_container(&iter, &variant_iter))
1253 dbus_message_unref(reply);
1254 return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL);
1258 DBusMessage * wpas_dbus_getter_p2p_peer_ies(
1259 DBusMessage *message, struct peer_handler_args *peer_args)
1266 * wpas_dbus_getter_persistent_groups - Get array of peristent group objects
1267 * @message: Pointer to incoming dbus message
1268 * @wpa_s: wpa_supplicant structure for a network interface
1269 * Returns: a dbus message containing an array of all persistent group
1270 * dbus object paths.
1272 * Getter for "Networks" property.
1274 DBusMessage * wpas_dbus_getter_persistent_groups(DBusMessage *message,
1275 struct wpa_supplicant *wpa_s)
1277 DBusMessage *reply = NULL;
1278 struct wpa_ssid *ssid;
1280 unsigned int i = 0, num = 0;
1282 if (wpa_s->conf == NULL) {
1283 wpa_printf(MSG_ERROR, "dbus: %s: "
1284 "An error occurred getting persistent groups list",
1286 return wpas_dbus_error_unknown_error(message, NULL);
1289 for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next)
1290 if (network_is_persistent_group(ssid))
1293 paths = os_zalloc(num * sizeof(char *));
1295 return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
1299 /* Loop through configured networks and append object path of each */
1300 for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
1301 if (!network_is_persistent_group(ssid))
1303 paths[i] = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX);
1304 if (paths[i] == NULL) {
1305 reply = dbus_message_new_error(message,
1306 DBUS_ERROR_NO_MEMORY,
1310 /* Construct the object path for this network. */
1311 os_snprintf(paths[i++], WPAS_DBUS_OBJECT_PATH_MAX,
1312 "%s/" WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART "/%d",
1313 wpa_s->dbus_new_path, ssid->id);
1316 reply = wpas_dbus_simple_array_property_getter(message,
1317 DBUS_TYPE_OBJECT_PATH,
1322 os_free(paths[--i]);
1329 * wpas_dbus_getter_persistent_group_properties - Get options for a persistent
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
1336 * Getter for "Properties" property of a persistent group.
1338 DBusMessage * wpas_dbus_getter_persistent_group_properties(
1339 DBusMessage *message, struct network_handler_args *net)
1342 * Leveraging the fact that persistent group object is still
1343 * represented in same manner as network within.
1345 return wpas_dbus_getter_network_properties(message, net);
1350 * wpas_dbus_setter_persistent_group_properties - Get options for a persistent
1352 * @message: Pointer to incoming dbus message
1353 * @net: wpa_supplicant structure for a network interface and
1354 * wpa_ssid structure for a configured persistent group (internally network)
1355 * Returns: DBus message with network properties or DBus error on failure
1357 * Setter for "Properties" property of a persistent group.
1359 DBusMessage * wpas_dbus_setter_persistent_group_properties(
1360 DBusMessage *message, struct network_handler_args *net)
1362 struct wpa_ssid *ssid = net->ssid;
1363 DBusMessage *reply = NULL;
1364 DBusMessageIter iter, variant_iter;
1366 dbus_message_iter_init(message, &iter);
1368 dbus_message_iter_next(&iter);
1369 dbus_message_iter_next(&iter);
1371 dbus_message_iter_recurse(&iter, &variant_iter);
1374 * Leveraging the fact that persistent group object is still
1375 * represented in same manner as network within.
1377 reply = set_network_properties(message, net->wpa_s, ssid,
1380 wpa_printf(MSG_DEBUG, "dbus control interface couldn't set "
1381 "persistent group properties");
1388 * wpas_dbus_new_iface_add_persistent_group - Add a new configured
1390 * @message: Pointer to incoming dbus message
1391 * @wpa_s: wpa_supplicant structure for a network interface
1392 * Returns: A dbus message containing the object path of the new
1395 * Handler function for "AddPersistentGroup" method call of a P2P Device
1398 DBusMessage * wpas_dbus_handler_add_persistent_group(
1399 DBusMessage *message, struct wpa_supplicant *wpa_s)
1401 DBusMessage *reply = NULL;
1402 DBusMessageIter iter;
1403 struct wpa_ssid *ssid = NULL;
1404 char path_buf[WPAS_DBUS_OBJECT_PATH_MAX], *path = path_buf;
1406 dbus_message_iter_init(message, &iter);
1408 ssid = wpa_config_add_network(wpa_s->conf);
1410 wpa_printf(MSG_ERROR, "dbus: %s: "
1411 "Cannot add new persistent group", __func__);
1412 reply = wpas_dbus_error_unknown_error(
1414 "wpa_supplicant could not add "
1415 "a persistent group on this interface.");
1419 /* Mark the ssid as being a persistent group before the notification */
1421 ssid->p2p_persistent_group = 1;
1422 wpas_notify_persistent_group_added(wpa_s, ssid);
1424 wpa_config_set_network_defaults(ssid);
1426 reply = set_network_properties(message, wpa_s, ssid, &iter);
1428 wpa_printf(MSG_DEBUG, "dbus: %s: "
1429 "Control interface could not set persistent group "
1430 "properties", __func__);
1434 /* Construct the object path for this network. */
1435 os_snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX,
1436 "%s/" WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART "/%d",
1437 wpa_s->dbus_new_path, ssid->id);
1439 reply = dbus_message_new_method_return(message);
1440 if (reply == NULL) {
1441 reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
1445 if (!dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &path,
1446 DBUS_TYPE_INVALID)) {
1447 dbus_message_unref(reply);
1448 reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
1457 wpas_notify_persistent_group_removed(wpa_s, ssid);
1458 wpa_config_remove_network(wpa_s->conf, ssid->id);
1465 * wpas_dbus_handler_remove_persistent_group - Remove a configured persistent
1467 * @message: Pointer to incoming dbus message
1468 * @wpa_s: wpa_supplicant structure for a network interface
1469 * Returns: NULL on success or dbus error on failure
1471 * Handler function for "RemovePersistentGroup" method call of a P2P Device
1474 DBusMessage * wpas_dbus_handler_remove_persistent_group(
1475 DBusMessage *message, struct wpa_supplicant *wpa_s)
1477 DBusMessage *reply = NULL;
1479 char *iface = NULL, *persistent_group_id = NULL;
1481 struct wpa_ssid *ssid;
1483 dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &op,
1487 * Extract the network ID and ensure the network is actually a child of
1490 iface = wpas_dbus_new_decompose_object_path(op, 1,
1491 &persistent_group_id,
1493 if (iface == NULL || os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
1494 reply = wpas_dbus_error_invalid_args(message, op);
1498 id = strtoul(persistent_group_id, NULL, 10);
1499 if (errno == EINVAL) {
1500 reply = wpas_dbus_error_invalid_args(message, op);
1504 ssid = wpa_config_get_network(wpa_s->conf, id);
1506 reply = wpas_dbus_error_persistent_group_unknown(message);
1510 wpas_notify_persistent_group_removed(wpa_s, ssid);
1512 if (wpa_config_remove_network(wpa_s->conf, id) < 0) {
1513 wpa_printf(MSG_ERROR, "dbus: %s: "
1514 "error occurred when removing persistent group %d",
1516 reply = wpas_dbus_error_unknown_error(
1518 "error removing the specified persistent group on "
1525 os_free(persistent_group_id);
1530 static void remove_persistent_group(struct wpa_supplicant *wpa_s,
1531 struct wpa_ssid *ssid)
1533 wpas_notify_persistent_group_removed(wpa_s, ssid);
1535 if (wpa_config_remove_network(wpa_s->conf, ssid->id) < 0) {
1536 wpa_printf(MSG_ERROR, "dbus: %s: "
1537 "error occurred when removing persistent group %d",
1538 __func__, ssid->id);
1545 * wpas_dbus_handler_remove_all_persistent_groups - Remove all configured
1547 * @message: Pointer to incoming dbus message
1548 * @wpa_s: wpa_supplicant structure for a network interface
1549 * Returns: NULL on success or dbus error on failure
1551 * Handler function for "RemoveAllPersistentGroups" method call of a
1552 * P2P Device interface.
1554 DBusMessage * wpas_dbus_handler_remove_all_persistent_groups(
1555 DBusMessage *message, struct wpa_supplicant *wpa_s)
1557 struct wpa_ssid *ssid, *next;
1558 struct wpa_config *config;
1560 config = wpa_s->conf;
1561 ssid = config->ssid;
1564 if (network_is_persistent_group(ssid))
1565 remove_persistent_group(wpa_s, ssid);
1573 * Group object properties accessor methods
1576 DBusMessage * wpas_dbus_getter_p2p_group_members(DBusMessage *message,
1577 struct wpa_supplicant *wpa_s)
1579 DBusMessage *reply = NULL;
1580 struct wpa_ssid *ssid;
1581 unsigned int num_members;
1587 /* Ensure we are a GO */
1588 if (wpa_s->wpa_state != WPA_COMPLETED)
1591 ssid = wpa_s->conf->ssid;
1592 /* At present WPAS P2P_GO mode only applicable for p2p_go */
1593 if (ssid->mode != WPAS_MODE_P2P_GO &&
1594 ssid->mode != WPAS_MODE_AP &&
1595 ssid->mode != WPAS_MODE_P2P_GROUP_FORMATION)
1598 num_members = p2p_get_group_num_members(wpa_s->p2p_group);
1600 paths = os_zalloc(num_members * sizeof(char *));
1605 while ((addr = p2p_iterate_group_members(wpa_s->p2p_group, &next))) {
1606 paths[i] = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX);
1609 os_snprintf(paths[i], WPAS_DBUS_OBJECT_PATH_MAX,
1610 "%s/" WPAS_DBUS_NEW_P2P_GROUPMEMBERS_PART
1612 wpa_s->dbus_groupobj_path, MAC2STR(addr));
1616 reply = wpas_dbus_simple_array_property_getter(message,
1617 DBUS_TYPE_OBJECT_PATH,
1618 paths, num_members);
1620 for (i = 0; i < num_members; i++)
1626 reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL);
1628 for (i = 0; i < num_members; i++)
1636 DBusMessage * wpas_dbus_getter_p2p_group_properties(
1637 DBusMessage *message, struct wpa_supplicant *wpa_s)
1639 DBusMessage *reply = NULL;
1640 DBusMessageIter iter, variant_iter, dict_iter;
1641 struct hostapd_data *hapd = wpa_s->ap_iface->bss[0];
1642 const struct wpabuf *vendor_ext[MAX_WPS_VENDOR_EXTENSIONS];
1643 int num_vendor_ext = 0;
1647 reply = dbus_message_new_error(message, DBUS_ERROR_FAILED,
1652 if (message == NULL)
1653 reply = dbus_message_new(DBUS_MESSAGE_TYPE_SIGNAL);
1655 reply = dbus_message_new_method_return(message);
1660 dbus_message_iter_init_append(reply, &iter);
1662 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT,
1663 "a{sv}", &variant_iter) ||
1664 !wpa_dbus_dict_open_write(&variant_iter, &dict_iter))
1667 /* Parse WPS Vendor Extensions sent in Beacon/Probe Response */
1668 for (i = 0; i < MAX_WPS_VENDOR_EXTENSIONS; i++) {
1669 if (hapd->conf->wps_vendor_ext[i] == NULL)
1671 vendor_ext[num_vendor_ext++] = hapd->conf->wps_vendor_ext[i];
1674 if (!wpa_dbus_dict_append_wpabuf_array(&dict_iter,
1675 "WPSVendorExtensions",
1676 vendor_ext, num_vendor_ext))
1679 if (!wpa_dbus_dict_close_write(&variant_iter, &dict_iter) ||
1680 !dbus_message_iter_close_container(&iter, &variant_iter))
1686 dbus_message_unref(reply);
1687 return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL);
1691 DBusMessage * wpas_dbus_setter_p2p_group_properties(
1692 DBusMessage *message, struct wpa_supplicant *wpa_s)
1694 DBusMessage *reply = NULL;
1695 DBusMessageIter iter, variant_iter;
1696 struct wpa_dbus_dict_entry entry = { .type = DBUS_TYPE_STRING };
1697 DBusMessageIter iter_dict;
1699 struct hostapd_data *hapd = wpa_s->ap_iface->bss[0];
1704 dbus_message_iter_init(message, &iter);
1706 dbus_message_iter_next(&iter);
1707 dbus_message_iter_next(&iter);
1709 dbus_message_iter_recurse(&iter, &variant_iter);
1711 if (!wpa_dbus_dict_open_read(&variant_iter, &iter_dict))
1712 return wpas_dbus_error_invalid_args(message, NULL);
1714 while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
1715 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) {
1716 reply = wpas_dbus_error_invalid_args(message, NULL);
1720 if (os_strcmp(entry.key, "WPSVendorExtensions") == 0) {
1721 if (entry.type != DBUS_TYPE_ARRAY ||
1722 entry.array_type != WPAS_DBUS_TYPE_BINARRAY ||
1723 entry.array_len > MAX_WPS_VENDOR_EXTENSIONS)
1726 for (i = 0; i < MAX_WPS_VENDOR_EXTENSIONS; i++) {
1727 if (i < entry.array_len) {
1728 hapd->conf->wps_vendor_ext[i] =
1729 entry.binarray_value[i];
1730 entry.binarray_value[i] = NULL;
1732 hapd->conf->wps_vendor_ext[i] = NULL;
1735 hostapd_update_wps(hapd);
1739 wpa_dbus_dict_entry_clear(&entry);
1745 reply = wpas_dbus_error_invalid_args(message, entry.key);
1746 wpa_dbus_dict_entry_clear(&entry);
1752 DBusMessage * wpas_dbus_handler_p2p_add_service(DBusMessage *message,
1753 struct wpa_supplicant *wpa_s)
1755 DBusMessageIter iter_dict;
1756 DBusMessage *reply = NULL;
1757 DBusMessageIter iter;
1758 struct wpa_dbus_dict_entry entry;
1761 char *service = NULL;
1762 struct wpabuf *query = NULL;
1763 struct wpabuf *resp = NULL;
1766 dbus_message_iter_init(message, &iter);
1768 if (!wpa_dbus_dict_open_read(&iter, &iter_dict))
1771 if (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
1772 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
1775 if (!os_strcmp(entry.key, "service_type") &&
1776 (entry.type == DBUS_TYPE_STRING)) {
1777 if (!os_strcmp(entry.str_value, "upnp"))
1779 else if (!os_strcmp(entry.str_value, "bonjour"))
1783 wpa_dbus_dict_entry_clear(&entry);
1788 while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
1789 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
1792 if (!os_strcmp(entry.key, "version") &&
1793 entry.type == DBUS_TYPE_INT32)
1794 version = entry.uint32_value;
1795 else if (!os_strcmp(entry.key, "service") &&
1796 entry.type == DBUS_TYPE_STRING)
1797 service = os_strdup(entry.str_value);
1798 wpa_dbus_dict_entry_clear(&entry);
1800 if (version <= 0 || service == NULL)
1803 if (wpas_p2p_service_add_upnp(wpa_s, version, service) != 0)
1807 } else if (bonjour == 1) {
1808 while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
1809 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
1812 if (!os_strcmp(entry.key, "query")) {
1813 if ((entry.type != DBUS_TYPE_ARRAY) ||
1814 (entry.array_type != DBUS_TYPE_BYTE))
1816 query = wpabuf_alloc_copy(
1817 entry.bytearray_value,
1819 } else if (!os_strcmp(entry.key, "response")) {
1820 if ((entry.type != DBUS_TYPE_ARRAY) ||
1821 (entry.array_type != DBUS_TYPE_BYTE))
1823 resp = wpabuf_alloc_copy(entry.bytearray_value,
1827 wpa_dbus_dict_entry_clear(&entry);
1830 if (query == NULL || resp == NULL)
1833 if (wpas_p2p_service_add_bonjour(wpa_s, query, resp) < 0) {
1843 wpa_dbus_dict_entry_clear(&entry);
1845 return wpas_dbus_error_invalid_args(message, NULL);
1849 DBusMessage * wpas_dbus_handler_p2p_delete_service(
1850 DBusMessage *message, struct wpa_supplicant *wpa_s)
1852 DBusMessageIter iter_dict;
1853 DBusMessage *reply = NULL;
1854 DBusMessageIter iter;
1855 struct wpa_dbus_dict_entry entry;
1859 char *service = NULL;
1860 struct wpabuf *query = NULL;
1863 dbus_message_iter_init(message, &iter);
1865 if (!wpa_dbus_dict_open_read(&iter, &iter_dict))
1868 if (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
1869 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
1872 if (!os_strcmp(entry.key, "service_type") &&
1873 (entry.type == DBUS_TYPE_STRING)) {
1874 if (!os_strcmp(entry.str_value, "upnp"))
1876 else if (!os_strcmp(entry.str_value, "bonjour"))
1880 wpa_dbus_dict_entry_clear(&entry);
1884 while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
1885 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
1887 if (!os_strcmp(entry.key, "version") &&
1888 entry.type == DBUS_TYPE_INT32)
1889 version = entry.uint32_value;
1890 else if (!os_strcmp(entry.key, "service") &&
1891 entry.type == DBUS_TYPE_STRING)
1892 service = os_strdup(entry.str_value);
1896 wpa_dbus_dict_entry_clear(&entry);
1899 if (version <= 0 || service == NULL)
1902 ret = wpas_p2p_service_del_upnp(wpa_s, version, service);
1906 } else if (bonjour == 1) {
1907 while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
1908 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
1911 if (!os_strcmp(entry.key, "query")) {
1912 if ((entry.type != DBUS_TYPE_ARRAY) ||
1913 (entry.array_type != DBUS_TYPE_BYTE))
1915 query = wpabuf_alloc_copy(
1916 entry.bytearray_value,
1921 wpa_dbus_dict_entry_clear(&entry);
1927 ret = wpas_p2p_service_del_bonjour(wpa_s, query);
1936 wpa_dbus_dict_entry_clear(&entry);
1938 return wpas_dbus_error_invalid_args(message, NULL);
1942 DBusMessage * wpas_dbus_handler_p2p_flush_service(DBusMessage *message,
1943 struct wpa_supplicant *wpa_s)
1945 wpas_p2p_service_flush(wpa_s);
1950 DBusMessage * wpas_dbus_handler_p2p_service_sd_req(
1951 DBusMessage *message, struct wpa_supplicant *wpa_s)
1953 DBusMessageIter iter_dict;
1954 DBusMessage *reply = NULL;
1955 DBusMessageIter iter;
1956 struct wpa_dbus_dict_entry entry;
1958 char *service = NULL;
1959 char *peer_object_path = NULL;
1960 struct wpabuf *tlv = NULL;
1965 dbus_message_iter_init(message, &iter);
1967 if (!wpa_dbus_dict_open_read(&iter, &iter_dict))
1970 while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
1971 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
1973 if (!os_strcmp(entry.key, "peer_object") &&
1974 entry.type == DBUS_TYPE_OBJECT_PATH) {
1975 peer_object_path = os_strdup(entry.str_value);
1976 } else if (!os_strcmp(entry.key, "service_type") &&
1977 entry.type == DBUS_TYPE_STRING) {
1978 if (!os_strcmp(entry.str_value, "upnp"))
1982 } else if (!os_strcmp(entry.key, "version") &&
1983 entry.type == DBUS_TYPE_INT32) {
1984 version = entry.uint32_value;
1985 } else if (!os_strcmp(entry.key, "service") &&
1986 entry.type == DBUS_TYPE_STRING) {
1987 service = os_strdup(entry.str_value);
1988 } else if (!os_strcmp(entry.key, "tlv")) {
1989 if (entry.type != DBUS_TYPE_ARRAY ||
1990 entry.array_type != DBUS_TYPE_BYTE)
1992 tlv = wpabuf_alloc_copy(entry.bytearray_value,
1997 wpa_dbus_dict_entry_clear(&entry);
2000 if (!peer_object_path ||
2001 (parse_peer_object_path(peer_object_path, addr) < 0) ||
2002 (p2p_get_peer_info(wpa_s->global->p2p, addr, 0, NULL, 0) < 0))
2006 if (version <= 0 || service == NULL)
2009 ref = (unsigned long) wpas_p2p_sd_request_upnp(wpa_s, addr,
2015 ref = (unsigned long)wpas_p2p_sd_request(wpa_s, addr, tlv);
2020 reply = dbus_message_new_method_return(message);
2021 dbus_message_append_args(reply, DBUS_TYPE_UINT64,
2022 &ref, DBUS_TYPE_INVALID);
2024 reply = wpas_dbus_error_unknown_error(
2025 message, "Unable to send SD request");
2029 os_free(peer_object_path);
2032 wpa_dbus_dict_entry_clear(&entry);
2036 reply = wpas_dbus_error_invalid_args(message, NULL);
2041 DBusMessage * wpas_dbus_handler_p2p_service_sd_res(
2042 DBusMessage *message, struct wpa_supplicant *wpa_s)
2044 DBusMessageIter iter_dict;
2045 DBusMessage *reply = NULL;
2046 DBusMessageIter iter;
2047 struct wpa_dbus_dict_entry entry;
2048 char *peer_object_path = NULL;
2049 struct wpabuf *tlv = NULL;
2054 dbus_message_iter_init(message, &iter);
2056 if (!wpa_dbus_dict_open_read(&iter, &iter_dict))
2059 while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
2060 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
2063 if (!os_strcmp(entry.key, "peer_object") &&
2064 entry.type == DBUS_TYPE_OBJECT_PATH) {
2065 peer_object_path = os_strdup(entry.str_value);
2066 } else if (!os_strcmp(entry.key, "frequency") &&
2067 entry.type == DBUS_TYPE_INT32) {
2068 freq = entry.uint32_value;
2069 } else if (!os_strcmp(entry.key, "dialog_token") &&
2070 entry.type == DBUS_TYPE_UINT32) {
2071 dlg_tok = entry.uint32_value;
2072 } else if (!os_strcmp(entry.key, "tlvs")) {
2073 if (entry.type != DBUS_TYPE_ARRAY ||
2074 entry.array_type != DBUS_TYPE_BYTE)
2076 tlv = wpabuf_alloc_copy(entry.bytearray_value,
2081 wpa_dbus_dict_entry_clear(&entry);
2083 if (!peer_object_path ||
2084 (parse_peer_object_path(peer_object_path, addr) < 0) ||
2085 (p2p_get_peer_info(wpa_s->global->p2p, addr, 0, NULL, 0) < 0))
2091 wpas_p2p_sd_response(wpa_s, freq, addr, (u8) dlg_tok, tlv);
2094 os_free(peer_object_path);
2097 wpa_dbus_dict_entry_clear(&entry);
2099 reply = wpas_dbus_error_invalid_args(message, NULL);
2104 DBusMessage * wpas_dbus_handler_p2p_service_sd_cancel_req(
2105 DBusMessage *message, struct wpa_supplicant *wpa_s)
2107 DBusMessageIter iter;
2110 dbus_message_iter_init(message, &iter);
2111 dbus_message_iter_get_basic(&iter, &req);
2116 if (!wpas_p2p_sd_cancel_request(wpa_s, (void *)(unsigned long) req))
2121 return wpas_dbus_error_invalid_args(message, NULL);
2125 DBusMessage * wpas_dbus_handler_p2p_service_update(
2126 DBusMessage *message, struct wpa_supplicant *wpa_s)
2128 wpas_p2p_sd_service_update(wpa_s);
2133 DBusMessage * wpas_dbus_handler_p2p_serv_disc_external(
2134 DBusMessage *message, struct wpa_supplicant *wpa_s)
2136 DBusMessageIter iter;
2139 dbus_message_iter_init(message, &iter);
2140 dbus_message_iter_get_basic(&iter, &ext);
2142 wpa_s->p2p_sd_over_ctrl_iface = ext;