diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 7ea13c0fad44..210d1507af7e 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -157,6 +157,29 @@ static struct l2cap_chan *__l2cap_get_chan_by_ident(struct l2cap_conn *conn, return NULL; } +/* Our connection request has been sent and is still outstanding */ +static bool l2cap_chan_connect_pending(struct l2cap_chan *chan) +{ + return chan->state == BT_CONNECT && + test_bit(CONF_CONNECT_PEND, &chan->conf_state); +} + +/* Other channels may hold the same ident for a response they still have + * to send, so only look at channels waiting for a connection response. + */ +static struct l2cap_chan *__l2cap_get_connect_chan_by_ident(struct l2cap_conn *conn, + u8 ident) + __must_hold(&conn->lock) +{ + struct l2cap_chan *c; + + list_for_each_entry(c, &conn->chan_l, list) { + if (c->ident == ident && l2cap_chan_connect_pending(c)) + return c; + } + return NULL; +} + static struct l2cap_chan *__l2cap_global_chan_by_addr(__le16 psm, bdaddr_t *src, u8 src_type) __must_hold_shared(&chan_list_lock) @@ -4446,7 +4469,7 @@ static int l2cap_connect_create_rsp(struct l2cap_conn *conn, if (!chan) return -EBADSLT; } else { - chan = __l2cap_get_chan_by_ident(conn, cmd->ident); + chan = __l2cap_get_connect_chan_by_ident(conn, cmd->ident); if (!chan) return -EBADSLT; } @@ -4461,8 +4484,11 @@ static int l2cap_connect_create_rsp(struct l2cap_conn *conn, lockdep_assert_held(&chan->conn->lock); - /* Ignore a late response after the channel has left BT_CONNECT. */ - if (chan->state != BT_CONNECT) + /* Only accept a response to a connection request we sent and that + * is still outstanding. A channel waiting in BT_CONNECT for security + * or the feature mask has not sent one yet. + */ + if (!l2cap_chan_connect_pending(chan)) goto done; switch (result) {