[PATCH] Add signed write command

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

 



Add bt_att_set_csrk for btgatt-client tool. However this patch hook into
shared/mgmt, so btgatt-client now should be running by the root user.
---
 src/shared/att-types.h   |    3 ++
 src/shared/att.c         |   49 ++++++++++++++++--
 src/shared/att.h         |    2 +
 src/shared/gatt-client.c |   11 ++--
 tools/btgatt-client.c    |  129 ++++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 186 insertions(+), 8 deletions(-)

diff --git a/src/shared/att-types.h b/src/shared/att-types.h
index b85c969..da8b6ae 100644
--- a/src/shared/att-types.h
+++ b/src/shared/att-types.h
@@ -25,6 +25,9 @@
 
 #define BT_ATT_DEFAULT_LE_MTU 23
 
+/* Length of signature in write signed packet */
+#define BT_ATT_SIGNATURE_LEN		12
+
 /* ATT protocol opcodes */
 #define BT_ATT_OP_ERROR_RSP	      		0x01
 #define BT_ATT_OP_MTU_REQ			0x02
diff --git a/src/shared/att.c b/src/shared/att.c
index a5cab45..aadef9e 100644
--- a/src/shared/att.c
+++ b/src/shared/att.c
@@ -36,6 +36,7 @@
 #include "lib/uuid.h"
 #include "src/shared/att.h"
 #include "src/shared/att-types.h"
+#include "src/shared/crypto.h"
 
 #define ATT_MIN_PDU_LEN			1  /* At least 1 byte for the opcode. */
 #define ATT_OP_CMD_MASK			0x40
