[PATCH] Connman : Initial P2P Invite and P2P Scan Implementation

Shailesh Rathod/LGSI Connectivity Team <[email protected]> Mon, 7 Jul 2025 07:13:13 +0000
Newsgroups dev.linux.lists.connman
Message-ID <SE1P216MB2647D406E36999304E431A80F04FA@SE1P216MB2647.KORP216.PROD.OUTLOOK.COM>
From b8ffe29f0969da98ab09de8bf9592a8777d84e5f Mon Sep 17 00:00:00 2001
From: shailesh <[email protected]>
Date: Tue, 24 Jun 2025 13:41:08 +0000
Subject: [PATCH] Initial P2P Invite and P2P Scan Implementation

- Added support for P2P Invite operation, including new structures and callbacks in gsupplicant.
- Implemented DBus methods and callbacks for handling P2P invitation results and received invitations.
- Extended device, peer, and technology interfaces to support P2P scan and invitation flows.
- Added new driver hooks and logic in wifi plugin for P2P scanning and invitation handling.
---
 gsupplicant/gsupplicant.h |  37 ++++
 gsupplicant/supplicant.c  | 425 +++++++++++++++++++++++++++++++++++++-
 include/device.h          |   2 +
 include/peer.h            |   3 +
 include/technology.h      |   2 +
 plugins/wifi.c            | 160 +++++++++++++-
 src/connman.h             |   2 +-
 src/device.c              |  43 +++-
 src/group.c               |  36 +++-
 src/peer.c                |  36 ++--
 src/technology.c          |  26 ++-
 11 files changed, 739 insertions(+), 33 deletions(-)

diff --git a/gsupplicant/gsupplicant.h b/gsupplicant/gsupplicant.h
index 26d5f73..eecad9c 100644
--- a/gsupplicant/gsupplicant.h
+++ b/gsupplicant/gsupplicant.h
@@ -220,6 +220,37 @@ struct _GSupplicantP2PGroupAddParams {
 
 typedef struct _GSupplicantP2PGroupAddParams GSupplicantP2PGroupAddParams;
 
+/**
+ * Parameters for a P2P Invite operation.
+ *
+ * peer:              The MAC address of the peer device to invite.
+ * persistent_group:  The identifier for the persistent group to be used for the invitation.
+ * frequency:         The frequency (in MHz) on which to perform the invitation.
+ */
+struct _GSupplicantP2PInviteParams {
+    const char *peer;
+    const char *persistent_group;
+    int frequency;
+};
+
+typedef struct _GSupplicantP2PInviteParams GSupplicantP2PInviteParams;
+
+typedef enum
+{
+   G_SUPPLICANT_P2P_FIND_START_WITH_FULL,
+   G_SUPPLICANT_P2P_FIND_ONLY_SOCIAL,
+   G_SUPPLICANT_P2P_FIND_PROGRESSIVE
+} GSupplicantP2PFindType;
+
+struct _GSupplicantP2PFindParams {
+   int timeout;
+   int disc_type;
+   const char** seek_array;
+   int frequency;
+};
+
+typedef struct _GSupplicantP2PFindParams GSupplicantP2PFindParams;
+
 /* global API */
 typedef void (*GSupplicantCountryCallback) (int result,
                        const char *alpha2,
@@ -295,6 +326,10 @@ int g_supplicant_interface_p2p_add_service(GSupplicantInterface *interface,
 int g_supplicant_interface_p2p_del_service(GSupplicantInterface *interface,
                GSupplicantP2PServiceParams *p2p_service_params);
 
+int g_supplicant_interface_p2p_invite(GSupplicantInterface *interface,
+               GSupplicantP2PInviteParams *invite_data,
+               GSupplicantInterfaceCallback callback, void *user_data);
+
 /* Flushes all P2P peer information and cached data from the given interface. */
 int g_supplicant_interface_p2p_flush(GSupplicantInterface *interface,
                GSupplicantInterfaceCallback callback, void *user_data);
@@ -452,6 +487,8 @@ struct _GSupplicantCallbacks {
                int reasoncode);
    void (*p2p_group_started)(GSupplicantGroup *group);
    void (*p2p_group_finished)(GSupplicantInterface *interface);
+   void (*p2p_invitation_result)(GSupplicantInterface *interface, int status);
+   void (*p2p_invitation_received) (GSupplicantInterface *interface, GSupplicantPeer *p2p_network, const char *go_dev_addr, bool persistent);
 };
 
 typedef struct _GSupplicantCallbacks GSupplicantCallbacks;
diff --git a/gsupplicant/supplicant.c b/gsupplicant/supplicant.c
index 36159e6..6fd7384 100644
--- a/gsupplicant/supplicant.c
+++ b/gsupplicant/supplicant.c
@@ -146,6 +146,8 @@ static GHashTable *peer_mapping;
 static GHashTable *group_mapping;
 static GHashTable *pending_peer_connection;
 static GHashTable *config_file_table;
+static GHashTable *p2p_peer_table;
+
 
 struct _GSupplicantWpsCredentials {
    unsigned char ssid[32];
@@ -302,6 +304,13 @@ struct interface_connect_data {
    };
 };
 
+struct interface_p2p_invite_data {
+   GSupplicantInterface *interface;
+   GSupplicantInterfaceCallback callback;
+   GSupplicantP2PInviteParams *p2p_invite_params;
+   void *user_data;
+};
+
 struct interface_scan_data {
    GSupplicantInterface *interface;
    char *path;
@@ -310,6 +319,15 @@ struct interface_scan_data {
    void *user_data;
 };
 
+struct g_supplicant_p2p_inv_recv_info {
+   GSupplicantInterface *interface;
+   const char *p2p_go_dev_addr;
+   const char *src_addr;
+   bool persistent;
+};
+
+static int inv_recv_ref = -1;
+
 static int network_remove(struct interface_data *data);
 
 void __connman_util_byte_to_string(unsigned char *src, char *dest, int len);
@@ -960,6 +978,9 @@ static void remove_peer(gpointer data)
    if (pending_peer_connection)
        g_hash_table_remove(pending_peer_connection, peer->path);
 
+   if (p2p_peer_table)
+       g_hash_table_remove(p2p_peer_table, peer->path);
+
    g_free(peer->path);
    g_free(peer->name);
    g_free(peer->identifier);
@@ -1606,6 +1627,84 @@ bool g_supplicant_peer_is_client(GSupplicantPeer *peer)
    return false;
 }
 
+static void interface_p2p_invite_params(DBusMessageIter *iter, void *user_data)
+{
+   DBusMessageIter dict;
+   struct interface_p2p_invite_data *data = user_data;
+
+   SUPPLICANT_DBG("");
+
+   supplicant_dbus_dict_open(iter, &dict);
+
+   if (data && data->p2p_invite_params) {
+       GSupplicantP2PInviteParams* params = data->p2p_invite_params;
+
+       supplicant_dbus_dict_append_basic(&dict, "peer",
+                   DBUS_TYPE_OBJECT_PATH, &params->peer);
+   }
+
+   supplicant_dbus_dict_close(iter, &dict);
+}
+
+static void interface_p2p_invite_result(const char *error,
+               DBusMessageIter *iter, void *user_data)
+{
+   struct interface_p2p_invite_data *data = user_data;
+   int err = 0;
+
+   SUPPLICANT_DBG("");
+
+   if (error) {
+       SUPPLICANT_DBG("error %s", error);
+       err = -EIO;
+   }
+
+   if (data->callback)
+       data->callback(err, data->interface, data->user_data);
+
+   dbus_free(data);
+}
+
+int g_supplicant_interface_p2p_invite(GSupplicantInterface *interface,
+               GSupplicantP2PInviteParams *invite_data,
+               GSupplicantInterfaceCallback callback, void *user_data)
+{
+   struct interface_p2p_invite_data *data;
+   int ret;
+
+   SUPPLICANT_DBG("");
+
+   if (!interface)
+       return -EINVAL;
+
+   if (!interface->p2p_support)
+       return -ENOTSUP;
+
+   data = dbus_malloc0(sizeof(*data));
+   if (!data)
+       return -ENOMEM;
+
+   data->user_data = user_data;
+   data->interface = interface;
+   data->callback = callback;
+   data->p2p_invite_params = invite_data;
+
+   SUPPLICANT_DBG("interface->path : %s\n", interface->path);
+
+   ret = supplicant_dbus_method_call(interface->path,
+                   SUPPLICANT_INTERFACE ".Interface.P2PDevice",
+                   "Invite",
+                   interface_p2p_invite_params,
+                   interface_p2p_invite_result, data, interface);
+
+   if (ret < 0) {
+       dbus_free(data);
+       return ret;
+   }
+
+   return -EINPROGRESS;
+}
+
 bool g_supplicant_peer_has_requested_connection(GSupplicantPeer *peer)
 {
    if (!peer)
@@ -2837,6 +2936,7 @@ static void signal_name_owner_changed(const char *path, DBusMessageIter *iter)
        g_hash_table_remove_all(group_mapping);
        g_hash_table_remove_all(config_file_table);
        g_hash_table_remove_all(interface_table);
+       g_hash_table_remove_all(p2p_peer_table);
        callback_system_killed();
    }
 
@@ -3295,6 +3395,8 @@ static void peer_property(const char *key, DBusMessageIter *iter,
        return;
 
    if (!key) {
+       if (g_hash_table_lookup(p2p_peer_table, peer->path) == NULL)
+           return;
        if (peer->name) {
            create_peer_identifier(peer);
            callback_peer_found(peer);
@@ -3377,6 +3479,7 @@ static void peer_property(const char *key, DBusMessageIter *iter,
 
 static void signal_peer_found(const char *path, DBusMessageIter *iter)
 {
+
    struct peer_property_data *property_data;
    GSupplicantInterface *interface;
    const char *obj_path = NULL;
@@ -3404,6 +3507,7 @@ static void signal_peer_found(const char *path, DBusMessageIter *iter)
    peer->path = g_strdup(obj_path);
    g_hash_table_insert(interface->peer_table, peer->path, peer);
    g_hash_table_replace(peer_mapping, peer->path, interface);
+   g_hash_table_replace(p2p_peer_table, g_strdup(peer->path), peer);
 
    property_data = dbus_malloc0(sizeof(struct peer_property_data));
    property_data->peer = peer;
@@ -3889,6 +3993,282 @@ static void signal_group_request(const char *path, DBusMessageIter *iter)
        g_hash_table_replace(pending_peer_connection, peer->path, peer);
 }
 
+static void callback_p2p_invitation_result(GSupplicantInterface *interface, int status)
+{
+   if (!callbacks_pointer)
+       return;
+
+   if (!callbacks_pointer->p2p_invitation_result)
+       return;
+
+   callbacks_pointer->p2p_invitation_result(interface, status);
+}
+
+static void interface_p2p_invitation_result(DBusMessageIter *iter, void *user_data)
+{
+   GSupplicantInterface *interface = user_data;
+   DBusMessageIter dict, entry, value;
+   char *key;
+   int status = 0;
+
+   SUPPLICANT_DBG("interface_p2p_invitation_result");
+
+   if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY) {
+       SUPPLICANT_DBG("not array\n");
+       return;
+   }
+
+   dbus_message_iter_recurse(iter, &dict);
+   if(dbus_message_iter_get_arg_type(&dict) != DBUS_TYPE_DICT_ENTRY) {
+       SUPPLICANT_DBG("not dict\n");
+       return;
+   }
+
+   dbus_message_iter_recurse(&dict, &entry);
+   if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING) {
+       SUPPLICANT_DBG("not string\n");
+       return;
+   }
+
+   dbus_message_iter_get_basic(&entry, &key);
+   SUPPLICANT_DBG("key : %s\n", key);
+   if(!g_str_equal(key, "status")) {
+       SUPPLICANT_DBG("not status\n");
+       return;
+   }
+
+   dbus_message_iter_next(&entry);
+   if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_VARIANT) {
+       SUPPLICANT_DBG("not variant\n");
+       return;
+   }
+
+   dbus_message_iter_recurse(&entry, &value);
+   dbus_message_iter_get_basic(&value, &status);
+   SUPPLICANT_DBG("status : %d\n", status);
+
+   callback_p2p_invitation_result(interface, status);
+}
+
+static void signal_invitation_result(const char *path, DBusMessageIter *iter)
+{
+   GSupplicantInterface *interface;
+
+   SUPPLICANT_DBG("signal invitation result");
+
+   interface = g_hash_table_lookup(interface_table, path);
+   if (!interface)
+       return;
+
+   interface_p2p_invitation_result(iter, interface);
+}
+
+static void callback_p2p_invitation_received(GSupplicantInterface *interface, GSupplicantPeer *peer, const char *go_dev_addr, bool persistent)
+{
+   if (!callbacks_pointer)
+       return;
+
+   if (!callbacks_pointer->p2p_invitation_received)
+       return;
+
+   callbacks_pointer->p2p_invitation_received(interface, peer, go_dev_addr, persistent);
+}
+
+static gboolean check_inv_src_network(gpointer argv)
+{
+   struct g_supplicant_p2p_inv_recv_info *inv_recv = argv;
+   GSupplicantInterface *interface = inv_recv->interface;
+
+   GSupplicantPeer *peer = g_supplicant_interface_peer_lookup(interface, inv_recv->src_addr);
+
+   if(!peer) {
+       inv_recv_ref = g_timeout_add(200, check_inv_src_network, inv_recv);
+       return FALSE;
+   }
+
+   callback_p2p_invitation_received(interface, peer, inv_recv->p2p_go_dev_addr, inv_recv->persistent);
+
+   g_free(inv_recv);
+   inv_recv_ref = -1;
+   return FALSE;
+}
+
+static void interface_p2p_invitation_received(DBusMessageIter *iter, void *user_data)
+{
+   GSupplicantInterface *interface = user_data;
+   DBusMessageIter dict, entry, value, array;
+   char *key;
+   int status;
+   int addr_len = 6;
+   unsigned char *bssid, *go_dev_addr, *src_addr;
+   char go_dev_addr_str[13], src_addr_str[13];
+   char *p_go_dev_addr, *p_src_addr;
+
+   SUPPLICANT_DBG("interface_p2p_invitation_received");
+
+   if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY) {
+       SUPPLICANT_DBG("not array\n");
+       return;
+   }
+
+   dbus_message_iter_recurse(iter, &dict);
+   if(dbus_message_iter_get_arg_type(&dict) != DBUS_TYPE_DICT_ENTRY) {
+       SUPPLICANT_DBG("not dict\n");
+       return;
+   }
+
+   dbus_message_iter_recurse(&dict, &entry);
+   if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING) {
+       SUPPLICANT_DBG("not string\n");
+       return;
+   }
+
+   dbus_message_iter_get_basic(&entry, &key);
+   SUPPLICANT_DBG("key : %s\n", key);
+   if(!g_str_equal(key, "status")) {
+       SUPPLICANT_DBG("not status\n");
+       return;
+   }
+
+   dbus_message_iter_next(&entry);
+   if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_VARIANT) {
+       SUPPLICANT_DBG("not variant\n");
+       return;
+   }
+
+   dbus_message_iter_recurse(&entry, &value);
+   dbus_message_iter_get_basic(&value, &status);
+   SUPPLICANT_DBG("status : %d\n", status);
+
+   if(status == 0) //Persistent group reinvoke case
+       g_supplicant_interface_p2p_listen(interface, 0, 0);
+
+   else if(status != 1)
+       return;
+
+   dbus_message_iter_next(&dict);
+
+   dbus_message_iter_recurse(&dict, &entry);
+   if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING) {
+       SUPPLICANT_DBG("not string\n");
+       return;
+   }
+
+   dbus_message_iter_get_basic(&entry, &key);
+   SUPPLICANT_DBG("key : %s\n", key);
+   if(!g_str_equal(key, "sa")) {
+       SUPPLICANT_DBG("not sa\n");
+       return;
+   }
+
+   dbus_message_iter_next(&entry);
+   if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_VARIANT) {
+       SUPPLICANT_DBG("not variant\n");
+       return;
+   }
+
+   dbus_message_iter_recurse(&entry, &value);
+   dbus_message_iter_recurse(&value, &array);
+
+   dbus_message_iter_get_fixed_array(&array, &src_addr, &addr_len);
+
+   dbus_message_iter_next(&dict);
+
+   dbus_message_iter_recurse(&dict, &entry);
+   if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING) {
+       SUPPLICANT_DBG("not string\n");
+       return;
+   }
+
+   dbus_message_iter_get_basic(&entry, &key);
+   SUPPLICANT_DBG("key : %s\n", key);
+
+   if(!g_str_equal(key, "go_dev_addr")) {
+       SUPPLICANT_DBG("not go_dev_addr\n");
+       return;
+   }
+
+   dbus_message_iter_next(&entry);
+   if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_VARIANT) {
+       SUPPLICANT_DBG("not variant\n");
+       return;
+   }
+
+   dbus_message_iter_recurse(&entry, &value);
+   dbus_message_iter_recurse(&value, &array);
+
+   dbus_message_iter_get_fixed_array(&array, &go_dev_addr, &addr_len);
+
+   dbus_message_iter_next(&dict);
+
+   dbus_message_iter_recurse(&dict, &entry);
+   if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING) {
+       SUPPLICANT_DBG("not string\n");
+       return;
+   }
+
+   dbus_message_iter_get_basic(&entry, &key);
+   SUPPLICANT_DBG("key : %s\n", key);
+   if(!g_str_equal(key, "bssid")) {
+       if(status == 0)
+           goto go_next; //BSSID is not exist at persistent go case
+       SUPPLICANT_DBG("not bssid\n");
+       return;
+   }
+
+   dbus_message_iter_next(&entry);
+   if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_VARIANT) {
+       SUPPLICANT_DBG("not variant\n");
+       return;
+   }
+
+   dbus_message_iter_recurse(&entry, &value);
+   dbus_message_iter_recurse(&value, &array);
+
+   dbus_message_iter_get_fixed_array(&array, &bssid, &addr_len);
+
+go_next:
+
+   __connman_util_byte_to_string(go_dev_addr, go_dev_addr_str, 6);
+   p_go_dev_addr = g_strdup(go_dev_addr_str);
+
+   __connman_util_byte_to_string(src_addr, src_addr_str, 6);
+   p_src_addr = g_strdup(src_addr_str);
+
+   if (inv_recv_ref != -1) {
+       g_free(p_src_addr);
+       g_free(p_go_dev_addr);
+       return;
+   }
+
+   struct g_supplicant_p2p_inv_recv_info *inv_recv = g_try_new0(struct g_supplicant_p2p_inv_recv_info, 1);
+   if (!inv_recv) {
+       g_free(p_src_addr);
+       g_free(p_go_dev_addr);
+       return;
+   }
+
+   inv_recv->interface = interface;
+   inv_recv->p2p_go_dev_addr = p_go_dev_addr;
+   inv_recv->src_addr = p_src_addr;
+   inv_recv->persistent = !status;
+   inv_recv_ref = g_timeout_add(500, check_inv_src_network, inv_recv);
+   return;
+}
+
+static void signal_invitation_received(const char *path, DBusMessageIter *iter)
+{
+   GSupplicantInterface *interface;
+
+   SUPPLICANT_DBG("signal invitation received");
+
+   interface = g_hash_table_lookup(interface_table, path);
+   if (!interface)
+       return;
+
+   interface_p2p_invitation_received(iter, interface);
+}
+
 static void signal_group_peer_joined(const char *path, DBusMessageIter *iter)
 {
    const char *peer_path = NULL;
@@ -3997,6 +4377,10 @@ static struct {
    { SUPPLICANT_INTERFACE ".Interface.P2PDevice", "GroupFinished", signal_group_finished },
    { SUPPLICANT_INTERFACE ".Interface.P2PDevice", "GONegotiationRequest", signal_group_request },
 
+   { SUPPLICANT_INTERFACE ".Interface.P2PDevice", "InvitationResult", signal_invitation_result },
+   { SUPPLICANT_INTERFACE ".Interface.P2PDevice", "InvitationReceived", signal_invitation_received },
+
+
    { SUPPLICANT_INTERFACE ".Group", "PeerJoined", signal_group_peer_joined },
    { SUPPLICANT_INTERFACE ".Group", "PeerDisconnected", signal_group_peer_disconnected },
 
@@ -5759,27 +6143,38 @@ int g_supplicant_interface_disconnect(GSupplicantInterface *interface,
    return ret;
 }
 
+struct interface_p2p_find_data {
+   GSupplicantInterface *interface;
+   char *path;
+   GSupplicantInterfaceCallback callback;
+   GSupplicantP2PFindParams *p2p_find_params;
+   void *user_data;
+};
+
 static void interface_p2p_find_result(const char *error,
                    DBusMessageIter *iter, void *user_data)
 {
-   struct interface_scan_data *data = user_data;
+   struct interface_p2p_find_data *data = user_data;
    int err = 0;
 
-   SUPPLICANT_DBG("error %s", error);
-
-   if (error)
+   if (error != NULL) {
+       SUPPLICANT_DBG("error %s", error);
        err = -EIO;
-
+   }
    if (interface_exists(data->interface, data->path)) {
        if (!data->interface->ready)
            err = -ENOLINK;
-       if (!err)
+       if (!err) {
            data->interface->p2p_finding = true;
+       }
    }
 
-   if (data->callback)
+   if (data->callback != NULL)
        data->callback(err, data->interface, data->user_data);
 
+   if (data->p2p_find_params)
+       g_free(data->p2p_find_params);
+
    g_free(data->path);
    dbus_free(data);
 }
@@ -5787,6 +6182,10 @@ static void interface_p2p_find_result(const char *error,
 static void interface_p2p_find_params(DBusMessageIter *iter, void *user_data)
 {
    DBusMessageIter dict;
+   struct interface_p2p_find_data *data = user_data;
+   int timeout = 0;
+   char *disc_type = "start_with_full";
+   int freq = 0;
 
    supplicant_dbus_dict_open(iter, &dict);
    supplicant_dbus_dict_close(iter, &dict);
@@ -6706,6 +7105,8 @@ int g_supplicant_register(const GSupplicantCallbacks *callbacks)
                                NULL, NULL);
    config_file_table = g_hash_table_new_full(g_str_hash, g_str_equal,
                                g_free, g_free);
+   p2p_peer_table = g_hash_table_new_full(g_str_hash, g_str_equal,
+                               g_free, NULL);
 
    supplicant_dbus_setup(connection);
 
@@ -6801,6 +7202,16 @@ void g_supplicant_unregister(const GSupplicantCallbacks *callbacks)
        interface_table = NULL;
    }
 
+   if (p2p_peer_table != NULL){
+       g_hash_table_destroy(p2p_peer_table);
+       p2p_peer_table = NULL;
+   }
+
+   if (p2p_peer_table != NULL){
+       g_hash_table_destroy(p2p_peer_table);
+       p2p_peer_table = NULL;
+   }
+
    if (system_available)
        callback_system_killed();
 
diff --git a/include/device.h b/include/device.h
index 0fc06bd..2a2cc77 100644
--- a/include/device.h
+++ b/include/device.h
@@ -137,6 +137,8 @@ struct connman_device_driver {
            struct connman_device *device);
    int (*set_regdom) (struct connman_device *device,
                        const char *alpha2);
+   int (*scan_p2p)(enum connman_service_type type,
+           struct connman_device *device);
 };
 
 int connman_device_driver_register(struct connman_device_driver *driver);
diff --git a/include/peer.h b/include/peer.h
index 6fe5e64..f6be3cb 100644
--- a/include/peer.h
+++ b/include/peer.h
@@ -112,6 +112,9 @@ void connman_peer_driver_unregister(struct connman_peer_driver *driver);
 struct connman_peer *connman_peer_get_by_path(const char *path);
 void __connman_peer_get_properties_struct(DBusMessageIter *iter, gpointer user_data);
 
+struct connman_peer *connman_peer_get_by_path(const char *path);
+const char *connman_peer_get_identifier(struct connman_peer *peer);
+
 bool connman_peer_service_is_master(void);
 
 #ifdef __cplusplus
diff --git a/include/technology.h b/include/technology.h
index 391b446..965ad49 100644
--- a/include/technology.h
+++ b/include/technology.h
@@ -75,6 +75,8 @@ int connman_technology_driver_register(struct connman_technology_driver *driver)
 void connman_technology_driver_unregister(struct connman_technology_driver *driver);
 void connman_technology_set_p2p_listen(struct connman_technology *technology,bool enabled);
 bool connman_technology_get_p2p_listen(struct connman_technology *technology);
+void __connman_technology_p2p_invitation_result(struct connman_technology *technology,
+                           int status);
 #ifdef __cplusplus
 }
 #endif
