Listen to DeviceFound and DeviceLost. From there it gets the Peer path
and properties, store it into the interface object and call relevant
peer_found/peer_lost callbacks provided by the wifi plugin.
Due to the fact wpa_supplicant might not (it's a bug) send the device
address, the peer identifier will be constructed on its name in this
case.
---
gsupplicant/gsupplicant.h | 11 ++-
gsupplicant/supplicant.c | 205 +++++++++++++++++++++++++++++++++++++++++++++-
2 files changed, 214 insertions(+), 2 deletions(-)
diff --git a/gsupplicant/gsupplicant.h b/gsupplicant/gsupplicant.h
index 4881396..a5ec405 100644
--- a/gsupplicant/gsupplicant.h
+++ b/gsupplicant/gsupplicant.h
@@ -230,10 +230,12 @@ int
g_supplicant_interface_set_country(GSupplicantInterface *interface,
void *user_data);
bool g_supplicant_interface_has_p2p(GSupplicantInterface *interface);
-/* Network API */
+/* Network and Peer API */
struct _GSupplicantNetwork;
+struct _GSupplicantPeer;
typedef struct _GSupplicantNetwork GSupplicantNetwork;
+typedef struct _GSupplicantPeer GSupplicantPeer;
GSupplicantInterface *g_supplicant_network_get_interface(GSupplicantNetwork
*network);
const char *g_supplicant_network_get_name(GSupplicantNetwork *network);
@@ -250,6 +252,11 @@ dbus_bool_t
g_supplicant_network_is_wps_active(GSupplicantNetwork *network);
dbus_bool_t g_supplicant_network_is_wps_pbc(GSupplicantNetwork *network);
dbus_bool_t g_supplicant_network_is_wps_advertizing(GSupplicantNetwork
*network);
+GSupplicantInterface *g_supplicant_peer_get_interface(GSupplicantPeer *peer);
+const char *g_supplicant_peer_get_identifier(GSupplicantPeer *peer);
+const void *g_supplicant_peer_get_device_address(GSupplicantPeer *peer);
+const char *g_supplicant_peer_get_name(GSupplicantPeer *peer);
+
struct _GSupplicantCallbacks {
void (*system_ready) (void);
void (*system_killed) (void);
@@ -263,6 +270,8 @@ struct _GSupplicantCallbacks {
void (*network_removed) (GSupplicantNetwork *network);
void (*network_changed) (GSupplicantNetwork *network,
const char *property);
+ void (*peer_found) (GSupplicantPeer *peer);
+ void (*peer_lost) (GSupplicantPeer *peer);
void (*debug) (const char *str);
};
diff --git a/gsupplicant/supplicant.c b/gsupplicant/supplicant.c
index 8f19345..cd35012 100644
--- a/gsupplicant/supplicant.c
+++ b/gsupplicant/supplicant.c
@@ -168,6 +168,7 @@ struct _GSupplicantInterface {
struct _GSupplicantWpsCredentials wps_cred;
GSupplicantWpsState wps_state;
GHashTable *network_table;
+ GHashTable *peer_table;
GHashTable *net_mapping;
GHashTable *bss_mapping;
void *data;
@@ -218,6 +219,14 @@ struct _GSupplicantNetwork {
GHashTable *config_table;
};
+struct _GSupplicantPeer {
+ GSupplicantInterface *interface;
+ char *path;
+ unsigned char device_address[6];
+ char *name;
+ char *identifier;
+};
+
static inline void debug(const char *format, ...)
{
char str[256];
@@ -448,6 +457,28 @@ static void callback_network_changed(GSupplicantNetwork
*network,
callbacks_pointer->network_changed(network, property);
}
+static void callback_peer_found(GSupplicantPeer *peer)
+{
+ if (!callbacks_pointer)
+ return;
+
+ if (!callbacks_pointer->peer_found)
+ return;
+
+ callbacks_pointer->peer_found(peer);
+}
+
+static void callback_peer_lost(GSupplicantPeer *peer)
+{
+ if (!callbacks_pointer)
+ return;
+
+ if (!callbacks_pointer->peer_lost)
+ return;
+
+ callbacks_pointer->peer_lost(peer);
+}
+
static void remove_interface(gpointer data)
{
GSupplicantInterface *interface = data;
@@ -455,6 +486,7 @@ static void remove_interface(gpointer data)
g_hash_table_destroy(interface->bss_mapping);
g_hash_table_destroy(interface->net_mapping);
g_hash_table_destroy(interface->network_table);
+ g_hash_table_destroy(interface->peer_table);
if (interface->scan_callback) {
SUPPLICANT_DBG("call interface %p callback %p scanning %d",
@@ -506,6 +538,17 @@ static void remove_bss(gpointer data)
g_free(bss);
}
+static void remove_peer(gpointer data)
+{
+ GSupplicantPeer *peer = data;
+
+ g_free(peer->path);
+ g_free(peer->name);
+ g_free(peer->identifier);
+
+ g_free(peer);
+}
+
static void debug_strvalmap(const char *label, struct strvalmap *map,
unsigned int val)
{
@@ -935,6 +978,38 @@ dbus_bool_t
g_supplicant_network_is_wps_advertizing(GSupplicantNetwork *network)
return FALSE;
}
+GSupplicantInterface *g_supplicant_peer_get_interface(GSupplicantPeer *peer)
+{
+ if (!peer)
+ return NULL;
+
+ return peer->interface;
+}
+
+const char *g_supplicant_peer_get_identifier(GSupplicantPeer *peer)
+{
+ if (!peer)
+ return NULL;
+
+ return peer->identifier;
+}
+
+const void *g_supplicant_peer_get_device_address(GSupplicantPeer *peer)
+{
+ if (!peer)
+ return NULL;
+
+ return peer->device_address;
+}
+
+const char *g_supplicant_peer_get_name(GSupplicantPeer *peer)
+{
+ if (!peer)
+ return NULL;
+
+ return peer->name;
+}
+
static void merge_network(GSupplicantNetwork *network)
{
GString *str;
@@ -1833,7 +1908,8 @@ static GSupplicantInterface *interface_alloc(const char
*path)
interface->network_table = g_hash_table_new_full(g_str_hash,
g_str_equal, NULL, remove_network);
-
+ interface->peer_table = g_hash_table_new_full(g_str_hash,
+ g_str_equal, NULL, remove_peer);
interface->net_mapping = g_hash_table_new_full(g_str_hash, g_str_equal,
NULL, NULL);
interface->bss_mapping = g_hash_table_new_full(g_str_hash, g_str_equal,
@@ -2322,6 +2398,127 @@ static void signal_wps_event(const char *path,
DBusMessageIter *iter)
supplicant_dbus_property_foreach(iter, wps_event_args, interface);
}
+static void create_peer_identifier(GSupplicantPeer *peer)
+{
+ if (!peer)
+ return;
+
+ if (!peer->device_address) {
+ peer->identifier = g_strdup(peer->name);
+ return;
+ }
+
+ peer->identifier = g_malloc0(19);
+ snprintf(peer->identifier, 19, "%02x%02x%02x%02x%02x%02x",
+ peer->device_address[0],
+ peer->device_address[1],
+ peer->device_address[2],
+ peer->device_address[3],
+ peer->device_address[4],
+ peer->device_address[5]);
+}
+
+static void peer_property(const char *key, DBusMessageIter *iter,
+ void *user_data)
+{
+ GSupplicantPeer *peer = user_data;
+
+ SUPPLICANT_DBG("key: %s", key);
+
+ if (!peer->interface)
+ return;
+
+ if (!key) {
+ if (peer->name) {
+ create_peer_identifier(peer);
+ callback_peer_found(peer);
+ }
+
+ return;
+ }
+
+ if (g_strcmp0(key, "DeviceAddress") == 0) {
+ unsigned char *dev_addr;
+ DBusMessageIter array;
+ int len;
+
+ dbus_message_iter_recurse(iter, &array);
+ dbus_message_iter_get_fixed_array(&array, &dev_addr, &len);
+
+ if (len == 6)
+ memcpy(peer->device_address, dev_addr, len);
+ } else if (g_strcmp0(key, "DeviceName") == 0) {
+ const char *str = NULL;
+
+ dbus_message_iter_get_basic(iter, &str);
+ if (str)
+ peer->name = g_strdup(str);
+ }
+}
+
+static void signal_peer_found(const char *path, DBusMessageIter *iter)
+{
+ GSupplicantInterface *interface;
+ const char *obj_path = NULL;
+ GSupplicantPeer *peer;
+
+ SUPPLICANT_DBG("");
+
+ interface = g_hash_table_lookup(interface_table, path);
+ if (!interface)
+ return;
+
+ dbus_message_iter_get_basic(iter, &obj_path);
+ if (!obj_path || g_strcmp0(obj_path, "/") == 0)
+ return;
+
+ peer = g_hash_table_lookup(interface->peer_table, obj_path);
+ if (peer)
+ return;
+
+ peer = g_try_new0(GSupplicantPeer, 1);
+ if (!peer)
+ return;
+
+ peer->interface = interface;
+ peer->path = g_strdup(obj_path);
+ g_hash_table_insert(interface->peer_table, peer->path, peer);
+
+ dbus_message_iter_next(iter);
+ if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_INVALID) {
+ supplicant_dbus_property_foreach(iter, peer_property, peer);
+ peer_property(NULL, NULL, peer);
+ return;
+ }
+
+ supplicant_dbus_property_get_all(obj_path,
+ SUPPLICANT_INTERFACE ".Peer", peer_property, peer);
+}
+
+static void signal_peer_lost(const char *path, DBusMessageIter *iter)
+{
+ GSupplicantInterface *interface;
+ const char *obj_path = NULL;
+ GSupplicantPeer *peer;
+
+ SUPPLICANT_DBG("");
+
+ interface = g_hash_table_lookup(interface_table, path);
+ if (!interface)
+ return;
+
+ dbus_message_iter_get_basic(iter, &obj_path);
+ if (!obj_path || g_strcmp0(obj_path, "/") == 0)
+ return;
+
+ peer = g_hash_table_lookup(interface->peer_table, obj_path);
+ if (!peer)
+ return;
+
+ callback_peer_lost(peer);
+ g_hash_table_remove(interface->peer_table, obj_path);
+}
+
static struct {
const char *interface;
const char *member;
@@ -2346,6 +2543,9 @@ static struct {
{ SUPPLICANT_INTERFACE ".Interface.WPS", "Credentials",
signal_wps_credentials },
{ SUPPLICANT_INTERFACE ".Interface.WPS", "Event",
signal_wps_event },
+ { SUPPLICANT_INTERFACE ".Interface.P2PDevice", "DeviceFound",
signal_peer_found },
+ { SUPPLICANT_INTERFACE ".Interface.P2PDevice", "DeviceLost",
signal_peer_lost },
+
{ }
};
@@ -3970,6 +4170,8 @@ static const char *g_supplicant_rule4 = "type=signal,"
"interface=" SUPPLICANT_INTERFACE ".BSS";
static const char *g_supplicant_rule5 = "type=signal,"
"interface=" SUPPLICANT_INTERFACE ".Network";
+static const char *g_supplicant_rule6 = "type=signal,"
+ "interface=" SUPPLICANT_INTERFACE ".Interface.P2PDevice";
static void invoke_introspect_method(void)
{
@@ -4018,6 +4220,7 @@ int g_supplicant_register(const GSupplicantCallbacks
*callbacks)
dbus_bus_add_match(connection, g_supplicant_rule3, NULL);
dbus_bus_add_match(connection, g_supplicant_rule4, NULL);
dbus_bus_add_match(connection, g_supplicant_rule5, NULL);
+ dbus_bus_add_match(connection, g_supplicant_rule6, NULL);
dbus_connection_flush(connection);
if (dbus_bus_name_has_owner(connection,
--
1.8.3.2
_______________________________________________
connman mailing list
[email protected]
https://lists.connman.net/mailman/listinfo/connman