[PATCH v2 1/5] Add device type to identify LE, BR/EDR or dual mode devices

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



If EIR Flags field is sent in the advertising data, it can be used
to detect the operation mode. If the remote device is dual mode,
GAP operation mode defines that it shall follow the connectable
mode for BR/EDR and non-connectable mode for LE. This patch forces
service discovery protocol prior to Discover All Primary Services.
---
 src/adapter.c |   55 +++++++++++++++++++++++++++++++++++++++----------------
 src/adapter.h |    3 ---
 src/device.c  |   12 ++++++------
 src/device.h  |   11 +++++++++--
 4 files changed, 54 insertions(+), 27 deletions(-)

diff --git a/src/adapter.c b/src/adapter.c
index 62afc0c..b3270ce 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -1196,16 +1196,17 @@ sdp_list_t *adapter_get_services(struct btd_adapter *adapter)
 	return adapter->services;
 }
 
-struct btd_device *adapter_create_device(DBusConnection *conn,
-					struct btd_adapter *adapter,
-					const char *address, gboolean le)
+static struct btd_device *adapter_create_device(DBusConnection *conn,
+						struct btd_adapter *adapter,
+						const char *address,
+						device_type_t type)
 {
 	struct btd_device *device;
 	const char *path;
 
 	DBG("%s", address);
 
-	device = device_create(conn, adapter, address, le);
+	device = device_create(conn, adapter, address, type);
 	if (!device)
 		return NULL;
 
@@ -1264,7 +1265,8 @@ struct btd_device *adapter_get_device(DBusConnection *conn,
 	if (device)
 		return device;
 
-	return adapter_create_device(conn, adapter, address, FALSE);
+	return adapter_create_device(conn, adapter, address,
+						DEVICE_TYPE_BREDR);
 }
 
 static gboolean stop_scanning(gpointer user_data)
@@ -1686,6 +1688,24 @@ static DBusMessage *cancel_device_creation(DBusConnection *conn,
 	return dbus_message_new_method_return(msg);
 }
 
+static device_type_t flags2type(uint8_t flags)
+{
+	/* Inferring the remote type based on the EIR Flags field */
+
+	/* For LE only and dual mode the following flags must be zero */
+	if (flags & (EIR_SIM_CONTROLLER | EIR_SIM_HOST))
+		return DEVICE_TYPE_UNKNOWN;
+
+	/* Limited or General discoverable mode bit must be enabled */
+	if (!(flags & (EIR_LIM_DISC | EIR_GEN_DISC)))
+		return DEVICE_TYPE_UNKNOWN;
+
+	if (flags & EIR_BREDR_UNSUP)
+		return DEVICE_TYPE_LE;
+	else
+		return DEVICE_TYPE_DUALMODE;
+}
+
 static DBusMessage *create_device(DBusConnection *conn,
 					DBusMessage *msg, void *data)
 {
@@ -1693,8 +1713,8 @@ static DBusMessage *create_device(DBusConnection *conn,
 	struct btd_device *device;
 	struct remote_dev_info *dev, match;
 	const gchar *address;
-	gboolean le;
 	int err;
+	device_type_t type;
 
 	if (dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &address,
 						DBUS_TYPE_INVALID) == FALSE)
@@ -1715,9 +1735,9 @@ static DBusMessage *create_device(DBusConnection *conn,
 	match.name_status = NAME_ANY;
 
 	dev = adapter_search_found_devices(adapter, &match);
-	le  = dev ? dev->le : FALSE;
+	type = dev && dev->flags ? flags2type(dev->flags) : DEVICE_TYPE_BREDR;
 
-	device = adapter_create_device(conn, adapter, address, le);
+	device = adapter_create_device(conn, adapter, address, type);
 	if (!device)
 		return NULL;
 
@@ -2013,7 +2033,7 @@ static void create_stored_device_from_profiles(char *key, char *value,
 				key, (GCompareFunc) device_address_cmp))
 		return;
 
-	device = device_create(connection, adapter, key, FALSE);
+	device = device_create(connection, adapter, key, DEVICE_TYPE_BREDR);
 	if (!device)
 		return;
 
@@ -2036,7 +2056,7 @@ static void create_stored_device_from_linkkeys(char *key, char *value,
 					(GCompareFunc) device_address_cmp))
 		return;
 
-	device = device_create(connection, adapter, key, FALSE);
+	device = device_create(connection, adapter, key, DEVICE_TYPE_BREDR);
 	if (device) {
 		device_set_temporary(device, FALSE);
 		adapter->devices = g_slist_append(adapter->devices, device);
@@ -2053,7 +2073,7 @@ static void create_stored_device_from_blocked(char *key, char *value,
 				key, (GCompareFunc) device_address_cmp))
 		return;
 
-	device = device_create(connection, adapter, key, FALSE);
+	device = device_create(connection, adapter, key, DEVICE_TYPE_BREDR);
 	if (device) {
 		device_set_temporary(device, FALSE);
 		adapter->devices = g_slist_append(adapter->devices, device);
@@ -3054,16 +3074,19 @@ static struct remote_dev_info *get_found_dev(struct btd_adapter *adapter,
 	return dev;
 }
 
-static uint8_t extract_eir_flags(uint8_t *eir_data)
+static gboolean extract_eir_flags(uint8_t *flags, uint8_t *eir_data)
 {
 	if (eir_data[0] == 0)
-		return 0;
+		return FALSE;
 
 	if (eir_data[1] != EIR_FLAGS)
-		return 0;
+		return FALSE;
 
 	/* For now, only one octet is used for flags */
-	return eir_data[2];
+	if (flags)
+		*flags = eir_data[2];
+
+	return TRUE;
 }
 
 void adapter_update_device_from_info(struct btd_adapter *adapter,
@@ -3098,7 +3121,7 @@ void adapter_update_device_from_info(struct btd_adapter *adapter,
 			dev->name = tmp_name;
 		}
 
-		dev->flags = extract_eir_flags(info->data);
+		extract_eir_flags(info->data, &dev->flags);
 	}
 
 	/* FIXME: check if other information was changed before emitting the
diff --git a/src/adapter.h b/src/adapter.h
index b189b27..3a2cf9c 100644
--- a/src/adapter.h
+++ b/src/adapter.h
@@ -108,9 +108,6 @@ struct btd_device *adapter_find_connection(struct btd_adapter *adapter, uint16_t
 void adapter_remove_device(DBusConnection *conn, struct btd_adapter *adapter,
 						struct btd_device *device,
 						gboolean remove_storage);
-struct btd_device *adapter_create_device(DBusConnection *conn,
-					struct btd_adapter *adapter,
-					const char *address, gboolean le);
 
 int adapter_resolve_names(struct btd_adapter *adapter);
 
diff --git a/src/device.c b/src/device.c
index 5326e3f..50fb83c 100644
--- a/src/device.c
+++ b/src/device.c
@@ -107,7 +107,7 @@ struct browse_req {
 
 struct btd_device {
 	bdaddr_t	bdaddr;
-	gboolean	le;
+	device_type_t	type;
 	gchar		*path;
 	char		name[MAX_NAME_LENGTH + 1];
 	char		*alias;
@@ -212,7 +212,7 @@ static void browse_request_cancel(struct browse_req *req)
 
 	adapter_get_address(adapter, &src);
 
-	if (device->le == FALSE)
+	if (device->type != DEVICE_TYPE_LE)
 		bt_cancel_discovery(&src, &device->bdaddr);
 
 	device->browse = NULL;
@@ -964,8 +964,8 @@ void device_set_secmode3_conn(struct btd_device *device, gboolean enable)
 }
 
 struct btd_device *device_create(DBusConnection *conn,
-					struct btd_adapter *adapter,
-					const gchar *address, gboolean le)
+				struct btd_adapter *adapter,
+				const gchar *address, device_type_t type)
 {
 	gchar *address_up;
 	struct btd_device *device;
@@ -993,7 +993,7 @@ struct btd_device *device_create(DBusConnection *conn,
 
 	str2ba(address, &device->bdaddr);
 	device->adapter = adapter;
-	device->le = le;
+	device->type = type;
 	adapter_get_address(adapter, &src);
 	ba2str(&src, srcaddr);
 	read_device_name(srcaddr, address, device->name);
@@ -1656,7 +1656,7 @@ int device_browse(struct btd_device *device, DBusConnection *conn,
 	if (device->browse)
 		return -EBUSY;
 
-	if (device->le)
+	if (device->type == DEVICE_TYPE_LE)
 		req = browse_primary(device, &err);
 	else
 		req = browse_sdp(device, search, reverse, &err);
diff --git a/src/device.h b/src/device.h
index a5b6273..784e931 100644
--- a/src/device.h
+++ b/src/device.h
@@ -34,9 +34,16 @@ typedef enum {
 	AUTH_TYPE_AUTO,
 } auth_type_t;
 
+typedef enum {
+	DEVICE_TYPE_UNKNOWN,
+	DEVICE_TYPE_BREDR,
+	DEVICE_TYPE_LE,
+	DEVICE_TYPE_DUALMODE
+} device_type_t;
+
 struct btd_device *device_create(DBusConnection *conn,
-					struct btd_adapter *adapter,
-					const gchar *address, gboolean le);
+				struct btd_adapter *adapter,
+				const gchar *address, device_type_t type);
 void device_set_name(struct btd_device *device, const char *name);
 void device_get_name(struct btd_device *device, char *name, size_t len);
 void device_remove(struct btd_device *device, gboolean remove_stored);
-- 
1.7.3.2

--
To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Bluez Devel]     [Linux Wireless Networking]     [Linux Wireless Personal Area Networking]     [Linux ATH6KL]     [Linux USB Devel]     [Linux Media Drivers]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Big List of Linux Books]

  Powered by Linux