Commit 984947dc authored by Marcel Holtmann's avatar Marcel Holtmann

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: default avatarMarcel Holtmann <marcel@holtmann.org>
parent 657e17b0
...@@ -223,7 +223,8 @@ struct l2cap_conn { ...@@ -223,7 +223,8 @@ struct l2cap_conn {
}; };
#define L2CAP_INFO_CL_MTU_REQ_SENT 0x01 #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 ----- */ /* ----- L2CAP channel and socket info ----- */
#define l2cap_pi(sk) ((struct l2cap_pinfo *) sk) #define l2cap_pi(sk) ((struct l2cap_pinfo *) sk)
......
...@@ -320,6 +320,9 @@ static void l2cap_do_start(struct sock *sk) ...@@ -320,6 +320,9 @@ static void l2cap_do_start(struct sock *sk)
struct l2cap_conn *conn = l2cap_pi(sk)->conn; 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_SENT) {
if (!(conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE))
return;
if (l2cap_check_security(sk)) { if (l2cap_check_security(sk)) {
struct l2cap_conn_req req; struct l2cap_conn_req req;
req.scid = cpu_to_le16(l2cap_pi(sk)->scid); req.scid = cpu_to_le16(l2cap_pi(sk)->scid);
...@@ -455,6 +458,8 @@ static void l2cap_info_timeout(unsigned long arg) ...@@ -455,6 +458,8 @@ static void l2cap_info_timeout(unsigned long arg)
conn->info_ident = 0; conn->info_ident = 0;
conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
l2cap_conn_start(conn); l2cap_conn_start(conn);
} }
...@@ -1787,6 +1792,9 @@ static inline int l2cap_command_rej(struct l2cap_conn *conn, struct l2cap_cmd_hd ...@@ -1787,6 +1792,9 @@ static inline int l2cap_command_rej(struct l2cap_conn *conn, struct l2cap_cmd_hd
cmd->ident == conn->info_ident) { cmd->ident == conn->info_ident) {
conn->info_ident = 0; conn->info_ident = 0;
del_timer(&conn->info_timer); del_timer(&conn->info_timer);
conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
l2cap_conn_start(conn); l2cap_conn_start(conn);
} }
...@@ -1857,7 +1865,7 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd ...@@ -1857,7 +1865,7 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd
l2cap_pi(sk)->ident = cmd->ident; 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 (l2cap_check_security(sk)) {
if (bt_sk(sk)->defer_setup) { if (bt_sk(sk)->defer_setup) {
sk->sk_state = BT_CONNECT2; sk->sk_state = BT_CONNECT2;
...@@ -2176,10 +2184,13 @@ static inline int l2cap_information_rsp(struct l2cap_conn *conn, struct l2cap_cm ...@@ -2176,10 +2184,13 @@ static inline int l2cap_information_rsp(struct l2cap_conn *conn, struct l2cap_cm
del_timer(&conn->info_timer); 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); conn->feat_mask = get_unaligned_le32(rsp->data);
conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
l2cap_conn_start(conn); l2cap_conn_start(conn);
}
return 0; return 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment