diff options
author | Mat Martineau <mathewm@codeaurora.org> | 2012-05-02 12:42:00 -0400 |
---|---|---|
committer | Gustavo Padovan <gustavo.padovan@collabora.co.uk> | 2012-05-16 15:13:51 -0400 |
commit | ef191aded58c5e6860b01f463818584a420a4d6b (patch) | |
tree | 3459b8a02ec5b4ef4566f139275c1c9dc234b3ce /net | |
parent | 35c84d76ee52f49fe2635d8cd686b5b658e8d892 (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.c | 10 |
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. */ |
102 | static struct l2cap_chan *l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16 cid) | 102 | static 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) |