[PATCH] Connman : Add initial support for P2P listen mode in ConnMan

Shailesh Rathod/LGSI Connectivity Team <[email protected]> Mon, 7 Jul 2025 07:00:37 +0000
Newsgroups dev.linux.lists.connman
Message-ID <SE1P216MB264723B08F4D99FF50554FB3F04FA@SE1P216MB2647.KORP216.PROD.OUTLOOK.COM>
From c8dafb2ffcd7f68b0e68725838095b755e5139d3 Mon Sep 17 00:00:00 2001
From: shailesh rathod <[email protected]>
Date: Fri, 30 May 2025 14:19:57 +0900
Subject: [PATCH] Add initial support for P2P listen mode in ConnMan

- Introduce P2P listen functionality for Wi-Fi Direct (P2P) via new D-Bus
  property "P2PListen" on the technology interface.
- Add technology driver callback set_p2p_listen and implement it in the WiFi plugin.
- Implement GSupplicantP2PExtendedListenParams and related API to trigger the
  ExtendedListen method in wpa_supplicant.
- Update technology and wifi plugin logic to handle enabling/disabling P2P listen state.
- Expose the P2PListen property in D-Bus technology properties and allow it to be set via D-Bus.
- Ensure proper error handling and state management for repeated or unsupported requests.
---
 gsupplicant/gsupplicant.h | 12 +++++++
 gsupplicant/supplicant.c  | 29 +++++++++++++++
 include/technology.h      |  1 +
 plugins/wifi.c            | 35 ++++++++++++++++++
 src/technology.c          | 74 ++++++++++++++++++++++++++++++++++++++-
 5 files changed, 150 insertions(+), 1 deletion(-)

diff --git a/gsupplicant/gsupplicant.h b/gsupplicant/gsupplicant.h
index eab6293..77c2d46 100644
--- a/gsupplicant/gsupplicant.h
+++ b/gsupplicant/gsupplicant.h
@@ -312,6 +312,18 @@ GSupplicantPeer *g_supplicant_interface_peer_lookup(GSupplicantInterface *interf
                        const char *identifier);
 bool g_supplicant_interface_is_p2p_finding(GSupplicantInterface *interface);
 
+struct _GSupplicantP2PExtendedListenParams {
+   int period;
+   int interval;
+};
+
+typedef struct _GSupplicantP2PExtendedListenParams GSupplicantP2PExtendedListenParams;
+
+int g_supplicant_interface_p2p_extended_listen(GSupplicantInterface *interface,
+                                                       GSupplicantP2PExtendedListenParams *extended_listen_data,
+                                                       GSupplicantInterfaceCallback callback,
+                                                       void *user_data);
+
 /* Network and Peer API */
 struct _GSupplicantNetwork;
 struct _GSupplicantGroup;
diff --git a/gsupplicant/supplicant.c b/gsupplicant/supplicant.c
index f3be9e7..7facfe8 100644
--- a/gsupplicant/supplicant.c
+++ b/gsupplicant/supplicant.c
@@ -4009,6 +4009,35 @@ done:
    interface_create_data_free(data);
 }
 
+static void extended_listen_append_args(DBusMessageIter *iter, GSupplicantP2PExtendedListenParams *params)
+{
+   //struct GSupplicantP2PExtendedListenParams *params = user_data;
+   DBusMessageIter dict;
+
+   supplicant_dbus_dict_open(iter, &dict);
+   if (params) {
+       supplicant_dbus_dict_append_basic(&dict, "period", DBUS_TYPE_INT32, &params->period);
+       supplicant_dbus_dict_append_basic(&dict, "interval", DBUS_TYPE_INT32, &params->interval);
+   }
+   supplicant_dbus_dict_close(iter, &dict);
+}
+int g_supplicant_interface_p2p_extended_listen(GSupplicantInterface *interface,
+   GSupplicantP2PExtendedListenParams *params,
+   GSupplicantInterfaceCallback callback,
+   void *user_data)
+{
+   if (!interface)
+       return -EINVAL;
+
+
+return supplicant_dbus_method_call(interface->path,
+       SUPPLICANT_INTERFACE ".Interface.P2PDevice",
+       "ExtendedListen",
+       extended_listen_append_args,
+       NULL,  // or NULL if no reply handler needed
+       params,
+       NULL);
+}
 static void interface_create_params(DBusMessageIter *iter, void *user_data)
 {
    struct interface_create_data *data = user_data;
diff --git a/include/technology.h b/include/technology.h
index fcd658e..fd7b87a 100644
--- a/include/technology.h
+++ b/include/technology.h
@@ -65,6 +65,7 @@ struct connman_technology_driver {
                const char *bridge, bool enabled);
    int (*set_regdom) (struct connman_technology *technology,
                        const char *alpha2);
+   int (*set_p2p_listen) (struct connman_technology *technology, bool enable);
 };
 
 int connman_technology_driver_register(struct connman_technology_driver *driver);
diff --git a/plugins/wifi.c b/plugins/wifi.c
index 12389fa..cbfcf5d 100644
--- a/plugins/wifi.c
+++ b/plugins/wifi.c
@@ -184,6 +184,7 @@ static bool wfd_service_registered = false;
 static void start_autoscan(struct connman_device *device);
 static int tech_set_tethering(struct connman_technology *technology,
                const char *bridge, bool enabled);
