Bluetooth: Refactor code for outgoing dedicated bonding
[pandora-kernel.git] / net / bluetooth / hci_event.c
index 5f81245..2c09732 100644 (file)
@@ -199,6 +199,8 @@ static void hci_cc_reset(struct hci_dev *hdev, struct sk_buff *skb)
        memset(hdev->scan_rsp_data, 0, sizeof(hdev->scan_rsp_data));
        hdev->scan_rsp_data_len = 0;
 
+       hdev->le_scan_type = LE_SCAN_PASSIVE;
+
        hdev->ssp_debug_mode = 0;
 }
 
@@ -461,6 +463,34 @@ static void hci_cc_write_ssp_mode(struct hci_dev *hdev, struct sk_buff *skb)
        }
 }
 
+static void hci_cc_write_sc_support(struct hci_dev *hdev, struct sk_buff *skb)
+{
+       u8 status = *((u8 *) skb->data);
+       struct hci_cp_write_sc_support *sent;
+
+       BT_DBG("%s status 0x%2.2x", hdev->name, status);
+
+       sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_SC_SUPPORT);
+       if (!sent)
+               return;
+
+       if (!status) {
+               if (sent->support)
+                       hdev->features[1][0] |= LMP_HOST_SC;
+               else
+                       hdev->features[1][0] &= ~LMP_HOST_SC;
+       }
+
+       if (test_bit(HCI_MGMT, &hdev->dev_flags))
+               mgmt_sc_enable_complete(hdev, sent->support, status);
+       else if (!status) {
+               if (sent->support)
+                       set_bit(HCI_SC_ENABLED, &hdev->dev_flags);
+               else
+                       clear_bit(HCI_SC_ENABLED, &hdev->dev_flags);
+       }
+}
+
 static void hci_cc_read_local_version(struct hci_dev *hdev, struct sk_buff *skb)
 {
        struct hci_rp_read_local_version *rp = (void *) skb->data;
@@ -904,16 +934,50 @@ static void hci_cc_user_passkey_neg_reply(struct hci_dev *hdev,
        hci_dev_unlock(hdev);
 }
 
-static void hci_cc_read_local_oob_data_reply(struct hci_dev *hdev,
-                                            struct sk_buff *skb)
+static void hci_cc_read_local_oob_data(struct hci_dev *hdev,
+                                      struct sk_buff *skb)
 {
        struct hci_rp_read_local_oob_data *rp = (void *) skb->data;
 
        BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
 
        hci_dev_lock(hdev);
-       mgmt_read_local_oob_data_reply_complete(hdev, rp->hash,
-                                               rp->randomizer, rp->status);
+       mgmt_read_local_oob_data_complete(hdev, rp->hash, rp->randomizer,
+                                         NULL, NULL, rp->status);
+       hci_dev_unlock(hdev);
+}
+
+static void hci_cc_read_local_oob_ext_data(struct hci_dev *hdev,
+                                          struct sk_buff *skb)
+{
+       struct hci_rp_read_local_oob_ext_data *rp = (void *) skb->data;
+
+       BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
+
+       hci_dev_lock(hdev);
+       mgmt_read_local_oob_data_complete(hdev, rp->hash192, rp->randomizer192,
+                                         rp->hash256, rp->randomizer256,
+                                         rp->status);
+       hci_dev_unlock(hdev);
+}
+
+
+static void hci_cc_le_set_random_addr(struct hci_dev *hdev, struct sk_buff *skb)
+{
+       __u8 status = *((__u8 *) skb->data);
+       bdaddr_t *sent;
+
+       BT_DBG("%s status 0x%2.2x", hdev->name, status);
+
+       sent = hci_sent_cmd_data(hdev, HCI_OP_LE_SET_RANDOM_ADDR);
+       if (!sent)
+               return;
+
+       hci_dev_lock(hdev);
+
+       if (!status)
+               bacpy(&hdev->random_addr, sent);
+
        hci_dev_unlock(hdev);
 }
 
@@ -927,18 +991,75 @@ static void hci_cc_le_set_adv_enable(struct hci_dev *hdev, struct sk_buff *skb)
        if (!sent)
                return;
 
+       if (status)
+               return;
+
        hci_dev_lock(hdev);
 
-       if (!status) {
-               if (*sent)
-                       set_bit(HCI_ADVERTISING, &hdev->dev_flags);
-               else
-                       clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
+       /* If we're doing connection initation as peripheral. Set a
+        * timeout in case something goes wrong.
+        */
+       if (*sent) {
+               struct hci_conn *conn;
+
+               conn = hci_conn_hash_lookup_state(hdev, LE_LINK, BT_CONNECT);
+               if (conn)
+                       queue_delayed_work(hdev->workqueue,
+                                          &conn->le_conn_timeout,
+                                          HCI_LE_CONN_TIMEOUT);
        }
 
+       mgmt_advertising(hdev, *sent);
+
        hci_dev_unlock(hdev);
 }
 
+static void hci_cc_le_set_scan_param(struct hci_dev *hdev, struct sk_buff *skb)
+{
+       struct hci_cp_le_set_scan_param *cp;
+       __u8 status = *((__u8 *) skb->data);
+
+       BT_DBG("%s status 0x%2.2x", hdev->name, status);
+
+       cp = hci_sent_cmd_data(hdev, HCI_OP_LE_SET_SCAN_PARAM);
+       if (!cp)
+               return;
+
+       hci_dev_lock(hdev);
+
+       if (!status)
+               hdev->le_scan_type = cp->type;
+
+       hci_dev_unlock(hdev);
+}
+
+static bool has_pending_adv_report(struct hci_dev *hdev)
+{
+       struct discovery_state *d = &hdev->discovery;
+
+       return bacmp(&d->last_adv_addr, BDADDR_ANY);
+}
+
+static void clear_pending_adv_report(struct hci_dev *hdev)
+{
+       struct discovery_state *d = &hdev->discovery;
+
+       bacpy(&d->last_adv_addr, BDADDR_ANY);
+       d->last_adv_data_len = 0;
+}
+
+static void store_pending_adv_report(struct hci_dev *hdev, bdaddr_t *bdaddr,
+                                    u8 bdaddr_type, s8 rssi, u8 *data, u8 len)
+{
+       struct discovery_state *d = &hdev->discovery;
+
+       bacpy(&d->last_adv_addr, bdaddr);
+       d->last_adv_addr_type = bdaddr_type;
+       d->last_adv_rssi = rssi;
+       memcpy(d->last_adv_data, data, len);
+       d->last_adv_data_len = len;
+}
+
 static void hci_cc_le_set_scan_enable(struct hci_dev *hdev,
                                      struct sk_buff *skb)
 {
@@ -957,10 +1078,38 @@ static void hci_cc_le_set_scan_enable(struct hci_dev *hdev,
        switch (cp->enable) {
        case LE_SCAN_ENABLE:
                set_bit(HCI_LE_SCAN, &hdev->dev_flags);
+               if (hdev->le_scan_type == LE_SCAN_ACTIVE)
+                       clear_pending_adv_report(hdev);
                break;
 
        case LE_SCAN_DISABLE:
+               /* We do this here instead of when setting DISCOVERY_STOPPED
+                * since the latter would potentially require waiting for
+                * inquiry to stop too.
+                */
+               if (has_pending_adv_report(hdev)) {
+                       struct discovery_state *d = &hdev->discovery;
+
+                       mgmt_device_found(hdev, &d->last_adv_addr, LE_LINK,
+                                         d->last_adv_addr_type, NULL,
+                                         d->last_adv_rssi, 0, 1,
+                                         d->last_adv_data,
+                                         d->last_adv_data_len, NULL, 0);
+               }
+
+               /* Cancel this timer so that we don't try to disable scanning
+                * when it's already disabled.
+                */
+               cancel_delayed_work(&hdev->le_scan_disable);
+
                clear_bit(HCI_LE_SCAN, &hdev->dev_flags);
+               /* The HCI_LE_SCAN_INTERRUPTED flag indicates that we
+                * interrupted scanning due to a connect request. Mark
+                * therefore discovery as stopped.
+                */
+               if (test_and_clear_bit(HCI_LE_SCAN_INTERRUPTED,
+                                      &hdev->dev_flags))
+                       hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
                break;
 
        default:
@@ -980,6 +1129,49 @@ static void hci_cc_le_read_white_list_size(struct hci_dev *hdev,
                hdev->le_white_list_size = rp->size;
 }
 
+static void hci_cc_le_clear_white_list(struct hci_dev *hdev,
+                                      struct sk_buff *skb)
+{
+       __u8 status = *((__u8 *) skb->data);
+
+       BT_DBG("%s status 0x%2.2x", hdev->name, status);
+
+       if (!status)
+               hci_white_list_clear(hdev);
+}
+
+static void hci_cc_le_add_to_white_list(struct hci_dev *hdev,
+                                       struct sk_buff *skb)
+{
+       struct hci_cp_le_add_to_white_list *sent;
+       __u8 status = *((__u8 *) skb->data);
+
+       BT_DBG("%s status 0x%2.2x", hdev->name, status);
+
+       sent = hci_sent_cmd_data(hdev, HCI_OP_LE_ADD_TO_WHITE_LIST);
+       if (!sent)
+               return;
+
+       if (!status)
+               hci_white_list_add(hdev, &sent->bdaddr, sent->bdaddr_type);
+}
+
+static void hci_cc_le_del_from_white_list(struct hci_dev *hdev,
+                                         struct sk_buff *skb)
+{
+       struct hci_cp_le_del_from_white_list *sent;
+       __u8 status = *((__u8 *) skb->data);
+
+       BT_DBG("%s status 0x%2.2x", hdev->name, status);
+
+       sent = hci_sent_cmd_data(hdev, HCI_OP_LE_DEL_FROM_WHITE_LIST);
+       if (!sent)
+               return;
+
+       if (!status)
+               hci_white_list_del(hdev, &sent->bdaddr, sent->bdaddr_type);
+}
+
 static void hci_cc_le_read_supported_states(struct hci_dev *hdev,
                                            struct sk_buff *skb)
 {
@@ -1020,6 +1212,25 @@ static void hci_cc_write_le_host_supported(struct hci_dev *hdev,
        }
 }
 
+static void hci_cc_set_adv_param(struct hci_dev *hdev, struct sk_buff *skb)
+{
+       struct hci_cp_le_set_adv_param *cp;
+       u8 status = *((u8 *) skb->data);
+
+       BT_DBG("%s status 0x%2.2x", hdev->name, status);
+
+       if (status)
+               return;
+
+       cp = hci_sent_cmd_data(hdev, HCI_OP_LE_SET_ADV_PARAM);
+       if (!cp)
+               return;
+
+       hci_dev_lock(hdev);
+       hdev->adv_addr_type = cp->own_address_type;
+       hci_dev_unlock(hdev);
+}
+
 static void hci_cc_write_remote_amp_assoc(struct hci_dev *hdev,
                                          struct sk_buff *skb)
 {
@@ -1185,9 +1396,12 @@ static int hci_outgoing_auth_needed(struct hci_dev *hdev,
                return 0;
 
        /* Only request authentication for SSP connections or non-SSP
-        * devices with sec_level HIGH or if MITM protection is requested */
+        * devices with sec_level MEDIUM or HIGH or if MITM protection
+        * is requested.
+        */
        if (!hci_conn_ssp_enabled(conn) && !(conn->auth_type & 0x01) &&
-           conn->pending_sec_level != BT_SECURITY_HIGH)
+           conn->pending_sec_level != BT_SECURITY_HIGH &&
+           conn->pending_sec_level != BT_SECURITY_MEDIUM)
                return 0;
 
        return 1;
@@ -1518,6 +1732,87 @@ static void hci_cs_accept_phylink(struct hci_dev *hdev, u8 status)
        amp_write_remote_assoc(hdev, cp->phy_handle);
 }
 
+static void hci_cs_le_create_conn(struct hci_dev *hdev, u8 status)
+{
+       struct hci_cp_le_create_conn *cp;
+       struct hci_conn *conn;
+
+       BT_DBG("%s status 0x%2.2x", hdev->name, status);
+
+       /* All connection failure handling is taken care of by the
+        * hci_le_conn_failed function which is triggered by the HCI
+        * request completion callbacks used for connecting.
+        */
+       if (status)
+               return;
+
+       cp = hci_sent_cmd_data(hdev, HCI_OP_LE_CREATE_CONN);
+       if (!cp)
+               return;
+
+       hci_dev_lock(hdev);
+
+       conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->peer_addr);
+       if (!conn)
+               goto unlock;
+
+       /* Store the initiator and responder address information which
+        * is needed for SMP. These values will not change during the
+        * lifetime of the connection.
+        */
+       conn->init_addr_type = cp->own_address_type;
+       if (cp->own_address_type == ADDR_LE_DEV_RANDOM)
+               bacpy(&conn->init_addr, &hdev->random_addr);
+       else
+               bacpy(&conn->init_addr, &hdev->bdaddr);
+
+       conn->resp_addr_type = cp->peer_addr_type;
+       bacpy(&conn->resp_addr, &cp->peer_addr);
+
+       /* We don't want the connection attempt to stick around
+        * indefinitely since LE doesn't have a page timeout concept
+        * like BR/EDR. Set a timer for any connection that doesn't use
+        * the white list for connecting.
+        */
+       if (cp->filter_policy == HCI_LE_USE_PEER_ADDR)
+               queue_delayed_work(conn->hdev->workqueue,
+                                  &conn->le_conn_timeout,
+                                  HCI_LE_CONN_TIMEOUT);
+
+unlock:
+       hci_dev_unlock(hdev);
+}
+
+static void hci_cs_le_start_enc(struct hci_dev *hdev, u8 status)
+{
+       struct hci_cp_le_start_enc *cp;
+       struct hci_conn *conn;
+
+       BT_DBG("%s status 0x%2.2x", hdev->name, status);
+
+       if (!status)
+               return;
+
+       hci_dev_lock(hdev);
+
+       cp = hci_sent_cmd_data(hdev, HCI_OP_LE_START_ENC);
+       if (!cp)
+               goto unlock;
+
+       conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(cp->handle));
+       if (!conn)
+               goto unlock;
+
+       if (conn->state != BT_CONNECTED)
+               goto unlock;
+
+       hci_disconnect(conn, HCI_ERROR_AUTH_FAILURE);
+       hci_conn_drop(conn);
+
+unlock:
+       hci_dev_unlock(hdev);
+}
+
 static void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
        __u8 status = *((__u8 *) skb->data);
@@ -1590,7 +1885,7 @@ static void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *skb)
                name_known = hci_inquiry_cache_update(hdev, &data, false, &ssp);
                mgmt_device_found(hdev, &info->bdaddr, ACL_LINK, 0x00,
                                  info->dev_class, 0, !name_known, ssp, NULL,
-                                 0);
+                                 0, NULL, 0);
        }
 
        hci_dev_unlock(hdev);
@@ -1659,7 +1954,7 @@ static void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
        } else {
                conn->state = BT_CLOSED;
                if (conn->type == ACL_LINK)
-                       mgmt_connect_failed(hdev, &ev->bdaddr, conn->type,
+                       mgmt_connect_failed(hdev, &conn->dst, conn->type,
                                            conn->dst_type, ev->status);
        }
 
@@ -1738,9 +2033,9 @@ static void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
                        bacpy(&cp.bdaddr, &ev->bdaddr);
                        cp.pkt_type = cpu_to_le16(conn->pkt_type);
 
-                       cp.tx_bandwidth   = __constant_cpu_to_le32(0x00001f40);
-                       cp.rx_bandwidth   = __constant_cpu_to_le32(0x00001f40);
-                       cp.max_latency    = __constant_cpu_to_le16(0xffff);
+                       cp.tx_bandwidth   = cpu_to_le32(0x00001f40);
+                       cp.rx_bandwidth   = cpu_to_le32(0x00001f40);
+                       cp.max_latency    = cpu_to_le16(0xffff);
                        cp.content_format = cpu_to_le16(hdev->voice_setting);
                        cp.retrans_effort = 0xff;
 
@@ -1780,7 +2075,9 @@ static void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
        struct hci_ev_disconn_complete *ev = (void *) skb->data;
        u8 reason = hci_to_mgmt_reason(ev->reason);
+       struct hci_conn_params *params;
        struct hci_conn *conn;
+       bool mgmt_connected;
        u8 type;
 
        BT_DBG("%s status 0x%2.2x", hdev->name, ev->status);
@@ -1799,13 +2096,30 @@ static void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
 
        conn->state = BT_CLOSED;
 
-       if (test_and_clear_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags))
-               mgmt_device_disconnected(hdev, &conn->dst, conn->type,
-                                        conn->dst_type, reason);
+       mgmt_connected = test_and_clear_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags);
+       mgmt_device_disconnected(hdev, &conn->dst, conn->type, conn->dst_type,
+                               reason, mgmt_connected);
 
        if (conn->type == ACL_LINK && conn->flush_key)
                hci_remove_link_key(hdev, &conn->dst);
 
