]> git.proxmox.com Git - mirror_ubuntu-zesty-kernel.git/blobdiff - net/bluetooth/mgmt.c
Bluetooth: Fix using hci_conn_get() for hci_conn pointers
[mirror_ubuntu-zesty-kernel.git] / net / bluetooth / mgmt.c
index af8e0a6243b7520617156f79d7d430ce12ef4be9..d8c66663ade8cd77ee7894c9ac47c3e9c0fbf5a8 100644 (file)
@@ -35,7 +35,7 @@
 #include "smp.h"
 
 #define MGMT_VERSION   1
-#define MGMT_REVISION  6
+#define MGMT_REVISION  7
 
 static const u16 mgmt_commands[] = {
        MGMT_OP_READ_INDEX_LIST,
@@ -44,7 +44,7 @@ static const u16 mgmt_commands[] = {
        MGMT_OP_SET_DISCOVERABLE,
        MGMT_OP_SET_CONNECTABLE,
        MGMT_OP_SET_FAST_CONNECTABLE,
-       MGMT_OP_SET_PAIRABLE,
+       MGMT_OP_SET_BONDABLE,
        MGMT_OP_SET_LINK_SECURITY,
        MGMT_OP_SET_SSP,
        MGMT_OP_SET_HS,
@@ -85,6 +85,14 @@ static const u16 mgmt_commands[] = {
        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,
+       MGMT_OP_LOAD_CONN_PARAM,
+       MGMT_OP_READ_UNCONF_INDEX_LIST,
+       MGMT_OP_READ_CONFIG_INFO,
+       MGMT_OP_SET_EXTERNAL_CONFIG,
+       MGMT_OP_SET_PUBLIC_ADDRESS,
 };
 
 static const u16 mgmt_events[] = {
@@ -111,13 +119,16 @@ 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,
+       MGMT_EV_NEW_CONN_PARAM,
+       MGMT_EV_UNCONF_INDEX_ADDED,
+       MGMT_EV_UNCONF_INDEX_REMOVED,
+       MGMT_EV_NEW_CONFIG_OPTIONS,
 };
 
 #define CACHE_TIMEOUT  msecs_to_jiffies(2 * 1000)
 
-#define hdev_is_powered(hdev) (test_bit(HCI_UP, &hdev->flags) && \
-                               !test_bit(HCI_AUTO_OFF, &hdev->dev_flags))
-
 struct pending_cmd {
        struct list_head list;
        u16 opcode;
@@ -200,6 +211,36 @@ static u8 mgmt_status(u8 hci_status)
        return MGMT_STATUS_FAILED;
 }
 
+static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, u16 data_len,
+                     struct sock *skip_sk)
+{
+       struct sk_buff *skb;
+       struct mgmt_hdr *hdr;
+
+       skb = alloc_skb(sizeof(*hdr) + data_len, GFP_KERNEL);
+       if (!skb)
+               return -ENOMEM;
+
+       hdr = (void *) skb_put(skb, sizeof(*hdr));
+       hdr->opcode = cpu_to_le16(event);
+       if (hdev)
+               hdr->index = cpu_to_le16(hdev->id);
+       else
+               hdr->index = cpu_to_le16(MGMT_INDEX_NONE);
+       hdr->len = cpu_to_le16(data_len);
+
+       if (data)
+               memcpy(skb_put(skb, data_len), data, data_len);
+
+       /* Time stamp */
+       __net_timestamp(skb);
+
+       hci_send_to_control(skb, skip_sk);
+       kfree_skb(skb);
+
+       return 0;
+}
+
 static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
 {
        struct sk_buff *skb;
@@ -327,7 +368,8 @@ static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data,
 
        count = 0;
        list_for_each_entry(d, &hci_dev_list, list) {
-               if (d->dev_type == HCI_BREDR)
+               if (d->dev_type == HCI_BREDR &&
+                   !test_bit(HCI_UNCONFIGURED, &d->dev_flags))
                        count++;
        }
 
@@ -340,13 +382,19 @@ static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data,
 
        count = 0;
        list_for_each_entry(d, &hci_dev_list, list) {
-               if (test_bit(HCI_SETUP, &d->dev_flags))
+               if (test_bit(HCI_SETUP, &d->dev_flags) ||
+                   test_bit(HCI_CONFIG, &d->dev_flags) ||
+                   test_bit(HCI_USER_CHANNEL, &d->dev_flags))
                        continue;
 
-               if (test_bit(HCI_USER_CHANNEL, &d->dev_flags))
+               /* Devices marked as raw-only are neither configured
+                * nor unconfigured controllers.
+                */
+               if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks))
                        continue;
 
-               if (d->dev_type == HCI_BREDR) {
+               if (d->dev_type == HCI_BREDR &&
+                   !test_bit(HCI_UNCONFIGURED, &d->dev_flags)) {
                        rp->index[count++] = cpu_to_le16(d->id);
                        BT_DBG("Added hci%u", d->id);
                }
@@ -365,19 +413,151 @@ static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data,
        return err;
 }
 
+static int read_unconf_index_list(struct sock *sk, struct hci_dev *hdev,
+                                 void *data, u16 data_len)
+{
+       struct mgmt_rp_read_unconf_index_list *rp;
+       struct hci_dev *d;
+       size_t rp_len;
+       u16 count;
+       int err;
+
+       BT_DBG("sock %p", sk);
+
+       read_lock(&hci_dev_list_lock);
+
+       count = 0;
+       list_for_each_entry(d, &hci_dev_list, list) {
+               if (d->dev_type == HCI_BREDR &&
+                   test_bit(HCI_UNCONFIGURED, &d->dev_flags))
+                       count++;
+       }
+
+       rp_len = sizeof(*rp) + (2 * count);
+       rp = kmalloc(rp_len, GFP_ATOMIC);
+       if (!rp) {
+               read_unlock(&hci_dev_list_lock);
+               return -ENOMEM;
+       }
+
+       count = 0;
+       list_for_each_entry(d, &hci_dev_list, list) {
+               if (test_bit(HCI_SETUP, &d->dev_flags) ||
+                   test_bit(HCI_CONFIG, &d->dev_flags) ||
+                   test_bit(HCI_USER_CHANNEL, &d->dev_flags))
+                       continue;
+
+               /* Devices marked as raw-only are neither configured
+                * nor unconfigured controllers.
+                */
+               if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks))
+                       continue;
+
+               if (d->dev_type == HCI_BREDR &&
+                   test_bit(HCI_UNCONFIGURED, &d->dev_flags)) {
+                       rp->index[count++] = cpu_to_le16(d->id);
+                       BT_DBG("Added hci%u", d->id);
+               }
+       }
+
+       rp->num_controllers = cpu_to_le16(count);
+       rp_len = sizeof(*rp) + (2 * count);
+
+       read_unlock(&hci_dev_list_lock);
+
+       err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_UNCONF_INDEX_LIST,
+                          0, rp, rp_len);
+
+       kfree(rp);
+
+       return err;
+}
+
+static bool is_configured(struct hci_dev *hdev)
+{
+       if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks) &&
+           !test_bit(HCI_EXT_CONFIGURED, &hdev->dev_flags))
+               return false;
+
+       if (test_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks) &&
+           !bacmp(&hdev->public_addr, BDADDR_ANY))
+               return false;
+
+       return true;
+}
+
+static __le32 get_missing_options(struct hci_dev *hdev)
+{
+       u32 options = 0;
+
+       if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks) &&
+           !test_bit(HCI_EXT_CONFIGURED, &hdev->dev_flags))
+               options |= MGMT_OPTION_EXTERNAL_CONFIG;
+
+       if (test_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks) &&
+           !bacmp(&hdev->public_addr, BDADDR_ANY))
+               options |= MGMT_OPTION_PUBLIC_ADDRESS;
+
+       return cpu_to_le32(options);
+}
+
+static int new_options(struct hci_dev *hdev, struct sock *skip)
+{
+       __le32 options = get_missing_options(hdev);
+
+       return mgmt_event(MGMT_EV_NEW_CONFIG_OPTIONS, hdev, &options,
+                         sizeof(options), skip);
+}
+
+static int send_options_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
+{
+       __le32 options = get_missing_options(hdev);
+
+       return cmd_complete(sk, hdev->id, opcode, 0, &options,
+                           sizeof(options));
+}
+
+static int read_config_info(struct sock *sk, struct hci_dev *hdev,
+                           void *data, u16 data_len)
+{
+       struct mgmt_rp_read_config_info rp;
+       u32 options = 0;
+
+       BT_DBG("sock %p %s", sk, hdev->name);
+
+       hci_dev_lock(hdev);
+
+       memset(&rp, 0, sizeof(rp));
+       rp.manufacturer = cpu_to_le16(hdev->manufacturer);
+
+       if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks))
+               options |= MGMT_OPTION_EXTERNAL_CONFIG;
+
+       if (hdev->set_bdaddr)
+               options |= MGMT_OPTION_PUBLIC_ADDRESS;
+
+       rp.supported_options = cpu_to_le32(options);
+       rp.missing_options = get_missing_options(hdev);
+
+       hci_dev_unlock(hdev);
+
+       return cmd_complete(sk, hdev->id, MGMT_OP_READ_CONFIG_INFO, 0, &rp,
+                           sizeof(rp));
+}
+
 static u32 get_supported_settings(struct hci_dev *hdev)
 {
        u32 settings = 0;
 
        settings |= MGMT_SETTING_POWERED;
-       settings |= MGMT_SETTING_PAIRABLE;
+       settings |= MGMT_SETTING_BONDABLE;
        settings |= MGMT_SETTING_DEBUG_KEYS;
+       settings |= MGMT_SETTING_CONNECTABLE;
+       settings |= MGMT_SETTING_DISCOVERABLE;
 
        if (lmp_bredr_capable(hdev)) {
-               settings |= MGMT_SETTING_CONNECTABLE;
                if (hdev->hci_ver >= BLUETOOTH_VER_1_2)
                        settings |= MGMT_SETTING_FAST_CONNECTABLE;
-               settings |= MGMT_SETTING_DISCOVERABLE;
                settings |= MGMT_SETTING_BREDR;
                settings |= MGMT_SETTING_LINK_SECURITY;
 
@@ -387,7 +567,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;
        }
 
@@ -397,6 +577,10 @@ static u32 get_supported_settings(struct hci_dev *hdev)
                settings |= MGMT_SETTING_PRIVACY;
        }
 
+       if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks) ||
+           hdev->set_bdaddr)
+               settings |= MGMT_SETTING_CONFIGURATION;
+
        return settings;
 }
 
@@ -416,8 +600,8 @@ static u32 get_current_settings(struct hci_dev *hdev)
        if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
                settings |= MGMT_SETTING_DISCOVERABLE;
 
-       if (test_bit(HCI_PAIRABLE, &hdev->dev_flags))
-               settings |= MGMT_SETTING_PAIRABLE;
+       if (test_bit(HCI_BONDABLE, &hdev->dev_flags))
+               settings |= MGMT_SETTING_BONDABLE;
 
        if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
                settings |= MGMT_SETTING_BREDR;
@@ -440,7 +624,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))
@@ -571,6 +755,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;
@@ -703,6 +903,16 @@ static void update_adv_data(struct hci_request *req)
        hci_req_add(req, HCI_OP_LE_SET_ADV_DATA, sizeof(cp), &cp);
 }
 
+int mgmt_update_adv_data(struct hci_dev *hdev)
+{
+       struct hci_request req;
+
+       hci_req_init(&req, hdev);
+       update_adv_data(&req);
+
+       return hci_req_run(&req, NULL);
+}
+
 static void create_eir(struct hci_dev *hdev, u8 *data)
 {
        u8 *ptr = data;
@@ -836,6 +1046,13 @@ static bool get_connectable(struct hci_dev *hdev)
        return test_bit(HCI_CONNECTABLE, &hdev->dev_flags);
 }
 
+static void disable_advertising(struct hci_request *req)
+{
+       u8 enable = 0x00;
+
+       hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable);
+}
+
 static void enable_advertising(struct hci_request *req)
 {
        struct hci_dev *hdev = req->hdev;
@@ -843,12 +1060,18 @@ static void enable_advertising(struct hci_request *req)
        u8 own_addr_type, enable = 0x01;
        bool connectable;
 
-       /* Clear the HCI_ADVERTISING bit temporarily so that the
+       if (hci_conn_num(hdev, LE_LINK) > 0)
+               return;
+
+       if (test_bit(HCI_LE_ADV, &hdev->dev_flags))
+               disable_advertising(req);
+
+       /* Clear the HCI_LE_ADV bit temporarily so that the
         * hci_update_random_address knows that it's safe to go ahead
         * and write a new random address. The flag will be set back on
         * as soon as the SET_ADV_ENABLE HCI command completes.
         */
-       clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
+       clear_bit(HCI_LE_ADV, &hdev->dev_flags);
 
        connectable = get_connectable(hdev);
 
@@ -860,8 +1083,8 @@ static void enable_advertising(struct hci_request *req)
                return;
 
        memset(&cp, 0, sizeof(cp));
-       cp.min_interval = cpu_to_le16(0x0800);
-       cp.max_interval = cpu_to_le16(0x0800);
+       cp.min_interval = cpu_to_le16(hdev->le_adv_min_interval);
+       cp.max_interval = cpu_to_le16(hdev->le_adv_max_interval);
        cp.type = connectable ? LE_ADV_IND : LE_ADV_NONCONN_IND;
        cp.own_address_type = own_addr_type;
        cp.channel_map = hdev->le_adv_channel_map;
@@ -871,13 +1094,6 @@ static void enable_advertising(struct hci_request *req)
        hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable);
 }
 
-static void disable_advertising(struct hci_request *req)
-{
-       u8 enable = 0x00;
-
-       hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable);
-}
-
 static void service_cache_off(struct work_struct *work)
 {
        struct hci_dev *hdev = container_of(work, struct hci_dev,
@@ -909,19 +1125,14 @@ static void rpa_expired(struct work_struct *work)
 
        set_bit(HCI_RPA_EXPIRED, &hdev->dev_flags);
 
-       if (!test_bit(HCI_ADVERTISING, &hdev->dev_flags) ||
-           hci_conn_num(hdev, LE_LINK) > 0)
+       if (!test_bit(HCI_ADVERTISING, &hdev->dev_flags))
                return;
 
        /* The generation of a new RPA and programming it into the
         * controller happens in the enable_advertising() function.
         */
-
        hci_req_init(&req, hdev);
-
-       disable_advertising(&req);
        enable_advertising(&req);
-
        hci_req_run(&req, NULL);
 }
 
@@ -938,7 +1149,7 @@ static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev)
         * for mgmt we require user-space to explicitly enable
         * it
         */
