Skip to content

Commit 7644e96

Browse files
Thalleym-alperen-sener
authored andcommitted
[nrf fromtree] Bluetooth: ATT: Disconnect ATT and ACL when receiving inval rsp
When we receive a response from a server we do not have an outstanding request with, we disconnect the connection rather than just ignoring it. The reason for this is that the remote server is not ensuring correct ATT flow control, which means that we cannot trust future responses from the server. Signed-off-by: Emil Gydesen <[email protected]> (cherry picked from commit 09fb533)
1 parent 7547117 commit 7644e96

File tree

1 file changed

+28
-9
lines changed
  • subsys/bluetooth/host

1 file changed

+28
-9
lines changed

subsys/bluetooth/host/att.c

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
* SPDX-License-Identifier: Apache-2.0
77
*/
88

9+
#include <zephyr/bluetooth/addr.h>
10+
#include <zephyr/bluetooth/conn.h>
911
#include <zephyr/kernel.h>
1012
#include <string.h>
1113
#include <errno.h>
@@ -295,6 +297,28 @@ struct net_buf *bt_att_create_rsp_pdu(struct bt_att_chan *chan, uint8_t op);
295297

296298
static void bt_att_sent(struct bt_l2cap_chan *ch);
297299

300+
static void att_disconnect(struct bt_att_chan *chan)
301+
{
302+
char addr[BT_ADDR_LE_STR_LEN];
303+
int err;
304+
305+
/* In rare circumstances we are "forced" to disconnect the ATT bearer and the ACL.
306+
* Examples of when this is right course of action is when there is an ATT timeout, we
307+
* receive an unexpected response from the server, or the response from the server is
308+
* invalid
309+
*/
310+
311+
bt_addr_le_to_str(bt_conn_get_dst(chan->att->conn), addr, sizeof(addr));
312+
LOG_DBG("ATT disconnecting device %s", addr);
313+
314+
bt_att_disconnected(&chan->chan.chan);
315+
316+
err = bt_conn_disconnect(chan->chan.chan.conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN);
317+
if (err) {
318+
LOG_ERR("Disconnecting failed (err %d)", err);
319+
}
320+
}
321+
298322
static void att_sent(void *user_data)
299323
{
300324
struct bt_att_tx_meta_data *data = user_data;
@@ -945,7 +969,8 @@ static uint8_t att_handle_rsp(struct bt_att_chan *chan, void *pdu, uint16_t len,
945969

946970
if (!chan->req) {
947971
LOG_WRN("No pending ATT request");
948-
goto process;
972+
att_disconnect(chan);
973+
return 0; /* Returning a non-0 value would attempt to send an error response */
949974
}
950975

951976
/* Check if request has been cancelled */
@@ -3154,9 +3179,7 @@ static void att_timeout(struct k_work *work)
31543179
{
31553180
char addr[BT_ADDR_LE_STR_LEN];
31563181
struct k_work_delayable *dwork = k_work_delayable_from_work(work);
3157-
struct bt_att_chan *chan = CONTAINER_OF(dwork, struct bt_att_chan,
3158-
timeout_work);
3159-
int err;
3182+
struct bt_att_chan *chan = CONTAINER_OF(dwork, struct bt_att_chan, timeout_work);
31603183

31613184
bt_addr_le_to_str(bt_conn_get_dst(chan->att->conn), addr, sizeof(addr));
31623185
LOG_ERR("ATT Timeout for device %s. Disconnecting...", addr);
@@ -3169,17 +3192,13 @@ static void att_timeout(struct k_work *work)
31693192
* requests, commands, indications or notifications shall be sent to the
31703193
* target device on this ATT Bearer.
31713194
*/
3172-
bt_att_disconnected(&chan->chan.chan);
31733195

31743196
/* The timeout state is local and can block new ATT operations, but does not affect the
31753197
* remote side. Disconnecting the GATT connection upon ATT timeout simplifies error handling
31763198
* for developers. This reduces rare failure conditions to a common one, allowing developers
31773199
* to handle unexpected disconnections without needing special cases for ATT timeouts.
31783200
*/
3179-
err = bt_conn_disconnect(chan->chan.chan.conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN);
3180-
if (err) {
3181-
LOG_ERR("Disconnecting failed (err %d)", err);
3182-
}
3201+
att_disconnect(chan);
31833202
}
31843203

31853204
static struct bt_att_chan *att_get_fixed_chan(struct bt_conn *conn)

0 commit comments

Comments
 (0)