aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorMat Martineau <mathewm@codeaurora.org>2012-05-02 12:42:00 -0400
committerGustavo Padovan <gustavo.padovan@collabora.co.uk>2012-05-16 15:13:51 -0400
commitef191aded58c5e6860b01f463818584a420a4d6b (patch)
tree3459b8a02ec5b4ef4566f139275c1c9dc234b3ce /net
parent35c84d76ee52f49fe2635d8cd686b5b658e8d892 (diff)
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 <mathewm@codeaurora.org> Reviewed-by: Ulisses Furquim <ulisses@profusion.mobi> Signed-off-by: Gustavo Padovan <gustavo@padovan.org>
Diffstat (limited to 'net')
-rw-r--r--net/bluetooth/l2cap_core.c10
1 files changed, 3 insertions, 7 deletions
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
98} 98}
99 99
100/* Find channel with given SCID. 100/* Find channel with given SCID.
101 * Returns locked socket */ 101 * Returns locked channel. */
102static struct l2cap_chan *l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16 cid) 102static struct l2cap_chan *l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16 cid)
103{ 103{
104 struct l2cap_chan *c; 104 struct l2cap_chan *c;
105 105
106 mutex_lock(&conn->chan_lock); 106 mutex_lock(&conn->chan_lock);
107 c = __l2cap_get_chan_by_scid(conn, cid); 107 c = __l2cap_get_chan_by_scid(conn, cid);
108 if (c)
109 l2cap_chan_lock(c);
108 mutex_unlock(&conn->chan_lock); 110 mutex_unlock(&conn->chan_lock);
109 111
110 return c; 112 return c;
@@ -3183,8 +3185,6 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr
3183 if (!chan) 3185 if (!chan)
3184 return -ENOENT; 3186 return -ENOENT;
3185 3187
3186 l2cap_chan_lock(chan);
3187
3188 if (chan->state != BT_CONFIG && chan->state != BT_CONNECT2) { 3188 if (chan->state != BT_CONFIG && chan->state != BT_CONNECT2) {
3189 struct l2cap_cmd_rej_cid rej; 3189 struct l2cap_cmd_rej_cid rej;
3190 3190
@@ -3297,8 +3297,6 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr
3297 if (!chan) 3297 if (!chan)
3298 return 0; 3298 return 0;
3299 3299
3300 l2cap_chan_lock(chan);
3301
3302 switch (result) { 3300 switch (result) {
3303 case L2CAP_CONF_SUCCESS: 3301 case L2CAP_CONF_SUCCESS:
3304 l2cap_conf_rfc_get(chan, rsp->data, len); 3302 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 return 0; 4629 return 0;
4632 } 4630 }
4633 4631
4634 l2cap_chan_lock(chan);
4635
4636 BT_DBG("chan %p, len %d", chan, skb->len); 4632 BT_DBG("chan %p, len %d", chan, skb->len);
4637 4633
4638 if (chan->state != BT_CONNECTED) 4634 if (chan->state != BT_CONNECTED)