diff options
author | Marcel Holtmann <marcel@holtmann.org> | 2009-02-06 17:35:19 -0500 |
---|---|---|
committer | Marcel Holtmann <marcel@holtmann.org> | 2009-02-27 00:14:41 -0500 |
commit | 984947dc64f82bc6cafa4d84ba1a139718f634a8 (patch) | |
tree | f85e4b260034f5b5a20af7a63900ee7de06fa7ad /net/bluetooth/l2cap.c | |
parent | 657e17b03c80bec817975984d221bef716f83558 (diff) |
Bluetooth: Fix race condition with L2CAP information request
When two L2CAP connections are requested quickly after the ACL link has
been established there exists a window for a race condition where a
connection request is sent before the information response has been
received. Any connection request should only be sent after an exchange
of the extended features mask has been finished.
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
Diffstat (limited to 'net/bluetooth/l2cap.c')
-rw-r--r-- | net/bluetooth/l2cap.c | 17 |
1 files changed, 14 insertions, 3 deletions
diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index 8a93dde4095b..07fdbc7dd54d 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c | |||
@@ -320,6 +320,9 @@ static void l2cap_do_start(struct sock *sk) | |||
320 | struct l2cap_conn *conn = l2cap_pi(sk)->conn; | 320 | struct l2cap_conn *conn = l2cap_pi(sk)->conn; |
321 | 321 | ||
322 | if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) { | 322 | if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) { |
323 | if (!(conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE)) | ||
324 | return; | ||
325 | |||
323 | if (l2cap_check_security(sk)) { | 326 | if (l2cap_check_security(sk)) { |
324 | struct l2cap_conn_req req; | 327 | struct l2cap_conn_req req; |
325 | req.scid = cpu_to_le16(l2cap_pi(sk)->scid); | 328 | req.scid = cpu_to_le16(l2cap_pi(sk)->scid); |
@@ -455,6 +458,8 @@ static void l2cap_info_timeout(unsigned long arg) | |||
455 | 458 | ||
456 | conn->info_ident = 0; | 459 | conn->info_ident = 0; |
457 | 460 | ||
461 | conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE; | ||
462 | |||
458 | l2cap_conn_start(conn); | 463 | l2cap_conn_start(conn); |
459 | } | 464 | } |
460 | 465 | ||
@@ -1787,6 +1792,9 @@ static inline int l2cap_command_rej(struct l2cap_conn *conn, struct l2cap_cmd_hd | |||
1787 | cmd->ident == conn->info_ident) { | 1792 | cmd->ident == conn->info_ident) { |
1788 | conn->info_ident = 0; | 1793 | conn->info_ident = 0; |
1789 | del_timer(&conn->info_timer); | 1794 | del_timer(&conn->info_timer); |
1795 | |||
1796 | conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE; | ||
1797 | |||
1790 | l2cap_conn_start(conn); | 1798 | l2cap_conn_start(conn); |
1791 | } | 1799 | } |
1792 | 1800 | ||
@@ -1857,7 +1865,7 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd | |||
1857 | 1865 | ||
1858 | l2cap_pi(sk)->ident = cmd->ident; | 1866 | l2cap_pi(sk)->ident = cmd->ident; |
1859 | 1867 | ||
1860 | if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) { | 1868 | if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE) { |
1861 | if (l2cap_check_security(sk)) { | 1869 | if (l2cap_check_security(sk)) { |
1862 | if (bt_sk(sk)->defer_setup) { | 1870 | if (bt_sk(sk)->defer_setup) { |
1863 | sk->sk_state = BT_CONNECT2; | 1871 | sk->sk_state = BT_CONNECT2; |
@@ -2176,10 +2184,13 @@ static inline int l2cap_information_rsp(struct l2cap_conn *conn, struct l2cap_cm | |||
2176 | 2184 | ||
2177 | del_timer(&conn->info_timer); | 2185 | del_timer(&conn->info_timer); |
2178 | 2186 | ||
2179 | if (type == L2CAP_IT_FEAT_MASK) | 2187 | if (type == L2CAP_IT_FEAT_MASK) { |
2180 | conn->feat_mask = get_unaligned_le32(rsp->data); | 2188 | conn->feat_mask = get_unaligned_le32(rsp->data); |
2181 | 2189 | ||
2182 | l2cap_conn_start(conn); | 2190 | conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE; |
2191 | |||
2192 | l2cap_conn_start(conn); | ||
2193 | } | ||
2183 | 2194 | ||
2184 | return 0; | 2195 | return 0; |
2185 | } | 2196 | } |