All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 0/5] android: LE device handling improvements
@ 2014-03-23 21:40 Szymon Janc
  2014-03-23 21:40 ` [PATCH v2 1/5] core: Move EIR flags definitions to eir.h Szymon Janc
                   ` (4 more replies)
  0 siblings, 5 replies; 8+ messages in thread
From: Szymon Janc @ 2014-03-23 21:40 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Szymon Janc

Hi,

This is combined version of previously send 2 series. Included:
- handle non-discovereable devices correctly durring discovery session,
- add uspport for handling LTK (including slave ones)
- add support for LE (and dual mode) device pairing

For dual-mode devices we currently only handle BREDR bonding. I'm still
not sure how to handle those correctly e.g. HAL has only single bonded
state.

Unfortunatelly handling things correctly requires backward incompatible
storage format change. More details in PATCH 5 commit message.

Comments are welcome.

Szymon Janc (5):
  core: Move EIR flags definitions to eir.h
  android/bluetooth: Filter out not discoverable LE devices
  android/bluetooth: Add support for loading LTKs
  android/bluetooth: Add support for new long term key mgmt event
  android/bluetooth: Fix handling of BREDR, LE and dual mode devices

 android/bluetooth.c | 354 ++++++++++++++++++++++++++++++++++++++++++++++------
 src/adapter.c       |  15 +--
 src/eir.h           |   9 ++
 3 files changed, 332 insertions(+), 46 deletions(-)

-- 
1.8.5.3


^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH v2 1/5] core: Move EIR flags definitions to eir.h
  2014-03-23 21:40 [PATCH v2 0/5] android: LE device handling improvements Szymon Janc
@ 2014-03-23 21:40 ` Szymon Janc
  2014-03-24  9:08   ` Johan Hedberg
  2014-03-23 21:40 ` [PATCH v2 2/5] android/bluetooth: Filter out not discoverable LE devices Szymon Janc
                   ` (3 subsequent siblings)
  4 siblings, 1 reply; 8+ messages in thread
From: Szymon Janc @ 2014-03-23 21:40 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Szymon Janc

---
 src/adapter.c | 15 ++++-----------
 src/eir.h     |  9 +++++++++
 2 files changed, 13 insertions(+), 11 deletions(-)

diff --git a/src/adapter.c b/src/adapter.c
index 88d94b4..68940e0 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -72,15 +72,6 @@
 
 #define ADAPTER_INTERFACE	"org.bluez.Adapter1"
 
-/* Flags Descriptions */
-#define EIR_LIM_DISC                0x01 /* LE Limited Discoverable Mode */
-#define EIR_GEN_DISC                0x02 /* LE General Discoverable Mode */
-#define EIR_BREDR_UNSUP             0x04 /* BR/EDR Not Supported */
-#define EIR_SIM_CONTROLLER          0x08 /* Simultaneous LE and BR/EDR to Same
-					    Device Capable (Controller) */
-#define EIR_SIM_HOST                0x10 /* Simultaneous LE and BR/EDR to Same
-					    Device Capable (Host) */
-
 #define MODE_OFF		0x00
 #define MODE_CONNECTABLE	0x01
 #define MODE_DISCOVERABLE	0x02
