diff mbox series

[BlueZ,19/22] shared/gatt: Add support for Handle Value Multiple Notifications

Message ID 20200108003342.15458-20-luiz.dentz@gmail.com
State New
Headers show
Series None | expand

Commit Message

Luiz Augusto von Dentz Jan. 8, 2020, 12:33 a.m. UTC
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

Handle Value Multiple Notification can be used to notify multiple
values at once.
---
 src/shared/att-types.h   |  7 ++--
 src/shared/att.c         | 16 ++++-----
 src/shared/gatt-client.c | 76 ++++++++++++++++++++++++++--------------
 src/shared/gatt-server.c |  4 +--
 4 files changed, 64 insertions(+), 39 deletions(-)
diff mbox series

Patch

diff --git a/src/shared/att-types.h b/src/shared/att-types.h
index cc9cc9fd6..99b108990 100644
--- a/src/shared/att-types.h
+++ b/src/shared/att-types.h
@@ -72,11 +72,12 @@ 
 #define BT_ATT_OP_PREP_WRITE_RSP		0x17
 #define BT_ATT_OP_EXEC_WRITE_REQ		0x18
 #define BT_ATT_OP_EXEC_WRITE_RSP		0x19
-#define BT_ATT_OP_HANDLE_VAL_NOT		0x1B
-#define BT_ATT_OP_HANDLE_VAL_IND		0x1D
-#define BT_ATT_OP_HANDLE_VAL_CONF		0x1E
+#define BT_ATT_OP_HANDLE_NFY			0x1B
+#define BT_ATT_OP_HANDLE_IND			0x1D
+#define BT_ATT_OP_HANDLE_CONF			0x1E
 #define BT_ATT_OP_READ_MULT_VL_REQ		0x20
 #define BT_ATT_OP_READ_MULT_VL_RSP		0x21
+#define BT_ATT_OP_HANDLE_NFY_MULT		0x23
 
 /* Packed struct definitions for ATT protocol PDUs */
 /* TODO: Complete these definitions for all opcodes */
diff --git a/src/shared/att.c b/src/shared/att.c
index 56ea40c46..6fa16e422 100644
--- a/src/shared/att.c
+++ b/src/shared/att.c
@@ -110,7 +110,7 @@  enum att_op_type {
 	ATT_OP_TYPE_RSP,
 	ATT_OP_TYPE_CMD,
 	ATT_OP_TYPE_IND,
-	ATT_OP_TYPE_NOT,
+	ATT_OP_TYPE_NFY,
 	ATT_OP_TYPE_CONF,
 	ATT_OP_TYPE_UNKNOWN,
 };
@@ -144,9 +144,9 @@  static const struct {
 	{ BT_ATT_OP_PREP_WRITE_RSP,		ATT_OP_TYPE_RSP },
 	{ BT_ATT_OP_EXEC_WRITE_REQ,		ATT_OP_TYPE_REQ },
 	{ BT_ATT_OP_EXEC_WRITE_RSP,		ATT_OP_TYPE_RSP },
-	{ BT_ATT_OP_HANDLE_VAL_NOT,		ATT_OP_TYPE_NOT },
-	{ BT_ATT_OP_HANDLE_VAL_IND,		ATT_OP_TYPE_IND },
-	{ BT_ATT_OP_HANDLE_VAL_CONF,		ATT_OP_TYPE_CONF },
+	{ BT_ATT_OP_HANDLE_NFY,			ATT_OP_TYPE_NFY },
+	{ BT_ATT_OP_HANDLE_IND,			ATT_OP_TYPE_IND },
+	{ BT_ATT_OP_HANDLE_CONF,		ATT_OP_TYPE_CONF },
 	{ }
 };
 
@@ -530,7 +530,7 @@  static bool can_write_data(struct io *io, void *user_data)
 		chan->in_req = false;
 		/* fall through */
 	case ATT_OP_TYPE_CMD:
-	case ATT_OP_TYPE_NOT:
+	case ATT_OP_TYPE_NFY:
 	case ATT_OP_TYPE_CONF:
 	case ATT_OP_TYPE_UNKNOWN:
 	default:
@@ -842,7 +842,7 @@  static void handle_conf(struct bt_att_chan *chan, uint8_t *pdu, ssize_t pdu_len)
 	}
 
 	if (op->callback)
-		op->callback(BT_ATT_OP_HANDLE_VAL_CONF, NULL, 0, op->user_data);
+		op->callback(BT_ATT_OP_HANDLE_NFY, NULL, 0, op->user_data);
 
 	destroy_att_send_op(op);
 	chan->pending_ind = NULL;
@@ -1042,7 +1042,7 @@  static bool can_read_data(struct io *io, void *user_data)
 		chan->in_req = true;
 		/* fall through */
 	case ATT_OP_TYPE_CMD:
-	case ATT_OP_TYPE_NOT:
+	case ATT_OP_TYPE_NFY:
 	case ATT_OP_TYPE_UNKNOWN:
 	case ATT_OP_TYPE_IND:
 		/* fall through */
@@ -1492,7 +1492,7 @@  unsigned int bt_att_send(struct bt_att *att, uint8_t opcode,
 		result = queue_push_tail(att->ind_queue, op);
 		break;
 	case ATT_OP_TYPE_CMD:
-	case ATT_OP_TYPE_NOT:
+	case ATT_OP_TYPE_NFY:
 	case ATT_OP_TYPE_UNKNOWN:
 	case ATT_OP_TYPE_RSP:
 	case ATT_OP_TYPE_CONF:
diff --git a/src/shared/gatt-client.c b/src/shared/gatt-client.c
index aecf0ca5a..8c563cdcc 100644
--- a/src/shared/gatt-client.c
+++ b/src/shared/gatt-client.c
@@ -95,7 +95,7 @@  struct bt_gatt_client {
 	struct queue *notify_list;
 	struct queue *notify_chrcs;
 	int next_reg_id;
-	unsigned int disc_id, notify_id, ind_id;
+	unsigned int disc_id, nfy_id, nfy_mult_id, ind_id;
 
 	/*
 	 * Handles of the GATT Service and the Service Changed characteristic
@@ -2069,9 +2069,10 @@  done:
 	return true;
 }
 
-struct pdu_data {
-	const void *pdu;
-	uint16_t length;
+struct value_data {
+	uint16_t handle;
+	uint16_t len;
+	const void *data;
 };
 
 static void disable_ccc_callback(uint8_t opcode, const void *pdu,
@@ -2122,25 +2123,18 @@  done:
 static void notify_handler(void *data, void *user_data)
 {
 	struct notify_data *notify_data = data;
-	struct pdu_data *pdu_data = user_data;
-	uint16_t value_handle;
-	const uint8_t *value = NULL;
-
-	value_handle = get_le16(pdu_data->pdu);
+	struct value_data *value_data = user_data;
 
-	if (notify_data->chrc->value_handle != value_handle)
+	if (notify_data->chrc->value_handle != value_data->handle)
 		return;
 
-	if (pdu_data->length > 2)
-		value = pdu_data->pdu + 2;
-
 	/*
 	 * Even if the notify data has a pending ATT request to write to the
 	 * CCC, there is really no reason not to notify the handlers.
 	 */
 	if (notify_data->notify)
-		notify_data->notify(value_handle, value, pdu_data->length - 2,
-							notify_data->user_data);
+		notify_data->notify(value_data->handle, value_data->data,
+				value_data->len, notify_data->user_data);
 }
 
 static void notify_cb(struct bt_att_chan *chan, uint8_t opcode,
@@ -2148,18 +2142,42 @@  static void notify_cb(struct bt_att_chan *chan, uint8_t opcode,
 					void *user_data)
 {
 	struct bt_gatt_client *client = user_data;
-	struct pdu_data pdu_data;
+	struct value_data data;
 
 	bt_gatt_client_ref(client);
 
-	memset(&pdu_data, 0, sizeof(pdu_data));
-	pdu_data.pdu = pdu;
-	pdu_data.length = length;
+	memset(&data, 0, sizeof(data));
+
+	if (opcode == BT_ATT_OP_HANDLE_NFY_MULT) {
+		while (length >= 4) {
+			data.handle = get_le16(pdu);
+			length -= 2;
+			pdu += 2;
+
+			data.len = get_le16(pdu);
+			length -= 2;
+			pdu += 2;
+
+			data.data = pdu;
+
+			queue_foreach(client->notify_list, notify_handler,
+								&data);
 
-	queue_foreach(client->notify_list, notify_handler, &pdu_data);
+			length -= data.len;
+		}
+	} else {
+		data.handle = get_le16(pdu);
+		length -= 2;
+		pdu += 2;
+
+		data.len = length;
+		data.data = pdu;
 
-	if (opcode == BT_ATT_OP_HANDLE_VAL_IND && !client->parent)
-		bt_att_chan_send(chan, BT_ATT_OP_HANDLE_VAL_CONF, NULL, 0,
+		queue_foreach(client->notify_list, notify_handler, &data);
+	}
+
+	if (opcode == BT_ATT_OP_HANDLE_IND && !client->parent)
+		bt_att_chan_send(chan, BT_ATT_OP_HANDLE_CONF, NULL, 0,
 							NULL, NULL, NULL);
 
 	bt_gatt_client_unref(client);
@@ -2178,7 +2196,8 @@  static void bt_gatt_client_free(struct bt_gatt_client *client)
 
 	if (client->att) {
 		bt_att_unregister_disconnect(client->att, client->disc_id);
-		bt_att_unregister(client->att, client->notify_id);
+		bt_att_unregister(client->att, client->nfy_id);
+		bt_att_unregister(client->att, client->nfy_mult_id);
 		bt_att_unregister(client->att, client->ind_id);
 		bt_att_unref(client->att);
 	}
@@ -2236,12 +2255,17 @@  static struct bt_gatt_client *gatt_client_new(struct gatt_db *db,
 	client->notify_chrcs = queue_new();
 	client->pending_requests = queue_new();
 
-	client->notify_id = bt_att_register(att, BT_ATT_OP_HANDLE_VAL_NOT,
+	client->nfy_id = bt_att_register(att, BT_ATT_OP_HANDLE_NFY,
+						notify_cb, client, NULL);
+	if (!client->nfy_id)
+		goto fail;
+
+	client->nfy_mult_id = bt_att_register(att, BT_ATT_OP_HANDLE_NFY_MULT,
 						notify_cb, client, NULL);
-	if (!client->notify_id)
+	if (!client->nfy_mult_id)
 		goto fail;
 
-	client->ind_id = bt_att_register(att, BT_ATT_OP_HANDLE_VAL_IND,
+	client->ind_id = bt_att_register(att, BT_ATT_OP_HANDLE_IND,
 						notify_cb, client, NULL);
 	if (!client->ind_id)
 		goto fail;
diff --git a/src/shared/gatt-server.c b/src/shared/gatt-server.c
index 55535abdf..0711f1d75 100644
--- a/src/shared/gatt-server.c
+++ b/src/shared/gatt-server.c
@@ -1748,7 +1748,7 @@  bool bt_gatt_server_send_notification(struct bt_gatt_server *server,
 	put_le16(handle, pdu);
 	memcpy(pdu + 2, value, pdu_len - 2);
 
-	result = !!bt_att_send(server->att, BT_ATT_OP_HANDLE_VAL_NOT, pdu,
+	result = !!bt_att_send(server->att, BT_ATT_OP_HANDLE_NFY, pdu,
 						pdu_len, NULL, NULL, NULL);
 	free(pdu);
 
@@ -1809,7 +1809,7 @@  bool bt_gatt_server_send_indication(struct bt_gatt_server *server,
 	put_le16(handle, pdu);
 	memcpy(pdu + 2, value, pdu_len - 2);
 
-	result = !!bt_att_send(server->att, BT_ATT_OP_HANDLE_VAL_IND, pdu,
+	result = !!bt_att_send(server->att, BT_ATT_OP_HANDLE_IND, pdu,
 							pdu_len, conf_cb,
 							data, destroy_ind_data);
 	if (!result)