2 * WPA Supplicant / dbus-based control interface (P2P)
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
8 * Alternatively, this software may be distributed under the terms of BSD
11 * See README and COPYING for more details.
16 #include "utils/includes.h"
18 #include "../config.h"
19 #include "../wpa_supplicant_i.h"
20 #include "../wps_supplicant.h"
21 #include "../notify.h"
22 #include "dbus_new_helpers.h"
24 #include "dbus_new_handlers.h"
25 #include "dbus_new_handlers_p2p.h"
26 #include "dbus_dict_helpers.h"
28 #include "common/ieee802_11_defs.h"
29 #include "ap/hostapd.h"
30 #include "ap/ap_config.h"
31 #include "ap/wps_hostapd.h"
33 #include "../p2p_supplicant.h"
36 * Parses out the mac address from the peer object path.
37 * @peer_path - object path of the form
38 * /fi/w1/wpa_supplicant1/Interfaces/n/Peers/00112233445566 (no colons)
39 * @addr - out param must be of ETH_ALEN size
40 * Returns 0 if valid (including MAC), -1 otherwise
42 static int parse_peer_object_path(char *peer_path, u8 addr[ETH_ALEN])
48 p = strrchr(peer_path, '/');
52 return hwaddr_compact_aton(p, addr);
57 * wpas_dbus_error_persistent_group_unknown - Return a new PersistentGroupUnknown
59 * @message: Pointer to incoming dbus message this error refers to
60 * Returns: a dbus error message
62 * Convenience function to create and return an invalid persistent group error.
64 static DBusMessage * wpas_dbus_error_persistent_group_unknown(
67 return dbus_message_new_error(message, WPAS_DBUS_ERROR_NETWORK_UNKNOWN,
68 "There is no such persistent group in "
73 DBusMessage * wpas_dbus_handler_p2p_find(DBusMessage *message,
74 struct wpa_supplicant *wpa_s)
76 struct wpa_dbus_dict_entry entry;
77 DBusMessage *reply = NULL;
79 DBusMessageIter iter_dict;
80 unsigned int timeout = 0;
81 enum p2p_discovery_type type = P2P_FIND_ONLY_SOCIAL;
82 int num_req_dev_types = 0;
84 u8 *req_dev_types = NULL;
86 dbus_message_iter_init(message, &iter);
89 if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
92 while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
93 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
96 if (!os_strcmp(entry.key, "Timeout") &&
97 (entry.type == DBUS_TYPE_INT32)) {
98 timeout = entry.uint32_value;
99 } else if (os_strcmp(entry.key, "RequestedDeviceTypes") == 0) {
100 if ((entry.type != DBUS_TYPE_ARRAY) ||
101 (entry.array_type != WPAS_DBUS_TYPE_BINARRAY))
105 os_malloc(WPS_DEV_TYPE_LEN * entry.array_len);
109 for (i = 0; i < entry.array_len; i++) {
110 if (wpabuf_len(entry.binarray_value[i]) !=
113 os_memcpy(req_dev_types + i * WPS_DEV_TYPE_LEN,
114 wpabuf_head(entry.binarray_value[i]),
118 num_req_dev_types = entry.array_len;
121 wpa_dbus_dict_entry_clear(&entry);
124 wpas_p2p_find(wpa_s, timeout, type, num_req_dev_types, req_dev_types);
125 os_free(req_dev_types);
129 wpa_dbus_dict_entry_clear(&entry);
131 os_free(req_dev_types);
132 reply = wpas_dbus_error_invalid_args(message, entry.key);
137 DBusMessage * wpas_dbus_handler_p2p_stop_find(DBusMessage *message,
138 struct wpa_supplicant *wpa_s)
140 wpas_p2p_stop_find(wpa_s);
145 DBusMessage * wpas_dbus_handler_p2p_rejectpeer(DBusMessage *message,
146 struct wpa_supplicant *wpa_s)
148 DBusMessageIter iter;
149 char *peer_object_path = NULL;
150 u8 peer_addr[ETH_ALEN];
152 dbus_message_iter_init(message, &iter);
153 dbus_message_iter_get_basic(&iter, &peer_object_path);
155 if (parse_peer_object_path(peer_object_path, peer_addr) < 0)
156 return wpas_dbus_error_invalid_args(message, NULL);
158 if (wpas_p2p_reject(wpa_s, peer_addr) < 0)
159 return wpas_dbus_error_unknown_error(message,
160 "Failed to call wpas_p2p_reject method.");
166 DBusMessage * wpas_dbus_handler_p2p_listen(DBusMessage *message,
167 struct wpa_supplicant *wpa_s)
169 dbus_int32_t timeout = 0;
171 if (!dbus_message_get_args(message, NULL, DBUS_TYPE_INT32, &timeout,
173 return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
176 if (wpas_p2p_listen(wpa_s, (unsigned int)timeout))
177 return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
184 DBusMessage * wpas_dbus_handler_p2p_extendedlisten(
185 DBusMessage *message, struct wpa_supplicant *wpa_s)
187 unsigned int period = 0, interval = 0;
188 struct wpa_dbus_dict_entry entry;
189 DBusMessageIter iter;
190 DBusMessageIter iter_dict;
192 dbus_message_iter_init(message, &iter);
195 if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
198 while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
199 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
202 if (!os_strcmp(entry.key, "period") &&
203 (entry.type == DBUS_TYPE_INT32))
204 period = entry.uint32_value;
205 else if (!os_strcmp(entry.key, "interval") &&
206 (entry.type == DBUS_TYPE_INT32))
207 interval = entry.uint32_value;
210 wpa_dbus_dict_entry_clear(&entry);
213 if (wpas_p2p_ext_listen(wpa_s, period, interval))
214 return wpas_dbus_error_unknown_error(
215 message, "failed to initiate a p2p_ext_listen.");
220 wpa_dbus_dict_entry_clear(&entry);
222 return wpas_dbus_error_invalid_args(message, entry.key);
226 DBusMessage * wpas_dbus_handler_p2p_presence_request(
227 DBusMessage *message, struct wpa_supplicant *wpa_s)
229 unsigned int dur1 = 0, int1 = 0, dur2 = 0, int2 = 0;
230 struct wpa_dbus_dict_entry entry;
231 DBusMessageIter iter;
232 DBusMessageIter iter_dict;
234 dbus_message_iter_init(message, &iter);
237 if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
240 while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
241 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
244 if (!os_strcmp(entry.key, "duration1") &&
245 (entry.type == DBUS_TYPE_INT32))
246 dur1 = entry.uint32_value;
247 else if (!os_strcmp(entry.key, "interval1") &&
248 entry.type == DBUS_TYPE_INT32)
249 int1 = entry.uint32_value;
250 else if (!os_strcmp(entry.key, "duration2") &&
251 entry.type == DBUS_TYPE_INT32)
252 dur2 = entry.uint32_value;
253 else if (!os_strcmp(entry.key, "interval2") &&
254 entry.type == DBUS_TYPE_INT32)
255 int2 = entry.uint32_value;
259 wpa_dbus_dict_entry_clear(&entry);
261 if (wpas_p2p_presence_req(wpa_s, dur1, int1, dur2, int2) < 0)
262 return wpas_dbus_error_unknown_error(message,
263 "Failed to invoke presence request.");
268 wpa_dbus_dict_entry_clear(&entry);
270 return wpas_dbus_error_invalid_args(message, entry.key);
274 DBusMessage * wpas_dbus_handler_p2p_group_add(DBusMessage *message,
275 struct wpa_supplicant *wpa_s)
277 DBusMessageIter iter_dict;
278 DBusMessage *reply = NULL;
279 DBusMessageIter iter;
280 struct wpa_dbus_dict_entry entry;
281 char *pg_object_path = NULL;
282 int persistent_group = 0;
285 char *net_id_str = NULL;
286 unsigned int group_id = 0;
287 struct wpa_ssid *ssid;
289 dbus_message_iter_init(message, &iter);
291 if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
294 while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
295 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
298 if (!os_strcmp(entry.key, "persistent") &&
299 (entry.type == DBUS_TYPE_BOOLEAN)) {
300 persistent_group = (entry.bool_value == TRUE) ? 1 : 0;
301 } else if (!os_strcmp(entry.key, "frequency") &&
302 (entry.type == DBUS_TYPE_INT32)) {
303 freq = entry.int32_value;
306 } else if (!os_strcmp(entry.key, "persistent_group_object") &&
307 entry.type == DBUS_TYPE_OBJECT_PATH)
308 pg_object_path = os_strdup(entry.str_value);
312 wpa_dbus_dict_entry_clear(&entry);
315 if (pg_object_path != NULL) {
317 * A persistent group Object Path is defined meaning we want
318 * to re-invoke a persistent group.
321 iface = wpas_dbus_new_decompose_object_path(pg_object_path, 1,
324 os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
326 wpas_dbus_error_invalid_args(message,
331 group_id = strtoul(net_id_str, NULL, 10);
332 if (errno == EINVAL) {
333 reply = wpas_dbus_error_invalid_args(
334 message, pg_object_path);
338 /* Get the SSID structure form the persistant group id */
339 ssid = wpa_config_get_network(wpa_s->conf, group_id);
340 if (ssid == NULL || ssid->disabled != 2)
343 if (wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq)) {
344 reply = wpas_dbus_error_unknown_error(
346 "Failed to reinvoke a persistent group");
349 } else if (wpas_p2p_group_add(wpa_s, persistent_group, freq))
353 os_free(pg_object_path);
358 wpa_dbus_dict_entry_clear(&entry);
360 reply = wpas_dbus_error_invalid_args(message, NULL);
365 DBusMessage * wpas_dbus_handler_p2p_disconnect(DBusMessage *message,
366 struct wpa_supplicant *wpa_s)
368 if (wpas_p2p_disconnect(wpa_s))
369 return wpas_dbus_error_unknown_error(message,
370 "failed to disconnect");
376 DBusMessage * wpas_dbus_handler_p2p_flush(DBusMessage *message,
377 struct wpa_supplicant *wpa_s)
379 os_memset(wpa_s->p2p_auth_invite, 0, ETH_ALEN);
380 wpa_s->force_long_sd = 0;
381 p2p_flush(wpa_s->global->p2p);
387 DBusMessage * wpas_dbus_handler_p2p_connect(DBusMessage *message,
388 struct wpa_supplicant *wpa_s)
390 DBusMessageIter iter_dict;
391 DBusMessage *reply = NULL;
392 DBusMessageIter iter;
393 struct wpa_dbus_dict_entry entry;
394 char *peer_object_path = NULL;
395 int persistent_group = 0;
397 int authorize_only = 0;
402 enum p2p_wps_method wps_method = WPS_NOT_READY;
404 char *err_msg = NULL;
407 dbus_message_iter_init(message, &iter);
409 if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
412 while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
413 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
416 if (!os_strcmp(entry.key, "peer") &&
417 (entry.type == DBUS_TYPE_OBJECT_PATH)) {
418 peer_object_path = os_strdup(entry.str_value);
419 } else if (!os_strcmp(entry.key, "persistent") &&
420 (entry.type == DBUS_TYPE_BOOLEAN)) {
421 persistent_group = (entry.bool_value == TRUE) ? 1 : 0;
422 } else if (!os_strcmp(entry.key, "join") &&
423 (entry.type == DBUS_TYPE_BOOLEAN)) {
424 join = (entry.bool_value == TRUE) ? 1 : 0;
425 } else if (!os_strcmp(entry.key, "authorize_only") &&
426 (entry.type == DBUS_TYPE_BOOLEAN)) {
427 authorize_only = (entry.bool_value == TRUE) ? 1 : 0;
428 } else if (!os_strcmp(entry.key, "frequency") &&
429 (entry.type == DBUS_TYPE_INT32)) {
430 freq = entry.int32_value;
433 } else if (!os_strcmp(entry.key, "go_intent") &&
434 (entry.type == DBUS_TYPE_INT32)) {
435 go_intent = entry.int32_value;
436 if ((go_intent < 0) || (go_intent > 15))
438 } else if (!os_strcmp(entry.key, "wps_method") &&
439 (entry.type == DBUS_TYPE_STRING)) {
440 if (!os_strcmp(entry.str_value, "pbc"))
441 wps_method = WPS_PBC;
442 else if (!os_strcmp(entry.str_value, "pin"))
443 wps_method = WPS_PIN_DISPLAY;
444 else if (!os_strcmp(entry.str_value, "label"))
445 wps_method = WPS_PIN_LABEL;
446 else if (!os_strcmp(entry.str_value, "display"))
447 wps_method = WPS_PIN_DISPLAY;
448 else if (!os_strcmp(entry.str_value, "keypad"))
449 wps_method = WPS_PIN_KEYPAD;
452 } else if (!os_strcmp(entry.key, "pin") &&
453 (entry.type == DBUS_TYPE_STRING)) {
454 pin = os_strdup(entry.str_value);
458 wpa_dbus_dict_entry_clear(&entry);
461 if (!peer_object_path || (wps_method == WPS_NOT_READY) ||
462 (parse_peer_object_path(peer_object_path, addr) < 0) ||
463 (p2p_get_peer_info(wpa_s->global->p2p, addr, 0, NULL, 0) < 0))
467 * Validate the wps_method specified and the pin value.
469 if ((!pin || !pin[0]) &&
470 ((wps_method == WPS_PIN_LABEL) || (wps_method == WPS_PIN_KEYPAD)))
473 new_pin = wpas_p2p_connect(wpa_s, addr, pin, wps_method,
474 persistent_group, join, authorize_only,
478 reply = dbus_message_new_method_return(message);
479 dbus_message_append_args(reply, DBUS_TYPE_INT32,
480 &new_pin, DBUS_TYPE_INVALID);
484 err_msg = "connect failed due to channel "
486 iface = WPAS_DBUS_ERROR_CONNECT_CHANNEL_UNAVAILABLE;
490 err_msg = "connect failed due to unsupported channel.";
491 iface = WPAS_DBUS_ERROR_CONNECT_CHANNEL_UNSUPPORTED;
495 err_msg = "connect failed due to unspecified error.";
496 iface = WPAS_DBUS_ERROR_CONNECT_UNSPECIFIED_ERROR;
502 * Do we need specialized errors corresponding to above
503 * error conditions as against just returning a different
506 reply = dbus_message_new_error(message, iface, err_msg);
510 os_free(peer_object_path);
514 wpa_dbus_dict_entry_clear(&entry);
516 reply = wpas_dbus_error_invalid_args(message, NULL);
521 DBusMessage * wpas_dbus_handler_p2p_invite(DBusMessage *message,
522 struct wpa_supplicant *wpa_s)
524 DBusMessageIter iter_dict;
525 DBusMessage *reply = NULL;
526 DBusMessageIter iter;
527 struct wpa_dbus_dict_entry entry;
528 char *peer_object_path = NULL;
529 char *pg_object_path = NULL;
531 char *net_id_str = NULL;
532 u8 peer_addr[ETH_ALEN];
533 unsigned int group_id = 0;
535 struct wpa_ssid *ssid;
537 dbus_message_iter_init(message, &iter);
539 if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
542 while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
543 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
546 if (!os_strcmp(entry.key, "peer") &&
547 (entry.type == DBUS_TYPE_OBJECT_PATH)) {
548 peer_object_path = os_strdup(entry.str_value);
549 wpa_dbus_dict_entry_clear(&entry);
550 } else if (!os_strcmp(entry.key, "persistent_group_object") &&
551 (entry.type == DBUS_TYPE_OBJECT_PATH)) {
552 pg_object_path = os_strdup(entry.str_value);
554 wpa_dbus_dict_entry_clear(&entry);
556 wpa_dbus_dict_entry_clear(&entry);
561 if (!peer_object_path ||
562 (parse_peer_object_path(peer_object_path, peer_addr) < 0) ||
563 (p2p_get_peer_info(wpa_s->global->p2p,
564 peer_addr, 0, NULL, 0) < 0)) {
570 * A group ID is defined meaning we want to re-invoke a
574 iface = wpas_dbus_new_decompose_object_path(pg_object_path, 1,
577 os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
578 reply = wpas_dbus_error_invalid_args(message,
583 group_id = strtoul(net_id_str, NULL, 10);
584 if (errno == EINVAL) {
585 reply = wpas_dbus_error_invalid_args(
586 message, pg_object_path);
590 /* Get the SSID structure form the persistant group id */
591 ssid = wpa_config_get_network(wpa_s->conf, group_id);
592 if (ssid == NULL || ssid->disabled != 2)
595 if (wpas_p2p_invite(wpa_s, peer_addr, ssid, NULL) < 0) {
596 reply = wpas_dbus_error_unknown_error(
598 "Failed to reinvoke a persistent group");
603 * No group ID means propose to a peer to join my active group
605 if (wpas_p2p_invite_group(wpa_s, wpa_s->ifname,
607 reply = wpas_dbus_error_unknown_error(
608 message, "Failed to join to an active group");
614 os_free(pg_object_path);
615 os_free(peer_object_path);
619 reply = wpas_dbus_error_invalid_args(message, NULL);
624 DBusMessage * wpas_dbus_handler_p2p_prov_disc_req(DBusMessage *message,
625 struct wpa_supplicant *wpa_s)
627 DBusMessageIter iter;
628 char *peer_object_path = NULL;
629 char *config_method = NULL;
630 u8 peer_addr[ETH_ALEN];
632 dbus_message_iter_init(message, &iter);
633 dbus_message_iter_get_basic(&iter, &peer_object_path);
635 if (parse_peer_object_path(peer_object_path, peer_addr) < 0)
636 return wpas_dbus_error_invalid_args(message, NULL);
638 dbus_message_iter_next(&iter);
639 dbus_message_iter_get_basic(&iter, &config_method);
642 * Validation checks on config_method are being duplicated here
643 * to be able to return invalid args reply since the error code
644 * from p2p module are not granular enough (yet).
646 if (os_strcmp(config_method, "display") &&
647 os_strcmp(config_method, "keypad") &&
648 os_strcmp(config_method, "pbc") &&
649 os_strcmp(config_method, "pushbutton"))
650 return wpas_dbus_error_invalid_args(message, NULL);
652 if (wpas_p2p_prov_disc(wpa_s, peer_addr, config_method) < 0)
653 return wpas_dbus_error_unknown_error(message,
654 "Failed to send provision discovery request");
661 * P2P Device property accessor methods.
664 dbus_bool_t wpas_dbus_getter_p2p_device_properties(DBusMessageIter *iter,
668 struct wpa_supplicant *wpa_s = user_data;
669 DBusMessageIter variant_iter, dict_iter;
670 DBusMessageIter iter_secdev_dict_entry, iter_secdev_dict_val,
671 iter_secdev_dict_array;
672 const char *dev_name;
673 int num_vendor_extensions = 0;
675 const struct wpabuf *vendor_ext[P2P_MAX_WPS_VENDOR_EXT];
677 if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
678 "a{sv}", &variant_iter) ||
679 !wpa_dbus_dict_open_write(&variant_iter, &dict_iter))
683 dev_name = wpa_s->conf->device_name;
685 !wpa_dbus_dict_append_string(&dict_iter, "DeviceName", dev_name))
688 /* Primary device type */
689 if (!wpa_dbus_dict_append_byte_array(&dict_iter, "PrimaryDeviceType",
690 (char *)wpa_s->conf->device_type,
694 /* Secondary device types */
695 if (wpa_s->conf->num_sec_device_types) {
696 if (!wpa_dbus_dict_begin_array(&dict_iter,
697 "SecondaryDeviceTypes",
698 DBUS_TYPE_ARRAY_AS_STRING
699 DBUS_TYPE_BYTE_AS_STRING,
700 &iter_secdev_dict_entry,
701 &iter_secdev_dict_val,
702 &iter_secdev_dict_array))
705 for (i = 0; i < wpa_s->conf->num_sec_device_types; i++)
706 wpa_dbus_dict_bin_array_add_element(
707 &iter_secdev_dict_array,
708 wpa_s->conf->sec_device_type[i],
711 if (!wpa_dbus_dict_end_array(&dict_iter,
712 &iter_secdev_dict_entry,
713 &iter_secdev_dict_val,
714 &iter_secdev_dict_array))
718 /* Vendor Extensions */
719 for (i = 0; i < P2P_MAX_WPS_VENDOR_EXT; i++) {
720 if (wpa_s->conf->wps_vendor_ext[i] == NULL)
722 vendor_ext[num_vendor_extensions++] =
723 wpa_s->conf->wps_vendor_ext[i];
726 if (num_vendor_extensions &&
727 !wpa_dbus_dict_append_wpabuf_array(&dict_iter,
730 num_vendor_extensions))
734 if (!wpa_dbus_dict_append_uint32(&dict_iter, "GOIntent",
735 wpa_s->conf->p2p_go_intent))
738 /* Persistant Reconnect */
739 if (!wpa_dbus_dict_append_bool(&dict_iter, "PersistantReconnect",
740 wpa_s->conf->persistent_reconnect))
743 /* Listen Reg Class */
744 if (!wpa_dbus_dict_append_uint32(&dict_iter, "ListenRegClass",
745 wpa_s->conf->p2p_listen_reg_class))
749 if (!wpa_dbus_dict_append_uint32(&dict_iter, "ListenChannel",
750 wpa_s->conf->p2p_listen_channel))
754 if (!wpa_dbus_dict_append_uint32(&dict_iter, "OperRegClass",
755 wpa_s->conf->p2p_oper_reg_class))
759 if (!wpa_dbus_dict_append_uint32(&dict_iter, "OperChannel",
760 wpa_s->conf->p2p_oper_channel))
764 if (wpa_s->conf->p2p_ssid_postfix &&
765 !wpa_dbus_dict_append_string(&dict_iter, "SsidPostfix",
766 wpa_s->conf->p2p_ssid_postfix))
770 if (!wpa_dbus_dict_append_bool(&dict_iter, "IntraBss",
771 wpa_s->conf->p2p_intra_bss))
775 if (!wpa_dbus_dict_append_uint32(&dict_iter, "GroupIdle",
776 wpa_s->conf->p2p_group_idle))
779 /* Dissasociation low ack */
780 if (!wpa_dbus_dict_append_uint32(&dict_iter, "disassoc_low_ack",
781 wpa_s->conf->disassoc_low_ack))
784 if (!wpa_dbus_dict_close_write(&variant_iter, &dict_iter) ||
785 !dbus_message_iter_close_container(iter, &variant_iter))
791 dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
796 dbus_bool_t wpas_dbus_setter_p2p_device_properties(DBusMessageIter *iter,
800 struct wpa_supplicant *wpa_s = user_data;
801 DBusMessageIter variant_iter, iter_dict;
802 struct wpa_dbus_dict_entry entry = {.type = DBUS_TYPE_STRING };
805 dbus_message_iter_recurse(iter, &variant_iter);
806 if (!wpa_dbus_dict_open_read(&variant_iter, &iter_dict, error))
809 while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
810 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) {
811 dbus_set_error_const(error, DBUS_ERROR_INVALID_ARGS,
812 "invalid message format");
816 if (os_strcmp(entry.key, "DeviceName") == 0) {
819 if (entry.type != DBUS_TYPE_STRING)
822 devname = os_strdup(entry.str_value);
824 goto err_no_mem_clear;
826 os_free(wpa_s->conf->device_name);
827 wpa_s->conf->device_name = devname;
829 wpa_s->conf->changed_parameters |=
830 CFG_CHANGED_DEVICE_NAME;
831 } else if (os_strcmp(entry.key, "PrimaryDeviceType") == 0) {
832 if (entry.type != DBUS_TYPE_ARRAY ||
833 entry.array_type != DBUS_TYPE_BYTE ||
834 entry.array_len != WPS_DEV_TYPE_LEN)
837 os_memcpy(wpa_s->conf->device_type,
838 entry.bytearray_value,
840 wpa_s->conf->changed_parameters |=
841 CFG_CHANGED_DEVICE_TYPE;
842 } else if (os_strcmp(entry.key, "SecondaryDeviceTypes") == 0) {
843 if (entry.type != DBUS_TYPE_ARRAY ||
844 entry.array_type != WPAS_DBUS_TYPE_BINARRAY ||
845 entry.array_len > MAX_SEC_DEVICE_TYPES)
848 for (i = 0; i < entry.array_len; i++)
849 if (wpabuf_len(entry.binarray_value[i]) !=
851 goto err_no_mem_clear;
852 for (i = 0; i < entry.array_len; i++)
853 os_memcpy(wpa_s->conf->sec_device_type[i],
854 wpabuf_head(entry.binarray_value[i]),
856 wpa_s->conf->num_sec_device_types = entry.array_len;
857 wpa_s->conf->changed_parameters |=
858 CFG_CHANGED_SEC_DEVICE_TYPE;
859 } else if (os_strcmp(entry.key, "VendorExtension") == 0) {
860 if ((entry.type != DBUS_TYPE_ARRAY) ||
861 (entry.array_type != WPAS_DBUS_TYPE_BINARRAY) ||
862 (entry.array_len > P2P_MAX_WPS_VENDOR_EXT))
865 wpa_s->conf->changed_parameters |=
866 CFG_CHANGED_VENDOR_EXTENSION;
868 for (i = 0; i < P2P_MAX_WPS_VENDOR_EXT; i++) {
869 wpabuf_free(wpa_s->conf->wps_vendor_ext[i]);
870 if (i < entry.array_len) {
871 wpa_s->conf->wps_vendor_ext[i] =
872 entry.binarray_value[i];
873 entry.binarray_value[i] = NULL;
875 wpa_s->conf->wps_vendor_ext[i] = NULL;
877 } else if ((os_strcmp(entry.key, "GOIntent") == 0) &&
878 (entry.type == DBUS_TYPE_UINT32) &&
879 (entry.uint32_value <= 15))
880 wpa_s->conf->p2p_go_intent = entry.uint32_value;
881 else if ((os_strcmp(entry.key, "PersistantReconnect") == 0) &&
882 (entry.type == DBUS_TYPE_BOOLEAN))
883 wpa_s->conf->persistent_reconnect = entry.bool_value;
884 else if ((os_strcmp(entry.key, "ListenRegClass") == 0) &&
885 (entry.type == DBUS_TYPE_UINT32)) {
886 wpa_s->conf->p2p_listen_reg_class = entry.uint32_value;
887 wpa_s->conf->changed_parameters |=
888 CFG_CHANGED_P2P_LISTEN_CHANNEL;
889 } else if ((os_strcmp(entry.key, "ListenChannel") == 0) &&
890 (entry.type == DBUS_TYPE_UINT32)) {
891 wpa_s->conf->p2p_listen_channel = entry.uint32_value;
892 wpa_s->conf->changed_parameters |=
893 CFG_CHANGED_P2P_LISTEN_CHANNEL;
894 } else if ((os_strcmp(entry.key, "OperRegClass") == 0) &&
895 (entry.type == DBUS_TYPE_UINT32)) {
896 wpa_s->conf->p2p_oper_reg_class = entry.uint32_value;
897 wpa_s->conf->changed_parameters |=
898 CFG_CHANGED_P2P_OPER_CHANNEL;
899 } else if ((os_strcmp(entry.key, "OperChannel") == 0) &&
900 (entry.type == DBUS_TYPE_UINT32)) {
901 wpa_s->conf->p2p_oper_channel = entry.uint32_value;
902 wpa_s->conf->changed_parameters |=
903 CFG_CHANGED_P2P_OPER_CHANNEL;
904 } else if (os_strcmp(entry.key, "SsidPostfix") == 0) {
907 if (entry.type != DBUS_TYPE_STRING)
910 postfix = os_strdup(entry.str_value);
912 goto err_no_mem_clear;
914 os_free(wpa_s->conf->p2p_ssid_postfix);
915 wpa_s->conf->p2p_ssid_postfix = postfix;
917 wpa_s->conf->changed_parameters |=
918 CFG_CHANGED_P2P_SSID_POSTFIX;
919 } else if ((os_strcmp(entry.key, "IntraBss") == 0) &&
920 (entry.type == DBUS_TYPE_BOOLEAN)) {
921 wpa_s->conf->p2p_intra_bss = entry.bool_value;
922 wpa_s->conf->changed_parameters |=
923 CFG_CHANGED_P2P_INTRA_BSS;
924 } else if ((os_strcmp(entry.key, "GroupIdle") == 0) &&
925 (entry.type == DBUS_TYPE_UINT32))
926 wpa_s->conf->p2p_group_idle = entry.uint32_value;
927 else if (os_strcmp(entry.key, "disassoc_low_ack") == 0 &&
928 entry.type == DBUS_TYPE_UINT32)
929 wpa_s->conf->disassoc_low_ack = entry.uint32_value;
933 wpa_dbus_dict_entry_clear(&entry);
936 if (wpa_s->conf->changed_parameters) {
937 /* Some changed parameters requires to update config*/
938 wpa_supplicant_update_config(wpa_s);
944 dbus_set_error_const(error, DBUS_ERROR_INVALID_ARGS,
945 "invalid message format");
946 wpa_dbus_dict_entry_clear(&entry);
950 dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
951 wpa_dbus_dict_entry_clear(&entry);
956 dbus_bool_t wpas_dbus_getter_p2p_peers(DBusMessageIter *iter, DBusError *error,
959 struct wpa_supplicant *wpa_s = user_data;
960 struct p2p_data *p2p = wpa_s->global->p2p;
962 int num = 0, out_of_mem = 0;
964 const struct p2p_peer_info *peer_info = NULL;
965 dbus_bool_t success = FALSE;
967 struct dl_list peer_objpath_list;
968 struct peer_objpath_node {
970 char path[WPAS_DBUS_OBJECT_PATH_MAX];
973 char **peer_obj_paths = NULL;
975 dl_list_init(&peer_objpath_list);
977 /* Get the first peer info */
978 peer_info = p2p_get_peer_found(p2p, NULL, next);
980 /* Get next and accumulate them */
982 while (peer_info != NULL) {
983 node = os_zalloc(sizeof(struct peer_objpath_node));
989 addr = peer_info->p2p_device_addr;
990 os_snprintf(node->path, WPAS_DBUS_OBJECT_PATH_MAX,
991 "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART
993 wpa_s->dbus_new_path, MAC2STR(addr));
994 dl_list_add_tail(&peer_objpath_list, &node->list);
997 peer_info = p2p_get_peer_found(p2p, addr, next);
1001 * Now construct the peer object paths in a form suitable for
1002 * array_property_getter helper below.
1004 peer_obj_paths = os_zalloc(num * sizeof(char *));
1006 if (!peer_obj_paths) {
1011 dl_list_for_each_safe(node, tmp, &peer_objpath_list,
1012 struct peer_objpath_node, list)
1013 peer_obj_paths[i++] = node->path;
1015 success = wpas_dbus_simple_array_property_getter(iter,
1016 DBUS_TYPE_OBJECT_PATH,
1017 peer_obj_paths, num,
1022 os_free(peer_obj_paths);
1024 dl_list_for_each_safe(node, tmp, &peer_objpath_list,
1025 struct peer_objpath_node, list) {
1026 dl_list_del(&node->list);
1030 dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
1036 enum wpas_p2p_role {
1037 WPAS_P2P_ROLE_DEVICE,
1039 WPAS_P2P_ROLE_CLIENT,
1042 static enum wpas_p2p_role wpas_get_p2p_role(struct wpa_supplicant *wpa_s)
1044 struct wpa_ssid *ssid = wpa_s->current_ssid;
1047 return WPAS_P2P_ROLE_DEVICE;
1048 if (wpa_s->wpa_state != WPA_COMPLETED)
1049 return WPAS_P2P_ROLE_DEVICE;
1051 switch (ssid->mode) {
1052 case WPAS_MODE_P2P_GO:
1053 case WPAS_MODE_P2P_GROUP_FORMATION:
1054 return WPAS_P2P_ROLE_GO;
1055 case WPAS_MODE_INFRA:
1056 if (ssid->p2p_group)
1057 return WPAS_P2P_ROLE_CLIENT;
1058 return WPAS_P2P_ROLE_DEVICE;
1060 return WPAS_P2P_ROLE_DEVICE;
1065 dbus_bool_t wpas_dbus_getter_p2p_role(DBusMessageIter *iter, DBusError *error,
1068 struct wpa_supplicant *wpa_s = user_data;
1071 switch (wpas_get_p2p_role(wpa_s)) {
1072 case WPAS_P2P_ROLE_GO:
1075 case WPAS_P2P_ROLE_CLIENT:
1082 return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING, &str,
1087 dbus_bool_t wpas_dbus_getter_p2p_group(DBusMessageIter *iter, DBusError *error,
1090 struct wpa_supplicant *wpa_s = user_data;
1092 if (wpa_s->dbus_groupobj_path == NULL)
1095 return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_OBJECT_PATH,
1096 &wpa_s->dbus_groupobj_path,
1101 dbus_bool_t wpas_dbus_getter_p2p_peergo(DBusMessageIter *iter,
1102 DBusError *error, void *user_data)
1104 struct wpa_supplicant *wpa_s = user_data;
1105 char go_peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path;
1107 if (wpas_get_p2p_role(wpa_s) != WPAS_P2P_ROLE_CLIENT)
1110 os_snprintf(go_peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
1111 "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/" COMPACT_MACSTR,
1112 wpa_s->dbus_new_path, MAC2STR(wpa_s->go_dev_addr));
1113 path = go_peer_obj_path;
1114 return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_OBJECT_PATH,
1120 * Peer object properties accessor methods
1123 dbus_bool_t wpas_dbus_getter_p2p_peer_properties(DBusMessageIter *iter,
1124 DBusError *error, void *user_data)
1126 struct peer_handler_args *peer_args = user_data;
1127 DBusMessageIter variant_iter, dict_iter;
1128 const struct p2p_peer_info *info = NULL;
1129 char devtype[WPS_DEV_TYPE_BUFSIZE];
1130 const struct wpabuf *vendor_extension[P2P_MAX_WPS_VENDOR_EXT];
1133 /* get the peer info */
1134 info = p2p_get_peer_found(peer_args->wpa_s->global->p2p,
1135 peer_args->p2p_device_addr, 0);
1137 dbus_set_error(error, DBUS_ERROR_FAILED, "failed to find peer");
1141 if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
1142 "a{sv}", &variant_iter) ||
1143 !wpa_dbus_dict_open_write(&variant_iter, &dict_iter))
1146 /* Fill out the dictionary */
1147 wps_dev_type_bin2str(info->pri_dev_type, devtype, sizeof(devtype));
1148 if (!wpa_dbus_dict_append_string(&dict_iter, "DeviceName",
1151 if (!wpa_dbus_dict_append_string(&dict_iter, "PrimaryDeviceType",
1154 if (!wpa_dbus_dict_append_uint16(&dict_iter, "config_method",
1155 info->config_methods))
1157 if (!wpa_dbus_dict_append_int32(&dict_iter, "level",
1160 if (!wpa_dbus_dict_append_byte(&dict_iter, "devicecapability",
1163 if (!wpa_dbus_dict_append_byte(&dict_iter, "groupcapability",
1167 if (info->wps_sec_dev_type_list_len) {
1168 char *sec_dev_types[MAX_SEC_DEVICE_TYPES];
1169 u8 *sec_dev_type_list = NULL;
1170 char secdevtype[WPS_DEV_TYPE_BUFSIZE];
1171 int num_sec_dev_types = 0;
1173 sec_dev_type_list = os_zalloc(info->wps_sec_dev_type_list_len);
1175 if (sec_dev_type_list == NULL)
1178 os_memcpy(sec_dev_type_list, info->wps_sec_dev_type_list,
1179 info->wps_sec_dev_type_list_len);
1181 for (i = 0; i < MAX_SEC_DEVICE_TYPES &&
1182 i < (int) (info->wps_sec_dev_type_list_len /
1185 sec_dev_types[i] = os_zalloc(sizeof(secdevtype));
1187 if (!sec_dev_types[i] ||
1188 wps_dev_type_bin2str(
1189 &sec_dev_type_list[i * WPS_DEV_TYPE_LEN],
1191 sizeof(secdevtype)) == NULL) {
1193 os_free(sec_dev_types[i]);
1194 os_free(sec_dev_type_list);
1198 num_sec_dev_types++;
1201 os_free(sec_dev_type_list);
1203 if (num_sec_dev_types) {
1204 if (!wpa_dbus_dict_append_string_array(&dict_iter,
1205 "SecondaryDeviceTypes",
1206 (const char **)sec_dev_types,
1207 num_sec_dev_types)) {
1208 for (i = 0; i < num_sec_dev_types; i++)
1209 os_free(sec_dev_types[i]);
1213 for (i = 0; i < num_sec_dev_types; i++)
1214 os_free(sec_dev_types[i]);
1218 /* Add WPS vendor extensions attribute */
1219 for (i = 0, num = 0; i < P2P_MAX_WPS_VENDOR_EXT; i++) {
1220 if (info->wps_vendor_ext[i] == NULL)
1222 vendor_extension[num] = info->wps_vendor_ext[i];
1226 if (!wpa_dbus_dict_append_wpabuf_array(&dict_iter, "VendorExtension",
1227 vendor_extension, num))
1230 if (!wpa_dbus_dict_close_write(&variant_iter, &dict_iter) ||
1231 !dbus_message_iter_close_container(iter, &variant_iter))
1237 dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
1242 dbus_bool_t wpas_dbus_getter_p2p_peer_ies(DBusMessageIter *iter,
1243 DBusError *error, void *user_data)
1245 /* struct peer_handler_args *peer_args = user_data; */
1247 dbus_set_error_const(error, DBUS_ERROR_FAILED, "not implemented");
1253 * wpas_dbus_getter_persistent_groups - Get array of peristent group objects
1254 * @iter: Pointer to incoming dbus message iter
1255 * @error: Location to store error on failure
1256 * @user_data: Function specific data
1257 * Returns: TRUE on success, FALSE on failure
1259 * Getter for "PersistentGroups" property.
1261 dbus_bool_t wpas_dbus_getter_persistent_groups(DBusMessageIter *iter,
1265 struct wpa_supplicant *wpa_s = user_data;
1266 struct wpa_ssid *ssid;
1268 unsigned int i = 0, num = 0;
1269 dbus_bool_t success = FALSE;
1271 if (wpa_s->conf == NULL) {
1272 wpa_printf(MSG_ERROR, "dbus: %s: "
1273 "An error occurred getting persistent groups list",
1275 dbus_set_error_const(error, DBUS_ERROR_FAILED, "an error "
1276 "occurred getting persistent groups list");
1280 for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next)
1281 if (network_is_persistent_group(ssid))
1284 paths = os_zalloc(num * sizeof(char *));
1286 dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
1290 /* Loop through configured networks and append object path of each */
1291 for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
1292 if (!network_is_persistent_group(ssid))
1294 paths[i] = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX);
1295 if (paths[i] == NULL) {
1296 dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY,
1300 /* Construct the object path for this network. */
1301 os_snprintf(paths[i++], WPAS_DBUS_OBJECT_PATH_MAX,
1302 "%s/" WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART "/%d",
1303 wpa_s->dbus_new_path, ssid->id);
1306 success = wpas_dbus_simple_array_property_getter(iter,
1307 DBUS_TYPE_OBJECT_PATH,
1312 os_free(paths[--i]);
1319 * wpas_dbus_getter_persistent_group_properties - Get options for a persistent
1321 * @iter: Pointer to incoming dbus message iter
1322 * @error: Location to store error on failure
1323 * @user_data: Function specific data
1324 * Returns: TRUE on success, FALSE on failure
1326 * Getter for "Properties" property of a persistent group.
1328 dbus_bool_t wpas_dbus_getter_persistent_group_properties(DBusMessageIter *iter,
1332 struct network_handler_args *net = user_data;
1334 /* Leveraging the fact that persistent group object is still
1335 * represented in same manner as network within.
1337 return wpas_dbus_getter_network_properties(iter, error, net);
1342 * wpas_dbus_setter_persistent_group_properties - Get options for a persistent
1344 * @iter: Pointer to incoming dbus message iter
1345 * @error: Location to store error on failure
1346 * @user_data: Function specific data
1347 * Returns: TRUE on success, FALSE on failure
1349 * Setter for "Properties" property of a persistent group.
1351 dbus_bool_t wpas_dbus_setter_persistent_group_properties(DBusMessageIter *iter,
1355 struct network_handler_args *net = user_data;
1356 struct wpa_ssid *ssid = net->ssid;
1357 DBusMessageIter variant_iter;
1360 * Leveraging the fact that persistent group object is still
1361 * represented in same manner as network within.
1363 dbus_message_iter_recurse(iter, &variant_iter);
1364 return set_network_properties(net->wpa_s, ssid, &variant_iter, error);
1369 * wpas_dbus_new_iface_add_persistent_group - Add a new configured
1371 * @message: Pointer to incoming dbus message
1372 * @wpa_s: wpa_supplicant structure for a network interface
1373 * Returns: A dbus message containing the object path of the new
1376 * Handler function for "AddPersistentGroup" method call of a P2P Device
1379 DBusMessage * wpas_dbus_handler_add_persistent_group(
1380 DBusMessage *message, struct wpa_supplicant *wpa_s)
1382 DBusMessage *reply = NULL;
1383 DBusMessageIter iter;
1384 struct wpa_ssid *ssid = NULL;
1385 char path_buf[WPAS_DBUS_OBJECT_PATH_MAX], *path = path_buf;
1388 dbus_message_iter_init(message, &iter);
1390 ssid = wpa_config_add_network(wpa_s->conf);
1392 wpa_printf(MSG_ERROR, "dbus: %s: "
1393 "Cannot add new persistent group", __func__);
1394 reply = wpas_dbus_error_unknown_error(
1396 "wpa_supplicant could not add "
1397 "a persistent group on this interface.");
1401 /* Mark the ssid as being a persistent group before the notification */
1403 ssid->p2p_persistent_group = 1;
1404 wpas_notify_persistent_group_added(wpa_s, ssid);
1406 wpa_config_set_network_defaults(ssid);
1408 dbus_error_init(&error);
1409 if (!set_network_properties(wpa_s, ssid, &iter, &error)) {
1410 wpa_printf(MSG_DEBUG, "dbus: %s: "
1411 "Control interface could not set persistent group "
1412 "properties", __func__);
1413 reply = wpas_dbus_reply_new_from_error(message, &error,
1414 DBUS_ERROR_INVALID_ARGS,
1415 "Failed to set network "
1417 dbus_error_free(&error);
1421 /* Construct the object path for this network. */
1422 os_snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX,
1423 "%s/" WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART "/%d",
1424 wpa_s->dbus_new_path, ssid->id);
1426 reply = dbus_message_new_method_return(message);
1427 if (reply == NULL) {
1428 reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
1432 if (!dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &path,
1433 DBUS_TYPE_INVALID)) {
1434 dbus_message_unref(reply);
1435 reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
1444 wpas_notify_persistent_group_removed(wpa_s, ssid);
1445 wpa_config_remove_network(wpa_s->conf, ssid->id);
1452 * wpas_dbus_handler_remove_persistent_group - Remove a configured persistent
1454 * @message: Pointer to incoming dbus message
1455 * @wpa_s: wpa_supplicant structure for a network interface
1456 * Returns: NULL on success or dbus error on failure
1458 * Handler function for "RemovePersistentGroup" method call of a P2P Device
1461 DBusMessage * wpas_dbus_handler_remove_persistent_group(
1462 DBusMessage *message, struct wpa_supplicant *wpa_s)
1464 DBusMessage *reply = NULL;
1466 char *iface = NULL, *persistent_group_id = NULL;
1468 struct wpa_ssid *ssid;
1470 dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &op,
1474 * Extract the network ID and ensure the network is actually a child of
1477 iface = wpas_dbus_new_decompose_object_path(op, 1,
1478 &persistent_group_id,
1480 if (iface == NULL || os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
1481 reply = wpas_dbus_error_invalid_args(message, op);
1485 id = strtoul(persistent_group_id, NULL, 10);
1486 if (errno == EINVAL) {
1487 reply = wpas_dbus_error_invalid_args(message, op);
1491 ssid = wpa_config_get_network(wpa_s->conf, id);
1493 reply = wpas_dbus_error_persistent_group_unknown(message);
1497 wpas_notify_persistent_group_removed(wpa_s, ssid);
1499 if (wpa_config_remove_network(wpa_s->conf, id) < 0) {
1500 wpa_printf(MSG_ERROR, "dbus: %s: "
1501 "error occurred when removing persistent group %d",
1503 reply = wpas_dbus_error_unknown_error(
1505 "error removing the specified persistent group on "
1512 os_free(persistent_group_id);
1517 static void remove_persistent_group(struct wpa_supplicant *wpa_s,
1518 struct wpa_ssid *ssid)
1520 wpas_notify_persistent_group_removed(wpa_s, ssid);
1522 if (wpa_config_remove_network(wpa_s->conf, ssid->id) < 0) {
1523 wpa_printf(MSG_ERROR, "dbus: %s: "
1524 "error occurred when removing persistent group %d",
1525 __func__, ssid->id);
1532 * wpas_dbus_handler_remove_all_persistent_groups - Remove all configured
1534 * @message: Pointer to incoming dbus message
1535 * @wpa_s: wpa_supplicant structure for a network interface
1536 * Returns: NULL on success or dbus error on failure
1538 * Handler function for "RemoveAllPersistentGroups" method call of a
1539 * P2P Device interface.
1541 DBusMessage * wpas_dbus_handler_remove_all_persistent_groups(
1542 DBusMessage *message, struct wpa_supplicant *wpa_s)
1544 struct wpa_ssid *ssid, *next;
1545 struct wpa_config *config;
1547 config = wpa_s->conf;
1548 ssid = config->ssid;
1551 if (network_is_persistent_group(ssid))
1552 remove_persistent_group(wpa_s, ssid);
1560 * Group object properties accessor methods
1563 dbus_bool_t wpas_dbus_getter_p2p_group_members(DBusMessageIter *iter,
1567 struct wpa_supplicant *wpa_s = user_data;
1568 struct wpa_ssid *ssid;
1569 unsigned int num_members;
1574 dbus_bool_t success = FALSE;
1576 /* Ensure we are a GO */
1577 if (wpa_s->wpa_state != WPA_COMPLETED)
1580 ssid = wpa_s->conf->ssid;
1581 /* At present WPAS P2P_GO mode only applicable for p2p_go */
1582 if (ssid->mode != WPAS_MODE_P2P_GO &&
1583 ssid->mode != WPAS_MODE_AP &&
1584 ssid->mode != WPAS_MODE_P2P_GROUP_FORMATION)
1587 num_members = p2p_get_group_num_members(wpa_s->p2p_group);
1589 paths = os_zalloc(num_members * sizeof(char *));
1594 while ((addr = p2p_iterate_group_members(wpa_s->p2p_group, &next))) {
1595 paths[i] = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX);
1598 os_snprintf(paths[i], WPAS_DBUS_OBJECT_PATH_MAX,
1599 "%s/" WPAS_DBUS_NEW_P2P_GROUPMEMBERS_PART
1601 wpa_s->dbus_groupobj_path, MAC2STR(addr));
1605 success = wpas_dbus_simple_array_property_getter(iter,
1606 DBUS_TYPE_OBJECT_PATH,
1610 for (i = 0; i < num_members; i++)
1616 dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
1618 for (i = 0; i < num_members; i++)
1626 dbus_bool_t wpas_dbus_getter_p2p_group_properties(DBusMessageIter *iter,
1630 struct wpa_supplicant *wpa_s = user_data;
1631 DBusMessageIter variant_iter, dict_iter;
1632 struct hostapd_data *hapd = wpa_s->ap_iface->bss[0];
1633 const struct wpabuf *vendor_ext[MAX_WPS_VENDOR_EXTENSIONS];
1634 int num_vendor_ext = 0;
1638 dbus_set_error_const(error, DBUS_ERROR_FAILED,
1643 if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
1644 "a{sv}", &variant_iter) ||
1645 !wpa_dbus_dict_open_write(&variant_iter, &dict_iter))
1648 /* Parse WPS Vendor Extensions sent in Beacon/Probe Response */
1649 for (i = 0; i < MAX_WPS_VENDOR_EXTENSIONS; i++) {
1650 if (hapd->conf->wps_vendor_ext[i] == NULL)
1652 vendor_ext[num_vendor_ext++] = hapd->conf->wps_vendor_ext[i];
1655 if (!wpa_dbus_dict_append_wpabuf_array(&dict_iter,
1656 "WPSVendorExtensions",
1657 vendor_ext, num_vendor_ext))
1660 if (!wpa_dbus_dict_close_write(&variant_iter, &dict_iter) ||
1661 !dbus_message_iter_close_container(iter, &variant_iter))
1667 dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
1672 dbus_bool_t wpas_dbus_setter_p2p_group_properties(DBusMessageIter *iter,
1676 struct wpa_supplicant *wpa_s = user_data;
1677 DBusMessageIter variant_iter, iter_dict;
1678 struct wpa_dbus_dict_entry entry = { .type = DBUS_TYPE_STRING };
1680 struct hostapd_data *hapd = wpa_s->ap_iface->bss[0];
1683 dbus_set_error_const(error, DBUS_ERROR_FAILED,
1688 dbus_message_iter_recurse(iter, &variant_iter);
1689 if (!wpa_dbus_dict_open_read(&variant_iter, &iter_dict, error))
1692 while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
1693 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) {
1694 dbus_set_error_const(error, DBUS_ERROR_INVALID_ARGS,
1695 "invalid message format");
1699 if (os_strcmp(entry.key, "WPSVendorExtensions") == 0) {
1700 if (entry.type != DBUS_TYPE_ARRAY ||
1701 entry.array_type != WPAS_DBUS_TYPE_BINARRAY ||
1702 entry.array_len > MAX_WPS_VENDOR_EXTENSIONS)
1705 for (i = 0; i < MAX_WPS_VENDOR_EXTENSIONS; i++) {
1706 if (i < entry.array_len) {
1707 hapd->conf->wps_vendor_ext[i] =
1708 entry.binarray_value[i];
1709 entry.binarray_value[i] = NULL;
1711 hapd->conf->wps_vendor_ext[i] = NULL;
1714 hostapd_update_wps(hapd);
1718 wpa_dbus_dict_entry_clear(&entry);
1724 wpa_dbus_dict_entry_clear(&entry);
1725 dbus_set_error_const(error, DBUS_ERROR_INVALID_ARGS,
1726 "invalid message format");
1731 DBusMessage * wpas_dbus_handler_p2p_add_service(DBusMessage *message,
1732 struct wpa_supplicant *wpa_s)
1734 DBusMessageIter iter_dict;
1735 DBusMessage *reply = NULL;
1736 DBusMessageIter iter;
1737 struct wpa_dbus_dict_entry entry;
1740 char *service = NULL;
1741 struct wpabuf *query = NULL;
1742 struct wpabuf *resp = NULL;
1745 dbus_message_iter_init(message, &iter);
1747 if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
1750 if (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
1751 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
1754 if (!os_strcmp(entry.key, "service_type") &&
1755 (entry.type == DBUS_TYPE_STRING)) {
1756 if (!os_strcmp(entry.str_value, "upnp"))
1758 else if (!os_strcmp(entry.str_value, "bonjour"))
1762 wpa_dbus_dict_entry_clear(&entry);
1767 while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
1768 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
1771 if (!os_strcmp(entry.key, "version") &&
1772 entry.type == DBUS_TYPE_INT32)
1773 version = entry.uint32_value;
1774 else if (!os_strcmp(entry.key, "service") &&
1775 entry.type == DBUS_TYPE_STRING)
1776 service = os_strdup(entry.str_value);
1777 wpa_dbus_dict_entry_clear(&entry);
1779 if (version <= 0 || service == NULL)
1782 if (wpas_p2p_service_add_upnp(wpa_s, version, service) != 0)
1786 } else if (bonjour == 1) {
1787 while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
1788 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
1791 if (!os_strcmp(entry.key, "query")) {
1792 if ((entry.type != DBUS_TYPE_ARRAY) ||
1793 (entry.array_type != DBUS_TYPE_BYTE))
1795 query = wpabuf_alloc_copy(
1796 entry.bytearray_value,
1798 } else if (!os_strcmp(entry.key, "response")) {
1799 if ((entry.type != DBUS_TYPE_ARRAY) ||
1800 (entry.array_type != DBUS_TYPE_BYTE))
1802 resp = wpabuf_alloc_copy(entry.bytearray_value,
1806 wpa_dbus_dict_entry_clear(&entry);
1809 if (query == NULL || resp == NULL)
1812 if (wpas_p2p_service_add_bonjour(wpa_s, query, resp) < 0) {
1822 wpa_dbus_dict_entry_clear(&entry);
1824 return wpas_dbus_error_invalid_args(message, NULL);
1828 DBusMessage * wpas_dbus_handler_p2p_delete_service(
1829 DBusMessage *message, struct wpa_supplicant *wpa_s)
1831 DBusMessageIter iter_dict;
1832 DBusMessage *reply = NULL;
1833 DBusMessageIter iter;
1834 struct wpa_dbus_dict_entry entry;
1838 char *service = NULL;
1839 struct wpabuf *query = NULL;
1842 dbus_message_iter_init(message, &iter);
1844 if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
1847 if (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
1848 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
1851 if (!os_strcmp(entry.key, "service_type") &&
1852 (entry.type == DBUS_TYPE_STRING)) {
1853 if (!os_strcmp(entry.str_value, "upnp"))
1855 else if (!os_strcmp(entry.str_value, "bonjour"))
1859 wpa_dbus_dict_entry_clear(&entry);
1863 while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
1864 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
1866 if (!os_strcmp(entry.key, "version") &&
1867 entry.type == DBUS_TYPE_INT32)
1868 version = entry.uint32_value;
1869 else if (!os_strcmp(entry.key, "service") &&
1870 entry.type == DBUS_TYPE_STRING)
1871 service = os_strdup(entry.str_value);
1875 wpa_dbus_dict_entry_clear(&entry);
1878 if (version <= 0 || service == NULL)
1881 ret = wpas_p2p_service_del_upnp(wpa_s, version, service);
1885 } else if (bonjour == 1) {
1886 while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
1887 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
1890 if (!os_strcmp(entry.key, "query")) {
1891 if ((entry.type != DBUS_TYPE_ARRAY) ||
1892 (entry.array_type != DBUS_TYPE_BYTE))
1894 query = wpabuf_alloc_copy(
1895 entry.bytearray_value,
1900 wpa_dbus_dict_entry_clear(&entry);
1906 ret = wpas_p2p_service_del_bonjour(wpa_s, query);
1915 wpa_dbus_dict_entry_clear(&entry);
1917 return wpas_dbus_error_invalid_args(message, NULL);
1921 DBusMessage * wpas_dbus_handler_p2p_flush_service(DBusMessage *message,
1922 struct wpa_supplicant *wpa_s)
1924 wpas_p2p_service_flush(wpa_s);
1929 DBusMessage * wpas_dbus_handler_p2p_service_sd_req(
1930 DBusMessage *message, struct wpa_supplicant *wpa_s)
1932 DBusMessageIter iter_dict;
1933 DBusMessage *reply = NULL;
1934 DBusMessageIter iter;
1935 struct wpa_dbus_dict_entry entry;
1937 char *service = NULL;
1938 char *peer_object_path = NULL;
1939 struct wpabuf *tlv = NULL;
1944 dbus_message_iter_init(message, &iter);
1946 if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
1949 while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
1950 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
1952 if (!os_strcmp(entry.key, "peer_object") &&
1953 entry.type == DBUS_TYPE_OBJECT_PATH) {
1954 peer_object_path = os_strdup(entry.str_value);
1955 } else if (!os_strcmp(entry.key, "service_type") &&
1956 entry.type == DBUS_TYPE_STRING) {
1957 if (!os_strcmp(entry.str_value, "upnp"))
1961 } else if (!os_strcmp(entry.key, "version") &&
1962 entry.type == DBUS_TYPE_INT32) {
1963 version = entry.uint32_value;
1964 } else if (!os_strcmp(entry.key, "service") &&
1965 entry.type == DBUS_TYPE_STRING) {
1966 service = os_strdup(entry.str_value);
1967 } else if (!os_strcmp(entry.key, "tlv")) {
1968 if (entry.type != DBUS_TYPE_ARRAY ||
1969 entry.array_type != DBUS_TYPE_BYTE)
1971 tlv = wpabuf_alloc_copy(entry.bytearray_value,
1976 wpa_dbus_dict_entry_clear(&entry);
1979 if (!peer_object_path ||
1980 (parse_peer_object_path(peer_object_path, addr) < 0) ||
1981 (p2p_get_peer_info(wpa_s->global->p2p, addr, 0, NULL, 0) < 0))
1985 if (version <= 0 || service == NULL)
1988 ref = (unsigned long) wpas_p2p_sd_request_upnp(wpa_s, addr,
1994 ref = (unsigned long)wpas_p2p_sd_request(wpa_s, addr, tlv);
1999 reply = dbus_message_new_method_return(message);
2000 dbus_message_append_args(reply, DBUS_TYPE_UINT64,
2001 &ref, DBUS_TYPE_INVALID);
2003 reply = wpas_dbus_error_unknown_error(
2004 message, "Unable to send SD request");
2008 os_free(peer_object_path);
2011 wpa_dbus_dict_entry_clear(&entry);
2015 reply = wpas_dbus_error_invalid_args(message, NULL);
2020 DBusMessage * wpas_dbus_handler_p2p_service_sd_res(
2021 DBusMessage *message, struct wpa_supplicant *wpa_s)
2023 DBusMessageIter iter_dict;
2024 DBusMessage *reply = NULL;
2025 DBusMessageIter iter;
2026 struct wpa_dbus_dict_entry entry;
2027 char *peer_object_path = NULL;
2028 struct wpabuf *tlv = NULL;
2033 dbus_message_iter_init(message, &iter);
2035 if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
2038 while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
2039 if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
2042 if (!os_strcmp(entry.key, "peer_object") &&
2043 entry.type == DBUS_TYPE_OBJECT_PATH) {
2044 peer_object_path = os_strdup(entry.str_value);
2045 } else if (!os_strcmp(entry.key, "frequency") &&
2046 entry.type == DBUS_TYPE_INT32) {
2047 freq = entry.uint32_value;
2048 } else if (!os_strcmp(entry.key, "dialog_token") &&
2049 entry.type == DBUS_TYPE_UINT32) {
2050 dlg_tok = entry.uint32_value;
2051 } else if (!os_strcmp(entry.key, "tlvs")) {
2052 if (entry.type != DBUS_TYPE_ARRAY ||
2053 entry.array_type != DBUS_TYPE_BYTE)
2055 tlv = wpabuf_alloc_copy(entry.bytearray_value,
2060 wpa_dbus_dict_entry_clear(&entry);
2062 if (!peer_object_path ||
2063 (parse_peer_object_path(peer_object_path, addr) < 0) ||
2064 (p2p_get_peer_info(wpa_s->global->p2p, addr, 0, NULL, 0) < 0))
2070 wpas_p2p_sd_response(wpa_s, freq, addr, (u8) dlg_tok, tlv);
2073 os_free(peer_object_path);
2076 wpa_dbus_dict_entry_clear(&entry);
2078 reply = wpas_dbus_error_invalid_args(message, NULL);
2083 DBusMessage * wpas_dbus_handler_p2p_service_sd_cancel_req(
2084 DBusMessage *message, struct wpa_supplicant *wpa_s)
2086 DBusMessageIter iter;
2089 dbus_message_iter_init(message, &iter);
2090 dbus_message_iter_get_basic(&iter, &req);
2095 if (!wpas_p2p_sd_cancel_request(wpa_s, (void *)(unsigned long) req))
2100 return wpas_dbus_error_invalid_args(message, NULL);
2104 DBusMessage * wpas_dbus_handler_p2p_service_update(
2105 DBusMessage *message, struct wpa_supplicant *wpa_s)
2107 wpas_p2p_sd_service_update(wpa_s);
2112 DBusMessage * wpas_dbus_handler_p2p_serv_disc_external(
2113 DBusMessage *message, struct wpa_supplicant *wpa_s)
2115 DBusMessageIter iter;
2118 dbus_message_iter_init(message, &iter);
2119 dbus_message_iter_get_basic(&iter, &ext);
2121 wpa_s->p2p_sd_over_ctrl_iface = ext;