shared/att: Add bt_att_register_exchange
authorLuiz Augusto von Dentz <luiz.von.dentz@intel.com>
Tue, 28 Sep 2021 23:07:10 +0000 (16:07 -0700)
committerAyush Garg <ayush.garg@samsung.com>
Fri, 11 Mar 2022 13:38:37 +0000 (19:08 +0530)
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.

Signed-off-by: Anuj Jain <anuj01.jain@samsung.com>
Signed-off-by: Ayush Garg <ayush.garg@samsung.com>
src/shared/att.c
src/shared/att.h

index 0dd7700979db7f5372473cfbbd4fa1f82c6740bc..5feb1e9bcda45b5b2d8e1d406d7a642af1852c1f 100755 (executable)
@@ -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 */
@@ -263,6 +264,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;
@@ -273,6 +282,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;
@@ -1139,6 +1158,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);
@@ -1265,6 +1285,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);
 
@@ -1380,6 +1401,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;
@@ -1404,8 +1437,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;
 }
@@ -1496,6 +1532,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,
@@ -1806,6 +1897,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;
 }
index 233f717817f6d9f4b3f83f1cb8f7866b36bef553..4b13fa5c620ded8cd7814c8f4a71f5361854cd95 100755 (executable)
@@ -46,6 +46,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,
@@ -91,6 +92,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);