-       clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
+       clear_bit(HCI_BONDABLE, &hdev->dev_flags);
 }
 
 static int read_controller_info(struct sock *sk, struct hci_dev *hdev,
@@ -984,7 +1195,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;
 
@@ -1047,7 +1258,7 @@ static void clean_up_hci_complete(struct hci_dev *hdev, u8 status)
        }
 }
 
-static void hci_stop_discovery(struct hci_request *req)
+static bool hci_stop_discovery(struct hci_request *req)
 {
        struct hci_dev *hdev = req->hdev;
        struct hci_cp_remote_name_req_cancel cp;
@@ -1062,32 +1273,39 @@ static void hci_stop_discovery(struct hci_request *req)
                        hci_req_add_le_scan_disable(req);
                }
 
-               break;
+               return true;
 
        case DISCOVERY_RESOLVING:
                e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY,
                                                     NAME_PENDING);
                if (!e)
-                       return;
+                       break;
 
                bacpy(&cp.bdaddr, &e->data.bdaddr);
                hci_req_add(req, HCI_OP_REMOTE_NAME_REQ_CANCEL, sizeof(cp),
                            &cp);
 
-               break;
+               return true;
 
        default:
                /* Passive scanning */
-               if (test_bit(HCI_LE_SCAN, &hdev->dev_flags))
+               if (test_bit(HCI_LE_SCAN, &hdev->dev_flags)) {
                        hci_req_add_le_scan_disable(req);
+                       return true;
+               }
+
                break;
        }
+
+       return false;
 }
 
 static int clean_up_hci_state(struct hci_dev *hdev)
 {
        struct hci_request req;
        struct hci_conn *conn;
+       bool discov_stopped;
+       int err;
 
        hci_req_init(&req, hdev);
 
@@ -1097,10 +1315,10 @@ static int clean_up_hci_state(struct hci_dev *hdev)
                hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
        }
 
-       if (test_bit(HCI_ADVERTISING, &hdev->dev_flags))
+       if (test_bit(HCI_LE_ADV, &hdev->dev_flags))
                disable_advertising(&req);
 
-       hci_stop_discovery(&req);
+       discov_stopped = hci_stop_discovery(&req);
 
        list_for_each_entry(conn, &hdev->conn_hash.list, list) {
                struct hci_cp_disconnect dc;
@@ -1134,7 +1352,11 @@ static int clean_up_hci_state(struct hci_dev *hdev)
                }
        }
 
-       return hci_req_run(&req, clean_up_hci_complete);
+       err = hci_req_run(&req, clean_up_hci_complete);
+       if (!err && discov_stopped)
+               hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
+
+       return err;
 }
 
 static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
@@ -1203,36 +1425,6 @@ failed:
        return err;
 }
 
-static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, u16 data_len,
-                     struct sock *skip_sk)
-{
-       struct sk_buff *skb;
-       struct mgmt_hdr *hdr;
-
-       skb = alloc_skb(sizeof(*hdr) + data_len, GFP_KERNEL);
-       if (!skb)
-               return -ENOMEM;
-
-       hdr = (void *) skb_put(skb, sizeof(*hdr));
-       hdr->opcode = cpu_to_le16(event);
-       if (hdev)
-               hdr->index = cpu_to_le16(hdev->id);
-       else
-               hdr->index = cpu_to_le16(MGMT_INDEX_NONE);
-       hdr->len = cpu_to_le16(data_len);
-
-       if (data)
-               memcpy(skb_put(skb, data_len), data, data_len);
-
-       /* Time stamp */
-       __net_timestamp(skb);
-
-       hci_send_to_control(skb, skip_sk);
-       kfree_skb(skb);
-
-       return 0;
-}
-
 static int new_settings(struct hci_dev *hdev, struct sock *skip)
 {
        __le32 ev;
@@ -1242,6 +1434,11 @@ static int new_settings(struct hci_dev *hdev, struct sock *skip)
        return mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), skip);
 }
 
+int mgmt_new_settings(struct hci_dev *hdev)
+{
+       return new_settings(hdev, NULL);
+}
+
 struct cmd_lookup {
        struct sock *sk;
        struct hci_dev *hdev;
@@ -1336,9 +1533,11 @@ static void set_discoverable_complete(struct hci_dev *hdev, u8 status)
 
        /* When the discoverable mode gets changed, make sure
         * that class of device has the limited discoverable
-        * bit correctly set.
+        * bit correctly set. Also update page scan based on whitelist
+        * entries.
         */
        hci_req_init(&req, hdev);
+       hci_update_page_scan(hdev, &req);
        update_class(&req);
        hci_req_run(&req, NULL);
 
@@ -1553,7 +1752,7 @@ static void set_connectable_complete(struct hci_dev *hdev, u8 status)
 {
        struct pending_cmd *cmd;
        struct mgmt_mode *cp;
-       bool changed;
+       bool conn_changed, discov_changed;
 
        BT_DBG("status 0x%02x", status);
 
@@ -1570,15 +1769,26 @@ static void set_connectable_complete(struct hci_dev *hdev, u8 status)
        }
 
        cp = cmd->param;
-       if (cp->val)
-               changed = !test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
-       else
-               changed = test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
+       if (cp->val) {
+               conn_changed = !test_and_set_bit(HCI_CONNECTABLE,
+                                                &hdev->dev_flags);
+               discov_changed = false;
+       } else {
+               conn_changed = test_and_clear_bit(HCI_CONNECTABLE,
+                                                 &hdev->dev_flags);
+               discov_changed = test_and_clear_bit(HCI_DISCOVERABLE,
+                                                   &hdev->dev_flags);
+       }
 
        send_settings_rsp(cmd->sk, MGMT_OP_SET_CONNECTABLE, hdev);
 
-       if (changed)
+       if (conn_changed || discov_changed) {
                new_settings(hdev, cmd->sk);
+               hci_update_page_scan(hdev, NULL);
+               if (discov_changed)
+                       mgmt_update_adv_data(hdev);
+               hci_update_background_scan(hdev);
+       }
 
 remove_cmd:
        mgmt_pending_remove(cmd);
@@ -1607,8 +1817,11 @@ static int set_connectable_update_settings(struct hci_dev *hdev,
        if (err < 0)
                return err;
 
-       if (changed)
+       if (changed) {
+               hci_update_page_scan(hdev, NULL);
+               hci_update_background_scan(hdev);
                return new_settings(hdev, sk);
+       }
 
        return 0;
 }
@@ -1669,7 +1882,18 @@ static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
                if (cp->val) {
                        scan = SCAN_PAGE;
                } else {
-                       scan = 0;
+                       /* If we don't have any whitelist entries just
+                        * disable all scanning. If there are entries
+                        * and we had both page and inquiry scanning
+                        * enabled then fall back to only page scanning.
+                        * Otherwise no changes are needed.
+                        */
+                       if (list_empty(&hdev->whitelist))
+                               scan = SCAN_DISABLED;
+                       else if (test_bit(HCI_ISCAN, &hdev->flags))
+                               scan = SCAN_PAGE;
+                       else
+                               goto no_scan_update;
 
                        if (test_bit(HCI_ISCAN, &hdev->flags) &&
                            hdev->discov_timeout > 0)
@@ -1679,6 +1903,7 @@ static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
                hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
        }
 
+no_scan_update:
        /* If we're going from non-connectable to connectable or
         * vice-versa when fast connectable is enabled ensure that fast
         * connectable gets disabled. write_fast_connectable won't do
@@ -1688,11 +1913,9 @@ static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
        if (cp->val || test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags))
                write_fast_connectable(&req, false);
 
-       if (test_bit(HCI_ADVERTISING, &hdev->dev_flags) &&
-           hci_conn_num(hdev, LE_LINK) == 0) {
-               disable_advertising(&req);
+       /* Update the advertising parameters if necessary */
+       if (test_bit(HCI_ADVERTISING, &hdev->dev_flags))
                enable_advertising(&req);
-       }
 
        err = hci_req_run(&req, set_connectable_complete);
        if (err < 0) {
@@ -1708,7 +1931,7 @@ failed:
        return err;
 }
 
