aboutsummaryrefslogtreecommitdiffstats
path: root/wpa_supplicant/dbus
diff options
context:
space:
mode:
authorJouni Malinen <jouni@qca.qualcomm.com>2011-06-27 15:19:46 -0700
committerDmitry Shmidt <dimitrysh@google.com>2011-06-27 15:20:55 -0700
commit75ecf5267604f166b85a7ee2cf0d9cb682966680 (patch)
tree0056e7ebf5af72a85abe6c0868de6ffc2f08eaae /wpa_supplicant/dbus
parente61a2d6db6113da5fad91660764afdb0596dbc46 (diff)
downloadexternal_wpa_supplicant_8-75ecf5267604f166b85a7ee2cf0d9cb682966680.zip
external_wpa_supplicant_8-75ecf5267604f166b85a7ee2cf0d9cb682966680.tar.gz
external_wpa_supplicant_8-75ecf5267604f166b85a7ee2cf0d9cb682966680.tar.bz2
Accumulative patch from commit 20a0b03debef66cc57b0c34a05f8be5229be907c
atheros: Fix auth_alg configuration for static WEP nl80211: Implement set_rate_sets for non-hostapd AP case nl80211: Enable more AP callbacks for non-hostapd AP mode nl80211: Re-order functions to group AP/hostapd specific code Remove compiler warning for non-P2P builds random: Add support for maintaining internal entropy store over restarts Fix a compiler warning on WPS-AP-without-UPnP builds P2P: Retry provision discovery requests in IDLE state P2P: Add callback for provision discovery failure P2P: Add wpas_notify_p2p_provision_discovery() P2P: Add group started notification DBus: Move wpas_dbus_new_decompose_object_path() DBus: Refactor array adding, add binary arrays DBus: Add support for P2P primitives DBus: Fix some typos on comments Fix CONFIG_AP=y build without CONFIG_P2P=y Fix non-P2P D-Bus build nl80211: Add support for driver-based PMKSA cache P2P: Start GO without extra scan step Remove a compiler warning on uninitialized variable Add EVENT_RX_ACTION handler for hostapd Fix hostapd build without NEED_AP_MLME=y Fix AP selection to check privacy mismatch and IBSS with WPA/RSN IE bsd: Fix set_key() sequence number endian issue Add a copyright and license statement for a radiotap header file Use nl80211 as an example instead of WEXT Add notes for CONFIG_WPS_ER build configuration option Fix CONFIG_NO_WPA_PASSPHRASE=y build hostapd: Don't mask out non-symmetric STA HT caps P2P: Enable P2P capability advertisement on D-Bus P2P: Update D-Bus network object semantics during group formation P2P: Show P2P peer signal level in D-Bus P2P device properties P2P: Fix P2P device signal level type in D-Bus P2P: Add dissasoc_low_ack in P2P device properties P2P: More complete persistent group management over D-Bus P2P: Add WpsFailed signal in P2P D-Bus P2P: Update listen and operating channel from P2P D-Bus P2P: Fix WpsFailed signal in P2P D-Bus atheros: Fix glibc 'invalid pointer' error when WPA_TRACE is enabled Clear WPA and EAPOL state machine config pointer on network removal 20a0b03debef66cc57b0c34a05f8be5229be907c Change-Id: I2b83bf86ba9c7a9a218638be7b4de31d209cdde1 Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
Diffstat (limited to 'wpa_supplicant/dbus')
-rw-r--r--wpa_supplicant/dbus/dbus_dict_helpers.c219
-rw-r--r--wpa_supplicant/dbus/dbus_dict_helpers.h43
-rw-r--r--wpa_supplicant/dbus/dbus_new.c1694
-rw-r--r--wpa_supplicant/dbus/dbus_new.h212
-rw-r--r--wpa_supplicant/dbus/dbus_new_handlers.c119
-rw-r--r--wpa_supplicant/dbus/dbus_new_handlers.h5
-rw-r--r--wpa_supplicant/dbus/dbus_new_handlers_p2p.c2113
-rw-r--r--wpa_supplicant/dbus/dbus_new_handlers_p2p.h162
-rw-r--r--wpa_supplicant/dbus/dbus_new_helpers.c71
-rw-r--r--wpa_supplicant/dbus/dbus_new_helpers.h5
10 files changed, 4536 insertions, 107 deletions
diff --git a/wpa_supplicant/dbus/dbus_dict_helpers.c b/wpa_supplicant/dbus/dbus_dict_helpers.c
index d900487..788f736 100644
--- a/wpa_supplicant/dbus/dbus_dict_helpers.c
+++ b/wpa_supplicant/dbus/dbus_dict_helpers.c
@@ -16,6 +16,7 @@
#include <dbus/dbus.h>
#include "common.h"
+#include "wpabuf.h"
#include "dbus_dict_helpers.h"
@@ -443,11 +444,12 @@ dbus_bool_t wpa_dbus_dict_append_byte_array(DBusMessageIter *iter_dict,
/**
- * Begin a string array entry in the dict
+ * Begin an array entry in the dict
*
* @param iter_dict A valid DBusMessageIter returned from
* wpa_dbus_dict_open_write()
* @param key The key of the dict item
+ * @param type The type of the contained data
* @param iter_dict_entry A private DBusMessageIter provided by the caller to
* be passed to wpa_dbus_dict_end_string_array()
* @param iter_dict_val A private DBusMessageIter provided by the caller to
@@ -457,12 +459,21 @@ dbus_bool_t wpa_dbus_dict_append_byte_array(DBusMessageIter *iter_dict,
* @return TRUE on success, FALSE on failure
*
*/
-dbus_bool_t wpa_dbus_dict_begin_string_array(DBusMessageIter *iter_dict,
- const char *key,
- DBusMessageIter *iter_dict_entry,
- DBusMessageIter *iter_dict_val,
- DBusMessageIter *iter_array)
+dbus_bool_t wpa_dbus_dict_begin_array(DBusMessageIter *iter_dict,
+ const char *key, const char *type,
+ DBusMessageIter *iter_dict_entry,
+ DBusMessageIter *iter_dict_val,
+ DBusMessageIter *iter_array)
{
+ char array_type[10];
+ int err;
+
+ err = os_snprintf(array_type, sizeof(array_type),
+ DBUS_TYPE_ARRAY_AS_STRING "%s",
+ type);
+ if (err < 0 || err > (int) sizeof(array_type))
+ return FALSE;
+
if (!iter_dict || !iter_dict_entry || !iter_dict_val || !iter_array)
return FALSE;
@@ -472,20 +483,31 @@ dbus_bool_t wpa_dbus_dict_begin_string_array(DBusMessageIter *iter_dict,
if (!dbus_message_iter_open_container(iter_dict_entry,
DBUS_TYPE_VARIANT,
- DBUS_TYPE_ARRAY_AS_STRING
- DBUS_TYPE_STRING_AS_STRING,
+ array_type,
iter_dict_val))
return FALSE;
if (!dbus_message_iter_open_container(iter_dict_val, DBUS_TYPE_ARRAY,
- DBUS_TYPE_STRING_AS_STRING,
- iter_array))
+ type, iter_array))
return FALSE;
return TRUE;
}
+dbus_bool_t wpa_dbus_dict_begin_string_array(DBusMessageIter *iter_dict,
+ const char *key,
+ DBusMessageIter *iter_dict_entry,
+ DBusMessageIter *iter_dict_val,
+ DBusMessageIter *iter_array)
+{
+ return wpa_dbus_dict_begin_array(
+ iter_dict, key,
+ DBUS_TYPE_STRING_AS_STRING,
+ iter_dict_entry, iter_dict_val, iter_array);
+}
+
+
/**
* Add a single string element to a string array dict entry
*
@@ -508,23 +530,67 @@ dbus_bool_t wpa_dbus_dict_string_array_add_element(DBusMessageIter *iter_array,
/**
- * End a string array dict entry
+ * Add a single byte array element to a string array dict entry
+ *
+ * @param iter_array A valid DBusMessageIter returned from
+ * wpa_dbus_dict_begin_array()'s iter_array
+ * parameter -- note that wpa_dbus_dict_begin_array()
+ * must have been called with "ay" as the type
+ * @param value The data to be added to the dict entry's array
+ * @param value_len The length of the data
+ * @return TRUE on success, FALSE on failure
+ *
+ */
+dbus_bool_t wpa_dbus_dict_bin_array_add_element(DBusMessageIter *iter_array,
+ const u8 *value,
+ size_t value_len)
+{
+ DBusMessageIter iter_bytes;
+ size_t i;
+
+ if (!iter_array || !value)
+ return FALSE;
+
+ if (!dbus_message_iter_open_container(iter_array, DBUS_TYPE_ARRAY,
+ DBUS_TYPE_BYTE_AS_STRING,
+ &iter_bytes))
+ return FALSE;
+
+ for (i = 0; i < value_len; i++) {
+ if (!dbus_message_iter_append_basic(&iter_bytes,
+ DBUS_TYPE_BYTE,
+ &(value[i])))
+ return FALSE;
+ }
+
+ if (!dbus_message_iter_close_container(iter_array, &iter_bytes))
+ return FALSE;
+
+ return TRUE;
+}
+
+
+/**
+ * End an array dict entry
*
* @param iter_dict A valid DBusMessageIter returned from
* wpa_dbus_dict_open_write()
* @param iter_dict_entry A private DBusMessageIter returned from
- * wpa_dbus_dict_end_string_array()
+ * wpa_dbus_dict_begin_string_array() or
+ * wpa_dbus_dict_begin_array()
* @param iter_dict_val A private DBusMessageIter returned from
- * wpa_dbus_dict_end_string_array()
+ * wpa_dbus_dict_begin_string_array() or
+ * wpa_dbus_dict_begin_array()
* @param iter_array A DBusMessageIter returned from
- * wpa_dbus_dict_end_string_array()
+ * wpa_dbus_dict_begin_string_array() or
+ * wpa_dbus_dict_begin_array()
* @return TRUE on success, FALSE on failure
*
*/
-dbus_bool_t wpa_dbus_dict_end_string_array(DBusMessageIter *iter_dict,
- DBusMessageIter *iter_dict_entry,
- DBusMessageIter *iter_dict_val,
- DBusMessageIter *iter_array)
+dbus_bool_t wpa_dbus_dict_end_array(DBusMessageIter *iter_dict,
+ DBusMessageIter *iter_dict_entry,
+ DBusMessageIter *iter_dict_val,
+ DBusMessageIter *iter_array)
{
if (!iter_dict || !iter_dict_entry || !iter_dict_val || !iter_array)
return FALSE;
@@ -583,6 +649,52 @@ dbus_bool_t wpa_dbus_dict_append_string_array(DBusMessageIter *iter_dict,
}
+/**
+ * Convenience function to add an wpabuf binary array to the dict.
+ *
+ * @param iter_dict A valid DBusMessageIter returned from
+ * wpa_dbus_dict_open_write()
+ * @param key The key of the dict item
+ * @param items The array of wpabuf structures
+ * @param num_items The number of strings in the array
+ * @return TRUE on success, FALSE on failure
+ *
+ */
+dbus_bool_t wpa_dbus_dict_append_wpabuf_array(DBusMessageIter *iter_dict,
+ const char *key,
+ const struct wpabuf **items,
+ const dbus_uint32_t num_items)
+{
+ DBusMessageIter iter_dict_entry, iter_dict_val, iter_array;
+ dbus_uint32_t i;
+
+ if (!key)
+ return FALSE;
+ if (!items && (num_items != 0))
+ return FALSE;
+
+ if (!wpa_dbus_dict_begin_array(iter_dict, key,
+ DBUS_TYPE_ARRAY_AS_STRING
+ DBUS_TYPE_BYTE_AS_STRING,
+ &iter_dict_entry, &iter_dict_val,
+ &iter_array))
+ return FALSE;
+
+ for (i = 0; i < num_items; i++) {
+ if (!wpa_dbus_dict_bin_array_add_element(&iter_array,
+ wpabuf_head(items[i]),
+ wpabuf_len(items[i])))
+ return FALSE;
+ }
+
+ if (!wpa_dbus_dict_end_array(iter_dict, &iter_dict_entry,
+ &iter_dict_val, &iter_array))
+ return FALSE;
+
+ return TRUE;
+}
+
+
/*****************************************************/
/* Stuff for reading dicts */
/*****************************************************/
@@ -615,8 +727,7 @@ dbus_bool_t wpa_dbus_dict_open_read(DBusMessageIter *iter,
#define BYTE_ARRAY_ITEM_SIZE (sizeof(char))
static dbus_bool_t _wpa_dbus_dict_entry_get_byte_array(
- DBusMessageIter *iter, int array_type,
- struct wpa_dbus_dict_entry *entry)
+ DBusMessageIter *iter, struct wpa_dbus_dict_entry *entry)
{
dbus_uint32_t count = 0;
dbus_bool_t success = FALSE;
@@ -733,6 +844,66 @@ done:
}
+#define BIN_ARRAY_CHUNK_SIZE 10
+#define BIN_ARRAY_ITEM_SIZE (sizeof(struct wpabuf *))
+
+static dbus_bool_t _wpa_dbus_dict_entry_get_binarray(
+ DBusMessageIter *iter, struct wpa_dbus_dict_entry *entry)
+{
+ struct wpa_dbus_dict_entry tmpentry;
+ size_t buflen = 0;
+ int i;
+
+ if (dbus_message_iter_get_element_type(iter) != DBUS_TYPE_BYTE)
+ return FALSE;
+
+ entry->array_type = WPAS_DBUS_TYPE_BINARRAY;
+ entry->array_len = 0;
+ entry->binarray_value = NULL;
+
+ while (dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_ARRAY) {
+ DBusMessageIter iter_array;
+
+ if (entry->array_len == buflen) {
+ struct wpabuf **newbuf;
+
+ buflen += BIN_ARRAY_CHUNK_SIZE;
+
+ newbuf = os_realloc(entry->binarray_value,
+ buflen * BIN_ARRAY_ITEM_SIZE);
+ if (!newbuf)
+ goto cleanup;
+ entry->binarray_value = newbuf;
+ }
+
+ dbus_message_iter_recurse(iter, &iter_array);
+ if (_wpa_dbus_dict_entry_get_byte_array(&iter_array, &tmpentry)
+ == FALSE)
+ goto cleanup;
+
+ entry->binarray_value[entry->array_len] =
+ wpabuf_alloc_ext_data((u8 *) tmpentry.bytearray_value,
+ tmpentry.array_len);
+ if (entry->binarray_value[entry->array_len] == NULL) {
+ wpa_dbus_dict_entry_clear(&tmpentry);
+ goto cleanup;
+ }
+ entry->array_len++;
+ dbus_message_iter_next(iter);
+ }
+
+ return TRUE;
+
+ cleanup:
+ for (i = 0; i < (int) entry->array_len; i++)
+ wpabuf_free(entry->binarray_value[i]);
+ os_free(entry->binarray_value);
+ entry->array_len = 0;
+ entry->binarray_value = NULL;
+ return FALSE;
+}
+
+
static dbus_bool_t _wpa_dbus_dict_entry_get_array(
DBusMessageIter *iter_dict_val, struct wpa_dbus_dict_entry *entry)
{
@@ -748,7 +919,6 @@ static dbus_bool_t _wpa_dbus_dict_entry_get_array(
switch (array_type) {
case DBUS_TYPE_BYTE:
success = _wpa_dbus_dict_entry_get_byte_array(&iter_array,
- array_type,
entry);
break;
case DBUS_TYPE_STRING:
@@ -756,6 +926,8 @@ static dbus_bool_t _wpa_dbus_dict_entry_get_array(
array_type,
entry);
break;
+ case DBUS_TYPE_ARRAY:
+ success = _wpa_dbus_dict_entry_get_binarray(&iter_array, entry);
default:
break;
}
@@ -917,6 +1089,11 @@ void wpa_dbus_dict_entry_clear(struct wpa_dbus_dict_entry *entry)
break;
}
break;
+ case WPAS_DBUS_TYPE_BINARRAY:
+ for (i = 0; i < entry->array_len; i++)
+ wpabuf_free(entry->binarray_value[i]);
+ os_free(entry->binarray_value);
+ break;
}
memset(entry, 0, sizeof(struct wpa_dbus_dict_entry));
diff --git a/wpa_supplicant/dbus/dbus_dict_helpers.h b/wpa_supplicant/dbus/dbus_dict_helpers.h
index eb31575..9e90c50 100644
--- a/wpa_supplicant/dbus/dbus_dict_helpers.h
+++ b/wpa_supplicant/dbus/dbus_dict_helpers.h
@@ -15,6 +15,8 @@
#ifndef DBUS_DICT_HELPERS_H
#define DBUS_DICT_HELPERS_H
+#include "wpabuf.h"
+
/*
* Adding a dict to a DBusMessage
*/
@@ -74,7 +76,13 @@ dbus_bool_t wpa_dbus_dict_append_byte_array(DBusMessageIter *iter_dict,
const char *value,
const dbus_uint32_t value_len);
-/* Manual construction and addition of string array elements */
+/* Manual construction and addition of array elements */
+dbus_bool_t wpa_dbus_dict_begin_array(DBusMessageIter *iter_dict,
+ const char *key, const char *type,
+ DBusMessageIter *iter_dict_entry,
+ DBusMessageIter *iter_dict_val,
+ DBusMessageIter *iter_array);
+
dbus_bool_t wpa_dbus_dict_begin_string_array(DBusMessageIter *iter_dict,
const char *key,
DBusMessageIter *iter_dict_entry,
@@ -84,10 +92,24 @@ dbus_bool_t wpa_dbus_dict_begin_string_array(DBusMessageIter *iter_dict,
dbus_bool_t wpa_dbus_dict_string_array_add_element(DBusMessageIter *iter_array,
const char *elem);
-dbus_bool_t wpa_dbus_dict_end_string_array(DBusMessageIter *iter_dict,
- DBusMessageIter *iter_dict_entry,
- DBusMessageIter *iter_dict_val,
- DBusMessageIter *iter_array);
+dbus_bool_t wpa_dbus_dict_bin_array_add_element(DBusMessageIter *iter_array,
+ const u8 *value,
+ size_t value_len);
+
+dbus_bool_t wpa_dbus_dict_end_array(DBusMessageIter *iter_dict,
+ DBusMessageIter *iter_dict_entry,
+ DBusMessageIter *iter_dict_val,
+ DBusMessageIter *iter_array);
+
+static inline dbus_bool_t
+wpa_dbus_dict_end_string_array(DBusMessageIter *iter_dict,
+ DBusMessageIter *iter_dict_entry,
+ DBusMessageIter *iter_dict_val,
+ DBusMessageIter *iter_array)
+{
+ return wpa_dbus_dict_end_array(iter_dict, iter_dict_entry,
+ iter_dict_val, iter_array);
+}
/* Convenience function to add a whole string list */
dbus_bool_t wpa_dbus_dict_append_string_array(DBusMessageIter *iter_dict,
@@ -95,14 +117,22 @@ dbus_bool_t wpa_dbus_dict_append_string_array(DBusMessageIter *iter_dict,
const char **items,
const dbus_uint32_t num_items);
+dbus_bool_t wpa_dbus_dict_append_wpabuf_array(DBusMessageIter *iter_dict,
+ const char *key,
+ const struct wpabuf **items,
+ const dbus_uint32_t num_items);
+
/*
* Reading a dict from a DBusMessage
*/
+#define WPAS_DBUS_TYPE_BINARRAY (DBUS_NUMBER_OF_TYPES + 100)
+
struct wpa_dbus_dict_entry {
int type; /** the dbus type of the dict entry's value */
int array_type; /** the dbus type of the array elements if the dict
- entry value contains an array */
+ entry value contains an array, or the special
+ WPAS_DBUS_TYPE_BINARRAY */
const char *key; /** key of the dict entry */
/** Possible values of the property */
@@ -119,6 +149,7 @@ struct wpa_dbus_dict_entry {
double double_value;
char *bytearray_value;
char **strarray_value;
+ struct wpabuf **binarray_value;
};
dbus_uint32_t array_len; /** length of the array if the dict entry's
value contains an array */
diff --git a/wpa_supplicant/dbus/dbus_new.c b/wpa_supplicant/dbus/dbus_new.c
index 49a0895..c75fbdf 100644
--- a/wpa_supplicant/dbus/dbus_new.c
+++ b/wpa_supplicant/dbus/dbus_new.c
@@ -17,6 +17,7 @@
#include "includes.h"
#include "common.h"
+#include "common/ieee802_11_defs.h"
#include "wps/wps.h"
#include "../config.h"
#include "../wpa_supplicant_i.h"
@@ -27,6 +28,8 @@
#include "dbus_new_handlers.h"
#include "dbus_common.h"
#include "dbus_common_i.h"
+#include "dbus_new_handlers_p2p.h"
+#include "p2p/p2p.h"
/**
@@ -650,13 +653,783 @@ nomem:
#endif /* CONFIG_WPS */
+#ifdef CONFIG_P2P
+
+/**
+ * wpas_dbus_signal_p2p_group_removed - Signals P2P group was removed
+ * @wpa_s: %wpa_supplicant network interface data
+ * @role: role of this device (client or GO)
+ * Sends signal with i/f name and role as string arguments
+ */
+void wpas_dbus_signal_p2p_group_removed(struct wpa_supplicant *wpa_s,
+ const char *role)
+{
+
+ DBusMessage *msg;
+ DBusMessageIter iter;
+ struct wpas_dbus_priv *iface = wpa_s->global->dbus;
+ char *ifname = wpa_s->ifname;
+
+ /* Do nothing if the control interface is not turned on */
+ if (iface == NULL)
+ return;
+
+ msg = dbus_message_new_signal(wpa_s->dbus_new_path,
+ WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ "GroupFinished");
+ if (msg == NULL)
+ return;
+
+ dbus_message_iter_init_append(msg, &iter);
+
+ if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &ifname)) {
+ wpa_printf(MSG_ERROR, "dbus: Failed to construct GroupFinished"
+ "signal -not enough memory for ifname ");
+ goto err;
+ }
+
+ if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &role))
+ wpa_printf(MSG_ERROR, "dbus: Failed to construct GroupFinished"
+ "signal -not enough memory for role ");
+ else
+ dbus_connection_send(iface->con, msg, NULL);
+
+err:
+ dbus_message_unref(msg);
+}
+
+
+/**
+ * wpas_dbus_signal_p2p_provision_discovery - Signals various PD events
+ *
+ * @dev_addr - who sent the request or responded to our request.
+ * @request - Will be 1 if request, 0 for response.
+ * @status - valid only in case of response
+ * @config_methods - wps config methods
+ * @generated_pin - pin to be displayed in case of WPS_CONFIG_DISPLAY method
+ *
+ * Sends following provision discovery related events:
+ * ProvisionDiscoveryRequestDisplayPin
+ * ProvisionDiscoveryResponseDisplayPin
+ * ProvisionDiscoveryRequestEnterPin
+ * ProvisionDiscoveryResponseEnterPin
+ * ProvisionDiscoveryPBCRequest
+ * ProvisionDiscoveryPBCResponse
+ *
+ * TODO::
+ * ProvisionDiscoveryFailure (timeout case)
+ */
+void wpas_dbus_signal_p2p_provision_discovery(struct wpa_supplicant *wpa_s,
+ const u8 *dev_addr, int request,
+ enum p2p_prov_disc_status status,
+ u16 config_methods,
+ unsigned int generated_pin)
+{
+ DBusMessage *msg;
+ DBusMessageIter iter;
+ struct wpas_dbus_priv *iface;
+ char *_signal;
+ int add_pin = 0;
+ char peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path;
+ int error_ret = 1;
+ char pin[9], *p_pin = NULL;
+
+ iface = wpa_s->global->dbus;
+
+ /* Do nothing if the control interface is not turned on */
+ if (iface == NULL)
+ return;
+
+ if (request || !status) {
+ if (config_methods & WPS_CONFIG_DISPLAY)
+ _signal = request ?
+ "ProvisionDiscoveryRequestDisplayPin" :
+ "ProvisionDiscoveryResponseEnterPin";
+ else if (config_methods & WPS_CONFIG_KEYPAD)
+ _signal = request ?
+ "ProvisionDiscoveryRequestEnterPin" :
+ "ProvisionDiscoveryResponseDisplayPin";
+ else if (config_methods & WPS_CONFIG_PUSHBUTTON)
+ _signal = request ? "ProvisionDiscoveryPBCRequest" :
+ "ProvisionDiscoveryPBCResponse";
+ else
+ return; /* Unknown or un-supported method */
+ } else if (!request && status)
+ /* Explicit check for failure response */
+ _signal = "ProvisionDiscoveryFailure";
+
+ add_pin = ((request && (config_methods & WPS_CONFIG_DISPLAY)) ||
+ (!request && !status &&
+ (config_methods & WPS_CONFIG_KEYPAD)));
+
+ if (add_pin) {
+ os_snprintf(pin, sizeof(pin), "%08d", generated_pin);
+ p_pin = pin;
+ }
+
+ msg = dbus_message_new_signal(wpa_s->dbus_new_path,
+ WPAS_DBUS_NEW_IFACE_P2PDEVICE, _signal);
+ if (msg == NULL)
+ return;
+
+ /* Check if this is a known peer */
+ if (p2p_get_peer_info(wpa_s->global->p2p, dev_addr, 0, NULL, 0) < 0)
+ goto error;
+
+ os_snprintf(peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
+ "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/"
+ COMPACT_MACSTR,
+ wpa_s->dbus_new_path, MAC2STR(dev_addr));
+
+ path = peer_obj_path;
+
+ dbus_message_iter_init_append(msg, &iter);
+
+ if (!dbus_message_iter_append_basic(&iter,
+ DBUS_TYPE_OBJECT_PATH,
+ &path))
+ goto error;
+
+ if (!request && status)
+ /* Attach status to ProvisionDiscoveryFailure */
+ error_ret = !dbus_message_iter_append_basic(&iter,
+ DBUS_TYPE_INT32,
+ &status);
+ else
+ error_ret = (add_pin &&
+ !dbus_message_iter_append_basic(&iter,
+ DBUS_TYPE_STRING,
+ &p_pin));
+
+error:
+ if (!error_ret)
+ dbus_connection_send(iface->con, msg, NULL);
+ else
+ wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+
+ dbus_message_unref(msg);
+}
+
+
+void wpas_dbus_signal_p2p_go_neg_req(struct wpa_supplicant *wpa_s,
+ const u8 *src, u16 dev_passwd_id)
+{
+ DBusMessage *msg;
+ DBusMessageIter iter;
+ struct wpas_dbus_priv *iface;
+ char peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path;
+
+ iface = wpa_s->global->dbus;
+
+ /* Do nothing if the control interface is not turned on */
+ if (iface == NULL)
+ return;
+
+ os_snprintf(peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
+ "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/" COMPACT_MACSTR,
+ wpa_s->dbus_new_path, MAC2STR(src));
+ path = peer_obj_path;
+
+ msg = dbus_message_new_signal(wpa_s->dbus_new_path,
+ WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ "GONegotiationRequest");
+ if (msg == NULL)
+ return;
+
+ dbus_message_iter_init_append(msg, &iter);
+
+ if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
+ &path) ||
+ !dbus_message_iter_append_basic(&iter, DBUS_TYPE_UINT16,
+ &dev_passwd_id))
+ wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+ else
+ dbus_connection_send(iface->con, msg, NULL);
+
+ dbus_message_unref(msg);
+}
+
+
+static int wpas_dbus_get_group_obj_path(struct wpa_supplicant *wpa_s,
+ const struct wpa_ssid *ssid,
+ char *group_obj_path)
+{
+ char group_name[3];
+
+ if (os_memcmp(ssid->ssid, P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN))
+ return -1;
+
+ memcpy(group_name, ssid->ssid + P2P_WILDCARD_SSID_LEN, 2);
+ group_name[2] = '\0';
+
+ os_snprintf(group_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
+ "%s/" WPAS_DBUS_NEW_P2P_GROUPS_PART "/%s",
+ wpa_s->dbus_new_path, group_name);
+
+ return 0;
+}
+
+
+/**
+ * wpas_dbus_signal_p2p_group_started - Signals P2P group has
+ * started.Emitted when a group is succesfully started
+ * irrespective of the role (client/GO) of the current device
+ *
+ * @wpa_s: %wpa_supplicant network interface data
+ * @ssid: SSID object
+ * @client: this device is P2P client
+ * @network_id: network id of the group started, use instead of ssid->id
+ * to account for persistent groups
+ */
+void wpas_dbus_signal_p2p_group_started(struct wpa_supplicant *wpa_s,
+ const struct wpa_ssid *ssid,
+ int client, int network_id)
+{
+ DBusMessage *msg;
+ DBusMessageIter iter, dict_iter;
+ struct wpas_dbus_priv *iface;
+ char net_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
+ char group_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
+
+ iface = wpa_s->parent->global->dbus;
+
+ /* Do nothing if the control interface is not turned on */
+ if (iface == NULL)
+ return;
+
+ if (wpas_dbus_get_group_obj_path(wpa_s, ssid, group_obj_path) < 0)
+ return;
+
+ /* New interface has been created for this group */
+ msg = dbus_message_new_signal(wpa_s->parent->dbus_new_path,
+ WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ "GroupStarted");
+
+ if (msg == NULL)
+ return;
+
+ dbus_message_iter_init_append(msg, &iter);
+ if (!wpa_dbus_dict_open_write(&iter, &dict_iter))
+ goto nomem;
+
+ /*
+ * In case the device supports creating a separate interface the
+ * DBus client will need to know the object path for the interface
+ * object this group was created on, so include it here.
+ */
+ if (!wpa_dbus_dict_append_object_path(&dict_iter,
+ "interface_object",
+ wpa_s->dbus_new_path))
+ goto nomem;
+
+ if (!wpa_dbus_dict_append_string(&dict_iter, "role",
+ client ? "client" : "GO"))
+ goto nomem;
+
+ os_snprintf(net_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
+ "%s/" WPAS_DBUS_NEW_NETWORKS_PART "/%u",
+ wpa_s->parent->dbus_new_path, network_id);
+
+ if (!wpa_dbus_dict_append_object_path(&dict_iter, "group_object",
+ group_obj_path) ||
+ !wpa_dbus_dict_append_object_path(&dict_iter, "network_object",
+ net_obj_path) ||
+ !wpa_dbus_dict_close_write(&iter, &dict_iter))
+ goto nomem;
+
+ dbus_connection_send(iface->con, msg, NULL);
+
+nomem:
+ dbus_message_unref(msg);
+}
+
+
+/**
+ *
+ * Method to emit GONeogtiation Success or Failure signals based
+ * on status.
+ * @status: Status of the GO neg request. 0 for success, other for errors.
+ */
+void wpas_dbus_signal_p2p_go_neg_resp(struct wpa_supplicant *wpa_s, int status)
+{
+ DBusMessage *msg;
+ DBusMessageIter iter;
+ struct wpas_dbus_priv *iface;
+
+ iface = wpa_s->global->dbus;
+
+ /* Do nothing if the control interface is not turned on */
+ if (iface == NULL)
+ return;
+
+ msg = dbus_message_new_signal(wpa_s->dbus_new_path,
+ WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ status ? "GONegotiationFailure" :
+ "GONegotiationSuccess");
+ if (msg == NULL)
+ return;
+
+ if (status) {
+ dbus_message_iter_init_append(msg, &iter);
+ if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32,
+ &status)) {
+ wpa_printf(MSG_ERROR,
+ "dbus: Failed to construct signal");
+ goto err;
+ }
+ }
+
+ dbus_connection_send(iface->con, msg, NULL);
+err:
+ dbus_message_unref(msg);
+}
+
+
+/**
+ *
+ * Method to emit Invitation Result signal based on status and
+ * bssid
+ * @status: Status of the Invite request. 0 for success, other
+ * for errors
+ * @bssid : Basic Service Set Identifier
+ */
+void wpas_dbus_signal_p2p_invitation_result(struct wpa_supplicant *wpa_s,
+ int status, const u8 *bssid)
+{
+ DBusMessage *msg;
+ DBusMessageIter iter, dict_iter;
+ struct wpas_dbus_priv *iface;
+
+ wpa_printf(MSG_INFO, "%s\n", __func__);
+
+ iface = wpa_s->global->dbus;
+ /* Do nothing if the control interface is not turned on */
+ if (iface == NULL)
+ return;
+
+ msg = dbus_message_new_signal(wpa_s->dbus_new_path,
+ WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ "InvitationResult");
+
+ if (msg == NULL)
+ return;
+
+ dbus_message_iter_init_append(msg, &iter);
+ if (!wpa_dbus_dict_open_write(&iter, &dict_iter))
+ goto nomem;
+
+ if (!wpa_dbus_dict_append_int32(&dict_iter, "status", status))
+ goto nomem;
+ if (bssid) {
+ if (!wpa_dbus_dict_append_byte_array(&dict_iter, "BSSID",
+ (const char *) bssid,
+ ETH_ALEN))
+ goto nomem;
+ }
+ if (!wpa_dbus_dict_close_write(&iter, &dict_iter))
+ goto nomem;
+
+ dbus_connection_send(iface->con, msg, NULL);
+
+nomem:
+ dbus_message_unref(msg);
+}
+
+
+/**
+ *
+ * Method to emit a signal for a peer joining the group.
+ * The signal will carry path to the group member object
+ * constructed using p2p i/f addr used for connecting.
+ *
+ * @wpa_s: %wpa_supplicant network interface data
+ * @member_addr: addr (p2p i/f) of the peer joining the group
+ */
+void wpas_dbus_signal_p2p_peer_joined(struct wpa_supplicant *wpa_s,
+ const u8 *member)
+{
+ struct wpas_dbus_priv *iface;
+ DBusMessage *msg;
+ DBusMessageIter iter;
+ char groupmember_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path;
+
+ iface = wpa_s->global->dbus;
+
+ /* Do nothing if the control interface is not turned on */
+ if (iface == NULL)
+ return;
+
+ if (!wpa_s->dbus_groupobj_path)
+ return;
+
+ os_snprintf(groupmember_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
+ "%s/" WPAS_DBUS_NEW_P2P_GROUPMEMBERS_PART "/"
+ COMPACT_MACSTR,
+ wpa_s->dbus_groupobj_path, MAC2STR(member));
+
+ msg = dbus_message_new_signal(wpa_s->dbus_groupobj_path,
+ WPAS_DBUS_NEW_IFACE_P2P_GROUP,
+ "PeerJoined");
+ if (msg == NULL)
+ return;
+
+ dbus_message_iter_init_append(msg, &iter);
+ path = groupmember_obj_path;
+ if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
+ &path))
+ goto err;
+
+ dbus_connection_send(iface->con, msg, NULL);
+
+ dbus_message_unref(msg);
+ return;
+
+err:
+ wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+ dbus_message_unref(msg);
+}
+
+
+/**
+ *
+ * Method to emit a signal for a peer disconnecting the group.
+ * The signal will carry path to the group member object
+ * constructed using p2p i/f addr used for connecting.
+ *
+ * @wpa_s: %wpa_supplicant network interface data
+ * @member_addr: addr (p2p i/f) of the peer joining the group
+ */
+void wpas_dbus_signal_p2p_peer_disconnected(struct wpa_supplicant *wpa_s,
+ const u8 *member)
+{
+ struct wpas_dbus_priv *iface;
+ DBusMessage *msg;
+ DBusMessageIter iter;
+ char groupmember_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path;
+
+ iface = wpa_s->global->dbus;
+
+ /* Do nothing if the control interface is not turned on */
+ if (iface == NULL)
+ return;
+
+ if (!wpa_s->dbus_groupobj_path)
+ return;
+
+ os_snprintf(groupmember_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
+ "%s/" WPAS_DBUS_NEW_P2P_GROUPMEMBERS_PART "/"
+ COMPACT_MACSTR,
+ wpa_s->dbus_groupobj_path, MAC2STR(member));
+
+ msg = dbus_message_new_signal(wpa_s->dbus_groupobj_path,
+ WPAS_DBUS_NEW_IFACE_P2P_GROUP,
+ "PeerDisconnected");
+ if (msg == NULL)
+ return;
+
+ dbus_message_iter_init_append(msg, &iter);
+ path = groupmember_obj_path;
+ if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
+ &path))
+ goto err;
+
+ dbus_connection_send(iface->con, msg, NULL);
+
+ dbus_message_unref(msg);
+ return;
+
+err:
+ wpa_printf(MSG_ERROR, "dbus: Failed to construct PeerDisconnected "
+ "signal");
+ dbus_message_unref(msg);
+}
+
+
+/**
+ *
+ * Method to emit a signal for a service discovery request.
+ * The signal will carry station address, frequency, dialog token,
+ * update indicator and it tlvs
+ *
+ * @wpa_s: %wpa_supplicant network interface data
+ * @sa: station addr (p2p i/f) of the peer
+ * @dialog_token: service discovery request dialog token
+ * @update_indic: service discovery request update indicator
+ * @tlvs: service discovery request genrated byte array of tlvs
+ * @tlvs_len: service discovery request tlvs length
+ */
+void wpas_dbus_signal_p2p_sd_request(struct wpa_supplicant *wpa_s,
+ int freq, const u8 *sa, u8 dialog_token,
+ u16 update_indic, const u8 *tlvs,
+ size_t tlvs_len)
+{
+ DBusMessage *msg;
+ DBusMessageIter iter, dict_iter;
+ struct wpas_dbus_priv *iface;
+ char peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path;
+ iface = wpa_s->global->dbus;
+
+ /* Do nothing if the control interface is not turned on */
+ if (iface == NULL)
+ return;
+
+ msg = dbus_message_new_signal(wpa_s->dbus_new_path,
+ WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ "ServiceDiscoveryRequest");
+ if (msg == NULL)
+ return;
+
+ /* Check if this is a known peer */
+ if (p2p_get_peer_info(wpa_s->global->p2p, sa, 0, NULL, 0) < 0)
+ goto error;
+
+ os_snprintf(peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
+ "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/"
+ COMPACT_MACSTR, wpa_s->dbus_new_path, MAC2STR(sa));
+
+ path = peer_obj_path;
+
+ dbus_message_iter_init_append(msg, &iter);
+ if (!wpa_dbus_dict_open_write(&iter, &dict_iter))
+ goto error;
+
+
+ if (!wpa_dbus_dict_append_object_path(&dict_iter, "peer_object",
+ path) ||
+ !wpa_dbus_dict_append_int32(&dict_iter, "frequency", freq) ||
+ !wpa_dbus_dict_append_int32(&dict_iter, "dialog_token",
+ dialog_token) ||
+ !wpa_dbus_dict_append_uint16(&dict_iter, "update_indicator",
+ update_indic) ||
+ !wpa_dbus_dict_append_byte_array(&dict_iter, "tlvs",
+ (const char *) tlvs,
+ tlvs_len) ||
+ !wpa_dbus_dict_close_write(&iter, &dict_iter))
+ goto error;
+
+ dbus_connection_send(iface->con, msg, NULL);
+ dbus_message_unref(msg);
+ return;
+error:
+ wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+ dbus_message_unref(msg);
+}
+
+
+/**
+ *
+ * Method to emit a signal for a service discovery response.
+ * The signal will carry station address, update indicator and it
+ * tlvs
+ *
+ * @wpa_s: %wpa_supplicant network interface data
+ * @sa: station addr (p2p i/f) of the peer
+ * @update_indic: service discovery request update indicator
+ * @tlvs: service discovery request genrated byte array of tlvs
+ * @tlvs_len: service discovery request tlvs length
+ */
+void wpas_dbus_signal_p2p_sd_response(struct wpa_supplicant *wpa_s,
+ const u8 *sa, u16 update_indic,
+ const u8 *tlvs, size_t tlvs_len)
+{
+ DBusMessage *msg;
+ DBusMessageIter iter, dict_iter;
+ struct wpas_dbus_priv *iface;
+ char peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path;
+ iface = wpa_s->global->dbus;
+
+ /* Do nothing if the control interface is not turned on */
+ if (iface == NULL)
+ return;
+
+ msg = dbus_message_new_signal(wpa_s->dbus_new_path,
+ WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ "ServiceDiscoveryResponse");
+ if (msg == NULL)
+ return;
+
+ /* Check if this is a known peer */
+ if (p2p_get_peer_info(wpa_s->global->p2p, sa, 0, NULL, 0) < 0)
+ goto error;
+
+ os_snprintf(peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
+ "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/"
+ COMPACT_MACSTR, wpa_s->dbus_new_path, MAC2STR(sa));
+
+ path = peer_obj_path;
+
+ dbus_message_iter_init_append(msg, &iter);
+ if (!wpa_dbus_dict_open_write(&iter, &dict_iter))
+ goto error;
+
+ if (!wpa_dbus_dict_append_object_path(&dict_iter, "peer_object",
+ path) ||
+ !wpa_dbus_dict_append_uint16(&dict_iter, "update_indicator",
+ update_indic) ||
+ !wpa_dbus_dict_append_byte_array(&dict_iter, "tlvs",
+ (const char *) tlvs,
+ tlvs_len) ||
+ !wpa_dbus_dict_close_write(&iter, &dict_iter))
+ goto error;
+
+
+ dbus_connection_send(iface->con, msg, NULL);
+ dbus_message_unref(msg);
+ return;
+error:
+ wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+ dbus_message_unref(msg);
+}
+
+/**
+ * wpas_dbus_signal_persistent_group - Send a persistent group related
+ * event signal
+ * @wpa_s: %wpa_supplicant network interface data
+ * @id: new persistent group id
+ * @sig_name: signal name - PersistentGroupAdded, PersistentGroupRemoved
+ * @properties: determines if add second argument with object properties
+ *
+ * Notify listeners about an event related to persistent groups.
+ */
+static void wpas_dbus_signal_persistent_group(struct wpa_supplicant *wpa_s,
+ int id, const char *sig_name,
+ int properties)
+{
+ struct wpas_dbus_priv *iface;
+ DBusMessage *msg;
+ DBusMessageIter iter, iter_dict;
+ char pgrp_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path;
+
+ iface = wpa_s->global->dbus;
+
+ /* Do nothing if the control interface is not turned on */
+ if (iface == NULL)
+ return;
+
+ os_snprintf(pgrp_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
+ "%s/" WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART "/%u",
+ wpa_s->dbus_new_path, id);
+
+ msg = dbus_message_new_signal(wpa_s->dbus_new_path,
+ WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ sig_name);
+ if (msg == NULL)
+ return;
+
+ dbus_message_iter_init_append(msg, &iter);
+ path = pgrp_obj_path;
+ if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
+ &path))
+ goto err;
+
+ if (properties) {
+ if (!wpa_dbus_dict_open_write(&iter, &iter_dict))
+ goto err;
+
+ wpa_dbus_get_object_properties(
+ iface, pgrp_obj_path,
+ WPAS_DBUS_NEW_IFACE_PERSISTENT_GROUP,
+ &iter_dict);
+
+ if (!wpa_dbus_dict_close_write(&iter, &iter_dict))
+ goto err;
+ }
+
+ dbus_connection_send(iface->con, msg, NULL);
+
+ dbus_message_unref(msg);
+ return;
+
+err:
+ wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+ dbus_message_unref(msg);
+}
+
+
+/**
+ * wpas_dbus_signal_persistent_group_added - Send a persistent_group
+ * added signal
+ * @wpa_s: %wpa_supplicant network interface data
+ * @id: new persistent group id
+ *
+ * Notify listeners about addition of a new persistent group.
+ */
+static void wpas_dbus_signal_persistent_group_added(
+ struct wpa_supplicant *wpa_s, int id)
+{
+ wpas_dbus_signal_persistent_group(wpa_s, id, "PersistentGroupAdded",
+ TRUE);
+}
+
+
+/**
+ * wpas_dbus_signal_persistent_group_removed - Send a persistent_group
+ * removed signal
+ * @wpa_s: %wpa_supplicant network interface data
+ * @id: persistent group id
+ *
+ * Notify listeners about removal of a persistent group.
+ */
+static void wpas_dbus_signal_persistent_group_removed(
+ struct wpa_supplicant *wpa_s, int id)
+{
+ wpas_dbus_signal_persistent_group(wpa_s, id, "PersistentGroupRemoved",
+ FALSE);
+}
+
+
+/**
+ * wpas_dbus_signal_p2p_wps_failed - Signals WpsFailed event
+ * @wpa_s: %wpa_supplicant network interface data
+ *
+ * Sends Event dbus signal with name "fail" and dictionary containing
+ * "msg" field with fail message number (int32) as arguments
+ */
+void wpas_dbus_signal_p2p_wps_failed(struct wpa_supplicant *wpa_s,
+ struct wps_event_fail *fail)
+{
+
+ DBusMessage *msg;
+ DBusMessageIter iter, dict_iter;
+ struct wpas_dbus_priv *iface;
+ char *key = "fail";
+
+ iface = wpa_s->global->dbus;
+
+ /* Do nothing if the control interface is not turned on */
+ if (iface == NULL)
+ return;
+
+ msg = dbus_message_new_signal(wpa_s->dbus_new_path,
+ WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ "WpsFailed");
+ if (msg == NULL)
+ return;
+
+ dbus_message_iter_init_append(msg, &iter);
+
+ if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &key) ||
+ !wpa_dbus_dict_open_write(&iter, &dict_iter) ||
+ !wpa_dbus_dict_append_int32(&dict_iter, "msg", fail->msg) ||
+ !wpa_dbus_dict_append_int16(&dict_iter, "config_error",
+ fail->config_error) ||
+ !wpa_dbus_dict_close_write(&iter, &dict_iter))
+ wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+ else
+ dbus_connection_send(iface->con, msg, NULL);
+
+ dbus_message_unref(msg);
+}
+
+#endif /*CONFIG_P2P*/
+
/**
* wpas_dbus_signal_prop_changed - Signals change of property
* @wpa_s: %wpa_supplicant network interface data
* @property: indicates which property has changed
*
- * Sends ProertyChanged signals with path, interface and arguments
+ * Sends PropertyChanged signals with path, interface and arguments
* depending on which property has changed.
*/
void wpas_dbus_signal_prop_changed(struct wpa_supplicant *wpa_s,
@@ -772,7 +1545,7 @@ void wpas_dbus_bss_signal_prop_changed(struct wpa_supplicant *wpa_s,
* wpas_dbus_signal_debug_level_changed - Signals change of debug param
* @global: wpa_global structure
*
- * Sends ProertyChanged signals informing that debug level has changed.
+ * Sends PropertyChanged signals informing that debug level has changed.
*/
void wpas_dbus_signal_debug_level_changed(struct wpa_global *global)
{
@@ -786,7 +1559,7 @@ void wpas_dbus_signal_debug_level_changed(struct wpa_global *global)
* wpas_dbus_signal_debug_timestamp_changed - Signals change of debug param
* @global: wpa_global structure
*
- * Sends ProertyChanged signals informing that debug timestamp has changed.
+ * Sends PropertyChanged signals informing that debug timestamp has changed.
*/
void wpas_dbus_signal_debug_timestamp_changed(struct wpa_global *global)
{
@@ -800,7 +1573,7 @@ void wpas_dbus_signal_debug_timestamp_changed(struct wpa_global *global)
* wpas_dbus_signal_debug_show_keys_changed - Signals change of debug param
* @global: wpa_global structure
*
- * Sends ProertyChanged signals informing that debug show_keys has changed.
+ * Sends PropertyChanged signals informing that debug show_keys has changed.
*/
void wpas_dbus_signal_debug_show_keys_changed(struct wpa_global *global)
{
@@ -1021,6 +1794,14 @@ int wpas_dbus_register_network(struct wpa_supplicant *wpa_s,
struct network_handler_args *arg;
char net_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
+ /*
+ * If it is a persistent group register it as such.
+ * This is to handle cases where an interface is being initialized
+ * with a list of networks read from config.
+ */
+ if (network_is_persistent_group(ssid))
+ return wpas_dbus_register_persistent_group(wpa_s, ssid);
+
/* Do nothing if the control interface is not turned on */
if (wpa_s == NULL || wpa_s->global == NULL)
return 0;
@@ -1083,6 +1864,13 @@ int wpas_dbus_unregister_network(struct wpa_supplicant *wpa_s, int nid)
struct wpas_dbus_priv *ctrl_iface;
char net_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
int ret;
+ struct wpa_ssid *ssid;
+
+ ssid = wpa_config_get_network(wpa_s->conf, nid);
+
+ /* If it is a persistent group unregister it as such */
+ if (ssid && network_is_persistent_group(ssid))
+ return wpas_dbus_unregister_persistent_group(wpa_s, nid);
/* Do nothing if the control interface is not turned on */
if (wpa_s == NULL || wpa_s->global == NULL ||
@@ -1358,6 +2146,174 @@ static const struct wpa_dbus_method_desc wpas_dbus_interface_methods[] = {
}
},
#endif /* CONFIG_WPS */
+#ifdef CONFIG_P2P
+ { "Find", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ (WPADBusMethodHandler)wpas_dbus_handler_p2p_find,
+ {
+ { "args", "a{sv}", ARG_IN },
+ END_ARGS
+ }
+ },
+ { "StopFind", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ (WPADBusMethodHandler)wpas_dbus_handler_p2p_stop_find,
+ {
+ END_ARGS
+ }
+ },
+ { "Listen", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ (WPADBusMethodHandler)wpas_dbus_handler_p2p_listen,
+ {
+ { "timeout", "i", ARG_IN },
+ END_ARGS
+ }
+ },
+ { "ExtendedListen", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ (WPADBusMethodHandler)wpas_dbus_handler_p2p_extendedlisten,
+ {
+ { "args", "a{sv}", ARG_IN },
+ END_ARGS
+ }
+ },
+ { "PresenceRequest", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ (WPADBusMethodHandler)wpas_dbus_handler_p2p_presence_request,
+ {
+ { "args", "a{sv}", ARG_IN },
+ END_ARGS
+ }
+ },
+ { "ProvisionDiscoveryRequest", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ (WPADBusMethodHandler)wpas_dbus_handler_p2p_prov_disc_req,
+ {
+ { "peer", "o", ARG_IN },
+ { "config_method", "s", ARG_IN },
+ END_ARGS
+ }
+ },
+ { "Connect", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ (WPADBusMethodHandler)wpas_dbus_handler_p2p_connect,
+ {
+ { "args", "a{sv}", ARG_IN },
+ { "generated_pin", "i", ARG_OUT },
+ END_ARGS
+ }
+ },
+ { "GroupAdd", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ (WPADBusMethodHandler)wpas_dbus_handler_p2p_group_add,
+ {
+ { "args", "a{sv}", ARG_IN },
+ END_ARGS
+ }
+ },
+ { "Invite", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ (WPADBusMethodHandler)wpas_dbus_handler_p2p_invite,
+ {
+ { "args", "a{sv}", ARG_IN },
+ END_ARGS
+ }
+ },
+ { "Disconnect", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ (WPADBusMethodHandler)wpas_dbus_handler_p2p_disconnect,
+ {
+ END_ARGS
+ }
+ },
+ { "RejectPeer", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ (WPADBusMethodHandler)wpas_dbus_handler_p2p_rejectpeer,
+ {
+ { "peer", "o", ARG_IN },
+ END_ARGS
+ }
+ },
+ { "Flush", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ (WPADBusMethodHandler)wpas_dbus_handler_p2p_flush,
+ {
+ END_ARGS
+ }
+ },
+ { "AddService", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ (WPADBusMethodHandler)wpas_dbus_handler_p2p_add_service,
+ {
+ { "args", "a{sv}", ARG_IN },
+ END_ARGS
+ }
+ },
+ { "DeleteService", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ (WPADBusMethodHandler)wpas_dbus_handler_p2p_delete_service,
+ {
+ { "args", "a{sv}", ARG_IN },
+ END_ARGS
+ }
+ },
+ { "FlushService", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ (WPADBusMethodHandler)wpas_dbus_handler_p2p_flush_service,
+ {
+ END_ARGS
+ }
+ },
+ { "ServiceDiscoveryRequest", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ (WPADBusMethodHandler)wpas_dbus_handler_p2p_service_sd_req,
+ {
+ { "args", "a{sv}", ARG_IN },
+ END_ARGS
+ }
+ },
+ { "ServiceDiscoveryResponse", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ (WPADBusMethodHandler)wpas_dbus_handler_p2p_service_sd_res,
+ {
+ { "args", "a{sv}", ARG_IN },
+ END_ARGS
+ }
+ },
+ { "ServiceDiscoveryCancelRequest", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ (WPADBusMethodHandler)wpas_dbus_handler_p2p_service_sd_cancel_req,
+ {
+ { "args", "t", ARG_IN },
+ END_ARGS
+ }
+ },
+ { "ServiceUpdate", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ (WPADBusMethodHandler)wpas_dbus_handler_p2p_service_update,
+ {
+ END_ARGS
+ }
+ },
+ { "ServiceDiscoveryExternal", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ (WPADBusMethodHandler)wpas_dbus_handler_p2p_serv_disc_external,
+ {
+ { "arg", "i", ARG_IN },
+ END_ARGS
+ }
+ },
+ { "ServiceDiscoveryExternal", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ (WPADBusMethodHandler)wpas_dbus_handler_p2p_serv_disc_external,
+ {
+ { "arg", "i", ARG_IN },
+ END_ARGS
+ }
+ },
+ { "AddPersistentGroup", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ (WPADBusMethodHandler) wpas_dbus_handler_add_persistent_group,
+ {
+ { "args", "a{sv}", ARG_IN },
+ { "path", "o", ARG_OUT },
+ END_ARGS
+ }
+ },
+ { "RemovePersistentGroup", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ (WPADBusMethodHandler) wpas_dbus_handler_remove_persistent_group,
+ {
+ { "path", "o", ARG_IN },
+ END_ARGS
+ }
+ },
+ { "RemoveAllPersistentGroups", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ (WPADBusMethodHandler)
+ wpas_dbus_handler_remove_all_persistent_groups,
+ {
+ END_ARGS
+ }
+ },
+#endif /* CONFIG_P2P */
{ "FlushBSS", WPAS_DBUS_NEW_IFACE_INTERFACE,
(WPADBusMethodHandler) &wpas_dbus_handler_flush_bss,
{
@@ -1444,6 +2400,33 @@ static const struct wpa_dbus_property_desc wpas_dbus_interface_properties[] = {
RW
},
#endif /* CONFIG_WPS */
+#ifdef CONFIG_P2P
+ { "P2PDeviceProperties", WPAS_DBUS_NEW_IFACE_P2PDEVICE, "a{sv}",
+ (WPADBusPropertyAccessor) wpas_dbus_getter_p2p_device_properties,
+ (WPADBusPropertyAccessor) wpas_dbus_setter_p2p_device_properties,
+ RW
+ },
+ { "Peers", WPAS_DBUS_NEW_IFACE_P2PDEVICE, "ao",
+ (WPADBusPropertyAccessor) wpas_dbus_getter_p2p_peers,
+ NULL, R
+ },
+ { "Role", WPAS_DBUS_NEW_IFACE_P2PDEVICE, "s",
+ (WPADBusPropertyAccessor) wpas_dbus_getter_p2p_role,
+ NULL, R
+ },
+ { "Group", WPAS_DBUS_NEW_IFACE_P2PDEVICE, "o",
+ (WPADBusPropertyAccessor) wpas_dbus_getter_p2p_group,
+ NULL, R
+ },
+ { "PeerGO", WPAS_DBUS_NEW_IFACE_P2PDEVICE, "o",
+ (WPADBusPropertyAccessor) wpas_dbus_getter_p2p_peergo,
+ NULL, R
+ },
+ { "PersistentGroups", WPAS_DBUS_NEW_IFACE_P2PDEVICE, "ao",
+ (WPADBusPropertyAccessor) wpas_dbus_getter_persistent_groups,
+ NULL, R
+ },
+#endif /* CONFIG_P2P */
{ NULL, NULL, NULL, NULL, NULL, 0 }
};
@@ -1525,6 +2508,135 @@ static const struct wpa_dbus_signal_desc wpas_dbus_interface_signals[] = {
}
},
#endif /* CONFIG_WPS */
+#ifdef CONFIG_P2P
+ { "P2PStateChanged", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ {
+ { "states", "a{ss}", ARG_OUT },
+ END_ARGS
+ }
+ },
+ { "DeviceFound", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ {
+ { "path", "o", ARG_OUT },
+ { "properties", "a{sv}", ARG_OUT },
+ END_ARGS
+ }
+ },
+ { "DeviceLost", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ {
+ { "path", "o", ARG_OUT },
+ END_ARGS
+ }
+ },
+ { "ProvisionDiscoveryRequestDisplayPin", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ {
+ { "peer_object", "o", ARG_OUT },
+ { "pin", "s", ARG_OUT },
+ END_ARGS
+ }
+ },
+ { "ProvisionDiscoveryResponseDisplayPin", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ {
+ { "peer_object", "o", ARG_OUT },
+ { "pin", "s", ARG_OUT },
+ END_ARGS
+ }
+ },
+ { "ProvisionDiscoveryRequestEnterPin", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ {
+ { "peer_object", "o", ARG_OUT },
+ END_ARGS
+ }
+ },
+ { "ProvisionDiscoveryResponseEnterPin", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ {
+ { "peer_object", "o", ARG_OUT },
+ END_ARGS
+ }
+ },
+ { "ProvisionDiscoveryPBCRequest", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ {
+ { "peer_object", "o", ARG_OUT },
+ END_ARGS
+ }
+ },
+ { "ProvisionDiscoveryPBCResponse", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ {
+ { "peer_object", "o", ARG_OUT },
+ END_ARGS
+ }
+ },
+ { "ProvisionDiscoveryFailure", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ {
+ { "peer_object", "o", ARG_OUT },
+ { "status", "i", ARG_OUT },
+ END_ARGS
+ }
+ },
+ { "GroupStarted", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ {
+ { "properties", "a{sv}", ARG_OUT },
+ END_ARGS
+ }
+ },
+ { "GONegotiationSuccess", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ {
+ END_ARGS
+ }
+ },
+ { "GONegotiationFailure", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ {
+ { "status", "i", ARG_OUT },
+ END_ARGS
+ }
+ },
+ { "GONegotiationRequest", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ {
+ { "path", "o", ARG_OUT },
+ { "dev_passwd_id", "i", ARG_OUT },
+ END_ARGS
+ }
+ },
+ { "InvitationResult", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ {
+ { "invite_result", "a{sv}", ARG_OUT },
+ END_ARGS
+ }
+ },
+ { "GroupFinished", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ {
+ { "ifname", "s", ARG_OUT },
+ { "role", "s", ARG_OUT },
+ END_ARGS
+ }
+ },
+ { "ServiceDiscoveryRequest", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ {
+ { "sd_request", "a{sv}", ARG_OUT },
+ END_ARGS
+ }
+ },
+ { "ServiceDiscoveryResponse", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ {
+ { "sd_response", "a{sv}", ARG_OUT },
+ END_ARGS
+ }
+ },
+ { "PersistentGroupAdded", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ {
+ { "path", "o", ARG_OUT },
+ { "properties", "a{sv}", ARG_OUT },
+ END_ARGS
+ }
+ },
+ { "WpsFailed", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ {
+ { "name", "s", ARG_OUT },
+ { "args", "a{sv}", ARG_OUT },
+ END_ARGS
+ }
+ },
+#endif /* CONFIG_P2P */
{ NULL, NULL, { END_ARGS } }
};
@@ -1603,3 +2715,577 @@ int wpas_dbus_unregister_interface(struct wpa_supplicant *wpa_s)
return 0;
}
+
+#ifdef CONFIG_P2P
+
+static const struct wpa_dbus_property_desc wpas_dbus_p2p_peer_properties[] = {
+ { "Properties", WPAS_DBUS_NEW_IFACE_P2P_PEER, "a{sv}",
+ (WPADBusPropertyAccessor) wpas_dbus_getter_p2p_peer_properties,
+ NULL, R
+ },
+ { "IEs", WPAS_DBUS_NEW_IFACE_P2P_PEER, "ay",
+ (WPADBusPropertyAccessor) wpas_dbus_getter_p2p_peer_ies,
+ NULL, R
+ },
+ { NULL, NULL, NULL, NULL, NULL, 0 }
+};
+
+static const struct wpa_dbus_signal_desc wpas_dbus_p2p_peer_signals[] = {
+
+ { NULL, NULL, { END_ARGS } }
+};
+
+/**
+ * wpas_dbus_signal_peer - Send a peer related event signal
+ * @wpa_s: %wpa_supplicant network interface data
+ * @dev: peer device object
+ * @interface: name of the interface emitting this signal.
+ * In case of peer objects, it would be emitted by either
+ * the "interface object" or by "peer objects"
+ * @sig_name: signal name - DeviceFound
+ *
+ * Notify listeners about event related with newly found p2p peer device
+ */
+static void wpas_dbus_signal_peer(struct wpa_supplicant *wpa_s,
+ const u8 *dev_addr, const char *interface,
+ const char *sig_name)
+{
+ struct wpas_dbus_priv *iface;
+ DBusMessage *msg;
+ DBusMessageIter iter;
+ char peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path;
+
+ iface = wpa_s->global->dbus;
+
+ /* Do nothing if the control interface is not turned on */
+ if (iface == NULL)
+ return;
+
+ os_snprintf(peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
+ "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/" COMPACT_MACSTR,
+ wpa_s->dbus_new_path, MAC2STR(dev_addr));
+
+ msg = dbus_message_new_signal(wpa_s->dbus_new_path, interface,
+ sig_name);
+ if (msg == NULL)
+ return;
+
+ dbus_message_iter_init_append(msg, &iter);
+ path = peer_obj_path;
+ if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
+ &path))
+ goto err;
+
+ dbus_connection_send(iface->con, msg, NULL);
+
+ dbus_message_unref(msg);
+ return;
+
+err:
+ wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+ dbus_message_unref(msg);
+}
+
+
+/**
+ * wpas_dbus_signal_peer_found - Send a peer found signal
+ * @wpa_s: %wpa_supplicant network interface data
+ * @dev: peer device object
+ *
+ * Notify listeners about find a p2p peer device found
+ */
+void wpas_dbus_signal_peer_device_found(struct wpa_supplicant *wpa_s,
+ const u8 *dev_addr)
+{
+ wpas_dbus_signal_peer(wpa_s, dev_addr,
+ WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ "DeviceFound");
+}
+
+/**
+ * wpas_dbus_signal_peer_lost - Send a peer lost signal
+ * @wpa_s: %wpa_supplicant network interface data
+ * @dev: peer device object
+ *
+ * Notify listeners about lost a p2p peer device
+ */
+void wpas_dbus_signal_peer_device_lost(struct wpa_supplicant *wpa_s,
+ const u8 *dev_addr)
+{
+ wpas_dbus_signal_peer(wpa_s, dev_addr,
+ WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ "DeviceLost");
+}
+
+/**
+ * wpas_dbus_register_peer - Register a discovered peer object with dbus
+ * @wpa_s: wpa_supplicant interface structure
+ * @ssid: network configuration data
+ * Returns: 0 on success, -1 on failure
+ *
+ * Registers network representing object with dbus
+ */
+int wpas_dbus_register_peer(struct wpa_supplicant *wpa_s, const u8 *dev_addr)
+{
+ struct wpas_dbus_priv *ctrl_iface;
+ struct wpa_dbus_object_desc *obj_desc;
+ struct peer_handler_args *arg;
+ char peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
+
+ /* Do nothing if the control interface is not turned on */
+ if (wpa_s == NULL || wpa_s->global == NULL)
+ return 0;
+
+ ctrl_iface = wpa_s->global->dbus;
+ if (ctrl_iface == NULL)
+ return 0;
+
+ os_snprintf(peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
+ "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/" COMPACT_MACSTR,
+ wpa_s->dbus_new_path, MAC2STR(dev_addr));
+
+ wpa_printf(MSG_INFO, "dbus: Register peer object '%s'",
+ peer_obj_path);
+ obj_desc = os_zalloc(sizeof(struct wpa_dbus_object_desc));
+ if (!obj_desc) {
+ wpa_printf(MSG_ERROR, "Not enough memory "
+ "to create object description");
+ goto err;
+ }
+
+ /* allocate memory for handlers arguments */
+ arg = os_zalloc(sizeof(struct peer_handler_args));
+ if (!arg) {
+ wpa_printf(MSG_ERROR, "Not enough memory "
+ "to create arguments for method");
+ goto err;
+ }
+
+ arg->wpa_s = wpa_s;
+ os_memcpy(arg->p2p_device_addr, dev_addr, ETH_ALEN);
+
+ wpas_dbus_register(obj_desc, arg, wpa_dbus_free,
+ NULL,
+ wpas_dbus_p2p_peer_properties,
+ wpas_dbus_p2p_peer_signals);
+
+ if (wpa_dbus_register_object_per_iface(ctrl_iface, peer_obj_path,
+ wpa_s->ifname, obj_desc))
+ goto err;
+
+ return 0;
+
+err:
+ free_dbus_object_desc(obj_desc);
+ return -1;
+}
+
+/**
+ * wpas_dbus_unregister_peer - Unregister a peer object with dbus
+ * @wpa_s: wpa_supplicant interface structure
+ * @dev_addr: p2p device addr
+ * Returns: 0 on success, -1 on failure
+ *
+ * Registers network representing object with dbus
+ */
+int wpas_dbus_unregister_peer(struct wpa_supplicant *wpa_s,
+ const u8 *dev_addr)
+{
+ struct wpas_dbus_priv *ctrl_iface;
+ char peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
+ int ret;
+
+ /* Do nothing if the control interface is not turned on */
+ if (wpa_s == NULL || wpa_s->global == NULL ||
+ wpa_s->dbus_new_path == NULL)
+ return 0;
+ ctrl_iface = wpa_s->global->dbus;
+ if (ctrl_iface == NULL)
+ return 0;
+
+ os_snprintf(peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
+ "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/" COMPACT_MACSTR,
+ wpa_s->dbus_new_path, MAC2STR(dev_addr));
+
+ wpa_printf(MSG_INFO, "dbus: Unregister peer object '%s'",
+ peer_obj_path);
+ ret = wpa_dbus_unregister_object_per_iface(ctrl_iface, peer_obj_path);
+
+ return ret;
+}
+
+
+static const struct wpa_dbus_property_desc wpas_dbus_p2p_group_properties[] = {
+ { "Members", WPAS_DBUS_NEW_IFACE_P2P_GROUP, "ao",
+ (WPADBusPropertyAccessor) wpas_dbus_getter_p2p_group_members,
+ NULL, R
+ },
+ { "Properties",
+ WPAS_DBUS_NEW_IFACE_P2P_GROUP, "a{sv}",
+ (WPADBusPropertyAccessor) wpas_dbus_getter_p2p_group_properties,
+ (WPADBusPropertyAccessor) wpas_dbus_setter_p2p_group_properties,
+ RW
+ },
+ { NULL, NULL, NULL, NULL, NULL, 0 }
+};
+
+static const struct wpa_dbus_signal_desc wpas_dbus_p2p_group_signals[] = {
+ { "PeerJoined", WPAS_DBUS_NEW_IFACE_P2P_GROUP,
+ {
+ { "peer", "o", ARG_OUT },
+ END_ARGS
+ }
+ },
+ { "PeerDisconnected", WPAS_DBUS_NEW_IFACE_P2P_GROUP,
+ {
+ { "peer", "o", ARG_OUT },
+ END_ARGS
+ }
+ },
+ { NULL, NULL, { END_ARGS } }
+};
+
+/**
+ * wpas_dbus_register_p2p_group - Register a p2p group object with dbus
+ * @wpa_s: wpa_supplicant interface structure
+ * @ssid: SSID struct
+ * Returns: 0 on success, -1 on failure
+ *
+ * Registers p2p group representing object with dbus
+ */
+void wpas_dbus_register_p2p_group(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid)
+{
+ struct wpas_dbus_priv *ctrl_iface;
+ struct wpa_dbus_object_desc *obj_desc;
+ char group_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
+
+ /* Do nothing if the control interface is not turned on */
+ if (wpa_s == NULL || wpa_s->global == NULL)
+ return;
+
+ ctrl_iface = wpa_s->global->dbus;
+ if (ctrl_iface == NULL)
+ return;
+
+ if (wpa_s->dbus_groupobj_path) {
+ wpa_printf(MSG_INFO, "%s: Group object '%s' already exists",
+ __func__, wpa_s->dbus_groupobj_path);
+ return;
+ }
+
+ if (wpas_dbus_get_group_obj_path(wpa_s, ssid, group_obj_path) < 0)
+ return;
+
+ wpa_s->dbus_groupobj_path = os_strdup(group_obj_path);
+ if (wpa_s->dbus_groupobj_path == NULL)
+ return;
+
+ wpa_printf(MSG_INFO, "dbus: Register group object '%s'",
+ group_obj_path);
+ obj_desc = os_zalloc(sizeof(struct wpa_dbus_object_desc));
+ if (!obj_desc) {
+ wpa_printf(MSG_ERROR, "Not enough memory "
+ "to create object description");
+ goto err;
+ }
+
+ wpas_dbus_register(obj_desc, wpa_s, NULL, NULL,
+ wpas_dbus_p2p_group_properties,
+ wpas_dbus_p2p_group_signals);
+
+ if (wpa_dbus_register_object_per_iface(ctrl_iface, group_obj_path,
+ wpa_s->ifname, obj_desc))
+ goto err;
+
+ return;
+
+err:
+ if (wpa_s->dbus_groupobj_path) {
+ os_free(wpa_s->dbus_groupobj_path);
+ wpa_s->dbus_groupobj_path = NULL;
+ }
+
+ free_dbus_object_desc(obj_desc);
+}
+
+/**
+ * wpas_dbus_unregister_p2p_group - Unregister a p2p group object from dbus
+ * @wpa_s: wpa_supplicant interface structure
+ * @ssid: network name of the p2p group started
+ */
+void wpas_dbus_unregister_p2p_group(struct wpa_supplicant *wpa_s,
+ const struct wpa_ssid *ssid)
+{
+ struct wpas_dbus_priv *ctrl_iface;
+
+ /* Do nothing if the control interface is not turned on */
+ if (wpa_s == NULL || wpa_s->global == NULL)
+ return;
+
+ ctrl_iface = wpa_s->global->dbus;
+ if (ctrl_iface == NULL)
+ return;
+
+ if (!wpa_s->dbus_groupobj_path) {
+ wpa_printf(MSG_DEBUG,
+ "%s: Group object '%s' already unregistered",
+ __func__, wpa_s->dbus_groupobj_path);
+ return;
+ }
+
+ wpa_printf(MSG_DEBUG, "dbus: Unregister group object '%s'",
+ wpa_s->dbus_groupobj_path);
+
+ wpa_dbus_unregister_object_per_iface(ctrl_iface,
+ wpa_s->dbus_groupobj_path);
+
+ os_free(wpa_s->dbus_groupobj_path);
+ wpa_s->dbus_groupobj_path = NULL;
+}
+
+static const struct wpa_dbus_property_desc
+wpas_dbus_p2p_groupmember_properties[] = {
+ { "Properties", WPAS_DBUS_NEW_IFACE_P2P_GROUPMEMBER, "a{sv}",
+ (WPADBusPropertyAccessor) wpas_dbus_getter_p2p_group_properties,
+ NULL, R
+ },
+ { NULL, NULL, NULL, NULL, NULL, 0 }
+};
+
+/**
+ * wpas_dbus_register_p2p_groupmember - Register a p2p groupmember
+ * object with dbus
+ * @wpa_s: wpa_supplicant interface structure
+ * @p2p_if_addr: i/f addr of the device joining this group
+ *
+ * Registers p2p groupmember representing object with dbus
+ */
+void wpas_dbus_register_p2p_groupmember(struct wpa_supplicant *wpa_s,
+ const u8 *p2p_if_addr)
+{
+ struct wpas_dbus_priv *ctrl_iface;
+ struct wpa_dbus_object_desc *obj_desc = NULL;
+ struct groupmember_handler_args *arg;
+ char groupmember_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
+
+ /* Do nothing if the control interface is not turned on */
+ if (wpa_s == NULL || wpa_s->global == NULL)
+ return;
+
+ ctrl_iface = wpa_s->global->dbus;
+ if (ctrl_iface == NULL)
+ return;
+
+ if (!wpa_s->dbus_groupobj_path)
+ return;
+
+ os_snprintf(groupmember_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
+ "%s/" WPAS_DBUS_NEW_P2P_GROUPMEMBERS_PART "/" COMPACT_MACSTR,
+ wpa_s->dbus_groupobj_path, MAC2STR(p2p_if_addr));
+
+ obj_desc = os_zalloc(sizeof(struct wpa_dbus_object_desc));
+ if (!obj_desc) {
+ wpa_printf(MSG_ERROR, "Not enough memory "
+ "to create object description");
+ goto err;
+ }
+
+ /* allocate memory for handlers arguments */
+ arg = os_zalloc(sizeof(struct groupmember_handler_args));
+ if (!arg) {
+ wpa_printf(MSG_ERROR, "Not enough memory "
+ "to create arguments for method");
+ goto err;
+ }
+
+ arg->wpa_s = wpa_s;
+ os_memcpy(arg->member_addr, p2p_if_addr, ETH_ALEN);
+
+ wpas_dbus_register(obj_desc, arg, wpa_dbus_free, NULL,
+ wpas_dbus_p2p_groupmember_properties, NULL);
+
+ if (wpa_dbus_register_object_per_iface(ctrl_iface, groupmember_obj_path,
+ wpa_s->ifname, obj_desc))
+ goto err;
+
+ wpa_printf(MSG_INFO,
+ "dbus: Registered group member object '%s' successfully",
+ groupmember_obj_path);
+ return;
+
+err:
+ free_dbus_object_desc(obj_desc);
+}
+
+/**
+ * wpas_dbus_unregister_p2p_groupmember - Unregister a p2p groupmember
+ * object with dbus
+ * @wpa_s: wpa_supplicant interface structure
+ * @p2p_if_addr: i/f addr of the device joining this group
+ *
+ * Unregisters p2p groupmember representing object with dbus
+ */
+void wpas_dbus_unregister_p2p_groupmember(struct wpa_supplicant *wpa_s,
+ const u8 *p2p_if_addr)
+{
+ struct wpas_dbus_priv *ctrl_iface;
+ char groupmember_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
+
+ /* Do nothing if the control interface is not turned on */
+ if (wpa_s == NULL || wpa_s->global == NULL)
+ return;
+
+ ctrl_iface = wpa_s->global->dbus;
+ if (ctrl_iface == NULL)
+ return;
+
+ if (!wpa_s->dbus_groupobj_path)
+ return;
+
+ os_snprintf(groupmember_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
+ "%s/" WPAS_DBUS_NEW_P2P_GROUPMEMBERS_PART "/" COMPACT_MACSTR,
+ wpa_s->dbus_groupobj_path, MAC2STR(p2p_if_addr));
+
+ wpa_dbus_unregister_object_per_iface(ctrl_iface, groupmember_obj_path);
+}
+
+
+static const struct wpa_dbus_property_desc
+ wpas_dbus_persistent_group_properties[] = {
+ { "Properties", WPAS_DBUS_NEW_IFACE_PERSISTENT_GROUP, "a{sv}",
+ (WPADBusPropertyAccessor)
+ wpas_dbus_getter_persistent_group_properties,
+ (WPADBusPropertyAccessor)
+ wpas_dbus_setter_persistent_group_properties,
+ RW
+ },
+ { NULL, NULL, NULL, NULL, NULL, 0 }
+};
+
+/* No signals intended for persistent group objects */
+
+/**
+ * wpas_dbus_register_persistent_group - Register a configured(saved)
+ * persistent group with dbus
+ * @wpa_s: wpa_supplicant interface structure
+ * @ssid: persistent group (still represented as a network within wpa)
+ * configuration data
+ * Returns: 0 on success, -1 on failure
+ *
+ * Registers a persistent group representing object with dbus.
+ */
+int wpas_dbus_register_persistent_group(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid)
+{
+ struct wpas_dbus_priv *ctrl_iface;
+ struct wpa_dbus_object_desc *obj_desc;
+ struct network_handler_args *arg;
+ char pgrp_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
+
+ /* Do nothing if the control interface is not turned on */
+ if (wpa_s == NULL || wpa_s->global == NULL)
+ return 0;
+
+ /* Make sure ssid is a persistent group */
+ if (ssid->disabled != 2 && !ssid->p2p_persistent_group)
+ return -1; /* should we return w/o complaining? */
+
+ ctrl_iface = wpa_s->global->dbus;
+ if (ctrl_iface == NULL)
+ return 0;
+
+ /*
+ * Intentionally not coming up with different numbering scheme
+ * for persistent groups.
+ */
+ os_snprintf(pgrp_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
+ "%s/" WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART "/%u",
+ wpa_s->dbus_new_path, ssid->id);
+
+ wpa_printf(MSG_DEBUG, "dbus: Register persistent group object '%s'",
+ pgrp_obj_path);
+ obj_desc = os_zalloc(sizeof(struct wpa_dbus_object_desc));
+ if (!obj_desc) {
+ wpa_printf(MSG_ERROR, "dbus: Not enough memory to create "
+ "object description");
+ goto err;
+ }
+
+ /*
+ * Reusing the same context structure as that for networks
+ * since these are represented using same data structure.
+ */
+ /* allocate memory for handlers arguments */
+ arg = os_zalloc(sizeof(struct network_handler_args));
+ if (!arg) {
+ wpa_printf(MSG_ERROR, "dbus: Not enough memory to create "
+ "arguments for method");
+ goto err;
+ }
+
+ arg->wpa_s = wpa_s;
+ arg->ssid = ssid;
+
+ wpas_dbus_register(obj_desc, arg, wpa_dbus_free, NULL,
+ wpas_dbus_persistent_group_properties,
+ NULL);
+
+ if (wpa_dbus_register_object_per_iface(ctrl_iface, pgrp_obj_path,
+ wpa_s->ifname, obj_desc))
+ goto err;
+
+ wpas_dbus_signal_persistent_group_added(wpa_s, ssid->id);
+
+ return 0;
+
+err:
+ free_dbus_object_desc(obj_desc);
+ return -1;
+}
+
+
+/**
+ * wpas_dbus_unregister_persistent_group - Unregister a persistent_group
+ * from dbus
+ * @wpa_s: wpa_supplicant interface structure
+ * @nid: network id
+ * Returns: 0 on success, -1 on failure
+ *
+ * Unregisters persistent group representing object from dbus
+ *
+ * NOTE: There is a slight issue with the semantics here. While the
+ * implementation simply means the persistent group is unloaded from memory,
+ * it should not get interpreted as the group is actually being erased/removed
+ * from persistent storage as well.
+ */
+int wpas_dbus_unregister_persistent_group(struct wpa_supplicant *wpa_s,
+ int nid)
+{
+ struct wpas_dbus_priv *ctrl_iface;
+ char pgrp_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
+ int ret;
+
+ /* Do nothing if the control interface is not turned on */
+ if (wpa_s == NULL || wpa_s->global == NULL ||
+ wpa_s->dbus_new_path == NULL)
+ return 0;
+ ctrl_iface = wpa_s->global->dbus;
+ if (ctrl_iface == NULL)
+ return 0;
+
+ os_snprintf(pgrp_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
+ "%s/" WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART "/%u",
+ wpa_s->dbus_new_path, nid);
+
+ wpa_printf(MSG_DEBUG, "dbus: Unregister persistent group object '%s'",
+ pgrp_obj_path);
+ ret = wpa_dbus_unregister_object_per_iface(ctrl_iface, pgrp_obj_path);
+
+ if (!ret)
+ wpas_dbus_signal_persistent_group_removed(wpa_s, nid);
+
+ return ret;
+}
+
+#endif /* CONFIG_P2P */
diff --git a/wpa_supplicant/dbus/dbus_new.h b/wpa_supplicant/dbus/dbus_new.h
index 377e381..3b0d50c 100644
--- a/wpa_supplicant/dbus/dbus_new.h
+++ b/wpa_supplicant/dbus/dbus_new.h
@@ -16,6 +16,8 @@
#ifndef CTRL_IFACE_DBUS_NEW_H
#define CTRL_IFACE_DBUS_NEW_H
+#include "p2p/p2p.h"
+
struct wpa_global;
struct wpa_supplicant;
struct wpa_ssid;
@@ -61,6 +63,29 @@ enum wpas_dbus_bss_prop {
#define WPAS_DBUS_NEW_BSSIDS_PART "BSSs"
#define WPAS_DBUS_NEW_IFACE_BSS WPAS_DBUS_NEW_INTERFACE ".BSS"
+#define WPAS_DBUS_NEW_IFACE_P2PDEVICE \
+ WPAS_DBUS_NEW_IFACE_INTERFACE ".P2PDevice"
+
+/*
+ * Groups correspond to P2P groups where this device is a GO (owner)
+ */
+#define WPAS_DBUS_NEW_P2P_GROUPS_PART "Groups"
+#define WPAS_DBUS_NEW_IFACE_P2P_GROUP WPAS_DBUS_NEW_INTERFACE ".Group"
+
+/*
+ * Different dbus object for persistent groups so they do not get confused
+ * with regular (configured) network objects.
+ */
+#define WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART "PersistentGroups"
+#define WPAS_DBUS_NEW_IFACE_PERSISTENT_GROUP \
+ WPAS_DBUS_NEW_INTERFACE ".PersistentGroup"
+
+#define WPAS_DBUS_NEW_P2P_PEERS_PART "Peers"
+#define WPAS_DBUS_NEW_IFACE_P2P_PEER WPAS_DBUS_NEW_INTERFACE ".Peer"
+
+#define WPAS_DBUS_NEW_P2P_GROUPMEMBERS_PART "Members"
+#define WPAS_DBUS_NEW_IFACE_P2P_GROUPMEMBER \
+ WPAS_DBUS_NEW_INTERFACE ".GroupMember"
/* Errors */
#define WPAS_DBUS_ERROR_UNKNOWN_ERROR \
@@ -78,6 +103,13 @@ enum wpas_dbus_bss_prop {
#define WPAS_DBUS_ERROR_NETWORK_UNKNOWN \
WPAS_DBUS_NEW_INTERFACE ".NetworkUnknown"
+#define WPAS_DBUS_ERROR_CONNECT_CHANNEL_UNAVAILABLE \
+ WPAS_DBUS_NEW_INTERFACE ".ConnectChannelUnavailable"
+#define WPAS_DBUS_ERROR_CONNECT_CHANNEL_UNSUPPORTED \
+ WPAS_DBUS_NEW_INTERFACE ".ConnectChannelUnsupported"
+#define WPAS_DBUS_ERROR_CONNECT_UNSPECIFIED_ERROR \
+ WPAS_DBUS_NEW_INTERFACE ".ConnectUnspecifiedError"
+
#define WPAS_DBUS_ERROR_BLOB_EXISTS \
WPAS_DBUS_NEW_INTERFACE ".BlobExists"
#define WPAS_DBUS_ERROR_BLOB_UNKNOWN \
@@ -122,6 +154,54 @@ void wpas_dbus_signal_debug_level_changed(struct wpa_global *global);
void wpas_dbus_signal_debug_timestamp_changed(struct wpa_global *global);
void wpas_dbus_signal_debug_show_keys_changed(struct wpa_global *global);
+int wpas_dbus_register_peer(struct wpa_supplicant *wpa_s, const u8 *dev_addr);
+void wpas_dbus_signal_peer_device_found(struct wpa_supplicant *wpa_s,
+ const u8 *dev_addr);
+int wpas_dbus_unregister_peer(struct wpa_supplicant *wpa_s,
+ const u8 *dev_addr);
+void wpas_dbus_signal_peer_device_lost(struct wpa_supplicant *wpa_s,
+ const u8 *dev_addr);
+void wpas_dbus_signal_p2p_group_removed(struct wpa_supplicant *wpa_s,
+ const char *role);
+void wpas_dbus_signal_p2p_provision_discovery(struct wpa_supplicant *wpa_s,
+ const u8 *dev_addr, int request,
+ enum p2p_prov_disc_status status,
+ u16 config_methods,
+ unsigned int generated_pin);
+void wpas_dbus_signal_p2p_go_neg_req(struct wpa_supplicant *wpa_s,
+ const u8 *src, u16 dev_passwd_id);
+void wpas_dbus_signal_p2p_group_started(struct wpa_supplicant *wpa_s,
+ const struct wpa_ssid *ssid,
+ int client, int network_id);
+void wpas_dbus_register_p2p_group(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid);
+void wpas_dbus_signal_p2p_go_neg_resp(struct wpa_supplicant *wpa_s, int status);
+void wpas_dbus_unregister_p2p_group(struct wpa_supplicant *wpa_s,
+ const struct wpa_ssid *ssid);
+int wpas_dbus_register_persistent_group(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid);
+int wpas_dbus_unregister_persistent_group(struct wpa_supplicant *wpa_s,
+ int nid);
+void wpas_dbus_signal_p2p_invitation_result(struct wpa_supplicant *wpa_s,
+ int status, const u8 *bssid);
+void wpas_dbus_register_p2p_groupmember(struct wpa_supplicant *wpa_s,
+ const u8 *p2p_if_addr);
+void wpas_dbus_unregister_p2p_groupmember(struct wpa_supplicant *wpa_s,
+ const u8 *p2p_if_addr);
+void wpas_dbus_signal_p2p_peer_disconnected(struct wpa_supplicant *wpa_s,
+ const u8 *member);
+void wpas_dbus_signal_p2p_sd_request(struct wpa_supplicant *wpa_s,
+ int freq, const u8 *sa, u8 dialog_token,
+ u16 update_indic, const u8 *tlvs,
+ size_t tlvs_len);
+void wpas_dbus_signal_p2p_sd_response(struct wpa_supplicant *wpa_s,
+ const u8 *sa, u16 update_indic,
+ const u8 *tlvs, size_t tlvs_len);
+void wpas_dbus_signal_p2p_peer_joined(struct wpa_supplicant *wpa_s,
+ const u8 *member);
+void wpas_dbus_signal_p2p_wps_failed(struct wpa_supplicant *wpa_s,
+ struct wps_event_fail *fail);
+
#else /* CONFIG_CTRL_IFACE_DBUS_NEW */
static inline int wpas_dbus_register_interface(struct wpa_supplicant *wpa_s)
@@ -231,6 +311,138 @@ static inline void wpas_dbus_signal_debug_show_keys_changed(
{
}
+static inline int wpas_dbus_register_peer(struct wpa_supplicant *wpa_s,
+ const u8 *dev_addr)
+{
+ return 0;
+}
+
+static inline int wpas_dbus_unregister_peer(struct wpa_supplicant *wpa_s,
+ const u8 *dev_addr)
+{
+ return 0;
+}
+
+static inline void
+wpas_dbus_signal_p2p_group_removed(struct wpa_supplicant *wpa_s,
+ const char *role)
+{
+}
+
+static inline void
+wpas_dbus_signal_p2p_provision_discovery(struct wpa_supplicant *wpa_s,
+ const u8 *dev_addr, int request,
+ enum p2p_prov_disc_status status,
+ u16 config_methods,
+ unsigned int generated_pin)
+{
+}
+
+static inline void wpas_dbus_signal_p2p_go_neg_req(
+ struct wpa_supplicant *wpa_s,
+ const u8 *src,
+ u16 dev_passwd_id)
+{
+}
+
+static inline void
+wpas_dbus_signal_p2p_group_started(struct wpa_supplicant *wpa_s,
+ const struct wpa_ssid *ssid,
+ int client, int network_id)
+{
+}
+
+static inline void
+wpas_dbus_register_p2p_group(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid)
+{
+}
+
+static inline int wpas_dbus_register_persistent_group(
+ struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
+{
+ return 0;
+}
+
+static inline int wpas_dbus_unregister_persistent_group(
+ struct wpa_supplicant *wpa_s, int nid)
+{
+ return 0;
+}
+
+static inline void
+wpas_dbus_signal_p2p_go_neg_resp(struct wpa_supplicant *wpa_s, int status)
+{
+}
+
+static inline void
+wpas_dbus_unregister_p2p_group(struct wpa_supplicant *wpa_s,
+ const struct wpa_ssid *ssid)
+{
+}
+
+static inline void wpas_dbus_signal_p2p_invitation_result(
+ struct wpa_supplicant *wpa_s, int status,
+ const u8 *bssid)
+{
+}
+
+static inline void
+wpas_dbus_register_p2p_groupmember(struct wpa_supplicant *wpa_s,
+ const u8 *p2p_if_addr)
+{
+}
+
+static inline void
+wpas_dbus_signal_p2p_sd_request(struct wpa_supplicant *wpa_s, int freq,
+ const u8 *sa, u8 dialog_token, u16 update_indic,
+ const u8 *tlvs, size_t tlvs_len)
+{
+}
+
+static inline void
+wpas_dbus_signal_p2p_sd_response(struct wpa_supplicant *wpa_s,
+ const u8 *sa, u16 update_indic,
+ const u8 *tlvs, size_t tlvs_len)
+{
+}
+
+static inline void
+wpas_dbus_unregister_p2p_groupmember(struct wpa_supplicant *wpa_s,
+ const u8 *p2p_if_addr)
+{
+}
+
+static inline void
+wpas_dbus_signal_p2p_peer_joined(struct wpa_supplicant *wpa_s,
+ const u8 *member)
+{
+}
+
+static inline void
+wpas_dbus_signal_peer_device_found(struct wpa_supplicant *wpa_s,
+ const u8 *dev_addr)
+{
+}
+
+static inline void
+wpas_dbus_signal_peer_device_lost(struct wpa_supplicant *wpa_s,
+ const u8 *dev_addr)
+{
+}
+
+static inline void
+wpas_dbus_signal_p2p_peer_disconnected(struct wpa_supplicant *wpa_s,
+ const u8 *member)
+{
+}
+
+static inline void
+wpas_dbus_signal_p2p_wps_failed(struct wpa_supplicant *wpa_s,
+ struct wps_event_fail *fail)
+{
+}
+
#endif /* CONFIG_CTRL_IFACE_DBUS_NEW */
#endif /* CTRL_IFACE_DBUS_H_NEW */
diff --git a/wpa_supplicant/dbus/dbus_new_handlers.c b/wpa_supplicant/dbus/dbus_new_handlers.c
index 68e5465..7c4218b 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers.c
@@ -43,70 +43,6 @@ static const char *debug_strings[] = {
/**
- * wpas_dbus_new_decompose_object_path - Decompose an interface object path into parts
- * @path: The dbus object path
- * @network: (out) the configured network this object path refers to, if any
- * @bssid: (out) the scanned bssid this object path refers to, if any
- * Returns: The object path of the network interface this path refers to
- *
- * For a given object path, decomposes the object path into object id, network,
- * and BSSID parts, if those parts exist.
- */
-static char * wpas_dbus_new_decompose_object_path(const char *path,
- char **network,
- char **bssid)
-{
- const unsigned int dev_path_prefix_len =
- strlen(WPAS_DBUS_NEW_PATH_INTERFACES "/");
- char *obj_path_only;
- char *next_sep;
-
- /* Be a bit paranoid about path */
- if (!path || os_strncmp(path, WPAS_DBUS_NEW_PATH_INTERFACES "/",
- dev_path_prefix_len))
- return NULL;
-
- /* Ensure there's something at the end of the path */
- if ((path + dev_path_prefix_len)[0] == '\0')
- return NULL;
-
- obj_path_only = os_strdup(path);
- if (obj_path_only == NULL)
- return NULL;
-
- next_sep = os_strchr(obj_path_only + dev_path_prefix_len, '/');
- if (next_sep != NULL) {
- const char *net_part = os_strstr(
- next_sep, WPAS_DBUS_NEW_NETWORKS_PART "/");
- const char *bssid_part = os_strstr(
- next_sep, WPAS_DBUS_NEW_BSSIDS_PART "/");
-
- if (network && net_part) {
- /* Deal with a request for a configured network */
- const char *net_name = net_part +
- os_strlen(WPAS_DBUS_NEW_NETWORKS_PART "/");
- *network = NULL;
- if (os_strlen(net_name))
- *network = os_strdup(net_name);
- } else if (bssid && bssid_part) {
- /* Deal with a request for a scanned BSSID */
- const char *bssid_name = bssid_part +
- os_strlen(WPAS_DBUS_NEW_BSSIDS_PART "/");
- if (strlen(bssid_name))
- *bssid = os_strdup(bssid_name);
- else
- *bssid = NULL;
- }
-
- /* Cut off interface object path before "/" */
- *next_sep = '\0';
- }
-
- return obj_path_only;
-}
-
-
-/**
* wpas_dbus_error_unknown_error - Return a new InvalidArgs error message
* @message: Pointer to incoming dbus message this error refers to
* @arg: Optional string appended to error message
@@ -236,10 +172,10 @@ static struct wpa_supplicant * get_iface_by_dbus_path(
*
* Sets network configuration with parameters given id DBus dictionary
*/
-static DBusMessage * set_network_properties(DBusMessage *message,
- struct wpa_supplicant *wpa_s,
- struct wpa_ssid *ssid,
- DBusMessageIter *iter)
+DBusMessage * set_network_properties(DBusMessage *message,
+ struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid,
+ DBusMessageIter *iter)
{
struct wpa_dbus_dict_entry entry = { .type = DBUS_TYPE_STRING };
@@ -1429,7 +1365,7 @@ DBusMessage * wpas_dbus_handler_remove_network(DBusMessage *message,
/* Extract the network ID and ensure the network */
/* is actually a child of this interface */
- iface = wpas_dbus_new_decompose_object_path(op, &net_id, NULL);
+ iface = wpas_dbus_new_decompose_object_path(op, 0, &net_id, NULL);
if (iface == NULL || os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
reply = wpas_dbus_error_invalid_args(message, op);
goto out;
@@ -1528,7 +1464,7 @@ DBusMessage * wpas_dbus_handler_select_network(DBusMessage *message,
/* Extract the network ID and ensure the network */
/* is actually a child of this interface */
- iface = wpas_dbus_new_decompose_object_path(op, &net_id, NULL);
+ iface = wpas_dbus_new_decompose_object_path(op, 0, &net_id, NULL);
if (iface == NULL || os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
reply = wpas_dbus_error_invalid_args(message, op);
goto out;
@@ -1763,8 +1699,6 @@ DBusMessage * wpas_dbus_getter_capabilities(DBusMessage *message,
DBusMessageIter iter_dict_entry, iter_dict_val, iter_array,
variant_iter;
const char *scans[] = { "active", "passive", "ssid" };
- const char *modes[] = { "infrastructure", "ad-hoc", "ap" };
- int n = sizeof(modes) / sizeof(char *);
if (message == NULL)
reply = dbus_message_new(DBUS_MESSAGE_TYPE_SIGNAL);
@@ -2035,11 +1969,41 @@ DBusMessage * wpas_dbus_getter_capabilities(DBusMessage *message,
goto nomem;
/***** Modes */
- if (res < 0 || !(capa.flags & WPA_DRIVER_FLAGS_AP))
- n--; /* exclude ap mode if it is not supported by the driver */
- if (!wpa_dbus_dict_append_string_array(&iter_dict, "Modes", modes, n))
+ if (!wpa_dbus_dict_begin_string_array(&iter_dict, "Modes",
+ &iter_dict_entry,
+ &iter_dict_val,
+ &iter_array))
+ goto nomem;
+
+ if (!wpa_dbus_dict_string_array_add_element(
+ &iter_array, "infrastructure"))
goto nomem;
+ if (!wpa_dbus_dict_string_array_add_element(
+ &iter_array, "ad-hoc"))
+ goto nomem;
+
+ if (res >= 0) {
+ if (capa.flags & (WPA_DRIVER_FLAGS_AP)) {
+ if (!wpa_dbus_dict_string_array_add_element(
+ &iter_array, "ap"))
+ goto nomem;
+ }
+
+ if (capa.flags & (WPA_DRIVER_FLAGS_P2P_CAPABLE)) {
+ if (!wpa_dbus_dict_string_array_add_element(
+ &iter_array, "p2p"))
+ goto nomem;
+ }
+ }
+
+ if (!wpa_dbus_dict_end_string_array(&iter_dict,
+ &iter_dict_entry,
+ &iter_dict_val,
+ &iter_array))
+ goto nomem;
+ /***** Modes end */
+
if (!wpa_dbus_dict_close_write(&variant_iter, &iter_dict))
goto nomem;
if (!dbus_message_iter_close_container(&iter, &variant_iter))
@@ -2544,7 +2508,8 @@ DBusMessage * wpas_dbus_getter_networks(DBusMessage *message,
}
for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next)
- num++;
+ if (!network_is_persistent_group(ssid))
+ num++;
paths = os_zalloc(num * sizeof(char *));
if (!paths) {
@@ -2554,6 +2519,8 @@ DBusMessage * wpas_dbus_getter_networks(DBusMessage *message,
/* Loop through configured networks and append object path of each */
for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
+ if (network_is_persistent_group(ssid))
+ continue;
paths[i] = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX);
if (paths[i] == NULL) {
reply = dbus_message_new_error(message,
diff --git a/wpa_supplicant/dbus/dbus_new_handlers.h b/wpa_supplicant/dbus/dbus_new_handlers.h
index 742d33c..978ee4c 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers.h
+++ b/wpa_supplicant/dbus/dbus_new_handlers.h
@@ -77,6 +77,11 @@ DBusMessage * wpas_dbus_handler_scan(DBusMessage *message,
DBusMessage * wpas_dbus_handler_disconnect(DBusMessage *message,
struct wpa_supplicant *wpa_s);
+DBusMessage * set_network_properties(DBusMessage *message,
+ struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid,
+ DBusMessageIter *iter);
+
DBusMessage * wpas_dbus_handler_add_network(DBusMessage *message,
struct wpa_supplicant *wpa_s);
diff --git a/wpa_supplicant/dbus/dbus_new_handlers_p2p.c b/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
new file mode 100644
index 0000000..3fec308
--- /dev/null
+++ b/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
@@ -0,0 +1,2113 @@
+/*
+ * WPA Supplicant / dbus-based control interface (P2P)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+
+#include "utils/includes.h"
+#include "common.h"
+#include "../config.h"
+#include "../wpa_supplicant_i.h"
+#include "../wps_supplicant.h"
+#include "../notify.h"
+#include "dbus_new_helpers.h"
+#include "dbus_new.h"
+#include "dbus_new_handlers.h"
+#include "dbus_new_handlers_p2p.h"
+#include "dbus_dict_helpers.h"
+#include "p2p/p2p.h"
+#include "common/ieee802_11_defs.h"
+#include "ap/hostapd.h"
+#include "ap/ap_config.h"
+#include "ap/wps_hostapd.h"
+
+#include "../p2p_supplicant.h"
+
+/**
+ * Parses out the mac address from the peer object path.
+ * @peer_path - object path of the form
+ * /fi/w1/wpa_supplicant1/Interfaces/n/Peers/00112233445566 (no colons)
+ * @addr - out param must be of ETH_ALEN size
+ * Returns 0 if valid (including MAC), -1 otherwise
+ */
+static int parse_peer_object_path(char *peer_path, u8 addr[ETH_ALEN])
+{
+ char *p;
+
+ if (!peer_path)
+ return -1;
+ p = strrchr(peer_path, '/');
+ if (!p)
+ return -1;
+ p++;
+ return hwaddr_compact_aton(p, addr);
+}
+
+
+/**
+ * wpas_dbus_error_persistent_group_unknown - Return a new PersistentGroupUnknown
+ * error message
+ * @message: Pointer to incoming dbus message this error refers to
+ * Returns: a dbus error message
+ *
+ * Convenience function to create and return an invalid persistent group error.
+ */
+static DBusMessage * wpas_dbus_error_persistent_group_unknown(
+ DBusMessage *message)
+{
+ return dbus_message_new_error(message, WPAS_DBUS_ERROR_NETWORK_UNKNOWN,
+ "There is no such persistent group in "
+ "this P2P device.");
+}
+
+
+DBusMessage *wpas_dbus_handler_p2p_find(DBusMessage * message,
+ struct wpa_supplicant * wpa_s)
+{
+ struct wpa_dbus_dict_entry entry;
+ DBusMessage *reply = NULL;
+ DBusMessageIter iter;
+ DBusMessageIter iter_dict;
+ unsigned int timeout = 0;
+ unsigned int searchonly = 0;
+ enum p2p_discovery_type type = P2P_FIND_ONLY_SOCIAL;
+ int num_req_dev_types = 0;
+ unsigned int i;
+ u8 *req_dev_types = NULL;
+
+ dbus_message_iter_init(message, &iter);
+
+ if (!wpa_dbus_dict_open_read(&iter, &iter_dict))
+ goto error;
+
+ while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
+ if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
+ goto error;
+
+ if (!os_strcmp(entry.key, "Timeout") &&
+ (entry.type == DBUS_TYPE_INT32)) {
+ timeout = entry.uint32_value;
+ } else if (!os_strcmp(entry.key, "SearchOnly") &&
+ (entry.type == DBUS_TYPE_BOOLEAN)) {
+ searchonly = (entry.bool_value == TRUE) ? 1 : 0;
+ } else if (os_strcmp(entry.key, "RequestedDeviceTypes") == 0) {
+ if ((entry.type != DBUS_TYPE_ARRAY) ||
+ (entry.array_type != WPAS_DBUS_TYPE_BINARRAY))
+ goto error_clear;
+
+ req_dev_types =
+ os_malloc(WPS_DEV_TYPE_LEN * entry.array_len);
+ if (!req_dev_types)
+ goto error_clear;
+
+ for (i = 0; i < entry.array_len; i++) {
+ if (wpabuf_len(entry.binarray_value[i]) !=
+ WPS_DEV_TYPE_LEN)
+ goto error_clear;
+ os_memcpy(req_dev_types + i * WPS_DEV_TYPE_LEN,
+ wpabuf_head(entry.binarray_value[i]),
+ WPS_DEV_TYPE_LEN);
+ }
+
+ num_req_dev_types = entry.array_len;
+ } else
+ goto error_clear;
+ wpa_dbus_dict_entry_clear(&entry);
+ }
+
+ wpas_p2p_find(wpa_s, timeout, type, num_req_dev_types, req_dev_types);
+ return reply;
+
+error_clear:
+ os_free(req_dev_types);
+ wpa_dbus_dict_entry_clear(&entry);
+error:
+ reply = wpas_dbus_error_invalid_args(message, entry.key);
+ return reply;
+}
+
+DBusMessage *wpas_dbus_handler_p2p_stop_find(DBusMessage * message,
+ struct wpa_supplicant * wpa_s)
+{
+ wpas_p2p_stop_find(wpa_s);
+ return NULL;
+}
+
+DBusMessage *wpas_dbus_handler_p2p_rejectpeer(DBusMessage * message,
+ struct wpa_supplicant * wpa_s)
+{
+ DBusMessageIter iter;
+ char *peer_object_path = NULL;
+ u8 peer_addr[ETH_ALEN];
+
+ dbus_message_iter_init(message, &iter);
+ dbus_message_iter_get_basic(&iter, &peer_object_path);
+
+ if (parse_peer_object_path(peer_object_path, peer_addr) < 0)
+ return wpas_dbus_error_invalid_args(message, NULL);
+
+ if (wpas_p2p_reject(wpa_s, peer_addr) < 0)
+ return wpas_dbus_error_unknown_error(message,
+ "Failed to call wpas_p2p_reject method.");
+
+ return NULL;
+}
+
+DBusMessage *wpas_dbus_handler_p2p_listen(DBusMessage * message,
+ struct wpa_supplicant * wpa_s)
+{
+ dbus_int32_t timeout = 0;
+
+ if (!dbus_message_get_args(message, NULL, DBUS_TYPE_INT32, &timeout,
+ DBUS_TYPE_INVALID))
+ return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
+ NULL);
+
+ if (wpas_p2p_listen(wpa_s, (unsigned int)timeout))
+ return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
+ NULL);
+
+ return NULL;
+}
+
+DBusMessage *wpas_dbus_handler_p2p_extendedlisten(DBusMessage * message,
+ struct wpa_supplicant * wpa_s)
+{
+ unsigned int period = 0, interval = 0;
+ struct wpa_dbus_dict_entry entry;
+ DBusMessageIter iter;
+ DBusMessageIter iter_dict;
+
+ dbus_message_iter_init(message, &iter);
+
+ if (!wpa_dbus_dict_open_read(&iter, &iter_dict))
+ goto error;
+
+ while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
+ if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
+ goto error;
+
+ if (!strcmp(entry.key, "period") &&
+ (entry.type == DBUS_TYPE_INT32))
+ period = entry.uint32_value;
+ else if (!strcmp(entry.key, "interval") &&
+ (entry.type == DBUS_TYPE_INT32))
+ interval = entry.uint32_value;
+ else
+ goto error_clear;
+ wpa_dbus_dict_entry_clear(&entry);
+ }
+
+ if (wpas_p2p_ext_listen(wpa_s, period, interval))
+ return wpas_dbus_error_unknown_error(message,
+ "failed to initiate a p2p_ext_listen.");
+
+ return NULL;
+
+error_clear:
+ wpa_dbus_dict_entry_clear(&entry);
+error:
+ return wpas_dbus_error_invalid_args(message, entry.key);
+}
+
+DBusMessage *wpas_dbus_handler_p2p_presence_request(DBusMessage * message,
+ struct wpa_supplicant *
+ wpa_s)
+{
+ unsigned int dur1 = 0, int1 = 0, dur2 = 0, int2 = 0;
+ struct wpa_dbus_dict_entry entry;
+ DBusMessageIter iter;
+ DBusMessageIter iter_dict;
+
+ dbus_message_iter_init(message, &iter);
+
+ if (!wpa_dbus_dict_open_read(&iter, &iter_dict))
+ goto error;
+
+ while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
+ if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
+ goto error;
+
+ if (!strcmp(entry.key, "duration1") &&
+ (entry.type == DBUS_TYPE_INT32))
+ dur1 = entry.uint32_value;
+ else if (!strcmp(entry.key, "interval1") &&
+ entry.type == DBUS_TYPE_INT32)
+ int1 = entry.uint32_value;
+ else if (!strcmp(entry.key, "duration2") &&
+ entry.type == DBUS_TYPE_INT32)
+ dur2 = entry.uint32_value;
+ else if (!strcmp(entry.key, "interval2") &&
+ entry.type == DBUS_TYPE_INT32)
+ int2 = entry.uint32_value;
+ else
+ goto error_clear;
+
+ wpa_dbus_dict_entry_clear(&entry);
+ }
+ if (wpas_p2p_presence_req(wpa_s, dur1, int1, dur2, int2) < 0)
+ return wpas_dbus_error_unknown_error(message,
+ "Failed to invoke presence request.");
+
+ return NULL;
+
+error_clear:
+ wpa_dbus_dict_entry_clear(&entry);
+error:
+ return wpas_dbus_error_invalid_args(message, entry.key);
+}
+
+DBusMessage *wpas_dbus_handler_p2p_group_add(DBusMessage * message,
+ struct wpa_supplicant * wpa_s)
+{
+ DBusMessageIter iter_dict;
+ DBusMessage *reply = NULL;
+ DBusMessageIter iter;
+ struct wpa_dbus_dict_entry entry;
+ char *pg_object_path = NULL;
+ int persistent_group = 0;
+ int freq = 0;
+ char *iface = NULL;
+ char *net_id_str = NULL;
+ unsigned int group_id = 0;
+ struct wpa_ssid *ssid;
+
+ dbus_message_iter_init(message, &iter);
+
+ if (!wpa_dbus_dict_open_read(&iter, &iter_dict))
+ goto inv_args;
+
+ while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
+ if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
+ goto inv_args;
+
+ if (!strcmp(entry.key, "persistent") &&
+ (entry.type == DBUS_TYPE_BOOLEAN)) {
+ persistent_group = (entry.bool_value == TRUE) ? 1 : 0;
+ } else if (!strcmp(entry.key, "frequency") &&
+ (entry.type == DBUS_TYPE_INT32)) {
+ freq = entry.int32_value;
+ if (freq <= 0)
+ goto inv_args_clear;
+ } else if (!strcmp(entry.key, "persistent_group_object") &&
+ entry.type == DBUS_TYPE_OBJECT_PATH)
+ pg_object_path = os_strdup(entry.str_value);
+ else
+ goto inv_args_clear;
+
+ wpa_dbus_dict_entry_clear(&entry);
+ }
+
+ if (pg_object_path != NULL) {
+ /*
+ * A persistent group Object Path is defined meaning we want
+ * to re-invoke a persistent group.
+ */
+
+ iface = wpas_dbus_new_decompose_object_path(pg_object_path, 1,
+ &net_id_str, NULL);
+ if (iface == NULL ||
+ os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
+ reply =
+ wpas_dbus_error_invalid_args(message,
+ pg_object_path);
+ goto out;
+ }
+
+ group_id = strtoul(net_id_str, NULL, 10);
+ if (errno == EINVAL) {
+ reply = wpas_dbus_error_invalid_args(
+ message, pg_object_path);
+ goto out;
+ }
+
+ /* Get the SSID structure form the persistant group id */
+ ssid = wpa_config_get_network(wpa_s->conf, group_id);
+ if (ssid == NULL || ssid->disabled != 2)
+ goto inv_args;
+
+ if (wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq)) {
+ reply = wpas_dbus_error_unknown_error(message,
+ "Failed to reinvoke a persistent group");
+ goto out;
+ }
+ } else if (wpas_p2p_group_add(wpa_s, persistent_group, freq))
+ goto inv_args;
+
+out:
+ os_free(pg_object_path);
+ os_free(net_id_str);
+ os_free(iface);
+ return reply;
+inv_args_clear:
+ wpa_dbus_dict_entry_clear(&entry);
+inv_args:
+ reply = wpas_dbus_error_invalid_args(message, NULL);
+ goto out;
+}
+
+DBusMessage *wpas_dbus_handler_p2p_disconnect(DBusMessage *message,
+ struct wpa_supplicant *wpa_s)
+{
+ if (wpas_p2p_disconnect(wpa_s))
+ return wpas_dbus_error_unknown_error(message,
+ "failed to disconnect");
+
+ return NULL;
+}
+
+DBusMessage *wpas_dbus_handler_p2p_flush(DBusMessage * message,
+ struct wpa_supplicant * wpa_s)
+{
+ os_memset(wpa_s->p2p_auth_invite, 0, ETH_ALEN);
+ wpa_s->force_long_sd = 0;
+ p2p_flush(wpa_s->global->p2p);
+
+ return NULL;
+}
+
+DBusMessage *wpas_dbus_handler_p2p_connect(DBusMessage * message,
+ struct wpa_supplicant * wpa_s)
+{
+ DBusMessageIter iter_dict;
+ DBusMessage *reply = NULL;
+ DBusMessageIter iter;
+ struct wpa_dbus_dict_entry entry;
+ char *peer_object_path = NULL;
+ int persistent_group = 0;
+ int join = 0;
+ int authorize_only = 0;
+ int go_intent = -1;
+ int freq = 0;
+ u8 addr[ETH_ALEN];
+ char *pin = NULL;
+ enum p2p_wps_method wps_method = WPS_NOT_READY;
+ int new_pin;
+ char *err_msg = NULL;
+ char *iface = NULL;
+
+ dbus_message_iter_init(message, &iter);
+
+ if (!wpa_dbus_dict_open_read(&iter, &iter_dict))
+ goto inv_args;
+
+ while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
+ if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
+ goto inv_args;
+
+ if (!strcmp(entry.key, "peer") &&
+ (entry.type == DBUS_TYPE_OBJECT_PATH)) {
+ peer_object_path = os_strdup(entry.str_value);
+ } else if (!strcmp(entry.key, "persistent") &&
+ (entry.type == DBUS_TYPE_BOOLEAN)) {
+ persistent_group = (entry.bool_value == TRUE) ? 1 : 0;
+ } else if (!strcmp(entry.key, "join") &&
+ (entry.type == DBUS_TYPE_BOOLEAN)) {
+ join = (entry.bool_value == TRUE) ? 1 : 0;
+ } else if (!strcmp(entry.key, "authorize_only") &&
+ (entry.type == DBUS_TYPE_BOOLEAN)) {
+ authorize_only = (entry.bool_value == TRUE) ? 1 : 0;
+ } else if (!strcmp(entry.key, "frequency") &&
+ (entry.type == DBUS_TYPE_INT32)) {
+ freq = entry.int32_value;
+ if (freq <= 0)
+ goto inv_args_clear;
+ } else if (!strcmp(entry.key, "go_intent") &&
+ (entry.type == DBUS_TYPE_INT32)) {
+ go_intent = entry.int32_value;
+ if ((go_intent < 0) || (go_intent > 15))
+ goto inv_args_clear;
+ } else if (!strcmp(entry.key, "wps_method") &&
+ (entry.type == DBUS_TYPE_STRING)) {
+ if (!strcmp(entry.str_value, "pbc"))
+ wps_method = WPS_PBC;
+ else if (!strcmp(entry.str_value, "pin"))
+ wps_method = WPS_PIN_DISPLAY;
+ else if (!strcmp(entry.str_value, "label"))
+ wps_method = WPS_PIN_LABEL;
+ else if (!strcmp(entry.str_value, "display"))
+ wps_method = WPS_PIN_DISPLAY;
+ else if (!strcmp(entry.str_value, "keypad"))
+ wps_method = WPS_PIN_KEYPAD;
+ else
+ goto inv_args_clear;
+ } else if (!strcmp(entry.key, "pin") &&
+ (entry.type == DBUS_TYPE_STRING)) {
+ pin = os_strdup(entry.str_value);
+ } else
+ goto inv_args_clear;
+
+ wpa_dbus_dict_entry_clear(&entry);
+ }
+
+ if (!peer_object_path || (wps_method == WPS_NOT_READY) ||
+ (parse_peer_object_path(peer_object_path, addr) < 0) ||
+ (p2p_get_peer_info(wpa_s->global->p2p, addr, 0, NULL, 0) < 0)) {
+ reply = wpas_dbus_error_invalid_args(message, NULL);
+ goto inv_args;
+ }
+
+ /*
+ * Validate the wps_method specified and the pin value.
+ */
+ if ((!pin || !pin[0]) &&
+ ((wps_method == WPS_PIN_LABEL) || (wps_method == WPS_PIN_KEYPAD)))
+ goto inv_args;
+
+ new_pin = wpas_p2p_connect(wpa_s, addr, pin, wps_method,
+ persistent_group, join, authorize_only,
+ go_intent, freq);
+
+ if (new_pin >= 0) {
+ reply = dbus_message_new_method_return(message);
+ dbus_message_append_args(reply, DBUS_TYPE_INT32,
+ &new_pin, DBUS_TYPE_INVALID);
+ } else {
+ switch (new_pin) {
+ case -2:
+ err_msg = "connect failed due to"
+ " channel unavailability.";
+ iface = WPAS_DBUS_ERROR_CONNECT_CHANNEL_UNAVAILABLE;
+ break;
+
+ case -3:
+ err_msg = "connect failed due to"
+ " unsupported channel.";
+ iface = WPAS_DBUS_ERROR_CONNECT_CHANNEL_UNSUPPORTED;
+ break;
+
+ default:
+ err_msg = "connect failed due to"
+ " unspecified error.";
+ iface = WPAS_DBUS_ERROR_CONNECT_UNSPECIFIED_ERROR;
+ break;
+ }
+ /*
+ * TODO::
+ * Do we need specialized errors corresponding to above
+ * error conditions as against just returning a different
+ * error message?
+ */
+ reply = dbus_message_new_error(message, iface, err_msg);
+ }
+
+out:
+ os_free(peer_object_path);
+ os_free(pin);
+ return reply;
+inv_args_clear:
+ wpa_dbus_dict_entry_clear(&entry);
+inv_args:
+ reply = wpas_dbus_error_invalid_args(message, NULL);
+ goto out;
+}
+
+DBusMessage *wpas_dbus_handler_p2p_invite(DBusMessage * message,
+ struct wpa_supplicant *wpa_s)
+{
+ DBusMessageIter iter_dict;
+ DBusMessage *reply = NULL;
+ DBusMessageIter iter;
+ struct wpa_dbus_dict_entry entry;
+ char *peer_object_path = NULL;
+ char *pg_object_path = NULL;
+ char *iface = NULL;
+ char *net_id_str = NULL;
+ u8 peer_addr[ETH_ALEN];
+ unsigned int group_id = 0;
+ int persistent = 0;
+ struct wpa_ssid *ssid;
+
+ dbus_message_iter_init(message, &iter);
+
+ if (!wpa_dbus_dict_open_read(&iter, &iter_dict))
+ goto err;
+
+ while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
+ if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
+ goto err;
+
+ if (!strcmp(entry.key, "peer") &&
+ (entry.type == DBUS_TYPE_OBJECT_PATH)) {
+ peer_object_path = os_strdup(entry.str_value);
+ wpa_dbus_dict_entry_clear(&entry);
+ } else if (!strcmp(entry.key, "persistent_group_object") &&
+ (entry.type == DBUS_TYPE_OBJECT_PATH)) {
+ pg_object_path = os_strdup(entry.str_value);
+ persistent = 1;
+ wpa_dbus_dict_entry_clear(&entry);
+ } else {
+ wpa_dbus_dict_entry_clear(&entry);
+ goto err;
+ }
+ }
+
+ if (!peer_object_path ||
+ (parse_peer_object_path(peer_object_path, peer_addr) < 0) ||
+ (p2p_get_peer_info(wpa_s->global->p2p,
+ peer_addr, 0, NULL, 0) < 0)) {
+ goto err;
+ }
+
+ if (persistent) {
+ /*
+ * A group ID is defined meaning we want to re-invoke a
+ * persisatnt group
+ */
+
+ iface = wpas_dbus_new_decompose_object_path(pg_object_path, 1,
+ &net_id_str, NULL);
+ if (iface == NULL ||
+ os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
+ reply =
+ wpas_dbus_error_invalid_args(message,
+ pg_object_path);
+ goto out;
+ }
+
+ group_id = strtoul(net_id_str, NULL, 10);
+ if (errno == EINVAL) {
+ reply = wpas_dbus_error_invalid_args(
+ message, pg_object_path);
+ goto out;
+ }
+
+ /* Get the SSID structure form the persistant group id */
+ ssid = wpa_config_get_network(wpa_s->conf, group_id);
+ if (ssid == NULL || ssid->disabled != 2)
+ goto err;
+
+ if (wpas_p2p_invite(wpa_s, peer_addr, ssid, NULL) < 0) {
+ reply = wpas_dbus_error_unknown_error(
+ message,
+ "Failed to reinvoke a persistent group");
+ goto out;
+ }
+ } else {
+ /*
+ * No group ID means propose to a peer to join my active group
+ */
+ if (wpas_p2p_invite_group(wpa_s, wpa_s->ifname,
+ peer_addr, NULL)) {
+ reply = wpas_dbus_error_unknown_error(
+ message,
+ "Failed to join to an active group");
+ goto out;
+ }
+ }
+
+out:
+ os_free(pg_object_path);
+ os_free(peer_object_path);
+ return reply;
+
+err:
+ reply = wpas_dbus_error_invalid_args(message, NULL);
+ goto out;
+}
+
+DBusMessage *wpas_dbus_handler_p2p_prov_disc_req(DBusMessage * message,
+ struct wpa_supplicant *wpa_s)
+{
+ DBusMessageIter iter;
+ char *peer_object_path = NULL;
+ char *config_method = NULL;
+ u8 peer_addr[ETH_ALEN];
+
+ dbus_message_iter_init(message, &iter);
+ dbus_message_iter_get_basic(&iter, &peer_object_path);
+
+ if (parse_peer_object_path(peer_object_path, peer_addr) < 0)
+ return wpas_dbus_error_invalid_args(message, NULL);
+
+ dbus_message_iter_next(&iter);
+ dbus_message_iter_get_basic(&iter, &config_method);
+
+ /*
+ * Validation checks on config_method are being duplicated here
+ * to be able to return invalid args reply since the error code
+ * from p2p module are not granular enough (yet).
+ */
+ if (os_strcmp(config_method, "display") &&
+ os_strcmp(config_method, "keypad") &&
+ os_strcmp(config_method, "pbc") &&
+ os_strcmp(config_method, "pushbutton"))
+ return wpas_dbus_error_invalid_args(message, NULL);
+
+ if (wpas_p2p_prov_disc(wpa_s, peer_addr, config_method) < 0)
+ return wpas_dbus_error_unknown_error(message,
+ "Failed to send provision discovery request");
+
+ return NULL;
+}
+
+/*
+ * P2P Device property accessor methods.
+ */
+
+DBusMessage *wpas_dbus_getter_p2p_device_properties(DBusMessage * message,
+ struct wpa_supplicant *
+ wpa_s)
+{
+ DBusMessage *reply = NULL;
+ DBusMessageIter iter, variant_iter, dict_iter;
+ const char *dev_name;
+ int num_sec_dev_types = 0;
+ int num_vendor_extensions = 0;
+ int i;
+ const struct wpabuf *vendor_ext[P2P_MAX_WPS_VENDOR_EXT];
+
+ if (message == NULL)
+ reply = dbus_message_new(DBUS_MESSAGE_TYPE_SIGNAL);
+ else
+ reply = dbus_message_new_method_return(message);
+
+ if (!reply)
+ goto err_no_mem;
+
+ dbus_message_iter_init_append(reply, &iter);
+
+ if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT,
+ "a{sv}", &variant_iter) ||
+ !wpa_dbus_dict_open_write(&variant_iter, &dict_iter))
+ goto err_no_mem;
+
+ /* DeviceName */
+ dev_name = wpa_s->conf->device_name;
+ if (dev_name &&
+ !wpa_dbus_dict_append_string(&dict_iter, "DeviceName", dev_name))
+ goto err_no_mem;
+
+ /* Primary device type */
+ if (!wpa_dbus_dict_append_byte_array(&dict_iter, "PrimaryDeviceType",
+ (char *)wpa_s->conf->device_type,
+ WPS_DEV_TYPE_LEN))
+ goto err_no_mem;
+
+ /* Secondary device types */
+ for (i = 0; i < MAX_SEC_DEVICE_TYPES; i++) {
+ if (wpa_s->conf->sec_device_type[i] == NULL)
+ break;
+ num_sec_dev_types++;
+ }
+
+ if (!wpa_dbus_dict_append_string_array(
+ &dict_iter, "SecondaryDeviceTypes",
+ (const char **)wpa_s->conf->sec_device_type,
+ num_sec_dev_types))
+ goto err_no_mem;
+
+ /* Vendor Extensions */
+ for (i = 0; i < P2P_MAX_WPS_VENDOR_EXT; i++) {
+ if (wpa_s->conf->wps_vendor_ext[i] == NULL)
+ continue;
+ vendor_ext[num_vendor_extensions++] =
+ wpa_s->conf->wps_vendor_ext[i];
+ }
+
+ if (num_vendor_extensions &&
+ !wpa_dbus_dict_append_wpabuf_array(&dict_iter,
+ "VendorExtension",
+ vendor_ext,
+ num_vendor_extensions))
+ goto err_no_mem;
+
+ /* GO Intent */
+ if (!wpa_dbus_dict_append_uint32(&dict_iter, "GOIntent",
+ wpa_s->conf->p2p_go_intent))
+ goto err_no_mem;
+
+ /* Persistant Reconnect */
+ if (!wpa_dbus_dict_append_bool(&dict_iter, "PersistantReconnect",
+ wpa_s->conf->persistent_reconnect))
+ goto err_no_mem;
+
+ /* Listen Reg Class */
+ if (!wpa_dbus_dict_append_uint32(&dict_iter, "ListenRegClass",
+ wpa_s->conf->p2p_listen_reg_class))
+ goto err_no_mem;
+
+ /* Listen Channel */
+ if (!wpa_dbus_dict_append_uint32(&dict_iter, "ListenChannel",
+ wpa_s->conf->p2p_listen_channel))
+ goto err_no_mem;
+
+ /* Oper Reg Class */
+ if (!wpa_dbus_dict_append_uint32(&dict_iter, "OperRegClass",
+ wpa_s->conf->p2p_oper_reg_class))
+ goto err_no_mem;
+
+ /* Oper Channel */
+ if (!wpa_dbus_dict_append_uint32(&dict_iter, "OperChannel",
+ wpa_s->conf->p2p_oper_channel))
+ goto err_no_mem;
+
+ /* SSID Postfix */
+ if (wpa_s->conf->p2p_ssid_postfix &&
+ !wpa_dbus_dict_append_string(&dict_iter, "SsidPostfix",
+ wpa_s->conf->p2p_ssid_postfix))
+ goto err_no_mem;
+
+ /* Intra Bss */
+ if (!wpa_dbus_dict_append_bool(&dict_iter, "IntraBss",
+ wpa_s->conf->p2p_intra_bss))
+ goto err_no_mem;
+
+ /* Group Idle */
+ if (!wpa_dbus_dict_append_uint32(&dict_iter, "GroupIdle",
+ wpa_s->conf->p2p_group_idle))
+ goto err_no_mem;
+
+ /* Dissasociation low ack */
+ if (!wpa_dbus_dict_append_uint32(&dict_iter, "disassoc_low_ack",
+ wpa_s->conf->disassoc_low_ack))
+ goto err_no_mem;
+
+ if (!wpa_dbus_dict_close_write(&variant_iter, &dict_iter) ||
+ !dbus_message_iter_close_container(&iter, &variant_iter))
+ goto err_no_mem;
+
+ return reply;
+err_no_mem:
+ dbus_message_unref(reply);
+ return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL);
+}
+
+DBusMessage *wpas_dbus_setter_p2p_device_properties(DBusMessage * message,
+ struct wpa_supplicant *
+ wpa_s)
+{
+ DBusMessage *reply = NULL;
+ DBusMessageIter iter, variant_iter;
+ struct wpa_dbus_dict_entry entry = {.type = DBUS_TYPE_STRING };
+ DBusMessageIter iter_dict;
+ unsigned int i;
+
+ dbus_message_iter_init(message, &iter);
+
+ dbus_message_iter_next(&iter);
+ dbus_message_iter_next(&iter);
+
+ dbus_message_iter_recurse(&iter, &variant_iter);
+
+ if (!wpa_dbus_dict_open_read(&variant_iter, &iter_dict))
+ return wpas_dbus_error_invalid_args(message, NULL);
+
+ while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
+ if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
+ return wpas_dbus_error_invalid_args(message, NULL);
+
+ if (os_strcmp(entry.key, "DeviceName") == 0) {
+ char *devname;
+
+ if (entry.type != DBUS_TYPE_STRING)
+ goto error_clear;
+
+ devname = os_strdup(entry.str_value);
+ if (devname == NULL)
+ goto err_no_mem_clear;
+
+ os_free(wpa_s->conf->device_name);
+ wpa_s->conf->device_name = devname;
+
+ wpa_s->conf->changed_parameters |=
+ CFG_CHANGED_DEVICE_NAME;
+ } else if (os_strcmp(entry.key, "PrimaryDeviceType") == 0) {
+ if (entry.type != DBUS_TYPE_ARRAY ||
+ entry.array_type != DBUS_TYPE_BYTE ||
+ entry.array_len != WPS_DEV_TYPE_LEN)
+ goto error_clear;
+
+ os_memcpy(wpa_s->conf->device_type,
+ entry.bytearray_value,
+ WPS_DEV_TYPE_LEN);
+ wpa_s->conf->changed_parameters |=
+ CFG_CHANGED_DEVICE_TYPE;
+ } else if (os_strcmp(entry.key, "SecondaryDeviceTypes") == 0) {
+ if (entry.type != DBUS_TYPE_ARRAY ||
+ entry.array_type != WPAS_DBUS_TYPE_BINARRAY ||
+ entry.array_len > MAX_SEC_DEVICE_TYPES)
+ goto error;
+
+ for (i = 0; i < entry.array_len; i++)
+ if (wpabuf_len(entry.binarray_value[i]) != WPS_DEV_TYPE_LEN)
+ goto err_no_mem_clear;
+ for (i = 0; i < entry.array_len; i++)
+ os_memcpy(wpa_s->conf->sec_device_type[i],
+ wpabuf_head(entry.binarray_value[i]),
+ WPS_DEV_TYPE_LEN);
+ wpa_s->conf->num_sec_device_types = entry.array_len;
+ wpa_s->conf->changed_parameters |=
+ CFG_CHANGED_SEC_DEVICE_TYPE;
+ } else if (os_strcmp(entry.key, "VendorExtension") == 0) {
+ if ((entry.type != DBUS_TYPE_ARRAY) ||
+ (entry.array_type != WPAS_DBUS_TYPE_BINARRAY) ||
+ (entry.array_len > P2P_MAX_WPS_VENDOR_EXT))
+ goto error_clear;
+
+ wpa_s->conf->changed_parameters |=
+ CFG_CHANGED_VENDOR_EXTENSION;
+
+ for (i = 0; i < P2P_MAX_WPS_VENDOR_EXT; i++) {
+ wpabuf_free(wpa_s->conf->wps_vendor_ext[i]);
+ if (i < entry.array_len) {
+ wpa_s->conf->wps_vendor_ext[i] =
+ entry.binarray_value[i];
+ entry.binarray_value[i] = NULL;
+ } else
+ wpa_s->conf->wps_vendor_ext[i] = NULL;
+ }
+ } else if ((os_strcmp(entry.key, "GOIntent") == 0) &&
+ (entry.type == DBUS_TYPE_UINT32) &&
+ (entry.uint32_value <= 15))
+ wpa_s->conf->p2p_go_intent = entry.uint32_value;
+
+ else if ((os_strcmp(entry.key, "PersistantReconnect") == 0) &&
+ (entry.type == DBUS_TYPE_BOOLEAN))
+ wpa_s->conf->persistent_reconnect = entry.bool_value;
+
+ else if ((os_strcmp(entry.key, "ListenRegClass") == 0) &&
+ (entry.type == DBUS_TYPE_UINT32)) {
+ wpa_s->conf->p2p_listen_reg_class = entry.uint32_value;
+ wpa_s->conf->changed_parameters |=
+ CFG_CHANGED_P2P_LISTEN_CHANNEL;
+ } else if ((os_strcmp(entry.key, "ListenChannel") == 0) &&
+ (entry.type == DBUS_TYPE_UINT32)) {
+ wpa_s->conf->p2p_listen_channel = entry.uint32_value;
+ wpa_s->conf->changed_parameters |=
+ CFG_CHANGED_P2P_LISTEN_CHANNEL;
+ } else if ((os_strcmp(entry.key, "OperRegClass") == 0) &&
+ (entry.type == DBUS_TYPE_UINT32)) {
+ wpa_s->conf->p2p_oper_reg_class = entry.uint32_value;
+ wpa_s->conf->changed_parameters |=
+ CFG_CHANGED_P2P_OPER_CHANNEL;
+ } else if ((os_strcmp(entry.key, "OperChannel") == 0) &&
+ (entry.type == DBUS_TYPE_UINT32)) {
+ wpa_s->conf->p2p_oper_channel = entry.uint32_value;
+ wpa_s->conf->changed_parameters |=
+ CFG_CHANGED_P2P_OPER_CHANNEL;
+ } else if (os_strcmp(entry.key, "SsidPostfix") == 0) {
+ char *postfix;
+
+ if (entry.type != DBUS_TYPE_STRING)
+ goto error_clear;
+
+ postfix = os_strdup(entry.str_value);
+ if (!postfix)
+ goto err_no_mem_clear;
+
+ os_free(wpa_s->conf->p2p_ssid_postfix);
+ wpa_s->conf->p2p_ssid_postfix = postfix;
+
+ wpa_s->conf->changed_parameters |=
+ CFG_CHANGED_P2P_SSID_POSTFIX;
+ } else if ((os_strcmp(entry.key, "IntraBss") == 0) &&
+ (entry.type == DBUS_TYPE_BOOLEAN)) {
+ wpa_s->conf->p2p_intra_bss = entry.bool_value;
+ wpa_s->conf->changed_parameters |=
+ CFG_CHANGED_P2P_INTRA_BSS;
+ } else if ((os_strcmp(entry.key, "GroupIdle") == 0) &&
+ (entry.type == DBUS_TYPE_UINT32))
+ wpa_s->conf->p2p_group_idle = entry.uint32_value;
+ else if (os_strcmp(entry.key, "disassoc_low_ack") == 0 &&
+ entry.type == DBUS_TYPE_UINT32)
+ wpa_s->conf->disassoc_low_ack = entry.uint32_value;
+ else
+ goto error_clear;
+
+ wpa_dbus_dict_entry_clear(&entry);
+ }
+
+ if (wpa_s->conf->changed_parameters) {
+ /* Some changed parameters requires to update config*/
+ wpa_supplicant_update_config(wpa_s);
+ }
+
+ return reply;
+
+ error_clear:
+ wpa_dbus_dict_entry_clear(&entry);
+ error:
+ reply = wpas_dbus_error_invalid_args(message, entry.key);
+ wpa_dbus_dict_entry_clear(&entry);
+
+ return reply;
+ err_no_mem_clear:
+ wpa_dbus_dict_entry_clear(&entry);
+ return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL);
+}
+
+DBusMessage *wpas_dbus_getter_p2p_peers(DBusMessage * message,
+ struct wpa_supplicant * wpa_s)
+{
+ DBusMessage *reply = NULL;
+ struct p2p_data *p2p = wpa_s->global->p2p;
+ int next = 0, i = 0;
+ int num = 0, out_of_mem = 0;
+ const u8 *addr;
+ const struct p2p_peer_info *peer_info = NULL;
+
+ struct dl_list peer_objpath_list;
+ struct peer_objpath_node {
+ struct dl_list list;
+ char path[WPAS_DBUS_OBJECT_PATH_MAX];
+ } *node, *tmp;
+
+ char **peer_obj_paths = NULL;
+
+ dl_list_init(&peer_objpath_list);
+
+ /* Get the first peer info */
+ peer_info = p2p_get_peer_found(p2p, NULL, next);
+
+ /* Get next and accumulate them */
+ next = 1;
+ while (peer_info != NULL) {
+ node = os_zalloc(sizeof(struct peer_objpath_node));
+ if (!node) {
+ out_of_mem = 1;
+ goto error;
+ }
+
+ addr = peer_info->p2p_device_addr;
+ os_snprintf(node->path, WPAS_DBUS_OBJECT_PATH_MAX,
+ "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART
+ "/" COMPACT_MACSTR,
+ wpa_s->dbus_new_path, MAC2STR(addr));
+ dl_list_add_tail(&peer_objpath_list, &node->list);
+ num++;
+
+ peer_info = p2p_get_peer_found(p2p, addr, next);
+ }
+
+ /*
+ * Now construct the peer object paths in a form suitable for
+ * array_property_getter helper below.
+ */
+ peer_obj_paths = os_zalloc(num * sizeof(char *));
+
+ if (!peer_obj_paths) {
+ out_of_mem = 1;
+ goto error;
+ }
+
+ dl_list_for_each_safe(node, tmp, &peer_objpath_list,
+ struct peer_objpath_node, list)
+ peer_obj_paths[i++] = node->path;
+
+ reply = wpas_dbus_simple_array_property_getter(message,
+ DBUS_TYPE_OBJECT_PATH,
+ peer_obj_paths, num);
+
+error:
+ if (peer_obj_paths)
+ os_free(peer_obj_paths);
+
+ dl_list_for_each_safe(node, tmp, &peer_objpath_list,
+ struct peer_objpath_node, list) {
+ dl_list_del(&node->list);
+ os_free(node);
+ }
+ if (out_of_mem)
+ reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
+ NULL);
+
+ return reply;
+}
+
+enum wpas_p2p_role {
+ WPAS_P2P_ROLE_DEVICE,
+ WPAS_P2P_ROLE_GO,
+ WPAS_P2P_ROLE_CLIENT,
+};
+
+static enum wpas_p2p_role wpas_get_p2p_role(struct wpa_supplicant *wpa_s)
+{
+ struct wpa_ssid *ssid = wpa_s->current_ssid;
+
+ if (!ssid)
+ return WPAS_P2P_ROLE_DEVICE;
+ if (wpa_s->wpa_state != WPA_COMPLETED)
+ return WPAS_P2P_ROLE_DEVICE;
+
+ switch (ssid->mode) {
+ case WPAS_MODE_P2P_GO:
+ case WPAS_MODE_P2P_GROUP_FORMATION:
+ return WPAS_P2P_ROLE_GO;
+ case WPAS_MODE_INFRA:
+ if (ssid->p2p_group)
+ return WPAS_P2P_ROLE_CLIENT;
+ return WPAS_P2P_ROLE_DEVICE;
+ default:
+ return WPAS_P2P_ROLE_DEVICE;
+ }
+}
+
+DBusMessage *wpas_dbus_getter_p2p_role(DBusMessage * message,
+ struct wpa_supplicant * wpa_s)
+{
+ char *str;
+
+ switch (wpas_get_p2p_role(wpa_s)) {
+ case WPAS_P2P_ROLE_GO:
+ str = "GO";
+ break;
+ case WPAS_P2P_ROLE_CLIENT:
+ str = "client";
+ break;
+ default:
+ str = "device";
+ }
+
+ return wpas_dbus_simple_property_getter(message, DBUS_TYPE_STRING,
+ &str);
+}
+
+DBusMessage *wpas_dbus_getter_p2p_group(DBusMessage * message,
+ struct wpa_supplicant * wpa_s)
+{
+ if (wpa_s->dbus_groupobj_path == NULL)
+ return NULL;
+
+ return wpas_dbus_simple_property_getter(message,
+ DBUS_TYPE_OBJECT_PATH,
+ &wpa_s->dbus_groupobj_path);
+}
+
+DBusMessage *wpas_dbus_getter_p2p_peergo(DBusMessage * message,
+ struct wpa_supplicant * wpa_s)
+{
+ char go_peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path;
+
+ if (wpas_get_p2p_role(wpa_s) != WPAS_P2P_ROLE_CLIENT)
+ return NULL;
+
+ os_snprintf(go_peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
+ "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/" COMPACT_MACSTR,
+ wpa_s->dbus_new_path, MAC2STR(wpa_s->go_dev_addr));
+ path = go_peer_obj_path;
+ return wpas_dbus_simple_property_getter(message,
+ DBUS_TYPE_OBJECT_PATH, &path);
+}
+
+/*
+ * Peer object properties accessor methods
+ */
+
+DBusMessage *wpas_dbus_getter_p2p_peer_properties(DBusMessage * message,
+ struct peer_handler_args *
+ peer_args)
+{
+ DBusMessage *reply = NULL;
+ DBusMessageIter iter, variant_iter, dict_iter;
+ const struct p2p_peer_info *info = NULL;
+ char devtype[WPS_DEV_TYPE_BUFSIZE];
+
+ /* get the peer info */
+ info = p2p_get_peer_found(peer_args->wpa_s->global->p2p,
+ peer_args->p2p_device_addr, 0);
+ if (info == NULL)
+ return NULL;
+
+ if (message == NULL)
+ reply = dbus_message_new(DBUS_MESSAGE_TYPE_SIGNAL);
+ else
+ reply = dbus_message_new_method_return(message);
+
+ if (!reply)
+ goto err_no_mem;
+
+ dbus_message_iter_init_append(reply, &iter);
+ if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT,
+ "a{sv}", &variant_iter) ||
+ !wpa_dbus_dict_open_write(&variant_iter, &dict_iter))
+ goto err_no_mem;
+
+ /* Fill out the dictionary */
+ wps_dev_type_bin2str(info->pri_dev_type, devtype, sizeof(devtype));
+ if (!wpa_dbus_dict_append_string(&dict_iter, "DeviceName",
+ info->device_name))
+ goto err_no_mem;
+ if (!wpa_dbus_dict_append_string(&dict_iter, "PrimaryDeviceType",
+ devtype))
+ goto err_no_mem;
+ if (!wpa_dbus_dict_append_uint16(&dict_iter, "config_method",
+ info->config_methods))
+ goto err_no_mem;
+ if (!wpa_dbus_dict_append_int32(&dict_iter, "level",
+ info->level))
+ goto err_no_mem;
+ if (!wpa_dbus_dict_append_byte(&dict_iter, "devicecapability",
+ info->dev_capab))
+ goto err_no_mem;
+ if (!wpa_dbus_dict_append_byte(&dict_iter, "groupcapability",
+ info->group_capab))
+ goto err_no_mem;
+
+ if (info->wps_sec_dev_type_list_len) {
+ char *sec_dev_types[MAX_SEC_DEVICE_TYPES];
+ u8 *sec_dev_type_list = NULL;
+ char secdevtype[WPS_DEV_TYPE_BUFSIZE];
+ int num_sec_dev_types = 0;
+ int i;
+
+ sec_dev_type_list = os_zalloc(info->wps_sec_dev_type_list_len);
+
+ if (sec_dev_type_list == NULL)
+ goto err_no_mem;
+
+ os_memcpy(sec_dev_type_list, info->wps_sec_dev_type_list,
+ info->wps_sec_dev_type_list_len);
+
+ for (i = 0; i < MAX_SEC_DEVICE_TYPES &&
+ i < (int) (info->wps_sec_dev_type_list_len /
+ WPS_DEV_TYPE_LEN);
+ i++) {
+ sec_dev_types[i] = os_zalloc(sizeof(secdevtype));
+
+ if (!sec_dev_types[i] ||
+ wps_dev_type_bin2str(
+ &sec_dev_type_list[i *
+ WPS_DEV_TYPE_LEN],
+ sec_dev_types[i],
+ sizeof(secdevtype)) == NULL) {
+ while (--i >= 0)
+ os_free(sec_dev_types[i]);
+ os_free(sec_dev_type_list);
+ goto err_no_mem;
+ }
+
+ num_sec_dev_types++;
+ }
+
+ os_free(sec_dev_type_list);
+
+ if (num_sec_dev_types) {
+ if (!wpa_dbus_dict_append_string_array(&dict_iter,
+ "SecondaryDeviceTypes",
+ (const char **)sec_dev_types,
+ num_sec_dev_types)) {
+ for (i = 0; i < num_sec_dev_types; i++)
+ os_free(sec_dev_types[i]);
+ goto err_no_mem;
+ }
+
+ for (i = 0; i < num_sec_dev_types; i++)
+ os_free(sec_dev_types[i]);
+ }
+ }
+
+ {
+ /* Add WPS vendor extensions attribute */
+ const struct wpabuf *vendor_extension[P2P_MAX_WPS_VENDOR_EXT];
+ int i, num = 0;
+
+ for (i = 0; i < P2P_MAX_WPS_VENDOR_EXT; i++) {
+ if (info->wps_vendor_ext[i] == NULL)
+ continue;
+ vendor_extension[num] = info->wps_vendor_ext[i];
+ num++;
+ }
+
+ if (!wpa_dbus_dict_append_wpabuf_array(
+ &dict_iter, "VendorExtension",
+ vendor_extension, num))
+ goto err_no_mem;
+ }
+
+ if (!wpa_dbus_dict_close_write(&variant_iter, &dict_iter) ||
+ !dbus_message_iter_close_container(&iter, &variant_iter))
+ goto err_no_mem;
+
+ return reply;
+err_no_mem:
+ dbus_message_unref(reply);
+ return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL);
+}
+
+DBusMessage *wpas_dbus_getter_p2p_peer_ies(DBusMessage * message,
+ struct peer_handler_args * peer_args)
+{
+ return NULL;
+}
+
+
+/**
+ * wpas_dbus_getter_persistent_groups - Get array of peristent group objects
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: a dbus message containing an array of all persistent group
+ * dbus object paths.
+ *
+ * Getter for "Networks" property.
+ */
+DBusMessage * wpas_dbus_getter_persistent_groups(DBusMessage *message,
+ struct wpa_supplicant *wpa_s)
+{
+ DBusMessage *reply = NULL;
+ struct wpa_ssid *ssid;
+ char **paths;
+ unsigned int i = 0, num = 0;
+
+ if (wpa_s->conf == NULL) {
+ wpa_printf(MSG_ERROR, "dbus: %s: "
+ "An error occurred getting persistent groups list",
+ __func__);
+ return wpas_dbus_error_unknown_error(message, NULL);
+ }
+
+ for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next)
+ if (network_is_persistent_group(ssid))
+ num++;
+
+ paths = os_zalloc(num * sizeof(char *));
+ if (!paths) {
+ return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
+ NULL);
+ }
+
+ /* Loop through configured networks and append object path of each */
+ for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
+ if (!network_is_persistent_group(ssid))
+ continue;
+ paths[i] = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX);
+ if (paths[i] == NULL) {
+ reply = dbus_message_new_error(message,
+ DBUS_ERROR_NO_MEMORY,
+ NULL);
+ goto out;
+ }
+ /* Construct the object path for this network. */
+ os_snprintf(paths[i++], WPAS_DBUS_OBJECT_PATH_MAX,
+ "%s/" WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART "/%d",
+ wpa_s->dbus_new_path, ssid->id);
+ }
+
+ reply = wpas_dbus_simple_array_property_getter(message,
+ DBUS_TYPE_OBJECT_PATH,
+ paths, num);
+
+out:
+ while (i)
+ os_free(paths[--i]);
+ os_free(paths);
+ return reply;
+}
+
+
+/**
+ * wpas_dbus_getter_persistent_group_properties - Get options for a persistent
+ * group
+ * @message: Pointer to incoming dbus message
+ * @net: wpa_supplicant structure for a network interface and
+ * wpa_ssid structure for a configured persistent group (internally network)
+ * Returns: DBus message with network properties or DBus error on failure
+ *
+ * Getter for "Properties" property of a persistent group.
+ */
+DBusMessage * wpas_dbus_getter_persistent_group_properties(
+ DBusMessage *message, struct network_handler_args *net)
+{
+ /*
+ * Leveraging the fact that persistent group object is still
+ * represented in same manner as network within.
+ */
+ return wpas_dbus_getter_network_properties(message, net);
+}
+
+
+/**
+ * wpas_dbus_setter_persistent_group_properties - Get options for a persistent
+ * group
+ * @message: Pointer to incoming dbus message
+ * @net: wpa_supplicant structure for a network interface and
+ * wpa_ssid structure for a configured persistent group (internally network)
+ * Returns: DBus message with network properties or DBus error on failure
+ *
+ * Setter for "Properties" property of a persistent group.
+ */
+DBusMessage * wpas_dbus_setter_persistent_group_properties(
+ DBusMessage *message, struct network_handler_args *net)
+{
+ struct wpa_ssid *ssid = net->ssid;
+ DBusMessage *reply = NULL;
+ DBusMessageIter iter, variant_iter;
+
+ dbus_message_iter_init(message, &iter);
+
+ dbus_message_iter_next(&iter);
+ dbus_message_iter_next(&iter);
+
+ dbus_message_iter_recurse(&iter, &variant_iter);
+
+ /*
+ * Leveraging the fact that persistent group object is still
+ * represented in same manner as network within.
+ */
+ reply = set_network_properties(message, net->wpa_s, ssid,
+ &variant_iter);
+ if (reply)
+ wpa_printf(MSG_DEBUG, "dbus control interface couldn't set "
+ "persistent group properties");
+
+ return reply;
+}
+
+
+/**
+ * wpas_dbus_new_iface_add_persistent_group - Add a new configured
+ * persistent_group
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: A dbus message containing the object path of the new
+ * persistent group
+ *
+ * Handler function for "AddPersistentGroup" method call of a P2P Device
+ * interface.
+ */
+DBusMessage * wpas_dbus_handler_add_persistent_group(
+ DBusMessage *message, struct wpa_supplicant *wpa_s)
+{
+ DBusMessage *reply = NULL;
+ DBusMessageIter iter;
+ struct wpa_ssid *ssid = NULL;
+ char path_buf[WPAS_DBUS_OBJECT_PATH_MAX], *path = path_buf;
+
+ dbus_message_iter_init(message, &iter);
+
+ ssid = wpa_config_add_network(wpa_s->conf);
+ if (ssid == NULL) {
+ wpa_printf(MSG_ERROR, "dbus: %s: "
+ "Cannot add new persistent group", __func__);
+ reply = wpas_dbus_error_unknown_error(
+ message,
+ "wpa_supplicant could not add "
+ "a persistent group on this interface.");
+ goto err;
+ }
+
+ /* Mark the ssid as being a persistent group before the notification */
+ ssid->disabled = 2;
+ ssid->p2p_persistent_group = 1;
+ wpas_notify_persistent_group_added(wpa_s, ssid);
+
+ wpa_config_set_network_defaults(ssid);
+
+ reply = set_network_properties(message, wpa_s, ssid, &iter);
+ if (reply) {
+ wpa_printf(MSG_DEBUG, "dbus: %s: "
+ "Control interface could not set persistent group "
+ "properties", __func__);
+ goto err;
+ }
+
+ /* Construct the object path for this network. */
+ os_snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX,
+ "%s/" WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART "/%d",
+ wpa_s->dbus_new_path, ssid->id);
+
+ reply = dbus_message_new_method_return(message);
+ if (reply == NULL) {
+ reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
+ NULL);
+ goto err;
+ }
+ if (!dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &path,
+ DBUS_TYPE_INVALID)) {
+ dbus_message_unref(reply);
+ reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
+ NULL);
+ goto err;
+ }
+
+ return reply;
+
+err:
+ if (ssid) {
+ wpas_notify_persistent_group_removed(wpa_s, ssid);
+ wpa_config_remove_network(wpa_s->conf, ssid->id);
+ }
+ return reply;
+}
+
+
+/**
+ * wpas_dbus_handler_remove_persistent_group - Remove a configured persistent
+ * group
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: NULL on success or dbus error on failure
+ *
+ * Handler function for "RemovePersistentGroup" method call of a P2P Device
+ * interface.
+ */
+DBusMessage * wpas_dbus_handler_remove_persistent_group(
+ DBusMessage *message, struct wpa_supplicant *wpa_s)
+{
+ DBusMessage *reply = NULL;
+ const char *op;
+ char *iface = NULL, *persistent_group_id = NULL;
+ int id;
+ struct wpa_ssid *ssid;
+
+ dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &op,
+ DBUS_TYPE_INVALID);
+
+ /*
+ * Extract the network ID and ensure the network is actually a child of
+ * this interface.
+ */
+ iface = wpas_dbus_new_decompose_object_path(op, 1,
+ &persistent_group_id,
+ NULL);
+ if (iface == NULL || os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
+ reply = wpas_dbus_error_invalid_args(message, op);
+ goto out;
+ }
+
+ id = strtoul(persistent_group_id, NULL, 10);
+ if (errno == EINVAL) {
+ reply = wpas_dbus_error_invalid_args(message, op);
+ goto out;
+ }
+
+ ssid = wpa_config_get_network(wpa_s->conf, id);
+ if (ssid == NULL) {
+ reply = wpas_dbus_error_persistent_group_unknown(message);
+ goto out;
+ }
+
+ wpas_notify_persistent_group_removed(wpa_s, ssid);
+
+ if (wpa_config_remove_network(wpa_s->conf, id) < 0) {
+ wpa_printf(MSG_ERROR, "dbus: %s: "
+ "error occurred when removing persistent group %d",
+ __func__, id);
+ reply = wpas_dbus_error_unknown_error(
+ message,
+ "error removing the specified persistent group on "
+ "this interface.");
+ goto out;
+ }
+
+out:
+ os_free(iface);
+ os_free(persistent_group_id);
+ return reply;
+}
+
+
+static void remove_persistent_group(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid)
+{
+ wpas_notify_persistent_group_removed(wpa_s, ssid);
+
+ if (wpa_config_remove_network(wpa_s->conf, ssid->id) < 0) {
+ wpa_printf(MSG_ERROR, "dbus: %s: "
+ "error occurred when removing persistent group %d",
+ __func__, ssid->id);
+ return;
+ }
+}
+
+
+/**
+ * wpas_dbus_handler_remove_all_persistent_groups - Remove all configured
+ * persistent groups
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: NULL on success or dbus error on failure
+ *
+ * Handler function for "RemoveAllPersistentGroups" method call of a
+ * P2P Device interface.
+ */
+DBusMessage * wpas_dbus_handler_remove_all_persistent_groups(
+ DBusMessage *message, struct wpa_supplicant *wpa_s)
+{
+ struct wpa_ssid *ssid, *next;
+ struct wpa_config *config;
+
+ config = wpa_s->conf;
+ ssid = config->ssid;
+ while (ssid) {
+ next = ssid->next;
+ if (network_is_persistent_group(ssid))
+ remove_persistent_group(wpa_s, ssid);
+ ssid = next;
+ }
+ return NULL;
+}
+
+
+/*
+ * Group object properties accessor methods
+ */
+
+DBusMessage *wpas_dbus_getter_p2p_group_members(DBusMessage * message,
+ struct wpa_supplicant * wpa_s)
+{
+ DBusMessage *reply = NULL;
+ struct wpa_ssid *ssid;
+ unsigned int num_members;
+ char **paths;
+ unsigned int i;
+ void *next = NULL;
+ const u8 *addr;
+
+ /* Ensure we are a GO */
+ if (wpa_s->wpa_state != WPA_COMPLETED)
+ goto out;
+
+ ssid = wpa_s->conf->ssid;
+ /* At present WPAS P2P_GO mode only applicable for p2p_go */
+ if (ssid->mode != WPAS_MODE_P2P_GO &&
+ ssid->mode != WPAS_MODE_AP &&
+ ssid->mode != WPAS_MODE_P2P_GROUP_FORMATION)
+ goto out;
+
+ num_members = p2p_get_group_num_members(wpa_s->p2p_group);
+
+ paths = os_zalloc(num_members * sizeof(char *));
+ if (!paths)
+ goto out_of_memory;
+
+ i = 0;
+ while ((addr = p2p_iterate_group_members(wpa_s->p2p_group, &next))) {
+ paths[i] = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX);
+ if (!paths[i])
+ goto out_of_memory;
+ os_snprintf(paths[i], WPAS_DBUS_OBJECT_PATH_MAX,
+ "%s/" WPAS_DBUS_NEW_P2P_GROUPMEMBERS_PART
+ "/" COMPACT_MACSTR,
+ wpa_s->dbus_groupobj_path, MAC2STR(addr));
+ i++;
+ }
+
+ reply = wpas_dbus_simple_array_property_getter(message,
+ DBUS_TYPE_OBJECT_PATH,
+ paths, num_members);
+
+out_free:
+ for (i = 0; i < num_members; i++)
+ os_free(paths[i]);
+ os_free(paths);
+out:
+ return reply;
+out_of_memory:
+ reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL);
+ goto out_free;
+}
+
+
+DBusMessage *wpas_dbus_getter_p2p_group_properties(
+ DBusMessage *message,
+ struct wpa_supplicant *wpa_s)
+{
+ DBusMessage *reply = NULL;
+ DBusMessageIter iter, variant_iter, dict_iter;
+ struct hostapd_data *hapd = wpa_s->ap_iface->bss[0];
+ const struct wpabuf *vendor_ext[MAX_WPS_VENDOR_EXTENSIONS];
+ int num_vendor_ext = 0;
+ int i;
+
+ if (!hapd) {
+ reply = dbus_message_new_error(message, DBUS_ERROR_FAILED,
+ NULL);
+ return reply;
+ }
+
+ if (message == NULL)
+ reply = dbus_message_new(DBUS_MESSAGE_TYPE_SIGNAL);
+ else
+ reply = dbus_message_new_method_return(message);
+
+ if (!reply)
+ goto err_no_mem;
+
+ dbus_message_iter_init_append(reply, &iter);
+
+ if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT,
+ "a{sv}", &variant_iter) ||
+ !wpa_dbus_dict_open_write(&variant_iter, &dict_iter))
+ goto err_no_mem;
+
+ /* Parse WPS Vendor Extensions sent in Beacon/Probe Response */
+ for (i = 0; i < MAX_WPS_VENDOR_EXTENSIONS; i++) {
+ if (hapd->conf->wps_vendor_ext[i] == NULL)
+ continue;
+ vendor_ext[num_vendor_ext++] = hapd->conf->wps_vendor_ext[i];
+ }
+
+ if (!wpa_dbus_dict_append_wpabuf_array(&dict_iter,
+ "WPSVendorExtensions",
+ vendor_ext, num_vendor_ext))
+ goto err_no_mem;
+
+ if (!wpa_dbus_dict_close_write(&variant_iter, &dict_iter) ||
+ !dbus_message_iter_close_container(&iter, &variant_iter))
+ goto err_no_mem;
+
+ return reply;
+
+err_no_mem:
+ dbus_message_unref(reply);
+ return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL);
+}
+
+DBusMessage *wpas_dbus_setter_p2p_group_properties(
+ DBusMessage *message,
+ struct wpa_supplicant *wpa_s)
+{
+ DBusMessage *reply = NULL;
+ DBusMessageIter iter, variant_iter;
+ struct wpa_dbus_dict_entry entry = {.type = DBUS_TYPE_STRING };
+ DBusMessageIter iter_dict;
+ unsigned int i;
+
+ struct hostapd_data *hapd = wpa_s->ap_iface->bss[0];
+
+ if (!hapd)
+ goto error;
+
+ dbus_message_iter_init(message, &iter);
+
+ dbus_message_iter_next(&iter);
+ dbus_message_iter_next(&iter);
+
+ dbus_message_iter_recurse(&iter, &variant_iter);
+
+ if (!wpa_dbus_dict_open_read(&variant_iter, &iter_dict))
+ return wpas_dbus_error_invalid_args(message, NULL);
+
+ while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
+ if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) {
+ reply = wpas_dbus_error_invalid_args(message, NULL);
+ break;
+ }
+
+ if (os_strcmp(entry.key, "WPSVendorExtensions") == 0) {
+ if (entry.type != DBUS_TYPE_ARRAY ||
+ entry.array_type != WPAS_DBUS_TYPE_BINARRAY ||
+ entry.array_len > MAX_WPS_VENDOR_EXTENSIONS)
+ goto error;
+
+ for (i = 0; i < MAX_WPS_VENDOR_EXTENSIONS; i++) {
+ if (i < entry.array_len) {
+ hapd->conf->wps_vendor_ext[i] =
+ entry.binarray_value[i];
+ entry.binarray_value[i] = NULL;
+ } else
+ hapd->conf->wps_vendor_ext[i] = NULL;
+ }
+
+ hostapd_update_wps(hapd);
+ } else
+ goto error;
+
+ wpa_dbus_dict_entry_clear(&entry);
+ }
+
+ return reply;
+
+error:
+ reply = wpas_dbus_error_invalid_args(message, entry.key);
+ wpa_dbus_dict_entry_clear(&entry);
+
+ return reply;
+}
+
+DBusMessage *wpas_dbus_handler_p2p_add_service(DBusMessage * message,
+ struct wpa_supplicant * wpa_s)
+{
+ DBusMessageIter iter_dict;
+ DBusMessage *reply = NULL;
+ DBusMessageIter iter;
+ struct wpa_dbus_dict_entry entry;
+ int upnp = 0;
+ int bonjour = 0;
+ char *service = NULL;
+ struct wpabuf *query = NULL;
+ struct wpabuf *resp = NULL;
+ u8 version = 0;
+
+ dbus_message_iter_init(message, &iter);
+
+ if (!wpa_dbus_dict_open_read(&iter, &iter_dict))
+ goto error;
+
+ if (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
+ if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
+ goto error;
+
+ if (!strcmp(entry.key, "service_type") &&
+ (entry.type == DBUS_TYPE_STRING)) {
+ if (!strcmp(entry.str_value, "upnp"))
+ upnp = 1;
+ else if (!strcmp(entry.str_value, "bonjour"))
+ bonjour = 1;
+ else
+ goto error_clear;
+ wpa_dbus_dict_entry_clear(&entry);
+ }
+ }
+
+ if (upnp == 1) {
+ while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
+ if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
+ goto error;
+
+ if (!strcmp(entry.key, "version") &&
+ entry.type == DBUS_TYPE_INT32)
+ version = entry.uint32_value;
+ else if (!strcmp(entry.key, "service") &&
+ entry.type == DBUS_TYPE_STRING)
+ service = os_strdup(entry.str_value);
+ wpa_dbus_dict_entry_clear(&entry);
+ }
+ if (version <= 0 || service == NULL)
+ goto error;
+
+ if (wpas_p2p_service_add_upnp(wpa_s, version, service) != 0)
+ goto error;
+
+ os_free(service);
+ } else if (bonjour == 1) {
+ while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
+ if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
+ goto error;
+
+ if (!strcmp(entry.key, "query")) {
+ if ((entry.type != DBUS_TYPE_ARRAY) ||
+ (entry.array_type != DBUS_TYPE_BYTE))
+ goto error_clear;
+ query = wpabuf_alloc_copy(entry.bytearray_value,
+ entry.array_len);
+ } else if (!strcmp(entry.key, "response")) {
+ if ((entry.type != DBUS_TYPE_ARRAY) ||
+ (entry.array_type != DBUS_TYPE_BYTE))
+ goto error_clear;
+ resp = wpabuf_alloc_copy(entry.bytearray_value,
+ entry.array_len);
+ }
+
+ wpa_dbus_dict_entry_clear(&entry);
+ }
+
+ if (query == NULL || resp == NULL)
+ goto error;
+
+ if (wpas_p2p_service_add_bonjour(wpa_s, query, resp) < 0) {
+ wpabuf_free(query);
+ wpabuf_free(resp);
+ goto error;
+ }
+ } else
+ goto error;
+
+ return reply;
+error_clear:
+ wpa_dbus_dict_entry_clear(&entry);
+error:
+ return wpas_dbus_error_invalid_args(message, NULL);
+}
+
+DBusMessage *wpas_dbus_handler_p2p_delete_service(DBusMessage * message,
+ struct wpa_supplicant * wpa_s)
+{
+ DBusMessageIter iter_dict;
+ DBusMessage *reply = NULL;
+ DBusMessageIter iter;
+ struct wpa_dbus_dict_entry entry;
+ int upnp = 0;
+ int bonjour = 0;
+ int ret = 0;
+ char *service = NULL;
+ struct wpabuf *query = NULL;
+ u8 version = 0;
+
+ dbus_message_iter_init(message, &iter);
+
+ if (!wpa_dbus_dict_open_read(&iter, &iter_dict))
+ goto error;
+
+ if (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
+ if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
+ goto error;
+
+ if (!strcmp(entry.key, "service_type") &&
+ (entry.type == DBUS_TYPE_STRING)) {
+ if (!strcmp(entry.str_value, "upnp"))
+ upnp = 1;
+ else if (!strcmp(entry.str_value, "bonjour"))
+ bonjour = 1;
+ else
+ goto error_clear;
+ wpa_dbus_dict_entry_clear(&entry);
+ }
+ }
+ if (upnp == 1) {
+ while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
+ if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
+ goto error;
+ if (!strcmp(entry.key, "version") &&
+ entry.type == DBUS_TYPE_INT32)
+ version = entry.uint32_value;
+ else if (!strcmp(entry.key, "service") &&
+ entry.type == DBUS_TYPE_STRING)
+ service = os_strdup(entry.str_value);
+ else
+ goto error_clear;
+
+ wpa_dbus_dict_entry_clear(&entry);
+ }
+
+ if (version <= 0 || service == NULL)
+ goto error;
+
+ ret = wpas_p2p_service_del_upnp(wpa_s, version, service);
+ os_free(service);
+ if (ret != 0)
+ goto error;
+ } else if (bonjour == 1) {
+ while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
+ if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
+ goto error;
+
+ if (!strcmp(entry.key, "query")) {
+ if ((entry.type != DBUS_TYPE_ARRAY) ||
+ (entry.array_type != DBUS_TYPE_BYTE))
+ goto error_clear;
+ query = wpabuf_alloc_copy(entry.bytearray_value,
+ entry.array_len);
+ } else
+ goto error_clear;
+
+ wpa_dbus_dict_entry_clear(&entry);
+ }
+
+ if (query == NULL)
+ goto error;
+
+ ret = wpas_p2p_service_del_bonjour(wpa_s, query);
+ if (ret != 0)
+ goto error;
+ wpabuf_free(query);
+ } else
+ goto error;
+
+ return reply;
+error_clear:
+ wpa_dbus_dict_entry_clear(&entry);
+error:
+ return wpas_dbus_error_invalid_args(message, NULL);
+}
+
+DBusMessage *wpas_dbus_handler_p2p_flush_service(DBusMessage * message,
+ struct wpa_supplicant * wpa_s)
+{
+ wpas_p2p_service_flush(wpa_s);
+ return NULL;
+}
+
+DBusMessage *wpas_dbus_handler_p2p_service_sd_req(DBusMessage * message,
+ struct wpa_supplicant * wpa_s)
+{
+ DBusMessageIter iter_dict;
+ DBusMessage *reply = NULL;
+ DBusMessageIter iter;
+ struct wpa_dbus_dict_entry entry;
+ int upnp = 0;
+ char *service = NULL;
+ char *peer_object_path = NULL;
+ struct wpabuf *tlv = NULL;
+ u8 version = 0;
+ u64 ref = 0;
+ u8 addr[ETH_ALEN];
+
+ dbus_message_iter_init(message, &iter);
+
+ if (!wpa_dbus_dict_open_read(&iter, &iter_dict))
+ goto error;
+
+ while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
+ if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
+ goto error;
+ if (!strcmp(entry.key, "peer_object") &&
+ entry.type == DBUS_TYPE_OBJECT_PATH) {
+ peer_object_path = os_strdup(entry.str_value);
+ } else if (!strcmp(entry.key, "service_type") &&
+ entry.type == DBUS_TYPE_STRING) {
+ if (!strcmp(entry.str_value, "upnp"))
+ upnp = 1;
+ else
+ goto error_clear;
+ } else if (!strcmp(entry.key, "version") &&
+ entry.type == DBUS_TYPE_INT32) {
+ version = entry.uint32_value;
+ } else if (!strcmp(entry.key, "service") &&
+ entry.type == DBUS_TYPE_STRING) {
+ service = os_strdup(entry.str_value);
+ } else if (!strcmp(entry.key, "tlv")) {
+ if (entry.type != DBUS_TYPE_ARRAY ||
+ entry.array_type != DBUS_TYPE_BYTE)
+ goto error_clear;
+ tlv = wpabuf_alloc_copy(entry.bytearray_value,
+ entry.array_len);
+ } else
+ goto error_clear;
+
+ wpa_dbus_dict_entry_clear(&entry);
+ }
+
+ if (!peer_object_path ||
+ (parse_peer_object_path(peer_object_path, addr) < 0) ||
+ (p2p_get_peer_info(wpa_s->global->p2p, addr, 0, NULL, 0) < 0))
+ goto error;
+
+ if (upnp == 1) {
+ if (version <= 0 || service == NULL)
+ goto error;
+
+ ref = (unsigned long)wpas_p2p_sd_request_upnp(wpa_s, addr,
+ version, service);
+ } else {
+ if (tlv == NULL)
+ goto error;
+ ref = (unsigned long)wpas_p2p_sd_request(wpa_s, addr, tlv);
+ wpabuf_free(tlv);
+ }
+
+ if (ref != 0) {
+ reply = dbus_message_new_method_return(message);
+ dbus_message_append_args(reply, DBUS_TYPE_UINT64,
+ &ref, DBUS_TYPE_INVALID);
+ } else {
+ reply = wpas_dbus_error_unknown_error(message,
+ "Unable to send SD request");
+ }
+out:
+ os_free(service);
+ os_free(peer_object_path);
+ return reply;
+error_clear:
+ wpa_dbus_dict_entry_clear(&entry);
+error:
+ if (tlv)
+ wpabuf_free(tlv);
+ reply = wpas_dbus_error_invalid_args(message, NULL);
+ goto out;
+}
+
+DBusMessage *wpas_dbus_handler_p2p_service_sd_res(
+ DBusMessage *message, struct wpa_supplicant *wpa_s)
+{
+ DBusMessageIter iter_dict;
+ DBusMessage *reply = NULL;
+ DBusMessageIter iter;
+ struct wpa_dbus_dict_entry entry;
+ char *peer_object_path = NULL;
+ struct wpabuf *tlv = NULL;
+ int freq = 0;
+ int dlg_tok = 0;
+ u8 addr[ETH_ALEN];
+
+ dbus_message_iter_init(message, &iter);
+
+ if (!wpa_dbus_dict_open_read(&iter, &iter_dict))
+ goto error;
+
+ while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
+ if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
+ goto error;
+
+ if (!strcmp(entry.key, "peer_object") &&
+ entry.type == DBUS_TYPE_OBJECT_PATH) {
+ peer_object_path = os_strdup(entry.str_value);
+ } else if (!strcmp(entry.key, "frequency") &&
+ entry.type == DBUS_TYPE_INT32) {
+ freq = entry.uint32_value;
+ } else if (!strcmp(entry.key, "dialog_token") &&
+ entry.type == DBUS_TYPE_UINT32) {
+ dlg_tok = entry.uint32_value;
+ } else if (!strcmp(entry.key, "tlvs")) {
+ if (entry.type != DBUS_TYPE_ARRAY ||
+ entry.array_type != DBUS_TYPE_BYTE)
+ goto error_clear;
+ tlv = wpabuf_alloc_copy(entry.bytearray_value,
+ entry.array_len);
+ } else
+ goto error_clear;
+
+ wpa_dbus_dict_entry_clear(&entry);
+ }
+ if (!peer_object_path ||
+ (parse_peer_object_path(peer_object_path, addr) < 0) ||
+ (p2p_get_peer_info(wpa_s->global->p2p, addr, 0, NULL, 0) < 0))
+ goto error;
+
+ if (tlv == NULL)
+ goto error;
+
+ wpas_p2p_sd_response(wpa_s, freq, addr, (u8) dlg_tok, tlv);
+ wpabuf_free(tlv);
+out:
+ os_free(peer_object_path);
+ return reply;
+error_clear:
+ wpa_dbus_dict_entry_clear(&entry);
+error:
+ reply = wpas_dbus_error_invalid_args(message, NULL);
+ goto out;
+}
+
+DBusMessage *wpas_dbus_handler_p2p_service_sd_cancel_req(DBusMessage * message, struct wpa_supplicant
+ *wpa_s)
+{
+ DBusMessageIter iter;
+ u64 req = 0;
+
+ dbus_message_iter_init(message, &iter);
+ dbus_message_iter_get_basic(&iter, &req);
+
+ if (req == 0)
+ goto error;
+
+ if (!wpas_p2p_sd_cancel_request(wpa_s, (void *)(unsigned long)req))
+ goto error;
+
+ return NULL;
+error:
+ return wpas_dbus_error_invalid_args(message, NULL);
+}
+
+DBusMessage *wpas_dbus_handler_p2p_service_update(DBusMessage * message,
+ struct wpa_supplicant * wpa_s)
+{
+ wpas_p2p_sd_service_update(wpa_s);
+ return NULL;
+}
+
+DBusMessage *wpas_dbus_handler_p2p_serv_disc_external(DBusMessage * message,
+ struct wpa_supplicant *
+ wpa_s)
+{
+ DBusMessageIter iter;
+ int ext = 0;
+
+ dbus_message_iter_init(message, &iter);
+ dbus_message_iter_get_basic(&iter, &ext);
+
+ wpa_s->p2p_sd_over_ctrl_iface = ext;
+
+ return NULL;
+
+}
diff --git a/wpa_supplicant/dbus/dbus_new_handlers_p2p.h b/wpa_supplicant/dbus/dbus_new_handlers_p2p.h
new file mode 100644
index 0000000..ed9a345
--- /dev/null
+++ b/wpa_supplicant/dbus/dbus_new_handlers_p2p.h
@@ -0,0 +1,162 @@
+
+/*
+ * WPA Supplicant / dbus-based control interface for p2p
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#ifndef DBUS_NEW_HANDLERS_P2P_H
+#define DBUS_NEW_HANDLERS_P2P_H
+
+struct peer_handler_args {
+ struct wpa_supplicant *wpa_s;
+ u8 p2p_device_addr[ETH_ALEN];
+};
+
+struct groupmember_handler_args {
+ struct wpa_supplicant *wpa_s;
+ u8 member_addr[ETH_ALEN];
+};
+
+/*
+ * P2P Device methods
+ */
+
+DBusMessage *wpas_dbus_handler_p2p_find(
+ DBusMessage *message, struct wpa_supplicant *wpa_s);
+
+DBusMessage *wpas_dbus_handler_p2p_stop_find(
+ DBusMessage *message, struct wpa_supplicant *wpa_s);
+
+DBusMessage *wpas_dbus_handler_p2p_rejectpeer(
+ DBusMessage *message, struct wpa_supplicant *wpa_s);
+
+DBusMessage *wpas_dbus_handler_p2p_listen(
+ DBusMessage *message, struct wpa_supplicant *wpa_s);
+
+DBusMessage *wpas_dbus_handler_p2p_extendedlisten(
+ DBusMessage *message, struct wpa_supplicant *wpa_s);
+
+DBusMessage *wpas_dbus_handler_p2p_presence_request(
+ DBusMessage *message, struct wpa_supplicant *wpa_s);
+
+DBusMessage *wpas_dbus_handler_p2p_prov_disc_req(
+ DBusMessage *message, struct wpa_supplicant *wpa_s);
+
+DBusMessage *wpas_dbus_handler_p2p_group_add(
+ DBusMessage *message, struct wpa_supplicant *wpa_s);
+
+DBusMessage *wpas_dbus_handler_p2p_connect(
+ DBusMessage *message,
+ struct wpa_supplicant *wpa_s);
+
+DBusMessage *wpas_dbus_handler_p2p_invite(
+ DBusMessage *message,
+ struct wpa_supplicant *wpa_s);
+
+DBusMessage *wpas_dbus_handler_p2p_disconnect(
+ DBusMessage *message, struct wpa_supplicant *wpa_s);
+
+DBusMessage *wpas_dbus_handler_p2p_flush(
+ DBusMessage *message, struct wpa_supplicant *wpa_s);
+
+DBusMessage *wpas_dbus_handler_p2p_add_service(
+ DBusMessage *message, struct wpa_supplicant *wpa_s);
+
+DBusMessage *wpas_dbus_handler_p2p_delete_service(
+ DBusMessage *message, struct wpa_supplicant *wpa_s);
+
+DBusMessage *wpas_dbus_handler_p2p_flush_service(
+ DBusMessage *message, struct wpa_supplicant *wpa_s);
+
+DBusMessage *wpas_dbus_handler_p2p_service_sd_req(
+ DBusMessage *message, struct wpa_supplicant *wpa_s);
+
+DBusMessage *wpas_dbus_handler_p2p_service_sd_res(
+ DBusMessage *message, struct wpa_supplicant *wpa_s);
+
+DBusMessage *wpas_dbus_handler_p2p_service_sd_cancel_req(
+ DBusMessage *message, struct wpa_supplicant *wpa_s);
+
+DBusMessage *wpas_dbus_handler_p2p_service_update(
+ DBusMessage *message, struct wpa_supplicant *wpa_s);
+
+DBusMessage *wpas_dbus_handler_p2p_serv_disc_external(
+ DBusMessage *message, struct wpa_supplicant *wpa_s);
+
+/*
+ * P2P Device property accessor methods.
+ */
+DBusMessage *wpas_dbus_setter_p2p_device_properties(DBusMessage *message,
+ struct wpa_supplicant *wpa_s);
+
+DBusMessage *wpas_dbus_getter_p2p_device_properties(DBusMessage *message,
+ struct wpa_supplicant *wpa_s);
+
+DBusMessage *wpas_dbus_getter_p2p_peers(DBusMessage *message,
+ struct wpa_supplicant *wpa_s);
+
+DBusMessage *wpas_dbus_getter_p2p_role(DBusMessage *message,
+ struct wpa_supplicant *wpa_s);
+
+DBusMessage *wpas_dbus_getter_p2p_group(DBusMessage *message,
+ struct wpa_supplicant *wpa_s);
+
+DBusMessage *wpas_dbus_getter_p2p_peergo(DBusMessage *message,
+ struct wpa_supplicant *wpa_s);
+
+/*
+ * P2P Peer properties.
+ */
+DBusMessage *wpas_dbus_getter_p2p_peer_properties(
+ DBusMessage *message,
+ struct peer_handler_args *peer);
+
+DBusMessage *wpas_dbus_getter_p2p_peer_ies(
+ DBusMessage *message,
+ struct peer_handler_args *peer);
+
+/*
+ * P2P Group properties
+ */
+
+DBusMessage *wpas_dbus_getter_p2p_group_members(
+ DBusMessage *message,
+ struct wpa_supplicant *wpa_s);
+
+DBusMessage *wpas_dbus_getter_p2p_group_properties(
+ DBusMessage *message,
+ struct wpa_supplicant *wpa_s);
+
+DBusMessage *wpas_dbus_setter_p2p_group_properties(
+ DBusMessage *message,
+ struct wpa_supplicant *wpa_s);
+
+/*
+ * P2P Persistent Groups and properties
+ */
+
+DBusMessage * wpas_dbus_getter_persistent_groups(DBusMessage *message,
+ struct wpa_supplicant *wpa_s);
+DBusMessage * wpas_dbus_getter_persistent_group_properties(
+ DBusMessage *message, struct network_handler_args *net);
+DBusMessage * wpas_dbus_setter_persistent_group_properties(
+ DBusMessage *message, struct network_handler_args *net);
+DBusMessage * wpas_dbus_handler_add_persistent_group(
+ DBusMessage *message, struct wpa_supplicant *wpa_s);
+
+DBusMessage * wpas_dbus_handler_remove_persistent_group(
+ DBusMessage *message, struct wpa_supplicant *wpa_s);
+
+DBusMessage * wpas_dbus_handler_remove_all_persistent_groups(
+ DBusMessage *message, struct wpa_supplicant *wpa_s);
+
+
+#endif /* DBUS_NEW_HANDLERS_P2P_H */
diff --git a/wpa_supplicant/dbus/dbus_new_helpers.c b/wpa_supplicant/dbus/dbus_new_helpers.c
index 6e6e842..78611d4 100644
--- a/wpa_supplicant/dbus/dbus_new_helpers.c
+++ b/wpa_supplicant/dbus/dbus_new_helpers.c
@@ -884,3 +884,74 @@ void wpa_dbus_get_object_properties(struct wpas_dbus_priv *iface,
fill_dict_with_properties(dict_iter, obj_desc->properties,
interface, obj_desc->user_data);
}
+
+/**
+ * wpas_dbus_new_decompose_object_path - Decompose an interface object path into parts
+ * @path: The dbus object path
+ * @p2p_persistent_group: indicates whether to parse the path as a P2P
+ * persistent group object
+ * @network: (out) the configured network this object path refers to, if any
+ * @bssid: (out) the scanned bssid this object path refers to, if any
+ * Returns: The object path of the network interface this path refers to
+ *
+ * For a given object path, decomposes the object path into object id, network,
+ * and BSSID parts, if those parts exist.
+ */
+char *wpas_dbus_new_decompose_object_path(const char *path,
+ int p2p_persistent_group,
+ char **network,
+ char **bssid)
+{
+ const unsigned int dev_path_prefix_len =
+ os_strlen(WPAS_DBUS_NEW_PATH_INTERFACES "/");
+ char *obj_path_only;
+ char *next_sep;
+
+ /* Be a bit paranoid about path */
+ if (!path || os_strncmp(path, WPAS_DBUS_NEW_PATH_INTERFACES "/",
+ dev_path_prefix_len))
+ return NULL;
+
+ /* Ensure there's something at the end of the path */
+ if ((path + dev_path_prefix_len)[0] == '\0')
+ return NULL;
+
+ obj_path_only = os_strdup(path);
+ if (obj_path_only == NULL)
+ return NULL;
+
+ next_sep = os_strchr(obj_path_only + dev_path_prefix_len, '/');
+ if (next_sep != NULL) {
+ const char *net_part = os_strstr(
+ next_sep, p2p_persistent_group ?
+ WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART "/" :
+ WPAS_DBUS_NEW_NETWORKS_PART "/");
+ const char *bssid_part = os_strstr(
+ next_sep, WPAS_DBUS_NEW_BSSIDS_PART "/");
+
+ if (network && net_part) {
+ /* Deal with a request for a configured network */
+ const char *net_name = net_part +
+ os_strlen(p2p_persistent_group ?
+ WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART
+ "/" :
+ WPAS_DBUS_NEW_NETWORKS_PART "/");
+ *network = NULL;
+ if (os_strlen(net_name))
+ *network = os_strdup(net_name);
+ } else if (bssid && bssid_part) {
+ /* Deal with a request for a scanned BSSID */
+ const char *bssid_name = bssid_part +
+ os_strlen(WPAS_DBUS_NEW_BSSIDS_PART "/");
+ if (os_strlen(bssid_name))
+ *bssid = os_strdup(bssid_name);
+ else
+ *bssid = NULL;
+ }
+
+ /* Cut off interface object path before "/" */
+ *next_sep = '\0';
+ }
+
+ return obj_path_only;
+}
diff --git a/wpa_supplicant/dbus/dbus_new_helpers.h b/wpa_supplicant/dbus/dbus_new_helpers.h
index 7038b63..fd21c22 100644
--- a/wpa_supplicant/dbus/dbus_new_helpers.h
+++ b/wpa_supplicant/dbus/dbus_new_helpers.h
@@ -145,4 +145,9 @@ void wpa_dbus_mark_property_changed(struct wpas_dbus_priv *iface,
DBusMessage * wpa_dbus_introspect(DBusMessage *message,
struct wpa_dbus_object_desc *obj_dsc);
+char *wpas_dbus_new_decompose_object_path(const char *path,
+ int p2p_persistent_group,
+ char **network,
+ char **bssid);
+
#endif /* WPA_DBUS_CTRL_H */