Commit d330e86e authored by Lyle Zhu's avatar Lyle Zhu Committed by Fabio Baltieri
Browse files

Bluetooth: Classic: l2cap: Fix ACL conn invalid issue



There is an issue found that the L2CAP BR channel attempts to send
signaling commands through fixed channel when the ACL connect is
broken. At this time, the ACL connect of fixed channel is invalid.
Then the `__assert` occurs in function `bt_conn_ref()`.

Fixed the issue by checking the ACL conn of the L2CAP channel before
sending the data.

Here is a referred fault case for this changes,
There are two connected L2CAP Channels. The first one is primary
connection of the profile. And the second one is secondary connection
of the profile. When the primary connection is broken, the secondary
connection should also be disconnected.
In normal case, if the primary connection is disconnected by calling
L2CAP channel disconnection function, the secondary connection will
be disconnected by calling L2CAP channel disconnection in the
disconnected callback of primary connection.

But there is a corner case is that, the ACL connection is broken.
When the disconnected callback of primary connection is called, the
function call of L2CAP channel disconnection for secondary connection
will be asserted. Because the signaling channel (fixed channel ID
0x01) is disconnected and the `chan->conn` of the fixed channel is
NULL in this time.

The call stack is,
o bt_conn_ref() -> Asserted in this function.
o bt_conn_data_ready() -> The parameter is `br_chan->chan.conn`.
  It is the NULL.
o raise_data_ready() -> The parameter `br_chan` is fixed channel.
o bt_l2cap_br_send_cb() -> The parameter is ACL conn and CID of fixed
  channel (cid = 0x01). The channel can be found, but `chan->conn` is
  NULL.
o l2cap_br_chan_send_req()
o bt_l2cap_br_chan_disconnect()
o bt_l2cap_chan_disconnect() -> The parameter is the channel of
  secondary connection. The state of secondary channel is connected,
  because the stack is handling the primary channel disconnecting.
  And the function is called in disconnected callback of primary
  channel.

Signed-off-by: default avatarLyle Zhu <lyle.zhu@nxp.com>
parent 2bfa1869
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -899,6 +899,11 @@ int bt_l2cap_br_send_cb(struct bt_conn *conn, uint16_t cid, struct net_buf *buf,
		return -ESHUTDOWN;
	}

	if (ch->conn == NULL) {
		LOG_WRN("ACL conn of chan %p is invalid", ch);
		return -ENOTCONN;
	}

	br_chan = CONTAINER_OF(ch, struct bt_l2cap_br_chan, chan);

	LOG_DBG("chan %p buf %p len %u", br_chan, buf, buf->len);