Linux bluetooth development
 help / color / mirror / Atom feed
* [PATCH 1/3] android/bluetooth: Pass correct device type for bonding commands
@ 2014-03-18 15:18 Szymon Janc
  2014-03-18 15:18 ` [PATCH 2/3] android/bluetooth: Add support for loading LTKs Szymon Janc
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: Szymon Janc @ 2014-03-18 15:18 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Szymon Janc

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.
---
 android/bluetooth.c | 45 ++++++++++++++++++++++++++++++++++++---------
 1 file changed, 36 insertions(+), 9 deletions(-)

diff --git a/android/bluetooth.c b/android/bluetooth.c
index 1becdfb..000f595 100644
--- a/android/bluetooth.c
+++ b/android/bluetooth.c
@@ -2697,13 +2697,18 @@ 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);
+
+	/* Fallback to BREDR if device is unknown eg. OOB */
+	cp.addr.type = dev ? dev->bdaddr_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;
@@ -2724,17 +2729,28 @@ 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);
 
+	dev = find_device(&cp.bdaddr);
+	if (!dev) {
+		status = HAL_STATUS_FAILED;
+		goto failed;
+	}
+
+	cp.type = 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_SUCCESS;
-	else
+				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);
 }
@@ -2757,19 +2773,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->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);
 }
-- 
1.8.5.3


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

* [PATCH 2/3] android/bluetooth: Add support for loading LTKs
  2014-03-18 15:18 [PATCH 1/3] android/bluetooth: Pass correct device type for bonding commands Szymon Janc
@ 2014-03-18 15:18 ` Szymon Janc
  2014-03-18 15:18 ` [PATCH 3/3] android/bluetooth: Add support for new long term key mgmt event Szymon Janc
  2014-03-19  9:23 ` [PATCH 1/3] android/bluetooth: Pass correct device type for bonding commands Szymon Janc
  2 siblings, 0 replies; 4+ messages in thread
From: Szymon Janc @ 2014-03-18 15:18 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Szymon Janc

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

diff --git a/android/bluetooth.c b/android/bluetooth.c
index 000f595..a6650ef 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>
@@ -38,6 +39,7 @@
 #include "lib/sdp.h"
 #include "lib/mgmt.h"
 #include "src/shared/mgmt.h"
+#include "src/shared/util.h"
 #include "src/uuid-helper.h"
 #include "src/eir.h"
 #include "lib/sdp.h"
@@ -1585,6 +1587,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;
@@ -1882,6 +1915,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);
@@ -1950,6 +1995,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;
@@ -1991,6 +2081,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();
 
@@ -2000,26 +2091,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] 4+ messages in thread

* [PATCH 3/3] android/bluetooth: Add support for new long term key mgmt event
  2014-03-18 15:18 [PATCH 1/3] android/bluetooth: Pass correct device type for bonding commands Szymon Janc
  2014-03-18 15:18 ` [PATCH 2/3] android/bluetooth: Add support for loading LTKs Szymon Janc
@ 2014-03-18 15:18 ` Szymon Janc
  2014-03-19  9:23 ` [PATCH 1/3] android/bluetooth: Pass correct device type for bonding commands Szymon Janc
  2 siblings, 0 replies; 4+ messages in thread
From: Szymon Janc @ 2014-03-18 15:18 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 a6650ef..845c761 100644
--- a/android/bluetooth.c
+++ b/android/bluetooth.c
@@ -1481,6 +1481,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,
@@ -1527,6 +1608,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,
@@ -2791,8 +2875,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] 4+ messages in thread

* Re: [PATCH 1/3] android/bluetooth: Pass correct device type for bonding commands
  2014-03-18 15:18 [PATCH 1/3] android/bluetooth: Pass correct device type for bonding commands Szymon Janc
  2014-03-18 15:18 ` [PATCH 2/3] android/bluetooth: Add support for loading LTKs Szymon Janc
  2014-03-18 15:18 ` [PATCH 3/3] android/bluetooth: Add support for new long term key mgmt event Szymon Janc
@ 2014-03-19  9:23 ` Szymon Janc
  2 siblings, 0 replies; 4+ messages in thread
From: Szymon Janc @ 2014-03-19  9:23 UTC (permalink / raw)
  To: linux-bluetooth

On Tuesday 18 of March 2014 16:18:09 Szymon Janc wrote:
> 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.
> ---
>  android/bluetooth.c | 45 ++++++++++++++++++++++++++++++++++++---------
>  1 file changed, 36 insertions(+), 9 deletions(-)
> 
> diff --git a/android/bluetooth.c b/android/bluetooth.c
> index 1becdfb..000f595 100644
> --- a/android/bluetooth.c
> +++ b/android/bluetooth.c
> @@ -2697,13 +2697,18 @@ 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);
> +
> +	/* Fallback to BREDR if device is unknown eg. OOB */
> +	cp.addr.type = dev ? dev->bdaddr_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;
> @@ -2724,17 +2729,28 @@ 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);
> 
> +	dev = find_device(&cp.bdaddr);
> +	if (!dev) {
> +		status = HAL_STATUS_FAILED;
> +		goto failed;
> +	}
> +
> +	cp.type = 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_SUCCESS;
> -	else
> +				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);
>  }
> @@ -2757,19 +2773,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->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);
>  }

This is not handling dual mode devices correctly. Please ignore for now.

-- 
BR
Szymon Janc

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

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

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-03-18 15:18 [PATCH 1/3] android/bluetooth: Pass correct device type for bonding commands Szymon Janc
2014-03-18 15:18 ` [PATCH 2/3] android/bluetooth: Add support for loading LTKs Szymon Janc
2014-03-18 15:18 ` [PATCH 3/3] android/bluetooth: Add support for new long term key mgmt event Szymon Janc
2014-03-19  9:23 ` [PATCH 1/3] android/bluetooth: Pass correct device type for bonding commands Szymon Janc

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox