Merge tag 'for-v3.20' of git://git.infradead.org/battery-2.6
[firefly-linux-kernel-4.4.55.git] / net / bluetooth / hci_event.c
index 8ed8516b18c7355de29b287928dea8e3dd6dd64e..a3fb094822b621e5ef3b3205d1d5fce7c9d3f6b8 100644 (file)
@@ -36,6 +36,9 @@
 #include "amp.h"
 #include "smp.h"
 
+#define ZERO_KEY "\x00\x00\x00\x00\x00\x00\x00\x00" \
+                "\x00\x00\x00\x00\x00\x00\x00\x00"
+
 /* Handle HCI Event packets */
 
 static void hci_cc_inquiry_cancel(struct hci_dev *hdev, struct sk_buff *skb)
@@ -197,7 +200,8 @@ static void hci_cc_reset(struct hci_dev *hdev, struct sk_buff *skb)
        /* Reset all non-persistent flags */
        hdev->dev_flags &= ~HCI_PERSISTENT_MASK;
 
-       hdev->discovery.state = DISCOVERY_STOPPED;
+       hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
+
        hdev->inq_tx_power = HCI_TX_POWER_INVALID;
        hdev->adv_tx_power = HCI_TX_POWER_INVALID;
 
@@ -1485,6 +1489,21 @@ unlock:
        hci_dev_unlock(hdev);
 }
 
+static void hci_cc_write_ssp_debug_mode(struct hci_dev *hdev, struct sk_buff *skb)
+{
+       u8 status = *((u8 *) skb->data);
+       u8 *mode;
+
+       BT_DBG("%s status 0x%2.2x", hdev->name, status);
+
+       if (status)
+               return;
+
+       mode = hci_sent_cmd_data(hdev, HCI_OP_WRITE_SSP_DEBUG_MODE);
+       if (mode)
+               hdev->ssp_debug_mode = *mode;
+}
+
 static void hci_cs_inquiry(struct hci_dev *hdev, __u8 status)
 {
        BT_DBG("%s status 0x%2.2x", hdev->name, status);
@@ -2667,7 +2686,8 @@ static void hci_remote_features_evt(struct hci_dev *hdev,
        if (conn->state != BT_CONFIG)
                goto unlock;
 
-       if (!ev->status && lmp_ssp_capable(hdev) && lmp_ssp_capable(conn)) {
+       if (!ev->status && lmp_ext_feat_capable(hdev) &&
+           lmp_ext_feat_capable(conn)) {
                struct hci_cp_read_remote_ext_features cp;
                cp.handle = ev->handle;
                cp.page = 0x01;
@@ -2978,6 +2998,10 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
                hci_cc_read_tx_power(hdev, skb);
                break;
 
+       case HCI_OP_WRITE_SSP_DEBUG_MODE:
+               hci_cc_write_ssp_debug_mode(hdev, skb);
+               break;
+
        default:
                BT_DBG("%s opcode 0x%4.4x", hdev->name, opcode);
                break;
@@ -3096,7 +3120,9 @@ static void hci_hardware_error_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
        struct hci_ev_hardware_error *ev = (void *) skb->data;
 
-       BT_ERR("%s hardware error 0x%2.2x", hdev->name, ev->code);
+       hdev->hw_error_code = ev->code;
+
+       queue_work(hdev->req_workqueue, &hdev->error_reset);
 }
 
 static void hci_role_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
@@ -3864,8 +3890,39 @@ static u8 bredr_oob_data_present(struct hci_conn *conn)
        if (!data)
                return 0x00;
 
-       if (conn->out || test_bit(HCI_CONN_REMOTE_OOB, &conn->flags))
+       if (conn->out || test_bit(HCI_CONN_REMOTE_OOB, &conn->flags)) {
+               if (bredr_sc_enabled(hdev)) {
+                       /* When Secure Connections is enabled, then just
+                        * return the present value stored with the OOB
+                        * data. The stored value contains the right present
+                        * information. However it can only be trusted when
+                        * not in Secure Connection Only mode.
+                        */
+                       if (!test_bit(HCI_SC_ONLY, &hdev->dev_flags))
+                               return data->present;
+
+                       /* When Secure Connections Only mode is enabled, then
+                        * the P-256 values are required. If they are not
+                        * available, then do not declare that OOB data is
+                        * present.
+                        */
+                       if (!memcmp(data->rand256, ZERO_KEY, 16) ||
+                           !memcmp(data->hash256, ZERO_KEY, 16))
+                               return 0x00;
+
+                       return 0x02;
+               }
+
+               /* When Secure Connections is not enabled or actually
+                * not supported by the hardware, then check that if
+                * P-192 data values are present.
+                */
+               if (!memcmp(data->rand192, ZERO_KEY, 16) ||
+                   !memcmp(data->hash192, ZERO_KEY, 16))
+                       return 0x00;
+
                return 0x01;
+       }
 
        return 0x00;
 }