-static int set_pairable(struct sock *sk, struct hci_dev *hdev, void *data,
+static int set_bondable(struct sock *sk, struct hci_dev *hdev, void *data,
                        u16 len)
 {
        struct mgmt_mode *cp = data;
@@ -1718,17 +1941,17 @@ static int set_pairable(struct sock *sk, struct hci_dev *hdev, void *data,
        BT_DBG("request for %s", hdev->name);
 
        if (cp->val != 0x00 && cp->val != 0x01)
-               return cmd_status(sk, hdev->id, MGMT_OP_SET_PAIRABLE,
+               return cmd_status(sk, hdev->id, MGMT_OP_SET_BONDABLE,
                                  MGMT_STATUS_INVALID_PARAMS);
 
        hci_dev_lock(hdev);
 
        if (cp->val)
-               changed = !test_and_set_bit(HCI_PAIRABLE, &hdev->dev_flags);
+               changed = !test_and_set_bit(HCI_BONDABLE, &hdev->dev_flags);
        else
-               changed = test_and_clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
+               changed = test_and_clear_bit(HCI_BONDABLE, &hdev->dev_flags);
 
-       err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev);
+       err = send_settings_rsp(sk, MGMT_OP_SET_BONDABLE, hdev);
        if (err < 0)
                goto unlock;
 
@@ -1877,6 +2100,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);
@@ -1973,6 +2200,8 @@ static void le_enable_complete(struct hci_dev *hdev, u8 status)
                update_scan_rsp_data(&req);
                hci_req_run(&req, NULL);
 
+               hci_update_background_scan(hdev);
+
                hci_dev_unlock(hdev);
        }
 }
@@ -2048,9 +2277,9 @@ static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
 
        if (val) {
                hci_cp.le = val;
-               hci_cp.simul = lmp_le_br_capable(hdev);
+               hci_cp.simul = 0x00;
        } else {
-               if (test_bit(HCI_ADVERTISING, &hdev->dev_flags))
+               if (test_bit(HCI_LE_ADV, &hdev->dev_flags))
                        disable_advertising(&req);
        }
 
@@ -2373,6 +2602,8 @@ static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
                          u16 len)
 {
        struct mgmt_cp_load_link_keys *cp = data;
+       const u16 max_key_count = ((U16_MAX - sizeof(*cp)) /
+                                  sizeof(struct mgmt_link_key_info));
        u16 key_count, expected_len;
        bool changed;
        int i;
@@ -2384,6 +2615,12 @@ static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
                                  MGMT_STATUS_NOT_SUPPORTED);
 
        key_count = __le16_to_cpu(cp->key_count);
+       if (key_count > max_key_count) {
+               BT_ERR("load_link_keys: too big key_count value %u",
+                      key_count);
+               return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
+                                 MGMT_STATUS_INVALID_PARAMS);
+       }
 
        expected_len = sizeof(*cp) + key_count *
                                        sizeof(struct mgmt_link_key_info);
@@ -2414,9 +2651,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);
@@ -2424,8 +2663,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);
@@ -2766,6 +3011,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;
@@ -2814,6 +3063,7 @@ static void pairing_complete(struct pending_cmd *cmd, u8 status)
        conn->disconn_cfm_cb = NULL;
 
        hci_conn_drop(conn);
+       hci_conn_put(conn);
 
        mgmt_pending_remove(cmd);
 }
@@ -2878,6 +3128,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)) {
@@ -2902,8 +3157,20 @@ 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);
+                                     sec_level, HCI_LE_CONN_TIMEOUT,
+                                     HCI_ROLE_MASTER);
        }
 
        if (IS_ERR(conn)) {
@@ -2946,10 +3213,10 @@ static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
        }
 
        conn->io_capability = cp->io_cap;
-       cmd->user_data = conn;
+       cmd->user_data = hci_conn_get(conn);
 
-       if (conn->state == BT_CONNECTED &&
-           hci_conn_security(conn, sec_level, auth_type))
+       if ((conn->state == BT_CONNECTED || conn->state == BT_CONFIG) &&
+           hci_conn_security(conn, sec_level, auth_type, true))
                pairing_complete(cmd, 0);
 
        err = 0;
@@ -3031,14 +3298,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. The hdev lock must be
-                * released as SMP may try to recquire it for crypto
-                * purposes.
-                */
-               hci_dev_unlock(hdev);
                err = smp_user_confirm_reply(conn, mgmt_op, passkey);
-               hci_dev_lock(hdev);
-
                if (!err)
                        err = cmd_complete(sk, hdev->id, mgmt_op,
                                           MGMT_STATUS_SUCCESS, addr,
@@ -3516,11 +3776,21 @@ static int start_discovery(struct sock *sk, struct hci_dev *hdev,
                        goto failed;
                }
 
-               if (test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
-                       err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
-                                        MGMT_STATUS_REJECTED);
-                       mgmt_pending_remove(cmd);
-                       goto failed;
+               if (test_bit(HCI_LE_ADV, &hdev->dev_flags)) {
+                       /* Don't let discovery abort an outgoing
+                        * connection attempt that's using directed
+                        * advertising.
+                        */
+                       if (hci_conn_hash_lookup_state(hdev, LE_LINK,
+                                                      BT_CONNECT)) {
+                               err = cmd_status(sk, hdev->id,
+                                                MGMT_OP_START_DISCOVERY,
+                                                MGMT_STATUS_REJECTED);
+                               mgmt_pending_remove(cmd);
+                               goto failed;
+                       }
+
+                       disable_advertising(&req);
                }
 
                /* If controller is scanning, it means the background scanning
@@ -3723,12 +3993,18 @@ 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)
+       err = hci_bdaddr_list_add(&hdev->blacklist, &cp->addr.bdaddr,
+                                 cp->addr.type);
+       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));
 
@@ -3753,12 +4029,18 @@ 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)
+       err = hci_bdaddr_list_del(&hdev->blacklist, &cp->addr.bdaddr,
+                                 cp->addr.type);
+       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));
 
@@ -3813,6 +4095,11 @@ static void set_advertising_complete(struct hci_dev *hdev, u8 status)
                return;
        }
 
+       if (test_bit(HCI_LE_ADV, &hdev->dev_flags))
+               set_bit(HCI_ADVERTISING, &hdev->dev_flags);
+       else
+               clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
+
        mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, settings_rsp,
                             &match);
 
@@ -3853,7 +4140,9 @@ static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data,
         * necessary).
         */
        if (!hdev_is_powered(hdev) || val == enabled ||
-           hci_conn_num(hdev, LE_LINK) > 0) {
+           hci_conn_num(hdev, LE_LINK) > 0 ||
+           (test_bit(HCI_LE_SCAN, &hdev->dev_flags) &&
+            hdev->le_scan_type == LE_SCAN_ACTIVE)) {
                bool changed = false;
 
                if (val != test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
@@ -4094,26 +4383,6 @@ unlock:
        return err;
 }
 
-static void set_bredr_scan(struct hci_request *req)
-{
-       struct hci_dev *hdev = req->hdev;
-       u8 scan = 0;
-
-       /* Ensure that fast connectable is disabled. This function will
-        * not do anything if the page scan parameters are already what
-        * they should be.
-        */
-       write_fast_connectable(req, false);
-
-       if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
-               scan |= SCAN_PAGE;
-       if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
-               scan |= SCAN_INQUIRY;
-
-       if (scan)
-               hci_req_add(req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
-}
-
 static void set_bredr_complete(struct hci_dev *hdev, u8 status)
 {
        struct pending_cmd *cmd;
@@ -4219,8 +4488,8 @@ static int set_bredr(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
 
        hci_req_init(&req, hdev);
 
-       if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
-               set_bredr_scan(&req);
+       write_fast_connectable(&req, false);
+       hci_update_page_scan(hdev, &req);
 
        /* Since only the advertising data flags will change, there
         * is no need to update the scan response data.
@@ -4252,7 +4521,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);
 
@@ -4328,21 +4597,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)
@@ -4426,6 +4711,8 @@ static int load_irks(struct sock *sk, struct hci_dev *hdev, void *cp_data,
                     u16 len)
 {
        struct mgmt_cp_load_irks *cp = cp_data;
+       const u16 max_irk_count = ((U16_MAX - sizeof(*cp)) /
+                                  sizeof(struct mgmt_irk_info));
        u16 irk_count, expected_len;
        int i, err;
 
@@ -4436,6 +4723,11 @@ static int load_irks(struct sock *sk, struct hci_dev *hdev, void *cp_data,
                                  MGMT_STATUS_NOT_SUPPORTED);
 
        irk_count = __le16_to_cpu(cp->irk_count);
+       if (irk_count > max_irk_count) {
+               BT_ERR("load_irks: too big irk_count value %u", irk_count);
+               return cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
+                                 MGMT_STATUS_INVALID_PARAMS);
+       }
 
        expected_len = sizeof(*cp) + irk_count * sizeof(struct mgmt_irk_info);
        if (expected_len != len) {
@@ -4505,6 +4797,8 @@ static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
                               void *cp_data, u16 len)
 {
        struct mgmt_cp_load_long_term_keys *cp = cp_data;
+       const u16 max_key_count = ((U16_MAX - sizeof(*cp)) /
+                                  sizeof(struct mgmt_ltk_info));
        u16 key_count, expected_len;
        int i, err;
 
@@ -4515,6 +4809,11 @@ static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
                                  MGMT_STATUS_NOT_SUPPORTED);
 
        key_count = __le16_to_cpu(cp->key_count);
+       if (key_count > max_key_count) {
+               BT_ERR("load_ltks: too big key_count value %u", key_count);
+               return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
+                                 MGMT_STATUS_INVALID_PARAMS);
+       }
 
        expected_len = sizeof(*cp) + key_count *
                                        sizeof(struct mgmt_ltk_info);
@@ -4550,9 +4849,9 @@ 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:
@@ -4616,6 +4915,7 @@ static void get_conn_info_complete(struct pending_cmd *cmd, void *data)
                     match->mgmt_status, &rp, sizeof(rp));
 
        hci_conn_drop(conn);
+       hci_conn_put(conn);
 
        mgmt_pending_remove(cmd);
 }
@@ -4772,7 +5072,7 @@ static int get_conn_info(struct sock *sk, struct hci_dev *hdev, void *data,
                }
 
                hci_conn_hold(conn);
-               cmd->user_data = conn;
+               cmd->user_data = hci_conn_get(conn);
 
                conn->conn_info_timestamp = jiffies;
        } else {
@@ -4790,6 +5090,536 @@ unlock:
        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);
+               hci_conn_put(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 = hci_conn_get(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_valid(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 && cp->action != 0x02)
+               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_BREDR) {
+               /* Only incoming connections action is supported for now */
+               if (cp->action != 0x01) {
+                       err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
+                                          MGMT_STATUS_INVALID_PARAMS,
+                                          &cp->addr, sizeof(cp->addr));
+                       goto unlock;
+               }
+
+               err = hci_bdaddr_list_add(&hdev->whitelist, &cp->addr.bdaddr,
+                                         cp->addr.type);
+               if (err)
+                       goto unlock;
+
+               hci_update_page_scan(hdev, NULL);
+
+               goto added;
+       }
+
+       if (cp->addr.type == BDADDR_LE_PUBLIC)
+               addr_type = ADDR_LE_DEV_PUBLIC;
+       else
+               addr_type = ADDR_LE_DEV_RANDOM;
+
+       if (cp->action == 0x02)
+               auto_conn = HCI_AUTO_CONN_ALWAYS;
+       else if (cp->action == 0x01)
+               auto_conn = HCI_AUTO_CONN_DIRECT;
+       else
+               auto_conn = HCI_AUTO_CONN_REPORT;
+
+       /* 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;
+       }
+
+added:
+       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)) {
+               struct hci_conn_params *params;
+               u8 addr_type;
+
+               if (!bdaddr_type_is_valid(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_BREDR) {
+                       err = hci_bdaddr_list_del(&hdev->whitelist,
+                                                 &cp->addr.bdaddr,
+                                                 cp->addr.type);
+                       if (err) {
+                               err = cmd_complete(sk, hdev->id,
+                                                  MGMT_OP_REMOVE_DEVICE,
+                                                  MGMT_STATUS_INVALID_PARAMS,
+                                                  &cp->addr, sizeof(cp->addr));
+                               goto unlock;
+                       }
+
+                       hci_update_page_scan(hdev, NULL);
+
+                       device_removed(sk, hdev, &cp->addr.bdaddr,
+                                      cp->addr.type);
+                       goto complete;
+               }
+
+               if (cp->addr.type == BDADDR_LE_PUBLIC)
+                       addr_type = ADDR_LE_DEV_PUBLIC;
+               else
+                       addr_type = ADDR_LE_DEV_RANDOM;
+
+               params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr,
+                                               addr_type);
+               if (!params) {
+                       err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_DEVICE,
+                                          MGMT_STATUS_INVALID_PARAMS,
+                                          &cp->addr, sizeof(cp->addr));
+                       goto unlock;
+               }
+
+               if (params->auto_connect == HCI_AUTO_CONN_DISABLED) {
+                       err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_DEVICE,
+                                          MGMT_STATUS_INVALID_PARAMS,
+                                          &cp->addr, sizeof(cp->addr));
+                       goto unlock;
+               }
+
+               list_del(&params->action);
+               list_del(&params->list);
+               kfree(params);
+               hci_update_background_scan(hdev);
+
+               device_removed(sk, hdev, &cp->addr.bdaddr, cp->addr.type);
+       } else {
+               struct hci_conn_params *p, *tmp;
+               struct bdaddr_list *b, *btmp;
+
+               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;
+               }
+
+               list_for_each_entry_safe(b, btmp, &hdev->whitelist, list) {
+                       device_removed(sk, hdev, &b->bdaddr, b->bdaddr_type);
+                       list_del(&b->list);
+                       kfree(b);
+               }
+
+               hci_update_page_scan(hdev, NULL);
+
+               list_for_each_entry_safe(p, tmp, &hdev->le_conn_params, list) {
+                       if (p->auto_connect == HCI_AUTO_CONN_DISABLED)
+                               continue;
+                       device_removed(sk, hdev, &p->addr, p->addr_type);
+                       list_del(&p->action);
+                       list_del(&p->list);
+                       kfree(p);
+               }
+
+               BT_DBG("All LE connection parameters were removed");
+
+               hci_update_background_scan(hdev);
+       }
+
+complete:
+       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 int load_conn_param(struct sock *sk, struct hci_dev *hdev, void *data,
+                          u16 len)
+{
+       struct mgmt_cp_load_conn_param *cp = data;
+       const u16 max_param_count = ((U16_MAX - sizeof(*cp)) /
+                                    sizeof(struct mgmt_conn_param));
+       u16 param_count, expected_len;
+       int i;
+
+       if (!lmp_le_capable(hdev))
+               return cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
+                                 MGMT_STATUS_NOT_SUPPORTED);
+
+       param_count = __le16_to_cpu(cp->param_count);
+       if (param_count > max_param_count) {
+               BT_ERR("load_conn_param: too big param_count value %u",
+                      param_count);
+               return cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
+                                 MGMT_STATUS_INVALID_PARAMS);
+       }
+
+       expected_len = sizeof(*cp) + param_count *
+                                       sizeof(struct mgmt_conn_param);
+       if (expected_len != len) {
+               BT_ERR("load_conn_param: expected %u bytes, got %u bytes",
+                      expected_len, len);
+               return cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
+                                 MGMT_STATUS_INVALID_PARAMS);
+       }
+
+       BT_DBG("%s param_count %u", hdev->name, param_count);
+
+       hci_dev_lock(hdev);
+
+       hci_conn_params_clear_disabled(hdev);
+
+       for (i = 0; i < param_count; i++) {
+               struct mgmt_conn_param *param = &cp->params[i];
+               struct hci_conn_params *hci_param;
+               u16 min, max, latency, timeout;
+               u8 addr_type;
+
+               BT_DBG("Adding %pMR (type %u)", &param->addr.bdaddr,
+                      param->addr.type);
+
+               if (param->addr.type == BDADDR_LE_PUBLIC) {
+                       addr_type = ADDR_LE_DEV_PUBLIC;
+               } else if (param->addr.type == BDADDR_LE_RANDOM) {
+                       addr_type = ADDR_LE_DEV_RANDOM;
+               } else {
+                       BT_ERR("Ignoring invalid connection parameters");
+                       continue;
+               }
+
+               min = le16_to_cpu(param->min_interval);
+               max = le16_to_cpu(param->max_interval);
+               latency = le16_to_cpu(param->latency);
+               timeout = le16_to_cpu(param->timeout);
+
+               BT_DBG("min 0x%04x max 0x%04x latency 0x%04x timeout 0x%04x",
+                      min, max, latency, timeout);
+
+               if (hci_check_conn_params(min, max, latency, timeout) < 0) {
+                       BT_ERR("Ignoring invalid connection parameters");
+                       continue;
+               }
+
+               hci_param = hci_conn_params_add(hdev, &param->addr.bdaddr,
+                                               addr_type);
+               if (!hci_param) {
+                       BT_ERR("Failed to add connection parameters");
+                       continue;
+               }
+
+               hci_param->conn_min_interval = min;
+               hci_param->conn_max_interval = max;
+               hci_param->conn_latency = latency;
+               hci_param->supervision_timeout = timeout;
+       }
+
+       hci_dev_unlock(hdev);
+
+       return cmd_complete(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM, 0, NULL, 0);
+}
+
+static int set_external_config(struct sock *sk, struct hci_dev *hdev,
+                              void *data, u16 len)
+{
+       struct mgmt_cp_set_external_config *cp = data;
+       bool changed;
+       int err;
+
+       BT_DBG("%s", hdev->name);
+
+       if (hdev_is_powered(hdev))
+               return cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
+                                 MGMT_STATUS_REJECTED);
+
+       if (cp->config != 0x00 && cp->config != 0x01)
+               return cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
+                                   MGMT_STATUS_INVALID_PARAMS);
+
+       if (!test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks))
+               return cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
+                                 MGMT_STATUS_NOT_SUPPORTED);
+
+       hci_dev_lock(hdev);
+
+       if (cp->config)
+               changed = !test_and_set_bit(HCI_EXT_CONFIGURED,
+                                           &hdev->dev_flags);
+       else
+               changed = test_and_clear_bit(HCI_EXT_CONFIGURED,
+                                            &hdev->dev_flags);
+
+       err = send_options_rsp(sk, MGMT_OP_SET_EXTERNAL_CONFIG, hdev);
+       if (err < 0)
+               goto unlock;
+
+       if (!changed)
+               goto unlock;
+
+       err = new_options(hdev, sk);
+
+       if (test_bit(HCI_UNCONFIGURED, &hdev->dev_flags) == is_configured(hdev)) {
+               mgmt_index_removed(hdev);
+
+               if (test_and_change_bit(HCI_UNCONFIGURED, &hdev->dev_flags)) {
+                       set_bit(HCI_CONFIG, &hdev->dev_flags);
+                       set_bit(HCI_AUTO_OFF, &hdev->dev_flags);
+
+                       queue_work(hdev->req_workqueue, &hdev->power_on);
+               } else {
+                       set_bit(HCI_RAW, &hdev->flags);
+                       mgmt_index_added(hdev);
+               }
+       }
+
+unlock:
+       hci_dev_unlock(hdev);
+       return err;
+}
+
+static int set_public_address(struct sock *sk, struct hci_dev *hdev,
+                             void *data, u16 len)
+{
+       struct mgmt_cp_set_public_address *cp = data;
+       bool changed;
+       int err;
+
+       BT_DBG("%s", hdev->name);
+
+       if (hdev_is_powered(hdev))
+               return cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
+                                 MGMT_STATUS_REJECTED);
+
+       if (!bacmp(&cp->bdaddr, BDADDR_ANY))
+               return cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
+                                 MGMT_STATUS_INVALID_PARAMS);
+
+       if (!hdev->set_bdaddr)
+               return cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
+                                 MGMT_STATUS_NOT_SUPPORTED);
+
+       hci_dev_lock(hdev);
+
+       changed = !!bacmp(&hdev->public_addr, &cp->bdaddr);
+       bacpy(&hdev->public_addr, &cp->bdaddr);
+
+       err = send_options_rsp(sk, MGMT_OP_SET_PUBLIC_ADDRESS, hdev);
+       if (err < 0)
+               goto unlock;
+
+       if (!changed)
+               goto unlock;
+
+       if (test_bit(HCI_UNCONFIGURED, &hdev->dev_flags))
+               err = new_options(hdev, sk);
+
+       if (is_configured(hdev)) {
+               mgmt_index_removed(hdev);
+
+               clear_bit(HCI_UNCONFIGURED, &hdev->dev_flags);
+
+               set_bit(HCI_CONFIG, &hdev->dev_flags);
+               set_bit(HCI_AUTO_OFF, &hdev->dev_flags);
+
+               queue_work(hdev->req_workqueue, &hdev->power_on);
+       }
+
+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);
@@ -4805,7 +5635,7 @@ static const struct mgmt_handler {
        { set_discoverable,       false, MGMT_SET_DISCOVERABLE_SIZE },
        { set_connectable,        false, MGMT_SETTING_SIZE },
        { set_fast_connectable,   false, MGMT_SETTING_SIZE },
-       { set_pairable,           false, MGMT_SETTING_SIZE },
+       { set_bondable,           false, MGMT_SETTING_SIZE },
        { set_link_security,      false, MGMT_SETTING_SIZE },
        { set_ssp,                false, MGMT_SETTING_SIZE },
        { set_hs,                 false, MGMT_SETTING_SIZE },
@@ -4846,9 +5676,16 @@ static const struct mgmt_handler {
        { 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 },
+       { load_conn_param,        true,  MGMT_LOAD_CONN_PARAM_SIZE },
+       { read_unconf_index_list, false, MGMT_READ_UNCONF_INDEX_LIST_SIZE },
+       { read_config_info,       false, MGMT_READ_CONFIG_INFO_SIZE },
+       { set_external_config,    false, MGMT_SET_EXTERNAL_CONFIG_SIZE },
+       { set_public_address,     false, MGMT_SET_PUBLIC_ADDRESS_SIZE },
 };
 
-
 int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
 {
        void *buf;
@@ -4892,11 +5729,21 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
                }
 
                if (test_bit(HCI_SETUP, &hdev->dev_flags) ||
+                   test_bit(HCI_CONFIG, &hdev->dev_flags) ||
                    test_bit(HCI_USER_CHANNEL, &hdev->dev_flags)) {
                        err = cmd_status(sk, index, opcode,
                                         MGMT_STATUS_INVALID_INDEX);
                        goto done;
                }
+
+               if (test_bit(HCI_UNCONFIGURED, &hdev->dev_flags) &&
+                   opcode != MGMT_OP_READ_CONFIG_INFO &&
+                   opcode != MGMT_OP_SET_EXTERNAL_CONFIG &&
+                   opcode != MGMT_OP_SET_PUBLIC_ADDRESS) {
+                       err = cmd_status(sk, index, opcode,
+                                        MGMT_STATUS_INVALID_INDEX);
+                       goto done;
+               }
        }
 
        if (opcode >= ARRAY_SIZE(mgmt_handlers) ||
@@ -4907,8 +5754,15 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
                goto done;
        }
 
-       if ((hdev && opcode < MGMT_OP_READ_INFO) ||
-           (!hdev && opcode >= MGMT_OP_READ_INFO)) {
+       if (hdev && (opcode <= MGMT_OP_READ_INDEX_LIST ||
+                    opcode == MGMT_OP_READ_UNCONF_INDEX_LIST)) {
+               err = cmd_status(sk, index, opcode,
+                                MGMT_STATUS_INVALID_INDEX);
+               goto done;
+       }
+
+       if (!hdev && (opcode > MGMT_OP_READ_INDEX_LIST &&
+                     opcode != MGMT_OP_READ_UNCONF_INDEX_LIST)) {
                err = cmd_status(sk, index, opcode,
                                 MGMT_STATUS_INVALID_INDEX);
                goto done;
@@ -4947,7 +5801,13 @@ void mgmt_index_added(struct hci_dev *hdev)
        if (hdev->dev_type != HCI_BREDR)
                return;
 
-       mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
+       if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
+               return;
+
+       if (test_bit(HCI_UNCONFIGURED, &hdev->dev_flags))
+               mgmt_event(MGMT_EV_UNCONF_INDEX_ADDED, hdev, NULL, 0, NULL);
+       else
+               mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
 }
 
 void mgmt_index_removed(struct hci_dev *hdev)
@@ -4957,20 +5817,42 @@ void mgmt_index_removed(struct hci_dev *hdev)
        if (hdev->dev_type != HCI_BREDR)
                return;
 
+       if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
+               return;
+
        mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
 
-       mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
+       if (test_bit(HCI_UNCONFIGURED, &hdev->dev_flags))
+               mgmt_event(MGMT_EV_UNCONF_INDEX_REMOVED, hdev, NULL, 0, NULL);
+       else
+               mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
 }
 
 /* This function requires the caller holds hdev->lock */
-static void restart_le_auto_conns(struct hci_dev *hdev)
+static void restart_le_actions(struct hci_dev *hdev)
 {
        struct hci_conn_params *p;
 
        list_for_each_entry(p, &hdev->le_conn_params, list) {
-               if (p->auto_connect == HCI_AUTO_CONN_ALWAYS)
-                       hci_pend_le_conn_add(hdev, &p->addr, p->addr_type);
+               /* Needed for AUTO_OFF case where might not "really"
+                * have been powered off.
+                */
+               list_del_init(&p->action);
+
+               switch (p->auto_connect) {
+               case HCI_AUTO_CONN_DIRECT:
+               case HCI_AUTO_CONN_ALWAYS:
+                       list_add(&p->action, &hdev->pend_le_conns);
+                       break;
+               case HCI_AUTO_CONN_REPORT:
+                       list_add(&p->action, &hdev->pend_le_reports);
+                       break;
+               default:
+                       break;
+               }
        }
+
+       hci_update_background_scan(hdev);
 }
 
 static void powered_complete(struct hci_dev *hdev, u8 status)
@@ -4981,7 +5863,7 @@ static void powered_complete(struct hci_dev *hdev, u8 status)
 
        hci_dev_lock(hdev);
 
-       restart_le_auto_conns(hdev);
+       restart_le_actions(hdev);
 
        mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
 
@@ -5011,8 +5893,8 @@ static int powered_update_hci(struct hci_dev *hdev)
            lmp_bredr_capable(hdev)) {
                struct hci_cp_write_le_host_supported cp;
 
-               cp.le = 1;
-               cp.simul = lmp_le_br_capable(hdev);
+               cp.le = 0x01;
+               cp.simul = 0x00;
 
                /* Check first if we already have the right
                 * host state (host features set)
@@ -5043,8 +5925,8 @@ static int powered_update_hci(struct hci_dev *hdev)
                            sizeof(link_sec), &link_sec);
 
        if (lmp_bredr_capable(hdev)) {
-               if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
-                       set_bredr_scan(&req);
+               write_fast_connectable(&req, false);
+               hci_update_page_scan(hdev, &req);
                update_class(&req);
                update_name(&req);
                update_eir(&req);
@@ -5138,92 +6020,6 @@ void mgmt_discoverable_timeout(struct hci_dev *hdev)
        hci_dev_unlock(hdev);
 }
 
-void mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
-{
-       bool changed;
-
-       /* Nothing needed here if there's a pending command since that
-        * commands request completion callback takes care of everything
-        * necessary.
-        */
-       if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev))
-               return;
-
-       /* Powering off may clear the scan mode - don't let that interfere */
-       if (!discoverable && mgmt_pending_find(MGMT_OP_SET_POWERED, hdev))
-               return;
-
-       if (discoverable) {
-               changed = !test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
-       } else {
-               clear_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
-               changed = test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
-       }
-
-       if (changed) {
-               struct hci_request req;
-
-               /* In case this change in discoverable was triggered by
-                * a disabling of connectable there could be a need to
-                * update the advertising flags.
-                */
-               hci_req_init(&req, hdev);
-               update_adv_data(&req);
-               hci_req_run(&req, NULL);
-
-               new_settings(hdev, NULL);
-       }
-}
-
-void mgmt_connectable(struct hci_dev *hdev, u8 connectable)
-{
-       bool changed;
-
-       /* Nothing needed here if there's a pending command since that
-        * commands request completion callback takes care of everything
-        * necessary.
-        */
-       if (mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev))
-               return;
-
-       /* Powering off may clear the scan mode - don't let that interfere */
-       if (!connectable && mgmt_pending_find(MGMT_OP_SET_POWERED, hdev))
-               return;
-
-       if (connectable)
-               changed = !test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
-       else
-               changed = test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
-
-       if (changed)
-               new_settings(hdev, NULL);
-}
-
-void mgmt_advertising(struct hci_dev *hdev, u8 advertising)
-{
-       /* Powering off may stop advertising - don't let that interfere */
-       if (!advertising && mgmt_pending_find(MGMT_OP_SET_POWERED, hdev))
-               return;
-
-       if (advertising)
-               set_bit(HCI_ADVERTISING, &hdev->dev_flags);
-       else
-               clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
-}
-
-void mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
-{
-       u8 mgmt_err = mgmt_status(status);
-
-       if (scan & SCAN_PAGE)
-               mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
-                                    cmd_status_rsp, &mgmt_err);
-
-       if (scan & SCAN_INQUIRY)
-               mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
-                                    cmd_status_rsp, &mgmt_err);
-}
-
 void mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
                       bool persistent)
 {
@@ -5279,7 +6075,7 @@ void mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, bool persistent)
        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));
@@ -5347,6 +6143,27 @@ void mgmt_new_csrk(struct hci_dev *hdev, struct smp_csrk *csrk,
        mgmt_event(MGMT_EV_NEW_CSRK, hdev, &ev, sizeof(ev), NULL);
 }
 
+void mgmt_new_conn_param(struct hci_dev *hdev, bdaddr_t *bdaddr,
+                        u8 bdaddr_type, u8 store_hint, u16 min_interval,
+                        u16 max_interval, u16 latency, u16 timeout)
+{
+       struct mgmt_ev_new_conn_param ev;
+
+       if (!hci_is_identity_address(bdaddr, bdaddr_type))
+               return;
+
+       memset(&ev, 0, sizeof(ev));
+       bacpy(&ev.addr.bdaddr, bdaddr);
+       ev.addr.type = link_to_bdaddr(LE_LINK, bdaddr_type);
+       ev.store_hint = store_hint;
+       ev.min_interval = cpu_to_le16(min_interval);
+       ev.max_interval = cpu_to_le16(max_interval);
+       ev.latency = cpu_to_le16(latency);
+       ev.timeout = cpu_to_le16(timeout);
+
+       mgmt_event(MGMT_EV_NEW_CONN_PARAM, hdev, &ev, sizeof(ev), NULL);
+}
+
 static inline u16 eir_append_data(u8 *eir, u16 eir_len, u8 type, u8 *data,
                                  u8 data_len)
 {
@@ -5420,25 +6237,35 @@ static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
        mgmt_pending_remove(cmd);
 }
 
+bool mgmt_powering_down(struct hci_dev *hdev)
+{
+       struct pending_cmd *cmd;
+       struct mgmt_mode *cp;
+
+       cmd = mgmt_pending_find(MGMT_OP_SET_POWERED, hdev);
+       if (!cmd)
+               return false;
+
+       cp = cmd->param;
+       if (!cp->val)
+               return true;
+
+       return false;
+}
+
 void mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
                              u8 link_type, u8 addr_type, u8 reason,
                              bool mgmt_connected)
 {
        struct mgmt_ev_device_disconnected ev;
-       struct pending_cmd *power_off;
        struct sock *sk = NULL;
 
-       power_off = mgmt_pending_find(MGMT_OP_SET_POWERED, hdev);
-       if (power_off) {
-               struct mgmt_mode *cp = power_off->param;
-
-               /* The connection is still in hci_conn_hash so test for 1
-                * instead of 0 to know if this is the last one.
-                */
-               if (!cp->val && hci_conn_count(hdev) == 1) {
-                       cancel_delayed_work(&hdev->power_off);
-                       queue_work(hdev->req_workqueue, &hdev->power_off.work);
-               }
+       /* The connection is still in hci_conn_hash so test for 1
+        * instead of 0 to know if this is the last one.
+        */
+       if (mgmt_powering_down(hdev) && hci_conn_count(hdev) == 1) {
+               cancel_delayed_work(&hdev->power_off);
+               queue_work(hdev->req_workqueue, &hdev->power_off.work);
        }
 
        if (!mgmt_connected)
@@ -5498,19 +6325,13 @@ void mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
                         u8 addr_type, u8 status)
 {
        struct mgmt_ev_connect_failed ev;
-       struct pending_cmd *power_off;
-
-       power_off = mgmt_pending_find(MGMT_OP_SET_POWERED, hdev);
-       if (power_off) {
-               struct mgmt_mode *cp = power_off->param;
 
-               /* The connection is still in hci_conn_hash so test for 1
-                * instead of 0 to know if this is the last one.
-                */
-               if (!cp->val && hci_conn_count(hdev) == 1) {
-                       cancel_delayed_work(&hdev->power_off);
-                       queue_work(hdev->req_workqueue, &hdev->power_off.work);
-               }
+       /* The connection is still in hci_conn_hash so test for 1
+        * instead of 0 to know if this is the last one.
+        */
+       if (mgmt_powering_down(hdev) && hci_conn_count(hdev) == 1) {
+               cancel_delayed_work(&hdev->power_off);
+               queue_work(hdev->req_workqueue, &hdev->power_off.work);
        }
 
        bacpy(&ev.addr.bdaddr, bdaddr);
@@ -5765,10 +6586,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);
 }
@@ -5912,17 +6737,23 @@ 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;
-       struct smp_irk *irk;
        size_t ev_size;
 
-       if (!hci_discovery_active(hdev))
-               return;
+       /* Don't send events for a non-kernel initiated discovery. With
+        * LE one exception is if we have pend_le_reports > 0 in which
+        * case we're doing passive scanning and want these events.
+        */
+       if (!hci_discovery_active(hdev)) {
+               if (link_type == ACL_LINK)
+                       return;
+               if (link_type == LE_LINK && list_empty(&hdev->pend_le_reports))
+                       return;
+       }
 
        /* Make sure that the buffer is big enough. The 5 extra bytes
         * are for the potential CoD field.
@@ -5932,20 +6763,10 @@ void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
 
        memset(buf, 0, sizeof(buf));
 
-       irk = hci_get_irk(hdev, bdaddr, addr_type);
-       if (irk) {
-               bacpy(&ev->addr.bdaddr, &irk->bdaddr);
-               ev->addr.type = link_to_bdaddr(link_type, irk->addr_type);
-       } else {
-               bacpy(&ev->addr.bdaddr, bdaddr);
-               ev->addr.type = link_to_bdaddr(link_type, addr_type);
-       }
-
+       bacpy(&ev->addr.bdaddr, bdaddr);
+       ev->addr.type = link_to_bdaddr(link_type, addr_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);
@@ -6013,63 +6834,19 @@ 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);
-
-       /* Clear the advertising mgmt setting if we failed to re-enable it */
-       if (status) {
-               clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
-               new_settings(hdev, NULL);
-       }
 }
 
 void mgmt_reenable_advertising(struct hci_dev *hdev)
 {
        struct hci_request req;
 
-       if (hci_conn_num(hdev, LE_LINK) > 0)
-               return;
-
        if (!test_bit(HCI_ADVERTISING, &hdev->dev_flags))
                return;
 
        hci_req_init(&req, hdev);
        enable_advertising(&req);
-
-       /* If this fails we have no option but to let user space know
-        * that we've disabled advertising.
-        */
-       if (hci_req_run(&req, adv_enable_complete) < 0) {
-               clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
-               new_settings(hdev, NULL);
-       }
+       hci_req_run(&req, adv_enable_complete);
 }