Commit ef191ade authored by Mat Martineau's avatar Mat Martineau Committed by Gustavo Padovan

Bluetooth: Restore locking semantics when looking up L2CAP channels

As the comment for l2cap_get_chan_by_scid indicated, the function used
to return a locked socket.  The lock for the socket was acquired while
the channel list was also locked.

When locking was moved over to the l2cap_chan structure, the channel
lock was no longer acquired with the channel list still locked.  This
made it possible for the l2cap_chan to be deleted after
conn->chan_lock was released but before l2cap_chan_lock was called.
Making the call to l2cap_chan_lock before releasing conn->chan_lock
makes it impossible for the l2cap_chan to be deleted at the wrong
time.
Signed-off-by: default avatarMat Martineau <mathewm@codeaurora.org>
Reviewed-by: default avatarUlisses Furquim <ulisses@profusion.mobi>
Signed-off-by: default avatarGustavo Padovan <gustavo@padovan.org>
parent 35c84d76
...@@ -98,13 +98,15 @@ static struct l2cap_chan *__l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16 ...@@ -98,13 +98,15 @@ static struct l2cap_chan *__l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16
} }
/* Find channel with given SCID. /* Find channel with given SCID.
* Returns locked socket */ * Returns locked channel. */
static struct l2cap_chan *l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16 cid) static struct l2cap_chan *l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16 cid)
{ {
struct l2cap_chan *c; struct l2cap_chan *c;
mutex_lock(&conn->chan_lock); mutex_lock(&conn->chan_lock);
c = __l2cap_get_chan_by_scid(conn, cid); c = __l2cap_get_chan_by_scid(conn, cid);
if (c)
l2cap_chan_lock(c);
mutex_unlock(&conn->chan_lock); mutex_unlock(&conn->chan_lock);
return c; return c;
...@@ -3183,8 +3185,6 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr ...@@ -3183,8 +3185,6 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr
if (!chan) if (!chan)
return -ENOENT; return -ENOENT;
l2cap_chan_lock(chan);
if (chan->state != BT_CONFIG && chan->state != BT_CONNECT2) { if (chan->state != BT_CONFIG && chan->state != BT_CONNECT2) {
struct l2cap_cmd_rej_cid rej; struct l2cap_cmd_rej_cid rej;
...@@ -3297,8 +3297,6 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr ...@@ -3297,8 +3297,6 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr
if (!chan) if (!chan)
return 0; return 0;
l2cap_chan_lock(chan);
switch (result) { switch (result) {
case L2CAP_CONF_SUCCESS: case L2CAP_CONF_SUCCESS:
l2cap_conf_rfc_get(chan, rsp->data, len); l2cap_conf_rfc_get(chan, rsp->data, len);
...@@ -4631,8 +4629,6 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk ...@@ -4631,8 +4629,6 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk
return 0; return 0;
} }
l2cap_chan_lock(chan);
BT_DBG("chan %p, len %d", chan, skb->len); BT_DBG("chan %p, len %d", chan, skb->len);
if (chan->state != BT_CONNECTED) if (chan->state != BT_CONNECTED)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment