diff mbox series

[BlueZ,3/5] shared/att: Add bt_att_register_exchange

Message ID 20210928235447.3077055-3-luiz.dentz@gmail.com (mailing list archive)
State Accepted
Delegated to: Brian Gix
Headers show
Series [BlueZ,1/5] gatt-api: Add MTU property to GattCharacteristic1 | expand

Checks

Context Check Description
tedd_an/checkpatch success Checkpatch PASS
tedd_an/gitlint success Gitlint PASS

Commit Message

Luiz Augusto von Dentz Sept. 28, 2021, 11:54 p.m. UTC
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

This adds bt_att_register_exchange which can be used to register
handlers that gets notified when the MTU gets changed via MTU exchange
procedure.
---
 src/shared/att.c | 94 +++++++++++++++++++++++++++++++++++++++++++++++-
 src/shared/att.h |  6 ++++
 2 files changed, 99 insertions(+), 1 deletion(-)
diff mbox series

Patch

diff --git a/src/shared/att.c b/src/shared/att.c
index 329497728..2387fe4c3 100644
--- a/src/shared/att.c
+++ b/src/shared/att.c
@@ -64,6 +64,7 @@  struct bt_att {
 
 	struct queue *notify_list;	/* List of registered callbacks */
 	struct queue *disconn_list;	/* List of disconnect handlers */
+	struct queue *exchange_list;	/* List of MTU changed handlers */
 
 	unsigned int next_send_id;	/* IDs for "send" ops */
 	unsigned int next_reg_id;	/* IDs for registered callbacks */
@@ -257,6 +258,14 @@  struct att_disconn {
 	void *user_data;
 };
 
+struct att_exchange {
+	unsigned int id;
+	bool removed;
+	bt_att_exchange_func_t callback;
+	bt_att_destroy_func_t destroy;
+	void *user_data;
+};
+
 static void destroy_att_disconn(void *data)
 {
 	struct att_disconn *disconn = data;
@@ -267,6 +276,16 @@  static void destroy_att_disconn(void *data)
 	free(disconn);
 }
 
+static void destroy_att_exchange(void *data)
+{
+	struct att_exchange *exchange = data;
+
+	if (exchange->destroy)
+		exchange->destroy(exchange->user_data);
+
+	free(exchange);
+}
+
 static bool match_disconn_id(const void *a, const void *b)
 {
 	const struct att_disconn *disconn = a;
@@ -1116,6 +1135,7 @@  static void bt_att_free(struct bt_att *att)
 	queue_destroy(att->write_queue, NULL);
 	queue_destroy(att->notify_list, NULL);
 	queue_destroy(att->disconn_list, NULL);
+	queue_destroy(att->exchange_list, NULL);
 	queue_destroy(att->chans, bt_att_chan_free);
 
 	free(att);
@@ -1242,6 +1262,7 @@  struct bt_att *bt_att_new(int fd, bool ext_signed)
 	att->write_queue = queue_new();
 	att->notify_list = queue_new();
 	att->disconn_list = queue_new();
+	att->exchange_list = queue_new();
 
 	bt_att_attach_chan(att, chan);
 
@@ -1357,6 +1378,18 @@  uint16_t bt_att_get_mtu(struct bt_att *att)
 	return att->mtu;
 }
 
+static void exchange_handler(void *data, void *user_data)
+{
+	struct att_exchange *exchange = data;
+	uint16_t mtu = PTR_TO_INT(user_data);
+
+	if (exchange->removed)
+		return;
+
+	if (exchange->callback)
+		exchange->callback(mtu, exchange->user_data);
+}
+
 bool bt_att_set_mtu(struct bt_att *att, uint16_t mtu)
 {
 	struct bt_att_chan *chan;
@@ -1382,8 +1415,11 @@  bool bt_att_set_mtu(struct bt_att *att, uint16_t mtu)
 	chan->mtu = mtu;
 	chan->buf = buf;
 
-	if (chan->mtu > att->mtu)
+	if (chan->mtu > att->mtu) {
 		att->mtu = chan->mtu;
+		queue_foreach(att->exchange_list, exchange_handler,
+						INT_TO_PTR(att->mtu));
+	}
 
 	return true;
 }
@@ -1474,6 +1510,61 @@  bool bt_att_unregister_disconnect(struct bt_att *att, unsigned int id)
 	return true;
 }
 
+unsigned int bt_att_register_exchange(struct bt_att *att,
+					bt_att_exchange_func_t callback,
+					void *user_data,
+					bt_att_destroy_func_t destroy)
+{
+	struct att_exchange *mtu;
+
+	if (!att || queue_isempty(att->chans))
+		return 0;
+
+	mtu = new0(struct att_exchange, 1);
+	mtu->callback = callback;
+	mtu->destroy = destroy;
+	mtu->user_data = user_data;
+
+	if (att->next_reg_id < 1)
+		att->next_reg_id = 1;
+
+	mtu->id = att->next_reg_id++;
+
+	if (!queue_push_tail(att->exchange_list, mtu)) {
+		free(att);
+		return 0;
+	}
+
+	return mtu->id;
+}
+
+bool bt_att_unregister_exchange(struct bt_att *att, unsigned int id)
+{
+	struct att_exchange *mtu;
+
+	if (!att || !id)
+		return false;
+
+	/* Check if disconnect is running */
+	if (queue_isempty(att->chans)) {
+		mtu = queue_find(att->exchange_list, match_disconn_id,
+							UINT_TO_PTR(id));
+		if (!mtu)
+			return false;
+
+		mtu->removed = true;
+		return true;
+	}
+
+	mtu = queue_remove_if(att->exchange_list, match_disconn_id,
+							UINT_TO_PTR(id));
+	if (!mtu)
+		return false;
+
+	destroy_att_exchange(mtu);
+	return true;
+}
+
 unsigned int bt_att_send(struct bt_att *att, uint8_t opcode,
 				const void *pdu, uint16_t length,
 				bt_att_response_func_t callback, void *user_data,
@@ -1785,6 +1876,7 @@  bool bt_att_unregister_all(struct bt_att *att)
 
 	queue_remove_all(att->notify_list, NULL, NULL, destroy_att_notify);
 	queue_remove_all(att->disconn_list, NULL, NULL, destroy_att_disconn);
+	queue_remove_all(att->exchange_list, NULL, NULL, destroy_att_exchange);
 
 	return true;
 }
diff --git a/src/shared/att.h b/src/shared/att.h
index 03a450988..de136a066 100644
--- a/src/shared/att.h
+++ b/src/shared/att.h
@@ -43,6 +43,7 @@  typedef void (*bt_att_debug_func_t)(const char *str, void *user_data);
 typedef void (*bt_att_timeout_func_t)(unsigned int id, uint8_t opcode,
 							void *user_data);
 typedef void (*bt_att_disconnect_func_t)(int err, void *user_data);
+typedef void (*bt_att_exchange_func_t)(uint16_t mtu, void *user_data);
 typedef bool (*bt_att_counter_func_t)(uint32_t *sign_cnt, void *user_data);
 
 bool bt_att_set_debug(struct bt_att *att, uint8_t level,
@@ -88,6 +89,11 @@  unsigned int bt_att_register_disconnect(struct bt_att *att,
 					bt_att_destroy_func_t destroy);
 bool bt_att_unregister_disconnect(struct bt_att *att, unsigned int id);
 
+unsigned int bt_att_register_exchange(struct bt_att *att,
+					bt_att_exchange_func_t callback,
+					void *user_data,
+					bt_att_destroy_func_t destroy);
+bool bt_att_unregister_exchange(struct bt_att *att, unsigned int id);
 bool bt_att_unregister_all(struct bt_att *att);
 
 int bt_att_get_security(struct bt_att *att, uint8_t *enc_size);