+       params = hci_conn_params_lookup(hdev, &conn->dst, conn->dst_type);
+       if (params) {
+               switch (params->auto_connect) {
+               case HCI_AUTO_CONN_LINK_LOSS:
+                       if (ev->reason != HCI_ERROR_CONNECTION_TIMEOUT)
+                               break;
+                       /* Fall through */
+
+               case HCI_AUTO_CONN_ALWAYS:
+                       hci_pend_le_conn_add(hdev, &conn->dst, conn->dst_type);
+                       break;
+
+               default:
+                       break;
+               }
+       }
+
        type = conn->type;
 
        hci_proto_disconn_cfm(conn, ev->reason);
@@ -1943,34 +2257,57 @@ static void hci_encrypt_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
        hci_dev_lock(hdev);
 
        conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle));
-       if (conn) {
-               if (!ev->status) {
-                       if (ev->encrypt) {
-                               /* Encryption implies authentication */
-                               conn->link_mode |= HCI_LM_AUTH;
-                               conn->link_mode |= HCI_LM_ENCRYPT;
-                               conn->sec_level = conn->pending_sec_level;
-                       } else
-                               conn->link_mode &= ~HCI_LM_ENCRYPT;
+       if (!conn)
+               goto unlock;
+
+       if (!ev->status) {
+               if (ev->encrypt) {
+                       /* Encryption implies authentication */
+                       conn->link_mode |= HCI_LM_AUTH;
+                       conn->link_mode |= HCI_LM_ENCRYPT;
+                       conn->sec_level = conn->pending_sec_level;
+
+                       /* P-256 authentication key implies FIPS */
+                       if (conn->key_type == HCI_LK_AUTH_COMBINATION_P256)
+                               conn->link_mode |= HCI_LM_FIPS;
+
+                       if ((conn->type == ACL_LINK && ev->encrypt == 0x02) ||
+                           conn->type == LE_LINK)
+                               set_bit(HCI_CONN_AES_CCM, &conn->flags);
+               } else {
+                       conn->link_mode &= ~HCI_LM_ENCRYPT;
+                       clear_bit(HCI_CONN_AES_CCM, &conn->flags);
                }
+       }
+
+       clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags);
 
-               clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags);
+       if (ev->status && conn->state == BT_CONNECTED) {
+               hci_disconnect(conn, HCI_ERROR_AUTH_FAILURE);
+               hci_conn_drop(conn);
+               goto unlock;
+       }
 
