Bluetooth: L2CAP: Fix not cleanup properly if ACL is disconnected
If ACL is disconnected with channels still active the code should call l2cap_chan_del to clean it up properly. Change-Id: Iffa9345a9697ac80c1f2295578c7161ffeb44420 Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
This commit is contained in:
parent
997765def2
commit
b008f74b0b
2 changed files with 42 additions and 31 deletions
|
@ -55,6 +55,7 @@ struct bt_l2cap_chan {
|
||||||
/** Channel operations reference */
|
/** Channel operations reference */
|
||||||
struct bt_l2cap_chan_ops *ops;
|
struct bt_l2cap_chan_ops *ops;
|
||||||
struct bt_l2cap_chan *_next;
|
struct bt_l2cap_chan *_next;
|
||||||
|
void (*destroy)(struct bt_l2cap_chan *chan);
|
||||||
};
|
};
|
||||||
|
|
||||||
/** @brief LE L2CAP Endpoint structure. */
|
/** @brief LE L2CAP Endpoint structure. */
|
||||||
|
|
|
@ -190,6 +190,21 @@ void bt_l2cap_connected(struct bt_conn *conn)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void l2cap_chan_del(struct bt_l2cap_chan *chan)
|
||||||
|
{
|
||||||
|
BT_DBG("conn %p chan %p", chan->conn, chan);
|
||||||
|
|
||||||
|
chan->conn = NULL;
|
||||||
|
|
||||||
|
if (chan->ops && chan->ops->disconnected) {
|
||||||
|
chan->ops->disconnected(chan);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (chan->destroy) {
|
||||||
|
chan->destroy(chan);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void bt_l2cap_disconnected(struct bt_conn *conn)
|
void bt_l2cap_disconnected(struct bt_conn *conn)
|
||||||
{
|
{
|
||||||
struct bt_l2cap_chan *chan;
|
struct bt_l2cap_chan *chan;
|
||||||
|
@ -200,11 +215,8 @@ void bt_l2cap_disconnected(struct bt_conn *conn)
|
||||||
/* prefetch since disconnected callback may cleanup */
|
/* prefetch since disconnected callback may cleanup */
|
||||||
next = chan->_next;
|
next = chan->_next;
|
||||||
|
|
||||||
if (chan->ops->disconnected) {
|
l2cap_chan_del(chan);
|
||||||
chan->ops->disconnected(chan);
|
|
||||||
}
|
|
||||||
|
|
||||||
chan->conn = NULL;
|
|
||||||
chan = next;
|
chan = next;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -412,6 +424,27 @@ static void l2cap_chan_rx_give_credits(struct bt_l2cap_le_chan *chan,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void l2cap_chan_destroy(struct bt_l2cap_chan *chan)
|
||||||
|
{
|
||||||
|
struct bt_l2cap_le_chan *ch = BT_L2CAP_LE_CHAN(chan);
|
||||||
|
|
||||||
|
BT_DBG("chan %p cid 0x%04x", chan->conn, ch, ch->rx.cid);
|
||||||
|
|
||||||
|
/* There could be a writer waiting for credits so return a dummy credit
|
||||||
|
* to wake it up.
|
||||||
|
*/
|
||||||
|
if (!ch->tx.credits.nsig) {
|
||||||
|
l2cap_chan_tx_give_credits(ch, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Destroy segmented SDU if it exists */
|
||||||
|
if (ch->_sdu) {
|
||||||
|
net_buf_unref(ch->_sdu);
|
||||||
|
ch->_sdu = NULL;
|
||||||
|
ch->_sdu_len = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void le_conn_req(struct bt_l2cap *l2cap, uint8_t ident,
|
static void le_conn_req(struct bt_l2cap *l2cap, uint8_t ident,
|
||||||
struct net_buf *buf)
|
struct net_buf *buf)
|
||||||
{
|
{
|
||||||
|
@ -488,6 +521,8 @@ static void le_conn_req(struct bt_l2cap *l2cap, uint8_t ident,
|
||||||
if (l2cap_chan_add(conn, chan)) {
|
if (l2cap_chan_add(conn, chan)) {
|
||||||
struct bt_l2cap_le_chan *ch = BT_L2CAP_LE_CHAN(chan);
|
struct bt_l2cap_le_chan *ch = BT_L2CAP_LE_CHAN(chan);
|
||||||
|
|
||||||
|
chan->destroy = l2cap_chan_destroy;
|
||||||
|
|
||||||
/* Init TX parameters */
|
/* Init TX parameters */
|
||||||
l2cap_chan_tx_init(ch);
|
l2cap_chan_tx_init(ch);
|
||||||
ch->tx.cid = scid;
|
ch->tx.cid = scid;
|
||||||
|
@ -542,33 +577,6 @@ static struct bt_l2cap_le_chan *l2cap_remove_tx_cid(struct bt_conn *conn,
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void l2cap_chan_del(struct bt_l2cap_chan *chan)
|
|
||||||
{
|
|
||||||
struct bt_l2cap_le_chan *ch = BT_L2CAP_LE_CHAN(chan);
|
|
||||||
|
|
||||||
BT_DBG("conn %p chan %p cid 0x%04x", chan->conn, ch, ch->rx.cid);
|
|
||||||
|
|
||||||
ch->chan.conn = NULL;
|
|
||||||
|
|
||||||
if (chan->ops && chan->ops->disconnected) {
|
|
||||||
chan->ops->disconnected(chan);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* There could be a writer waiting for credits so return a dummy credit
|
|
||||||
* to wake it up.
|
|
||||||
*/
|
|
||||||
if (!ch->tx.credits.nsig) {
|
|
||||||
l2cap_chan_tx_give_credits(ch, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Destroy segmented SDU if it exists */
|
|
||||||
if (ch->_sdu) {
|
|
||||||
net_buf_unref(ch->_sdu);
|
|
||||||
ch->_sdu = NULL;
|
|
||||||
ch->_sdu_len = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void le_disconn_req(struct bt_l2cap *l2cap, uint8_t ident,
|
static void le_disconn_req(struct bt_l2cap *l2cap, uint8_t ident,
|
||||||
struct net_buf *buf)
|
struct net_buf *buf)
|
||||||
{
|
{
|
||||||
|
@ -1167,6 +1175,8 @@ static int l2cap_le_connect(struct bt_conn *conn, struct bt_l2cap_le_chan *ch,
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ch->chan.destroy = l2cap_chan_destroy;
|
||||||
|
|
||||||
buf = bt_l2cap_create_pdu(&le_sig);
|
buf = bt_l2cap_create_pdu(&le_sig);
|
||||||
if (!buf) {
|
if (!buf) {
|
||||||
BT_ERR("Unable to send L2CAP connection request");
|
BT_ERR("Unable to send L2CAP connection request");
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue