summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarcel Holtmann <marcel@holtmann.org>2009-02-06 23:56:36 +0100
committerNick Pelly <npelly@google.com>2009-04-06 17:39:29 -0700
commit975f50007602fc41ee34248fee1e5f53daf24b69 (patch)
treefbca3ccb2f679a2d5b4ff1b8e7de6db8e3025379
parent84cde0e1ce16cf400a787f93cfb0555e4435bec9 (diff)
Bluetooth: Fix double L2CAP connection request
If the remote L2CAP server uses authentication pending stage and encryption is enabled it can happen that a L2CAP connection request is sent twice due to a race condition in the connection state machine. When the remote side indicates any kind of connection pending, then track this state and skip sending of L2CAP commands for this period. Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
-rw-r--r--include/net/bluetooth/l2cap.h1
-rw-r--r--net/bluetooth/l2cap.c8
2 files changed, 9 insertions, 0 deletions
diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index 1c8cf3e9b1ca..4781d285b2e9 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -259,6 +259,7 @@ struct l2cap_pinfo {
#define L2CAP_CONF_REQ_SENT 0x01
#define L2CAP_CONF_INPUT_DONE 0x02
#define L2CAP_CONF_OUTPUT_DONE 0x04
+#define L2CAP_CONF_CONNECT_PEND 0x80
#define L2CAP_CONF_MAX_RETRIES 2
diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c
index 07fdbc7dd54d..01f750142d55 100644
--- a/net/bluetooth/l2cap.c
+++ b/net/bluetooth/l2cap.c
@@ -1946,11 +1946,14 @@ static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hd
l2cap_pi(sk)->dcid = dcid;
l2cap_pi(sk)->conf_state |= L2CAP_CONF_REQ_SENT;
+ l2cap_pi(sk)->conf_state &= ~L2CAP_CONF_CONNECT_PEND;
+
l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
l2cap_build_conf_req(sk, req), req);
break;
case L2CAP_CR_PEND:
+ l2cap_pi(sk)->conf_state |= L2CAP_CONF_CONNECT_PEND;
break;
default:
@@ -2478,6 +2481,11 @@ static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) {
bh_lock_sock(sk);
+ if (l2cap_pi(sk)->conf_state & L2CAP_CONF_CONNECT_PEND) {
+ bh_unlock_sock(sk);
+ continue;
+ }
+
if (!status && (sk->sk_state == BT_CONNECTED ||
sk->sk_state == BT_CONFIG)) {
l2cap_check_encryption(sk, encrypt);