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);
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, "SearchOnly") &&
100 (entry.type == DBUS_TYPE_BOOLEAN)) {
101 searchonly = (entry.bool_value == TRUE) ? 1 : 0;
102 } else if (os_strcmp(entry.key, "RequestedDeviceTypes") == 0) {
103 if ((entry.type != DBUS_TYPE_ARRAY) ||
104 (entry.array_type != WPAS_DBUS_TYPE_BINARRAY))
108 os_malloc(WPS_DEV_TYPE_LEN * entry.array_len);
112 for (i = 0; i < entry.array_len; i++) {
113 if (wpabuf_len(entry.binarray_value[i]) !=
116 os_memcpy(req_dev_types + i * WPS_DEV_TYPE_LEN,
117 wpabuf_head(entry.binarray_value[i]),
121 num_req_dev_types = entry.array_len;
124 wpa_dbus_dict_entry_clear(&entry);
127 wpas_p2p_find(wpa_s, timeout, type, num_req_dev_types, req_dev_types);
131 os_free(req_dev_types);
132 wpa_dbus_dict_entry_clear(&entry);
134 reply = wpas_dbus_error_invalid_args(message, entry.key);
138 DBusMessage *wpas_dbus_handler_p2p_stop_find(DBusMessage * message,
139 struct wpa_supplicant * wpa_s)
141 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.");
165 DBusMessage *wpas_dbus_handler_p2p_listen(DBusMessage * message,
166 struct wpa_supplicant * wpa_s)
168 dbus_int32_t timeout = 0;
170 if (!dbus_message_get_args(message, NULL, DBUS_TYPE_INT32, &timeout,
172 return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
175 if (wpas_p2p_listen(wpa_s, (unsigned int)timeout))
176 return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
182 DBusMessage *wpas_dbus_handler_p2p_extendedlisten(DBusMessage * message,
183 struct wpa_supplicant * wpa_s)
185 unsigned int period = 0, interval = 0;
186 struct wpa_dbus_dict_entry entry;
187 DBusMessageIter iter;
188 DBusMessageIter iter_dict;
190 dbus_message_iter_init(message, &iter);
192 if (!wpa_dbus_dict_open_read(&iter, &iter_dict))
195 while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
196 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
199 if (!strcmp(entry.key, "period") &&
200 (entry.type == DBUS_TYPE_INT32))
201 period = entry.uint32_value;
202 else if (!strcmp(entry.key, "interval") &&
203 (entry.type == DBUS_TYPE_INT32))
204 interval = entry.uint32_value;
207 wpa_dbus_dict_entry_clear(&entry);
210 if (wpas_p2p_ext_listen(wpa_s, period, interval))
211 return wpas_dbus_error_unknown_error(message,
212 "failed to initiate a p2p_ext_listen.");
217 wpa_dbus_dict_entry_clear(&entry);
219 return wpas_dbus_error_invalid_args(message, entry.key);
222 DBusMessage *wpas_dbus_handler_p2p_presence_request(DBusMessage * message,
223 struct wpa_supplicant *
226 unsigned int dur1 = 0, int1 = 0, dur2 = 0, int2 = 0;
227 struct wpa_dbus_dict_entry entry;
228 DBusMessageIter iter;
229 DBusMessageIter iter_dict;
231 dbus_message_iter_init(message, &iter);
233 if (!wpa_dbus_dict_open_read(&iter, &iter_dict))
236 while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
237 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
240 if (!strcmp(entry.key, "duration1") &&
241 (entry.type == DBUS_TYPE_INT32))
242 dur1 = entry.uint32_value;
243 else if (!strcmp(entry.key, "interval1") &&
244 entry.type == DBUS_TYPE_INT32)
245 int1 = entry.uint32_value;
246 else if (!strcmp(entry.key, "duration2") &&
247 entry.type == DBUS_TYPE_INT32)
248 dur2 = entry.uint32_value;
249 else if (!strcmp(entry.key, "interval2") &&
250 entry.type == DBUS_TYPE_INT32)
251 int2 = entry.uint32_value;
255 wpa_dbus_dict_entry_clear(&entry);
257 if (wpas_p2p_presence_req(wpa_s, dur1, int1, dur2, int2) < 0)
258 return wpas_dbus_error_unknown_error(message,
259 "Failed to invoke presence request.");
264 wpa_dbus_dict_entry_clear(&entry);
266 return wpas_dbus_error_invalid_args(message, entry.key);
269 DBusMessage *wpas_dbus_handler_p2p_group_add(DBusMessage * message,
270 struct wpa_supplicant * wpa_s)
272 DBusMessageIter iter_dict;
273 DBusMessage *reply = NULL;
274 DBusMessageIter iter;
275 struct wpa_dbus_dict_entry entry;
276 char *pg_object_path = NULL;
277 int persistent_group = 0;
280 char *net_id_str = NULL;
281 unsigned int group_id = 0;
282 struct wpa_ssid *ssid;
284 dbus_message_iter_init(message, &iter);
286 if (!wpa_dbus_dict_open_read(&iter, &iter_dict))
289 while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
290 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
293 if (!strcmp(entry.key, "persistent") &&
294 (entry.type == DBUS_TYPE_BOOLEAN)) {
295 persistent_group = (entry.bool_value == TRUE) ? 1 : 0;
296 } else if (!strcmp(entry.key, "frequency") &&
297 (entry.type == DBUS_TYPE_INT32)) {
298 freq = entry.int32_value;
301 } else if (!strcmp(entry.key, "persistent_group_object") &&
302 entry.type == DBUS_TYPE_OBJECT_PATH)
303 pg_object_path = os_strdup(entry.str_value);
307 wpa_dbus_dict_entry_clear(&entry);
310 if (pg_object_path != NULL) {
312 * A persistent group Object Path is defined meaning we want
313 * to re-invoke a persistent group.
316 iface = wpas_dbus_new_decompose_object_path(pg_object_path, 1,
319 os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
321 wpas_dbus_error_invalid_args(message,
326 group_id = strtoul(net_id_str, NULL, 10);
327 if (errno == EINVAL) {
328 reply = wpas_dbus_error_invalid_args(
329 message, pg_object_path);
333 /* Get the SSID structure form the persistant group id */
334 ssid = wpa_config_get_network(wpa_s->conf, group_id);
335 if (ssid == NULL || ssid->disabled != 2)
338 if (wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq)) {
339 reply = wpas_dbus_error_unknown_error(message,
340 "Failed to reinvoke a persistent group");
343 } else if (wpas_p2p_group_add(wpa_s, persistent_group, freq))
347 os_free(pg_object_path);
352 wpa_dbus_dict_entry_clear(&entry);
354 reply = wpas_dbus_error_invalid_args(message, NULL);
358 DBusMessage *wpas_dbus_handler_p2p_disconnect(DBusMessage *message,
359 struct wpa_supplicant *wpa_s)
361 if (wpas_p2p_disconnect(wpa_s))
362 return wpas_dbus_error_unknown_error(message,
363 "failed to disconnect");
368 DBusMessage *wpas_dbus_handler_p2p_flush(DBusMessage * message,
369 struct wpa_supplicant * wpa_s)
371 os_memset(wpa_s->p2p_auth_invite, 0, ETH_ALEN);
372 wpa_s->force_long_sd = 0;
373 p2p_flush(wpa_s->global->p2p);
378 DBusMessage *wpas_dbus_handler_p2p_connect(DBusMessage * message,
379 struct wpa_supplicant * wpa_s)
381 DBusMessageIter iter_dict;
382 DBusMessage *reply = NULL;
383 DBusMessageIter iter;
384 struct wpa_dbus_dict_entry entry;
385 char *peer_object_path = NULL;
386 int persistent_group = 0;
388 int authorize_only = 0;
393 enum p2p_wps_method wps_method = WPS_NOT_READY;
395 char *err_msg = NULL;
398 dbus_message_iter_init(message, &iter);
400 if (!wpa_dbus_dict_open_read(&iter, &iter_dict))
403 while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
404 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
407 if (!strcmp(entry.key, "peer") &&
408 (entry.type == DBUS_TYPE_OBJECT_PATH)) {
409 peer_object_path = os_strdup(entry.str_value);
410 } else if (!strcmp(entry.key, "persistent") &&
411 (entry.type == DBUS_TYPE_BOOLEAN)) {
412 persistent_group = (entry.bool_value == TRUE) ? 1 : 0;
413 } else if (!strcmp(entry.key, "join") &&
414 (entry.type == DBUS_TYPE_BOOLEAN)) {
415 join = (entry.bool_value == TRUE) ? 1 : 0;
416 } else if (!strcmp(entry.key, "authorize_only") &&
417 (entry.type == DBUS_TYPE_BOOLEAN)) {
418 authorize_only = (entry.bool_value == TRUE) ? 1 : 0;
419 } else if (!strcmp(entry.key, "frequency") &&
420 (entry.type == DBUS_TYPE_INT32)) {
421 freq = entry.int32_value;
424 } else if (!strcmp(entry.key, "go_intent") &&
425 (entry.type == DBUS_TYPE_INT32)) {
426 go_intent = entry.int32_value;
427 if ((go_intent < 0) || (go_intent > 15))
429 } else if (!strcmp(entry.key, "wps_method") &&
430 (entry.type == DBUS_TYPE_STRING)) {
431 if (!strcmp(entry.str_value, "pbc"))
432 wps_method = WPS_PBC;
433 else if (!strcmp(entry.str_value, "pin"))
434 wps_method = WPS_PIN_DISPLAY;
435 else if (!strcmp(entry.str_value, "label"))
436 wps_method = WPS_PIN_LABEL;
437 else if (!strcmp(entry.str_value, "display"))
438 wps_method = WPS_PIN_DISPLAY;
439 else if (!strcmp(entry.str_value, "keypad"))
440 wps_method = WPS_PIN_KEYPAD;
443 } else if (!strcmp(entry.key, "pin") &&
444 (entry.type == DBUS_TYPE_STRING)) {
445 pin = os_strdup(entry.str_value);
449 wpa_dbus_dict_entry_clear(&entry);
452 if (!peer_object_path || (wps_method == WPS_NOT_READY) ||
453 (parse_peer_object_path(peer_object_path, addr) < 0) ||
454 (p2p_get_peer_info(wpa_s->global->p2p, addr, 0, NULL, 0) < 0)) {
455 reply = wpas_dbus_error_invalid_args(message, NULL);
460 * Validate the wps_method specified and the pin value.
462 if ((!pin || !pin[0]) &&
463 ((wps_method == WPS_PIN_LABEL) || (wps_method == WPS_PIN_KEYPAD)))
466 new_pin = wpas_p2p_connect(wpa_s, addr, pin, wps_method,
467 persistent_group, join, authorize_only,
471 reply = dbus_message_new_method_return(message);
472 dbus_message_append_args(reply, DBUS_TYPE_INT32,
473 &new_pin, DBUS_TYPE_INVALID);
477 err_msg = "connect failed due to"
478 " channel unavailability.";
479 iface = WPAS_DBUS_ERROR_CONNECT_CHANNEL_UNAVAILABLE;
483 err_msg = "connect failed due to"
484 " unsupported channel.";
485 iface = WPAS_DBUS_ERROR_CONNECT_CHANNEL_UNSUPPORTED;
489 err_msg = "connect failed due to"
490 " unspecified error.";
491 iface = WPAS_DBUS_ERROR_CONNECT_UNSPECIFIED_ERROR;
496 * Do we need specialized errors corresponding to above
497 * error conditions as against just returning a different
500 reply = dbus_message_new_error(message, iface, err_msg);
504 os_free(peer_object_path);
508 wpa_dbus_dict_entry_clear(&entry);
510 reply = wpas_dbus_error_invalid_args(message, NULL);
514 DBusMessage *wpas_dbus_handler_p2p_invite(DBusMessage * message,
515 struct wpa_supplicant *wpa_s)
517 DBusMessageIter iter_dict;
518 DBusMessage *reply = NULL;
519 DBusMessageIter iter;
520 struct wpa_dbus_dict_entry entry;
521 char *peer_object_path = NULL;
522 char *pg_object_path = NULL;
524 char *net_id_str = NULL;
525 u8 peer_addr[ETH_ALEN];
526 unsigned int group_id = 0;
528 struct wpa_ssid *ssid;
530 dbus_message_iter_init(message, &iter);
532 if (!wpa_dbus_dict_open_read(&iter, &iter_dict))
535 while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
536 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
539 if (!strcmp(entry.key, "peer") &&
540 (entry.type == DBUS_TYPE_OBJECT_PATH)) {
541 peer_object_path = os_strdup(entry.str_value);
542 wpa_dbus_dict_entry_clear(&entry);
543 } else if (!strcmp(entry.key, "persistent_group_object") &&
544 (entry.type == DBUS_TYPE_OBJECT_PATH)) {
545 pg_object_path = os_strdup(entry.str_value);
547 wpa_dbus_dict_entry_clear(&entry);
549 wpa_dbus_dict_entry_clear(&entry);
554 if (!peer_object_path ||
555 (parse_peer_object_path(peer_object_path, peer_addr) < 0) ||
556 (p2p_get_peer_info(wpa_s->global->p2p,
557 peer_addr, 0, NULL, 0) < 0)) {
563 * A group ID is defined meaning we want to re-invoke a
567 iface = wpas_dbus_new_decompose_object_path(pg_object_path, 1,
570 os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
572 wpas_dbus_error_invalid_args(message,
577 group_id = strtoul(net_id_str, NULL, 10);
578 if (errno == EINVAL) {
579 reply = wpas_dbus_error_invalid_args(
580 message, pg_object_path);
584 /* Get the SSID structure form the persistant group id */
585 ssid = wpa_config_get_network(wpa_s->conf, group_id);
586 if (ssid == NULL || ssid->disabled != 2)
589 if (wpas_p2p_invite(wpa_s, peer_addr, ssid, NULL) < 0) {
590 reply = wpas_dbus_error_unknown_error(
592 "Failed to reinvoke a persistent group");
597 * No group ID means propose to a peer to join my active group
599 if (wpas_p2p_invite_group(wpa_s, wpa_s->ifname,
601 reply = wpas_dbus_error_unknown_error(
603 "Failed to join to an active group");
609 os_free(pg_object_path);
610 os_free(peer_object_path);
614 reply = wpas_dbus_error_invalid_args(message, NULL);
618 DBusMessage *wpas_dbus_handler_p2p_prov_disc_req(DBusMessage * message,
619 struct wpa_supplicant *wpa_s)
621 DBusMessageIter iter;
622 char *peer_object_path = NULL;
623 char *config_method = NULL;
624 u8 peer_addr[ETH_ALEN];
626 dbus_message_iter_init(message, &iter);
627 dbus_message_iter_get_basic(&iter, &peer_object_path);
629 if (parse_peer_object_path(peer_object_path, peer_addr) < 0)
630 return wpas_dbus_error_invalid_args(message, NULL);
632 dbus_message_iter_next(&iter);
633 dbus_message_iter_get_basic(&iter, &config_method);
636 * Validation checks on config_method are being duplicated here
637 * to be able to return invalid args reply since the error code
638 * from p2p module are not granular enough (yet).
640 if (os_strcmp(config_method, "display") &&
641 os_strcmp(config_method, "keypad") &&
642 os_strcmp(config_method, "pbc") &&
643 os_strcmp(config_method, "pushbutton"))
644 return wpas_dbus_error_invalid_args(message, NULL);
646 if (wpas_p2p_prov_disc(wpa_s, peer_addr, config_method) < 0)
647 return wpas_dbus_error_unknown_error(message,
648 "Failed to send provision discovery request");
654 * P2P Device property accessor methods.
657 DBusMessage *wpas_dbus_getter_p2p_device_properties(DBusMessage * message,
658 struct wpa_supplicant *
661 DBusMessage *reply = NULL;
662 DBusMessageIter iter, variant_iter, dict_iter;
663 const char *dev_name;
664 int num_sec_dev_types = 0;
665 int num_vendor_extensions = 0;
667 const struct wpabuf *vendor_ext[P2P_MAX_WPS_VENDOR_EXT];
670 reply = dbus_message_new(DBUS_MESSAGE_TYPE_SIGNAL);
672 reply = dbus_message_new_method_return(message);
677 dbus_message_iter_init_append(reply, &iter);
679 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT,
680 "a{sv}", &variant_iter) ||
681 !wpa_dbus_dict_open_write(&variant_iter, &dict_iter))
685 dev_name = wpa_s->conf->device_name;
687 !wpa_dbus_dict_append_string(&dict_iter, "DeviceName", dev_name))
690 /* Primary device type */
691 if (!wpa_dbus_dict_append_byte_array(&dict_iter, "PrimaryDeviceType",
692 (char *)wpa_s->conf->device_type,
696 /* Secondary device types */
697 for (i = 0; i < MAX_SEC_DEVICE_TYPES; i++) {
698 if (wpa_s->conf->sec_device_type[i] == NULL)
703 if (!wpa_dbus_dict_append_string_array(
704 &dict_iter, "SecondaryDeviceTypes",
705 (const char **)wpa_s->conf->sec_device_type,
709 /* Vendor Extensions */
710 for (i = 0; i < P2P_MAX_WPS_VENDOR_EXT; i++) {
711 if (wpa_s->conf->wps_vendor_ext[i] == NULL)
713 vendor_ext[num_vendor_extensions++] =
714 wpa_s->conf->wps_vendor_ext[i];
717 if (num_vendor_extensions &&
718 !wpa_dbus_dict_append_wpabuf_array(&dict_iter,
721 num_vendor_extensions))
725 if (!wpa_dbus_dict_append_uint32(&dict_iter, "GOIntent",
726 wpa_s->conf->p2p_go_intent))
729 /* Persistant Reconnect */
730 if (!wpa_dbus_dict_append_bool(&dict_iter, "PersistantReconnect",
731 wpa_s->conf->persistent_reconnect))
734 /* Listen Reg Class */
735 if (!wpa_dbus_dict_append_uint32(&dict_iter, "ListenRegClass",
736 wpa_s->conf->p2p_listen_reg_class))
740 if (!wpa_dbus_dict_append_uint32(&dict_iter, "ListenChannel",
741 wpa_s->conf->p2p_listen_channel))
745 if (!wpa_dbus_dict_append_uint32(&dict_iter, "OperRegClass",
746 wpa_s->conf->p2p_oper_reg_class))
750 if (!wpa_dbus_dict_append_uint32(&dict_iter, "OperChannel",
751 wpa_s->conf->p2p_oper_channel))
755 if (wpa_s->conf->p2p_ssid_postfix &&
756 !wpa_dbus_dict_append_string(&dict_iter, "SsidPostfix",
757 wpa_s->conf->p2p_ssid_postfix))
761 if (!wpa_dbus_dict_append_bool(&dict_iter, "IntraBss",
762 wpa_s->conf->p2p_intra_bss))
766 if (!wpa_dbus_dict_append_uint32(&dict_iter, "GroupIdle",
767 wpa_s->conf->p2p_group_idle))
770 /* Dissasociation low ack */
771 if (!wpa_dbus_dict_append_uint32(&dict_iter, "disassoc_low_ack",
772 wpa_s->conf->disassoc_low_ack))
775 if (!wpa_dbus_dict_close_write(&variant_iter, &dict_iter) ||
776 !dbus_message_iter_close_container(&iter, &variant_iter))
781 dbus_message_unref(reply);
782 return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL);
785 DBusMessage *wpas_dbus_setter_p2p_device_properties(DBusMessage * message,
786 struct wpa_supplicant *
789 DBusMessage *reply = NULL;
790 DBusMessageIter iter, variant_iter;
791 struct wpa_dbus_dict_entry entry = {.type = DBUS_TYPE_STRING };
792 DBusMessageIter iter_dict;
795 dbus_message_iter_init(message, &iter);
797 dbus_message_iter_next(&iter);
798 dbus_message_iter_next(&iter);
800 dbus_message_iter_recurse(&iter, &variant_iter);
802 if (!wpa_dbus_dict_open_read(&variant_iter, &iter_dict))
803 return wpas_dbus_error_invalid_args(message, NULL);
805 while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
806 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
807 return wpas_dbus_error_invalid_args(message, NULL);
809 if (os_strcmp(entry.key, "DeviceName") == 0) {
812 if (entry.type != DBUS_TYPE_STRING)
815 devname = os_strdup(entry.str_value);
817 goto err_no_mem_clear;
819 os_free(wpa_s->conf->device_name);
820 wpa_s->conf->device_name = devname;
822 wpa_s->conf->changed_parameters |=
823 CFG_CHANGED_DEVICE_NAME;
824 } else if (os_strcmp(entry.key, "PrimaryDeviceType") == 0) {
825 if (entry.type != DBUS_TYPE_ARRAY ||
826 entry.array_type != DBUS_TYPE_BYTE ||
827 entry.array_len != WPS_DEV_TYPE_LEN)
830 os_memcpy(wpa_s->conf->device_type,
831 entry.bytearray_value,
833 wpa_s->conf->changed_parameters |=
834 CFG_CHANGED_DEVICE_TYPE;
835 } else if (os_strcmp(entry.key, "SecondaryDeviceTypes") == 0) {
836 if (entry.type != DBUS_TYPE_ARRAY ||
837 entry.array_type != WPAS_DBUS_TYPE_BINARRAY ||
838 entry.array_len > MAX_SEC_DEVICE_TYPES)
841 for (i = 0; i < entry.array_len; i++)
842 if (wpabuf_len(entry.binarray_value[i]) != WPS_DEV_TYPE_LEN)
843 goto err_no_mem_clear;
844 for (i = 0; i < entry.array_len; i++)
845 os_memcpy(wpa_s->conf->sec_device_type[i],
846 wpabuf_head(entry.binarray_value[i]),
848 wpa_s->conf->num_sec_device_types = entry.array_len;
849 wpa_s->conf->changed_parameters |=
850 CFG_CHANGED_SEC_DEVICE_TYPE;
851 } else if (os_strcmp(entry.key, "VendorExtension") == 0) {
852 if ((entry.type != DBUS_TYPE_ARRAY) ||
853 (entry.array_type != WPAS_DBUS_TYPE_BINARRAY) ||
854 (entry.array_len > P2P_MAX_WPS_VENDOR_EXT))
857 wpa_s->conf->changed_parameters |=
858 CFG_CHANGED_VENDOR_EXTENSION;
860 for (i = 0; i < P2P_MAX_WPS_VENDOR_EXT; i++) {
861 wpabuf_free(wpa_s->conf->wps_vendor_ext[i]);
862 if (i < entry.array_len) {
863 wpa_s->conf->wps_vendor_ext[i] =
864 entry.binarray_value[i];
865 entry.binarray_value[i] = NULL;
867 wpa_s->conf->wps_vendor_ext[i] = NULL;
869 } else if ((os_strcmp(entry.key, "GOIntent") == 0) &&
870 (entry.type == DBUS_TYPE_UINT32) &&
871 (entry.uint32_value <= 15))
872 wpa_s->conf->p2p_go_intent = entry.uint32_value;
874 else if ((os_strcmp(entry.key, "PersistantReconnect") == 0) &&
875 (entry.type == DBUS_TYPE_BOOLEAN))
876 wpa_s->conf->persistent_reconnect = entry.bool_value;
878 else if ((os_strcmp(entry.key, "ListenRegClass") == 0) &&
879 (entry.type == DBUS_TYPE_UINT32)) {
880 wpa_s->conf->p2p_listen_reg_class = entry.uint32_value;
881 wpa_s->conf->changed_parameters |=
882 CFG_CHANGED_P2P_LISTEN_CHANNEL;
883 } else if ((os_strcmp(entry.key, "ListenChannel") == 0) &&
884 (entry.type == DBUS_TYPE_UINT32)) {
885 wpa_s->conf->p2p_listen_channel = entry.uint32_value;
886 wpa_s->conf->changed_parameters |=
887 CFG_CHANGED_P2P_LISTEN_CHANNEL;
888 } else if ((os_strcmp(entry.key, "OperRegClass") == 0) &&
889 (entry.type == DBUS_TYPE_UINT32)) {
890 wpa_s->conf->p2p_oper_reg_class = entry.uint32_value;
891 wpa_s->conf->changed_parameters |=
892 CFG_CHANGED_P2P_OPER_CHANNEL;
893 } else if ((os_strcmp(entry.key, "OperChannel") == 0) &&
894 (entry.type == DBUS_TYPE_UINT32)) {
895 wpa_s->conf->p2p_oper_channel = entry.uint32_value;
896 wpa_s->conf->changed_parameters |=
897 CFG_CHANGED_P2P_OPER_CHANNEL;
898 } else if (os_strcmp(entry.key, "SsidPostfix") == 0) {
901 if (entry.type != DBUS_TYPE_STRING)
904 postfix = os_strdup(entry.str_value);
906 goto err_no_mem_clear;
908 os_free(wpa_s->conf->p2p_ssid_postfix);
909 wpa_s->conf->p2p_ssid_postfix = postfix;
911 wpa_s->conf->changed_parameters |=
912 CFG_CHANGED_P2P_SSID_POSTFIX;
913 } else if ((os_strcmp(entry.key, "IntraBss") == 0) &&
914 (entry.type == DBUS_TYPE_BOOLEAN)) {
915 wpa_s->conf->p2p_intra_bss = entry.bool_value;
916 wpa_s->conf->changed_parameters |=
917 CFG_CHANGED_P2P_INTRA_BSS;
918 } else if ((os_strcmp(entry.key, "GroupIdle") == 0) &&
919 (entry.type == DBUS_TYPE_UINT32))
920 wpa_s->conf->p2p_group_idle = entry.uint32_value;
921 else if (os_strcmp(entry.key, "disassoc_low_ack") == 0 &&
922 entry.type == DBUS_TYPE_UINT32)
923 wpa_s->conf->disassoc_low_ack = entry.uint32_value;
927 wpa_dbus_dict_entry_clear(&entry);
930 if (wpa_s->conf->changed_parameters) {
931 /* Some changed parameters requires to update config*/
932 wpa_supplicant_update_config(wpa_s);
938 wpa_dbus_dict_entry_clear(&entry);
940 reply = wpas_dbus_error_invalid_args(message, entry.key);
941 wpa_dbus_dict_entry_clear(&entry);
945 wpa_dbus_dict_entry_clear(&entry);
946 return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL);
949 DBusMessage *wpas_dbus_getter_p2p_peers(DBusMessage * message,
950 struct wpa_supplicant * wpa_s)
952 DBusMessage *reply = NULL;
953 struct p2p_data *p2p = wpa_s->global->p2p;
955 int num = 0, out_of_mem = 0;
957 const struct p2p_peer_info *peer_info = NULL;
959 struct dl_list peer_objpath_list;
960 struct peer_objpath_node {
962 char path[WPAS_DBUS_OBJECT_PATH_MAX];
965 char **peer_obj_paths = NULL;
967 dl_list_init(&peer_objpath_list);
969 /* Get the first peer info */
970 peer_info = p2p_get_peer_found(p2p, NULL, next);
972 /* Get next and accumulate them */
974 while (peer_info != NULL) {
975 node = os_zalloc(sizeof(struct peer_objpath_node));
981 addr = peer_info->p2p_device_addr;
982 os_snprintf(node->path, WPAS_DBUS_OBJECT_PATH_MAX,
983 "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART
985 wpa_s->dbus_new_path, MAC2STR(addr));
986 dl_list_add_tail(&peer_objpath_list, &node->list);
989 peer_info = p2p_get_peer_found(p2p, addr, next);
993 * Now construct the peer object paths in a form suitable for
994 * array_property_getter helper below.
996 peer_obj_paths = os_zalloc(num * sizeof(char *));
998 if (!peer_obj_paths) {
1003 dl_list_for_each_safe(node, tmp, &peer_objpath_list,
1004 struct peer_objpath_node, list)
1005 peer_obj_paths[i++] = node->path;
1007 reply = wpas_dbus_simple_array_property_getter(message,
1008 DBUS_TYPE_OBJECT_PATH,
1009 peer_obj_paths, num);
1013 os_free(peer_obj_paths);
1015 dl_list_for_each_safe(node, tmp, &peer_objpath_list,
1016 struct peer_objpath_node, list) {
1017 dl_list_del(&node->list);
1021 reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
1027 enum wpas_p2p_role {
1028 WPAS_P2P_ROLE_DEVICE,
1030 WPAS_P2P_ROLE_CLIENT,
1033 static enum wpas_p2p_role wpas_get_p2p_role(struct wpa_supplicant *wpa_s)
1035 struct wpa_ssid *ssid = wpa_s->current_ssid;
1038 return WPAS_P2P_ROLE_DEVICE;
1039 if (wpa_s->wpa_state != WPA_COMPLETED)
1040 return WPAS_P2P_ROLE_DEVICE;
1042 switch (ssid->mode) {
1043 case WPAS_MODE_P2P_GO:
1044 case WPAS_MODE_P2P_GROUP_FORMATION:
1045 return WPAS_P2P_ROLE_GO;
1046 case WPAS_MODE_INFRA:
1047 if (ssid->p2p_group)
1048 return WPAS_P2P_ROLE_CLIENT;
1049 return WPAS_P2P_ROLE_DEVICE;
1051 return WPAS_P2P_ROLE_DEVICE;
1055 DBusMessage *wpas_dbus_getter_p2p_role(DBusMessage * message,
1056 struct wpa_supplicant * wpa_s)
1060 switch (wpas_get_p2p_role(wpa_s)) {
1061 case WPAS_P2P_ROLE_GO:
1064 case WPAS_P2P_ROLE_CLIENT:
1071 return wpas_dbus_simple_property_getter(message, DBUS_TYPE_STRING,
1075 DBusMessage *wpas_dbus_getter_p2p_group(DBusMessage * message,
1076 struct wpa_supplicant * wpa_s)
1078 if (wpa_s->dbus_groupobj_path == NULL)
1081 return wpas_dbus_simple_property_getter(message,
1082 DBUS_TYPE_OBJECT_PATH,
1083 &wpa_s->dbus_groupobj_path);
1086 DBusMessage *wpas_dbus_getter_p2p_peergo(DBusMessage * message,
1087 struct wpa_supplicant * wpa_s)
1089 char go_peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path;
1091 if (wpas_get_p2p_role(wpa_s) != WPAS_P2P_ROLE_CLIENT)
1094 os_snprintf(go_peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
1095 "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/" COMPACT_MACSTR,
1096 wpa_s->dbus_new_path, MAC2STR(wpa_s->go_dev_addr));
1097 path = go_peer_obj_path;
1098 return wpas_dbus_simple_property_getter(message,
1099 DBUS_TYPE_OBJECT_PATH, &path);
1103 * Peer object properties accessor methods
1106 DBusMessage *wpas_dbus_getter_p2p_peer_properties(DBusMessage * message,
1107 struct peer_handler_args *
1110 DBusMessage *reply = NULL;
1111 DBusMessageIter iter, variant_iter, dict_iter;
1112 const struct p2p_peer_info *info = NULL;
1113 char devtype[WPS_DEV_TYPE_BUFSIZE];
1115 /* get the peer info */
1116 info = p2p_get_peer_found(peer_args->wpa_s->global->p2p,
1117 peer_args->p2p_device_addr, 0);
1121 if (message == NULL)
1122 reply = dbus_message_new(DBUS_MESSAGE_TYPE_SIGNAL);
1124 reply = dbus_message_new_method_return(message);
1129 dbus_message_iter_init_append(reply, &iter);
1130 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT,
1131 "a{sv}", &variant_iter) ||
1132 !wpa_dbus_dict_open_write(&variant_iter, &dict_iter))
1135 /* Fill out the dictionary */
1136 wps_dev_type_bin2str(info->pri_dev_type, devtype, sizeof(devtype));
1137 if (!wpa_dbus_dict_append_string(&dict_iter, "DeviceName",
1140 if (!wpa_dbus_dict_append_string(&dict_iter, "PrimaryDeviceType",
1143 if (!wpa_dbus_dict_append_uint16(&dict_iter, "config_method",
1144 info->config_methods))
1146 if (!wpa_dbus_dict_append_int32(&dict_iter, "level",
1149 if (!wpa_dbus_dict_append_byte(&dict_iter, "devicecapability",
1152 if (!wpa_dbus_dict_append_byte(&dict_iter, "groupcapability",
1156 if (info->wps_sec_dev_type_list_len) {
1157 char *sec_dev_types[MAX_SEC_DEVICE_TYPES];
1158 u8 *sec_dev_type_list = NULL;
1159 char secdevtype[WPS_DEV_TYPE_BUFSIZE];
1160 int num_sec_dev_types = 0;
1163 sec_dev_type_list = os_zalloc(info->wps_sec_dev_type_list_len);
1165 if (sec_dev_type_list == NULL)
1168 os_memcpy(sec_dev_type_list, info->wps_sec_dev_type_list,
1169 info->wps_sec_dev_type_list_len);
1171 for (i = 0; i < MAX_SEC_DEVICE_TYPES &&
1172 i < (int) (info->wps_sec_dev_type_list_len /
1175 sec_dev_types[i] = os_zalloc(sizeof(secdevtype));
1177 if (!sec_dev_types[i] ||
1178 wps_dev_type_bin2str(
1179 &sec_dev_type_list[i *
1182 sizeof(secdevtype)) == NULL) {
1184 os_free(sec_dev_types[i]);
1185 os_free(sec_dev_type_list);
1189 num_sec_dev_types++;
1192 os_free(sec_dev_type_list);
1194 if (num_sec_dev_types) {
1195 if (!wpa_dbus_dict_append_string_array(&dict_iter,
1196 "SecondaryDeviceTypes",
1197 (const char **)sec_dev_types,
1198 num_sec_dev_types)) {
1199 for (i = 0; i < num_sec_dev_types; i++)
1200 os_free(sec_dev_types[i]);
1204 for (i = 0; i < num_sec_dev_types; i++)
1205 os_free(sec_dev_types[i]);
1210 /* Add WPS vendor extensions attribute */
1211 const struct wpabuf *vendor_extension[P2P_MAX_WPS_VENDOR_EXT];
1214 for (i = 0; i < P2P_MAX_WPS_VENDOR_EXT; i++) {
1215 if (info->wps_vendor_ext[i] == NULL)
1217 vendor_extension[num] = info->wps_vendor_ext[i];
1221 if (!wpa_dbus_dict_append_wpabuf_array(
1222 &dict_iter, "VendorExtension",
1223 vendor_extension, num))
1227 if (!wpa_dbus_dict_close_write(&variant_iter, &dict_iter) ||
1228 !dbus_message_iter_close_container(&iter, &variant_iter))
1233 dbus_message_unref(reply);
1234 return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL);
1237 DBusMessage *wpas_dbus_getter_p2p_peer_ies(DBusMessage * message,
1238 struct peer_handler_args * peer_args)
1245 * wpas_dbus_getter_persistent_groups - Get array of peristent group objects
1246 * @message: Pointer to incoming dbus message
1247 * @wpa_s: wpa_supplicant structure for a network interface
1248 * Returns: a dbus message containing an array of all persistent group
1249 * dbus object paths.
1251 * Getter for "Networks" property.
1253 DBusMessage * wpas_dbus_getter_persistent_groups(DBusMessage *message,
1254 struct wpa_supplicant *wpa_s)
1256 DBusMessage *reply = NULL;
1257 struct wpa_ssid *ssid;
1259 unsigned int i = 0, num = 0;
1261 if (wpa_s->conf == NULL) {
1262 wpa_printf(MSG_ERROR, "dbus: %s: "
1263 "An error occurred getting persistent groups list",
1265 return wpas_dbus_error_unknown_error(message, NULL);
1268 for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next)
1269 if (network_is_persistent_group(ssid))
1272 paths = os_zalloc(num * sizeof(char *));
1274 return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
1278 /* Loop through configured networks and append object path of each */
1279 for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
1280 if (!network_is_persistent_group(ssid))
1282 paths[i] = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX);
1283 if (paths[i] == NULL) {
1284 reply = dbus_message_new_error(message,
1285 DBUS_ERROR_NO_MEMORY,
1289 /* Construct the object path for this network. */
1290 os_snprintf(paths[i++], WPAS_DBUS_OBJECT_PATH_MAX,
1291 "%s/" WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART "/%d",
1292 wpa_s->dbus_new_path, ssid->id);
1295 reply = wpas_dbus_simple_array_property_getter(message,
1296 DBUS_TYPE_OBJECT_PATH,
1301 os_free(paths[--i]);
1308 * wpas_dbus_getter_persistent_group_properties - Get options for a persistent
1310 * @message: Pointer to incoming dbus message
1311 * @net: wpa_supplicant structure for a network interface and
1312 * wpa_ssid structure for a configured persistent group (internally network)
1313 * Returns: DBus message with network properties or DBus error on failure
1315 * Getter for "Properties" property of a persistent group.
1317 DBusMessage * wpas_dbus_getter_persistent_group_properties(
1318 DBusMessage *message, struct network_handler_args *net)
1321 * Leveraging the fact that persistent group object is still
1322 * represented in same manner as network within.
1324 return wpas_dbus_getter_network_properties(message, net);
1329 * wpas_dbus_setter_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 * Setter for "Properties" property of a persistent group.
1338 DBusMessage * wpas_dbus_setter_persistent_group_properties(
1339 DBusMessage *message, struct network_handler_args *net)
1341 struct wpa_ssid *ssid = net->ssid;
1342 DBusMessage *reply = NULL;
1343 DBusMessageIter iter, variant_iter;
1345 dbus_message_iter_init(message, &iter);
1347 dbus_message_iter_next(&iter);
1348 dbus_message_iter_next(&iter);
1350 dbus_message_iter_recurse(&iter, &variant_iter);
1353 * Leveraging the fact that persistent group object is still
1354 * represented in same manner as network within.
1356 reply = set_network_properties(message, net->wpa_s, ssid,
1359 wpa_printf(MSG_DEBUG, "dbus control interface couldn't set "
1360 "persistent group properties");
1367 * wpas_dbus_new_iface_add_persistent_group - Add a new configured
1369 * @message: Pointer to incoming dbus message
1370 * @wpa_s: wpa_supplicant structure for a network interface
1371 * Returns: A dbus message containing the object path of the new
1374 * Handler function for "AddPersistentGroup" method call of a P2P Device
1377 DBusMessage * wpas_dbus_handler_add_persistent_group(
1378 DBusMessage *message, struct wpa_supplicant *wpa_s)
1380 DBusMessage *reply = NULL;
1381 DBusMessageIter iter;
1382 struct wpa_ssid *ssid = NULL;
1383 char path_buf[WPAS_DBUS_OBJECT_PATH_MAX], *path = path_buf;
1385 dbus_message_iter_init(message, &iter);
1387 ssid = wpa_config_add_network(wpa_s->conf);
1389 wpa_printf(MSG_ERROR, "dbus: %s: "
1390 "Cannot add new persistent group", __func__);
1391 reply = wpas_dbus_error_unknown_error(
1393 "wpa_supplicant could not add "
1394 "a persistent group on this interface.");
1398 /* Mark the ssid as being a persistent group before the notification */
1400 ssid->p2p_persistent_group = 1;
1401 wpas_notify_persistent_group_added(wpa_s, ssid);
1403 wpa_config_set_network_defaults(ssid);
1405 reply = set_network_properties(message, wpa_s, ssid, &iter);
1407 wpa_printf(MSG_DEBUG, "dbus: %s: "
1408 "Control interface could not set persistent group "
1409 "properties", __func__);
1413 /* Construct the object path for this network. */
1414 os_snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX,
1415 "%s/" WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART "/%d",
1416 wpa_s->dbus_new_path, ssid->id);
1418 reply = dbus_message_new_method_return(message);
1419 if (reply == NULL) {
1420 reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
1424 if (!dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &path,
1425 DBUS_TYPE_INVALID)) {
1426 dbus_message_unref(reply);
1427 reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
1436 wpas_notify_persistent_group_removed(wpa_s, ssid);
1437 wpa_config_remove_network(wpa_s->conf, ssid->id);
1444 * wpas_dbus_handler_remove_persistent_group - Remove a configured persistent
1446 * @message: Pointer to incoming dbus message
1447 * @wpa_s: wpa_supplicant structure for a network interface
1448 * Returns: NULL on success or dbus error on failure
1450 * Handler function for "RemovePersistentGroup" method call of a P2P Device
1453 DBusMessage * wpas_dbus_handler_remove_persistent_group(
1454 DBusMessage *message, struct wpa_supplicant *wpa_s)
1456 DBusMessage *reply = NULL;
1458 char *iface = NULL, *persistent_group_id = NULL;
1460 struct wpa_ssid *ssid;
1462 dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &op,
1466 * Extract the network ID and ensure the network is actually a child of
1469 iface = wpas_dbus_new_decompose_object_path(op, 1,
1470 &persistent_group_id,
1472 if (iface == NULL || os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
1473 reply = wpas_dbus_error_invalid_args(message, op);
1477 id = strtoul(persistent_group_id, NULL, 10);
1478 if (errno == EINVAL) {
1479 reply = wpas_dbus_error_invalid_args(message, op);
1483 ssid = wpa_config_get_network(wpa_s->conf, id);
1485 reply = wpas_dbus_error_persistent_group_unknown(message);
1489 wpas_notify_persistent_group_removed(wpa_s, ssid);
1491 if (wpa_config_remove_network(wpa_s->conf, id) < 0) {
1492 wpa_printf(MSG_ERROR, "dbus: %s: "
1493 "error occurred when removing persistent group %d",
1495 reply = wpas_dbus_error_unknown_error(
1497 "error removing the specified persistent group on "
1504 os_free(persistent_group_id);
1509 static void remove_persistent_group(struct wpa_supplicant *wpa_s,
1510 struct wpa_ssid *ssid)
1512 wpas_notify_persistent_group_removed(wpa_s, ssid);
1514 if (wpa_config_remove_network(wpa_s->conf, ssid->id) < 0) {
1515 wpa_printf(MSG_ERROR, "dbus: %s: "
1516 "error occurred when removing persistent group %d",
1517 __func__, ssid->id);
1524 * wpas_dbus_handler_remove_all_persistent_groups - Remove all configured
1526 * @message: Pointer to incoming dbus message
1527 * @wpa_s: wpa_supplicant structure for a network interface
1528 * Returns: NULL on success or dbus error on failure
1530 * Handler function for "RemoveAllPersistentGroups" method call of a
1531 * P2P Device interface.
1533 DBusMessage * wpas_dbus_handler_remove_all_persistent_groups(
1534 DBusMessage *message, struct wpa_supplicant *wpa_s)
1536 struct wpa_ssid *ssid, *next;
1537 struct wpa_config *config;
1539 config = wpa_s->conf;
1540 ssid = config->ssid;
1543 if (network_is_persistent_group(ssid))
1544 remove_persistent_group(wpa_s, ssid);
1552 * Group object properties accessor methods
1555 DBusMessage *wpas_dbus_getter_p2p_group_members(DBusMessage * message,
1556 struct wpa_supplicant * wpa_s)
1558 DBusMessage *reply = NULL;
1559 struct wpa_ssid *ssid;
1560 unsigned int num_members;
1566 /* Ensure we are a GO */
1567 if (wpa_s->wpa_state != WPA_COMPLETED)
1570 ssid = wpa_s->conf->ssid;
1571 /* At present WPAS P2P_GO mode only applicable for p2p_go */
1572 if (ssid->mode != WPAS_MODE_P2P_GO &&
1573 ssid->mode != WPAS_MODE_AP &&
1574 ssid->mode != WPAS_MODE_P2P_GROUP_FORMATION)
1577 num_members = p2p_get_group_num_members(wpa_s->p2p_group);
1579 paths = os_zalloc(num_members * sizeof(char *));
1584 while ((addr = p2p_iterate_group_members(wpa_s->p2p_group, &next))) {
1585 paths[i] = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX);
1588 os_snprintf(paths[i], WPAS_DBUS_OBJECT_PATH_MAX,
1589 "%s/" WPAS_DBUS_NEW_P2P_GROUPMEMBERS_PART
1591 wpa_s->dbus_groupobj_path, MAC2STR(addr));
1595 reply = wpas_dbus_simple_array_property_getter(message,
1596 DBUS_TYPE_OBJECT_PATH,
1597 paths, num_members);
1600 for (i = 0; i < num_members; i++)
1606 reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL);
1611 DBusMessage *wpas_dbus_getter_p2p_group_properties(
1612 DBusMessage *message,
1613 struct wpa_supplicant *wpa_s)
1615 DBusMessage *reply = NULL;
1616 DBusMessageIter iter, variant_iter, dict_iter;
1617 struct hostapd_data *hapd = wpa_s->ap_iface->bss[0];
1618 const struct wpabuf *vendor_ext[MAX_WPS_VENDOR_EXTENSIONS];
1619 int num_vendor_ext = 0;
1623 reply = dbus_message_new_error(message, DBUS_ERROR_FAILED,
1628 if (message == NULL)
1629 reply = dbus_message_new(DBUS_MESSAGE_TYPE_SIGNAL);
1631 reply = dbus_message_new_method_return(message);
1636 dbus_message_iter_init_append(reply, &iter);
1638 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT,
1639 "a{sv}", &variant_iter) ||
1640 !wpa_dbus_dict_open_write(&variant_iter, &dict_iter))
1643 /* Parse WPS Vendor Extensions sent in Beacon/Probe Response */
1644 for (i = 0; i < MAX_WPS_VENDOR_EXTENSIONS; i++) {
1645 if (hapd->conf->wps_vendor_ext[i] == NULL)
1647 vendor_ext[num_vendor_ext++] = hapd->conf->wps_vendor_ext[i];
1650 if (!wpa_dbus_dict_append_wpabuf_array(&dict_iter,
1651 "WPSVendorExtensions",
1652 vendor_ext, num_vendor_ext))
1655 if (!wpa_dbus_dict_close_write(&variant_iter, &dict_iter) ||
1656 !dbus_message_iter_close_container(&iter, &variant_iter))
1662 dbus_message_unref(reply);
1663 return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL);
1666 DBusMessage *wpas_dbus_setter_p2p_group_properties(
1667 DBusMessage *message,
1668 struct wpa_supplicant *wpa_s)
1670 DBusMessage *reply = NULL;
1671 DBusMessageIter iter, variant_iter;
1672 struct wpa_dbus_dict_entry entry = {.type = DBUS_TYPE_STRING };
1673 DBusMessageIter iter_dict;
1676 struct hostapd_data *hapd = wpa_s->ap_iface->bss[0];
1681 dbus_message_iter_init(message, &iter);
1683 dbus_message_iter_next(&iter);
1684 dbus_message_iter_next(&iter);
1686 dbus_message_iter_recurse(&iter, &variant_iter);
1688 if (!wpa_dbus_dict_open_read(&variant_iter, &iter_dict))
1689 return wpas_dbus_error_invalid_args(message, NULL);
1691 while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
1692 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) {
1693 reply = wpas_dbus_error_invalid_args(message, NULL);
1697 if (os_strcmp(entry.key, "WPSVendorExtensions") == 0) {
1698 if (entry.type != DBUS_TYPE_ARRAY ||
1699 entry.array_type != WPAS_DBUS_TYPE_BINARRAY ||
1700 entry.array_len > MAX_WPS_VENDOR_EXTENSIONS)
1703 for (i = 0; i < MAX_WPS_VENDOR_EXTENSIONS; i++) {
1704 if (i < entry.array_len) {
1705 hapd->conf->wps_vendor_ext[i] =
1706 entry.binarray_value[i];
1707 entry.binarray_value[i] = NULL;
1709 hapd->conf->wps_vendor_ext[i] = NULL;
1712 hostapd_update_wps(hapd);
1716 wpa_dbus_dict_entry_clear(&entry);
1722 reply = wpas_dbus_error_invalid_args(message, entry.key);
1723 wpa_dbus_dict_entry_clear(&entry);
1728 DBusMessage *wpas_dbus_handler_p2p_add_service(DBusMessage * message,
1729 struct wpa_supplicant * wpa_s)
1731 DBusMessageIter iter_dict;
1732 DBusMessage *reply = NULL;
1733 DBusMessageIter iter;
1734 struct wpa_dbus_dict_entry entry;
1737 char *service = NULL;
1738 struct wpabuf *query = NULL;
1739 struct wpabuf *resp = NULL;
1742 dbus_message_iter_init(message, &iter);
1744 if (!wpa_dbus_dict_open_read(&iter, &iter_dict))
1747 if (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
1748 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
1751 if (!strcmp(entry.key, "service_type") &&
1752 (entry.type == DBUS_TYPE_STRING)) {
1753 if (!strcmp(entry.str_value, "upnp"))
1755 else if (!strcmp(entry.str_value, "bonjour"))
1759 wpa_dbus_dict_entry_clear(&entry);
1764 while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
1765 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
1768 if (!strcmp(entry.key, "version") &&
1769 entry.type == DBUS_TYPE_INT32)
1770 version = entry.uint32_value;
1771 else if (!strcmp(entry.key, "service") &&
1772 entry.type == DBUS_TYPE_STRING)
1773 service = os_strdup(entry.str_value);
1774 wpa_dbus_dict_entry_clear(&entry);
1776 if (version <= 0 || service == NULL)
1779 if (wpas_p2p_service_add_upnp(wpa_s, version, service) != 0)
1783 } else if (bonjour == 1) {
1784 while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
1785 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
1788 if (!strcmp(entry.key, "query")) {
1789 if ((entry.type != DBUS_TYPE_ARRAY) ||
1790 (entry.array_type != DBUS_TYPE_BYTE))
1792 query = wpabuf_alloc_copy(entry.bytearray_value,
1794 } else if (!strcmp(entry.key, "response")) {
1795 if ((entry.type != DBUS_TYPE_ARRAY) ||
1796 (entry.array_type != DBUS_TYPE_BYTE))
1798 resp = wpabuf_alloc_copy(entry.bytearray_value,
1802 wpa_dbus_dict_entry_clear(&entry);
1805 if (query == NULL || resp == NULL)
1808 if (wpas_p2p_service_add_bonjour(wpa_s, query, resp) < 0) {
1818 wpa_dbus_dict_entry_clear(&entry);
1820 return wpas_dbus_error_invalid_args(message, NULL);
1823 DBusMessage *wpas_dbus_handler_p2p_delete_service(DBusMessage * message,
1824 struct wpa_supplicant * wpa_s)
1826 DBusMessageIter iter_dict;
1827 DBusMessage *reply = NULL;
1828 DBusMessageIter iter;
1829 struct wpa_dbus_dict_entry entry;
1833 char *service = NULL;
1834 struct wpabuf *query = NULL;
1837 dbus_message_iter_init(message, &iter);
1839 if (!wpa_dbus_dict_open_read(&iter, &iter_dict))
1842 if (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
1843 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
1846 if (!strcmp(entry.key, "service_type") &&
1847 (entry.type == DBUS_TYPE_STRING)) {
1848 if (!strcmp(entry.str_value, "upnp"))
1850 else if (!strcmp(entry.str_value, "bonjour"))
1854 wpa_dbus_dict_entry_clear(&entry);
1858 while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
1859 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
1861 if (!strcmp(entry.key, "version") &&
1862 entry.type == DBUS_TYPE_INT32)
1863 version = entry.uint32_value;
1864 else if (!strcmp(entry.key, "service") &&
1865 entry.type == DBUS_TYPE_STRING)
1866 service = os_strdup(entry.str_value);
1870 wpa_dbus_dict_entry_clear(&entry);
1873 if (version <= 0 || service == NULL)
1876 ret = wpas_p2p_service_del_upnp(wpa_s, version, service);
1880 } else if (bonjour == 1) {
1881 while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
1882 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
1885 if (!strcmp(entry.key, "query")) {
1886 if ((entry.type != DBUS_TYPE_ARRAY) ||
1887 (entry.array_type != DBUS_TYPE_BYTE))
1889 query = wpabuf_alloc_copy(entry.bytearray_value,
1894 wpa_dbus_dict_entry_clear(&entry);
1900 ret = wpas_p2p_service_del_bonjour(wpa_s, query);
1909 wpa_dbus_dict_entry_clear(&entry);
1911 return wpas_dbus_error_invalid_args(message, NULL);
1914 DBusMessage *wpas_dbus_handler_p2p_flush_service(DBusMessage * message,
1915 struct wpa_supplicant * wpa_s)
1917 wpas_p2p_service_flush(wpa_s);
1921 DBusMessage *wpas_dbus_handler_p2p_service_sd_req(DBusMessage * message,
1922 struct wpa_supplicant * wpa_s)
1924 DBusMessageIter iter_dict;
1925 DBusMessage *reply = NULL;
1926 DBusMessageIter iter;
1927 struct wpa_dbus_dict_entry entry;
1929 char *service = NULL;
1930 char *peer_object_path = NULL;
1931 struct wpabuf *tlv = NULL;
1936 dbus_message_iter_init(message, &iter);
1938 if (!wpa_dbus_dict_open_read(&iter, &iter_dict))
1941 while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
1942 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
1944 if (!strcmp(entry.key, "peer_object") &&
1945 entry.type == DBUS_TYPE_OBJECT_PATH) {
1946 peer_object_path = os_strdup(entry.str_value);
1947 } else if (!strcmp(entry.key, "service_type") &&
1948 entry.type == DBUS_TYPE_STRING) {
1949 if (!strcmp(entry.str_value, "upnp"))
1953 } else if (!strcmp(entry.key, "version") &&
1954 entry.type == DBUS_TYPE_INT32) {
1955 version = entry.uint32_value;
1956 } else if (!strcmp(entry.key, "service") &&
1957 entry.type == DBUS_TYPE_STRING) {
1958 service = os_strdup(entry.str_value);
1959 } else if (!strcmp(entry.key, "tlv")) {
1960 if (entry.type != DBUS_TYPE_ARRAY ||
1961 entry.array_type != DBUS_TYPE_BYTE)
1963 tlv = wpabuf_alloc_copy(entry.bytearray_value,
1968 wpa_dbus_dict_entry_clear(&entry);
1971 if (!peer_object_path ||
1972 (parse_peer_object_path(peer_object_path, addr) < 0) ||
1973 (p2p_get_peer_info(wpa_s->global->p2p, addr, 0, NULL, 0) < 0))
1977 if (version <= 0 || service == NULL)
1980 ref = (unsigned long)wpas_p2p_sd_request_upnp(wpa_s, addr,
1985 ref = (unsigned long)wpas_p2p_sd_request(wpa_s, addr, tlv);
1990 reply = dbus_message_new_method_return(message);
1991 dbus_message_append_args(reply, DBUS_TYPE_UINT64,
1992 &ref, DBUS_TYPE_INVALID);
1994 reply = wpas_dbus_error_unknown_error(message,
1995 "Unable to send SD request");
1999 os_free(peer_object_path);
2002 wpa_dbus_dict_entry_clear(&entry);
2006 reply = wpas_dbus_error_invalid_args(message, NULL);
2010 DBusMessage *wpas_dbus_handler_p2p_service_sd_res(
2011 DBusMessage *message, struct wpa_supplicant *wpa_s)
2013 DBusMessageIter iter_dict;
2014 DBusMessage *reply = NULL;
2015 DBusMessageIter iter;
2016 struct wpa_dbus_dict_entry entry;
2017 char *peer_object_path = NULL;
2018 struct wpabuf *tlv = NULL;
2023 dbus_message_iter_init(message, &iter);
2025 if (!wpa_dbus_dict_open_read(&iter, &iter_dict))
2028 while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
2029 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
2032 if (!strcmp(entry.key, "peer_object") &&
2033 entry.type == DBUS_TYPE_OBJECT_PATH) {
2034 peer_object_path = os_strdup(entry.str_value);
2035 } else if (!strcmp(entry.key, "frequency") &&
2036 entry.type == DBUS_TYPE_INT32) {
2037 freq = entry.uint32_value;
2038 } else if (!strcmp(entry.key, "dialog_token") &&
2039 entry.type == DBUS_TYPE_UINT32) {
2040 dlg_tok = entry.uint32_value;
2041 } else if (!strcmp(entry.key, "tlvs")) {
2042 if (entry.type != DBUS_TYPE_ARRAY ||
2043 entry.array_type != DBUS_TYPE_BYTE)
2045 tlv = wpabuf_alloc_copy(entry.bytearray_value,
2050 wpa_dbus_dict_entry_clear(&entry);
2052 if (!peer_object_path ||
2053 (parse_peer_object_path(peer_object_path, addr) < 0) ||
2054 (p2p_get_peer_info(wpa_s->global->p2p, addr, 0, NULL, 0) < 0))
2060 wpas_p2p_sd_response(wpa_s, freq, addr, (u8) dlg_tok, tlv);
2063 os_free(peer_object_path);
2066 wpa_dbus_dict_entry_clear(&entry);
2068 reply = wpas_dbus_error_invalid_args(message, NULL);
2072 DBusMessage *wpas_dbus_handler_p2p_service_sd_cancel_req(DBusMessage * message, struct wpa_supplicant
2075 DBusMessageIter iter;
2078 dbus_message_iter_init(message, &iter);
2079 dbus_message_iter_get_basic(&iter, &req);
2084 if (!wpas_p2p_sd_cancel_request(wpa_s, (void *)(unsigned long)req))
2089 return wpas_dbus_error_invalid_args(message, NULL);
2092 DBusMessage *wpas_dbus_handler_p2p_service_update(DBusMessage * message,
2093 struct wpa_supplicant * wpa_s)
2095 wpas_p2p_sd_service_update(wpa_s);
2099 DBusMessage *wpas_dbus_handler_p2p_serv_disc_external(DBusMessage * message,
2100 struct wpa_supplicant *
2103 DBusMessageIter iter;
2106 dbus_message_iter_init(message, &iter);
2107 dbus_message_iter_get_basic(&iter, &ext);
2109 wpa_s->p2p_sd_over_ctrl_iface = ext;