[Bluetooth] Initiate authentication during connection establishment
[pandora-kernel.git] / net / bluetooth / hci_event.c
index e3e360c..64668e2 100644 (file)
@@ -619,6 +619,60 @@ static void hci_cs_add_sco(struct hci_dev *hdev, __u8 status)
        hci_dev_unlock(hdev);
 }
 
        hci_dev_unlock(hdev);
 }
 
+static void hci_cs_auth_requested(struct hci_dev *hdev, __u8 status)
+{
+       struct hci_cp_auth_requested *cp;
+       struct hci_conn *conn;
+
+       BT_DBG("%s status 0x%x", hdev->name, status);
+
+       if (!status)
+               return;
+
+       cp = hci_sent_cmd_data(hdev, HCI_OP_AUTH_REQUESTED);
+       if (!cp)
+               return;
+
+       hci_dev_lock(hdev);
+
+       conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(cp->handle));
+       if (conn) {
+               if (conn->state == BT_CONFIG) {
+                       hci_proto_connect_cfm(conn, status);
+                       hci_conn_put(conn);
+               }
+       }
+
+       hci_dev_unlock(hdev);
+}
+
+static void hci_cs_set_conn_encrypt(struct hci_dev *hdev, __u8 status)
+{
+       struct hci_cp_set_conn_encrypt *cp;
+       struct hci_conn *conn;
+
+       BT_DBG("%s status 0x%x", hdev->name, status);
+
+       if (!status)
+               return;
+
+       cp = hci_sent_cmd_data(hdev, HCI_OP_SET_CONN_ENCRYPT);
+       if (!cp)
+               return;
+
+       hci_dev_lock(hdev);
+
+       conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(cp->handle));
+       if (conn) {
+               if (conn->state == BT_CONFIG) {
+                       hci_proto_connect_cfm(conn, status);
+                       hci_conn_put(conn);
+               }
+       }
+
+       hci_dev_unlock(hdev);
+}
+
 static void hci_cs_remote_name_req(struct hci_dev *hdev, __u8 status)
 {
        BT_DBG("%s status 0x%x", hdev->name, status);
 static void hci_cs_remote_name_req(struct hci_dev *hdev, __u8 status)
 {
        BT_DBG("%s status 0x%x", hdev->name, status);
@@ -643,7 +697,6 @@ static void hci_cs_read_remote_features(struct hci_dev *hdev, __u8 status)
        conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(cp->handle));
        if (conn) {
                if (conn->state == BT_CONFIG) {
        conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(cp->handle));
        if (conn) {
                if (conn->state == BT_CONFIG) {
-                       conn->state = BT_CONNECTED;
                        hci_proto_connect_cfm(conn, status);
                        hci_conn_put(conn);
                }
                        hci_proto_connect_cfm(conn, status);
                        hci_conn_put(conn);
                }
@@ -671,7 +724,6 @@ static void hci_cs_read_remote_ext_features(struct hci_dev *hdev, __u8 status)
        conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(cp->handle));
        if (conn) {
                if (conn->state == BT_CONFIG) {
        conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(cp->handle));
        if (conn) {
                if (conn->state == BT_CONFIG) {
-                       conn->state = BT_CONNECTED;
                        hci_proto_connect_cfm(conn, status);
                        hci_conn_put(conn);
                }
                        hci_proto_connect_cfm(conn, status);
                        hci_conn_put(conn);
                }
@@ -982,15 +1034,29 @@ static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *s
 
                clear_bit(HCI_CONN_AUTH_PEND, &conn->pend);
 
 
                clear_bit(HCI_CONN_AUTH_PEND, &conn->pend);
 
-               hci_auth_cfm(conn, ev->status);
+               if (conn->state == BT_CONFIG) {
+                       if (!ev->status && hdev->ssp_mode > 0 &&
+                                                       conn->ssp_mode > 0) {
+                               struct hci_cp_set_conn_encrypt cp;
+                               cp.handle  = ev->handle;
+                               cp.encrypt = 0x01;
+                               hci_send_cmd(hdev, HCI_OP_SET_CONN_ENCRYPT,
+                                                       sizeof(cp), &cp);
+                       } else {
+                               conn->state = BT_CONNECTED;
+                               hci_proto_connect_cfm(conn, ev->status);
+                               hci_conn_put(conn);
+                       }
+               } else
+                       hci_auth_cfm(conn, ev->status);
 
                if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend)) {
                        if (!ev->status) {
                                struct hci_cp_set_conn_encrypt cp;
 
                if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend)) {
                        if (!ev->status) {
                                struct hci_cp_set_conn_encrypt cp;
-                               cp.handle  = cpu_to_le16(conn->handle);
-                               cp.encrypt = 1;
-                               hci_send_cmd(conn->hdev,
-                                       HCI_OP_SET_CONN_ENCRYPT, sizeof(cp), &cp);
+                               cp.handle  = ev->handle;
+                               cp.encrypt = 0x01;
+                               hci_send_cmd(hdev, HCI_OP_SET_CONN_ENCRYPT,
+                                                       sizeof(cp), &cp);
                        } else {
                                clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend);
                                hci_encrypt_cfm(conn, ev->status, 0x00);
                        } else {
                                clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend);
                                hci_encrypt_cfm(conn, ev->status, 0x00);
