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
))
104 os_free(req_dev_types
);
106 os_malloc(WPS_DEV_TYPE_LEN
* entry
.array_len
);
110 for (i
= 0; i
< entry
.array_len
; i
++) {
111 if (wpabuf_len(entry
.binarray_value
[i
]) !=
114 os_memcpy(req_dev_types
+ i
* WPS_DEV_TYPE_LEN
,
115 wpabuf_head(entry
.binarray_value
[i
]),
118 num_req_dev_types
= entry
.array_len
;
119 } else if (!os_strcmp(entry
.key
, "DiscoveryType") &&
120 (entry
.type
== DBUS_TYPE_STRING
)) {
121 if (!os_strcmp(entry
.str_value
, "start_with_full"))
122 type
= P2P_FIND_START_WITH_FULL
;
123 else if (!os_strcmp(entry
.str_value
, "social"))
124 type
= P2P_FIND_ONLY_SOCIAL
;
125 else if (!os_strcmp(entry
.str_value
, "progressive"))
126 type
= P2P_FIND_PROGRESSIVE
;
131 wpa_dbus_dict_entry_clear(&entry
);
134 wpas_p2p_find(wpa_s
, timeout
, type
, num_req_dev_types
, req_dev_types
);
135 os_free(req_dev_types
);
139 wpa_dbus_dict_entry_clear(&entry
);
141 os_free(req_dev_types
);
142 reply
= wpas_dbus_error_invalid_args(message
, entry
.key
);
147 DBusMessage
* wpas_dbus_handler_p2p_stop_find(DBusMessage
*message
,
148 struct wpa_supplicant
*wpa_s
)
150 wpas_p2p_stop_find(wpa_s
);
155 DBusMessage
* wpas_dbus_handler_p2p_rejectpeer(DBusMessage
*message
,
156 struct wpa_supplicant
*wpa_s
)
158 DBusMessageIter iter
;
159 char *peer_object_path
= NULL
;
160 u8 peer_addr
[ETH_ALEN
];
162 dbus_message_iter_init(message
, &iter
);
163 dbus_message_iter_get_basic(&iter
, &peer_object_path
);
165 if (parse_peer_object_path(peer_object_path
, peer_addr
) < 0)
166 return wpas_dbus_error_invalid_args(message
, NULL
);
168 if (wpas_p2p_reject(wpa_s
, peer_addr
) < 0)
169 return wpas_dbus_error_unknown_error(message
,
170 "Failed to call wpas_p2p_reject method.");
176 DBusMessage
* wpas_dbus_handler_p2p_listen(DBusMessage
*message
,
177 struct wpa_supplicant
*wpa_s
)
179 dbus_int32_t timeout
= 0;
181 if (!dbus_message_get_args(message
, NULL
, DBUS_TYPE_INT32
, &timeout
,
183 return dbus_message_new_error(message
, DBUS_ERROR_NO_MEMORY
,
186 if (wpas_p2p_listen(wpa_s
, (unsigned int)timeout
))
187 return dbus_message_new_error(message
, DBUS_ERROR_NO_MEMORY
,
194 DBusMessage
* wpas_dbus_handler_p2p_extendedlisten(
195 DBusMessage
*message
, struct wpa_supplicant
*wpa_s
)
197 unsigned int period
= 0, interval
= 0;
198 struct wpa_dbus_dict_entry entry
;
199 DBusMessageIter iter
;
200 DBusMessageIter iter_dict
;
202 dbus_message_iter_init(message
, &iter
);
205 if (!wpa_dbus_dict_open_read(&iter
, &iter_dict
, NULL
))
208 while (wpa_dbus_dict_has_dict_entry(&iter_dict
)) {
209 if (!wpa_dbus_dict_get_entry(&iter_dict
, &entry
))
212 if (!os_strcmp(entry
.key
, "period") &&
213 (entry
.type
== DBUS_TYPE_INT32
))
214 period
= entry
.uint32_value
;
215 else if (!os_strcmp(entry
.key
, "interval") &&
216 (entry
.type
== DBUS_TYPE_INT32
))
217 interval
= entry
.uint32_value
;
220 wpa_dbus_dict_entry_clear(&entry
);
223 if (wpas_p2p_ext_listen(wpa_s
, period
, interval
))
224 return wpas_dbus_error_unknown_error(
225 message
, "failed to initiate a p2p_ext_listen.");
230 wpa_dbus_dict_entry_clear(&entry
);
232 return wpas_dbus_error_invalid_args(message
, entry
.key
);
236 DBusMessage
* wpas_dbus_handler_p2p_presence_request(
237 DBusMessage
*message
, struct wpa_supplicant
*wpa_s
)
239 unsigned int dur1
= 0, int1
= 0, dur2
= 0, int2
= 0;
240 struct wpa_dbus_dict_entry entry
;
241 DBusMessageIter iter
;
242 DBusMessageIter iter_dict
;
244 dbus_message_iter_init(message
, &iter
);
247 if (!wpa_dbus_dict_open_read(&iter
, &iter_dict
, NULL
))
250 while (wpa_dbus_dict_has_dict_entry(&iter_dict
)) {
251 if (!wpa_dbus_dict_get_entry(&iter_dict
, &entry
))
254 if (!os_strcmp(entry
.key
, "duration1") &&
255 (entry
.type
== DBUS_TYPE_INT32
))
256 dur1
= entry
.uint32_value
;
257 else if (!os_strcmp(entry
.key
, "interval1") &&
258 entry
.type
== DBUS_TYPE_INT32
)
259 int1
= entry
.uint32_value
;
260 else if (!os_strcmp(entry
.key
, "duration2") &&
261 entry
.type
== DBUS_TYPE_INT32
)
262 dur2
= entry
.uint32_value
;
263 else if (!os_strcmp(entry
.key
, "interval2") &&
264 entry
.type
== DBUS_TYPE_INT32
)
265 int2
= entry
.uint32_value
;
269 wpa_dbus_dict_entry_clear(&entry
);
271 if (wpas_p2p_presence_req(wpa_s
, dur1
, int1
, dur2
, int2
) < 0)
272 return wpas_dbus_error_unknown_error(message
,
273 "Failed to invoke presence request.");
278 wpa_dbus_dict_entry_clear(&entry
);
280 return wpas_dbus_error_invalid_args(message
, entry
.key
);
284 DBusMessage
* wpas_dbus_handler_p2p_group_add(DBusMessage
*message
,
285 struct wpa_supplicant
*wpa_s
)
287 DBusMessageIter iter_dict
;
288 DBusMessage
*reply
= NULL
;
289 DBusMessageIter iter
;
290 struct wpa_dbus_dict_entry entry
;
291 char *pg_object_path
= NULL
;
292 int persistent_group
= 0;
295 char *net_id_str
= NULL
;
296 unsigned int group_id
= 0;
297 struct wpa_ssid
*ssid
;
299 dbus_message_iter_init(message
, &iter
);
301 if (!wpa_dbus_dict_open_read(&iter
, &iter_dict
, NULL
))
304 while (wpa_dbus_dict_has_dict_entry(&iter_dict
)) {
305 if (!wpa_dbus_dict_get_entry(&iter_dict
, &entry
))
308 if (!os_strcmp(entry
.key
, "persistent") &&
309 (entry
.type
== DBUS_TYPE_BOOLEAN
)) {
310 persistent_group
= (entry
.bool_value
== TRUE
) ? 1 : 0;
311 } else if (!os_strcmp(entry
.key
, "frequency") &&
312 (entry
.type
== DBUS_TYPE_INT32
)) {
313 freq
= entry
.int32_value
;
316 } else if (!os_strcmp(entry
.key
, "persistent_group_object") &&
317 entry
.type
== DBUS_TYPE_OBJECT_PATH
)
318 pg_object_path
= os_strdup(entry
.str_value
);
322 wpa_dbus_dict_entry_clear(&entry
);
325 if (pg_object_path
!= NULL
) {
327 * A persistent group Object Path is defined meaning we want
328 * to re-invoke a persistent group.
331 iface
= wpas_dbus_new_decompose_object_path(pg_object_path
, 1,
334 os_strcmp(iface
, wpa_s
->dbus_new_path
) != 0) {
336 wpas_dbus_error_invalid_args(message
,
341 group_id
= strtoul(net_id_str
, NULL
, 10);
342 if (errno
== EINVAL
) {
343 reply
= wpas_dbus_error_invalid_args(
344 message
, pg_object_path
);
348 /* Get the SSID structure from the persistent group id */
349 ssid
= wpa_config_get_network(wpa_s
->conf
, group_id
);
350 if (ssid
== NULL
|| ssid
->disabled
!= 2)
353 if (wpas_p2p_group_add_persistent(wpa_s
, ssid
, 0, freq
)) {
354 reply
= wpas_dbus_error_unknown_error(
356 "Failed to reinvoke a persistent group");
359 } else if (wpas_p2p_group_add(wpa_s
, persistent_group
, freq
))
363 os_free(pg_object_path
);
368 wpa_dbus_dict_entry_clear(&entry
);
370 reply
= wpas_dbus_error_invalid_args(message
, NULL
);
375 DBusMessage
* wpas_dbus_handler_p2p_disconnect(DBusMessage
*message
,
376 struct wpa_supplicant
*wpa_s
)
378 if (wpas_p2p_disconnect(wpa_s
))
379 return wpas_dbus_error_unknown_error(message
,
380 "failed to disconnect");
386 static dbus_bool_t
wpa_dbus_p2p_check_enabled(struct wpa_supplicant
*wpa_s
,
387 DBusMessage
*message
,
388 DBusMessage
**out_reply
,
391 /* Return an error message or an error if P2P isn't available */
392 if (wpa_s
->global
->p2p_disabled
|| wpa_s
->global
->p2p
== NULL
) {
394 *out_reply
= dbus_message_new_error(
395 message
, DBUS_ERROR_FAILED
,
396 "P2P is not available for this interface");
398 dbus_set_error_const(error
, DBUS_ERROR_FAILED
,
399 "P2P is not available for this "
407 DBusMessage
* wpas_dbus_handler_p2p_flush(DBusMessage
*message
,
408 struct wpa_supplicant
*wpa_s
)
410 DBusMessage
*reply
= NULL
;
412 if (!wpa_dbus_p2p_check_enabled(wpa_s
, message
, &reply
, NULL
))
415 os_memset(wpa_s
->p2p_auth_invite
, 0, ETH_ALEN
);
416 wpa_s
->force_long_sd
= 0;
417 p2p_flush(wpa_s
->global
->p2p
);
423 DBusMessage
* wpas_dbus_handler_p2p_connect(DBusMessage
*message
,
424 struct wpa_supplicant
*wpa_s
)
426 DBusMessageIter iter_dict
;
427 DBusMessage
*reply
= NULL
;
428 DBusMessageIter iter
;
429 struct wpa_dbus_dict_entry entry
;
430 char *peer_object_path
= NULL
;
431 int persistent_group
= 0;
433 int authorize_only
= 0;
438 enum p2p_wps_method wps_method
= WPS_NOT_READY
;
440 char *err_msg
= NULL
;
443 if (!wpa_dbus_p2p_check_enabled(wpa_s
, message
, &reply
, NULL
))
446 dbus_message_iter_init(message
, &iter
);
448 if (!wpa_dbus_dict_open_read(&iter
, &iter_dict
, NULL
))
451 while (wpa_dbus_dict_has_dict_entry(&iter_dict
)) {
452 if (!wpa_dbus_dict_get_entry(&iter_dict
, &entry
))
455 if (!os_strcmp(entry
.key
, "peer") &&
456 (entry
.type
== DBUS_TYPE_OBJECT_PATH
)) {
457 peer_object_path
= os_strdup(entry
.str_value
);
458 } else if (!os_strcmp(entry
.key
, "persistent") &&
459 (entry
.type
== DBUS_TYPE_BOOLEAN
)) {
460 persistent_group
= (entry
.bool_value
== TRUE
) ? 1 : 0;
461 } else if (!os_strcmp(entry
.key
, "join") &&
462 (entry
.type
== DBUS_TYPE_BOOLEAN
)) {
463 join
= (entry
.bool_value
== TRUE
) ? 1 : 0;
464 } else if (!os_strcmp(entry
.key
, "authorize_only") &&
465 (entry
.type
== DBUS_TYPE_BOOLEAN
)) {
466 authorize_only
= (entry
.bool_value
== TRUE
) ? 1 : 0;
467 } else if (!os_strcmp(entry
.key
, "frequency") &&
468 (entry
.type
== DBUS_TYPE_INT32
)) {
469 freq
= entry
.int32_value
;
472 } else if (!os_strcmp(entry
.key
, "go_intent") &&
473 (entry
.type
== DBUS_TYPE_INT32
)) {
474 go_intent
= entry
.int32_value
;
475 if ((go_intent
< 0) || (go_intent
> 15))
477 } else if (!os_strcmp(entry
.key
, "wps_method") &&
478 (entry
.type
== DBUS_TYPE_STRING
)) {
479 if (!os_strcmp(entry
.str_value
, "pbc"))
480 wps_method
= WPS_PBC
;
481 else if (!os_strcmp(entry
.str_value
, "pin"))
482 wps_method
= WPS_PIN_DISPLAY
;
483 else if (!os_strcmp(entry
.str_value
, "display"))
484 wps_method
= WPS_PIN_DISPLAY
;
485 else if (!os_strcmp(entry
.str_value
, "keypad"))
486 wps_method
= WPS_PIN_KEYPAD
;
489 } else if (!os_strcmp(entry
.key
, "pin") &&
490 (entry
.type
== DBUS_TYPE_STRING
)) {
491 pin
= os_strdup(entry
.str_value
);
495 wpa_dbus_dict_entry_clear(&entry
);
498 if (!peer_object_path
|| (wps_method
== WPS_NOT_READY
) ||
499 (parse_peer_object_path(peer_object_path
, addr
) < 0) ||
500 (p2p_get_peer_info(wpa_s
->global
->p2p
, addr
, 0, NULL
, 0) < 0))
504 * Validate the wps_method specified and the pin value.
506 if ((!pin
|| !pin
[0]) && (wps_method
== WPS_PIN_KEYPAD
))
509 new_pin
= wpas_p2p_connect(wpa_s
, addr
, pin
, wps_method
,
510 persistent_group
, join
, authorize_only
,
516 os_snprintf(npin
, sizeof(npin
), "%08d", new_pin
);
517 generated_pin
= npin
;
518 reply
= dbus_message_new_method_return(message
);
519 dbus_message_append_args(reply
, DBUS_TYPE_STRING
,
520 &generated_pin
, DBUS_TYPE_INVALID
);
524 err_msg
= "connect failed due to channel "
526 iface
= WPAS_DBUS_ERROR_CONNECT_CHANNEL_UNAVAILABLE
;
530 err_msg
= "connect failed due to unsupported channel.";
531 iface
= WPAS_DBUS_ERROR_CONNECT_CHANNEL_UNSUPPORTED
;
535 err_msg
= "connect failed due to unspecified error.";
536 iface
= WPAS_DBUS_ERROR_CONNECT_UNSPECIFIED_ERROR
;
542 * Do we need specialized errors corresponding to above
543 * error conditions as against just returning a different
546 reply
= dbus_message_new_error(message
, iface
, err_msg
);
550 os_free(peer_object_path
);
554 wpa_dbus_dict_entry_clear(&entry
);
556 reply
= wpas_dbus_error_invalid_args(message
, NULL
);
561 DBusMessage
* wpas_dbus_handler_p2p_invite(DBusMessage
*message
,
562 struct wpa_supplicant
*wpa_s
)
564 DBusMessageIter iter_dict
;
565 DBusMessage
*reply
= NULL
;
566 DBusMessageIter iter
;
567 struct wpa_dbus_dict_entry entry
;
568 char *peer_object_path
= NULL
;
569 char *pg_object_path
= NULL
;
571 char *net_id_str
= NULL
;
572 u8 peer_addr
[ETH_ALEN
];
573 unsigned int group_id
= 0;
575 struct wpa_ssid
*ssid
;
577 if (!wpa_dbus_p2p_check_enabled(wpa_s
, message
, &reply
, NULL
))
580 dbus_message_iter_init(message
, &iter
);
582 if (!wpa_dbus_dict_open_read(&iter
, &iter_dict
, NULL
))
585 while (wpa_dbus_dict_has_dict_entry(&iter_dict
)) {
586 if (!wpa_dbus_dict_get_entry(&iter_dict
, &entry
))
589 if (!os_strcmp(entry
.key
, "peer") &&
590 (entry
.type
== DBUS_TYPE_OBJECT_PATH
)) {
591 peer_object_path
= os_strdup(entry
.str_value
);
592 wpa_dbus_dict_entry_clear(&entry
);
593 } else if (!os_strcmp(entry
.key
, "persistent_group_object") &&
594 (entry
.type
== DBUS_TYPE_OBJECT_PATH
)) {
595 pg_object_path
= os_strdup(entry
.str_value
);
597 wpa_dbus_dict_entry_clear(&entry
);
599 wpa_dbus_dict_entry_clear(&entry
);
604 if (!peer_object_path
||
605 (parse_peer_object_path(peer_object_path
, peer_addr
) < 0) ||
606 (p2p_get_peer_info(wpa_s
->global
->p2p
,
607 peer_addr
, 0, NULL
, 0) < 0)) {
613 * A group ID is defined meaning we want to re-invoke a
617 iface
= wpas_dbus_new_decompose_object_path(pg_object_path
, 1,
620 os_strcmp(iface
, wpa_s
->dbus_new_path
) != 0) {
621 reply
= wpas_dbus_error_invalid_args(message
,
626 group_id
= strtoul(net_id_str
, NULL
, 10);
627 if (errno
== EINVAL
) {
628 reply
= wpas_dbus_error_invalid_args(
629 message
, pg_object_path
);
633 /* Get the SSID structure from the persistent group id */
634 ssid
= wpa_config_get_network(wpa_s
->conf
, group_id
);
635 if (ssid
== NULL
|| ssid
->disabled
!= 2)
638 if (wpas_p2p_invite(wpa_s
, peer_addr
, ssid
, NULL
) < 0) {
639 reply
= wpas_dbus_error_unknown_error(
641 "Failed to reinvoke a persistent group");
646 * No group ID means propose to a peer to join my active group
648 if (wpas_p2p_invite_group(wpa_s
, wpa_s
->ifname
,
650 reply
= wpas_dbus_error_unknown_error(
651 message
, "Failed to join to an active group");
657 os_free(pg_object_path
);
658 os_free(peer_object_path
);
662 reply
= wpas_dbus_error_invalid_args(message
, NULL
);
667 DBusMessage
* wpas_dbus_handler_p2p_prov_disc_req(DBusMessage
*message
,
668 struct wpa_supplicant
*wpa_s
)
670 DBusMessageIter iter
;
671 char *peer_object_path
= NULL
;
672 char *config_method
= NULL
;
673 u8 peer_addr
[ETH_ALEN
];
675 dbus_message_iter_init(message
, &iter
);
676 dbus_message_iter_get_basic(&iter
, &peer_object_path
);
678 if (parse_peer_object_path(peer_object_path
, peer_addr
) < 0)
679 return wpas_dbus_error_invalid_args(message
, NULL
);
681 dbus_message_iter_next(&iter
);
682 dbus_message_iter_get_basic(&iter
, &config_method
);
685 * Validation checks on config_method are being duplicated here
686 * to be able to return invalid args reply since the error code
687 * from p2p module are not granular enough (yet).
689 if (os_strcmp(config_method
, "display") &&
690 os_strcmp(config_method
, "keypad") &&
691 os_strcmp(config_method
, "pbc") &&
692 os_strcmp(config_method
, "pushbutton"))
693 return wpas_dbus_error_invalid_args(message
, NULL
);
695 if (wpas_p2p_prov_disc(wpa_s
, peer_addr
, config_method
) < 0)
696 return wpas_dbus_error_unknown_error(message
,
697 "Failed to send provision discovery request");
704 * P2P Device property accessor methods.
707 dbus_bool_t
wpas_dbus_getter_p2p_device_properties(DBusMessageIter
*iter
,
711 struct wpa_supplicant
*wpa_s
= user_data
;
712 DBusMessageIter variant_iter
, dict_iter
;
713 DBusMessageIter iter_secdev_dict_entry
, iter_secdev_dict_val
,
714 iter_secdev_dict_array
;
715 const char *dev_name
;
716 int num_vendor_extensions
= 0;
718 const struct wpabuf
*vendor_ext
[P2P_MAX_WPS_VENDOR_EXT
];
720 if (!wpa_dbus_p2p_check_enabled(wpa_s
, NULL
, NULL
, error
))
723 if (!dbus_message_iter_open_container(iter
, DBUS_TYPE_VARIANT
,
724 "a{sv}", &variant_iter
) ||
725 !wpa_dbus_dict_open_write(&variant_iter
, &dict_iter
))
729 dev_name
= wpa_s
->conf
->device_name
;
731 !wpa_dbus_dict_append_string(&dict_iter
, "DeviceName", dev_name
))
734 /* Primary device type */
735 if (!wpa_dbus_dict_append_byte_array(&dict_iter
, "PrimaryDeviceType",
736 (char *)wpa_s
->conf
->device_type
,
740 /* Secondary device types */
741 if (wpa_s
->conf
->num_sec_device_types
) {
742 if (!wpa_dbus_dict_begin_array(&dict_iter
,
743 "SecondaryDeviceTypes",
744 DBUS_TYPE_ARRAY_AS_STRING
745 DBUS_TYPE_BYTE_AS_STRING
,
746 &iter_secdev_dict_entry
,
747 &iter_secdev_dict_val
,
748 &iter_secdev_dict_array
))
751 for (i
= 0; i
< wpa_s
->conf
->num_sec_device_types
; i
++)
752 wpa_dbus_dict_bin_array_add_element(
753 &iter_secdev_dict_array
,
754 wpa_s
->conf
->sec_device_type
[i
],
757 if (!wpa_dbus_dict_end_array(&dict_iter
,
758 &iter_secdev_dict_entry
,
759 &iter_secdev_dict_val
,
760 &iter_secdev_dict_array
))
764 /* Vendor Extensions */
765 for (i
= 0; i
< P2P_MAX_WPS_VENDOR_EXT
; i
++) {
766 if (wpa_s
->conf
->wps_vendor_ext
[i
] == NULL
)
768 vendor_ext
[num_vendor_extensions
++] =
769 wpa_s
->conf
->wps_vendor_ext
[i
];
772 if (num_vendor_extensions
&&
773 !wpa_dbus_dict_append_wpabuf_array(&dict_iter
,
776 num_vendor_extensions
))
780 if (!wpa_dbus_dict_append_uint32(&dict_iter
, "GOIntent",
781 wpa_s
->conf
->p2p_go_intent
))
784 /* Persistent Reconnect */
785 if (!wpa_dbus_dict_append_bool(&dict_iter
, "PersistantReconnect",
786 wpa_s
->conf
->persistent_reconnect
))
789 /* Listen Reg Class */
790 if (!wpa_dbus_dict_append_uint32(&dict_iter
, "ListenRegClass",
791 wpa_s
->conf
->p2p_listen_reg_class
))
795 if (!wpa_dbus_dict_append_uint32(&dict_iter
, "ListenChannel",
796 wpa_s
->conf
->p2p_listen_channel
))
800 if (!wpa_dbus_dict_append_uint32(&dict_iter
, "OperRegClass",
801 wpa_s
->conf
->p2p_oper_reg_class
))
805 if (!wpa_dbus_dict_append_uint32(&dict_iter
, "OperChannel",
806 wpa_s
->conf
->p2p_oper_channel
))
810 if (wpa_s
->conf
->p2p_ssid_postfix
&&
811 !wpa_dbus_dict_append_string(&dict_iter
, "SsidPostfix",
812 wpa_s
->conf
->p2p_ssid_postfix
))
816 if (!wpa_dbus_dict_append_bool(&dict_iter
, "IntraBss",
817 wpa_s
->conf
->p2p_intra_bss
))
821 if (!wpa_dbus_dict_append_uint32(&dict_iter
, "GroupIdle",
822 wpa_s
->conf
->p2p_group_idle
))
825 /* Dissasociation low ack */
826 if (!wpa_dbus_dict_append_uint32(&dict_iter
, "disassoc_low_ack",
827 wpa_s
->conf
->disassoc_low_ack
))
830 if (!wpa_dbus_dict_close_write(&variant_iter
, &dict_iter
) ||
831 !dbus_message_iter_close_container(iter
, &variant_iter
))
837 dbus_set_error_const(error
, DBUS_ERROR_NO_MEMORY
, "no memory");
842 dbus_bool_t
wpas_dbus_setter_p2p_device_properties(DBusMessageIter
*iter
,
846 struct wpa_supplicant
*wpa_s
= user_data
;
847 DBusMessageIter variant_iter
, iter_dict
;
848 struct wpa_dbus_dict_entry entry
= {.type
= DBUS_TYPE_STRING
};
851 if (!wpa_dbus_p2p_check_enabled(wpa_s
, NULL
, NULL
, error
))
854 dbus_message_iter_recurse(iter
, &variant_iter
);
855 if (!wpa_dbus_dict_open_read(&variant_iter
, &iter_dict
, error
))
858 while (wpa_dbus_dict_has_dict_entry(&iter_dict
)) {
859 if (!wpa_dbus_dict_get_entry(&iter_dict
, &entry
)) {
860 dbus_set_error_const(error
, DBUS_ERROR_INVALID_ARGS
,
861 "invalid message format");
865 if (os_strcmp(entry
.key
, "DeviceName") == 0) {
868 if (entry
.type
!= DBUS_TYPE_STRING
)
871 devname
= os_strdup(entry
.str_value
);
873 goto err_no_mem_clear
;
875 os_free(wpa_s
->conf
->device_name
);
876 wpa_s
->conf
->device_name
= devname
;
878 wpa_s
->conf
->changed_parameters
|=
879 CFG_CHANGED_DEVICE_NAME
;
880 } else if (os_strcmp(entry
.key
, "PrimaryDeviceType") == 0) {
881 if (entry
.type
!= DBUS_TYPE_ARRAY
||
882 entry
.array_type
!= DBUS_TYPE_BYTE
||
883 entry
.array_len
!= WPS_DEV_TYPE_LEN
)
886 os_memcpy(wpa_s
->conf
->device_type
,
887 entry
.bytearray_value
,
889 wpa_s
->conf
->changed_parameters
|=
890 CFG_CHANGED_DEVICE_TYPE
;
891 } else if (os_strcmp(entry
.key
, "SecondaryDeviceTypes") == 0) {
892 if (entry
.type
!= DBUS_TYPE_ARRAY
||
893 entry
.array_type
!= WPAS_DBUS_TYPE_BINARRAY
||
894 entry
.array_len
> MAX_SEC_DEVICE_TYPES
)
897 for (i
= 0; i
< entry
.array_len
; i
++)
898 if (wpabuf_len(entry
.binarray_value
[i
]) !=
900 goto err_no_mem_clear
;
901 for (i
= 0; i
< entry
.array_len
; i
++)
902 os_memcpy(wpa_s
->conf
->sec_device_type
[i
],
903 wpabuf_head(entry
.binarray_value
[i
]),
905 wpa_s
->conf
->num_sec_device_types
= entry
.array_len
;
906 wpa_s
->conf
->changed_parameters
|=
907 CFG_CHANGED_SEC_DEVICE_TYPE
;
908 } else if (os_strcmp(entry
.key
, "VendorExtension") == 0) {
909 if ((entry
.type
!= DBUS_TYPE_ARRAY
) ||
910 (entry
.array_type
!= WPAS_DBUS_TYPE_BINARRAY
) ||
911 (entry
.array_len
> P2P_MAX_WPS_VENDOR_EXT
))
914 wpa_s
->conf
->changed_parameters
|=
915 CFG_CHANGED_VENDOR_EXTENSION
;
917 for (i
= 0; i
< P2P_MAX_WPS_VENDOR_EXT
; i
++) {
918 wpabuf_free(wpa_s
->conf
->wps_vendor_ext
[i
]);
919 if (i
< entry
.array_len
) {
920 wpa_s
->conf
->wps_vendor_ext
[i
] =
921 entry
.binarray_value
[i
];
922 entry
.binarray_value
[i
] = NULL
;
924 wpa_s
->conf
->wps_vendor_ext
[i
] = NULL
;
926 } else if ((os_strcmp(entry
.key
, "GOIntent") == 0) &&
927 (entry
.type
== DBUS_TYPE_UINT32
) &&
928 (entry
.uint32_value
<= 15))
929 wpa_s
->conf
->p2p_go_intent
= entry
.uint32_value
;
930 else if ((os_strcmp(entry
.key
, "PersistantReconnect") == 0) &&
931 (entry
.type
== DBUS_TYPE_BOOLEAN
))
932 wpa_s
->conf
->persistent_reconnect
= entry
.bool_value
;
933 else if ((os_strcmp(entry
.key
, "ListenRegClass") == 0) &&
934 (entry
.type
== DBUS_TYPE_UINT32
)) {
935 wpa_s
->conf
->p2p_listen_reg_class
= entry
.uint32_value
;
936 wpa_s
->conf
->changed_parameters
|=
937 CFG_CHANGED_P2P_LISTEN_CHANNEL
;
938 } else if ((os_strcmp(entry
.key
, "ListenChannel") == 0) &&
939 (entry
.type
== DBUS_TYPE_UINT32
)) {
940 wpa_s
->conf
->p2p_listen_channel
= entry
.uint32_value
;
941 wpa_s
->conf
->changed_parameters
|=
942 CFG_CHANGED_P2P_LISTEN_CHANNEL
;
943 } else if ((os_strcmp(entry
.key
, "OperRegClass") == 0) &&
944 (entry
.type
== DBUS_TYPE_UINT32
)) {
945 wpa_s
->conf
->p2p_oper_reg_class
= entry
.uint32_value
;
946 wpa_s
->conf
->changed_parameters
|=
947 CFG_CHANGED_P2P_OPER_CHANNEL
;
948 } else if ((os_strcmp(entry
.key
, "OperChannel") == 0) &&
949 (entry
.type
== DBUS_TYPE_UINT32
)) {
950 wpa_s
->conf
->p2p_oper_channel
= entry
.uint32_value
;
951 wpa_s
->conf
->changed_parameters
|=
952 CFG_CHANGED_P2P_OPER_CHANNEL
;
953 } else if (os_strcmp(entry
.key
, "SsidPostfix") == 0) {
956 if (entry
.type
!= DBUS_TYPE_STRING
)
959 postfix
= os_strdup(entry
.str_value
);
961 goto err_no_mem_clear
;
963 os_free(wpa_s
->conf
->p2p_ssid_postfix
);
964 wpa_s
->conf
->p2p_ssid_postfix
= postfix
;
966 wpa_s
->conf
->changed_parameters
|=
967 CFG_CHANGED_P2P_SSID_POSTFIX
;
968 } else if ((os_strcmp(entry
.key
, "IntraBss") == 0) &&
969 (entry
.type
== DBUS_TYPE_BOOLEAN
)) {
970 wpa_s
->conf
->p2p_intra_bss
= entry
.bool_value
;
971 wpa_s
->conf
->changed_parameters
|=
972 CFG_CHANGED_P2P_INTRA_BSS
;
973 } else if ((os_strcmp(entry
.key
, "GroupIdle") == 0) &&
974 (entry
.type
== DBUS_TYPE_UINT32
))
975 wpa_s
->conf
->p2p_group_idle
= entry
.uint32_value
;
976 else if (os_strcmp(entry
.key
, "disassoc_low_ack") == 0 &&
977 entry
.type
== DBUS_TYPE_UINT32
)
978 wpa_s
->conf
->disassoc_low_ack
= entry
.uint32_value
;
982 wpa_dbus_dict_entry_clear(&entry
);
985 if (wpa_s
->conf
->changed_parameters
) {
986 /* Some changed parameters requires to update config*/
987 wpa_supplicant_update_config(wpa_s
);
993 dbus_set_error_const(error
, DBUS_ERROR_INVALID_ARGS
,
994 "invalid message format");
995 wpa_dbus_dict_entry_clear(&entry
);
999 dbus_set_error_const(error
, DBUS_ERROR_NO_MEMORY
, "no memory");
1000 wpa_dbus_dict_entry_clear(&entry
);
1005 dbus_bool_t
wpas_dbus_getter_p2p_peers(DBusMessageIter
*iter
, DBusError
*error
,
1008 struct wpa_supplicant
*wpa_s
= user_data
;
1009 struct p2p_data
*p2p
= wpa_s
->global
->p2p
;
1010 int next
= 0, i
= 0;
1011 int num
= 0, out_of_mem
= 0;
1013 const struct p2p_peer_info
*peer_info
= NULL
;
1014 dbus_bool_t success
= FALSE
;
1016 struct dl_list peer_objpath_list
;
1017 struct peer_objpath_node
{
1018 struct dl_list list
;
1019 char path
[WPAS_DBUS_OBJECT_PATH_MAX
];
1022 char **peer_obj_paths
= NULL
;
1024 if (!wpa_dbus_p2p_check_enabled(wpa_s
, NULL
, NULL
, error
))
1027 dl_list_init(&peer_objpath_list
);
1029 /* Get the first peer info */
1030 peer_info
= p2p_get_peer_found(p2p
, NULL
, next
);
1032 /* Get next and accumulate them */
1034 while (peer_info
!= NULL
) {
1035 node
= os_zalloc(sizeof(struct peer_objpath_node
));
1041 addr
= peer_info
->p2p_device_addr
;
1042 os_snprintf(node
->path
, WPAS_DBUS_OBJECT_PATH_MAX
,
1043 "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART
1045 wpa_s
->dbus_new_path
, MAC2STR(addr
));
1046 dl_list_add_tail(&peer_objpath_list
, &node
->list
);
1049 peer_info
= p2p_get_peer_found(p2p
, addr
, next
);
1053 * Now construct the peer object paths in a form suitable for
1054 * array_property_getter helper below.
1056 peer_obj_paths
= os_zalloc(num
* sizeof(char *));
1058 if (!peer_obj_paths
) {
1063 dl_list_for_each_safe(node
, tmp
, &peer_objpath_list
,
1064 struct peer_objpath_node
, list
)
1065 peer_obj_paths
[i
++] = node
->path
;
1067 success
= wpas_dbus_simple_array_property_getter(iter
,
1068 DBUS_TYPE_OBJECT_PATH
,
1069 peer_obj_paths
, num
,
1074 os_free(peer_obj_paths
);
1076 dl_list_for_each_safe(node
, tmp
, &peer_objpath_list
,
1077 struct peer_objpath_node
, list
) {
1078 dl_list_del(&node
->list
);
1082 dbus_set_error_const(error
, DBUS_ERROR_NO_MEMORY
, "no memory");
1088 enum wpas_p2p_role
{
1089 WPAS_P2P_ROLE_DEVICE
,
1091 WPAS_P2P_ROLE_CLIENT
,
1094 static enum wpas_p2p_role
wpas_get_p2p_role(struct wpa_supplicant
*wpa_s
)
1096 struct wpa_ssid
*ssid
= wpa_s
->current_ssid
;
1099 return WPAS_P2P_ROLE_DEVICE
;
1100 if (wpa_s
->wpa_state
!= WPA_COMPLETED
)
1101 return WPAS_P2P_ROLE_DEVICE
;
1103 switch (ssid
->mode
) {
1104 case WPAS_MODE_P2P_GO
:
1105 case WPAS_MODE_P2P_GROUP_FORMATION
:
1106 return WPAS_P2P_ROLE_GO
;
1107 case WPAS_MODE_INFRA
:
1108 if (ssid
->p2p_group
)
1109 return WPAS_P2P_ROLE_CLIENT
;
1110 return WPAS_P2P_ROLE_DEVICE
;
1112 return WPAS_P2P_ROLE_DEVICE
;
1117 dbus_bool_t
wpas_dbus_getter_p2p_role(DBusMessageIter
*iter
, DBusError
*error
,
1120 struct wpa_supplicant
*wpa_s
= user_data
;
1123 switch (wpas_get_p2p_role(wpa_s
)) {
1124 case WPAS_P2P_ROLE_GO
:
1127 case WPAS_P2P_ROLE_CLIENT
:
1134 return wpas_dbus_simple_property_getter(iter
, DBUS_TYPE_STRING
, &str
,
1139 dbus_bool_t
wpas_dbus_getter_p2p_group(DBusMessageIter
*iter
, DBusError
*error
,
1142 struct wpa_supplicant
*wpa_s
= user_data
;
1144 if (wpa_s
->dbus_groupobj_path
== NULL
)
1147 return wpas_dbus_simple_property_getter(iter
, DBUS_TYPE_OBJECT_PATH
,
1148 &wpa_s
->dbus_groupobj_path
,
1153 dbus_bool_t
wpas_dbus_getter_p2p_peergo(DBusMessageIter
*iter
,
1154 DBusError
*error
, void *user_data
)
1156 struct wpa_supplicant
*wpa_s
= user_data
;
1157 char go_peer_obj_path
[WPAS_DBUS_OBJECT_PATH_MAX
], *path
;
1159 if (wpas_get_p2p_role(wpa_s
) != WPAS_P2P_ROLE_CLIENT
)
1162 os_snprintf(go_peer_obj_path
, WPAS_DBUS_OBJECT_PATH_MAX
,
1163 "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART
"/" COMPACT_MACSTR
,
1164 wpa_s
->dbus_new_path
, MAC2STR(wpa_s
->go_dev_addr
));
1165 path
= go_peer_obj_path
;
1166 return wpas_dbus_simple_property_getter(iter
, DBUS_TYPE_OBJECT_PATH
,
1172 * Peer object properties accessor methods
1175 dbus_bool_t
wpas_dbus_getter_p2p_peer_properties(DBusMessageIter
*iter
,
1176 DBusError
*error
, void *user_data
)
1178 struct peer_handler_args
*peer_args
= user_data
;
1179 DBusMessageIter variant_iter
, dict_iter
;
1180 const struct p2p_peer_info
*info
= NULL
;
1181 const struct wpabuf
*vendor_extension
[P2P_MAX_WPS_VENDOR_EXT
];
1184 if (!wpa_dbus_p2p_check_enabled(peer_args
->wpa_s
, NULL
, NULL
, error
))
1187 /* get the peer info */
1188 info
= p2p_get_peer_found(peer_args
->wpa_s
->global
->p2p
,
1189 peer_args
->p2p_device_addr
, 0);
1191 dbus_set_error(error
, DBUS_ERROR_FAILED
, "failed to find peer");
1195 if (!dbus_message_iter_open_container(iter
, DBUS_TYPE_VARIANT
,
1196 "a{sv}", &variant_iter
) ||
1197 !wpa_dbus_dict_open_write(&variant_iter
, &dict_iter
))
1200 /* Fill out the dictionary */
1201 if (!wpa_dbus_dict_append_string(&dict_iter
, "DeviceName",
1204 if (!wpa_dbus_dict_append_byte_array(&dict_iter
, "PrimaryDeviceType",
1205 (char *)info
->pri_dev_type
,
1208 if (!wpa_dbus_dict_append_uint16(&dict_iter
, "config_method",
1209 info
->config_methods
))
1211 if (!wpa_dbus_dict_append_int32(&dict_iter
, "level",
1214 if (!wpa_dbus_dict_append_byte(&dict_iter
, "devicecapability",
1217 if (!wpa_dbus_dict_append_byte(&dict_iter
, "groupcapability",
1221 if (info
->wps_sec_dev_type_list_len
) {
1222 const u8
*sec_dev_type_list
= info
->wps_sec_dev_type_list
;
1223 int num_sec_dev_types
=
1224 info
->wps_sec_dev_type_list_len
/ WPS_DEV_TYPE_LEN
;
1225 DBusMessageIter iter_secdev_dict_entry
, iter_secdev_dict_val
,
1226 iter_secdev_dict_array
;
1228 if (num_sec_dev_types
) {
1229 if (!wpa_dbus_dict_begin_array(&dict_iter
,
1230 "SecondaryDeviceTypes",
1231 DBUS_TYPE_ARRAY_AS_STRING
1232 DBUS_TYPE_BYTE_AS_STRING
,
1233 &iter_secdev_dict_entry
,
1234 &iter_secdev_dict_val
,
1235 &iter_secdev_dict_array
))
1237 for (i
= 0; i
< num_sec_dev_types
; i
++) {
1238 wpa_dbus_dict_bin_array_add_element(
1239 &iter_secdev_dict_array
,
1242 sec_dev_type_list
+= WPS_DEV_TYPE_LEN
;
1245 if (!wpa_dbus_dict_end_array(&dict_iter
,
1246 &iter_secdev_dict_entry
,
1247 &iter_secdev_dict_val
,
1248 &iter_secdev_dict_array
))
1253 /* Add WPS vendor extensions attribute */
1254 for (i
= 0, num
= 0; i
< P2P_MAX_WPS_VENDOR_EXT
; i
++) {
1255 if (info
->wps_vendor_ext
[i
] == NULL
)
1257 vendor_extension
[num
] = info
->wps_vendor_ext
[i
];
1261 if (!wpa_dbus_dict_append_wpabuf_array(&dict_iter
, "VendorExtension",
1262 vendor_extension
, num
))
1265 if (!wpa_dbus_dict_close_write(&variant_iter
, &dict_iter
) ||
1266 !dbus_message_iter_close_container(iter
, &variant_iter
))
1272 dbus_set_error_const(error
, DBUS_ERROR_NO_MEMORY
, "no memory");
1277 dbus_bool_t
wpas_dbus_getter_p2p_peer_ies(DBusMessageIter
*iter
,
1278 DBusError
*error
, void *user_data
)
1280 /* struct peer_handler_args *peer_args = user_data; */
1282 dbus_set_error_const(error
, DBUS_ERROR_FAILED
, "not implemented");
1288 * wpas_dbus_getter_persistent_groups - Get array of persistent group objects
1289 * @iter: Pointer to incoming dbus message iter
1290 * @error: Location to store error on failure
1291 * @user_data: Function specific data
1292 * Returns: TRUE on success, FALSE on failure
1294 * Getter for "PersistentGroups" property.
1296 dbus_bool_t
wpas_dbus_getter_persistent_groups(DBusMessageIter
*iter
,
1300 struct wpa_supplicant
*wpa_s
= user_data
;
1301 struct wpa_ssid
*ssid
;
1303 unsigned int i
= 0, num
= 0;
1304 dbus_bool_t success
= FALSE
;
1306 if (wpa_s
->conf
== NULL
) {
1307 wpa_printf(MSG_ERROR
, "dbus: %s: "
1308 "An error occurred getting persistent groups list",
1310 dbus_set_error_const(error
, DBUS_ERROR_FAILED
, "an error "
1311 "occurred getting persistent groups list");
1315 for (ssid
= wpa_s
->conf
->ssid
; ssid
; ssid
= ssid
->next
)
1316 if (network_is_persistent_group(ssid
))
1319 paths
= os_zalloc(num
* sizeof(char *));
1321 dbus_set_error_const(error
, DBUS_ERROR_NO_MEMORY
, "no memory");
1325 /* Loop through configured networks and append object path of each */
1326 for (ssid
= wpa_s
->conf
->ssid
; ssid
; ssid
= ssid
->next
) {
1327 if (!network_is_persistent_group(ssid
))
1329 paths
[i
] = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX
);
1330 if (paths
[i
] == NULL
) {
1331 dbus_set_error_const(error
, DBUS_ERROR_NO_MEMORY
,
1335 /* Construct the object path for this network. */
1336 os_snprintf(paths
[i
++], WPAS_DBUS_OBJECT_PATH_MAX
,
1337 "%s/" WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART
"/%d",
1338 wpa_s
->dbus_new_path
, ssid
->id
);
1341 success
= wpas_dbus_simple_array_property_getter(iter
,
1342 DBUS_TYPE_OBJECT_PATH
,
1347 os_free(paths
[--i
]);
1354 * wpas_dbus_getter_persistent_group_properties - Get options for a persistent
1356 * @iter: Pointer to incoming dbus message iter
1357 * @error: Location to store error on failure
1358 * @user_data: Function specific data
1359 * Returns: TRUE on success, FALSE on failure
1361 * Getter for "Properties" property of a persistent group.
1363 dbus_bool_t
wpas_dbus_getter_persistent_group_properties(DBusMessageIter
*iter
,
1367 struct network_handler_args
*net
= user_data
;
1369 /* Leveraging the fact that persistent group object is still
1370 * represented in same manner as network within.
1372 return wpas_dbus_getter_network_properties(iter
, error
, net
);
1377 * wpas_dbus_setter_persistent_group_properties - Get options for a persistent
1379 * @iter: Pointer to incoming dbus message iter
1380 * @error: Location to store error on failure
1381 * @user_data: Function specific data
1382 * Returns: TRUE on success, FALSE on failure
1384 * Setter for "Properties" property of a persistent group.
1386 dbus_bool_t
wpas_dbus_setter_persistent_group_properties(DBusMessageIter
*iter
,
1390 struct network_handler_args
*net
= user_data
;
1391 struct wpa_ssid
*ssid
= net
->ssid
;
1392 DBusMessageIter variant_iter
;
1395 * Leveraging the fact that persistent group object is still
1396 * represented in same manner as network within.
1398 dbus_message_iter_recurse(iter
, &variant_iter
);
1399 return set_network_properties(net
->wpa_s
, ssid
, &variant_iter
, error
);
1404 * wpas_dbus_new_iface_add_persistent_group - Add a new configured
1406 * @message: Pointer to incoming dbus message
1407 * @wpa_s: wpa_supplicant structure for a network interface
1408 * Returns: A dbus message containing the object path of the new
1411 * Handler function for "AddPersistentGroup" method call of a P2P Device
1414 DBusMessage
* wpas_dbus_handler_add_persistent_group(
1415 DBusMessage
*message
, struct wpa_supplicant
*wpa_s
)
1417 DBusMessage
*reply
= NULL
;
1418 DBusMessageIter iter
;
1419 struct wpa_ssid
*ssid
= NULL
;
1420 char path_buf
[WPAS_DBUS_OBJECT_PATH_MAX
], *path
= path_buf
;
1423 dbus_message_iter_init(message
, &iter
);
1425 ssid
= wpa_config_add_network(wpa_s
->conf
);
1427 wpa_printf(MSG_ERROR
, "dbus: %s: "
1428 "Cannot add new persistent group", __func__
);
1429 reply
= wpas_dbus_error_unknown_error(
1431 "wpa_supplicant could not add "
1432 "a persistent group on this interface.");
1436 /* Mark the ssid as being a persistent group before the notification */
1438 ssid
->p2p_persistent_group
= 1;
1439 wpas_notify_persistent_group_added(wpa_s
, ssid
);
1441 wpa_config_set_network_defaults(ssid
);
1443 dbus_error_init(&error
);
1444 if (!set_network_properties(wpa_s
, ssid
, &iter
, &error
)) {
1445 wpa_printf(MSG_DEBUG
, "dbus: %s: "
1446 "Control interface could not set persistent group "
1447 "properties", __func__
);
1448 reply
= wpas_dbus_reply_new_from_error(message
, &error
,
1449 DBUS_ERROR_INVALID_ARGS
,
1450 "Failed to set network "
1452 dbus_error_free(&error
);
1456 /* Construct the object path for this network. */
1457 os_snprintf(path
, WPAS_DBUS_OBJECT_PATH_MAX
,
1458 "%s/" WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART
"/%d",
1459 wpa_s
->dbus_new_path
, ssid
->id
);
1461 reply
= dbus_message_new_method_return(message
);
1462 if (reply
== NULL
) {
1463 reply
= dbus_message_new_error(message
, DBUS_ERROR_NO_MEMORY
,
1467 if (!dbus_message_append_args(reply
, DBUS_TYPE_OBJECT_PATH
, &path
,
1468 DBUS_TYPE_INVALID
)) {
1469 dbus_message_unref(reply
);
1470 reply
= dbus_message_new_error(message
, DBUS_ERROR_NO_MEMORY
,
1479 wpas_notify_persistent_group_removed(wpa_s
, ssid
);
1480 wpa_config_remove_network(wpa_s
->conf
, ssid
->id
);
1487 * wpas_dbus_handler_remove_persistent_group - Remove a configured persistent
1489 * @message: Pointer to incoming dbus message
1490 * @wpa_s: wpa_supplicant structure for a network interface
1491 * Returns: NULL on success or dbus error on failure
1493 * Handler function for "RemovePersistentGroup" method call of a P2P Device
1496 DBusMessage
* wpas_dbus_handler_remove_persistent_group(
1497 DBusMessage
*message
, struct wpa_supplicant
*wpa_s
)
1499 DBusMessage
*reply
= NULL
;
1501 char *iface
= NULL
, *persistent_group_id
= NULL
;
1503 struct wpa_ssid
*ssid
;
1505 dbus_message_get_args(message
, NULL
, DBUS_TYPE_OBJECT_PATH
, &op
,
1509 * Extract the network ID and ensure the network is actually a child of
1512 iface
= wpas_dbus_new_decompose_object_path(op
, 1,
1513 &persistent_group_id
,
1515 if (iface
== NULL
|| os_strcmp(iface
, wpa_s
->dbus_new_path
) != 0) {
1516 reply
= wpas_dbus_error_invalid_args(message
, op
);
1520 id
= strtoul(persistent_group_id
, NULL
, 10);
1521 if (errno
== EINVAL
) {
1522 reply
= wpas_dbus_error_invalid_args(message
, op
);
1526 ssid
= wpa_config_get_network(wpa_s
->conf
, id
);
1528 reply
= wpas_dbus_error_persistent_group_unknown(message
);
1532 wpas_notify_persistent_group_removed(wpa_s
, ssid
);
1534 if (wpa_config_remove_network(wpa_s
->conf
, id
) < 0) {
1535 wpa_printf(MSG_ERROR
, "dbus: %s: "
1536 "error occurred when removing persistent group %d",
1538 reply
= wpas_dbus_error_unknown_error(
1540 "error removing the specified persistent group on "
1547 os_free(persistent_group_id
);
1552 static void remove_persistent_group(struct wpa_supplicant
*wpa_s
,
1553 struct wpa_ssid
*ssid
)
1555 wpas_notify_persistent_group_removed(wpa_s
, ssid
);
1557 if (wpa_config_remove_network(wpa_s
->conf
, ssid
->id
) < 0) {
1558 wpa_printf(MSG_ERROR
, "dbus: %s: "
1559 "error occurred when removing persistent group %d",
1560 __func__
, ssid
->id
);
1567 * wpas_dbus_handler_remove_all_persistent_groups - Remove all configured
1569 * @message: Pointer to incoming dbus message
1570 * @wpa_s: wpa_supplicant structure for a network interface
1571 * Returns: NULL on success or dbus error on failure
1573 * Handler function for "RemoveAllPersistentGroups" method call of a
1574 * P2P Device interface.
1576 DBusMessage
* wpas_dbus_handler_remove_all_persistent_groups(
1577 DBusMessage
*message
, struct wpa_supplicant
*wpa_s
)
1579 struct wpa_ssid
*ssid
, *next
;
1580 struct wpa_config
*config
;
1582 config
= wpa_s
->conf
;
1583 ssid
= config
->ssid
;
1586 if (network_is_persistent_group(ssid
))
1587 remove_persistent_group(wpa_s
, ssid
);
1595 * Group object properties accessor methods
1598 dbus_bool_t
wpas_dbus_getter_p2p_group_members(DBusMessageIter
*iter
,
1602 struct wpa_supplicant
*wpa_s
= user_data
;
1603 struct wpa_ssid
*ssid
;
1604 unsigned int num_members
;
1609 dbus_bool_t success
= FALSE
;
1611 /* Ensure we are a GO */
1612 if (wpa_s
->wpa_state
!= WPA_COMPLETED
)
1615 ssid
= wpa_s
->conf
->ssid
;
1616 /* At present WPAS P2P_GO mode only applicable for p2p_go */
1617 if (ssid
->mode
!= WPAS_MODE_P2P_GO
&&
1618 ssid
->mode
!= WPAS_MODE_AP
&&
1619 ssid
->mode
!= WPAS_MODE_P2P_GROUP_FORMATION
)
1622 num_members
= p2p_get_group_num_members(wpa_s
->p2p_group
);
1624 paths
= os_zalloc(num_members
* sizeof(char *));
1629 while ((addr
= p2p_iterate_group_members(wpa_s
->p2p_group
, &next
))) {
1630 paths
[i
] = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX
);
1633 os_snprintf(paths
[i
], WPAS_DBUS_OBJECT_PATH_MAX
,
1634 "%s/" WPAS_DBUS_NEW_P2P_GROUPMEMBERS_PART
1636 wpa_s
->dbus_groupobj_path
, MAC2STR(addr
));
1640 success
= wpas_dbus_simple_array_property_getter(iter
,
1641 DBUS_TYPE_OBJECT_PATH
,
1645 for (i
= 0; i
< num_members
; i
++)
1651 dbus_set_error_const(error
, DBUS_ERROR_NO_MEMORY
, "no memory");
1653 for (i
= 0; i
< num_members
; i
++)
1661 dbus_bool_t
wpas_dbus_getter_p2p_group_properties(DBusMessageIter
*iter
,
1665 struct wpa_supplicant
*wpa_s
= user_data
;
1666 DBusMessageIter variant_iter
, dict_iter
;
1667 struct hostapd_data
*hapd
= wpa_s
->ap_iface
->bss
[0];
1668 const struct wpabuf
*vendor_ext
[MAX_WPS_VENDOR_EXTENSIONS
];
1669 int num_vendor_ext
= 0;
1673 dbus_set_error_const(error
, DBUS_ERROR_FAILED
,
1678 if (!dbus_message_iter_open_container(iter
, DBUS_TYPE_VARIANT
,
1679 "a{sv}", &variant_iter
) ||
1680 !wpa_dbus_dict_open_write(&variant_iter
, &dict_iter
))
1683 /* Parse WPS Vendor Extensions sent in Beacon/Probe Response */
1684 for (i
= 0; i
< MAX_WPS_VENDOR_EXTENSIONS
; i
++) {
1685 if (hapd
->conf
->wps_vendor_ext
[i
] == NULL
)
1687 vendor_ext
[num_vendor_ext
++] = hapd
->conf
->wps_vendor_ext
[i
];
1690 if (!wpa_dbus_dict_append_wpabuf_array(&dict_iter
,
1691 "WPSVendorExtensions",
1692 vendor_ext
, num_vendor_ext
))
1695 if (!wpa_dbus_dict_close_write(&variant_iter
, &dict_iter
) ||
1696 !dbus_message_iter_close_container(iter
, &variant_iter
))
1702 dbus_set_error_const(error
, DBUS_ERROR_NO_MEMORY
, "no memory");
1707 dbus_bool_t
wpas_dbus_setter_p2p_group_properties(DBusMessageIter
*iter
,
1711 struct wpa_supplicant
*wpa_s
= user_data
;
1712 DBusMessageIter variant_iter
, iter_dict
;
1713 struct wpa_dbus_dict_entry entry
= { .type
= DBUS_TYPE_STRING
};
1715 struct hostapd_data
*hapd
= wpa_s
->ap_iface
->bss
[0];
1718 dbus_set_error_const(error
, DBUS_ERROR_FAILED
,
1723 dbus_message_iter_recurse(iter
, &variant_iter
);
1724 if (!wpa_dbus_dict_open_read(&variant_iter
, &iter_dict
, error
))
1727 while (wpa_dbus_dict_has_dict_entry(&iter_dict
)) {
1728 if (!wpa_dbus_dict_get_entry(&iter_dict
, &entry
)) {
1729 dbus_set_error_const(error
, DBUS_ERROR_INVALID_ARGS
,
1730 "invalid message format");
1734 if (os_strcmp(entry
.key
, "WPSVendorExtensions") == 0) {
1735 if (entry
.type
!= DBUS_TYPE_ARRAY
||
1736 entry
.array_type
!= WPAS_DBUS_TYPE_BINARRAY
||
1737 entry
.array_len
> MAX_WPS_VENDOR_EXTENSIONS
)
1740 for (i
= 0; i
< MAX_WPS_VENDOR_EXTENSIONS
; i
++) {
1741 if (i
< entry
.array_len
) {
1742 hapd
->conf
->wps_vendor_ext
[i
] =
1743 entry
.binarray_value
[i
];
1744 entry
.binarray_value
[i
] = NULL
;
1746 hapd
->conf
->wps_vendor_ext
[i
] = NULL
;
1749 hostapd_update_wps(hapd
);
1753 wpa_dbus_dict_entry_clear(&entry
);
1759 wpa_dbus_dict_entry_clear(&entry
);
1760 dbus_set_error_const(error
, DBUS_ERROR_INVALID_ARGS
,
1761 "invalid message format");
1766 DBusMessage
* wpas_dbus_handler_p2p_add_service(DBusMessage
*message
,
1767 struct wpa_supplicant
*wpa_s
)
1769 DBusMessageIter iter_dict
;
1770 DBusMessage
*reply
= NULL
;
1771 DBusMessageIter iter
;
1772 struct wpa_dbus_dict_entry entry
;
1775 char *service
= NULL
;
1776 struct wpabuf
*query
= NULL
;
1777 struct wpabuf
*resp
= NULL
;
1780 dbus_message_iter_init(message
, &iter
);
1782 if (!wpa_dbus_dict_open_read(&iter
, &iter_dict
, NULL
))
1785 if (wpa_dbus_dict_has_dict_entry(&iter_dict
)) {
1786 if (!wpa_dbus_dict_get_entry(&iter_dict
, &entry
))
1789 if (!os_strcmp(entry
.key
, "service_type") &&
1790 (entry
.type
== DBUS_TYPE_STRING
)) {
1791 if (!os_strcmp(entry
.str_value
, "upnp"))
1793 else if (!os_strcmp(entry
.str_value
, "bonjour"))
1797 wpa_dbus_dict_entry_clear(&entry
);
1802 while (wpa_dbus_dict_has_dict_entry(&iter_dict
)) {
1803 if (!wpa_dbus_dict_get_entry(&iter_dict
, &entry
))
1806 if (!os_strcmp(entry
.key
, "version") &&
1807 entry
.type
== DBUS_TYPE_INT32
)
1808 version
= entry
.uint32_value
;
1809 else if (!os_strcmp(entry
.key
, "service") &&
1810 entry
.type
== DBUS_TYPE_STRING
)
1811 service
= os_strdup(entry
.str_value
);
1812 wpa_dbus_dict_entry_clear(&entry
);
1814 if (version
<= 0 || service
== NULL
)
1817 if (wpas_p2p_service_add_upnp(wpa_s
, version
, service
) != 0)
1821 } else if (bonjour
== 1) {
1822 while (wpa_dbus_dict_has_dict_entry(&iter_dict
)) {
1823 if (!wpa_dbus_dict_get_entry(&iter_dict
, &entry
))
1826 if (!os_strcmp(entry
.key
, "query")) {
1827 if ((entry
.type
!= DBUS_TYPE_ARRAY
) ||
1828 (entry
.array_type
!= DBUS_TYPE_BYTE
))
1830 query
= wpabuf_alloc_copy(
1831 entry
.bytearray_value
,
1833 } else if (!os_strcmp(entry
.key
, "response")) {
1834 if ((entry
.type
!= DBUS_TYPE_ARRAY
) ||
1835 (entry
.array_type
!= DBUS_TYPE_BYTE
))
1837 resp
= wpabuf_alloc_copy(entry
.bytearray_value
,
1841 wpa_dbus_dict_entry_clear(&entry
);
1844 if (query
== NULL
|| resp
== NULL
)
1847 if (wpas_p2p_service_add_bonjour(wpa_s
, query
, resp
) < 0) {
1857 wpa_dbus_dict_entry_clear(&entry
);
1859 return wpas_dbus_error_invalid_args(message
, NULL
);
1863 DBusMessage
* wpas_dbus_handler_p2p_delete_service(
1864 DBusMessage
*message
, struct wpa_supplicant
*wpa_s
)
1866 DBusMessageIter iter_dict
;
1867 DBusMessage
*reply
= NULL
;
1868 DBusMessageIter iter
;
1869 struct wpa_dbus_dict_entry entry
;
1873 char *service
= NULL
;
1874 struct wpabuf
*query
= NULL
;
1877 dbus_message_iter_init(message
, &iter
);
1879 if (!wpa_dbus_dict_open_read(&iter
, &iter_dict
, NULL
))
1882 if (wpa_dbus_dict_has_dict_entry(&iter_dict
)) {
1883 if (!wpa_dbus_dict_get_entry(&iter_dict
, &entry
))
1886 if (!os_strcmp(entry
.key
, "service_type") &&
1887 (entry
.type
== DBUS_TYPE_STRING
)) {
1888 if (!os_strcmp(entry
.str_value
, "upnp"))
1890 else if (!os_strcmp(entry
.str_value
, "bonjour"))
1894 wpa_dbus_dict_entry_clear(&entry
);
1898 while (wpa_dbus_dict_has_dict_entry(&iter_dict
)) {
1899 if (!wpa_dbus_dict_get_entry(&iter_dict
, &entry
))
1901 if (!os_strcmp(entry
.key
, "version") &&
1902 entry
.type
== DBUS_TYPE_INT32
)
1903 version
= entry
.uint32_value
;
1904 else if (!os_strcmp(entry
.key
, "service") &&
1905 entry
.type
== DBUS_TYPE_STRING
)
1906 service
= os_strdup(entry
.str_value
);
1910 wpa_dbus_dict_entry_clear(&entry
);
1913 if (version
<= 0 || service
== NULL
)
1916 ret
= wpas_p2p_service_del_upnp(wpa_s
, version
, service
);
1920 } else if (bonjour
== 1) {
1921 while (wpa_dbus_dict_has_dict_entry(&iter_dict
)) {
1922 if (!wpa_dbus_dict_get_entry(&iter_dict
, &entry
))
1925 if (!os_strcmp(entry
.key
, "query")) {
1926 if ((entry
.type
!= DBUS_TYPE_ARRAY
) ||
1927 (entry
.array_type
!= DBUS_TYPE_BYTE
))
1929 query
= wpabuf_alloc_copy(
1930 entry
.bytearray_value
,
1935 wpa_dbus_dict_entry_clear(&entry
);
1941 ret
= wpas_p2p_service_del_bonjour(wpa_s
, query
);
1950 wpa_dbus_dict_entry_clear(&entry
);
1952 return wpas_dbus_error_invalid_args(message
, NULL
);
1956 DBusMessage
* wpas_dbus_handler_p2p_flush_service(DBusMessage
*message
,
1957 struct wpa_supplicant
*wpa_s
)
1959 wpas_p2p_service_flush(wpa_s
);
1964 DBusMessage
* wpas_dbus_handler_p2p_service_sd_req(
1965 DBusMessage
*message
, struct wpa_supplicant
*wpa_s
)
1967 DBusMessageIter iter_dict
;
1968 DBusMessage
*reply
= NULL
;
1969 DBusMessageIter iter
;
1970 struct wpa_dbus_dict_entry entry
;
1972 char *service
= NULL
;
1973 char *peer_object_path
= NULL
;
1974 struct wpabuf
*tlv
= NULL
;
1979 dbus_message_iter_init(message
, &iter
);
1981 if (!wpa_dbus_dict_open_read(&iter
, &iter_dict
, NULL
))
1984 while (wpa_dbus_dict_has_dict_entry(&iter_dict
)) {
1985 if (!wpa_dbus_dict_get_entry(&iter_dict
, &entry
))
1987 if (!os_strcmp(entry
.key
, "peer_object") &&
1988 entry
.type
== DBUS_TYPE_OBJECT_PATH
) {
1989 peer_object_path
= os_strdup(entry
.str_value
);
1990 } else if (!os_strcmp(entry
.key
, "service_type") &&
1991 entry
.type
== DBUS_TYPE_STRING
) {
1992 if (!os_strcmp(entry
.str_value
, "upnp"))
1996 } else if (!os_strcmp(entry
.key
, "version") &&
1997 entry
.type
== DBUS_TYPE_INT32
) {
1998 version
= entry
.uint32_value
;
1999 } else if (!os_strcmp(entry
.key
, "service") &&
2000 entry
.type
== DBUS_TYPE_STRING
) {
2001 service
= os_strdup(entry
.str_value
);
2002 } else if (!os_strcmp(entry
.key
, "tlv")) {
2003 if (entry
.type
!= DBUS_TYPE_ARRAY
||
2004 entry
.array_type
!= DBUS_TYPE_BYTE
)
2006 tlv
= wpabuf_alloc_copy(entry
.bytearray_value
,
2011 wpa_dbus_dict_entry_clear(&entry
);
2014 if (!peer_object_path
||
2015 (parse_peer_object_path(peer_object_path
, addr
) < 0) ||
2016 (p2p_get_peer_info(wpa_s
->global
->p2p
, addr
, 0, NULL
, 0) < 0))
2020 if (version
<= 0 || service
== NULL
)
2023 ref
= (unsigned long) wpas_p2p_sd_request_upnp(wpa_s
, addr
,
2029 ref
= (unsigned long)wpas_p2p_sd_request(wpa_s
, addr
, tlv
);
2034 reply
= dbus_message_new_method_return(message
);
2035 dbus_message_append_args(reply
, DBUS_TYPE_UINT64
,
2036 &ref
, DBUS_TYPE_INVALID
);
2038 reply
= wpas_dbus_error_unknown_error(
2039 message
, "Unable to send SD request");
2043 os_free(peer_object_path
);
2046 wpa_dbus_dict_entry_clear(&entry
);
2050 reply
= wpas_dbus_error_invalid_args(message
, NULL
);
2055 DBusMessage
* wpas_dbus_handler_p2p_service_sd_res(
2056 DBusMessage
*message
, struct wpa_supplicant
*wpa_s
)
2058 DBusMessageIter iter_dict
;
2059 DBusMessage
*reply
= NULL
;
2060 DBusMessageIter iter
;
2061 struct wpa_dbus_dict_entry entry
;
2062 char *peer_object_path
= NULL
;
2063 struct wpabuf
*tlv
= NULL
;
2068 dbus_message_iter_init(message
, &iter
);
2070 if (!wpa_dbus_dict_open_read(&iter
, &iter_dict
, NULL
))
2073 while (wpa_dbus_dict_has_dict_entry(&iter_dict
)) {
2074 if (!wpa_dbus_dict_get_entry(&iter_dict
, &entry
))
2077 if (!os_strcmp(entry
.key
, "peer_object") &&
2078 entry
.type
== DBUS_TYPE_OBJECT_PATH
) {
2079 peer_object_path
= os_strdup(entry
.str_value
);
2080 } else if (!os_strcmp(entry
.key
, "frequency") &&
2081 entry
.type
== DBUS_TYPE_INT32
) {
2082 freq
= entry
.uint32_value
;
2083 } else if (!os_strcmp(entry
.key
, "dialog_token") &&
2084 entry
.type
== DBUS_TYPE_UINT32
) {
2085 dlg_tok
= entry
.uint32_value
;
2086 } else if (!os_strcmp(entry
.key
, "tlvs")) {
2087 if (entry
.type
!= DBUS_TYPE_ARRAY
||
2088 entry
.array_type
!= DBUS_TYPE_BYTE
)
2090 tlv
= wpabuf_alloc_copy(entry
.bytearray_value
,
2095 wpa_dbus_dict_entry_clear(&entry
);
2097 if (!peer_object_path
||
2098 (parse_peer_object_path(peer_object_path
, addr
) < 0) ||
2099 (p2p_get_peer_info(wpa_s
->global
->p2p
, addr
, 0, NULL
, 0) < 0))
2105 wpas_p2p_sd_response(wpa_s
, freq
, addr
, (u8
) dlg_tok
, tlv
);
2108 os_free(peer_object_path
);
2111 wpa_dbus_dict_entry_clear(&entry
);
2113 reply
= wpas_dbus_error_invalid_args(message
, NULL
);
2118 DBusMessage
* wpas_dbus_handler_p2p_service_sd_cancel_req(
2119 DBusMessage
*message
, struct wpa_supplicant
*wpa_s
)
2121 DBusMessageIter iter
;
2124 dbus_message_iter_init(message
, &iter
);
2125 dbus_message_iter_get_basic(&iter
, &req
);
2130 if (!wpas_p2p_sd_cancel_request(wpa_s
, (void *)(unsigned long) req
))
2135 return wpas_dbus_error_invalid_args(message
, NULL
);
2139 DBusMessage
* wpas_dbus_handler_p2p_service_update(
2140 DBusMessage
*message
, struct wpa_supplicant
*wpa_s
)
2142 wpas_p2p_sd_service_update(wpa_s
);
2147 DBusMessage
* wpas_dbus_handler_p2p_serv_disc_external(
2148 DBusMessage
*message
, struct wpa_supplicant
*wpa_s
)
2150 DBusMessageIter iter
;
2153 dbus_message_iter_init(message
, &iter
);
2154 dbus_message_iter_get_basic(&iter
, &ext
);
2156 wpa_s
->p2p_sd_over_ctrl_iface
= ext
;