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:
parent
cf3832f0bf
commit
c8b2279f89
3 changed files with 196 additions and 93 deletions
|
@ -90,7 +90,6 @@ struct bt_att_chan {
|
||||||
struct bt_att_req *req;
|
struct bt_att_req *req;
|
||||||
struct k_fifo tx_queue;
|
struct k_fifo tx_queue;
|
||||||
struct k_work_delayable timeout_work;
|
struct k_work_delayable timeout_work;
|
||||||
void (*sent)(struct bt_att_chan *chan);
|
|
||||||
sys_snode_t node;
|
sys_snode_t node;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -133,17 +132,45 @@ static struct bt_att_req cancel;
|
||||||
*/
|
*/
|
||||||
static k_tid_t att_handle_rsp_thread;
|
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);
|
struct bt_att_tx_meta {
|
||||||
static bt_conn_tx_cb_t att_cb(bt_att_chan_sent_t cb);
|
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 att_chan_mtu_updated(struct bt_att_chan *updated_chan);
|
||||||
static void bt_att_disconnected(struct bt_l2cap_chan *chan);
|
static void bt_att_disconnected(struct bt_l2cap_chan *chan);
|
||||||
|
|
||||||
void att_sent(struct bt_conn *conn, void *user_data)
|
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);
|
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
|
* 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.
|
* 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,
|
static int chan_send(struct bt_att_chan *chan, struct net_buf *buf)
|
||||||
bt_att_chan_sent_t cb)
|
|
||||||
{
|
{
|
||||||
struct bt_att_hdr *hdr;
|
struct bt_att_hdr *hdr;
|
||||||
struct net_buf_simple_state state;
|
struct net_buf_simple_state state;
|
||||||
int err;
|
int err;
|
||||||
|
struct bt_att_tx_meta_data *data = bt_att_tx_meta_data(buf);
|
||||||
|
|
||||||
hdr = (void *)buf->data;
|
hdr = (void *)buf->data;
|
||||||
|
|
||||||
|
@ -191,8 +218,6 @@ static int chan_send(struct bt_att_chan *chan, struct net_buf *buf,
|
||||||
return -EAGAIN;
|
return -EAGAIN;
|
||||||
}
|
}
|
||||||
|
|
||||||
chan->sent = cb ? cb : chan_cb(buf);
|
|
||||||
|
|
||||||
if (hdr->code == BT_ATT_OP_SIGNED_WRITE_CMD) {
|
if (hdr->code == BT_ATT_OP_SIGNED_WRITE_CMD) {
|
||||||
return -ENOTSUP;
|
return -ENOTSUP;
|
||||||
}
|
}
|
||||||
|
@ -212,10 +237,12 @@ static int chan_send(struct bt_att_chan *chan, struct net_buf *buf,
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data->att_chan = chan;
|
||||||
|
|
||||||
/* bt_l2cap_chan_send does actually return the number of bytes
|
/* bt_l2cap_chan_send does actually return the number of bytes
|
||||||
* that could be sent immediately.
|
* 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) {
|
if (err < 0) {
|
||||||
return err;
|
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);
|
err = bt_smp_sign(chan->att->conn, buf);
|
||||||
if (err) {
|
if (err) {
|
||||||
BT_ERR("Error signing data");
|
BT_ERR("Error signing data");
|
||||||
|
tx_meta_data_free(bt_att_tx_meta_data(buf));
|
||||||
net_buf_unref(buf);
|
net_buf_unref(buf);
|
||||||
return err;
|
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);
|
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,
|
err = bt_l2cap_send_cb(chan->att->conn, BT_L2CAP_CID_ATT,
|
||||||
buf, att_cb(chan->sent),
|
buf, att_cb(buf), data);
|
||||||
&chan->chan.chan);
|
|
||||||
if (err) {
|
if (err) {
|
||||||
/* In case of an error has occurred restore the buffer state */
|
/* In case of an error has occurred restore the buffer state */
|
||||||
net_buf_simple_restore(&buf->b, &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);
|
buf = net_buf_get(queue, K_NO_WAIT);
|
||||||
if (buf) {
|
if (buf) {
|
||||||
err = chan_send(chan, buf, NULL);
|
err = chan_send(chan, buf);
|
||||||
if (err) {
|
if (err) {
|
||||||
/* Push it back if it could not be send */
|
/* Push it back if it could not be send */
|
||||||
k_queue_prepend(&queue->_queue, buf);
|
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;
|
buf = req->buf;
|
||||||
req->buf = NULL;
|
req->buf = NULL;
|
||||||
|
|
||||||
err = chan_send(chan, buf, NULL);
|
err = chan_send(chan, buf);
|
||||||
if (err) {
|
if (err) {
|
||||||
/* We still have the ownership of the buffer */
|
/* We still have the ownership of the buffer */
|
||||||
req->buf = buf;
|
req->buf = buf;
|
||||||
|
@ -306,10 +333,6 @@ static void bt_att_sent(struct bt_l2cap_chan *ch)
|
||||||
|
|
||||||
BT_DBG("chan %p", chan);
|
BT_DBG("chan %p", chan);
|
||||||
|
|
||||||
if (chan->sent) {
|
|
||||||
chan->sent(chan);
|
|
||||||
}
|
|
||||||
|
|
||||||
atomic_clear_bit(chan->flags, ATT_PENDING_SENT);
|
atomic_clear_bit(chan->flags, ATT_PENDING_SENT);
|
||||||
|
|
||||||
if (!att) {
|
if (!att) {
|
||||||
|
@ -343,37 +366,73 @@ static void bt_att_sent(struct bt_l2cap_chan *ch)
|
||||||
(void)process_queue(chan, &att->tx_queue);
|
(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);
|
BT_DBG("chan %p", chan);
|
||||||
|
|
||||||
if (IS_ENABLED(CONFIG_BT_ATT_ENFORCE_FLOW)) {
|
if (IS_ENABLED(CONFIG_BT_ATT_ENFORCE_FLOW)) {
|
||||||
atomic_clear_bit(chan->flags, ATT_PENDING_CFM);
|
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);
|
BT_DBG("chan %p", chan);
|
||||||
|
|
||||||
if (IS_ENABLED(CONFIG_BT_ATT_ENFORCE_FLOW)) {
|
if (IS_ENABLED(CONFIG_BT_ATT_ENFORCE_FLOW)) {
|
||||||
atomic_clear_bit(chan->flags, ATT_PENDING_RSP);
|
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);
|
BT_DBG("chan %p chan->req %p", chan, chan->req);
|
||||||
|
|
||||||
/* Start timeout work */
|
/* Start timeout work */
|
||||||
if (chan->req) {
|
if (chan->req) {
|
||||||
k_work_reschedule(&chan->timeout_work, BT_ATT_TIMEOUT);
|
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:
|
case ATT_RESPONSE:
|
||||||
return chan_rsp_sent;
|
return chan_rsp_sent;
|
||||||
case ATT_CONFIRMATION:
|
case ATT_CONFIRMATION:
|
||||||
|
@ -381,58 +440,66 @@ static bt_att_chan_sent_t chan_cb(struct net_buf *buf)
|
||||||
case ATT_REQUEST:
|
case ATT_REQUEST:
|
||||||
case ATT_INDICATION:
|
case ATT_INDICATION:
|
||||||
return chan_req_sent;
|
return chan_req_sent;
|
||||||
|
case ATT_COMMAND:
|
||||||
|
case ATT_NOTIFICATION:
|
||||||
|
return chan_tx_complete;
|
||||||
default:
|
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)
|
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);
|
att_sent(conn, user_data);
|
||||||
|
chan_cfm_sent(conn, user_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void att_rsp_sent(struct bt_conn *conn, void *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);
|
att_sent(conn, user_data);
|
||||||
|
chan_rsp_sent(conn, user_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void att_req_sent(struct bt_conn *conn, void *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);
|
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;
|
return att_rsp_sent;
|
||||||
} else if (cb == chan_cfm_sent) {
|
case ATT_CONFIRMATION:
|
||||||
return att_cfm_sent;
|
return att_cfm_sent;
|
||||||
} else if (cb == chan_req_sent) {
|
case ATT_REQUEST:
|
||||||
|
case ATT_INDICATION:
|
||||||
return att_req_sent;
|
return att_req_sent;
|
||||||
} else {
|
case ATT_COMMAND:
|
||||||
return att_sent;
|
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,
|
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 bt_att_hdr *hdr;
|
||||||
struct net_buf *buf;
|
struct net_buf *buf;
|
||||||
|
struct bt_att_tx_meta_data *data;
|
||||||
|
|
||||||
if (len + sizeof(op) > chan->chan.tx.mtu) {
|
if (len + sizeof(op) > chan->chan.tx.mtu) {
|
||||||
BT_WARN("ATT MTU exceeded, max %u, wanted %zu",
|
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;
|
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 = net_buf_add(buf, sizeof(*hdr));
|
||||||
hdr->code = op;
|
hdr->code = op;
|
||||||
|
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int bt_att_chan_send(struct bt_att_chan *chan, struct net_buf *buf,
|
static int bt_att_chan_send(struct bt_att_chan *chan, struct net_buf *buf)
|
||||||
bt_att_chan_sent_t cb)
|
|
||||||
{
|
{
|
||||||
BT_DBG("chan %p flags %lu code 0x%02x", chan, atomic_get(chan->flags),
|
BT_DBG("chan %p flags %lu code 0x%02x", chan, atomic_get(chan->flags),
|
||||||
((struct bt_att_hdr *)buf->data)->code);
|
((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)
|
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) {
|
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) {
|
if (err >= 0) {
|
||||||
break;
|
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,
|
static void bt_att_chan_send_rsp(struct bt_att_chan *chan, struct net_buf *buf)
|
||||||
bt_att_chan_sent_t cb)
|
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
err = bt_att_chan_send(chan, buf, cb);
|
err = bt_att_chan_send(chan, buf);
|
||||||
if (err) {
|
if (err) {
|
||||||
/* Responses need to be sent back using the same channel */
|
/* Responses need to be sent back using the same channel */
|
||||||
net_buf_put(&chan->tx_queue, buf);
|
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->handle = sys_cpu_to_le16(handle);
|
||||||
rsp->error = err;
|
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)
|
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 = net_buf_add(pdu, sizeof(*rsp));
|
||||||
rsp->mtu = sys_cpu_to_le16(mtu_server);
|
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:
|
/* 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);
|
bt_gatt_foreach_attr(start_handle, end_handle, find_info_cb, &data);
|
||||||
|
|
||||||
if (!data.rsp) {
|
if (!data.rsp) {
|
||||||
|
tx_meta_data_free(bt_att_tx_meta_data(data.buf));
|
||||||
net_buf_unref(data.buf);
|
net_buf_unref(data.buf);
|
||||||
/* Respond since handle is set */
|
/* Respond since handle is set */
|
||||||
send_err_rsp(chan, BT_ATT_OP_FIND_INFO_REQ, start_handle,
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bt_att_chan_send_rsp(chan, data.buf, chan_rsp_sent);
|
bt_att_chan_send_rsp(chan, data.buf);
|
||||||
|
|
||||||
return 0;
|
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 error has not been cleared, no service has been found */
|
||||||
if (data.err) {
|
if (data.err) {
|
||||||
|
tx_meta_data_free(bt_att_tx_meta_data(data.buf));
|
||||||
net_buf_unref(data.buf);
|
net_buf_unref(data.buf);
|
||||||
/* Respond since handle is set */
|
/* Respond since handle is set */
|
||||||
send_err_rsp(chan, BT_ATT_OP_FIND_TYPE_REQ, start_handle,
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bt_att_chan_send_rsp(chan, data.buf, chan_rsp_sent);
|
bt_att_chan_send_rsp(chan, data.buf);
|
||||||
|
|
||||||
return 0;
|
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);
|
bt_gatt_foreach_attr(start_handle, end_handle, read_type_cb, &data);
|
||||||
|
|
||||||
if (data.err) {
|
if (data.err) {
|
||||||
|
tx_meta_data_free(bt_att_tx_meta_data(data.buf));
|
||||||
net_buf_unref(data.buf);
|
net_buf_unref(data.buf);
|
||||||
/* Response here since handle is set */
|
/* Response here since handle is set */
|
||||||
send_err_rsp(chan, BT_ATT_OP_READ_TYPE_REQ, start_handle,
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bt_att_chan_send_rsp(chan, data.buf, chan_rsp_sent);
|
bt_att_chan_send_rsp(chan, data.buf);
|
||||||
|
|
||||||
return 0;
|
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 */
|
/* In case of error discard data and respond with an error */
|
||||||
if (data.err) {
|
if (data.err) {
|
||||||
|
tx_meta_data_free(bt_att_tx_meta_data(data.buf));
|
||||||
net_buf_unref(data.buf);
|
net_buf_unref(data.buf);
|
||||||
/* Respond here since handle is set */
|
/* Respond here since handle is set */
|
||||||
send_err_rsp(chan, op, handle, data.err);
|
send_err_rsp(chan, op, handle, data.err);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bt_att_chan_send_rsp(chan, data.buf, chan_rsp_sent);
|
bt_att_chan_send_rsp(chan, data.buf);
|
||||||
|
|
||||||
return 0;
|
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 */
|
/* Stop reading in case of error */
|
||||||
if (data.err) {
|
if (data.err) {
|
||||||
|
tx_meta_data_free(bt_att_tx_meta_data(data.buf));
|
||||||
net_buf_unref(data.buf);
|
net_buf_unref(data.buf);
|
||||||
/* Respond here since handle is set */
|
/* Respond here since handle is set */
|
||||||
send_err_rsp(chan, BT_ATT_OP_READ_MULT_REQ, handle,
|
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;
|
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 */
|
/* Stop reading in case of error */
|
||||||
if (data.err) {
|
if (data.err) {
|
||||||
|
tx_meta_data_free(bt_att_tx_meta_data(data.buf));
|
||||||
net_buf_unref(data.buf);
|
net_buf_unref(data.buf);
|
||||||
/* Respond here since handle is set */
|
/* Respond here since handle is set */
|
||||||
send_err_rsp(chan, BT_ATT_OP_READ_MULT_VL_REQ, handle,
|
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;
|
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);
|
bt_gatt_foreach_attr(start_handle, end_handle, read_group_cb, &data);
|
||||||
|
|
||||||
if (!data.rsp->len) {
|
if (!data.rsp->len) {
|
||||||
|
tx_meta_data_free(bt_att_tx_meta_data(data.buf));
|
||||||
net_buf_unref(data.buf);
|
net_buf_unref(data.buf);
|
||||||
/* Respond here since handle is set */
|
/* Respond here since handle is set */
|
||||||
send_err_rsp(chan, BT_ATT_OP_READ_GROUP_REQ, start_handle,
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bt_att_chan_send_rsp(chan, data.buf, chan_rsp_sent);
|
bt_att_chan_send_rsp(chan, data.buf);
|
||||||
|
|
||||||
return 0;
|
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) {
|
if (data.err) {
|
||||||
/* In case of error discard data and respond with an error */
|
/* In case of error discard data and respond with an error */
|
||||||
if (rsp) {
|
if (rsp) {
|
||||||
|
tx_meta_data_free(bt_att_tx_meta_data(data.buf));
|
||||||
net_buf_unref(data.buf);
|
net_buf_unref(data.buf);
|
||||||
/* Respond here since handle is set */
|
/* Respond here since handle is set */
|
||||||
send_err_rsp(chan, req, handle, data.err);
|
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) {
|
if (data.buf) {
|
||||||
bt_att_chan_send_rsp(chan, data.buf, chan_rsp_sent);
|
bt_att_chan_send_rsp(chan, data.buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
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);
|
net_buf_add(data.buf, len);
|
||||||
memcpy(rsp->value, value, 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;
|
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;
|
return BT_ATT_ERR_UNLIKELY;
|
||||||
}
|
}
|
||||||
|
|
||||||
bt_att_chan_send_rsp(chan, buf, chan_rsp_sent);
|
bt_att_chan_send_rsp(chan, buf);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -2344,7 +2427,7 @@ static uint8_t att_indicate(struct bt_att_chan *chan, struct net_buf *buf)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bt_att_chan_send_rsp(chan, buf, chan_cfm_sent);
|
bt_att_chan_send_rsp(chan, buf);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -2680,6 +2763,7 @@ static void att_reset(struct bt_att *att)
|
||||||
#if CONFIG_BT_ATT_PREPARE_COUNT > 0
|
#if CONFIG_BT_ATT_PREPARE_COUNT > 0
|
||||||
/* Discard queued buffers */
|
/* Discard queued buffers */
|
||||||
while ((buf = net_buf_slist_get(&att->prep_queue))) {
|
while ((buf = net_buf_slist_get(&att->prep_queue))) {
|
||||||
|
tx_meta_data_free(bt_att_tx_meta_data(buf));
|
||||||
net_buf_unref(buf);
|
net_buf_unref(buf);
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_BT_ATT_PREPARE_COUNT > 0 */
|
#endif /* CONFIG_BT_ATT_PREPARE_COUNT > 0 */
|
||||||
|
@ -2691,6 +2775,7 @@ static void att_reset(struct bt_att *att)
|
||||||
#endif /* CONFIG_BT_EATT */
|
#endif /* CONFIG_BT_EATT */
|
||||||
|
|
||||||
while ((buf = net_buf_get(&att->tx_queue, K_NO_WAIT))) {
|
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);
|
net_buf_unref(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2726,6 +2811,7 @@ static void att_chan_detach(struct bt_att_chan *chan)
|
||||||
|
|
||||||
/* Release pending buffers */
|
/* Release pending buffers */
|
||||||
while ((buf = net_buf_get(&chan->tx_queue, K_NO_WAIT))) {
|
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);
|
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)) {
|
if (req->encode(buf, req->len, req->user_data)) {
|
||||||
|
tx_meta_data_free(bt_att_tx_meta_data(buf));
|
||||||
net_buf_unref(buf);
|
net_buf_unref(buf);
|
||||||
return BT_ATT_ERR_UNLIKELY;
|
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);
|
net_buf_unref(buf);
|
||||||
return BT_ATT_ERR_UNLIKELY;
|
return BT_ATT_ERR_UNLIKELY;
|
||||||
}
|
}
|
||||||
|
@ -3287,6 +3375,10 @@ static void bt_eatt_init(void)
|
||||||
|
|
||||||
void bt_att_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();
|
bt_gatt_init();
|
||||||
|
|
||||||
if (IS_ENABLED(CONFIG_BT_EATT)) {
|
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);
|
BT_DBG("req %p", req);
|
||||||
|
|
||||||
if (req->buf) {
|
if (req->buf) {
|
||||||
|
tx_meta_data_free(bt_att_tx_meta_data(req->buf));
|
||||||
net_buf_unref(req->buf);
|
net_buf_unref(req->buf);
|
||||||
req->buf = NULL;
|
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);
|
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,
|
int bt_att_send(struct bt_conn *conn, struct net_buf *buf)
|
||||||
void *user_data)
|
|
||||||
{
|
{
|
||||||
struct bt_att *att;
|
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);
|
att = att_get(conn);
|
||||||
if (!att) {
|
if (!att) {
|
||||||
|
tx_meta_data_free(bt_att_tx_meta_data(buf));
|
||||||
net_buf_unref(buf);
|
net_buf_unref(buf);
|
||||||
return -ENOTCONN;
|
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);
|
net_buf_put(&att->tx_queue, buf);
|
||||||
att_send_process(att);
|
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);
|
att_chan = ATT_CHAN(l2cap_chan);
|
||||||
return atomic_test_bit(att_chan->flags, ATT_OUT_OF_SYNC_SENT);
|
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));
|
||||||
|
}
|
||||||
|
|
|
@ -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);
|
void bt_att_req_free(struct bt_att_req *req);
|
||||||
|
|
||||||
/* Send ATT PDU over a connection */
|
/* Send ATT PDU over a connection */
|
||||||
int bt_att_send(struct bt_conn *conn, struct net_buf *buf, bt_conn_tx_cb_t cb,
|
int bt_att_send(struct bt_conn *conn, struct net_buf *buf);
|
||||||
void *user_data);
|
|
||||||
|
|
||||||
/* Send ATT Request over a connection */
|
/* Send ATT Request over a connection */
|
||||||
int bt_att_req_send(struct bt_conn *conn, struct bt_att_req *req);
|
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 */
|
/* 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);
|
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);
|
||||||
|
|
|
@ -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)
|
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;
|
int ret;
|
||||||
|
|
||||||
ret = bt_att_send(conn, *buf, data->func, data->user_data);
|
ret = bt_att_send(conn, *buf);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
net_buf_unref(*buf);
|
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
|
* the existing buffer and proceed to create a new one
|
||||||
*/
|
*/
|
||||||
if (*buf && ((net_buf_tailroom(*buf) < sizeof(*nfy) + params->len) ||
|
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;
|
int ret;
|
||||||
|
|
||||||
ret = gatt_notify_mult_send(conn, buf);
|
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) {
|
if (!*buf) {
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
/* Set user_data so it can be restored when sending */
|
|
||||||
nfy_mult_user_data(*buf)->func = params->func;
|
bt_att_set_tx_meta_data(*buf, params->func, params->user_data);
|
||||||
nfy_mult_user_data(*buf)->user_data = params->user_data;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BT_DBG("handle 0x%04x len %u", handle, params->len);
|
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);
|
net_buf_add(buf, params->len);
|
||||||
memcpy(nfy->value, params->data, 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,
|
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);
|
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)
|
static int gatt_exec_encode(struct net_buf *buf, size_t len, void *user_data)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue