Bluetooth: Fix redundant device (un)blocked events
[cascardo/linux.git] / net / bluetooth / mgmt.c
index 54abbce..ba5e215 100644 (file)
 
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci_core.h>
+#include <net/bluetooth/l2cap.h>
 #include <net/bluetooth/mgmt.h>
 
 #include "smp.h"
 
 #define MGMT_VERSION   1
-#define MGMT_REVISION  5
+#define MGMT_REVISION  7
 
 static const u16 mgmt_commands[] = {
        MGMT_OP_READ_INDEX_LIST,
@@ -83,6 +84,10 @@ static const u16 mgmt_commands[] = {
        MGMT_OP_SET_DEBUG_KEYS,
        MGMT_OP_SET_PRIVACY,
        MGMT_OP_LOAD_IRKS,
+       MGMT_OP_GET_CONN_INFO,
+       MGMT_OP_GET_CLOCK_INFO,
+       MGMT_OP_ADD_DEVICE,
+       MGMT_OP_REMOVE_DEVICE,
 };
 
 static const u16 mgmt_events[] = {
@@ -109,6 +114,8 @@ static const u16 mgmt_events[] = {
        MGMT_EV_PASSKEY_NOTIFY,
        MGMT_EV_NEW_IRK,
        MGMT_EV_NEW_CSRK,
+       MGMT_EV_DEVICE_ADDED,
+       MGMT_EV_DEVICE_REMOVED,
 };
 
 #define CACHE_TIMEOUT  msecs_to_jiffies(2 * 1000)
@@ -344,6 +351,9 @@ static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data,
                if (test_bit(HCI_USER_CHANNEL, &d->dev_flags))
                        continue;
 
+               if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks))
+                       continue;
+
                if (d->dev_type == HCI_BREDR) {
                        rp->index[count++] = cpu_to_le16(d->id);
                        BT_DBG("Added hci%u", d->id);
@@ -385,7 +395,7 @@ static u32 get_supported_settings(struct hci_dev *hdev)
                }
 
                if (lmp_sc_capable(hdev) ||
-                   test_bit(HCI_FORCE_SC, &hdev->dev_flags))
+                   test_bit(HCI_FORCE_SC, &hdev->dbg_flags))
                        settings |= MGMT_SETTING_SECURE_CONN;
        }
 
@@ -438,7 +448,7 @@ static u32 get_current_settings(struct hci_dev *hdev)
        if (test_bit(HCI_SC_ENABLED, &hdev->dev_flags))
                settings |= MGMT_SETTING_SECURE_CONN;
 
-       if (test_bit(HCI_DEBUG_KEYS, &hdev->dev_flags))
+       if (test_bit(HCI_KEEP_DEBUG_KEYS, &hdev->dev_flags))
                settings |= MGMT_SETTING_DEBUG_KEYS;
 
        if (test_bit(HCI_PRIVACY, &hdev->dev_flags))
@@ -569,6 +579,22 @@ static struct pending_cmd *mgmt_pending_find(u16 opcode, struct hci_dev *hdev)
        return NULL;
 }
 
+static struct pending_cmd *mgmt_pending_find_data(u16 opcode,
+                                                 struct hci_dev *hdev,
+                                                 const void *data)
+{
+       struct pending_cmd *cmd;
+
+       list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
+               if (cmd->user_data != data)
+                       continue;
+               if (cmd->opcode == opcode)
+                       return cmd;
+       }
+
+       return NULL;
+}
+
 static u8 create_scan_rsp_data(struct hci_dev *hdev, u8 *ptr)
 {
        u8 ad_len = 0;
@@ -982,7 +1008,7 @@ static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
 {
        struct pending_cmd *cmd;
 
-       cmd = kmalloc(sizeof(*cmd), GFP_KERNEL);
+       cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
        if (!cmd)
                return NULL;
 
@@ -1045,6 +1071,43 @@ static void clean_up_hci_complete(struct hci_dev *hdev, u8 status)
        }
 }
 
+static void hci_stop_discovery(struct hci_request *req)
+{
+       struct hci_dev *hdev = req->hdev;
+       struct hci_cp_remote_name_req_cancel cp;
+       struct inquiry_entry *e;
+
+       switch (hdev->discovery.state) {
+       case DISCOVERY_FINDING:
+               if (test_bit(HCI_INQUIRY, &hdev->flags)) {
+                       hci_req_add(req, HCI_OP_INQUIRY_CANCEL, 0, NULL);
+               } else {
+                       cancel_delayed_work(&hdev->le_scan_disable);
+                       hci_req_add_le_scan_disable(req);
+               }
+
+               break;
+
+       case DISCOVERY_RESOLVING:
+               e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY,
+                                                    NAME_PENDING);
+               if (!e)
+                       return;
+
+               bacpy(&cp.bdaddr, &e->data.bdaddr);
+               hci_req_add(req, HCI_OP_REMOTE_NAME_REQ_CANCEL, sizeof(cp),
+                           &cp);
+
+               break;
+
+       default:
+               /* Passive scanning */
+               if (test_bit(HCI_LE_SCAN, &hdev->dev_flags))
+                       hci_req_add_le_scan_disable(req);
+               break;
+       }
+}
+
 static int clean_up_hci_state(struct hci_dev *hdev)
 {
        struct hci_request req;
@@ -1061,9 +1124,7 @@ static int clean_up_hci_state(struct hci_dev *hdev)
        if (test_bit(HCI_ADVERTISING, &hdev->dev_flags))
                disable_advertising(&req);
 
-       if (test_bit(HCI_LE_SCAN, &hdev->dev_flags)) {
-               hci_req_add_le_scan_disable(&req);
-       }
+       hci_stop_discovery(&req);
 
        list_for_each_entry(conn, &hdev->conn_hash.list, list) {
                struct hci_cp_disconnect dc;
@@ -1840,6 +1901,10 @@ static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
                goto failed;
        }
 
+       if (!cp->val && test_bit(HCI_USE_DEBUG_KEYS, &hdev->dev_flags))
+               hci_send_cmd(hdev, HCI_OP_WRITE_SSP_DEBUG_MODE,
+                            sizeof(cp->val), &cp->val);
+
        err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, 1, &cp->val);
        if (err < 0) {
                mgmt_pending_remove(cmd);
@@ -2377,9 +2442,11 @@ static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
        hci_link_keys_clear(hdev);
 
        if (cp->debug_keys)
-               changed = !test_and_set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
+               changed = !test_and_set_bit(HCI_KEEP_DEBUG_KEYS,
+                                           &hdev->dev_flags);
        else
-               changed = test_and_clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
+               changed = test_and_clear_bit(HCI_KEEP_DEBUG_KEYS,
+                                            &hdev->dev_flags);
 
        if (changed)
                new_settings(hdev, NULL);
@@ -2387,8 +2454,14 @@ static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
        for (i = 0; i < key_count; i++) {
                struct mgmt_link_key_info *key = &cp->keys[i];
 
-               hci_add_link_key(hdev, NULL, 0, &key->addr.bdaddr, key->val,
-                                key->type, key->pin_len);
+               /* Always ignore debug keys and require a new pairing if
+                * the user wants to use them.
+                */
+               if (key->type == HCI_LK_DEBUG_COMBINATION)
+                       continue;
+
+               hci_add_link_key(hdev, NULL, &key->addr.bdaddr, key->val,
+                                key->type, key->pin_len, NULL);
        }
 
        cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
@@ -2729,6 +2802,10 @@ static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
 
        BT_DBG("");
 
+       if (cp->io_capability > SMP_IO_KEYBOARD_DISPLAY)
+               return cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY,
+                                   MGMT_STATUS_INVALID_PARAMS, NULL, 0);
+
        hci_dev_lock(hdev);
 
        hdev->io_capability = cp->io_capability;
@@ -2841,6 +2918,11 @@ static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
                                    MGMT_STATUS_INVALID_PARAMS,
                                    &rp, sizeof(rp));
 
+       if (cp->io_cap > SMP_IO_KEYBOARD_DISPLAY)
+               return cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
+                                   MGMT_STATUS_INVALID_PARAMS,
+                                   &rp, sizeof(rp));
+
        hci_dev_lock(hdev);
 
        if (!hdev_is_powered(hdev)) {
@@ -2865,6 +2947,17 @@ static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
                else
                        addr_type = ADDR_LE_DEV_RANDOM;
 
+               /* When pairing a new device, it is expected to remember
+                * this device for future connections. Adding the connection
+                * parameter information ahead of time allows tracking
+                * of the slave preferred values and will speed up any
+                * further connection establishment.
+                *
+                * If connection parameters already exist, then they
+                * will be kept and this function does nothing.
+                */
+               hci_conn_params_add(hdev, &cp->addr.bdaddr, addr_type);
+
                conn = hci_connect_le(hdev, &cp->addr.bdaddr, addr_type,
                                      sec_level, auth_type);
        }
