Skip to content

Commit ae9380d

Browse files
alwa-nordiccarlescufi
authored andcommitted
Bluetooth: Host: L2CAP: Don't send credits if chan is disconnected
Fixes bug where Host sends L2CAP Flow Control Credit after receiving a L2CAP Disconnect Response. The when the callback in l2cap_chan_le_recv_sdu is handed a Disconnect Reponse, the connnection becomes disconnected, as illustrated by the asserts. The function should now trigger sending credits if the connection is disconnected after the callback returns. Fixes #42112 Signed-off-by: Aleksander Wasaznik <[email protected]>
1 parent 31c6a9c commit ae9380d

File tree

1 file changed

+25
-1
lines changed

1 file changed

+25
-1
lines changed

subsys/bluetooth/host/l2cap.c

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include <bluetooth/hci.h>
1717
#include <bluetooth/bluetooth.h>
1818
#include <bluetooth/conn.h>
19+
#include <bluetooth/l2cap.h>
1920
#include <drivers/bluetooth/hci_driver.h>
2021

2122
#define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_DEBUG_L2CAP)
@@ -2143,11 +2144,29 @@ static void l2cap_chan_shutdown(struct bt_l2cap_chan *chan)
21432144
}
21442145
}
21452146

2147+
/** @brief Get @c chan->state.
2148+
*
2149+
* This field does not exist when @kconfig{CONFIG_BT_L2CAP_DYNAMIC_CHANNEL} is
2150+
* disabled. In that case, this function returns @ref BT_L2CAP_CONNECTED since
2151+
* the struct can only represent static channels in that case and static
2152+
* channels are always connected.
2153+
*/
2154+
static inline bt_l2cap_chan_state_t bt_l2cap_chan_get_state(struct bt_l2cap_chan *chan)
2155+
{
2156+
#if defined(CONFIG_BT_L2CAP_DYNAMIC_CHANNEL)
2157+
return chan->state;
2158+
#else
2159+
return BT_L2CAP_CONNECTED;
2160+
#endif
2161+
}
2162+
21462163
static void l2cap_chan_send_credits(struct bt_l2cap_le_chan *chan,
21472164
struct net_buf *buf, uint16_t credits)
21482165
{
21492166
struct bt_l2cap_le_credits *ev;
21502167

2168+
__ASSERT_NO_MSG(bt_l2cap_chan_get_state(&chan->chan) == BT_L2CAP_CONNECTED);
2169+
21512170
/* Cap the number of credits given */
21522171
if (credits > chan->rx.init_credits) {
21532172
credits = chan->rx.init_credits;
@@ -2245,6 +2264,8 @@ static void l2cap_chan_le_recv_sdu(struct bt_l2cap_le_chan *chan,
22452264

22462265
BT_DBG("chan %p len %zu", chan, net_buf_frags_len(buf));
22472266

2267+
__ASSERT_NO_MSG(bt_l2cap_chan_get_state(&chan->chan) == BT_L2CAP_CONNECTED);
2268+
22482269
/* Receiving complete SDU, notify channel and reset SDU buf */
22492270
err = chan->chan.ops->recv(&chan->chan, buf);
22502271
if (err < 0) {
@@ -2256,7 +2277,10 @@ static void l2cap_chan_le_recv_sdu(struct bt_l2cap_le_chan *chan,
22562277
return;
22572278
}
22582279

2259-
l2cap_chan_send_credits(chan, buf, seg);
2280+
if (bt_l2cap_chan_get_state(&chan->chan) == BT_L2CAP_CONNECTED) {
2281+
l2cap_chan_send_credits(chan, buf, seg);
2282+
}
2283+
22602284
net_buf_unref(buf);
22612285
}
22622286

0 commit comments

Comments
 (0)