Bluetooth: L2CAP: Don't try to send on disconnected channel

We could start executing the work item after the channel has been
disconnected or destroyed, due to a race condition.

Double-check we are connected before attempting to send data.

Signed-off-by: Jonathan Rico <jonathan.rico@nordicsemi.no>
This commit is contained in:
Jonathan Rico 2024-04-17 13:57:50 +02:00 committed by Carles Cufí
parent 57b94080b2
commit e4364413c2

View file

@ -899,6 +899,22 @@ static struct net_buf *l2cap_chan_le_get_tx_buf(struct bt_l2cap_le_chan *ch)
static int l2cap_chan_le_send_sdu(struct bt_l2cap_le_chan *ch,
struct net_buf *buf);
/** @brief Get @c chan->state.
*
* This field does not exist when @kconfig{CONFIG_BT_L2CAP_DYNAMIC_CHANNEL} is
* disabled. In that case, this function returns @ref BT_L2CAP_CONNECTED since
* the struct can only represent static channels in that case and static
* channels are always connected.
*/
static bt_l2cap_chan_state_t bt_l2cap_chan_get_state(struct bt_l2cap_chan *chan)
{
#if defined(CONFIG_BT_L2CAP_DYNAMIC_CHANNEL)
return BT_L2CAP_LE_CHAN(chan)->state;
#else
return BT_L2CAP_CONNECTED;
#endif
}
static void l2cap_chan_tx_process(struct k_work *work)
{
struct bt_l2cap_le_chan *ch;
@ -907,6 +923,11 @@ static void l2cap_chan_tx_process(struct k_work *work)
ch = CONTAINER_OF(k_work_delayable_from_work(work), struct bt_l2cap_le_chan, tx_work);
if (bt_l2cap_chan_get_state(&ch->chan) != BT_L2CAP_CONNECTED) {
LOG_DBG("Cannot send on non-connected channel");
return;
}
/* Resume tx in case there are buffers in the queue */
while ((buf = l2cap_chan_le_get_tx_buf(ch))) {
/* Here buf is either:
@ -2214,22 +2235,6 @@ static void l2cap_chan_shutdown(struct bt_l2cap_chan *chan)
}
}
/** @brief Get @c chan->state.
*
* This field does not exist when @kconfig{CONFIG_BT_L2CAP_DYNAMIC_CHANNEL} is
* disabled. In that case, this function returns @ref BT_L2CAP_CONNECTED since
* the struct can only represent static channels in that case and static
* channels are always connected.
*/
static inline bt_l2cap_chan_state_t bt_l2cap_chan_get_state(struct bt_l2cap_chan *chan)
{
#if defined(CONFIG_BT_L2CAP_DYNAMIC_CHANNEL)
return BT_L2CAP_LE_CHAN(chan)->state;
#else
return BT_L2CAP_CONNECTED;
#endif
}
static void l2cap_chan_send_credits(struct bt_l2cap_le_chan *chan,
uint16_t credits)
{