Skip to content

Commit 088526c

Browse files
committed
Bluetooth: L2CAP: Introduce BT_L2CAP_STATUS_SHUTDOWN flag
This introduces BT_L2CAP_STATUS_SHUTDOWN which is used to indicate when a channel has been shutdown. Signed-off-by: Luiz Augusto von Dentz <[email protected]>
1 parent 4dabce3 commit 088526c

File tree

2 files changed

+61
-1
lines changed

2 files changed

+61
-1
lines changed

include/bluetooth/l2cap.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,13 @@ typedef enum bt_l2cap_chan_status {
7474
/** Channel output status */
7575
BT_L2CAP_STATUS_OUT,
7676

77+
/** Channel shutdown status
78+
*
79+
* Once this status is notified it means the channel will no longer be
80+
* able to transmit or receive data.
81+
*/
82+
BT_L2CAP_STATUS_SHUTDOWN,
83+
7784
/* Total number of status - must be at the end of the enum */
7885
BT_L2CAP_NUM_STATUS,
7986
} __packed bt_l2cap_chan_status_t;

subsys/bluetooth/host/l2cap.c

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,8 @@ void bt_l2cap_chan_del(struct bt_l2cap_chan *chan)
255255
if (chan->destroy) {
256256
chan->destroy(chan);
257257
}
258+
259+
atomic_clear(chan->status);
258260
}
259261

260262
static void l2cap_rtx_timeout(struct k_work *work)
@@ -1503,6 +1505,44 @@ static int l2cap_recv(struct bt_l2cap_chan *chan, struct net_buf *buf)
15031505
}
15041506

15051507
#if defined(CONFIG_BT_L2CAP_DYNAMIC_CHANNEL)
1508+
static void l2cap_chan_shutdown(struct bt_l2cap_chan *chan)
1509+
{
1510+
struct bt_l2cap_le_chan *ch = BT_L2CAP_LE_CHAN(chan);
1511+
struct net_buf *buf;
1512+
1513+
BT_DBG("chan %p", chan);
1514+
1515+
atomic_set_bit(chan->status, BT_L2CAP_STATUS_SHUTDOWN);
1516+
1517+
/* Destroy segmented SDU if it exists */
1518+
if (ch->_sdu) {
1519+
net_buf_unref(ch->_sdu);
1520+
ch->_sdu = NULL;
1521+
ch->_sdu_len = 0U;
1522+
}
1523+
1524+
/* Cleanup outstanding request */
1525+
if (ch->tx_buf) {
1526+
net_buf_unref(ch->tx_buf);
1527+
ch->tx_buf = NULL;
1528+
}
1529+
1530+
/* Remove buffers on the TX queue */
1531+
while ((buf = net_buf_get(&ch->tx_queue, K_NO_WAIT))) {
1532+
net_buf_unref(buf);
1533+
}
1534+
1535+
/* Remove buffers on the RX queue */
1536+
while ((buf = net_buf_get(&ch->rx_queue, K_NO_WAIT))) {
1537+
net_buf_unref(buf);
1538+
}
1539+
1540+
/* Update status */
1541+
if (chan->ops->status) {
1542+
chan->ops->status(chan, chan->status);
1543+
}
1544+
}
1545+
15061546
static void l2cap_chan_send_credits(struct bt_l2cap_le_chan *chan,
15071547
struct net_buf *buf, u16_t credits)
15081548
{
@@ -1517,7 +1557,10 @@ static void l2cap_chan_send_credits(struct bt_l2cap_le_chan *chan,
15171557
sizeof(*ev));
15181558
if (!buf) {
15191559
BT_ERR("Unable to send credits update");
1520-
bt_l2cap_chan_disconnect(&chan->chan);
1560+
/* Disconnect would probably not work either so the only
1561+
* option left is to shutdown the channel.
1562+
*/
1563+
l2cap_chan_shutdown(&chan->chan);
15211564
return;
15221565
}
15231566

@@ -1727,6 +1770,12 @@ static void l2cap_chan_recv_queue(struct bt_l2cap_le_chan *chan,
17271770
return;
17281771
}
17291772

1773+
if (atomic_test_bit(chan->chan.status, BT_L2CAP_STATUS_SHUTDOWN)) {
1774+
BT_WARN("Ignoring data received while channel has shutdown");
1775+
net_buf_unref(buf);
1776+
return;
1777+
}
1778+
17301779
net_buf_put(&chan->rx_queue, buf);
17311780
k_work_submit(&chan->rx_work);
17321781
}
@@ -1956,6 +2005,10 @@ int bt_l2cap_chan_send(struct bt_l2cap_chan *chan, struct net_buf *buf)
19562005
return -ENOTCONN;
19572006
}
19582007

2008+
if (atomic_test_bit(chan->status, BT_L2CAP_STATUS_SHUTDOWN)) {
2009+
return -ESHUTDOWN;
2010+
}
2011+
19592012
if (IS_ENABLED(CONFIG_BT_BREDR) &&
19602013
chan->conn->type == BT_CONN_TYPE_BR) {
19612014
return bt_l2cap_br_chan_send(chan, buf);

0 commit comments

Comments
 (0)