+static int tech_set_p2p_listen(struct connman_technology *technology, bool enable);
 
 static int p2p_tech_probe(struct connman_technology *technology)
 {
@@ -3663,6 +3664,7 @@ static struct connman_technology_driver tech_driver = {
    .remove     = tech_remove,
    .set_tethering  = tech_set_tethering,
    .set_regdom = tech_set_regdom,
+   .set_p2p_listen = tech_set_p2p_listen,
 };
 
 static int wifi_init(void)
@@ -3700,5 +3702,38 @@ static void wifi_exit(void)
    connman_network_driver_unregister(&network_driver);
 }
 
+static int p2p_enter_listen_state(GSupplicantInterface *interface)
+{
+   GSupplicantP2PExtendedListenParams params = {
+       .period = 50,      // ms
+       .interval = 100    // ms
+   };
+
+   return g_supplicant_interface_p2p_extended_listen(interface, &params, NULL, NULL);
+}
+
+static int tech_set_p2p_listen(struct connman_technology *technology, bool enable)
+{
+   GList *list;
+   struct wifi_data *wifi = NULL;
+   GSupplicantInterface *interface;
+   int err;
+
+   for (list = iface_list; list; list = list->next) {
+       wifi = list->data;
+       interface = wifi->interface;
+
+       if (interface == NULL)
+           continue;
+
+       if (wifi->interface){
+           err = p2p_enter_listen_state(wifi->interface);
+           return err;
+       }
+   }
+
+   return -EOPNOTSUPP;
+}
+
 CONNMAN_PLUGIN_DEFINE(wifi, "WiFi interface plugin", VERSION,
        CONNMAN_PLUGIN_PRIORITY_DEFAULT, wifi_init, wifi_exit)
diff --git a/src/technology.c b/src/technology.c
index 1bcd184..3f3b022 100644
--- a/src/technology.c
+++ b/src/technology.c
@@ -85,6 +85,7 @@ struct connman_technology {
    bool softblocked;
    bool hardblocked;
    bool dbus_registered;
+   bool p2p_listen;
 };
 
 static GSList *driver_list = NULL;
@@ -647,6 +648,10 @@ static void append_properties(DBusMessageIter *iter,
                DBUS_TYPE_INT32,
                &technology->tethering_freq);
 
+    connman_dbus_dict_append_basic(&dict, "P2PListen",
+                   DBUS_TYPE_BOOLEAN,
+                   &technology->p2p_listen);
+
    connman_dbus_dict_close(iter, &dict);
 }
 
@@ -957,6 +962,61 @@ make_reply:
    return reply;
 }
 
+static DBusMessage *set_p2p_listen(struct connman_technology *technology,
+                                   DBusMessage *msg, bool enable)
+{
+   DBusMessage *reply = NULL;
+   int err = 0;
+   GSList *tech_drivers;
+
+   __sync_synchronize();
+   if (technology->enabled == FALSE) {
+       err = -EOPNOTSUPP;
+       goto make_reply;
+   }
+
+   if (technology->type != CONNMAN_SERVICE_TYPE_WIFI) {
+       err = -EOPNOTSUPP;
+       goto make_reply;
+   }
+
+   if (technology->p2p_listen == enable) {
+       err = -EALREADY;
+       goto make_reply;
+   }
+
+   for (tech_drivers = technology->driver_list; tech_drivers != NULL;
+           tech_drivers = g_slist_next(tech_drivers)) {
+       struct connman_technology_driver *driver = tech_drivers->data;
+
+       if (driver == NULL || driver->set_p2p_listen == NULL)
+           continue;
+
+       err = driver->set_p2p_listen(technology, enable);
+       if (err < 0)
+           break;
+   }
+
+   if (err >= 0)
+       technology->p2p_listen = enable;
+
+   make_reply:
+   if (err == -EINPROGRESS)
+       reply = g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+   else if (err == -EALREADY) {
+       if (enable == TRUE)
+           reply = __connman_error_already_enabled(msg);
+       else
+           reply = __connman_error_already_disabled(msg);
+   } else if (err < 0)
+       reply = __connman_error_failed(msg, -err);
+   else
+       reply = g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+
+   return reply;
+}
+
+
 static DBusMessage *set_property(DBusConnection *conn,
                    DBusMessage *msg, void *data)
 {
@@ -1148,7 +1208,19 @@ static DBusMessage *set_property(DBusConnection *conn,
        dbus_message_iter_get_basic(&value, &enable);
 
        return set_powered(technology, msg, enable);
-   } else
+   } else if (g_str_equal(name, "P2PListen") == TRUE) {
+   bool enable;
+
+   if (type != DBUS_TYPE_BOOLEAN)
+       return __connman_error_invalid_arguments(msg);
+
+   if (technology->type != CONNMAN_SERVICE_TYPE_WIFI)
+       return __connman_error_not_supported(msg);
+
+   dbus_message_iter_get_basic(&value, &enable);
+
+   return set_p2p_listen(technology, msg, enable);
+} else
        return __connman_error_invalid_property(msg);
 
    return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);