Bluetooth: ATT: Fix not restoring buffer state when send fails
Since bt_l2cap_send_cb can fail returning its error is not enough as the buffer has been modified to add the headers, so this save the state before calling bt_conn_send_cb and takes a reference so it can be restored its original state in case of error. Fixes #27434 Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
This commit is contained in:
parent
65d4e177ca
commit
426fb82bd8
1 changed files with 24 additions and 6 deletions
|
@ -147,6 +147,8 @@ 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 net_buf_simple_state state;
|
||||
int err;
|
||||
|
||||
hdr = (void *)buf->data;
|
||||
|
||||
|
@ -154,8 +156,6 @@ static int chan_send(struct bt_att_chan *chan, struct net_buf *buf,
|
|||
|
||||
if (IS_ENABLED(CONFIG_BT_EATT) &&
|
||||
atomic_test_bit(chan->flags, ATT_ENHANCED)) {
|
||||
int err;
|
||||
|
||||
/* Check if sent is pending already, if it does it cannot be
|
||||
* modified so the operation will need to be queued.
|
||||
*/
|
||||
|
@ -198,10 +198,23 @@ 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);
|
||||
|
||||
return bt_l2cap_send_cb(chan->att->conn, BT_L2CAP_CID_ATT, buf,
|
||||
att_cb(chan->sent), &chan->chan.chan);
|
||||
/* Take a ref since bt_l2cap_send_cb takes ownership of the buffer */
|
||||
err = bt_l2cap_send_cb(chan->att->conn, BT_L2CAP_CID_ATT,
|
||||
net_buf_ref(buf), att_cb(chan->sent),
|
||||
&chan->chan.chan);
|
||||
if (!err) {
|
||||
net_buf_unref(buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
net_buf_simple_restore(&buf->b, &state);
|
||||
|
||||
return err;
|
||||
|
||||
}
|
||||
|
||||
static int process_queue(struct bt_att_chan *chan, struct k_fifo *queue)
|
||||
|
@ -241,11 +254,16 @@ static int chan_req_send(struct bt_att_chan *chan, struct bt_att_req *req)
|
|||
/* Save request state so it can be resent */
|
||||
net_buf_simple_save(&req->buf->b, &req->state);
|
||||
|
||||
/* Keep a reference for resending in case of an error */
|
||||
/* Keep a reference for resending the req in case the security
|
||||
* needs to be changed.
|
||||
*/
|
||||
err = chan_send(chan, net_buf_ref(req->buf), NULL);
|
||||
if (err) {
|
||||
/* Drop the extra reference if buffer could not be sent but
|
||||
* don't reset the buffer as it will likelly be pushed back to
|
||||
* request queue to be send later.
|
||||
*/
|
||||
net_buf_unref(req->buf);
|
||||
chan->req = NULL;
|
||||
}
|
||||
|
||||
return err;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue