Bluetooth: Host: Make tx complete callback work for EATT channels

Previously, if a callback was set for notifications, they would always be
sent over unenhanced ATT.

The nfy_mult_data was bigger than the buffer user_data and we were this
overflowing the buffer when setting the tx callback user_data. Now the
data is stored separately and only a pointer to it is added to the
buffer user_data.

Signed-off-by: Herman Berget <herman.berget@nordicsemi.no>
This commit is contained in:
Herman Berget 2022-03-25 14:27:44 +01:00 committed by Carles Cufí
commit c8b2279f89
3 changed files with 196 additions and 93 deletions

View file

@ -90,7 +90,6 @@ struct bt_att_chan {
struct bt_att_req *req;
struct k_fifo tx_queue;
struct k_work_delayable timeout_work;
void (*sent)(struct bt_att_chan *chan);
sys_snode_t node;
};
@ -133,17 +132,45 @@ static struct bt_att_req cancel;
*/
static k_tid_t att_handle_rsp_thread;
typedef void (*bt_att_chan_sent_t)(struct bt_att_chan *chan);
struct bt_att_tx_meta_data {
struct bt_att_chan *att_chan;
bt_conn_tx_cb_t func;
void *user_data;
};
static bt_att_chan_sent_t chan_cb(struct net_buf *buf);
static bt_conn_tx_cb_t att_cb(bt_att_chan_sent_t cb);
struct bt_att_tx_meta {
struct bt_att_tx_meta_data *data;
};
#define bt_att_tx_meta_data(buf) (((struct bt_att_tx_meta *)net_buf_user_data(buf))->data)
static struct bt_att_tx_meta_data tx_meta_data[CONFIG_BT_CONN_TX_MAX];
K_FIFO_DEFINE(free_att_tx_meta_data);
static struct bt_att_tx_meta_data *tx_meta_data_alloc(void)
{
return k_fifo_get(&free_att_tx_meta_data, K_NO_WAIT);
}
static inline void tx_meta_data_free(struct bt_att_tx_meta_data *data)
{
__ASSERT_NO_MSG(data);
(void)memset(data, 0, sizeof(*data));
k_fifo_put(&free_att_tx_meta_data, data);
}
static bt_conn_tx_cb_t chan_cb(const struct net_buf *buf);
static bt_conn_tx_cb_t att_cb(const struct net_buf *buf);
static void att_chan_mtu_updated(struct bt_att_chan *updated_chan);
static void bt_att_disconnected(struct bt_l2cap_chan *chan);
void att_sent(struct bt_conn *conn, void *user_data)
{
struct bt_l2cap_chan *chan = user_data;
struct bt_att_tx_meta_data *data = user_data;
struct bt_att_chan *att_chan = data->att_chan;
struct bt_l2cap_chan *chan = &att_chan->chan.chan;
BT_DBG("conn %p chan %p", conn, chan);
@ -159,12 +186,12 @@ void att_sent(struct bt_conn *conn, void *user_data)
* In case bt_l2cap_send_cb fails the buffer state and ownership are retained
* so the buffer can be safely pushed back to the queue to be processed later.
*/
static int chan_send(struct bt_att_chan *chan, struct net_buf *buf,
bt_att_chan_sent_t cb)
static int chan_send(struct bt_att_chan *chan, struct net_buf *buf)
{
struct bt_att_hdr *hdr;
struct net_buf_simple_state state;
int err;
struct bt_att_tx_meta_data *data = bt_att_tx_meta_data(buf);
hdr = (void *)buf->data;
@ -191,8 +218,6 @@ static int chan_send(struct bt_att_chan *chan, struct net_buf *buf,
return -EAGAIN;
}
chan->sent = cb ? cb : chan_cb(buf);
if (hdr->code == BT_ATT_OP_SIGNED_WRITE_CMD) {
return -ENOTSUP;
}
@ -212,10 +237,12 @@ static int chan_send(struct bt_att_chan *chan, struct net_buf *buf,
return -EINVAL;
}
data->att_chan = chan;
/* bt_l2cap_chan_send does actually return the number of bytes
* that could be sent immediately.
*/
err = bt_l2cap_chan_send(&chan->chan.chan, buf);
err = bt_l2cap_chan_send_cb(&chan->chan.chan, buf, chan_cb(buf), data);
if (err < 0) {
return err;
}
@ -229,6 +256,7 @@ static int chan_send(struct bt_att_chan *chan, struct net_buf *buf,
err = bt_smp_sign(chan->att->conn, buf);
if (err) {
BT_ERR("Error signing data");
tx_meta_data_free(bt_att_tx_meta_data(buf));
net_buf_unref(buf);
return err;
}
@ -236,11 +264,10 @@ static int chan_send(struct bt_att_chan *chan, struct net_buf *buf,
net_buf_simple_save(&buf->b, &state);
chan->sent = cb ? cb : chan_cb(buf);
data->att_chan = chan;
err = bt_l2cap_send_cb(chan->att->conn, BT_L2CAP_CID_ATT,
buf, att_cb(chan->sent),
&chan->chan.chan);
buf, att_cb(buf), data);
if (err) {
/* In case of an error has occurred restore the buffer state */
net_buf_simple_restore(&buf->b, &state);
@ -256,7 +283,7 @@ static int process_queue(struct bt_att_chan *chan, struct k_fifo *queue)
buf = net_buf_get(queue, K_NO_WAIT);
if (buf) {
err = chan_send(chan, buf, NULL);
err = chan_send(chan, buf);
if (err) {
/* Push it back if it could not be send */
k_queue_prepend(&queue->_queue, buf);
@ -288,7 +315,7 @@ static int chan_req_send(struct bt_att_chan *chan, struct bt_att_req *req)
buf = req->buf;
req->buf = NULL;
err = chan_send(chan, buf, NULL);
err = chan_send(chan, buf);
if (err) {
/* We still have the ownership of the buffer */
req->buf = buf;
@ -306,10 +333,6 @@ static void bt_att_sent(struct bt_l2cap_chan *ch)
BT_DBG("chan %p", chan);
if (chan->sent) {
chan->sent(chan);
}
atomic_clear_bit(chan->flags, ATT_PENDING_SENT);
if (!att) {
@ -343,37 +366,73 @@ static void bt_att_sent(struct bt_l2cap_chan *ch)
(void)process_queue(chan, &att->tx_queue);
}
static void chan_cfm_sent(struct bt_att_chan *chan)
static void chan_cfm_sent(struct bt_conn *conn, void *user_data)
{
struct bt_att_tx_meta_data *data = user_data;
struct bt_att_chan *chan = data->att_chan;
BT_DBG("chan %p", chan);
if (IS_ENABLED(CONFIG_BT_ATT_ENFORCE_FLOW)) {
atomic_clear_bit(chan->flags, ATT_PENDING_CFM);
}
tx_meta_data_free(data);
}
static void chan_rsp_sent(struct bt_att_chan *chan)
static void chan_rsp_sent(struct bt_conn *conn, void *user_data)
{
struct bt_att_tx_meta_data *data = user_data;
struct bt_att_chan *chan = data->att_chan;
BT_DBG("chan %p", chan);
if (IS_ENABLED(CONFIG_BT_ATT_ENFORCE_FLOW)) {
atomic_clear_bit(chan->flags, ATT_PENDING_RSP);
}
tx_meta_data_free(data);
}
static void chan_req_sent(struct bt_att_chan *chan)
static void chan_req_sent(struct bt_conn *conn, void *user_data)
{
struct bt_att_tx_meta_data *data = user_data;
struct bt_att_chan *chan = data->att_chan;
BT_DBG("chan %p chan->req %p", chan, chan->req);
/* Start timeout work */
if (chan->req) {
k_work_reschedule(&chan->timeout_work, BT_ATT_TIMEOUT);
}
tx_meta_data_free(user_data);
}
static bt_att_chan_sent_t chan_cb(struct net_buf *buf)
static void chan_tx_complete(struct bt_conn *conn, void *user_data)
{
switch (att_op_get_type(buf->data[0])) {
struct bt_att_tx_meta_data *data = user_data;
struct bt_att_chan *chan = data->att_chan;
BT_DBG("TX Complete chan %p CID 0x%04X", chan, chan->chan.tx.cid);
if (data->func) {
data->func(conn, data->user_data);
}
tx_meta_data_free(data);
}
static void chan_unknown(struct bt_conn *conn, void *user_data)
{
tx_meta_data_free(user_data);
}
static bt_conn_tx_cb_t chan_cb(const struct net_buf *buf)
{
const att_type_t op_type = att_op_get_type(buf->data[0]);
switch (op_type) {
case ATT_RESPONSE:
return chan_rsp_sent;
case ATT_CONFIRMATION:
@ -381,58 +440,66 @@ static bt_att_chan_sent_t chan_cb(struct net_buf *buf)
case ATT_REQUEST:
case ATT_INDICATION:
return chan_req_sent;
case ATT_COMMAND:
case ATT_NOTIFICATION:
return chan_tx_complete;
default:
return NULL;
__ASSERT(false, "Unknown op type 0x%02X", op_type);
}
return chan_unknown;
}
static void att_cfm_sent(struct bt_conn *conn, void *user_data)
{
struct bt_l2cap_chan *ch = user_data;
struct bt_att_chan *chan = ATT_CHAN(ch);
BT_DBG("conn %p chan %p", conn, chan);
chan->sent = chan_cfm_sent;
att_sent(conn, user_data);
chan_cfm_sent(conn, user_data);
}
static void att_rsp_sent(struct bt_conn *conn, void *user_data)
{
struct bt_l2cap_chan *ch = user_data;
struct bt_att_chan *chan = ATT_CHAN(ch);
BT_DBG("conn %p chan %p", conn, chan);
chan->sent = chan_rsp_sent;
att_sent(conn, user_data);
chan_rsp_sent(conn, user_data);
}
static void att_req_sent(struct bt_conn *conn, void *user_data)
{
struct bt_l2cap_chan *ch = user_data;
struct bt_att_chan *chan = ATT_CHAN(ch);
BT_DBG("conn %p chan %p", conn, chan);
chan->sent = chan_req_sent;
att_sent(conn, user_data);
chan_req_sent(conn, user_data);
}
static bt_conn_tx_cb_t att_cb(bt_att_chan_sent_t cb)
static void att_tx_complete(struct bt_conn *conn, void *user_data)
{
if (cb == chan_rsp_sent) {
att_sent(conn, user_data);
chan_tx_complete(conn, user_data);
}
static void att_unknown(struct bt_conn *conn, void *user_data)
{
att_sent(conn, user_data);
chan_unknown(conn, user_data);
}
static bt_conn_tx_cb_t att_cb(const struct net_buf *buf)
{
const att_type_t op_type = att_op_get_type(buf->data[0]);
switch (op_type) {
case ATT_RESPONSE:
return att_rsp_sent;
} else if (cb == chan_cfm_sent) {
case ATT_CONFIRMATION:
return att_cfm_sent;
} else if (cb == chan_req_sent) {
case ATT_REQUEST:
case ATT_INDICATION:
return att_req_sent;
} else {
return att_sent;
case ATT_COMMAND:
case ATT_NOTIFICATION:
return att_tx_complete;
default:
__ASSERT(false, "Unknown op type 0x%02X", op_type);
}
return att_unknown;
}
struct net_buf *bt_att_chan_create_pdu(struct bt_att_chan *chan, uint8_t op,
@ -440,6 +507,7 @@ struct net_buf *bt_att_chan_create_pdu(struct bt_att_chan *chan, uint8_t op,
{
struct bt_att_hdr *hdr;
struct net_buf *buf;
struct bt_att_tx_meta_data *data;
if (len + sizeof(op) > chan->chan.tx.mtu) {
BT_WARN("ATT MTU exceeded, max %u, wanted %zu",
@ -462,19 +530,27 @@ struct net_buf *bt_att_chan_create_pdu(struct bt_att_chan *chan, uint8_t op,
return NULL;
}
data = tx_meta_data_alloc();
if (!data) {
BT_WARN("Unable to allocate ATT TX meta");
net_buf_unref(buf);
return NULL;
}
bt_att_tx_meta_data(buf) = data;
hdr = net_buf_add(buf, sizeof(*hdr));
hdr->code = op;
return buf;
}
static int bt_att_chan_send(struct bt_att_chan *chan, struct net_buf *buf,
bt_att_chan_sent_t cb)
static int bt_att_chan_send(struct bt_att_chan *chan, struct net_buf *buf)
{
BT_DBG("chan %p flags %lu code 0x%02x", chan, atomic_get(chan->flags),
((struct bt_att_hdr *)buf->data)->code);
return chan_send(chan, buf, cb);
return chan_send(chan, buf);
}
static void att_send_process(struct bt_att *att)
@ -489,7 +565,7 @@ static void att_send_process(struct bt_att *att)
}
SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&att->chans, chan, tmp, node) {
err = bt_att_chan_send(chan, buf, NULL);
err = bt_att_chan_send(chan, buf);
if (err >= 0) {
break;
}
@ -501,12 +577,11 @@ static void att_send_process(struct bt_att *att)
}
}
static void bt_att_chan_send_rsp(struct bt_att_chan *chan, struct net_buf *buf,
bt_att_chan_sent_t cb)
static void bt_att_chan_send_rsp(struct bt_att_chan *chan, struct net_buf *buf)
{
int err;
err = bt_att_chan_send(chan, buf, cb);
err = bt_att_chan_send(chan, buf);
if (err) {
/* Responses need to be sent back using the same channel */
net_buf_put(&chan->tx_queue, buf);
@ -534,7 +609,7 @@ static void send_err_rsp(struct bt_att_chan *chan, uint8_t req, uint16_t handle,
rsp->handle = sys_cpu_to_le16(handle);
rsp->error = err;
bt_att_chan_send_rsp(chan, buf, chan_rsp_sent);
bt_att_chan_send_rsp(chan, buf);
}
static uint8_t att_mtu_req(struct bt_att_chan *chan, struct net_buf *buf)
@ -575,7 +650,7 @@ static uint8_t att_mtu_req(struct bt_att_chan *chan, struct net_buf *buf)
rsp = net_buf_add(pdu, sizeof(*rsp));
rsp->mtu = sys_cpu_to_le16(mtu_server);
bt_att_chan_send_rsp(chan, pdu, chan_rsp_sent);
bt_att_chan_send_rsp(chan, pdu);
/* BLUETOOTH SPECIFICATION Version 4.2 [Vol 3, Part F] page 484:
*
@ -817,6 +892,7 @@ static uint8_t att_find_info_rsp(struct bt_att_chan *chan, uint16_t start_handle
bt_gatt_foreach_attr(start_handle, end_handle, find_info_cb, &data);
if (!data.rsp) {
tx_meta_data_free(bt_att_tx_meta_data(data.buf));
net_buf_unref(data.buf);
/* Respond since handle is set */
send_err_rsp(chan, BT_ATT_OP_FIND_INFO_REQ, start_handle,
@ -824,7 +900,7 @@ static uint8_t att_find_info_rsp(struct bt_att_chan *chan, uint16_t start_handle
return 0;
}
bt_att_chan_send_rsp(chan, data.buf, chan_rsp_sent);
bt_att_chan_send_rsp(chan, data.buf);
return 0;
}
@ -981,6 +1057,7 @@ static uint8_t att_find_type_rsp(struct bt_att_chan *chan, uint16_t start_handle
/* If error has not been cleared, no service has been found */
if (data.err) {
tx_meta_data_free(bt_att_tx_meta_data(data.buf));
net_buf_unref(data.buf);
/* Respond since handle is set */
send_err_rsp(chan, BT_ATT_OP_FIND_TYPE_REQ, start_handle,
@ -988,7 +1065,7 @@ static uint8_t att_find_type_rsp(struct bt_att_chan *chan, uint16_t start_handle
return 0;
}
bt_att_chan_send_rsp(chan, data.buf, chan_rsp_sent);
bt_att_chan_send_rsp(chan, data.buf);
return 0;
}
@ -1213,6 +1290,7 @@ static uint8_t att_read_type_rsp(struct bt_att_chan *chan, struct bt_uuid *uuid,
bt_gatt_foreach_attr(start_handle, end_handle, read_type_cb, &data);
if (data.err) {
tx_meta_data_free(bt_att_tx_meta_data(data.buf));
net_buf_unref(data.buf);
/* Response here since handle is set */
send_err_rsp(chan, BT_ATT_OP_READ_TYPE_REQ, start_handle,
@ -1220,7 +1298,7 @@ static uint8_t att_read_type_rsp(struct bt_att_chan *chan, struct bt_uuid *uuid,
return 0;
}
bt_att_chan_send_rsp(chan, data.buf, chan_rsp_sent);
bt_att_chan_send_rsp(chan, data.buf);
return 0;
}
@ -1335,13 +1413,14 @@ static uint8_t att_read_rsp(struct bt_att_chan *chan, uint8_t op, uint8_t rsp,
/* In case of error discard data and respond with an error */
if (data.err) {
tx_meta_data_free(bt_att_tx_meta_data(data.buf));
net_buf_unref(data.buf);
/* Respond here since handle is set */
send_err_rsp(chan, op, handle, data.err);
return 0;
}
bt_att_chan_send_rsp(chan, data.buf, chan_rsp_sent);
bt_att_chan_send_rsp(chan, data.buf);
return 0;
}
@ -1419,6 +1498,7 @@ static uint8_t att_read_mult_req(struct bt_att_chan *chan, struct net_buf *buf)
/* Stop reading in case of error */
if (data.err) {
tx_meta_data_free(bt_att_tx_meta_data(data.buf));
net_buf_unref(data.buf);
/* Respond here since handle is set */
send_err_rsp(chan, BT_ATT_OP_READ_MULT_REQ, handle,
@ -1427,7 +1507,7 @@ static uint8_t att_read_mult_req(struct bt_att_chan *chan, struct net_buf *buf)
}
}
bt_att_chan_send_rsp(chan, data.buf, chan_rsp_sent);
bt_att_chan_send_rsp(chan, data.buf);
return 0;
}
@ -1513,6 +1593,7 @@ static uint8_t att_read_mult_vl_req(struct bt_att_chan *chan, struct net_buf *bu
/* Stop reading in case of error */
if (data.err) {
tx_meta_data_free(bt_att_tx_meta_data(data.buf));
net_buf_unref(data.buf);
/* Respond here since handle is set */
send_err_rsp(chan, BT_ATT_OP_READ_MULT_VL_REQ, handle,
@ -1521,7 +1602,7 @@ static uint8_t att_read_mult_vl_req(struct bt_att_chan *chan, struct net_buf *bu
}
}
bt_att_chan_send_rsp(chan, data.buf, chan_rsp_sent);
bt_att_chan_send_rsp(chan, data.buf);
return 0;
}
@ -1631,6 +1712,7 @@ static uint8_t att_read_group_rsp(struct bt_att_chan *chan, struct bt_uuid *uuid
bt_gatt_foreach_attr(start_handle, end_handle, read_group_cb, &data);
if (!data.rsp->len) {
tx_meta_data_free(bt_att_tx_meta_data(data.buf));
net_buf_unref(data.buf);
/* Respond here since handle is set */
send_err_rsp(chan, BT_ATT_OP_READ_GROUP_REQ, start_handle,
@ -1638,7 +1720,7 @@ static uint8_t att_read_group_rsp(struct bt_att_chan *chan, struct bt_uuid *uuid
return 0;
}
bt_att_chan_send_rsp(chan, data.buf, chan_rsp_sent);
bt_att_chan_send_rsp(chan, data.buf);
return 0;
}
@ -1780,6 +1862,7 @@ static uint8_t att_write_rsp(struct bt_att_chan *chan, uint8_t req, uint8_t rsp,
if (data.err) {
/* In case of error discard data and respond with an error */
if (rsp) {
tx_meta_data_free(bt_att_tx_meta_data(data.buf));
net_buf_unref(data.buf);
/* Respond here since handle is set */
send_err_rsp(chan, req, handle, data.err);
@ -1788,7 +1871,7 @@ static uint8_t att_write_rsp(struct bt_att_chan *chan, uint8_t req, uint8_t rsp,
}
if (data.buf) {
bt_att_chan_send_rsp(chan, data.buf, chan_rsp_sent);
bt_att_chan_send_rsp(chan, data.buf);
}
return 0;
@ -1917,7 +2000,7 @@ static uint8_t att_prep_write_rsp(struct bt_att_chan *chan, uint16_t handle,
net_buf_add(data.buf, len);
memcpy(rsp->value, value, len);
bt_att_chan_send_rsp(chan, data.buf, chan_rsp_sent);
bt_att_chan_send_rsp(chan, data.buf);
return 0;
}
@ -2060,7 +2143,7 @@ static uint8_t att_exec_write_rsp(struct bt_att_chan *chan, uint8_t flags)
return BT_ATT_ERR_UNLIKELY;
}
bt_att_chan_send_rsp(chan, buf, chan_rsp_sent);
bt_att_chan_send_rsp(chan, buf);
return 0;
}
@ -2344,7 +2427,7 @@ static uint8_t att_indicate(struct bt_att_chan *chan, struct net_buf *buf)
return 0;
}
bt_att_chan_send_rsp(chan, buf, chan_cfm_sent);
bt_att_chan_send_rsp(chan, buf);
return 0;
}
@ -2680,6 +2763,7 @@ static void att_reset(struct bt_att *att)
#if CONFIG_BT_ATT_PREPARE_COUNT > 0
/* Discard queued buffers */
while ((buf = net_buf_slist_get(&att->prep_queue))) {
tx_meta_data_free(bt_att_tx_meta_data(buf));
net_buf_unref(buf);
}
#endif /* CONFIG_BT_ATT_PREPARE_COUNT > 0 */
@ -2691,6 +2775,7 @@ static void att_reset(struct bt_att *att)
#endif /* CONFIG_BT_EATT */
while ((buf = net_buf_get(&att->tx_queue, K_NO_WAIT))) {
tx_meta_data_free(bt_att_tx_meta_data(buf));
net_buf_unref(buf);
}
@ -2726,6 +2811,7 @@ static void att_chan_detach(struct bt_att_chan *chan)
/* Release pending buffers */
while ((buf = net_buf_get(&chan->tx_queue, K_NO_WAIT))) {
tx_meta_data_free(bt_att_tx_meta_data(buf));
net_buf_unref(buf);
}
@ -2846,11 +2932,13 @@ static uint8_t att_req_retry(struct bt_att_chan *att_chan)
}
if (req->encode(buf, req->len, req->user_data)) {
tx_meta_data_free(bt_att_tx_meta_data(buf));
net_buf_unref(buf);
return BT_ATT_ERR_UNLIKELY;
}
if (chan_send(att_chan, buf, NULL)) {
if (chan_send(att_chan, buf)) {
tx_meta_data_free(bt_att_tx_meta_data(buf));
net_buf_unref(buf);
return BT_ATT_ERR_UNLIKELY;
}
@ -3287,6 +3375,10 @@ static void bt_eatt_init(void)
void bt_att_init(void)
{
for (size_t i = 0; i < ARRAY_SIZE(tx_meta_data); i++) {
k_fifo_put(&free_att_tx_meta_data, &tx_meta_data[i]);
}
bt_gatt_init();
if (IS_ENABLED(CONFIG_BT_EATT)) {
@ -3367,6 +3459,7 @@ void bt_att_req_free(struct bt_att_req *req)
BT_DBG("req %p", req);
if (req->buf) {
tx_meta_data_free(bt_att_tx_meta_data(req->buf));
net_buf_unref(req->buf);
req->buf = NULL;
}
@ -3374,8 +3467,7 @@ void bt_att_req_free(struct bt_att_req *req)
k_mem_slab_free(&req_slab, (void **)&req);
}
int bt_att_send(struct bt_conn *conn, struct net_buf *buf, bt_conn_tx_cb_t cb,
void *user_data)
int bt_att_send(struct bt_conn *conn, struct net_buf *buf)
{
struct bt_att *att;
@ -3384,18 +3476,11 @@ int bt_att_send(struct bt_conn *conn, struct net_buf *buf, bt_conn_tx_cb_t cb,
att = att_get(conn);
if (!att) {
tx_meta_data_free(bt_att_tx_meta_data(buf));
net_buf_unref(buf);
return -ENOTCONN;
}
/* If callback is set use the fixed channel since bt_l2cap_chan_send
* cannot be used with a custom user_data.
*/
if (cb) {
return bt_l2cap_send_cb(conn, BT_L2CAP_CID_ATT, buf, cb,
user_data);
}
net_buf_put(&att->tx_queue, buf);
att_send_process(att);
@ -3527,3 +3612,18 @@ bool bt_att_out_of_sync_sent_on_fixed(struct bt_conn *conn)
att_chan = ATT_CHAN(l2cap_chan);
return atomic_test_bit(att_chan->flags, ATT_OUT_OF_SYNC_SENT);
}
void bt_att_set_tx_meta_data(struct net_buf *buf, bt_conn_tx_cb_t func, void *user_data)
{
struct bt_att_tx_meta_data *data = bt_att_tx_meta_data(buf);
data->func = func;
data->user_data = user_data;
}
bool bt_att_tx_meta_data_match(const struct net_buf *buf, bt_conn_tx_cb_t func,
const void *user_data)
{
return ((bt_att_tx_meta_data(buf)->func == func) &&
(bt_att_tx_meta_data(buf)->user_data == user_data));
}

View file

@ -290,8 +290,7 @@ struct bt_att_req *bt_att_req_alloc(k_timeout_t timeout);
void bt_att_req_free(struct bt_att_req *req);
/* Send ATT PDU over a connection */
int bt_att_send(struct bt_conn *conn, struct net_buf *buf, bt_conn_tx_cb_t cb,
void *user_data);
int bt_att_send(struct bt_conn *conn, struct net_buf *buf);
/* Send ATT Request over a connection */
int bt_att_req_send(struct bt_conn *conn, struct bt_att_req *req);
@ -317,3 +316,8 @@ void bt_att_clear_out_of_sync_sent(struct bt_conn *conn);
/* Check if BT_ATT_ERR_DB_OUT_OF_SYNC has been sent on the fixed ATT channel */
bool bt_att_out_of_sync_sent_on_fixed(struct bt_conn *conn);
void bt_att_set_tx_meta_data(struct net_buf *buf, bt_conn_tx_cb_t func, void *user_data);
bool bt_att_tx_meta_data_match(const struct net_buf *buf, bt_conn_tx_cb_t func,
const void *user_data);

View file

@ -2078,10 +2078,9 @@ static struct net_buf *nfy_mult[CONFIG_BT_MAX_CONN];
static int gatt_notify_mult_send(struct bt_conn *conn, struct net_buf **buf)
{
struct nfy_mult_data *data = nfy_mult_user_data(*buf);
int ret;
ret = bt_att_send(conn, *buf, data->func, data->user_data);
ret = bt_att_send(conn, *buf);
if (ret < 0) {
net_buf_unref(*buf);
}
@ -2132,7 +2131,7 @@ static int gatt_notify_mult(struct bt_conn *conn, uint16_t handle,
* the existing buffer and proceed to create a new one
*/
if (*buf && ((net_buf_tailroom(*buf) < sizeof(*nfy) + params->len) ||
!nfy_mult_data_match(*buf, params->func, params->user_data))) {
!bt_att_tx_meta_data_match(*buf, params->func, params->user_data))) {
int ret;
ret = gatt_notify_mult_send(conn, buf);
@ -2147,9 +2146,8 @@ static int gatt_notify_mult(struct bt_conn *conn, uint16_t handle,
if (!*buf) {
return -ENOMEM;
}
/* Set user_data so it can be restored when sending */
nfy_mult_user_data(*buf)->func = params->func;
nfy_mult_user_data(*buf)->user_data = params->user_data;
bt_att_set_tx_meta_data(*buf, params->func, params->user_data);
}
BT_DBG("handle 0x%04x len %u", handle, params->len);
@ -2212,7 +2210,8 @@ static int gatt_notify(struct bt_conn *conn, uint16_t handle,
net_buf_add(buf, params->len);
memcpy(nfy->value, params->data, params->len);
return bt_att_send(conn, buf, params->func, params->user_data);
bt_att_set_tx_meta_data(buf, params->func, params->user_data);
return bt_att_send(conn, buf);
}
static void gatt_indicate_rsp(struct bt_conn *conn, uint8_t err,
@ -4425,7 +4424,7 @@ int bt_gatt_write_without_response_cb(struct bt_conn *conn, uint16_t handle,
BT_DBG("handle 0x%04x length %u", handle, length);
return bt_att_send(conn, buf, func, user_data);
return bt_att_send(conn, buf);
}
static int gatt_exec_encode(struct net_buf *buf, size_t len, void *user_data)