@@ -2994,9 +3087,7 @@ static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
        }
 
        if (addr->type == BDADDR_LE_PUBLIC || addr->type == BDADDR_LE_RANDOM) {
-               /* Continue with pairing via SMP */
                err = smp_user_confirm_reply(conn, mgmt_op, passkey);
-
                if (!err)
                        err = cmd_complete(sk, hdev->id, mgmt_op,
                                           MGMT_STATUS_SUCCESS, addr,
@@ -3572,8 +3663,6 @@ static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
 {
        struct mgmt_cp_stop_discovery *mgmt_cp = data;
        struct pending_cmd *cmd;
-       struct hci_cp_remote_name_req_cancel cp;
-       struct inquiry_entry *e;
        struct hci_request req;
        int err;
 
@@ -3603,52 +3692,22 @@ static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
 
        hci_req_init(&req, hdev);
 
-       switch (hdev->discovery.state) {
-       case DISCOVERY_FINDING:
-               if (test_bit(HCI_INQUIRY, &hdev->flags)) {
-                       hci_req_add(&req, HCI_OP_INQUIRY_CANCEL, 0, NULL);
-               } else {
-                       cancel_delayed_work(&hdev->le_scan_disable);
-
-                       hci_req_add_le_scan_disable(&req);
-               }
-
-               break;
-
-       case DISCOVERY_RESOLVING:
-               e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY,
-                                                    NAME_PENDING);
-               if (!e) {
-                       mgmt_pending_remove(cmd);
-                       err = cmd_complete(sk, hdev->id,
-                                          MGMT_OP_STOP_DISCOVERY, 0,
-                                          &mgmt_cp->type,
-                                          sizeof(mgmt_cp->type));
-                       hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
-                       goto unlock;
-               }
-
-               bacpy(&cp.bdaddr, &e->data.bdaddr);
-               hci_req_add(&req, HCI_OP_REMOTE_NAME_REQ_CANCEL, sizeof(cp),
-                           &cp);
-
-               break;
+       hci_stop_discovery(&req);
 
-       default:
-               BT_DBG("unknown discovery state %u", hdev->discovery.state);
-
-               mgmt_pending_remove(cmd);
-               err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
-                                  MGMT_STATUS_FAILED, &mgmt_cp->type,
-                                  sizeof(mgmt_cp->type));
+       err = hci_req_run(&req, stop_discovery_complete);
+       if (!err) {
+               hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
                goto unlock;
        }
 
-       err = hci_req_run(&req, stop_discovery_complete);
-       if (err < 0)
-               mgmt_pending_remove(cmd);
-       else
-               hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
+       mgmt_pending_remove(cmd);
+
+       /* If no HCI commands were sent we're done */
+       if (err == -ENODATA) {
+               err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY, 0,
+                                  &mgmt_cp->type, sizeof(mgmt_cp->type));
+               hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
+       }
 
 unlock:
        hci_dev_unlock(hdev);
@@ -3714,11 +3773,16 @@ static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
        hci_dev_lock(hdev);
 
        err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
-       if (err < 0)
+       if (err < 0) {
                status = MGMT_STATUS_FAILED;
-       else
-               status = MGMT_STATUS_SUCCESS;
+               goto done;
+       }
 
+       mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &cp->addr, sizeof(cp->addr),
+                  sk);
+       status = MGMT_STATUS_SUCCESS;
+
+done:
        err = cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
                           &cp->addr, sizeof(cp->addr));
 
@@ -3744,11 +3808,16 @@ static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
        hci_dev_lock(hdev);
 
        err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
-       if (err < 0)
+       if (err < 0) {
                status = MGMT_STATUS_INVALID_PARAMS;
-       else
-               status = MGMT_STATUS_SUCCESS;
+               goto done;
+       }
+
+       mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &cp->addr, sizeof(cp->addr),
+                  sk);
+       status = MGMT_STATUS_SUCCESS;
 
+done:
        err = cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
                           &cp->addr, sizeof(cp->addr));
 
@@ -4242,7 +4311,7 @@ static int set_secure_conn(struct sock *sk, struct hci_dev *hdev,
                                  status);
 
        if (!lmp_sc_capable(hdev) &&
-           !test_bit(HCI_FORCE_SC, &hdev->dev_flags))
+           !test_bit(HCI_FORCE_SC, &hdev->dbg_flags))
                return cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
                                  MGMT_STATUS_NOT_SUPPORTED);
 
@@ -4318,21 +4387,37 @@ static int set_debug_keys(struct sock *sk, struct hci_dev *hdev,
                          void *data, u16 len)
 {
        struct mgmt_mode *cp = data;
-       bool changed;
+       bool changed, use_changed;
        int err;
 
        BT_DBG("request for %s", hdev->name);
 
-       if (cp->val != 0x00 && cp->val != 0x01)
+       if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
                return cmd_status(sk, hdev->id, MGMT_OP_SET_DEBUG_KEYS,
                                  MGMT_STATUS_INVALID_PARAMS);
 
        hci_dev_lock(hdev);
 
        if (cp->val)
-               changed = !test_and_set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
+               changed = !test_and_set_bit(HCI_KEEP_DEBUG_KEYS,
+                                           &hdev->dev_flags);
+       else
+               changed = test_and_clear_bit(HCI_KEEP_DEBUG_KEYS,
+                                            &hdev->dev_flags);
+
+       if (cp->val == 0x02)
+               use_changed = !test_and_set_bit(HCI_USE_DEBUG_KEYS,
+                                               &hdev->dev_flags);
        else
-               changed = test_and_clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
+               use_changed = test_and_clear_bit(HCI_USE_DEBUG_KEYS,
+                                                &hdev->dev_flags);
+
+       if (hdev_is_powered(hdev) && use_changed &&
+           test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
+               u8 mode = (cp->val == 0x02) ? 0x01 : 0x00;
+               hci_send_cmd(hdev, HCI_OP_WRITE_SSP_DEBUG_MODE,
+                            sizeof(mode), &mode);
+       }
 
        err = send_settings_rsp(sk, MGMT_OP_SET_DEBUG_KEYS, hdev);
        if (err < 0)
@@ -4532,7 +4617,7 @@ static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
 
        for (i = 0; i < key_count; i++) {
                struct mgmt_ltk_info *key = &cp->keys[i];
-               u8 type, addr_type;
+               u8 type, addr_type, authenticated;
 
                if (key->addr.type == BDADDR_LE_PUBLIC)
                        addr_type = ADDR_LE_DEV_PUBLIC;
@@ -4540,12 +4625,23 @@ static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
                        addr_type = ADDR_LE_DEV_RANDOM;
 
                if (key->master)
-                       type = HCI_SMP_LTK;
+                       type = SMP_LTK;
                else
-                       type = HCI_SMP_LTK_SLAVE;
+                       type = SMP_LTK_SLAVE;
+
+               switch (key->type) {
+               case MGMT_LTK_UNAUTHENTICATED:
+                       authenticated = 0x00;
+                       break;
+               case MGMT_LTK_AUTHENTICATED:
+                       authenticated = 0x01;
+                       break;
+               default:
+                       continue;
+               }
 
                hci_add_ltk(hdev, &key->addr.bdaddr, addr_type, type,
-                           key->type, key->val, key->enc_size, key->ediv,
+                           authenticated, key->val, key->enc_size, key->ediv,
                            key->rand);
        }
 
@@ -4557,6 +4653,467 @@ static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
        return err;
 }
 
+struct cmd_conn_lookup {
+       struct hci_conn *conn;
+       bool valid_tx_power;
+       u8 mgmt_status;
+};
+
+static void get_conn_info_complete(struct pending_cmd *cmd, void *data)
+{
+       struct cmd_conn_lookup *match = data;
+       struct mgmt_cp_get_conn_info *cp;
+       struct mgmt_rp_get_conn_info rp;
+       struct hci_conn *conn = cmd->user_data;
+
+       if (conn != match->conn)
+               return;
+
+       cp = (struct mgmt_cp_get_conn_info *) cmd->param;
+
+       memset(&rp, 0, sizeof(rp));
+       bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
+       rp.addr.type = cp->addr.type;
+
+       if (!match->mgmt_status) {
+               rp.rssi = conn->rssi;
+
+               if (match->valid_tx_power) {
+                       rp.tx_power = conn->tx_power;
+                       rp.max_tx_power = conn->max_tx_power;
+               } else {
+                       rp.tx_power = HCI_TX_POWER_INVALID;
+                       rp.max_tx_power = HCI_TX_POWER_INVALID;
+               }
+       }
+
+       cmd_complete(cmd->sk, cmd->index, MGMT_OP_GET_CONN_INFO,
+                    match->mgmt_status, &rp, sizeof(rp));
+
+       hci_conn_drop(conn);
+
+       mgmt_pending_remove(cmd);
+}
+
+static void conn_info_refresh_complete(struct hci_dev *hdev, u8 status)
+{
+       struct hci_cp_read_rssi *cp;
+       struct hci_conn *conn;
+       struct cmd_conn_lookup match;
+       u16 handle;
+
+       BT_DBG("status 0x%02x", status);
+
+       hci_dev_lock(hdev);
+
+       /* TX power data is valid in case request completed successfully,
+        * otherwise we assume it's not valid. At the moment we assume that
+        * either both or none of current and max values are valid to keep code
+        * simple.
+        */
+       match.valid_tx_power = !status;
+
+       /* Commands sent in request are either Read RSSI or Read Transmit Power
+        * Level so we check which one was last sent to retrieve connection
+        * handle.  Both commands have handle as first parameter so it's safe to
+        * cast data on the same command struct.
+        *
+        * First command sent is always Read RSSI and we fail only if it fails.
+        * In other case we simply override error to indicate success as we
+        * already remembered if TX power value is actually valid.
+        */
+       cp = hci_sent_cmd_data(hdev, HCI_OP_READ_RSSI);
+       if (!cp) {
+               cp = hci_sent_cmd_data(hdev, HCI_OP_READ_TX_POWER);
+               status = 0;
+       }
+
+       if (!cp) {
+               BT_ERR("invalid sent_cmd in response");
+               goto unlock;
+       }
+
+       handle = __le16_to_cpu(cp->handle);
+       conn = hci_conn_hash_lookup_handle(hdev, handle);
+       if (!conn) {
+               BT_ERR("unknown handle (%d) in response", handle);
+               goto unlock;
+       }
+
+       match.conn = conn;
+       match.mgmt_status = mgmt_status(status);
+
+       /* Cache refresh is complete, now reply for mgmt request for given
+        * connection only.
+        */
+       mgmt_pending_foreach(MGMT_OP_GET_CONN_INFO, hdev,
+                            get_conn_info_complete, &match);
+
+unlock:
+       hci_dev_unlock(hdev);
+}
+
+static int get_conn_info(struct sock *sk, struct hci_dev *hdev, void *data,
+                        u16 len)
+{
+       struct mgmt_cp_get_conn_info *cp = data;
+       struct mgmt_rp_get_conn_info rp;
+       struct hci_conn *conn;
+       unsigned long conn_info_age;
+       int err = 0;
+
+       BT_DBG("%s", hdev->name);
+
+       memset(&rp, 0, sizeof(rp));
+       bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
+       rp.addr.type = cp->addr.type;
+
+       if (!bdaddr_type_is_valid(cp->addr.type))
+               return cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
+                                   MGMT_STATUS_INVALID_PARAMS,
+                                   &rp, sizeof(rp));
+
+       hci_dev_lock(hdev);
+
+       if (!hdev_is_powered(hdev)) {
+               err = cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
+                                  MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
+               goto unlock;
+       }
+
+       if (cp->addr.type == BDADDR_BREDR)
+               conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
+                                              &cp->addr.bdaddr);
+       else
+               conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
+
+       if (!conn || conn->state != BT_CONNECTED) {
+               err = cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
+                                  MGMT_STATUS_NOT_CONNECTED, &rp, sizeof(rp));
+               goto unlock;
+       }
+
+       /* To avoid client trying to guess when to poll again for information we
+        * calculate conn info age as random value between min/max set in hdev.
+        */
+       conn_info_age = hdev->conn_info_min_age +
+                       prandom_u32_max(hdev->conn_info_max_age -
+                                       hdev->conn_info_min_age);
+
+       /* Query controller to refresh cached values if they are too old or were
+        * never read.
+        */
+       if (time_after(jiffies, conn->conn_info_timestamp +
+                      msecs_to_jiffies(conn_info_age)) ||
+           !conn->conn_info_timestamp) {
+               struct hci_request req;
+               struct hci_cp_read_tx_power req_txp_cp;
+               struct hci_cp_read_rssi req_rssi_cp;
+               struct pending_cmd *cmd;
+
+               hci_req_init(&req, hdev);
+               req_rssi_cp.handle = cpu_to_le16(conn->handle);
+               hci_req_add(&req, HCI_OP_READ_RSSI, sizeof(req_rssi_cp),
+                           &req_rssi_cp);
+
+               /* For LE links TX power does not change thus we don't need to
+                * query for it once value is known.
+                */
+               if (!bdaddr_type_is_le(cp->addr.type) ||
+                   conn->tx_power == HCI_TX_POWER_INVALID) {
+                       req_txp_cp.handle = cpu_to_le16(conn->handle);
+                       req_txp_cp.type = 0x00;
+                       hci_req_add(&req, HCI_OP_READ_TX_POWER,
+                                   sizeof(req_txp_cp), &req_txp_cp);
+               }
+
+               /* Max TX power needs to be read only once per connection */
+               if (conn->max_tx_power == HCI_TX_POWER_INVALID) {
+                       req_txp_cp.handle = cpu_to_le16(conn->handle);
+                       req_txp_cp.type = 0x01;
+                       hci_req_add(&req, HCI_OP_READ_TX_POWER,
+                                   sizeof(req_txp_cp), &req_txp_cp);
+               }
+
+               err = hci_req_run(&req, conn_info_refresh_complete);
+               if (err < 0)
+                       goto unlock;
+
+               cmd = mgmt_pending_add(sk, MGMT_OP_GET_CONN_INFO, hdev,
+                                      data, len);
+               if (!cmd) {
+                       err = -ENOMEM;
+                       goto unlock;
+               }
+
+               hci_conn_hold(conn);
+               cmd->user_data = conn;
+
+               conn->conn_info_timestamp = jiffies;
+       } else {
+               /* Cache is valid, just reply with values cached in hci_conn */
+               rp.rssi = conn->rssi;
+               rp.tx_power = conn->tx_power;
+               rp.max_tx_power = conn->max_tx_power;
+
+               err = cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
+                                  MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
+       }
+
+unlock:
+       hci_dev_unlock(hdev);
+       return err;
+}
+
+static void get_clock_info_complete(struct hci_dev *hdev, u8 status)
+{
+       struct mgmt_cp_get_clock_info *cp;
+       struct mgmt_rp_get_clock_info rp;
+       struct hci_cp_read_clock *hci_cp;
+       struct pending_cmd *cmd;
+       struct hci_conn *conn;
+
+       BT_DBG("%s status %u", hdev->name, status);
+
+       hci_dev_lock(hdev);
+
+       hci_cp = hci_sent_cmd_data(hdev, HCI_OP_READ_CLOCK);
+       if (!hci_cp)
+               goto unlock;
+
+       if (hci_cp->which) {
+               u16 handle = __le16_to_cpu(hci_cp->handle);
+               conn = hci_conn_hash_lookup_handle(hdev, handle);
+       } else {
+               conn = NULL;
+       }
+
+       cmd = mgmt_pending_find_data(MGMT_OP_GET_CLOCK_INFO, hdev, conn);
+       if (!cmd)
+               goto unlock;
+
+       cp = cmd->param;
+
+       memset(&rp, 0, sizeof(rp));
+       memcpy(&rp.addr, &cp->addr, sizeof(rp.addr));
+
+       if (status)
+               goto send_rsp;
+
+       rp.local_clock = cpu_to_le32(hdev->clock);
+
+       if (conn) {
+               rp.piconet_clock = cpu_to_le32(conn->clock);
+               rp.accuracy = cpu_to_le16(conn->clock_accuracy);
+       }
+
+send_rsp:
+       cmd_complete(cmd->sk, cmd->index, cmd->opcode, mgmt_status(status),
+                    &rp, sizeof(rp));
+       mgmt_pending_remove(cmd);
+       if (conn)
+               hci_conn_drop(conn);
+
+unlock:
+       hci_dev_unlock(hdev);
+}
+
+static int get_clock_info(struct sock *sk, struct hci_dev *hdev, void *data,
+                        u16 len)
+{
+       struct mgmt_cp_get_clock_info *cp = data;
+       struct mgmt_rp_get_clock_info rp;
+       struct hci_cp_read_clock hci_cp;
+       struct pending_cmd *cmd;
+       struct hci_request req;
+       struct hci_conn *conn;
+       int err;
+
+       BT_DBG("%s", hdev->name);
+
+       memset(&rp, 0, sizeof(rp));
+       bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
+       rp.addr.type = cp->addr.type;
+
+       if (cp->addr.type != BDADDR_BREDR)
+               return cmd_complete(sk, hdev->id, MGMT_OP_GET_CLOCK_INFO,
+                                   MGMT_STATUS_INVALID_PARAMS,
+                                   &rp, sizeof(rp));
+
+       hci_dev_lock(hdev);
+
+       if (!hdev_is_powered(hdev)) {
+               err = cmd_complete(sk, hdev->id, MGMT_OP_GET_CLOCK_INFO,
+                                  MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
+               goto unlock;
+       }
+
+       if (bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
+               conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
+                                              &cp->addr.bdaddr);
+               if (!conn || conn->state != BT_CONNECTED) {
+                       err = cmd_complete(sk, hdev->id,
+                                          MGMT_OP_GET_CLOCK_INFO,
+                                          MGMT_STATUS_NOT_CONNECTED,
+                                          &rp, sizeof(rp));
+                       goto unlock;
+               }
+       } else {
+               conn = NULL;
+       }
+
+       cmd = mgmt_pending_add(sk, MGMT_OP_GET_CLOCK_INFO, hdev, data, len);
+       if (!cmd) {
+               err = -ENOMEM;
+               goto unlock;
+       }
+
+       hci_req_init(&req, hdev);
+
+       memset(&hci_cp, 0, sizeof(hci_cp));
+       hci_req_add(&req, HCI_OP_READ_CLOCK, sizeof(hci_cp), &hci_cp);
+
+       if (conn) {
+               hci_conn_hold(conn);
+               cmd->user_data = conn;
+
+               hci_cp.handle = cpu_to_le16(conn->handle);
+               hci_cp.which = 0x01; /* Piconet clock */
+               hci_req_add(&req, HCI_OP_READ_CLOCK, sizeof(hci_cp), &hci_cp);
+       }
+
+       err = hci_req_run(&req, get_clock_info_complete);
+       if (err < 0)
+               mgmt_pending_remove(cmd);
+
+unlock:
+       hci_dev_unlock(hdev);
+       return err;
+}
+
+static void device_added(struct sock *sk, struct hci_dev *hdev,
+                        bdaddr_t *bdaddr, u8 type, u8 action)
+{
+       struct mgmt_ev_device_added ev;
+
+       bacpy(&ev.addr.bdaddr, bdaddr);
+       ev.addr.type = type;
+       ev.action = action;
+
+       mgmt_event(MGMT_EV_DEVICE_ADDED, hdev, &ev, sizeof(ev), sk);
+}
+
+static int add_device(struct sock *sk, struct hci_dev *hdev,
+                     void *data, u16 len)
+{
+       struct mgmt_cp_add_device *cp = data;
+       u8 auto_conn, addr_type;
+       int err;
+
+       BT_DBG("%s", hdev->name);
+
+       if (!bdaddr_type_is_le(cp->addr.type) ||
+           !bacmp(&cp->addr.bdaddr, BDADDR_ANY))
+               return cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
+                                   MGMT_STATUS_INVALID_PARAMS,
+                                   &cp->addr, sizeof(cp->addr));
+
+       if (cp->action != 0x00 && cp->action != 0x01)
+               return cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
+                                   MGMT_STATUS_INVALID_PARAMS,
+                                   &cp->addr, sizeof(cp->addr));
+
+       hci_dev_lock(hdev);
+
+       if (cp->addr.type == BDADDR_LE_PUBLIC)
+               addr_type = ADDR_LE_DEV_PUBLIC;
+       else
+               addr_type = ADDR_LE_DEV_RANDOM;
+
+       if (cp->action)
+               auto_conn = HCI_AUTO_CONN_ALWAYS;
+       else
+               auto_conn = HCI_AUTO_CONN_DISABLED;
+
+       /* If the connection parameters don't exist for this device,
+        * they will be created and configured with defaults.
+        */
+       if (hci_conn_params_set(hdev, &cp->addr.bdaddr, addr_type,
+                               auto_conn) < 0) {
+               err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
+                                  MGMT_STATUS_FAILED,
+                                  &cp->addr, sizeof(cp->addr));
+               goto unlock;
+       }
+
+       device_added(sk, hdev, &cp->addr.bdaddr, cp->addr.type, cp->action);
+
+       err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
+                          MGMT_STATUS_SUCCESS, &cp->addr, sizeof(cp->addr));
+
+unlock:
+       hci_dev_unlock(hdev);
+       return err;
+}
+
+static void device_removed(struct sock *sk, struct hci_dev *hdev,
+                          bdaddr_t *bdaddr, u8 type)
+{
+       struct mgmt_ev_device_removed ev;
+
+       bacpy(&ev.addr.bdaddr, bdaddr);
+       ev.addr.type = type;
+
+       mgmt_event(MGMT_EV_DEVICE_REMOVED, hdev, &ev, sizeof(ev), sk);
+}
+
+static int remove_device(struct sock *sk, struct hci_dev *hdev,
+                        void *data, u16 len)
+{
+       struct mgmt_cp_remove_device *cp = data;
+       int err;
+
+       BT_DBG("%s", hdev->name);
+
+       hci_dev_lock(hdev);
+
+       if (bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
+               u8 addr_type;
+
+               if (!bdaddr_type_is_le(cp->addr.type)) {
+                       err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_DEVICE,
+                                          MGMT_STATUS_INVALID_PARAMS,
+                                          &cp->addr, sizeof(cp->addr));
+                       goto unlock;
+               }
+
+               if (cp->addr.type == BDADDR_LE_PUBLIC)
+                       addr_type = ADDR_LE_DEV_PUBLIC;
+               else
+                       addr_type = ADDR_LE_DEV_RANDOM;
+
+               hci_conn_params_del(hdev, &cp->addr.bdaddr, addr_type);
+
+               device_removed(sk, hdev, &cp->addr.bdaddr, cp->addr.type);
+       } else {
+               if (cp->addr.type) {
+                       err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_DEVICE,
+                                          MGMT_STATUS_INVALID_PARAMS,
+                                          &cp->addr, sizeof(cp->addr));
+                       goto unlock;
+               }
+
+               hci_conn_params_clear(hdev);
+       }
+
+       err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_DEVICE,
+                          MGMT_STATUS_SUCCESS, &cp->addr, sizeof(cp->addr));
+
+unlock:
+       hci_dev_unlock(hdev);
+       return err;
+}
+
 static const struct mgmt_handler {
        int (*func) (struct sock *sk, struct hci_dev *hdev, void *data,
                     u16 data_len);
@@ -4612,9 +5169,12 @@ static const struct mgmt_handler {
        { set_debug_keys,         false, MGMT_SETTING_SIZE },
        { set_privacy,            false, MGMT_SET_PRIVACY_SIZE },
        { load_irks,              true,  MGMT_LOAD_IRKS_SIZE },
+       { get_conn_info,          false, MGMT_GET_CONN_INFO_SIZE },
+       { get_clock_info,         false, MGMT_GET_CLOCK_INFO_SIZE },
+       { add_device,             false, MGMT_ADD_DEVICE_SIZE },
+       { remove_device,          false, MGMT_REMOVE_DEVICE_SIZE },
 };
 
-
 int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
 {
        void *buf;
@@ -4658,7 +5218,8 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
                }
 
                if (test_bit(HCI_SETUP, &hdev->dev_flags) ||
-                   test_bit(HCI_USER_CHANNEL, &hdev->dev_flags)) {
+                   test_bit(HCI_USER_CHANNEL, &hdev->dev_flags) ||
+                   test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks)) {
                        err = cmd_status(sk, index, opcode,
                                         MGMT_STATUS_INVALID_INDEX);
                        goto done;
@@ -4732,11 +5293,27 @@ void mgmt_index_removed(struct hci_dev *hdev)
 static void restart_le_auto_conns(struct hci_dev *hdev)
 {
        struct hci_conn_params *p;
+       bool added = false;
 
        list_for_each_entry(p, &hdev->le_conn_params, list) {
-               if (p->auto_connect == HCI_AUTO_CONN_ALWAYS)
+               if (p->auto_connect == HCI_AUTO_CONN_ALWAYS) {
                        hci_pend_le_conn_add(hdev, &p->addr, p->addr_type);
+                       added = true;
+               }
        }
+
+       /* Calling hci_pend_le_conn_add will actually already trigger
+        * background scanning when needed. So no need to trigger it
+        * just another time.
+        *
+        * This check is here to avoid an unneeded restart of the
+        * passive scanning. Since this is during the controller
+        * power up phase the duplicate filtering is not an issue.
+        */
+       if (added)
+               return;
+
+       hci_update_background_scan(hdev);
 }
 
 static void powered_complete(struct hci_dev *hdev, u8 status)
@@ -5007,6 +5584,14 @@ void mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
        mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
 }
 
+static u8 mgmt_ltk_type(struct smp_ltk *ltk)
+{
+       if (ltk->authenticated)
+               return MGMT_LTK_AUTHENTICATED;
+
+       return MGMT_LTK_UNAUTHENTICATED;
+}
+
 void mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, bool persistent)
 {
        struct mgmt_ev_new_long_term_key ev;
@@ -5032,12 +5617,12 @@ void mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, bool persistent)
 
        bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
        ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type);
-       ev.key.type = key->authenticated;
+       ev.key.type = mgmt_ltk_type(key);
        ev.key.enc_size = key->enc_size;
        ev.key.ediv = key->ediv;
        ev.key.rand = key->rand;
 
-       if (key->type == HCI_SMP_LTK)
+       if (key->type == SMP_LTK)
                ev.key.master = 1;
 
        memcpy(ev.key.val, key->val, sizeof(key->val));
@@ -5523,10 +6108,14 @@ void mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
 
        hci_req_init(&req, hdev);
 
-       if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
+       if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
+               if (test_bit(HCI_USE_DEBUG_KEYS, &hdev->dev_flags))
+                       hci_req_add(&req, HCI_OP_WRITE_SSP_DEBUG_MODE,
+                                   sizeof(enable), &enable);
                update_eir(&req);
-       else
+       } else {
                clear_eir(&req);
+       }
 
        hci_req_run(&req, NULL);
 }