@@ -77,6 +78,11 @@ struct bt_att {
 	bt_att_debug_func_t debug_callback;
 	bt_att_destroy_func_t debug_destroy;
 	void *debug_data;
+
+	struct bt_crypto *crypto;
+
+	uint8_t local_csrk[16];
+	uint32_t local_sign_cnt;
 };
 
 enum att_op_type {
@@ -176,6 +182,8 @@ struct att_send_op {
 	bt_att_response_func_t callback;
 	bt_att_destroy_func_t destroy;
 	void *user_data;
+
+	struct bt_att *att;
 };
 
 static void destroy_att_send_op(void *data)
@@ -277,6 +285,10 @@ static bool encode_pdu(struct att_send_op *op, const void *pdu,
 						uint16_t length, uint16_t mtu)
 {
 	uint16_t pdu_len = 1;
+	struct bt_att *att = op->att;
+
+	if (op->opcode & ATT_OP_SIGNED_MASK)
+		pdu_len += BT_ATT_SIGNATURE_LEN;
 
 	if (length && pdu)
 		pdu_len += length;
@@ -293,17 +305,32 @@ static bool encode_pdu(struct att_send_op *op, const void *pdu,
 	if (pdu_len > 1)
 		memcpy(op->pdu + 1, pdu, length);
 
+	if (op->opcode & ATT_OP_SIGNED_MASK) {
+		if (bt_crypto_sign_att(att->crypto,
+					att->local_csrk,
+					op->pdu,
+					1 + length,
+					att->local_sign_cnt,
+					&((uint8_t *) op->pdu)[1 + length]))
+			att->local_sign_cnt++;
+		else
+			return false;
+	}
+
 	return true;
 }
 
-static struct att_send_op *create_att_send_op(uint8_t opcode, const void *pdu,
-						uint16_t length, uint16_t mtu,
+static struct att_send_op *create_att_send_op(uint8_t opcode,
+						const void *pdu,
+						uint16_t length,
+						struct bt_att *att,
 						bt_att_response_func_t callback,
 						void *user_data,
 						bt_att_destroy_func_t destroy)
 {
 	struct att_send_op *op;
 	enum att_op_type op_type;
+	uint16_t mtu = att->mtu;
 
 	if (length && !pdu)
 		return NULL;
@@ -334,6 +361,7 @@ static struct att_send_op *create_att_send_op(uint8_t opcode, const void *pdu,
 	op->callback = callback;
 	op->destroy = destroy;
 	op->user_data = user_data;
+	op->att = att;
 
 	if (!encode_pdu(op, pdu, length, mtu)) {
 		free(op);
@@ -707,6 +735,10 @@ struct bt_att *bt_att_new(int fd)
 	if (!att->io)
 		goto fail;
 
+	att->crypto = bt_crypto_new();
+	if (!att->crypto)
+		goto fail;
+
 	att->req_queue = queue_new();
 	if (!att->req_queue)
 		goto fail;
@@ -741,6 +773,7 @@ fail:
 	queue_destroy(att->write_queue, NULL);
 	queue_destroy(att->notify_list, NULL);
 	queue_destroy(att->disconn_list, NULL);
+	bt_crypto_unref(att->crypto);
 	io_destroy(att->io);
 	free(att->buf);
 	free(att);
@@ -931,7 +964,7 @@ unsigned int bt_att_send(struct bt_att *att, uint8_t opcode,
 	if (!att || !att->io)
 		return 0;
 
-	op = create_att_send_op(opcode, pdu, length, att->mtu, callback,
+	op = create_att_send_op(opcode, pdu, length, att, callback,
 							user_data, destroy);
 	if (!op)
 		return 0;
@@ -1116,3 +1149,13 @@ bool bt_att_unregister_all(struct bt_att *att)
 
 	return true;
 }
+
+void bt_att_set_csrk(struct bt_att *att,
+			const uint8_t *val,
+			uint32_t local_sign_cnt)
+{
+	memcpy(att->local_csrk, val, 16);
+	att->local_sign_cnt = local_sign_cnt;
+}
+
+
diff --git a/src/shared/att.h b/src/shared/att.h
index 1063021..b76e5f5 100644
--- a/src/shared/att.h
+++ b/src/shared/att.h
@@ -76,3 +76,5 @@ unsigned int bt_att_register_disconnect(struct bt_att *att,
 bool bt_att_unregister_disconnect(struct bt_att *att, unsigned int id);
 
 bool bt_att_unregister_all(struct bt_att *att);
+
+void bt_att_set_csrk(struct bt_att *att, const uint8_t *val, uint32_t local_sign_cnt);
diff --git a/src/shared/gatt-client.c b/src/shared/gatt-client.c
index 1a157ec..b1619c6 100644
--- a/src/shared/gatt-client.c
+++ b/src/shared/gatt-client.c
@@ -973,19 +973,20 @@ bool bt_gatt_client_read_long_value(struct bt_gatt_client *client,
 bool bt_gatt_client_write_without_response(struct bt_gatt_client *client,
 					uint16_t value_handle,
 					bool signed_write,
-					uint8_t *value, uint16_t length) {
+					uint8_t *value, uint16_t length)
+{
 	uint8_t pdu[2 + length];
 
 	if (!client)
 		return 0;
 
-	/* TODO: Support this once bt_att_send supports signed writes. */
-	if (signed_write)
-		return 0;
-
 	put_le16(value_handle, pdu);
 	memcpy(pdu + 2, value, length);
 
+	if (signed_write)
+		return bt_att_send(client->att, BT_ATT_OP_SIGNED_WRITE_CMD,
+					pdu, sizeof(pdu), NULL, NULL, NULL);
+
 	return bt_att_send(client->att, BT_ATT_OP_WRITE_CMD, pdu, sizeof(pdu),
 							NULL, NULL, NULL);
 }
diff --git a/tools/btgatt-client.c b/tools/btgatt-client.c
index d1395b2..fdf8485 100644
--- a/tools/btgatt-client.c
+++ b/tools/btgatt-client.c
@@ -38,11 +38,14 @@
 #include <bluetooth/hci_lib.h>
 #include <bluetooth/l2cap.h>
 #include "lib/uuid.h"
+#include "lib/bluetooth.h"
+#include "lib/mgmt.h"
 
 #include "monitor/mainloop.h"
 #include "src/shared/util.h"
 #include "src/shared/att.h"
 #include "src/shared/gatt-client.h"
+#include "src/shared/mgmt.h"
 
 #define ATT_CID 4
 
@@ -59,6 +62,8 @@
 #define COLOR_BOLDWHITE	"\x1B[1;37m"
 
 static bool verbose = false;
+static struct mgmt *mgmt_if = NULL;
+static uint16_t adapter_index = MGMT_INDEX_NONE;
 
 struct client {
 	int fd;
@@ -92,6 +97,115 @@ static void gatt_debug_cb(const char *str, void *user_data)
 	PRLOG(COLOR_GREEN "%s%s\n" COLOR_OFF, prefix, str);
 }
 
+static void new_csrk_callback(uint16_t index, uint16_t length,
+					const void *param, void *user_data)
+{
+	const struct mgmt_ev_new_csrk *ev = param;
+	struct bt_att *att = user_data;
+
+	if (length < sizeof(*ev)) {
+		fprintf(stderr, "Too small csrk event (%u bytes)\n", length);
+		return;
+	}
+
+	switch (ev->key.master) {
+	case 0x00:
+		bt_att_set_csrk(att, ev->key.val, 0);
+		break;
+	case 0x01:
+		break;
+	default:
+		fprintf(stderr,
+			"Unknown CSRK key type 02%02x\n", ev->key.master);
+		return;
+	}
+}
+
+static void mgmt_index_added_event(uint16_t index, uint16_t length,
+					const void *param, void *user_data)
+{
+	struct bt_att *att = user_data;
+
+	printf("index %u\n", index);
+
+	if (adapter_index != MGMT_INDEX_NONE) {
+		fprintf(stderr, "skip event for index %u\n", index);
+		return;
+	}
+
+	adapter_index = index;
+
+	mgmt_register(mgmt_if, MGMT_EV_NEW_CSRK, adapter_index,
+						new_csrk_callback, att, NULL);
+}
+
+static void mgmt_index_removed_event(uint16_t index, uint16_t length,
+					const void *param, void *user_data)
+{
+	if (index != adapter_index)
+		return;
+
+	perror("Adapter was removed. Exiting.\n");
+	raise(SIGTERM);
+}
+
+static void read_version_complete(uint8_t status, uint16_t length,
+					const void *param, void *user_data)
+{
+	const struct mgmt_rp_read_version *rp = param;
+	uint8_t mgmt_version, mgmt_revision;
+	struct bt_att *att = user_data;
+
+	if (status) {
+		fprintf(stderr,
+			"Failed to read version information: %s (0x%02x)\n",
+						mgmt_errstr(status), status);
+		return;
+	}
+
+	if (length < sizeof(*rp)) {
+		perror("Wrong size response\n");
+		return;
+	}
+
+	mgmt_version = rp->version;
+	mgmt_revision = btohs(rp->revision);
+
+	printf("Bluetooth management interface %u.%u initialized\n",
+						mgmt_version, mgmt_revision);
+
+	if (MGMT_VERSION(mgmt_version, mgmt_revision) < MGMT_VERSION(1, 3)) {
+		perror("Version 1.3 later of management interface required\n");
+		return;
+	}
+
+	mgmt_register(mgmt_if, MGMT_EV_INDEX_ADDED, MGMT_INDEX_NONE,
+					mgmt_index_added_event, att, NULL);
+	mgmt_register(mgmt_if, MGMT_EV_INDEX_REMOVED, MGMT_INDEX_NONE,
+					mgmt_index_removed_event, NULL, NULL);
+}
+
+static bool mgmt_create(struct bt_att *att)
+{
+	mgmt_if = mgmt_new_default();
+	if (!mgmt_if) {
+		perror("Failed to access management interface\n");
+		return false;
+	}
+
+	if (mgmt_send(mgmt_if, MGMT_OP_READ_VERSION, MGMT_INDEX_NONE, 0, NULL,
+				read_version_complete, att, NULL) == 0) {
+		perror("Error sending READ_VERSION mgmt command\n");
+
+		mgmt_unref(mgmt_if);
+		mgmt_if = NULL;
+
+		return false;
+	}
+
+	return true;
+}
+
 static void ready_cb(bool success, uint8_t att_ecode, void *user_data);
 
 static struct client *client_create(int fd, uint16_t mtu)
@@ -136,6 +250,13 @@ static struct client *client_create(int fd, uint16_t mtu)
 		return NULL;
 	}
 
+	if (!mgmt_create(att)) {
+		fprintf(stderr, "Failed to create management interface\n");
+		bt_att_unref(att);
+		free(cli);
+		return NULL;
+	}
+
 	if (verbose) {
 		bt_att_set_debug(att, att_debug_cb, "att: ", NULL);
 		bt_gatt_client_set_debug(cli->gatt, gatt_debug_cb, "gatt: ",
@@ -155,6 +276,12 @@ static void client_destroy(struct client *cli)
 	bt_gatt_client_unref(cli->gatt);
 }
 
+static void mgmt_destroy(struct mgmt *mgmt_if)
+{
+	mgmt_unref(mgmt_if);
+	mgmt_if = NULL;
+}
+
 static void print_uuid(const uint8_t uuid[16])
 {
 	char uuid_str[MAX_LEN_UUID_STR];
@@ -1029,5 +1156,7 @@ int main(int argc, char *argv[])
 
 	client_destroy(cli);
 
+	mgmt_destroy(mgmt_if);
+
 	return EXIT_SUCCESS;
 }
-- 
1.7.10.4

--
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