diff --git a/plugins/wifi.c b/plugins/wifi.c
index 9fa22dd..c6629f1 100644
--- a/plugins/wifi.c
+++ b/plugins/wifi.c
@@ -61,6 +61,8 @@
 
 #include "src/shared/util.h"
 
+#include "src/connman.h"
+
 #define CLEANUP_TIMEOUT   8    /* in seconds */
 #define INACTIVE_TIMEOUT  12   /* in seconds */
 #define FAVORITE_MAXIMUM_RETRIES 2
@@ -85,6 +87,10 @@ static int p2p_group_ifindex = -1;
 
 static char *p2p_go_identifier = NULL;
 
+static guint p2p_scan_ref = 0;
+
+static int p2p_find_ref = -1;
+
 #define ASSOC_STATUS_AUTH_TIMEOUT 16
 #define ASSOC_STATUS_NO_CLIENT 17
 #define LOAD_SHAPING_MAX_RETRIES 3
@@ -177,6 +183,7 @@ struct wifi_data {
    int servicing;
    int disconnect_code;
    int assoc_code;
+   const char *invited_path;
 };
 
 struct wifi_network {
@@ -1048,6 +1055,12 @@ static void wifi_remove(struct connman_device *device)
    if (wifi->scan_params)
        g_supplicant_free_scan_params(wifi->scan_params);
 
+   if (p2p_scan_ref) {
+       g_source_remove(p2p_scan_ref);
+       p2p_scan_ref = 0;
+   }
+
+
    g_free(wifi->autoscan);
    g_free(wifi->identifier);
    g_free(wifi);
@@ -1945,6 +1958,22 @@ static gboolean p2p_find_stop(gpointer data)
    return FALSE;
 }
 