@@ -5670,9 +6259,8 @@ void mgmt_read_local_oob_data_complete(struct hci_dev *hdev, u8 *hash192,
 }
 
 void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
-                      u8 addr_type, u8 *dev_class, s8 rssi, u8 cfm_name,
-                      u8 ssp, u8 *eir, u16 eir_len, u8 *scan_rsp,
-                      u8 scan_rsp_len)
+                      u8 addr_type, u8 *dev_class, s8 rssi, u32 flags,
+                      u8 *eir, u16 eir_len, u8 *scan_rsp, u8 scan_rsp_len)
 {
        char buf[512];
        struct mgmt_ev_device_found *ev = (void *) buf;
@@ -5700,10 +6288,7 @@ void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
        }
 
        ev->rssi = rssi;
-       if (cfm_name)
-               ev->flags |= cpu_to_le32(MGMT_DEV_FOUND_CONFIRM_NAME);
-       if (!ssp)
-               ev->flags |= cpu_to_le32(MGMT_DEV_FOUND_LEGACY_PAIRING);
+       ev->flags = cpu_to_le32(flags);
 
        if (eir_len > 0)
                memcpy(ev->eir, eir, eir_len);
@@ -5771,34 +6356,6 @@ void mgmt_discovering(struct hci_dev *hdev, u8 discovering)
        mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
 }
 
-int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
-{
-       struct pending_cmd *cmd;
-       struct mgmt_ev_device_blocked ev;
-
-       cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
-
-       bacpy(&ev.addr.bdaddr, bdaddr);
-       ev.addr.type = type;
-
-       return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
-                         cmd ? cmd->sk : NULL);
-}
-
-int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
-{
-       struct pending_cmd *cmd;
-       struct mgmt_ev_device_unblocked ev;
-
-       cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
-
-       bacpy(&ev.addr.bdaddr, bdaddr);
-       ev.addr.type = type;
-
-       return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
-                         cmd ? cmd->sk : NULL);
-}
-
 static void adv_enable_complete(struct hci_dev *hdev, u8 status)
 {
        BT_DBG("%s status %u", hdev->name, status);