diff options
author | Marcel Holtmann <marcel@holtmann.org> | 2009-02-06 23:35:19 +0100 |
---|---|---|
committer | Marcel Holtmann <marcel@holtmann.org> | 2009-02-27 06:14:41 +0100 |
commit | 984947dc64f82bc6cafa4d84ba1a139718f634a8 (patch) | |
tree | f85e4b260034f5b5a20af7a63900ee7de06fa7ad | |
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>
-rw-r--r-- | include/net/bluetooth/l2cap.h | 3 | ||||
-rw-r--r-- | net/bluetooth/l2cap.c | 17 |
2 files changed, 16 insertions, 4 deletions
diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 29f720e6188a..1c8cf3e9b1ca 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -223,7 +223,8 @@ struct l2cap_conn { }; #define L2CAP_INFO_CL_MTU_REQ_SENT 0x01 -#define L2CAP_INFO_FEAT_MASK_REQ_SENT 0x02 +#define L2CAP_INFO_FEAT_MASK_REQ_SENT 0x04 +#define L2CAP_INFO_FEAT_MASK_REQ_DONE 0x08 /* ----- L2CAP channel and socket info ----- */ #define l2cap_pi(sk) ((struct l2cap_pinfo *) sk) 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) struct l2cap_conn *conn = l2cap_pi(sk)->conn; if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) { + if (!(conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE)) + return; + if (l2cap_check_security(sk)) { struct l2cap_conn_req req; req.scid = cpu_to_le16(l2cap_pi(sk)->scid); @@ -455,6 +458,8 @@ static void l2cap_info_timeout(unsigned long arg) conn->info_ident = 0; + conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE; + l2cap_conn_start(conn); } @@ -1787,6 +1792,9 @@ static inline int l2cap_command_rej(struct l2cap_conn *conn, struct l2cap_cmd_hd cmd->ident == conn->info_ident) { conn->info_ident = 0; del_timer(&conn->info_timer); + + conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE; + l2cap_conn_start(conn); } @@ -1857,7 +1865,7 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd l2cap_pi(sk)->ident = cmd->ident; - if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) { + if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE) { if (l2cap_check_security(sk)) { if (bt_sk(sk)->defer_setup) { sk->sk_state = BT_CONNECT2; @@ -2176,10 +2184,13 @@ static inline int l2cap_information_rsp(struct l2cap_conn *conn, struct l2cap_cm del_timer(&conn->info_timer); - if (type == L2CAP_IT_FEAT_MASK) + if (type == L2CAP_IT_FEAT_MASK) { conn->feat_mask = get_unaligned_le32(rsp->data); - l2cap_conn_start(conn); + conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE; + + l2cap_conn_start(conn); + } return 0; } |