+static gboolean p2p_find_complete(gpointer argv)
+{
+   struct connman_device *device = argv;
+   struct wifi_data *wifi = connman_device_get_data(device);
+   int ret = 0;
+
+   if(!wifi) {
+       p2p_find_ref = -1;
+       return FALSE;
+   }
+
+   p2p_find_ref = -1;
+
+   return FALSE;
+}
+
 static void p2p_find_callback(int result, GSupplicantInterface *interface,
                            void *user_data)
 {
@@ -1969,6 +1998,8 @@ static void p2p_find_callback(int result, GSupplicantInterface *interface,
    if (!wifi->p2p_find_timeout)
        goto error;
 
+   p2p_find_ref = -1;
+
    return;
 error:
    p2p_find_stop(device);
@@ -1994,12 +2025,16 @@ static int p2p_find(struct connman_device *device)
 
    ret = g_supplicant_interface_p2p_find(wifi->interface,
                        p2p_find_callback, device);
+
+   DBG("p2p_find returned %d", ret);
+
    if (ret) {
        connman_device_unref(device);
        start_autoscan(device);
    } else {
        connman_device_set_scanning(device,
                CONNMAN_SERVICE_TYPE_P2P, true);
+       p2p_find_ref = g_timeout_add_seconds(wifi->p2p_find_timeout, p2p_find_complete, device);
    }
 
    return ret;
@@ -2184,6 +2219,41 @@ static int wifi_set_regdom(struct connman_device *device, const char *alpha2)
    return ret;
 }
 
+static gboolean check_wifi_device_connecting(gpointer argv)
+{
+   struct connman_device *device = argv;
+
+   bool connecting = false;
+   bool wifi_total = false;
+   p2p_scan_ref = 0;
+
+   p2p_find(device);
+   return FALSE;
+}
+
+
+static int wifi_scan_p2p(enum connman_service_type type,
+           struct connman_device *device)
+{
+   int ret;
+
+   connman_info("wifi_scan_p2p");
+
+   if (!p2p_technology)
+       return -ENOTSUP;
+
+
+
+   if (p2p_scan_ref) {
+       connman_warn("wifi_scan_p2p p2p_scan_ref=%u", p2p_scan_ref);
+       return -EALREADY;
+   }
+
+   p2p_scan_ref = g_timeout_add_full(G_PRIORITY_DEFAULT, 2000, check_wifi_device_connecting, device, NULL);
+
+   return 0;
+}
+
 static struct connman_device_driver wifi_ng_driver = {
    .name       = "wifi",
    .type       = CONNMAN_DEVICE_TYPE_WIFI,
@@ -2193,10 +2263,16 @@ static struct connman_device_driver wifi_ng_driver = {
    .enable     = wifi_enable,
    .disable    = wifi_disable,
    .scan       = wifi_scan,
+   .scan_p2p   = wifi_scan_p2p,
    .stop_scan  = wifi_stop_scan,
    .set_regdom = wifi_set_regdom,
 };
 
+
+
+
+
+
 static void system_ready(void)
 {
    DBG("");
@@ -3215,6 +3291,82 @@ static void network_associated(GSupplicantNetwork *network)
    interface_state(interface);
 }
 
+static void p2p_invitation_result(GSupplicantInterface *interface, int status)
+{
+   struct wifi_data *wifi;
+
+   wifi = g_supplicant_interface_get_data(interface);
+
+   if (!wifi)
+       return;
+
+   DBG("status %i", status);
+
+   __connman_technology_p2p_invitation_result(p2p_technology, status);
+}
+
+static void p2p_invitation_received(GSupplicantInterface *interface,
+               GSupplicantPeer *peer, const char *go_dev_addr, bool persistent)
+{
+   struct wifi_data *wifi = g_supplicant_interface_get_data(interface);
+   struct connman_peer *connman_peer;
+   const char *identifier, *path;
+   const char *go_dev_addr_colon;
+
+   if (!wifi || !wifi->device)
+       return;
+
+   identifier = g_supplicant_peer_get_identifier(peer);
+
+   DBG("ident: %s", identifier);
+
+   connman_peer = connman_peer_get(wifi->device, identifier);
+   if (!connman_peer)
+       return;
+
+   go_dev_addr_colon = __connman_util_insert_colon_to_mac_addr(go_dev_addr);
+   path = __connman_peer_get_path(connman_peer);
+
+   if (!path) {
+       g_free(go_dev_addr_colon);
+       return;
+   }
+
+   if (!persistent) {
+       connman_peer_set_state(connman_peer, CONNMAN_PEER_STATE_IDLE);
+
+       /* Invitation received from GO */
+       if (g_str_equal(identifier, go_dev_addr)) {
+           wifi->invited_path = __connman_peer_get_path(connman_peer);
+       /* Sometimes there is only src address in InvitationReceived signal without GO device address */
+       } else if (g_str_equal(go_dev_addr, "000000000000")) {
+           wifi->invited_path = __connman_peer_get_path(connman_peer);
+           g_free(go_dev_addr_colon);
+           go_dev_addr_colon = __connman_util_insert_colon_to_mac_addr(identifier);
+       } else {
+           struct connman_network *network_go = connman_device_get_network(wifi->device, go_dev_addr);
+
+           if (network_go) {
+               struct connman_service *service_go;
+
+               wifi->invited_path = connman_network_get_string(network_go, "Path");
+           }
+       }
+
+       connman_dbus_property_changed_basic(path, CONNMAN_PEER_INTERFACE,
+               "P2PInvitationReceived", DBUS_TYPE_STRING, &go_dev_addr_colon);
+
+   } else {
+       p2p_find_stop(wifi->device);
+       if (connman_technology_get_p2p_listen(wifi_technology)) //already changed to listen off
+           connman_technology_set_p2p_listen(wifi_technology, false);
+
+       connman_dbus_property_changed_basic(path, CONNMAN_PEER_INTERFACE,
+               "P2PPersistentReceived", DBUS_TYPE_STRING, &go_dev_addr_colon);
+   }
+}
+
+
 static void sta_authorized(GSupplicantInterface *interface,
                    const char *addr)
 {
@@ -3263,11 +3415,15 @@ static void peer_found(GSupplicantPeer *peer)
    GSupplicantInterface *iface = g_supplicant_peer_get_interface(peer);
    struct wifi_data *wifi = g_supplicant_interface_get_data(iface);
    struct connman_peer *connman_peer;
-   const char *identifier, *name;
+   const char *identifier, *name,*path;
    int ret;
 
    identifier = g_supplicant_peer_get_identifier(peer);
    name = g_supplicant_peer_get_name(peer);
+   path = g_supplicant_peer_get_path(peer);
+
+   DBG("peer_found - ident: %s", identifier);
+
 
    DBG("ident: %s", identifier);
 
@@ -3546,6 +3702,8 @@ static const GSupplicantCallbacks callbacks = {
    .assoc_status_code      = assoc_status_code,
    .p2p_group_started  = p2p_group_started,
    .p2p_group_finished = p2p_group_finished,
+   .p2p_invitation_result = p2p_invitation_result,
+   .p2p_invitation_received = p2p_invitation_received,
 };
 
 static int tech_probe(struct connman_technology *technology)
diff --git a/src/connman.h b/src/connman.h
index 034a990..d9adc48 100644
--- a/src/connman.h
+++ b/src/connman.h
@@ -627,7 +627,7 @@ void __connman_device_list(DBusMessageIter *iter, void *user_data);
 enum connman_service_type __connman_device_get_service_type(struct connman_device *device);
 struct connman_device *__connman_device_find_device(enum connman_service_type type);
 int __connman_device_request_scan(enum connman_service_type type);
-int __connman_device_request_scan_full(enum connman_service_type type);
+int __connman_device_request_scan_full(enum connman_service_type type,bool priority);
 int __connman_device_request_hidden_scan(struct connman_device *device,
                const char *ssid, unsigned int ssid_len,
                const char *identity, const char *passphrase,
diff --git a/src/device.c b/src/device.c
index 5567009..3ab5268 100644
--- a/src/device.c
+++ b/src/device.c
@@ -174,6 +174,8 @@ static bool device_has_service_type(struct connman_device *device,
    return service_type == device_service_type;
 }
 
+
+
 static gboolean device_pending_reset(gpointer user_data)
 {
    struct connman_device *device = user_data;
@@ -642,7 +644,7 @@ bool connman_device_get_powered(struct connman_device *device)
 
 static int device_scan(enum connman_service_type type,
                struct connman_device *device,
-               bool force_full_scan)
+               bool priority)
 {
    struct connman_device_scan_params params;
 
@@ -654,9 +656,11 @@ static int device_scan(enum connman_service_type type,
 
    memset(&params, 0, sizeof(params));
    params.type = type;
-   params.force_full_scan = force_full_scan;
-
-   return device->driver->scan(device, &params);
+   params.force_full_scan = priority;
+   if(priority)
+       return device->driver->scan_p2p(type, device);
+   else
+       return device->driver->scan(device, &params);
 }
 
 int __connman_device_disconnect(struct connman_device *device)
@@ -1102,7 +1106,7 @@ void connman_device_regdom_notify(struct connman_device *device,
 }
 
 static int connman_device_request_scan(enum connman_service_type type,
-                   bool force_full_scan)
+                   bool priority)
 {
    bool success = false;
    int last_err = -ENOSYS;
@@ -1130,7 +1134,7 @@ static int connman_device_request_scan(enum connman_service_type type,
        if (!device_has_service_type(device, type))
            continue;
 
-       err = device_scan(type, device, force_full_scan);
+       err = device_scan(type, device, priority);
        if (err == 0 || err == -EALREADY || err == -EINPROGRESS) {
            success = true;
        } else {
@@ -1150,9 +1154,9 @@ int __connman_device_request_scan(enum connman_service_type type)
    return connman_device_request_scan(type, false);
 }
 
-int __connman_device_request_scan_full(enum connman_service_type type)
+int __connman_device_request_scan_full(enum connman_service_type type,bool priority)
 {
-   return connman_device_request_scan(type, true);
+   return connman_device_request_scan(type, priority);
 }
 
 int __connman_device_request_hidden_scan(struct connman_device *device,
@@ -1240,6 +1244,27 @@ static char *index2ident(int index, const char *prefix)
    return str;
 }
 
+struct connman_device *connman_get_device_from_interface(const char* device_interface)
+{
+   GSList *list_h;
+   int i_h = 0;
+
+   if (!device_interface)
+       return NULL;
+
+   for (list_h = device_list; list_h; list_h = list_h->next) {
+       struct connman_device *device = list_h->data;
+
+       if (g_strcmp0(connman_device_get_string(device, "Interface"), device_interface) == 0) {
+           return device;
+       }
+   }
+
+   return NULL;
+}
+
+
+
 static char *index2addr(int index)
 {
    struct ifreq ifr;
@@ -1283,6 +1308,8 @@ static char *index2addr(int index)
    return str;
 }
 
+
+
 struct connman_device *connman_device_create_from_index(int index)
 {
    enum connman_device_type type;
diff --git a/src/group.c b/src/group.c
index 8715d65..84f1619 100644
--- a/src/group.c
+++ b/src/group.c
@@ -369,6 +369,13 @@ static DBusMessage *p2p_disconnect(DBusConnection *conn,
    return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
 }
 
+static void p2p_invite_callback(int result,
+                   GSupplicantInterface *interface,
+                           void *user_data)
+{
+   DBG("p2p invite callback %d\n", result);
+}
+
 /**
  * Handles a D-Bus method call to invite a peer to a P2P group.
  *
@@ -385,7 +392,34 @@ static DBusMessage *p2p_disconnect(DBusConnection *conn,
 static DBusMessage *p2p_invite(DBusConnection *conn,
                                DBusMessage *msg, void *user_data)
 {
-   // TODO: Implement the logic for inviting a peer to a P2P group.
+   struct connman_group *group = user_data;
+   DBusMessageIter iter;
+   const char *peer_path;
+   char *peer_ident;
+   GSupplicantP2PInviteParams *invite_params = NULL;
+   struct connman_service *service;
+   struct connman_network *network;
+   struct connman_peer *connman_peer;
+   GSupplicantPeer *gs_peer;
+
+   DBG("group %p", group);
+
+   if (dbus_message_iter_init(msg, &iter) == FALSE)
+       return __connman_error_invalid_arguments(msg);
+
+   if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
+       return __connman_error_invalid_arguments(msg);
+
+   dbus_message_iter_get_basic(&iter, &peer_path);
+
+   invite_params = g_try_malloc0(sizeof(GSupplicantP2PInviteParams));
+   if (!invite_params)
+       return __connman_error_invalid_arguments(msg);
+
+   invite_params->peer = peer_path;
+
+   g_supplicant_interface_p2p_invite(group->interface, invite_params, p2p_invite_callback, NULL);
+
    return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
 }
 
diff --git a/src/peer.c b/src/peer.c
index 03c96c0..e81a038 100644
--- a/src/peer.c
+++ b/src/peer.c
@@ -68,6 +68,9 @@ struct connman_peer {
    GDHCPServer *dhcp_server;
    uint32_t lease_ip;
    GSList *services;
+   const char *device_address;
+   bool is_groupOwner;
+   int config_methods;
 };
 
 static void settings_changed(struct connman_peer *peer);
@@ -363,6 +366,13 @@ static void append_peer_services(DBusMessageIter *iter, void *user_data)
    dbus_message_iter_close_container(iter, &container);
 }
 
+static void append_peer(DBusMessageIter *dict, void *user_data)
+{
+   //TO-DO: Implement append_peer function
+   dbus_bool_t val;
+   struct connman_peer *peer = user_data;
+}
+
 static void append_properties(DBusMessageIter *iter, struct connman_peer *peer)
 {
    const char *state = state2string(peer->state);
@@ -374,6 +384,7 @@ static void append_properties(DBusMessageIter *iter, struct connman_peer *peer)
                    DBUS_TYPE_STRING, &state);
    connman_dbus_dict_append_basic(&dict, "Name",
                    DBUS_TYPE_STRING, &peer->name);
+   connman_dbus_dict_append_dict(&dict, "P2P", append_peer, peer);
    connman_dbus_dict_append_dict(&dict, "IPv4", append_ipv4, peer);
    connman_dbus_dict_append_array(&dict, "Services",
                    DBUS_TYPE_DICT_ENTRY,
@@ -617,8 +628,9 @@ static int peer_connect(struct connman_peer *peer)
 
    if (peer_driver->connect){
        if(!pin || strlen(pin)==0){
-       err = peer_driver->connect(peer,
-                   CONNMAN_PEER_WPS_PBC, NULL);
+           err = __connman_agent_request_peer_authorization(peer,
+                       request_authorization_cb, true,
+                       get_dbus_sender(peer), NULL);
        }else{
        err = peer_driver->connect(peer,
                    CONNMAN_PEER_WPS_PIN, pin);
@@ -687,11 +699,9 @@ static DBusMessage *connect_peer(DBusConnection *conn,
    g_list_free(start);
 
    peer->pending = dbus_message_ref(msg);
-
    err = peer_connect(peer);
    if (err == -EINPROGRESS)
        return NULL;
-
    if (err < 0) {
        dbus_message_unref(peer->pending);
        peer->pending = NULL;
@@ -1202,15 +1212,6 @@ static void disconnect_peer_hash_table(gpointer key,
    peer_disconnect(peer);
 }
 
-struct connman_peer *connman_peer_get_by_path(const char *path)
-{
-   struct connman_peer *peer;
-
-   peer = g_hash_table_lookup(peers_table, path);
-
-   return peer;
-}
-
 void __connman_peer_get_properties_struct(DBusMessageIter *iter, gpointer user_data)
 {
    struct connman_peer *peer = user_data;
@@ -1223,6 +1224,15 @@ void __connman_peer_disconnect_all(void)
    g_hash_table_foreach(peers_table, disconnect_peer_hash_table, NULL);
 }
 
+struct connman_peer *connman_peer_get_by_path(const char *path)
+{
+   struct connman_peer *peer;
+
+   peer = g_hash_table_lookup(peers_table, path);
+
+   return peer;
+}
+
 int __connman_peer_init(void)
 {
    DBG("");
diff --git a/src/technology.c b/src/technology.c
index 10041a1..98c98b2 100644
--- a/src/technology.c
+++ b/src/technology.c
@@ -969,6 +969,16 @@ make_reply:
    return reply;
 }
 
+void __connman_technology_p2p_invitation_result(struct connman_technology *technology, int status)
+{
+   if(technology->type != CONNMAN_SERVICE_TYPE_P2P)
+       return;
+
+   connman_dbus_property_changed_basic(technology->path,
+           CONNMAN_TECHNOLOGY_INTERFACE, "P2PInvitationResult",
+           DBUS_TYPE_INT32, &status);
+}
+
 static DBusMessage *set_p2p_listen(struct connman_technology *technology,
                                    DBusMessage *msg, bool enable)
 {
@@ -1404,6 +1414,8 @@ static DBusMessage *scan(DBusConnection *conn, DBusMessage *msg, void *data)
 {
    struct connman_technology *technology = data;
    int err;
+   DBusMessageIter iter;
+   bool priority = false;
 
    DBG("technology %p request from %s", technology,
            dbus_message_get_sender(msg));
@@ -1412,11 +1424,21 @@ static DBusMessage *scan(DBusConnection *conn, DBusMessage *msg, void *data)
                !technology->enabled)
        return __connman_error_permission_denied(msg);
 
+   if (!dbus_message_iter_init(msg, &iter))
+       return __connman_error_invalid_arguments(msg);
+
+   if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_BOOLEAN)
+       return __connman_error_invalid_arguments(msg);
+
+   dbus_message_iter_get_basic(&iter, &priority);
+
    dbus_message_ref(msg);
    technology->scan_pending =
        g_slist_prepend(technology->scan_pending, msg);
 
-   err = __connman_device_request_scan_full(technology->type);
+   DBG("technology scan set priority = %s", priority?"HIGH":"LOW");
+
+   err = __connman_device_request_scan_full(technology->type,priority);
    if (err < 0)
        reply_scan_pending(technology, err);
 
@@ -1430,7 +1452,7 @@ static const GDBusMethodTable technology_methods[] = {
    { GDBUS_ASYNC_METHOD("SetProperty",
            GDBUS_ARGS({ "name", "s" }, { "value", "v" }),
            NULL, set_property) },
-   { GDBUS_ASYNC_METHOD("Scan", NULL, NULL, scan) },
+   { GDBUS_ASYNC_METHOD("Scan", GDBUS_ARGS({ "priority", "b" }), NULL, scan) },
    { },
 };