-               if (ev->status && conn->state == BT_CONNECTED) {
-                       hci_disconnect(conn, HCI_ERROR_AUTH_FAILURE);
+       if (conn->state == BT_CONFIG) {
+               if (!ev->status)
+                       conn->state = BT_CONNECTED;
+
+               /* In Secure Connections Only mode, do not allow any
+                * connections that are not encrypted with AES-CCM
+                * using a P-256 authenticated combination key.
+                */
+               if (test_bit(HCI_SC_ONLY, &hdev->dev_flags) &&
+                   (!test_bit(HCI_CONN_AES_CCM, &conn->flags) ||
+                    conn->key_type != HCI_LK_AUTH_COMBINATION_P256)) {
+                       hci_proto_connect_cfm(conn, HCI_ERROR_AUTH_FAILURE);
                        hci_conn_drop(conn);
                        goto unlock;
                }
 
-               if (conn->state == BT_CONFIG) {
-                       if (!ev->status)
-                               conn->state = BT_CONNECTED;
-
-                       hci_proto_connect_cfm(conn, ev->status);
-                       hci_conn_drop(conn);
-               } else
-                       hci_encrypt_cfm(conn, ev->status, ev->encrypt);
-       }
+               hci_proto_connect_cfm(conn, ev->status);
+               hci_conn_drop(conn);
+       } else
+               hci_encrypt_cfm(conn, ev->status, ev->encrypt);
 
 unlock:
        hci_dev_unlock(hdev);
@@ -2144,6 +2481,10 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
                hci_cc_write_ssp_mode(hdev, skb);
                break;
 
+       case HCI_OP_WRITE_SC_SUPPORT:
+               hci_cc_write_sc_support(hdev, skb);
+               break;
+
        case HCI_OP_READ_LOCAL_VERSION:
                hci_cc_read_local_version(hdev, skb);
                break;
@@ -2213,7 +2554,11 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
                break;
 
        case HCI_OP_READ_LOCAL_OOB_DATA:
-               hci_cc_read_local_oob_data_reply(hdev, skb);
+               hci_cc_read_local_oob_data(hdev, skb);
+               break;
+
+       case HCI_OP_READ_LOCAL_OOB_EXT_DATA:
+               hci_cc_read_local_oob_ext_data(hdev, skb);
                break;
 
        case HCI_OP_LE_READ_BUFFER_SIZE:
@@ -2244,10 +2589,18 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
                hci_cc_user_passkey_neg_reply(hdev, skb);
                break;
 
+       case HCI_OP_LE_SET_RANDOM_ADDR:
+               hci_cc_le_set_random_addr(hdev, skb);
+               break;
+
        case HCI_OP_LE_SET_ADV_ENABLE:
                hci_cc_le_set_adv_enable(hdev, skb);
                break;
 
+       case HCI_OP_LE_SET_SCAN_PARAM:
+               hci_cc_le_set_scan_param(hdev, skb);
+               break;
+
        case HCI_OP_LE_SET_SCAN_ENABLE:
                hci_cc_le_set_scan_enable(hdev, skb);
                break;
@@ -2256,6 +2609,18 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
                hci_cc_le_read_white_list_size(hdev, skb);
                break;
 
+       case HCI_OP_LE_CLEAR_WHITE_LIST:
+               hci_cc_le_clear_white_list(hdev, skb);
+               break;
+
+       case HCI_OP_LE_ADD_TO_WHITE_LIST:
+               hci_cc_le_add_to_white_list(hdev, skb);
+               break;
+
+       case HCI_OP_LE_DEL_FROM_WHITE_LIST:
+               hci_cc_le_del_from_white_list(hdev, skb);
+               break;
+
        case HCI_OP_LE_READ_SUPPORTED_STATES:
                hci_cc_le_read_supported_states(hdev, skb);
                break;
@@ -2264,6 +2629,10 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
                hci_cc_write_le_host_supported(hdev, skb);
                break;
 
+       case HCI_OP_LE_SET_ADV_PARAM:
+               hci_cc_set_adv_param(hdev, skb);
+               break;
+
        case HCI_OP_WRITE_REMOTE_AMP_ASSOC:
                hci_cc_write_remote_amp_assoc(hdev, skb);
                break;
@@ -2351,6 +2720,14 @@ static void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb)
                hci_cs_accept_phylink(hdev, ev->status);
                break;
 
+       case HCI_OP_LE_CREATE_CONN:
+               hci_cs_le_create_conn(hdev, ev->status);
+               break;
+
+       case HCI_OP_LE_START_ENC:
+               hci_cs_le_start_enc(hdev, ev->status);
+               break;
+
        default:
                BT_DBG("%s opcode 0x%4.4x", hdev->name, opcode);
                break;
@@ -2630,7 +3007,8 @@ static void hci_link_key_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
 
        conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
        if (conn) {
-               if (key->type == HCI_LK_UNAUTH_COMBINATION &&
+               if ((key->type == HCI_LK_UNAUTH_COMBINATION_P192 ||
+                    key->type == HCI_LK_UNAUTH_COMBINATION_P256) &&
                    conn->auth_type != 0xff && (conn->auth_type & 0x01)) {
                        BT_DBG("%s ignoring unauthenticated key", hdev->name);
                        goto not_found;
@@ -2782,7 +3160,7 @@ static void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev,
                                                              false, &ssp);
                        mgmt_device_found(hdev, &info->bdaddr, ACL_LINK, 0x00,
                                          info->dev_class, info->rssi,
-                                         !name_known, ssp, NULL, 0);
+                                         !name_known, ssp, NULL, 0, NULL, 0);
                }
        } else {
                struct inquiry_info_with_rssi *info = (void *) (skb->data + 1);
@@ -2800,7 +3178,7 @@ static void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev,
                                                              false, &ssp);
                        mgmt_device_found(hdev, &info->bdaddr, ACL_LINK, 0x00,
                                          info->dev_class, info->rssi,
-                                         !name_known, ssp, NULL, 0);
+                                         !name_known, ssp, NULL, 0, NULL, 0);
                }
        }
 
@@ -2844,6 +3222,9 @@ static void hci_remote_ext_features_evt(struct hci_dev *hdev,
                         * features do not indicate SSP support */
                        clear_bit(HCI_CONN_SSP_ENABLED, &conn->flags);
                }
+
+               if (ev->features[0] & LMP_HOST_SC)
+                       set_bit(HCI_CONN_SC_ENABLED, &conn->flags);
        }
 
        if (conn->state != BT_CONFIG)
@@ -2905,6 +3286,7 @@ static void hci_sync_conn_complete_evt(struct hci_dev *hdev,
        case 0x1c:      /* SCO interval rejected */
        case 0x1a:      /* Unsupported Remote Feature */
        case 0x1f:      /* Unspecified error */
+       case 0x20:      /* Unsupported LMP Parameter value */
                if (conn->out) {
                        conn->pkt_type = (hdev->esco_type & SCO_ESCO_MASK) |
                                        (hdev->esco_type & EDR_ESCO_MASK);
@@ -2985,7 +3367,7 @@ static void hci_extended_inquiry_result_evt(struct hci_dev *hdev,
                eir_len = eir_get_length(info->data, sizeof(info->data));
                mgmt_device_found(hdev, &info->bdaddr, ACL_LINK, 0x00,
                                  info->dev_class, info->rssi, !name_known,
-                                 ssp, info->data, eir_len);
+                                 ssp, info->data, eir_len, NULL, 0);
        }
 
        hci_dev_unlock(hdev);
@@ -3037,24 +3419,25 @@ unlock:
 
 static u8 hci_get_auth_req(struct hci_conn *conn)
 {
-       /* If remote requests dedicated bonding follow that lead */
-       if (conn->remote_auth == HCI_AT_DEDICATED_BONDING ||
-           conn->remote_auth == HCI_AT_DEDICATED_BONDING_MITM) {
-               /* If both remote and local IO capabilities allow MITM
-                * protection then require it, otherwise don't */
-               if (conn->remote_cap == HCI_IO_NO_INPUT_OUTPUT ||
-                   conn->io_capability == HCI_IO_NO_INPUT_OUTPUT)
-                       return HCI_AT_DEDICATED_BONDING;
-               else
-                       return HCI_AT_DEDICATED_BONDING_MITM;
-       }
-
        /* If remote requests no-bonding follow that lead */
        if (conn->remote_auth == HCI_AT_NO_BONDING ||
            conn->remote_auth == HCI_AT_NO_BONDING_MITM)
                return conn->remote_auth | (conn->auth_type & 0x01);
 
-       return conn->auth_type;
+       /* For general bonding, use the given auth_type */
+       if (conn->remote_auth == HCI_AT_GENERAL_BONDING ||
+           conn->remote_auth == HCI_AT_GENERAL_BONDING_MITM)
+               return conn->auth_type;
+
+       /* If both remote and local have enough IO capabilities, require
+        * MITM protection
+        */
+       if (conn->remote_cap != HCI_IO_NO_INPUT_OUTPUT &&
+           conn->io_capability != HCI_IO_NO_INPUT_OUTPUT)
+               return conn->remote_auth | 0x01;
+
+       /* No MITM protection possible so remove requirement */
+       return conn->remote_auth & ~0x01;
 }
 
 static void hci_io_capa_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
@@ -3084,8 +3467,19 @@ static void hci_io_capa_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
                 * to DisplayYesNo as it is not supported by BT spec. */
                cp.capability = (conn->io_capability == 0x04) ?
                                HCI_IO_DISPLAY_YESNO : conn->io_capability;
-               conn->auth_type = hci_get_auth_req(conn);
-               cp.authentication = conn->auth_type;
+
+               /* If we are initiators, there is no remote information yet */
+               if (conn->remote_auth == 0xff) {
+                       cp.authentication = conn->auth_type;
+
+                       /* Use MITM protection for outgoing dedicated bonding */
+                       if (conn->io_capability != HCI_IO_NO_INPUT_OUTPUT &&
+                           cp.authentication == HCI_AT_DEDICATED_BONDING)
+                               cp.authentication |= 0x01;
+               } else {
+                       conn->auth_type = hci_get_auth_req(conn);
+                       cp.authentication = conn->auth_type;
+               }
 
                if (hci_find_remote_oob_data(hdev, &conn->dst) &&
                    (conn->out || test_bit(HCI_CONN_REMOTE_OOB, &conn->flags)))
@@ -3153,12 +3547,9 @@ static void hci_user_confirm_request_evt(struct hci_dev *hdev,
        rem_mitm = (conn->remote_auth & 0x01);
 
        /* If we require MITM but the remote device can't provide that
-        * (it has NoInputNoOutput) then reject the confirmation
-        * request. The only exception is when we're dedicated bonding
-        * initiators (connect_cfm_cb set) since then we always have the MITM
-        * bit set. */
-       if (!conn->connect_cfm_cb && loc_mitm &&
-           conn->remote_cap == HCI_IO_NO_INPUT_OUTPUT) {
+        * (it has NoInputNoOutput) then reject the confirmation request
+        */
+       if (loc_mitm && conn->remote_cap == HCI_IO_NO_INPUT_OUTPUT) {
                BT_DBG("Rejecting request: remote device can't provide MITM");
                hci_send_cmd(hdev, HCI_OP_USER_CONFIRM_NEG_REPLY,
                             sizeof(ev->bdaddr), &ev->bdaddr);
@@ -3194,8 +3585,8 @@ static void hci_user_confirm_request_evt(struct hci_dev *hdev,
        }
 
 confirm:
-       mgmt_user_confirm_request(hdev, &ev->bdaddr, ACL_LINK, 0, ev->passkey,
-                                 confirm_hint);
+       mgmt_user_confirm_request(hdev, &ev->bdaddr, ACL_LINK, 0,
+                                 le32_to_cpu(ev->passkey), confirm_hint);
 
 unlock:
        hci_dev_unlock(hdev);
@@ -3337,20 +3728,36 @@ static void hci_remote_oob_data_request_evt(struct hci_dev *hdev,
 
        data = hci_find_remote_oob_data(hdev, &ev->bdaddr);
        if (data) {
-               struct hci_cp_remote_oob_data_reply cp;
+               if (test_bit(HCI_SC_ENABLED, &hdev->dev_flags)) {
+                       struct hci_cp_remote_oob_ext_data_reply cp;
 
-               bacpy(&cp.bdaddr, &ev->bdaddr);
-               memcpy(cp.hash, data->hash, sizeof(cp.hash));
-               memcpy(cp.randomizer, data->randomizer, sizeof(cp.randomizer));
+                       bacpy(&cp.bdaddr, &ev->bdaddr);
+                       memcpy(cp.hash192, data->hash192, sizeof(cp.hash192));
+                       memcpy(cp.randomizer192, data->randomizer192,
+                              sizeof(cp.randomizer192));
+                       memcpy(cp.hash256, data->hash256, sizeof(cp.hash256));
+                       memcpy(cp.randomizer256, data->randomizer256,
+                              sizeof(cp.randomizer256));
+
+                       hci_send_cmd(hdev, HCI_OP_REMOTE_OOB_EXT_DATA_REPLY,
+                                    sizeof(cp), &cp);
+               } else {
+                       struct hci_cp_remote_oob_data_reply cp;
 
-               hci_send_cmd(hdev, HCI_OP_REMOTE_OOB_DATA_REPLY, sizeof(cp),
-                            &cp);
+                       bacpy(&cp.bdaddr, &ev->bdaddr);
+                       memcpy(cp.hash, data->hash192, sizeof(cp.hash));
+                       memcpy(cp.randomizer, data->randomizer192,
+                              sizeof(cp.randomizer));
+
+                       hci_send_cmd(hdev, HCI_OP_REMOTE_OOB_DATA_REPLY,
+                                    sizeof(cp), &cp);
+               }
        } else {
                struct hci_cp_remote_oob_data_neg_reply cp;
 
                bacpy(&cp.bdaddr, &ev->bdaddr);
-               hci_send_cmd(hdev, HCI_OP_REMOTE_OOB_DATA_NEG_REPLY, sizeof(cp),
-                            &cp);
+               hci_send_cmd(hdev, HCI_OP_REMOTE_OOB_DATA_NEG_REPLY,
+                            sizeof(cp), &cp);
        }
 
 unlock:
@@ -3484,6 +3891,7 @@ static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
        struct hci_ev_le_conn_complete *ev = (void *) skb->data;
        struct hci_conn *conn;
+       struct smp_irk *irk;
 
        BT_DBG("%s status 0x%2.2x", hdev->name, ev->status);
 
@@ -3499,34 +3907,71 @@ static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
 
                conn->dst_type = ev->bdaddr_type;
 
-               /* The advertising parameters for own address type
-                * define which source address and source address
-                * type this connections has.
-                */
-               if (bacmp(&conn->src, BDADDR_ANY)) {
-                       conn->src_type = ADDR_LE_DEV_PUBLIC;
-               } else {
-                       bacpy(&conn->src, &hdev->static_addr);
-                       conn->src_type = ADDR_LE_DEV_RANDOM;
-               }
-
                if (ev->role == LE_CONN_ROLE_MASTER) {
                        conn->out = true;
                        conn->link_mode |= HCI_LM_MASTER;
                }
+
+               /* If we didn't have a hci_conn object previously
+                * but we're in master role this must be something
+                * initiated using a white list. Since white list based
+                * connections are not "first class citizens" we don't
+                * have full tracking of them. Therefore, we go ahead
+                * with a "best effort" approach of determining the
+                * initiator address based on the HCI_PRIVACY flag.
+                */
+               if (conn->out) {
+                       conn->resp_addr_type = ev->bdaddr_type;
+                       bacpy(&conn->resp_addr, &ev->bdaddr);
+                       if (test_bit(HCI_PRIVACY, &hdev->dev_flags)) {
+                               conn->init_addr_type = ADDR_LE_DEV_RANDOM;
+                               bacpy(&conn->init_addr, &hdev->rpa);
+                       } else {
+                               hci_copy_identity_address(hdev,
+                                                         &conn->init_addr,
+                                                         &conn->init_addr_type);
+                       }
+               }
+       } else {
+               cancel_delayed_work(&conn->le_conn_timeout);
+       }
+
+       if (!conn->out) {
+               /* Set the responder (our side) address type based on
+                * the advertising address type.
+                */
+               conn->resp_addr_type = hdev->adv_addr_type;
+               if (hdev->adv_addr_type == ADDR_LE_DEV_RANDOM)
+                       bacpy(&conn->resp_addr, &hdev->random_addr);
+               else
+                       bacpy(&conn->resp_addr, &hdev->bdaddr);
+
+               conn->init_addr_type = ev->bdaddr_type;
+               bacpy(&conn->init_addr, &ev->bdaddr);
+       }
+
+       /* Lookup the identity address from the stored connection
+        * address and address type.
+        *
+        * When establishing connections to an identity address, the
+        * connection procedure will store the resolvable random
+        * address first. Now if it can be converted back into the
+        * identity address, start using the identity address from
+        * now on.
+        */
+       irk = hci_get_irk(hdev, &conn->dst, conn->dst_type);
+       if (irk) {
+               bacpy(&conn->dst, &irk->bdaddr);
+               conn->dst_type = irk->addr_type;
        }
 
        if (ev->status) {
-               mgmt_connect_failed(hdev, &conn->dst, conn->type,
-                                   conn->dst_type, ev->status);
-               hci_proto_connect_cfm(conn, ev->status);
-               conn->state = BT_CLOSED;
-               hci_conn_del(conn);
+               hci_le_conn_failed(conn, ev->status);
                goto unlock;
        }
 
        if (!test_and_set_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags))
-               mgmt_device_connected(hdev, &ev->bdaddr, conn->type,
+               mgmt_device_connected(hdev, &conn->dst, conn->type,
                                      conn->dst_type, 0, NULL, 0, NULL);
 
        conn->sec_level = BT_SECURITY_LOW;
@@ -3540,25 +3985,145 @@ static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
 
        hci_proto_connect_cfm(conn, ev->status);
 
+       hci_pend_le_conn_del(hdev, &conn->dst, conn->dst_type);
+
 unlock:
        hci_dev_unlock(hdev);
 }
 
+/* This function requires the caller holds hdev->lock */
+static void check_pending_le_conn(struct hci_dev *hdev, bdaddr_t *addr,
+                                 u8 addr_type)
+{
+       struct hci_conn *conn;
+       struct smp_irk *irk;
+
+       /* If this is a resolvable address, we should resolve it and then
+        * update address and address type variables.
+        */
+       irk = hci_get_irk(hdev, addr, addr_type);
+       if (irk) {
+               addr = &irk->bdaddr;
+               addr_type = irk->addr_type;
+       }
+
+       if (!hci_pend_le_conn_lookup(hdev, addr, addr_type))
+               return;
+
+       conn = hci_connect_le(hdev, addr, addr_type, BT_SECURITY_LOW,
+                             HCI_AT_NO_BONDING);
+       if (!IS_ERR(conn))
+               return;
+
+       switch (PTR_ERR(conn)) {
+       case -EBUSY:
+               /* If hci_connect() returns -EBUSY it means there is already
+                * an LE connection attempt going on. Since controllers don't
+                * support more than one connection attempt at the time, we
+                * don't consider this an error case.
+                */
+               break;
+       default:
+               BT_DBG("Failed to connect: err %ld", PTR_ERR(conn));
+       }
+}
+
+static void process_adv_report(struct hci_dev *hdev, u8 type, bdaddr_t *bdaddr,
+                              u8 bdaddr_type, s8 rssi, u8 *data, u8 len)
+{
+       struct discovery_state *d = &hdev->discovery;
+       bool match;
+
+       /* Passive scanning shouldn't trigger any device found events */
+       if (hdev->le_scan_type == LE_SCAN_PASSIVE) {
+               if (type == LE_ADV_IND || type == LE_ADV_DIRECT_IND)
+                       check_pending_le_conn(hdev, bdaddr, bdaddr_type);
+               return;
+       }
+
+       /* If there's nothing pending either store the data from this
+        * event or send an immediate device found event if the data
+        * should not be stored for later.
+        */
+       if (!has_pending_adv_report(hdev)) {
+               /* If the report will trigger a SCAN_REQ store it for
+                * later merging.
+                */
+               if (type == LE_ADV_IND || type == LE_ADV_SCAN_IND) {
+                       store_pending_adv_report(hdev, bdaddr, bdaddr_type,
+                                                rssi, data, len);
+                       return;
+               }
+
+               mgmt_device_found(hdev, bdaddr, LE_LINK, bdaddr_type, NULL,
+                                 rssi, 0, 1, data, len, NULL, 0);
+               return;
+       }
+
+       /* Check if the pending report is for the same device as the new one */
+       match = (!bacmp(bdaddr, &d->last_adv_addr) &&
+                bdaddr_type == d->last_adv_addr_type);
+
+       /* If the pending data doesn't match this report or this isn't a
+        * scan response (e.g. we got a duplicate ADV_IND) then force
+        * sending of the pending data.
+        */
+       if (type != LE_ADV_SCAN_RSP || !match) {
+               /* Send out whatever is in the cache, but skip duplicates */
+               if (!match)
+                       mgmt_device_found(hdev, &d->last_adv_addr, LE_LINK,
+                                         d->last_adv_addr_type, NULL,
+                                         d->last_adv_rssi, 0, 1,
+                                         d->last_adv_data,
+                                         d->last_adv_data_len, NULL, 0);
+
+               /* If the new report will trigger a SCAN_REQ store it for
+                * later merging.
+                */
+               if (type == LE_ADV_IND || type == LE_ADV_SCAN_IND) {
+                       store_pending_adv_report(hdev, bdaddr, bdaddr_type,
+                                                rssi, data, len);
+                       return;
+               }
+
+               /* The advertising reports cannot be merged, so clear
+                * the pending report and send out a device found event.
+                */
+               clear_pending_adv_report(hdev);
+               mgmt_device_found(hdev, bdaddr, LE_LINK, bdaddr_type, NULL,
+                                 rssi, 0, 1, data, len, NULL, 0);
+               return;
+       }
+
+       /* If we get here we've got a pending ADV_IND or ADV_SCAN_IND and
+        * the new event is a SCAN_RSP. We can therefore proceed with
+        * sending a merged device found event.
+        */
+       mgmt_device_found(hdev, &d->last_adv_addr, LE_LINK,
+                         d->last_adv_addr_type, NULL, rssi, 0, 1, data, len,
+                         d->last_adv_data, d->last_adv_data_len);
+       clear_pending_adv_report(hdev);
+}
+
 static void hci_le_adv_report_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
        u8 num_reports = skb->data[0];
        void *ptr = &skb->data[1];
-       s8 rssi;
+
+       hci_dev_lock(hdev);
 
        while (num_reports--) {
                struct hci_ev_le_advertising_info *ev = ptr;
+               s8 rssi;
 
                rssi = ev->data[ev->length];
-               mgmt_device_found(hdev, &ev->bdaddr, LE_LINK, ev->bdaddr_type,
-                                 NULL, rssi, 0, 1, ev->data, ev->length);
+               process_adv_report(hdev, ev->evt_type, &ev->bdaddr,
+                                  ev->bdaddr_type, rssi, ev->data, ev->length);
 
                ptr += sizeof(*ev) + ev->length + 1;
        }
+
+       hci_dev_unlock(hdev);
 }
 
 static void hci_le_ltk_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
@@ -3577,7 +4142,7 @@ static void hci_le_ltk_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
        if (conn == NULL)
                goto not_found;
 
-       ltk = hci_find_ltk(hdev, ev->ediv, ev->random);
+       ltk = hci_find_ltk(hdev, ev->ediv, ev->rand, conn->out);
        if (ltk == NULL)
                goto not_found;
 
@@ -3593,7 +4158,13 @@ static void hci_le_ltk_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
 
        hci_send_cmd(hdev, HCI_OP_LE_LTK_REPLY, sizeof(cp), &cp);
 
-       if (ltk->type & HCI_SMP_STK) {
+       /* Ref. Bluetooth Core SPEC pages 1975 and 2004. STK is a
+        * temporary key used to encrypt a connection following
+        * pairing. It is used during the Encrypted Session Setup to
+        * distribute the keys. Later, security can be re-established
+        * using a distributed LTK.
+        */
+       if (ltk->type == HCI_SMP_STK_SLAVE) {
                list_del(&ltk->list);
                kfree(ltk);
        }