From 9abafccc0d67aab140898131b7bb45b8b4cef908 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 12 Jun 2011 15:08:19 -0700 Subject: [PATCH] DBus: Add support for P2P primitives Signed-off-by: Johannes Berg --- wpa_supplicant/Makefile | 3 + wpa_supplicant/dbus/dbus_new.c | 1352 ++++++++++++++ wpa_supplicant/dbus/dbus_new.h | 179 ++ wpa_supplicant/dbus/dbus_new_handlers_p2p.c | 1772 +++++++++++++++++++ wpa_supplicant/dbus/dbus_new_handlers_p2p.h | 142 ++ wpa_supplicant/notify.c | 51 + wpa_supplicant/wpa_supplicant_i.h | 1 + 7 files changed, 3500 insertions(+) create mode 100644 wpa_supplicant/dbus/dbus_new_handlers_p2p.c create mode 100644 wpa_supplicant/dbus/dbus_new_handlers_p2p.h diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile index aeb9ab98a..ec2d350be 100644 --- a/wpa_supplicant/Makefile +++ b/wpa_supplicant/Makefile @@ -1140,6 +1140,9 @@ DBUS_OBJS += dbus/dbus_new.o dbus/dbus_new_handlers.o ifdef CONFIG_WPS DBUS_OBJS += dbus/dbus_new_handlers_wps.o endif +ifdef CONFIG_P2P +DBUS_OBJS += dbus/dbus_new_handlers_p2p.o +endif ifndef DBUS_LIBS DBUS_LIBS := $(shell pkg-config --libs dbus-1) endif diff --git a/wpa_supplicant/dbus/dbus_new.c b/wpa_supplicant/dbus/dbus_new.c index 49a0895d1..1340f505e 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,6 +653,636 @@ 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); +} + +#endif /*CONFIG_P2P*/ + /** * wpas_dbus_signal_prop_changed - Signals change of property @@ -1358,6 +1991,152 @@ 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 + } + }, +#endif /* CONFIG_P2P */ { "FlushBSS", WPAS_DBUS_NEW_IFACE_INTERFACE, (WPADBusMethodHandler) &wpas_dbus_handler_flush_bss, { @@ -1444,6 +2223,29 @@ 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 + }, +#endif /* CONFIG_P2P */ { NULL, NULL, NULL, NULL, NULL, 0 } }; @@ -1525,6 +2327,121 @@ 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 + } + }, +#endif /* CONFIG_P2P */ { NULL, NULL, { END_ARGS } } }; @@ -1603,3 +2520,438 @@ 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); +} +#endif /* CONFIG_P2P */ diff --git a/wpa_supplicant/dbus/dbus_new.h b/wpa_supplicant/dbus/dbus_new.h index 377e38117..e8376fe0a 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,21 @@ 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" + +#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 +95,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 +146,48 @@ 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); +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); + #else /* CONFIG_CTRL_IFACE_DBUS_NEW */ static inline int wpas_dbus_register_interface(struct wpa_supplicant *wpa_s) @@ -231,6 +297,119 @@ 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 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) +{ +} #endif /* CONFIG_CTRL_IFACE_DBUS_NEW */ #endif /* CTRL_IFACE_DBUS_H_NEW */ 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 000000000..ec43d0cb0 --- /dev/null +++ b/wpa_supplicant/dbus/dbus_new_handlers_p2p.c @@ -0,0 +1,1772 @@ +/* + * 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 "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); +} + +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 *network_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, "network_object") && + entry.type == DBUS_TYPE_OBJECT_PATH) + network_object_path = os_strdup(entry.str_value); + else + goto inv_args_clear; + + wpa_dbus_dict_entry_clear(&entry); + } + + if (network_object_path != NULL) { + /* + * A Network Object Path is defined meaning we want to re-invoke + * a persisatnt group. + */ + + iface = wpas_dbus_new_decompose_object_path(network_object_path, + &net_id_str, NULL); + if (iface == NULL || + os_strcmp(iface, wpa_s->dbus_new_path) != 0) { + reply = + wpas_dbus_error_invalid_args(message, + network_object_path); + goto out; + } + + group_id = strtoul(net_id_str, NULL, 10); + if (errno == EINVAL) { + reply = wpas_dbus_error_invalid_args( + message, network_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(network_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 *network_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, "network_object") && + (entry.type == DBUS_TYPE_OBJECT_PATH)) { + network_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(network_object_path, + &net_id_str, NULL); + if (iface == NULL || + os_strcmp(iface, wpa_s->dbus_new_path) != 0) { + reply = + wpas_dbus_error_invalid_args(message, + network_object_path); + goto out; + } + + group_id = strtoul(net_id_str, NULL, 10); + if (errno == EINVAL) { + reply = wpas_dbus_error_invalid_args( + message, network_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(network_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; + + 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; + + else if ((os_strcmp(entry.key, "ListenChannel") == 0) && + (entry.type == DBUS_TYPE_UINT32)) + wpa_s->conf->p2p_listen_channel = entry.uint32_value; + + else if ((os_strcmp(entry.key, "OperRegClass") == 0) && + (entry.type == DBUS_TYPE_UINT32)) + wpa_s->conf->p2p_oper_reg_class = entry.uint32_value; + + else if ((os_strcmp(entry.key, "OperChannel") == 0) && + (entry.type == DBUS_TYPE_UINT32)) + wpa_s->conf->p2p_oper_channel = entry.uint32_value; + + 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 + 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_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; +} + + +/* + * 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 000000000..b0c192966 --- /dev/null +++ b/wpa_supplicant/dbus/dbus_new_handlers_p2p.h @@ -0,0 +1,142 @@ + +/* + * 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); + +#endif /* DBUS_NEW_HANDLERS_P2P_H */ diff --git a/wpa_supplicant/notify.c b/wpa_supplicant/notify.c index 14741f647..6d11a3d35 100644 --- a/wpa_supplicant/notify.c +++ b/wpa_supplicant/notify.c @@ -368,12 +368,23 @@ void wpas_notify_resume(struct wpa_global *global) void wpas_notify_p2p_device_found(struct wpa_supplicant *wpa_s, const u8 *dev_addr, int new_device) { + if (new_device) { + /* Create the new peer object */ + wpas_dbus_register_peer(wpa_s, dev_addr); + } + + /* Notify a new peer has been detected*/ + wpas_dbus_signal_peer_device_found(wpa_s, dev_addr); } void wpas_notify_p2p_device_lost(struct wpa_supplicant *wpa_s, const u8 *dev_addr) { + wpas_dbus_unregister_peer(wpa_s, dev_addr); + + /* Create signal on interface object*/ + wpas_dbus_signal_peer_device_lost(wpa_s, dev_addr); } @@ -381,23 +392,29 @@ void wpas_notify_p2p_group_removed(struct wpa_supplicant *wpa_s, const struct wpa_ssid *ssid, const char *role) { + wpas_dbus_unregister_p2p_group(wpa_s, ssid); + + wpas_dbus_signal_p2p_group_removed(wpa_s, role); } void wpas_notify_p2p_go_neg_req(struct wpa_supplicant *wpa_s, const u8 *src, u16 dev_passwd_id) { + wpas_dbus_signal_p2p_go_neg_req(wpa_s, src, dev_passwd_id); } void wpas_notify_p2p_go_neg_completed(struct wpa_supplicant *wpa_s, int status) { + wpas_dbus_signal_p2p_go_neg_resp(wpa_s, status); } void wpas_notify_p2p_invitation_result(struct wpa_supplicant *wpa_s, int status, const u8 *bssid) { + wpas_dbus_signal_p2p_invitation_result(wpa_s, status, bssid); } @@ -406,6 +423,8 @@ void wpas_notify_p2p_sd_request(struct wpa_supplicant *wpa_s, u16 update_indic, const u8 *tlvs, size_t tlvs_len) { + wpas_dbus_signal_p2p_sd_request(wpa_s, freq, sa, dialog_token, + update_indic, tlvs, tlvs_len); } @@ -413,6 +432,8 @@ void wpas_notify_p2p_sd_response(struct wpa_supplicant *wpa_s, const u8 *sa, u16 update_indic, const u8 *tlvs, size_t tlvs_len) { + wpas_dbus_signal_p2p_sd_response(wpa_s, sa, update_indic, + tlvs, tlvs_len); } @@ -435,6 +456,9 @@ void wpas_notify_p2p_provision_discovery(struct wpa_supplicant *wpa_s, u16 config_methods, unsigned int generated_pin) { + wpas_dbus_signal_p2p_provision_discovery(wpa_s, dev_addr, request, + status, config_methods, + generated_pin); } @@ -442,6 +466,10 @@ void wpas_notify_p2p_group_started(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, int network_id, int client) { + /* Notify a group has been started */ + wpas_dbus_register_p2p_group(wpa_s, ssid); + + wpas_dbus_signal_p2p_group_started(wpa_s, ssid, client, network_id); } #endif /* CONFIG_P2P */ @@ -449,12 +477,35 @@ void wpas_notify_p2p_group_started(struct wpa_supplicant *wpa_s, static void wpas_notify_ap_sta_authorized(struct wpa_supplicant *wpa_s, const u8 *sta) { + /* + * Register a group member object corresponding to this peer and + * emit a PeerJoined signal. This will check if it really is a + * P2P group. + */ + wpas_dbus_register_p2p_groupmember(wpa_s, sta); + + /* + * Create 'peer-joined' signal on group object -- will also + * check P2P itself. + */ + wpas_dbus_signal_p2p_peer_joined(wpa_s, sta); } static void wpas_notify_ap_sta_deauthorized(struct wpa_supplicant *wpa_s, const u8 *sta) { + /* + * Unregister a group member object corresponding to this peer + * if this is a P2P group. + */ + wpas_dbus_unregister_p2p_groupmember(wpa_s, sta); + + /* + * Create 'peer-disconnected' signal on group object if this + * is a P2P group. + */ + wpas_dbus_signal_p2p_peer_disconnected(wpa_s, sta); } diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h index b18d6d9a3..281c5f671 100644 --- a/wpa_supplicant/wpa_supplicant_i.h +++ b/wpa_supplicant/wpa_supplicant_i.h @@ -342,6 +342,7 @@ struct wpa_supplicant { #endif /* CONFIG_CTRL_IFACE_DBUS */ #ifdef CONFIG_CTRL_IFACE_DBUS_NEW char *dbus_new_path; + char *dbus_groupobj_path; #endif /* CONFIG_CTRL_IFACE_DBUS_NEW */ char bridge_ifname[16];