Bluetooth: Fix double L2CAP connection request
[pandora-kernel.git] / net / bluetooth / l2cap.c
index 8a93dde..01f7501 100644 (file)
@@ -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;
@@ -1938,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:
@@ -2176,10 +2187,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;
 }
@@ -2467,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);