@@ -1030,7 +1096,14 @@ static inline void hci_encrypt_change_evt(struct hci_dev *hdev, struct sk_buff *
 
                clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend);
 
 
                clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend);
 
-               hci_encrypt_cfm(conn, ev->status, ev->encrypt);
+               if (conn->state == BT_CONFIG) {
+                       if (!ev->status)
+                               conn->state = BT_CONNECTED;
+
+                       hci_proto_connect_cfm(conn, ev->status);
+                       hci_conn_put(conn);
+               } else
+                       hci_encrypt_cfm(conn, ev->status, ev->encrypt);
        }
 
        hci_dev_unlock(hdev);
        }
 
        hci_dev_unlock(hdev);
@@ -1250,6 +1323,14 @@ static inline void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb)
                hci_cs_add_sco(hdev, ev->status);
                break;
 
                hci_cs_add_sco(hdev, ev->status);
                break;
 
+       case HCI_OP_AUTH_REQUESTED:
+               hci_cs_auth_requested(hdev, ev->status);
+               break;
+
+       case HCI_OP_SET_CONN_ENCRYPT:
+               hci_cs_set_conn_encrypt(hdev, ev->status);
+               break;
+
        case HCI_OP_REMOTE_NAME_REQ:
                hci_cs_remote_name_req(hdev, ev->status);
                break;
        case HCI_OP_REMOTE_NAME_REQ:
                hci_cs_remote_name_req(hdev, ev->status);
                break;
@@ -1518,9 +1599,20 @@ static inline void hci_remote_ext_features_evt(struct hci_dev *hdev, struct sk_b
                }
 
                if (conn->state == BT_CONFIG) {
                }
 
                if (conn->state == BT_CONFIG) {
-                       conn->state = BT_CONNECTED;
-                       hci_proto_connect_cfm(conn, ev->status);
-                       hci_conn_put(conn);
+                       if (!ev->status && hdev->ssp_mode > 0 &&
+                                                       conn->ssp_mode > 0) {
+                               if (conn->out) {
+                                       struct hci_cp_auth_requested cp;
+                                       cp.handle = ev->handle;
+                                       hci_send_cmd(hdev,
+                                               HCI_OP_AUTH_REQUESTED,
+                                                       sizeof(cp), &cp);
+                               }
+                       } else {
+                               conn->state = BT_CONNECTED;
+                               hci_proto_connect_cfm(conn, ev->status);
+                               hci_conn_put(conn);
+                       }
                }
        }
 
                }
        }