@@ -4314,7 +4305,8 @@ static void update_found_devices(struct btd_adapter *adapter,
 	if (bdaddr_type == BDADDR_BREDR)
 		discoverable = true;
 	 else
-		discoverable = eir_data.flags & (EIR_LIM_DISC | EIR_GEN_DISC);
+		discoverable = eir_data.flags &
+					(EIR_FLAG_LIM_DISC | EIR_FLAG_GEN_DISC);
 
 	ba2str(bdaddr, addr);
 
@@ -4351,7 +4343,8 @@ static void update_found_devices(struct btd_adapter *adapter,
 
 	device_update_last_seen(dev, bdaddr_type);
 
-	if (bdaddr_type != BDADDR_BREDR && !(eir_data.flags & EIR_BREDR_UNSUP))
+	if (bdaddr_type != BDADDR_BREDR &&
+				!(eir_data.flags & EIR_FLAG_BREDR_UNSUP))
 		device_set_bredr_support(dev, true);
 
 	if (eir_data.name != NULL && eir_data.name_complete)
diff --git a/src/eir.h b/src/eir.h
index 9e53983..b861b33 100644
--- a/src/eir.h
+++ b/src/eir.h
@@ -38,6 +38,15 @@
 #define EIR_DEVICE_ID               0x10  /* device ID */
 #define EIR_GAP_APPEARANCE          0x19  /* GAP appearance */
 
+/* Flags Descriptions */
+#define EIR_FLAG_LIM_DISC           0x01 /* LE Limited Discoverable Mode */
+#define EIR_FLAG_GEN_DISC           0x02 /* LE General Discoverable Mode */
+#define EIR_FLAG_BREDR_UNSUP        0x04 /* BR/EDR Not Supported */
+#define EIR_FLAG_CONTROLLER         0x08 /* Simultaneous LE and BR/EDR to Same
+					    Device Capable (Controller) */
+#define EIR_FLAG_SIM_HOST           0x10 /* Simultaneous LE and BR/EDR to Same
+					    Device Capable (Host) */
+
 struct eir_data {
 	GSList *services;
 	unsigned int flags;
-- 
1.8.5.3


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v2 2/5] android/bluetooth: Filter out not discoverable LE devices
  2014-03-23 21:40 [PATCH v2 0/5] android: LE device handling improvements Szymon Janc
  2014-03-23 21:40 ` [PATCH v2 1/5] core: Move EIR flags definitions to eir.h Szymon Janc
@ 2014-03-23 21:40 ` Szymon Janc
  2014-03-24  9:12   ` Johan Hedberg
  2014-03-23 21:40 ` [PATCH v2 3/5] android/bluetooth: Add support for loading LTKs Szymon Janc
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 8+ messages in thread
From: Szymon Janc @ 2014-03-23 21:40 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Szymon Janc

Filter out the LE devices that do not have Discoverable flag or Limited
Discoverable flag set.
---
 android/bluetooth.c | 23 ++++++++++++++++++-----
 1 file changed, 18 insertions(+), 5 deletions(-)

diff --git a/android/bluetooth.c b/android/bluetooth.c
index d2795e3..3c859e8 100644
--- a/android/bluetooth.c
+++ b/android/bluetooth.c
@@ -1258,6 +1258,11 @@ static void update_device(struct device *dev, int8_t rssi,
 					HAL_EV_REMOTE_DEVICE_PROPS, size, buf);
 }
 
+static bool is_le_dev_discoverable(unsigned int flags)
+{
+	return flags & (EIR_FLAG_LIM_DISC | EIR_FLAG_GEN_DISC);
+}
+
 static void update_found_device(const bdaddr_t *bdaddr, uint8_t bdaddr_type,
 					int8_t rssi, bool confirm,
 					const uint8_t *data, uint8_t data_len)
@@ -1271,6 +1276,19 @@ static void update_found_device(const bdaddr_t *bdaddr, uint8_t bdaddr_type,
 
 	dev = find_device(bdaddr);
 
+	if (bdaddr_type != BDADDR_BREDR) {
+		/* Notify Gatt if its registered for LE events */
+		if (gatt_device_found_cb)
+			gatt_device_found_cb(bdaddr, bdaddr_type, rssi,
+							sizeof(eir), &eir);
+
+		if (adapter.cur_discovery_type != SCAN_TYPE_NONE &&
+					!is_le_dev_discoverable(eir.flags)) {
+			eir_data_free(&eir);
+			return;
+		}
+	}
+
 	/* Device found event needs to be send also for known device if this is
 	 * new discovery session. Otherwise framework will ignore it.
 	 */
@@ -1283,11 +1301,6 @@ static void update_found_device(const bdaddr_t *bdaddr, uint8_t bdaddr_type,
 		update_device(dev, rssi, &eir);
 	}
 
-	/* Notify Gatt if its registered for LE events */
-	if (gatt_device_found_cb && (dev->bdaddr_type & BDADDR_LE))
-		gatt_device_found_cb(&dev->bdaddr, dev->bdaddr_type,
-						dev->rssi, sizeof(eir), &eir);
-
 	eir_data_free(&eir);
 
 	if (dev->bond_state != HAL_BOND_STATE_BONDED)
-- 
1.8.5.3


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v2 3/5] android/bluetooth: Add support for loading LTKs
  2014-03-23 21:40 [PATCH v2 0/5] android: LE device handling improvements Szymon Janc
  2014-03-23 21:40 ` [PATCH v2 1/5] core: Move EIR flags definitions to eir.h Szymon Janc
  2014-03-23 21:40 ` [PATCH v2 2/5] android/bluetooth: Filter out not discoverable LE devices Szymon Janc
@ 2014-03-23 21:40 ` Szymon Janc
  2014-03-23 21:40 ` [PATCH v2 4/5] android/bluetooth: Add support for new long term key mgmt event Szymon Janc
  2014-03-23 21:40 ` [PATCH v2 5/5] android/bluetooth: Fix handling of BREDR, LE and dual mode devices Szymon Janc
  4 siblings, 0 replies; 8+ messages in thread
From: Szymon Janc @ 2014-03-23 21:40 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Szymon Janc

---
 android/bluetooth.c | 117 +++++++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 111 insertions(+), 6 deletions(-)

diff --git a/android/bluetooth.c b/android/bluetooth.c
index 3c859e8..405ec55 100644
--- a/android/bluetooth.c
+++ b/android/bluetooth.c
@@ -28,6 +28,7 @@
 #include <errno.h>
 #include <stdlib.h>
 #include <unistd.h>
+#include <inttypes.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <fcntl.h>
@@ -1599,6 +1600,37 @@ static void load_link_keys(GSList *keys, bt_bluetooth_ready cb)
 	}
 }
 
+static void load_ltks(GSList *ltks)
+{
+	struct mgmt_cp_load_long_term_keys *cp;
+	struct mgmt_ltk_info *ltk;
+	size_t ltk_count, cp_size;
+	GSList *l;
+
+	ltk_count = g_slist_length(ltks);
+
+	DBG("ltks %zu", ltk_count);
+
+	cp_size = sizeof(*cp) + (ltk_count * sizeof(*ltk));
+
+	cp = g_malloc0(cp_size);
+
+	/* Even if the list of stored keys is empty, it is important to load
+	 * an empty list into the kernel. That way it is ensured that no old
+	 * keys from a previous daemon are present.
+	 */
+	cp->key_count = htobs(ltk_count);
+
+	for (l = ltks, ltk = cp->keys; l != NULL; l = g_slist_next(l), ltk++)
+		memcpy(ltk, ltks->data, sizeof(*ltk));
+
+	if (mgmt_send(mgmt_if, MGMT_OP_LOAD_LONG_TERM_KEYS, adapter.index,
+					cp_size, cp, NULL, NULL, NULL) == 0)
+		error("Failed to load LTKs");
+
+	g_free(cp);
+}
+
 static uint8_t get_adapter_uuids(void)
 {
 	struct hal_ev_adapter_props_changed *ev;
@@ -1896,6 +1928,18 @@ static struct device *create_device_from_info(GKeyFile *key_file,
 		dev->bond_state = HAL_BOND_STATE_BONDED;
 	}
 
+	str = g_key_file_get_string(key_file, peer, "LongTermKey", NULL);
+	if (str) {
+		g_free(str);
+		dev->bond_state = HAL_BOND_STATE_BONDED;
+	}
+
+	str = g_key_file_get_string(key_file, peer, "SlaveLongTermKey", NULL);
+	if (str) {
+		g_free(str);
+		dev->bond_state = HAL_BOND_STATE_BONDED;
+	}
+
 	str = g_key_file_get_string(key_file, peer, "Name", NULL);
 	if (str) {
 		g_free(dev->name);
@@ -1965,6 +2009,51 @@ failed:
 	return info;
 }
 
+static struct mgmt_ltk_info *get_ltk_info(GKeyFile *key_file, const char *peer,
+								bool master)
+{
+	const char *key_s, *keytype_s, *encsize_s, *ediv_s, *rand_s;
+	struct mgmt_ltk_info *info = NULL;
+	char *key;
+	unsigned int i;
+
+	key_s = master ? "LongTermKey" : "SlaveLongTermKey";
+	keytype_s = master ? "LongTermKeyType" : "SlaveLongTermKeyType";
+	encsize_s = master ? "LongTermKeyEncSize" : "SlaveLongTermKeyEncSize";
+	ediv_s = master ? "LongTermKeyEDiv" : "SlaveLongTermKeyEDiv";
+	rand_s = master ? "LongTermKeyRand" : "SlaveLongTermKeyRand";
+
+	key = g_key_file_get_string(key_file, peer, key_s, NULL);
+	if (!key || strlen(key) != 32)
+		goto failed;
+
+	info = g_new0(struct mgmt_ltk_info, 1);
+
+	str2ba(peer, &info->addr.bdaddr);
+
+	info->addr.type = g_key_file_get_integer(key_file, peer, "Type", NULL);
+
+	for (i = 0; i < sizeof(info->val); i++)
+		sscanf(key + (i * 2), "%02hhX", &info->val[i]);
+
+	info->type = g_key_file_get_integer(key_file, peer, keytype_s, NULL);
+
+	info->enc_size = g_key_file_get_integer(key_file, peer, encsize_s, NULL);
+
+	info->rand = g_key_file_get_uint64(key_file, peer, rand_s, NULL);
+	info->rand = cpu_to_le64(info->rand);
+
+	info->ediv = g_key_file_get_integer(key_file, peer, ediv_s, NULL);
+	info->ediv = cpu_to_le16(info->ediv);
+
+	info->master = master;
+
+failed:
+	g_free(key);
+
+	return info;
+}
+
 static int device_timestamp_cmp(gconstpointer  a, gconstpointer  b)
 {
 	const struct device *deva = a;
@@ -2006,6 +2095,7 @@ static void load_devices_info(bt_bluetooth_ready cb)
 	gsize len = 0;
 	unsigned int i;
 	GSList *keys = NULL;
+	GSList *ltks = NULL;
 
 	key_file = g_key_file_new();
 
@@ -2015,26 +2105,41 @@ static void load_devices_info(bt_bluetooth_ready cb)
 
 	for (i = 0; i < len; i++) {
 		struct mgmt_link_key_info *key_info;
+		struct mgmt_ltk_info *ltk_info;
+		struct mgmt_ltk_info *slave_ltk_info;
 		struct device *dev;
 
 		key_info = get_key_info(key_file, devs[i]);
-		if (!key_info) {
-			error("Failed to load linkkey for %s, skipping",
-								devs[i]);
+		ltk_info = get_ltk_info(key_file, devs[i], true);
+		slave_ltk_info = get_ltk_info(key_file, devs[i], false);
+
+		if (!key_info && !ltk_info && !slave_ltk_info) {
+			error("Failed to load keys for %s, skipping", devs[i]);
+
 			continue;
 		}
 
-		/* TODO ltk */
+		if (key_info)
+			keys = g_slist_prepend(keys, key_info);
+
+		if (ltk_info)
+			ltks = g_slist_prepend(ltks, ltk_info);
+
+		if (slave_ltk_info)
+			ltks = g_slist_prepend(ltks, slave_ltk_info);
 
 		dev = create_device_from_info(key_file, devs[i]);
 
-		keys = g_slist_prepend(keys, key_info);
 		bonded_devices = g_slist_prepend(bonded_devices, dev);
 	}
 
+	load_ltks(ltks);
+	g_slist_free_full(ltks, g_free);
+
 	load_link_keys(keys, cb);
-	g_strfreev(devs);
 	g_slist_free_full(keys, g_free);
+
+	g_strfreev(devs);
 	g_key_file_free(key_file);
 }
 
-- 
1.8.5.3


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v2 4/5] android/bluetooth: Add support for new long term key mgmt event
  2014-03-23 21:40 [PATCH v2 0/5] android: LE device handling improvements Szymon Janc
                   ` (2 preceding siblings ...)
  2014-03-23 21:40 ` [PATCH v2 3/5] android/bluetooth: Add support for loading LTKs Szymon Janc
@ 2014-03-23 21:40 ` Szymon Janc
  2014-03-23 21:40 ` [PATCH v2 5/5] android/bluetooth: Fix handling of BREDR, LE and dual mode devices Szymon Janc
  4 siblings, 0 replies; 8+ messages in thread
From: Szymon Janc @ 2014-03-23 21:40 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Szymon Janc

---
 android/bluetooth.c | 88 +++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 86 insertions(+), 2 deletions(-)

diff --git a/android/bluetooth.c b/android/bluetooth.c
index 405ec55..5db5515 100644
--- a/android/bluetooth.c
+++ b/android/bluetooth.c
@@ -1494,6 +1494,87 @@ static void mgmt_device_unpaired_event(uint16_t index, uint16_t length,
 							HAL_BOND_STATE_NONE);
 }
 
+static void store_ltk(const bdaddr_t *dst, uint8_t bdaddr_type, bool master,
+			const uint8_t *key, uint8_t key_type, uint8_t enc_size,
+			uint16_t ediv, uint64_t rand)
+{
+	const char *key_s, *keytype_s, *encsize_s, *ediv_s, *rand_s;
+	GKeyFile *key_file;
+	char key_str[33];
+	gsize length = 0;
+	char addr[18];
+	char *data;
+	int i;
+
+	key_file = g_key_file_new();
+	if (!g_key_file_load_from_file(key_file, DEVICES_FILE, 0, NULL)) {
+		g_key_file_free(key_file);
+		return;
+	}
+
+	ba2str(dst, addr);
+
+	key_s = master ? "LongTermKey" : "SlaveLongTermKey";
+	keytype_s = master ? "LongTermKeyType" : "SlaveLongTermKeyType";
+	encsize_s = master ? "LongTermKeyEncSize" : "SlaveLongTermKeyEncSize";
+	ediv_s = master ? "LongTermKeyEDiv" : "SlaveLongTermKeyEDiv";
+	rand_s = master ? "LongTermKeyRand" : "SlaveLongTermKeyRand";
+
+	for (i = 0; i < 16; i++)
+		sprintf(key_str + (i * 2), "%2.2X", key[i]);
+
+	g_key_file_set_string(key_file, addr, key_s, key_str);
+
+	g_key_file_set_integer(key_file, addr, keytype_s, key_type);
+
+	g_key_file_set_integer(key_file, addr, encsize_s, enc_size);
+
+	g_key_file_set_integer(key_file, addr, ediv_s, ediv);
+
+	g_key_file_set_uint64(key_file, addr, rand_s, rand);
+
+	data = g_key_file_to_data(key_file, &length, NULL);
+	g_file_set_contents(DEVICES_FILE, data, length, NULL);
+	g_free(data);
+
+	g_key_file_free(key_file);
+}
+
+static void new_long_term_key_event(uint16_t index, uint16_t length,
+					const void *param, void *user_data)
+{
+	const struct mgmt_ev_new_long_term_key *ev = param;
+	const struct mgmt_addr_info *addr = &ev->key.addr;
+	char dst[18];
+
+	if (length < sizeof(*ev)) {
+		error("Too small long term key event (%u bytes)", length);
+		return;
+	}
+
+	ba2str(&addr->bdaddr, dst);
+
+	DBG("new LTK for %s type %u enc_size %u store_hint %u",
+			dst, ev->key.type, ev->key.enc_size, ev->store_hint);
+
+	set_device_bond_state(&addr->bdaddr, HAL_STATUS_SUCCESS,
+							HAL_BOND_STATE_BONDED);
+
+	if (ev->store_hint) {
+		const struct mgmt_ltk_info *key = &ev->key;
+		uint16_t ediv;
+		uint64_t rand;
+
+		ediv = le16_to_cpu(key->ediv);
+		rand = le64_to_cpu(key->rand);
+
+		store_ltk(&key->addr.bdaddr, key->addr.type, key->master,
+				key->val, key->type, key->enc_size, ediv, rand);
+	}
+
+	/* TODO browse services here? */
+}
+
 static void register_mgmt_handlers(void)
 {
 	mgmt_register(mgmt_if, MGMT_EV_NEW_SETTINGS, adapter.index,
@@ -1540,6 +1621,9 @@ static void register_mgmt_handlers(void)
 
 	mgmt_register(mgmt_if, MGMT_EV_DEVICE_UNPAIRED, adapter.index,
 				mgmt_device_unpaired_event, NULL, NULL);
+
+	mgmt_register(mgmt_if, MGMT_EV_NEW_LONG_TERM_KEY, adapter.index,
+					new_long_term_key_event, NULL, NULL);
 }
 
 static void load_link_keys_complete(uint8_t status, uint16_t length,
@@ -2805,8 +2889,8 @@ static void pair_device_complete(uint8_t status, uint16_t length,
 
 	DBG("status %u", status);
 
-	/* On success bond state change will be send when new link key event
-	 * is received */
+	/* On success bond state change will be send when new link key or LTK
+	 * event is received */
 	if (status == MGMT_STATUS_SUCCESS)
 		return;
 
-- 
1.8.5.3


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v2 5/5] android/bluetooth: Fix handling of BREDR, LE and dual mode devices
  2014-03-23 21:40 [PATCH v2 0/5] android: LE device handling improvements Szymon Janc
                   ` (3 preceding siblings ...)
  2014-03-23 21:40 ` [PATCH v2 4/5] android/bluetooth: Add support for new long term key mgmt event Szymon Janc
@ 2014-03-23 21:40 ` Szymon Janc
  4 siblings, 0 replies; 8+ messages in thread
From: Szymon Janc @ 2014-03-23 21:40 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Szymon Janc

This includes fix for storage format so that dual mode devices are
handled correctly. Unfortunatelly this change is not backward
compatible so wiping out /data/misc/bluetooth/ is recommended.

Also correct device type is passed to bonding commands. For create_bond
we fallback to BDEDR if device is not known. This can happen eg. with
OOB. For cancel_bond and remove_bond we require device to be known.
For dual mode device currently only BREDR type is used.

Storage change details:
Instead of storing bdaddr type of device as "Type", now two variables
are used. Boolean "BREDR" if device supports BREDR. Address type is
stored in "AddressType" only if device supports LE and is either
LE random or LE public type.
---
 android/bluetooth.c | 126 +++++++++++++++++++++++++++++++++++++++++++---------
 1 file changed, 104 insertions(+), 22 deletions(-)

diff --git a/android/bluetooth.c b/android/bluetooth.c
index 5db5515..73e7ac2 100644
--- a/android/bluetooth.c
+++ b/android/bluetooth.c
@@ -93,6 +93,9 @@ struct device {
 	bdaddr_t bdaddr;
 	uint8_t bdaddr_type;
 
+	bool le;
+	bool bredr;
+
 	int bond_state;
 
 	char *name;
@@ -240,7 +243,11 @@ static void store_device_info(struct device *dev, const char *path)
 	key_file = g_key_file_new();
 	g_key_file_load_from_file(key_file, path, 0, NULL);
 
-	g_key_file_set_integer(key_file, addr, "Type", dev->bdaddr_type);
+	g_key_file_set_boolean(key_file, addr, "BREDR", dev->bredr);
+
+	if (dev->le)
+		g_key_file_set_integer(key_file, addr, "AddressType",
+							dev->bdaddr_type);
 
 	g_key_file_set_string(key_file, addr, "Name", dev->name);
 
@@ -370,7 +377,7 @@ cache:
 	store_device_info(new_dev, CACHE_FILE);
 }
 
-static struct device *create_device(const bdaddr_t *bdaddr, uint8_t type)
+static struct device *create_device(const bdaddr_t *bdaddr, uint8_t bdaddr_type)
 {
 	struct device *dev;
 	char addr[18];
@@ -381,7 +388,14 @@ static struct device *create_device(const bdaddr_t *bdaddr, uint8_t type)
 	dev = g_new0(struct device, 1);
 
 	bacpy(&dev->bdaddr, bdaddr);
-	dev->bdaddr_type = type;
+
+	if (bdaddr_type == BDADDR_BREDR) {
+		dev->bredr = true;
+	} else {
+		dev->le = true;
+		dev->bdaddr_type = bdaddr_type;
+	}
+
 	dev->bond_state = HAL_BOND_STATE_NONE;
 	dev->timestamp = time(NULL);
 
@@ -1151,12 +1165,15 @@ static int fill_hal_prop(void *buf, uint8_t type, uint16_t len,
 	return sizeof(*prop) + len;
 }
 
-static uint8_t bdaddr_type2android(uint8_t type)
+static uint8_t get_device_android_type(struct device *dev)
 {
-	if (type == BDADDR_BREDR)
-		return HAL_TYPE_BREDR;
+	if (dev->bredr && dev->le)
+		return HAL_TYPE_DUAL;
 
-	return HAL_TYPE_LE;
+	if (dev->le)
+		return HAL_TYPE_LE;
+
+	return HAL_TYPE_BREDR;
 }
 
 static bool rssi_above_threshold(int old, int new)
@@ -1187,7 +1204,7 @@ static void update_new_device(struct device *dev, int8_t rssi,
 						&android_bdaddr);
 	ev->num_props++;
 
-	android_type = bdaddr_type2android(dev->bdaddr_type);
+	android_type = get_device_android_type(dev);
 	size += fill_hal_prop(buf + size, HAL_PROP_DEVICE_TYPE,
 				sizeof(android_type), &android_type);
 	ev->num_props++;
@@ -1219,10 +1236,11 @@ static void update_new_device(struct device *dev, int8_t rssi,
 }
 
 static void update_device(struct device *dev, int8_t rssi,
-						const struct eir_data *eir)
+				const struct eir_data *eir, uint8_t bdaddr_type)
 {
 	uint8_t buf[IPC_MTU];
 	struct hal_ev_remote_device_props *ev = (void *) buf;
+	uint8_t android_type;
 	int size;
 
 	memset(buf, 0, sizeof(buf));
@@ -1232,6 +1250,27 @@ static void update_device(struct device *dev, int8_t rssi,
 	ev->status = HAL_STATUS_SUCCESS;
 	bdaddr2android(&dev->bdaddr, ev->bdaddr);
 
+	if (dev->bdaddr_type != bdaddr_type) {
+		bool type_changed = false;
+
+		dev->bdaddr_type = bdaddr_type;
+		if (bdaddr_type == BDADDR_BREDR) {
+			type_changed = !dev->bredr;
+			dev->bredr = true;
+		} else {
+			type_changed = !dev->le;
+			dev->le = true;
+		}
+
+		if (type_changed) {
+			android_type = get_device_android_type(dev);
+			size += fill_hal_prop(buf + size, HAL_PROP_DEVICE_TYPE,
+							sizeof(android_type),
+							&android_type);
+			ev->num_props++;
+		}
+	}
+
 	if (eir->class && dev->class != eir->class) {
 		dev->class = eir->class;
 		size += fill_hal_prop(buf + size, HAL_PROP_DEVICE_CLASS,
@@ -1299,7 +1338,7 @@ static void update_found_device(const bdaddr_t *bdaddr, uint8_t bdaddr_type,
 
 		update_new_device(dev, rssi, &eir);
 	} else {
-		update_device(dev, rssi, &eir);
+		update_device(dev, rssi, &eir, bdaddr_type);
 	}
 
 	eir_data_free(&eir);
@@ -2001,11 +2040,16 @@ static struct device *create_device_from_info(GKeyFile *key_file,
 
 	DBG("%s", peer);
 
-	type = g_key_file_get_integer(key_file, peer, "Type", NULL);
+	/* BREDR if not present */
+	type = g_key_file_get_integer(key_file, peer, "AddressType", NULL);
 
 	str2ba(peer, &bdaddr);
 	dev = create_device(&bdaddr, type);
 
+	if (type != BDADDR_BREDR)
+		dev->bredr = g_key_file_get_boolean(key_file, peer, "BREDR",
+									NULL);
+
 	str = g_key_file_get_string(key_file, peer, "LinkKey", NULL);
 	if (str) {
 		g_free(str);
@@ -2901,13 +2945,27 @@ static void pair_device_complete(uint8_t status, uint16_t length,
 static void handle_create_bond_cmd(const void *buf, uint16_t len)
 {
 	const struct hal_cmd_create_bond *cmd = buf;
+	struct device *dev;
 	uint8_t status;
 	struct mgmt_cp_pair_device cp;
 
 	cp.io_cap = DEFAULT_IO_CAPABILITY;
-	cp.addr.type = BDADDR_BREDR;
 	android2bdaddr(cmd->bdaddr, &cp.addr.bdaddr);
 
+	dev = find_device(&cp.addr.bdaddr);
+
+	if (dev) {
+		if (dev->bond_state != HAL_BOND_STATE_NONE) {
+			status = HAL_STATUS_FAILED;
+			goto fail;
+		}
+
+		cp.addr.type = dev->bredr ? BDADDR_BREDR : dev->bdaddr_type;
+	} else {
+		/* Fallback to BREDR if device is unknown eg. OOB */
+		cp.addr.type = BDADDR_BREDR;
+	}
+
 	if (mgmt_send(mgmt_if, MGMT_OP_PAIR_DEVICE, adapter.index, sizeof(cp),
 				&cp, pair_device_complete, NULL, NULL) == 0) {
 		status = HAL_STATUS_FAILED;
@@ -2928,17 +2986,30 @@ static void handle_cancel_bond_cmd(const void *buf, uint16_t len)
 {
 	const struct hal_cmd_cancel_bond *cmd = buf;
 	struct mgmt_addr_info cp;
+	struct device *dev;
 	uint8_t status;
 
-	cp.type = BDADDR_BREDR;
 	android2bdaddr(cmd->bdaddr, &cp.bdaddr);
 
-	if (mgmt_reply(mgmt_if, MGMT_OP_CANCEL_PAIR_DEVICE, adapter.index,
-					sizeof(cp), &cp, NULL, NULL, NULL) > 0)
-		status = HAL_STATUS_SUCCESS;
-	else
+	dev = find_device(&cp.bdaddr);
+	if (!dev) {
+		status = HAL_STATUS_FAILED;
+		goto failed;
+	}
+
+	cp.type = dev->bredr ? BDADDR_BREDR : dev->bdaddr_type;
+
+
+	if (mgmt_reply(mgmt_if, MGMT_OP_CANCEL_PAIR_DEVICE,
+					adapter.index, sizeof(cp), &cp,
+					NULL, NULL, NULL) == 0) {
 		status = HAL_STATUS_FAILED;
+		goto failed;
+	}
+
+	status = HAL_STATUS_SUCCESS;
 
+failed:
 	ipc_send_rsp(hal_ipc, HAL_SERVICE_ID_BLUETOOTH, HAL_OP_CANCEL_BOND,
 									status);
 }
@@ -2961,19 +3032,30 @@ static void handle_remove_bond_cmd(const void *buf, uint16_t len)
 {
 	const struct hal_cmd_remove_bond *cmd = buf;
 	struct mgmt_cp_unpair_device cp;
+	struct device *dev;
 	uint8_t status;
 
 	cp.disconnect = 1;
-	cp.addr.type = BDADDR_BREDR;
 	android2bdaddr(cmd->bdaddr, &cp.addr.bdaddr);
 
+	dev = find_device(&cp.addr.bdaddr);
+	if (!dev) {
+		status = HAL_STATUS_FAILED;
+		goto failed;
+	}
+
+	cp.addr.type = dev->bredr ? BDADDR_BREDR : dev->bdaddr_type;
+
 	if (mgmt_send(mgmt_if, MGMT_OP_UNPAIR_DEVICE, adapter.index,
 				sizeof(cp), &cp, unpair_device_complete,
-				NULL, NULL) > 0)
-		status = HAL_STATUS_SUCCESS;
-	else
+				NULL, NULL) ==  0) {
 		status = HAL_STATUS_FAILED;
+		goto failed;
+	}
 
+	status = HAL_STATUS_SUCCESS;
+
+failed:
 	ipc_send_rsp(hal_ipc, HAL_SERVICE_ID_BLUETOOTH, HAL_OP_REMOVE_BOND,
 									status);
 }
@@ -3150,7 +3232,7 @@ static uint8_t get_device_class(struct device *dev)
 
 static uint8_t get_device_type(struct device *dev)
 {
-	uint8_t type = bdaddr_type2android(dev->bdaddr_type);
+	uint8_t type = get_device_android_type(dev);
 
 	send_device_property(&dev->bdaddr, HAL_PROP_DEVICE_TYPE,
 							sizeof(type), &type);
-- 
1.8.5.3


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH v2 1/5] core: Move EIR flags definitions to eir.h
  2014-03-23 21:40 ` [PATCH v2 1/5] core: Move EIR flags definitions to eir.h Szymon Janc
@ 2014-03-24  9:08   ` Johan Hedberg
  0 siblings, 0 replies; 8+ messages in thread
From: Johan Hedberg @ 2014-03-24  9:08 UTC (permalink / raw)
  To: Szymon Janc; +Cc: linux-bluetooth

Hi Szymon,

On Sun, Mar 23, 2014, Szymon Janc wrote:
> ---
>  src/adapter.c | 15 ++++-----------
>  src/eir.h     |  9 +++++++++
>  2 files changed, 13 insertions(+), 11 deletions(-)
> diff --git a/src/adapter.c b/src/adapter.c

This patch is otherwise fine, but please don't rename the defines. The
EIR prefix is good enough and keeps the usage of the readable enough.
Also, even if we did want to rename them, it's misleading to hide that
in a patch which you (in the commit message) claim to be only about
moving stuff around.

Johan

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH v2 2/5] android/bluetooth: Filter out not discoverable LE devices
  2014-03-23 21:40 ` [PATCH v2 2/5] android/bluetooth: Filter out not discoverable LE devices Szymon Janc
@ 2014-03-24  9:12   ` Johan Hedberg
  0 siblings, 0 replies; 8+ messages in thread
From: Johan Hedberg @ 2014-03-24  9:12 UTC (permalink / raw)
  To: Szymon Janc; +Cc: linux-bluetooth

Hi Szymon,

On Sun, Mar 23, 2014, Szymon Janc wrote:
> Filter out the LE devices that do not have Discoverable flag or Limited
> Discoverable flag set.
> ---
>  android/bluetooth.c | 23 ++++++++++++++++++-----
>  1 file changed, 18 insertions(+), 5 deletions(-)
> 
> diff --git a/android/bluetooth.c b/android/bluetooth.c
> index d2795e3..3c859e8 100644
> --- a/android/bluetooth.c
> +++ b/android/bluetooth.c
> @@ -1258,6 +1258,11 @@ static void update_device(struct device *dev, int8_t rssi,
>  					HAL_EV_REMOTE_DEVICE_PROPS, size, buf);
>  }
>  
> +static bool is_le_dev_discoverable(unsigned int flags)
> +{
> +	return flags & (EIR_FLAG_LIM_DISC | EIR_FLAG_GEN_DISC);
> +}
> +
>  static void update_found_device(const bdaddr_t *bdaddr, uint8_t bdaddr_type,
>  					int8_t rssi, bool confirm,
>  					const uint8_t *data, uint8_t data_len)
> @@ -1271,6 +1276,19 @@ static void update_found_device(const bdaddr_t *bdaddr, uint8_t bdaddr_type,
>  
>  	dev = find_device(bdaddr);
>  
> +	if (bdaddr_type != BDADDR_BREDR) {
> +		/* Notify Gatt if its registered for LE events */
> +		if (gatt_device_found_cb)
> +			gatt_device_found_cb(bdaddr, bdaddr_type, rssi,
> +							sizeof(eir), &eir);
> +
> +		if (adapter.cur_discovery_type != SCAN_TYPE_NONE &&
> +					!is_le_dev_discoverable(eir.flags)) {
> +			eir_data_free(&eir);
> +			return;
> +		}
> +	}

Do note the recent changes I had to do for the normal bluetoothd since
it's not possible to distinguish ADV_IND/ADV_SCAN_IND from SCAN_RSP
events. The flags field is not permitted to be in the SCAN_RSP so you'd
not be able to take advantage of any data in such events if you discard
the data when the flags are not around.

Also be aware of the recent kernel patch set I sent which merges these
events into a single device found event and again makes it possible to
do strict checking of the flags. That said, this all depends on what
kind of kernel version we want to depend on. If we're going to rely also
on the kernel-side passive for LE (which will probably land in 3.16)
then it's probably fine to overlook this issue for now.

Johan

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2014-03-24  9:12 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-03-23 21:40 [PATCH v2 0/5] android: LE device handling improvements Szymon Janc
2014-03-23 21:40 ` [PATCH v2 1/5] core: Move EIR flags definitions to eir.h Szymon Janc
2014-03-24  9:08   ` Johan Hedberg
2014-03-23 21:40 ` [PATCH v2 2/5] android/bluetooth: Filter out not discoverable LE devices Szymon Janc
2014-03-24  9:12   ` Johan Hedberg
2014-03-23 21:40 ` [PATCH v2 3/5] android/bluetooth: Add support for loading LTKs Szymon Janc
2014-03-23 21:40 ` [PATCH v2 4/5] android/bluetooth: Add support for new long term key mgmt event Szymon Janc
2014-03-23 21:40 ` [PATCH v2 5/5] android/bluetooth: Fix handling of BREDR, LE and dual mode devices Szymon Janc

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.