From: Mat Martineau Date: Wed, 2 May 2012 16:42:00 +0000 (-0700) Subject: Bluetooth: Restore locking semantics when looking up L2CAP channels X-Git-Url: http://git.lede-project.org./?a=commitdiff_plain;h=ef191aded58c5e6860b01f463818584a420a4d6b;p=openwrt%2Fstaging%2Fblogic.git 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: Mat Martineau Reviewed-by: Ulisses Furquim Signed-off-by: Gustavo Padovan --- diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index aea54f55c41d..285c5e13c7d5 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -98,13 +98,15 @@ static struct l2cap_chan *__l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16 } /* 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) { struct l2cap_chan *c; mutex_lock(&conn->chan_lock); c = __l2cap_get_chan_by_scid(conn, cid); + if (c) + l2cap_chan_lock(c); mutex_unlock(&conn->chan_lock); return c; @@ -3183,8 +3185,6 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr if (!chan) return -ENOENT; - l2cap_chan_lock(chan); - if (chan->state != BT_CONFIG && chan->state != BT_CONNECT2) { struct l2cap_cmd_rej_cid rej; @@ -3297,8 +3297,6 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr if (!chan) return 0; - l2cap_chan_lock(chan); - switch (result) { case L2CAP_CONF_SUCCESS: 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 return 0; } - l2cap_chan_lock(chan); - BT_DBG("chan %p, len %d", chan, skb->len); if (chan->state != BT_CONNECTED)