diff options
author | Jouni Malinen <jouni@qca.qualcomm.com> | 2011-06-27 15:19:46 -0700 |
---|---|---|
committer | Dmitry Shmidt <dimitrysh@google.com> | 2011-06-27 15:20:55 -0700 |
commit | 75ecf5267604f166b85a7ee2cf0d9cb682966680 (patch) | |
tree | 0056e7ebf5af72a85abe6c0868de6ffc2f08eaae /wpa_supplicant/dbus | |
parent | e61a2d6db6113da5fad91660764afdb0596dbc46 (diff) | |
download | external_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.c | 219 | ||||
-rw-r--r-- | wpa_supplicant/dbus/dbus_dict_helpers.h | 43 | ||||
-rw-r--r-- | wpa_supplicant/dbus/dbus_new.c | 1694 | ||||
-rw-r--r-- | wpa_supplicant/dbus/dbus_new.h | 212 | ||||
-rw-r--r-- | wpa_supplicant/dbus/dbus_new_handlers.c | 119 | ||||
-rw-r--r-- | wpa_supplicant/dbus/dbus_new_handlers.h | 5 | ||||
-rw-r--r-- | wpa_supplicant/dbus/dbus_new_handlers_p2p.c | 2113 | ||||
-rw-r--r-- | wpa_supplicant/dbus/dbus_new_handlers_p2p.h | 162 | ||||
-rw-r--r-- | wpa_supplicant/dbus/dbus_new_helpers.c | 71 | ||||
-rw-r--r-- | wpa_supplicant/dbus/dbus_new_helpers.h | 5 |
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 */ |