Merge tag 'for-net-next-2021-11-16' of git://git.kernel.org/pub/scm/linux/kernel...
authorDavid S. Miller <davem@davemloft.net>
Wed, 17 Nov 2021 14:52:44 +0000 (14:52 +0000)
committerDavid S. Miller <davem@davemloft.net>
Wed, 17 Nov 2021 14:52:44 +0000 (14:52 +0000)
Luiz Augusto von Dentz says:

====================
bluetooth-next pull request for net-next:

 - Add support for AOSP Bluetooth Quality Report
 - Enables AOSP extension for Mediatek Chip (MT7921 & MT7922)
 - Rework of HCI command execution serialization
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
38 files changed:
drivers/bluetooth/Kconfig
drivers/bluetooth/Makefile
drivers/bluetooth/bfusb.c
drivers/bluetooth/btintel.c
drivers/bluetooth/btmrvl_main.c
drivers/bluetooth/btmtk.c [new file with mode: 0644]
drivers/bluetooth/btmtk.h [new file with mode: 0644]
drivers/bluetooth/btmtksdio.c
drivers/bluetooth/btsdio.c
drivers/bluetooth/btusb.c
drivers/bluetooth/hci_bcm.c
drivers/bluetooth/hci_h4.c
drivers/bluetooth/hci_vhci.c
drivers/bluetooth/virtio_bt.c
include/linux/mmc/sdio_ids.h
include/net/bluetooth/bluetooth.h
include/net/bluetooth/hci.h
include/net/bluetooth/hci_core.h
include/net/bluetooth/hci_sync.h [new file with mode: 0644]
net/bluetooth/Makefile
net/bluetooth/aosp.c
net/bluetooth/aosp.h
net/bluetooth/cmtp/core.c
net/bluetooth/hci_codec.c
net/bluetooth/hci_conn.c
net/bluetooth/hci_core.c
net/bluetooth/hci_event.c
net/bluetooth/hci_request.c
net/bluetooth/hci_request.h
net/bluetooth/hci_sock.c
net/bluetooth/hci_sync.c [new file with mode: 0644]
net/bluetooth/hci_sysfs.c
net/bluetooth/l2cap_sock.c
net/bluetooth/mgmt.c
net/bluetooth/mgmt_util.c
net/bluetooth/mgmt_util.h
net/bluetooth/msft.c
net/bluetooth/msft.h

index 8518423..36380e6 100644 (file)
@@ -19,6 +19,10 @@ config BT_QCA
        tristate
        select FW_LOADER
 
+config BT_MTK
+       tristate
+       select FW_LOADER
+
 config BT_HCIBTUSB
        tristate "HCI USB driver"
        depends on USB
@@ -55,6 +59,7 @@ config BT_HCIBTUSB_BCM
 config BT_HCIBTUSB_MTK
        bool "MediaTek protocol support"
        depends on BT_HCIBTUSB
+       select BT_MTK
        default n
        help
          The MediaTek protocol support enables firmware download
@@ -383,6 +388,7 @@ config BT_ATH3K
 config BT_MTKSDIO
        tristate "MediaTek HCI SDIO driver"
        depends on MMC
+       select BT_MTK
        help
          MediaTek Bluetooth HCI SDIO driver.
          This driver is required if you want to use MediaTek Bluetooth
index 16286ea..3321a8a 100644 (file)
@@ -25,6 +25,7 @@ obj-$(CONFIG_BT_QCOMSMD)      += btqcomsmd.o
 obj-$(CONFIG_BT_BCM)           += btbcm.o
 obj-$(CONFIG_BT_RTL)           += btrtl.o
 obj-$(CONFIG_BT_QCA)           += btqca.o
+obj-$(CONFIG_BT_MTK)           += btmtk.o
 
 obj-$(CONFIG_BT_VIRTIO)                += virtio_bt.o
 
index 5a321b4..cab9393 100644 (file)
@@ -628,6 +628,9 @@ static int bfusb_probe(struct usb_interface *intf, const struct usb_device_id *i
        data->bulk_out_ep   = bulk_out_ep->desc.bEndpointAddress;
        data->bulk_pkt_size = le16_to_cpu(bulk_out_ep->desc.wMaxPacketSize);
 
+       if (!data->bulk_pkt_size)
+               goto done;
+
        rwlock_init(&data->lock);
 
        data->reassembly = NULL;
index 9359bff..8f9109b 100644 (file)
@@ -2081,14 +2081,16 @@ static int btintel_prepare_fw_download_tlv(struct hci_dev *hdev,
        if (ver->img_type == 0x03) {
                btintel_clear_flag(hdev, INTEL_BOOTLOADER);
                btintel_check_bdaddr(hdev);
-       }
-
-       /* If the OTP has no valid Bluetooth device address, then there will
-        * also be no valid address for the operational firmware.
-        */
-       if (!bacmp(&ver->otp_bd_addr, BDADDR_ANY)) {
-               bt_dev_info(hdev, "No device address configured");
-               set_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks);
+       } else {
+               /*
+                * Check for valid bd address in boot loader mode. Device
+                * will be marked as unconfigured if empty bd address is
+                * found.
+                */
+               if (!bacmp(&ver->otp_bd_addr, BDADDR_ANY)) {
+                       bt_dev_info(hdev, "No device address configured");
+                       set_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks);
+               }
        }
 
        btintel_get_fw_name_tlv(ver, fwname, sizeof(fwname), "sfi");
@@ -2466,6 +2468,10 @@ static int btintel_setup_combined(struct hci_dev *hdev)
                goto exit_error;
        }
 
+       /* memset ver_tlv to start with clean state as few fields are exclusive
+        * to bootloader mode and are not populated in operational mode
+        */
+       memset(&ver_tlv, 0, sizeof(ver_tlv));
        /* For TLV type device, parse the tlv data */
        err = btintel_parse_version_tlv(hdev, &ver_tlv, skb);
        if (err) {
index 5ccbe4d..181338f 100644 (file)
@@ -1,4 +1,4 @@
-/**
+/*
  * Marvell Bluetooth driver
  *
  * Copyright (C) 2009, Marvell International Ltd.
diff --git a/drivers/bluetooth/btmtk.c b/drivers/bluetooth/btmtk.c
new file mode 100644 (file)
index 0000000..c2ee5c4
--- /dev/null
@@ -0,0 +1,289 @@
+// SPDX-License-Identifier: ISC
+/* Copyright (C) 2021 MediaTek Inc.
+ *
+ */
+#include <linux/module.h>
+#include <linux/firmware.h>
+
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci_core.h>
+
+#include "btmtk.h"
+
+#define VERSION "0.1"
+
+/* It is for mt79xx download rom patch*/
+#define MTK_FW_ROM_PATCH_HEADER_SIZE   32
+#define MTK_FW_ROM_PATCH_GD_SIZE       64
+#define MTK_FW_ROM_PATCH_SEC_MAP_SIZE  64
+#define MTK_SEC_MAP_COMMON_SIZE        12
+#define MTK_SEC_MAP_NEED_SEND_SIZE     52
+
+struct btmtk_patch_header {
+       u8 datetime[16];
+       u8 platform[4];
+       __le16 hwver;
+       __le16 swver;
+       __le32 magicnum;
+} __packed;
+
+struct btmtk_global_desc {
+       __le32 patch_ver;
+       __le32 sub_sys;
+       __le32 feature_opt;
+       __le32 section_num;
+} __packed;
+
+struct btmtk_section_map {
+       __le32 sectype;
+       __le32 secoffset;
+       __le32 secsize;
+       union {
+               __le32 u4SecSpec[13];
+               struct {
+                       __le32 dlAddr;
+                       __le32 dlsize;
+                       __le32 seckeyidx;
+                       __le32 alignlen;
+                       __le32 sectype;
+                       __le32 dlmodecrctype;
+                       __le32 crc;
+                       __le32 reserved[6];
+               } bin_info_spec;
+       };
+} __packed;
+
+int btmtk_setup_firmware_79xx(struct hci_dev *hdev, const char *fwname,
+                             wmt_cmd_sync_func_t wmt_cmd_sync)
+{
+       struct btmtk_hci_wmt_params wmt_params;
+       struct btmtk_global_desc *globaldesc = NULL;
+       struct btmtk_section_map *sectionmap;
+       const struct firmware *fw;
+       const u8 *fw_ptr;
+       const u8 *fw_bin_ptr;
+       int err, dlen, i, status;
+       u8 flag, first_block, retry;
+       u32 section_num, dl_size, section_offset;
+       u8 cmd[64];
+
+       err = request_firmware(&fw, fwname, &hdev->dev);
+       if (err < 0) {
+               bt_dev_err(hdev, "Failed to load firmware file (%d)", err);
+               return err;
+       }
+
+       fw_ptr = fw->data;
+       fw_bin_ptr = fw_ptr;
+       globaldesc = (struct btmtk_global_desc *)(fw_ptr + MTK_FW_ROM_PATCH_HEADER_SIZE);
+       section_num = le32_to_cpu(globaldesc->section_num);
+
+       for (i = 0; i < section_num; i++) {
+               first_block = 1;
+               fw_ptr = fw_bin_ptr;
+               sectionmap = (struct btmtk_section_map *)(fw_ptr + MTK_FW_ROM_PATCH_HEADER_SIZE +
+                             MTK_FW_ROM_PATCH_GD_SIZE + MTK_FW_ROM_PATCH_SEC_MAP_SIZE * i);
+
+               section_offset = le32_to_cpu(sectionmap->secoffset);
+               dl_size = le32_to_cpu(sectionmap->bin_info_spec.dlsize);
+
+               if (dl_size > 0) {
+                       retry = 20;
+                       while (retry > 0) {
+                               cmd[0] = 0; /* 0 means legacy dl mode. */
+                               memcpy(cmd + 1,
+                                      fw_ptr + MTK_FW_ROM_PATCH_HEADER_SIZE +
+                                      MTK_FW_ROM_PATCH_GD_SIZE +
+                                      MTK_FW_ROM_PATCH_SEC_MAP_SIZE * i +
+                                      MTK_SEC_MAP_COMMON_SIZE,
+                                      MTK_SEC_MAP_NEED_SEND_SIZE + 1);
+
+                               wmt_params.op = BTMTK_WMT_PATCH_DWNLD;
+                               wmt_params.status = &status;
+                               wmt_params.flag = 0;
+                               wmt_params.dlen = MTK_SEC_MAP_NEED_SEND_SIZE + 1;
+                               wmt_params.data = &cmd;
+
+                               err = wmt_cmd_sync(hdev, &wmt_params);
+                               if (err < 0) {
+                                       bt_dev_err(hdev, "Failed to send wmt patch dwnld (%d)",
+                                                  err);
+                                       goto err_release_fw;
+                               }
+
+                               if (status == BTMTK_WMT_PATCH_UNDONE) {
+                                       break;
+                               } else if (status == BTMTK_WMT_PATCH_PROGRESS) {
+                                       msleep(100);
+                                       retry--;
+                               } else if (status == BTMTK_WMT_PATCH_DONE) {
+                                       goto next_section;
+                               } else {
+                                       bt_dev_err(hdev, "Failed wmt patch dwnld status (%d)",
+                                                  status);
+                                       goto err_release_fw;
+                               }
+                       }
+
+                       fw_ptr += section_offset;
+                       wmt_params.op = BTMTK_WMT_PATCH_DWNLD;
+                       wmt_params.status = NULL;
+
+                       while (dl_size > 0) {
+                               dlen = min_t(int, 250, dl_size);
+                               if (first_block == 1) {
+                                       flag = 1;
+                                       first_block = 0;
+                               } else if (dl_size - dlen <= 0) {
+                                       flag = 3;
+                               } else {
+                                       flag = 2;
+                               }
+
+                               wmt_params.flag = flag;
+                               wmt_params.dlen = dlen;
+                               wmt_params.data = fw_ptr;
+
+                               err = wmt_cmd_sync(hdev, &wmt_params);
+                               if (err < 0) {
+                                       bt_dev_err(hdev, "Failed to send wmt patch dwnld (%d)",
+                                                  err);
+                                       goto err_release_fw;
+                               }
+
+                               dl_size -= dlen;
+                               fw_ptr += dlen;
+                       }
+               }
+next_section:
+               continue;
+       }
+       /* Wait a few moments for firmware activation done */
+       usleep_range(100000, 120000);
+
+err_release_fw:
+       release_firmware(fw);
+
+       return err;
+}
+EXPORT_SYMBOL_GPL(btmtk_setup_firmware_79xx);
+
+int btmtk_setup_firmware(struct hci_dev *hdev, const char *fwname,
+                        wmt_cmd_sync_func_t wmt_cmd_sync)
+{
+       struct btmtk_hci_wmt_params wmt_params;
+       const struct firmware *fw;
+       const u8 *fw_ptr;
+       size_t fw_size;
+       int err, dlen;
+       u8 flag, param;
+
+       err = request_firmware(&fw, fwname, &hdev->dev);
+       if (err < 0) {
+               bt_dev_err(hdev, "Failed to load firmware file (%d)", err);
+               return err;
+       }
+
+       /* Power on data RAM the firmware relies on. */
+       param = 1;
+       wmt_params.op = BTMTK_WMT_FUNC_CTRL;
+       wmt_params.flag = 3;
+       wmt_params.dlen = sizeof(param);
+       wmt_params.data = &param;
+       wmt_params.status = NULL;
+
+       err = wmt_cmd_sync(hdev, &wmt_params);
+       if (err < 0) {
+               bt_dev_err(hdev, "Failed to power on data RAM (%d)", err);
+               goto err_release_fw;
+       }
+
+       fw_ptr = fw->data;
+       fw_size = fw->size;
+
+       /* The size of patch header is 30 bytes, should be skip */
+       if (fw_size < 30) {
+               err = -EINVAL;
+               goto err_release_fw;
+       }
+
+       fw_size -= 30;
+       fw_ptr += 30;
+       flag = 1;
+
+       wmt_params.op = BTMTK_WMT_PATCH_DWNLD;
+       wmt_params.status = NULL;
+
+       while (fw_size > 0) {
+               dlen = min_t(int, 250, fw_size);
+
+               /* Tell device the position in sequence */
+               if (fw_size - dlen <= 0)
+                       flag = 3;
+               else if (fw_size < fw->size - 30)
+                       flag = 2;
+
+               wmt_params.flag = flag;
+               wmt_params.dlen = dlen;
+               wmt_params.data = fw_ptr;
+
+               err = wmt_cmd_sync(hdev, &wmt_params);
+               if (err < 0) {
+                       bt_dev_err(hdev, "Failed to send wmt patch dwnld (%d)",
+                                  err);
+                       goto err_release_fw;
+               }
+
+               fw_size -= dlen;
+               fw_ptr += dlen;
+       }
+
+       wmt_params.op = BTMTK_WMT_RST;
+       wmt_params.flag = 4;
+       wmt_params.dlen = 0;
+       wmt_params.data = NULL;
+       wmt_params.status = NULL;
+
+       /* Activate funciton the firmware providing to */
+       err = wmt_cmd_sync(hdev, &wmt_params);
+       if (err < 0) {
+               bt_dev_err(hdev, "Failed to send wmt rst (%d)", err);
+               goto err_release_fw;
+       }
+
+       /* Wait a few moments for firmware activation done */
+       usleep_range(10000, 12000);
+
+err_release_fw:
+       release_firmware(fw);
+
+       return err;
+}
+EXPORT_SYMBOL_GPL(btmtk_setup_firmware);
+
+int btmtk_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr)
+{
+       struct sk_buff *skb;
+       long ret;
+
+       skb = __hci_cmd_sync(hdev, 0xfc1a, 6, bdaddr, HCI_INIT_TIMEOUT);
+       if (IS_ERR(skb)) {
+               ret = PTR_ERR(skb);
+               bt_dev_err(hdev, "changing Mediatek device address failed (%ld)",
+                          ret);
+               return ret;
+       }
+       kfree_skb(skb);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(btmtk_set_bdaddr);
+
+MODULE_AUTHOR("Sean Wang <sean.wang@mediatek.com>");
+MODULE_AUTHOR("Mark Chen <mark-yw.chen@mediatek.com>");
+MODULE_DESCRIPTION("Bluetooth support for MediaTek devices ver " VERSION);
+MODULE_VERSION(VERSION);
+MODULE_LICENSE("GPL");
+MODULE_FIRMWARE(FIRMWARE_MT7663);
+MODULE_FIRMWARE(FIRMWARE_MT7668);
+MODULE_FIRMWARE(FIRMWARE_MT7961);
diff --git a/drivers/bluetooth/btmtk.h b/drivers/bluetooth/btmtk.h
new file mode 100644 (file)
index 0000000..6e7b0c7
--- /dev/null
@@ -0,0 +1,111 @@
+/* SPDX-License-Identifier: ISC */
+/* Copyright (C) 2021 MediaTek Inc. */
+
+#define FIRMWARE_MT7663                "mediatek/mt7663pr2h.bin"
+#define FIRMWARE_MT7668                "mediatek/mt7668pr2h.bin"
+#define FIRMWARE_MT7961                "mediatek/BT_RAM_CODE_MT7961_1_2_hdr.bin"
+
+#define HCI_WMT_MAX_EVENT_SIZE         64
+
+#define BTMTK_WMT_REG_READ 0x2
+
+enum {
+       BTMTK_WMT_PATCH_DWNLD = 0x1,
+       BTMTK_WMT_TEST = 0x2,
+       BTMTK_WMT_WAKEUP = 0x3,
+       BTMTK_WMT_HIF = 0x4,
+       BTMTK_WMT_FUNC_CTRL = 0x6,
+       BTMTK_WMT_RST = 0x7,
+       BTMTK_WMT_REGISTER = 0x8,
+       BTMTK_WMT_SEMAPHORE = 0x17,
+};
+
+enum {
+       BTMTK_WMT_INVALID,
+       BTMTK_WMT_PATCH_UNDONE,
+       BTMTK_WMT_PATCH_PROGRESS,
+       BTMTK_WMT_PATCH_DONE,
+       BTMTK_WMT_ON_UNDONE,
+       BTMTK_WMT_ON_DONE,
+       BTMTK_WMT_ON_PROGRESS,
+};
+
+struct btmtk_wmt_hdr {
+       u8      dir;
+       u8      op;
+       __le16  dlen;
+       u8      flag;
+} __packed;
+
+struct btmtk_hci_wmt_cmd {
+       struct btmtk_wmt_hdr hdr;
+       u8 data[];
+} __packed;
+
+struct btmtk_hci_wmt_evt {
+       struct hci_event_hdr hhdr;
+       struct btmtk_wmt_hdr whdr;
+} __packed;
+
+struct btmtk_hci_wmt_evt_funcc {
+       struct btmtk_hci_wmt_evt hwhdr;
+       __be16 status;
+} __packed;
+
+struct btmtk_hci_wmt_evt_reg {
+       struct btmtk_hci_wmt_evt hwhdr;
+       u8 rsv[2];
+       u8 num;
+       __le32 addr;
+       __le32 val;
+} __packed;
+
+struct btmtk_tci_sleep {
+       u8 mode;
+       __le16 duration;
+       __le16 host_duration;
+       u8 host_wakeup_pin;
+       u8 time_compensation;
+} __packed;
+
+struct btmtk_hci_wmt_params {
+       u8 op;
+       u8 flag;
+       u16 dlen;
+       const void *data;
+       u32 *status;
+};
+
+typedef int (*wmt_cmd_sync_func_t)(struct hci_dev *,
+                                  struct btmtk_hci_wmt_params *);
+
+#if IS_ENABLED(CONFIG_BT_MTK)
+
+int btmtk_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr);
+
+int btmtk_setup_firmware_79xx(struct hci_dev *hdev, const char *fwname,
+                             wmt_cmd_sync_func_t wmt_cmd_sync);
+
+int btmtk_setup_firmware(struct hci_dev *hdev, const char *fwname,
+                        wmt_cmd_sync_func_t wmt_cmd_sync);
+#else
+
+static inline int btmtk_set_bdaddr(struct hci_dev *hdev,
+                                  const bdaddr_t *bdaddr)
+{
+       return -EOPNOTSUPP;
+}
+
+static int btmtk_setup_firmware_79xx(struct hci_dev *hdev, const char *fwname,
+                                    wmt_cmd_sync_func_t wmt_cmd_sync)
+{
+       return -EOPNOTSUPP;
+}
+
+static int btmtk_setup_firmware(struct hci_dev *hdev, const char *fwname,
+                               wmt_cmd_sync_func_t wmt_cmd_sync)
+{
+       return -EOPNOTSUPP;
+}
+
+#endif
index 9872ef1..ce6a6c0 100644 (file)
@@ -12,7 +12,6 @@
 
 #include <asm/unaligned.h>
 #include <linux/atomic.h>
-#include <linux/firmware.h>
 #include <linux/init.h>
 #include <linux/iopoll.h>
 #include <linux/kernel.h>
 #include <net/bluetooth/hci_core.h>
 
 #include "h4_recv.h"
+#include "btmtk.h"
 
 #define VERSION "0.1"
 
-#define FIRMWARE_MT7663                "mediatek/mt7663pr2h.bin"
-#define FIRMWARE_MT7668                "mediatek/mt7668pr2h.bin"
-
 #define MTKBTSDIO_AUTOSUSPEND_DELAY    8000
 
 static bool enable_autosuspend;
 
 struct btmtksdio_data {
        const char *fwname;
+       u16 chipid;
 };
 
 static const struct btmtksdio_data mt7663_data = {
        .fwname = FIRMWARE_MT7663,
+       .chipid = 0x7663,
 };
 
 static const struct btmtksdio_data mt7668_data = {
        .fwname = FIRMWARE_MT7668,
+       .chipid = 0x7668,
+};
+
+static const struct btmtksdio_data mt7921_data = {
+       .fwname = FIRMWARE_MT7961,
+       .chipid = 0x7921,
 };
 
 static const struct sdio_device_id btmtksdio_table[] = {
@@ -55,6 +60,8 @@ static const struct sdio_device_id btmtksdio_table[] = {
         .driver_data = (kernel_ulong_t)&mt7663_data },
        {SDIO_DEVICE(SDIO_VENDOR_ID_MEDIATEK, SDIO_DEVICE_ID_MEDIATEK_MT7668),
         .driver_data = (kernel_ulong_t)&mt7668_data },
+       {SDIO_DEVICE(SDIO_VENDOR_ID_MEDIATEK, SDIO_DEVICE_ID_MEDIATEK_MT7961),
+        .driver_data = (kernel_ulong_t)&mt7921_data },
        { }     /* Terminating entry */
 };
 MODULE_DEVICE_TABLE(sdio, btmtksdio_table);
@@ -86,81 +93,27 @@ MODULE_DEVICE_TABLE(sdio, btmtksdio_table);
 
 #define MTK_REG_CRDR           0x1c
 
+#define MTK_REG_CRPLR          0x24
+
 #define MTK_SDIO_BLOCK_SIZE    256
 
 #define BTMTKSDIO_TX_WAIT_VND_EVT      1
 
-enum {
-       MTK_WMT_PATCH_DWNLD = 0x1,
-       MTK_WMT_TEST = 0x2,
-       MTK_WMT_WAKEUP = 0x3,
-       MTK_WMT_HIF = 0x4,
-       MTK_WMT_FUNC_CTRL = 0x6,
-       MTK_WMT_RST = 0x7,
-       MTK_WMT_SEMAPHORE = 0x17,
-};
-
-enum {
-       BTMTK_WMT_INVALID,
-       BTMTK_WMT_PATCH_UNDONE,
-       BTMTK_WMT_PATCH_DONE,
-       BTMTK_WMT_ON_UNDONE,
-       BTMTK_WMT_ON_DONE,
-       BTMTK_WMT_ON_PROGRESS,
-};
-
 struct mtkbtsdio_hdr {
        __le16  len;
        __le16  reserved;
        u8      bt_type;
 } __packed;
 
-struct mtk_wmt_hdr {
-       u8      dir;
-       u8      op;
-       __le16  dlen;
-       u8      flag;
-} __packed;
-
-struct mtk_hci_wmt_cmd {
-       struct mtk_wmt_hdr hdr;
-       u8 data[256];
-} __packed;
-
-struct btmtk_hci_wmt_evt {
-       struct hci_event_hdr hhdr;
-       struct mtk_wmt_hdr whdr;
-} __packed;
-
-struct btmtk_hci_wmt_evt_funcc {
-       struct btmtk_hci_wmt_evt hwhdr;
-       __be16 status;
-} __packed;
-
-struct btmtk_tci_sleep {
-       u8 mode;
-       __le16 duration;
-       __le16 host_duration;
-       u8 host_wakeup_pin;
-       u8 time_compensation;
-} __packed;
-
-struct btmtk_hci_wmt_params {
-       u8 op;
-       u8 flag;
-       u16 dlen;
-       const void *data;
-       u32 *status;
-};
-
 struct btmtksdio_dev {
        struct hci_dev *hdev;
        struct sdio_func *func;
        struct device *dev;
 
-       struct work_struct tx_work;
+       struct work_struct txrx_work;
        unsigned long tx_state;
        struct sk_buff_head txq;
+       bool hw_tx_ready;
 
        struct sk_buff *evt_skb;
 
@@ -172,29 +125,35 @@ static int mtk_hci_wmt_sync(struct hci_dev *hdev,
 {
        struct btmtksdio_dev *bdev = hci_get_drvdata(hdev);
        struct btmtk_hci_wmt_evt_funcc *wmt_evt_funcc;
+       struct btmtk_hci_wmt_evt_reg *wmt_evt_reg;
        u32 hlen, status = BTMTK_WMT_INVALID;
        struct btmtk_hci_wmt_evt *wmt_evt;
-       struct mtk_hci_wmt_cmd wc;
-       struct mtk_wmt_hdr *hdr;
+       struct btmtk_hci_wmt_cmd *wc;
+       struct btmtk_wmt_hdr *hdr;
        int err;
 
+       /* Send the WMT command and wait until the WMT event returns */
        hlen = sizeof(*hdr) + wmt_params->dlen;
        if (hlen > 255)
                return -EINVAL;
 
-       hdr = (struct mtk_wmt_hdr *)&wc;
+       wc = kzalloc(hlen, GFP_KERNEL);
+       if (!wc)
+               return -ENOMEM;
+
+       hdr = &wc->hdr;
        hdr->dir = 1;
        hdr->op = wmt_params->op;
        hdr->dlen = cpu_to_le16(wmt_params->dlen + 1);
        hdr->flag = wmt_params->flag;
-       memcpy(wc.data, wmt_params->data, wmt_params->dlen);
+       memcpy(wc->data, wmt_params->data, wmt_params->dlen);
 
        set_bit(BTMTKSDIO_TX_WAIT_VND_EVT, &bdev->tx_state);
 
-       err = __hci_cmd_send(hdev, 0xfc6f, hlen, &wc);
+       err = __hci_cmd_send(hdev, 0xfc6f, hlen, wc);
        if (err < 0) {
                clear_bit(BTMTKSDIO_TX_WAIT_VND_EVT, &bdev->tx_state);
-               return err;
+               goto err_free_wc;
        }
 
        /* The vendor specific WMT commands are all answered by a vendor
@@ -211,13 +170,14 @@ static int mtk_hci_wmt_sync(struct hci_dev *hdev,
        if (err == -EINTR) {
                bt_dev_err(hdev, "Execution of wmt command interrupted");
                clear_bit(BTMTKSDIO_TX_WAIT_VND_EVT, &bdev->tx_state);
-               return err;
+               goto err_free_wc;
        }
 
        if (err) {
                bt_dev_err(hdev, "Execution of wmt command timed out");
                clear_bit(BTMTKSDIO_TX_WAIT_VND_EVT, &bdev->tx_state);
-               return -ETIMEDOUT;
+               err = -ETIMEDOUT;
+               goto err_free_wc;
        }
 
        /* Parse and handle the return WMT event */
@@ -230,13 +190,13 @@ static int mtk_hci_wmt_sync(struct hci_dev *hdev,
        }
 
        switch (wmt_evt->whdr.op) {
-       case MTK_WMT_SEMAPHORE:
+       case BTMTK_WMT_SEMAPHORE:
                if (wmt_evt->whdr.flag == 2)
                        status = BTMTK_WMT_PATCH_UNDONE;
                else
                        status = BTMTK_WMT_PATCH_DONE;
                break;
-       case MTK_WMT_FUNC_CTRL:
+       case BTMTK_WMT_FUNC_CTRL:
                wmt_evt_funcc = (struct btmtk_hci_wmt_evt_funcc *)wmt_evt;
                if (be16_to_cpu(wmt_evt_funcc->status) == 0x404)
                        status = BTMTK_WMT_ON_DONE;
@@ -245,6 +205,19 @@ static int mtk_hci_wmt_sync(struct hci_dev *hdev,
                else
                        status = BTMTK_WMT_ON_UNDONE;
                break;
+       case BTMTK_WMT_PATCH_DWNLD:
+               if (wmt_evt->whdr.flag == 2)
+                       status = BTMTK_WMT_PATCH_DONE;
+               else if (wmt_evt->whdr.flag == 1)
+                       status = BTMTK_WMT_PATCH_PROGRESS;
+               else
+                       status = BTMTK_WMT_PATCH_UNDONE;
+               break;
+       case BTMTK_WMT_REGISTER:
+               wmt_evt_reg = (struct btmtk_hci_wmt_evt_reg *)wmt_evt;
+               if (le16_to_cpu(wmt_evt->whdr.dlen) == 12)
+                       status = le32_to_cpu(wmt_evt_reg->val);
+               break;
        }
 
        if (wmt_params->status)
@@ -253,6 +226,8 @@ static int mtk_hci_wmt_sync(struct hci_dev *hdev,
 err_free_skb:
        kfree_skb(bdev->evt_skb);
        bdev->evt_skb = NULL;
+err_free_wc:
+       kfree(wc);
 
        return err;
 }
@@ -279,6 +254,7 @@ static int btmtksdio_tx_packet(struct btmtksdio_dev *bdev,
        sdio_hdr->reserved = cpu_to_le16(0);
        sdio_hdr->bt_type = hci_skb_pkt_type(skb);
 
+       bdev->hw_tx_ready = false;
        err = sdio_writesb(bdev->func, MTK_REG_CTDR, skb->data,
                           round_up(skb->len, MTK_SDIO_BLOCK_SIZE));
        if (err < 0)
@@ -301,32 +277,6 @@ static u32 btmtksdio_drv_own_query(struct btmtksdio_dev *bdev)
        return sdio_readl(bdev->func, MTK_REG_CHLPCR, NULL);
 }
 
-static void btmtksdio_tx_work(struct work_struct *work)
-{
-       struct btmtksdio_dev *bdev = container_of(work, struct btmtksdio_dev,
-                                                 tx_work);
-       struct sk_buff *skb;
-       int err;
-
-       pm_runtime_get_sync(bdev->dev);
-
-       sdio_claim_host(bdev->func);
-
-       while ((skb = skb_dequeue(&bdev->txq))) {
-               err = btmtksdio_tx_packet(bdev, skb);
-               if (err < 0) {
-                       bdev->hdev->stat.err_tx++;
-                       skb_queue_head(&bdev->txq, skb);
-                       break;
-               }
-       }
-
-       sdio_release_host(bdev->func);
-
-       pm_runtime_mark_last_busy(bdev->dev);
-       pm_runtime_put_autosuspend(bdev->dev);
-}
-
 static int btmtksdio_recv_event(struct hci_dev *hdev, struct sk_buff *skb)
 {
        struct btmtksdio_dev *bdev = hci_get_drvdata(hdev);
@@ -477,70 +427,89 @@ err_kfree_skb:
        return err;
 }
 
-static void btmtksdio_interrupt(struct sdio_func *func)
+static void btmtksdio_txrx_work(struct work_struct *work)
 {
-       struct btmtksdio_dev *bdev = sdio_get_drvdata(func);
-       u32 int_status;
-       u16 rx_size;
-
-       /* It is required that the host gets ownership from the device before
-        * accessing any register, however, if SDIO host is not being released,
-        * a potential deadlock probably happens in a circular wait between SDIO
-        * IRQ work and PM runtime work. So, we have to explicitly release SDIO
-        * host here and claim again after the PM runtime work is all done.
-        */
-       sdio_release_host(bdev->func);
+       struct btmtksdio_dev *bdev = container_of(work, struct btmtksdio_dev,
+                                                 txrx_work);
+       unsigned long txrx_timeout;
+       u32 int_status, rx_size;
+       struct sk_buff *skb;
+       int err;
 
        pm_runtime_get_sync(bdev->dev);
 
        sdio_claim_host(bdev->func);
 
        /* Disable interrupt */
-       sdio_writel(func, C_INT_EN_CLR, MTK_REG_CHLPCR, NULL);
-
-       int_status = sdio_readl(func, MTK_REG_CHISR, NULL);
-
-       /* Ack an interrupt as soon as possible before any operation on
-        * hardware.
-        *
-        * Note that we don't ack any status during operations to avoid race
-        * condition between the host and the device such as it's possible to
-        * mistakenly ack RX_DONE for the next packet and then cause interrupts
-        * not be raised again but there is still pending data in the hardware
-        * FIFO.
-        */
-       sdio_writel(func, int_status, MTK_REG_CHISR, NULL);
+       sdio_writel(bdev->func, C_INT_EN_CLR, MTK_REG_CHLPCR, 0);
+
+       txrx_timeout = jiffies + 5 * HZ;
+
+       do {
+               int_status = sdio_readl(bdev->func, MTK_REG_CHISR, NULL);
+
+               /* Ack an interrupt as soon as possible before any operation on
+                * hardware.
+                *
+                * Note that we don't ack any status during operations to avoid race
+                * condition between the host and the device such as it's possible to
+                * mistakenly ack RX_DONE for the next packet and then cause interrupts
+                * not be raised again but there is still pending data in the hardware
+                * FIFO.
+                */
+               sdio_writel(bdev->func, int_status, MTK_REG_CHISR, NULL);
+
+               if (int_status & FW_OWN_BACK_INT)
+                       bt_dev_dbg(bdev->hdev, "Get fw own back");
+
+               if (int_status & TX_EMPTY)
+                       bdev->hw_tx_ready = true;
+               else if (unlikely(int_status & TX_FIFO_OVERFLOW))
+                       bt_dev_warn(bdev->hdev, "Tx fifo overflow");
+
+               if (bdev->hw_tx_ready) {
+                       skb = skb_dequeue(&bdev->txq);
+                       if (skb) {
+                               err = btmtksdio_tx_packet(bdev, skb);
+                               if (err < 0) {
+                                       bdev->hdev->stat.err_tx++;
+                                       skb_queue_head(&bdev->txq, skb);
+                               }
+                       }
+               }
 
-       if (unlikely(!int_status))
-               bt_dev_err(bdev->hdev, "CHISR is 0");
+               if (int_status & RX_DONE_INT) {
+                       rx_size = sdio_readl(bdev->func, MTK_REG_CRPLR, NULL);
+                       rx_size = (rx_size & RX_PKT_LEN) >> 16;
+                       if (btmtksdio_rx_packet(bdev, rx_size) < 0)
+                               bdev->hdev->stat.err_rx++;
+               }
+       } while (int_status || time_is_before_jiffies(txrx_timeout));
 
-       if (int_status & FW_OWN_BACK_INT)
-               bt_dev_dbg(bdev->hdev, "Get fw own back");
+       /* Enable interrupt */
+       sdio_writel(bdev->func, C_INT_EN_SET, MTK_REG_CHLPCR, 0);
 
-       if (int_status & TX_EMPTY)
-               schedule_work(&bdev->tx_work);
-       else if (unlikely(int_status & TX_FIFO_OVERFLOW))
-               bt_dev_warn(bdev->hdev, "Tx fifo overflow");
+       sdio_release_host(bdev->func);
 
-       if (int_status & RX_DONE_INT) {
-               rx_size = (int_status & RX_PKT_LEN) >> 16;
+       pm_runtime_mark_last_busy(bdev->dev);
+       pm_runtime_put_autosuspend(bdev->dev);
+}
 
-               if (btmtksdio_rx_packet(bdev, rx_size) < 0)
-                       bdev->hdev->stat.err_rx++;
-       }
+static void btmtksdio_interrupt(struct sdio_func *func)
+{
+       struct btmtksdio_dev *bdev = sdio_get_drvdata(func);
 
-       /* Enable interrupt */
-       sdio_writel(func, C_INT_EN_SET, MTK_REG_CHLPCR, NULL);
+       /* Disable interrupt */
+       sdio_writel(bdev->func, C_INT_EN_CLR, MTK_REG_CHLPCR, 0);
 
-       pm_runtime_mark_last_busy(bdev->dev);
-       pm_runtime_put_autosuspend(bdev->dev);
+       schedule_work(&bdev->txrx_work);
 }
 
 static int btmtksdio_open(struct hci_dev *hdev)
 {
        struct btmtksdio_dev *bdev = hci_get_drvdata(hdev);
+       u32 status, val;
        int err;
-       u32 status;
 
        sdio_claim_host(bdev->func);
 
@@ -580,13 +549,22 @@ static int btmtksdio_open(struct hci_dev *hdev)
        /* SDIO CMD 5 allows the SDIO device back to idle state an
         * synchronous interrupt is supported in SDIO 4-bit mode
         */
-       sdio_writel(bdev->func, SDIO_INT_CTL | SDIO_RE_INIT_EN,
-                   MTK_REG_CSDIOCSR, &err);
+       val = sdio_readl(bdev->func, MTK_REG_CSDIOCSR, &err);
+       if (err < 0)
+               goto err_release_irq;
+
+       val |= SDIO_INT_CTL;
+       sdio_writel(bdev->func, val, MTK_REG_CSDIOCSR, &err);
+       if (err < 0)
+               goto err_release_irq;
+
+       /* Explitly set write-1-clear method */
+       val = sdio_readl(bdev->func, MTK_REG_CHCR, &err);
        if (err < 0)
                goto err_release_irq;
 
-       /* Setup write-1-clear for CHISR register */
-       sdio_writel(bdev->func, C_INT_CLR_CTRL, MTK_REG_CHCR, &err);
+       val |= C_INT_CLR_CTRL;
+       sdio_writel(bdev->func, val, MTK_REG_CHCR, &err);
        if (err < 0)
                goto err_release_irq;
 
@@ -630,6 +608,8 @@ static int btmtksdio_close(struct hci_dev *hdev)
 
        sdio_release_irq(bdev->func);
 
+       cancel_work_sync(&bdev->txrx_work);
+
        /* Return ownership to the device */
        sdio_writel(bdev->func, C_FW_OWN_REQ_SET, MTK_REG_CHLPCR, NULL);
 
@@ -651,7 +631,7 @@ static int btmtksdio_flush(struct hci_dev *hdev)
 
        skb_queue_purge(&bdev->txq);
 
-       cancel_work_sync(&bdev->tx_work);
+       cancel_work_sync(&bdev->txrx_work);
 
        return 0;
 }
@@ -663,7 +643,7 @@ static int btmtksdio_func_query(struct hci_dev *hdev)
        u8 param = 0;
 
        /* Query whether the function is enabled */
-       wmt_params.op = MTK_WMT_FUNC_CTRL;
+       wmt_params.op = BTMTK_WMT_FUNC_CTRL;
        wmt_params.flag = 4;
        wmt_params.dlen = sizeof(param);
        wmt_params.data = &param;
@@ -678,111 +658,16 @@ static int btmtksdio_func_query(struct hci_dev *hdev)
        return status;
 }
 
-static int mtk_setup_firmware(struct hci_dev *hdev, const char *fwname)
+static int mt76xx_setup(struct hci_dev *hdev, const char *fwname)
 {
        struct btmtk_hci_wmt_params wmt_params;
-       const struct firmware *fw;
-       const u8 *fw_ptr;
-       size_t fw_size;
-       int err, dlen;
-       u8 flag, param;
-
-       err = request_firmware(&fw, fwname, &hdev->dev);
-       if (err < 0) {
-               bt_dev_err(hdev, "Failed to load firmware file (%d)", err);
-               return err;
-       }
-
-       /* Power on data RAM the firmware relies on. */
-       param = 1;
-       wmt_params.op = MTK_WMT_FUNC_CTRL;
-       wmt_params.flag = 3;
-       wmt_params.dlen = sizeof(param);
-       wmt_params.data = &param;
-       wmt_params.status = NULL;
-
-       err = mtk_hci_wmt_sync(hdev, &wmt_params);
-       if (err < 0) {
-               bt_dev_err(hdev, "Failed to power on data RAM (%d)", err);
-               goto free_fw;
-       }
-
-       fw_ptr = fw->data;
-       fw_size = fw->size;
-
-       /* The size of patch header is 30 bytes, should be skip */
-       if (fw_size < 30) {
-               err = -EINVAL;
-               goto free_fw;
-       }
-
-       fw_size -= 30;
-       fw_ptr += 30;
-       flag = 1;
-
-       wmt_params.op = MTK_WMT_PATCH_DWNLD;
-       wmt_params.status = NULL;
-
-       while (fw_size > 0) {
-               dlen = min_t(int, 250, fw_size);
-
-               /* Tell device the position in sequence */
-               if (fw_size - dlen <= 0)
-                       flag = 3;
-               else if (fw_size < fw->size - 30)
-                       flag = 2;
-
-               wmt_params.flag = flag;
-               wmt_params.dlen = dlen;
-               wmt_params.data = fw_ptr;
-
-               err = mtk_hci_wmt_sync(hdev, &wmt_params);
-               if (err < 0) {
-                       bt_dev_err(hdev, "Failed to send wmt patch dwnld (%d)",
-                                  err);
-                       goto free_fw;
-               }
-
-               fw_size -= dlen;
-               fw_ptr += dlen;
-       }
-
-       wmt_params.op = MTK_WMT_RST;
-       wmt_params.flag = 4;
-       wmt_params.dlen = 0;
-       wmt_params.data = NULL;
-       wmt_params.status = NULL;
-
-       /* Activate funciton the firmware providing to */
-       err = mtk_hci_wmt_sync(hdev, &wmt_params);
-       if (err < 0) {
-               bt_dev_err(hdev, "Failed to send wmt rst (%d)", err);
-               goto free_fw;
-       }
-
-       /* Wait a few moments for firmware activation done */
-       usleep_range(10000, 12000);
-
-free_fw:
-       release_firmware(fw);
-       return err;
-}
-
-static int btmtksdio_setup(struct hci_dev *hdev)
-{
-       struct btmtksdio_dev *bdev = hci_get_drvdata(hdev);
-       struct btmtk_hci_wmt_params wmt_params;
-       ktime_t calltime, delta, rettime;
        struct btmtk_tci_sleep tci_sleep;
-       unsigned long long duration;
        struct sk_buff *skb;
        int err, status;
        u8 param = 0x1;
 
-       calltime = ktime_get();
-
        /* Query whether the firmware is already download */
-       wmt_params.op = MTK_WMT_SEMAPHORE;
+       wmt_params.op = BTMTK_WMT_SEMAPHORE;
        wmt_params.flag = 1;
        wmt_params.dlen = 0;
        wmt_params.data = NULL;
@@ -800,7 +685,7 @@ static int btmtksdio_setup(struct hci_dev *hdev)
        }
 
        /* Setup a firmware which the device definitely requires */
-       err = mtk_setup_firmware(hdev, bdev->data->fwname);
+       err = btmtk_setup_firmware(hdev, fwname, mtk_hci_wmt_sync);
        if (err < 0)
                return err;
 
@@ -823,7 +708,7 @@ ignore_setup_fw:
        }
 
        /* Enable Bluetooth protocol */
-       wmt_params.op = MTK_WMT_FUNC_CTRL;
+       wmt_params.op = BTMTK_WMT_FUNC_CTRL;
        wmt_params.flag = 0;
        wmt_params.dlen = sizeof(param);
        wmt_params.data = &param;
@@ -852,6 +737,113 @@ ignore_func_on:
        }
        kfree_skb(skb);
 
+       return 0;
+}
+
+static int mt79xx_setup(struct hci_dev *hdev, const char *fwname)
+{
+       struct btmtk_hci_wmt_params wmt_params;
+       u8 param = 0x1;
+       int err;
+
+       err = btmtk_setup_firmware_79xx(hdev, fwname, mtk_hci_wmt_sync);
+       if (err < 0) {
+               bt_dev_err(hdev, "Failed to setup 79xx firmware (%d)", err);
+               return err;
+       }
+
+       /* Enable Bluetooth protocol */
+       wmt_params.op = BTMTK_WMT_FUNC_CTRL;
+       wmt_params.flag = 0;
+       wmt_params.dlen = sizeof(param);
+       wmt_params.data = &param;
+       wmt_params.status = NULL;
+
+       err = mtk_hci_wmt_sync(hdev, &wmt_params);
+       if (err < 0) {
+               bt_dev_err(hdev, "Failed to send wmt func ctrl (%d)", err);
+               return err;
+       }
+
+       return err;
+}
+
+static int btsdio_mtk_reg_read(struct hci_dev *hdev, u32 reg, u32 *val)
+{
+       struct btmtk_hci_wmt_params wmt_params;
+       struct reg_read_cmd {
+               u8 type;
+               u8 rsv;
+               u8 num;
+               __le32 addr;
+       } __packed reg_read = {
+               .type = 1,
+               .num = 1,
+       };
+       u32 status;
+       int err;
+
+       reg_read.addr = cpu_to_le32(reg);
+       wmt_params.op = BTMTK_WMT_REGISTER;
+       wmt_params.flag = BTMTK_WMT_REG_READ;
+       wmt_params.dlen = sizeof(reg_read);
+       wmt_params.data = &reg_read;
+       wmt_params.status = &status;
+
+       err = mtk_hci_wmt_sync(hdev, &wmt_params);
+       if (err < 0) {
+               bt_dev_err(hdev, "Failed to read reg(%d)", err);
+               return err;
+       }
+
+       *val = status;
+
+       return err;
+}
+
+static int btmtksdio_setup(struct hci_dev *hdev)
+{
+       struct btmtksdio_dev *bdev = hci_get_drvdata(hdev);
+       ktime_t calltime, delta, rettime;
+       unsigned long long duration;
+       char fwname[64];
+       int err, dev_id;
+       u32 fw_version = 0;
+
+       calltime = ktime_get();
+       bdev->hw_tx_ready = true;
+
+       switch (bdev->data->chipid) {
+       case 0x7921:
+               err = btsdio_mtk_reg_read(hdev, 0x70010200, &dev_id);
+               if (err < 0) {
+                       bt_dev_err(hdev, "Failed to get device id (%d)", err);
+                       return err;
+               }
+
+               err = btsdio_mtk_reg_read(hdev, 0x80021004, &fw_version);
+               if (err < 0) {
+                       bt_dev_err(hdev, "Failed to get fw version (%d)", err);
+                       return err;
+               }
+
+               snprintf(fwname, sizeof(fwname),
+                        "mediatek/BT_RAM_CODE_MT%04x_1_%x_hdr.bin",
+                        dev_id & 0xffff, (fw_version & 0xff) + 1);
+               err = mt79xx_setup(hdev, fwname);
+               if (err < 0)
+                       return err;
+               break;
+       case 0x7663:
+       case 0x7668:
+               err = mt76xx_setup(hdev, bdev->data->fwname);
+               if (err < 0)
+                       return err;
+               break;
+       default:
+               return -ENODEV;
+       }
+
        rettime = ktime_get();
        delta = ktime_sub(rettime, calltime);
        duration = (unsigned long long)ktime_to_ns(delta) >> 10;
@@ -891,7 +883,7 @@ static int btmtksdio_shutdown(struct hci_dev *hdev)
        pm_runtime_get_sync(bdev->dev);
 
        /* Disable the device */
-       wmt_params.op = MTK_WMT_FUNC_CTRL;
+       wmt_params.op = BTMTK_WMT_FUNC_CTRL;
        wmt_params.flag = 0;
        wmt_params.dlen = sizeof(param);
        wmt_params.data = &param;
@@ -932,7 +924,7 @@ static int btmtksdio_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
 
        skb_queue_tail(&bdev->txq, skb);
 
-       schedule_work(&bdev->tx_work);
+       schedule_work(&bdev->txrx_work);
 
        return 0;
 }
@@ -955,7 +947,7 @@ static int btmtksdio_probe(struct sdio_func *func,
        bdev->dev = &func->dev;
        bdev->func = func;
 
-       INIT_WORK(&bdev->tx_work, btmtksdio_tx_work);
+       INIT_WORK(&bdev->txrx_work, btmtksdio_txrx_work);
        skb_queue_head_init(&bdev->txq);
 
        /* Initialize and register HCI device */
@@ -976,6 +968,8 @@ static int btmtksdio_probe(struct sdio_func *func,
        hdev->setup    = btmtksdio_setup;
        hdev->shutdown = btmtksdio_shutdown;
        hdev->send     = btmtksdio_send_frame;
+       hdev->set_bdaddr = btmtk_set_bdaddr;
+
        SET_HCIDEV_DEV(hdev, &func->dev);
 
        hdev->manufacturer = 70;
@@ -1112,5 +1106,3 @@ MODULE_AUTHOR("Sean Wang <sean.wang@mediatek.com>");
 MODULE_DESCRIPTION("MediaTek Bluetooth SDIO driver ver " VERSION);
 MODULE_VERSION(VERSION);
 MODULE_LICENSE("GPL");
-MODULE_FIRMWARE(FIRMWARE_MT7663);
-MODULE_FIRMWARE(FIRMWARE_MT7668);
index 199e8f7..795be33 100644 (file)
@@ -295,6 +295,8 @@ static int btsdio_probe(struct sdio_func *func,
                switch (func->device) {
                case SDIO_DEVICE_ID_BROADCOM_43341:
                case SDIO_DEVICE_ID_BROADCOM_43430:
+               case SDIO_DEVICE_ID_BROADCOM_4345:
+               case SDIO_DEVICE_ID_BROADCOM_43455:
                case SDIO_DEVICE_ID_BROADCOM_4356:
                        return -ENODEV;
                }
index 75c8376..30a057e 100644 (file)
@@ -24,6 +24,7 @@
 #include "btintel.h"
 #include "btbcm.h"
 #include "btrtl.h"
+#include "btmtk.h"
 
 #define VERSION "0.8"
 
@@ -2131,122 +2132,6 @@ static int btusb_send_frame_intel(struct hci_dev *hdev, struct sk_buff *skb)
 #define MTK_BT_RST_DONE                0x00000100
 #define MTK_BT_RESET_WAIT_MS   100
 #define MTK_BT_RESET_NUM_TRIES 10
-#define FIRMWARE_MT7663                "mediatek/mt7663pr2h.bin"
-#define FIRMWARE_MT7668                "mediatek/mt7668pr2h.bin"
-
-#define HCI_WMT_MAX_EVENT_SIZE         64
-/* It is for mt79xx download rom patch*/
-#define MTK_FW_ROM_PATCH_HEADER_SIZE   32
-#define MTK_FW_ROM_PATCH_GD_SIZE       64
-#define MTK_FW_ROM_PATCH_SEC_MAP_SIZE  64
-#define MTK_SEC_MAP_COMMON_SIZE        12
-#define MTK_SEC_MAP_NEED_SEND_SIZE     52
-
-enum {
-       BTMTK_WMT_PATCH_DWNLD = 0x1,
-       BTMTK_WMT_FUNC_CTRL = 0x6,
-       BTMTK_WMT_RST = 0x7,
-       BTMTK_WMT_SEMAPHORE = 0x17,
-};
-
-enum {
-       BTMTK_WMT_INVALID,
-       BTMTK_WMT_PATCH_UNDONE,
-       BTMTK_WMT_PATCH_PROGRESS,
-       BTMTK_WMT_PATCH_DONE,
-       BTMTK_WMT_ON_UNDONE,
-       BTMTK_WMT_ON_DONE,
-       BTMTK_WMT_ON_PROGRESS,
-};
-
-struct btmtk_wmt_hdr {
-       u8      dir;
-       u8      op;
-       __le16  dlen;
-       u8      flag;
-} __packed;
-
-struct btmtk_hci_wmt_cmd {
-       struct btmtk_wmt_hdr hdr;
-       u8 data[];
-} __packed;
-
-struct btmtk_hci_wmt_evt {
-       struct hci_event_hdr hhdr;
-       struct btmtk_wmt_hdr whdr;
-} __packed;
-
-struct btmtk_hci_wmt_evt_funcc {
-       struct btmtk_hci_wmt_evt hwhdr;
-       __be16 status;
-} __packed;
-
-struct btmtk_tci_sleep {
-       u8 mode;
-       __le16 duration;
-       __le16 host_duration;
-       u8 host_wakeup_pin;
-       u8 time_compensation;
-} __packed;
-
-struct btmtk_hci_wmt_params {
-       u8 op;
-       u8 flag;
-       u16 dlen;
-       const void *data;
-       u32 *status;
-};
-
-struct btmtk_patch_header {
-       u8 datetime[16];
-       u8 platform[4];
-       __le16 hwver;
-       __le16 swver;
-       __le32 magicnum;
-} __packed;
-
-struct btmtk_global_desc {
-       __le32 patch_ver;
-       __le32 sub_sys;
-       __le32 feature_opt;
-       __le32 section_num;
-} __packed;
-
-struct btmtk_section_map {
-       __le32 sectype;
-       __le32 secoffset;
-       __le32 secsize;
-       union {
-               __le32 u4SecSpec[13];
-               struct {
-                       __le32 dlAddr;
-                       __le32 dlsize;
-                       __le32 seckeyidx;
-                       __le32 alignlen;
-                       __le32 sectype;
-                       __le32 dlmodecrctype;
-                       __le32 crc;
-                       __le32 reserved[6];
-               } bin_info_spec;
-       };
-} __packed;
-
-static int btusb_set_bdaddr_mtk(struct hci_dev *hdev, const bdaddr_t *bdaddr)
-{
-       struct sk_buff *skb;
-       long ret;
-
-       skb = __hci_cmd_sync(hdev, 0xfc1a, sizeof(bdaddr), bdaddr, HCI_INIT_TIMEOUT);
-       if (IS_ERR(skb)) {
-               ret = PTR_ERR(skb);
-               bt_dev_err(hdev, "changing Mediatek device address failed (%ld)",
-                          ret);
-               return ret;
-       }
-       kfree_skb(skb);
-
-       return 0;
-}
 
 static void btusb_mtk_wmt_recv(struct urb *urb)
 {
@@ -2265,6 +2150,7 @@ static void btusb_mtk_wmt_recv(struct urb *urb)
                skb = bt_skb_alloc(HCI_WMT_MAX_EVENT_SIZE, GFP_ATOMIC);
                if (!skb) {
                        hdev->stat.err_rx++;
+                       kfree(urb->setup_packet);
                        return;
                }
 
@@ -2285,6 +2171,7 @@ static void btusb_mtk_wmt_recv(struct urb *urb)
                        data->evt_skb = skb_clone(skb, GFP_ATOMIC);
                        if (!data->evt_skb) {
                                kfree_skb(skb);
+                               kfree(urb->setup_packet);
                                return;
                        }
                }
@@ -2293,6 +2180,7 @@ static void btusb_mtk_wmt_recv(struct urb *urb)
                if (err < 0) {
                        kfree_skb(data->evt_skb);
                        data->evt_skb = NULL;
+                       kfree(urb->setup_packet);
                        return;
                }
 
@@ -2303,6 +2191,7 @@ static void btusb_mtk_wmt_recv(struct urb *urb)
                        wake_up_bit(&data->flags,
                                    BTUSB_TX_WAIT_VND_EVT);
                }
+               kfree(urb->setup_packet);
                return;
        } else if (urb->status == -ENOENT) {
                /* Avoid suspend failed when usb_kill_urb */
@@ -2323,6 +2212,7 @@ static void btusb_mtk_wmt_recv(struct urb *urb)
        usb_anchor_urb(urb, &data->ctrl_anchor);
        err = usb_submit_urb(urb, GFP_ATOMIC);
        if (err < 0) {
+               kfree(urb->setup_packet);
                /* -EPERM: urb is being killed;
                 * -ENODEV: device got disconnected
                 */
@@ -2497,209 +2387,6 @@ err_free_wc:
        return err;
 }
 
-static int btusb_mtk_setup_firmware_79xx(struct hci_dev *hdev, const char *fwname)
-{
-       struct btmtk_hci_wmt_params wmt_params;
-       struct btmtk_global_desc *globaldesc = NULL;
-       struct btmtk_section_map *sectionmap;
-       const struct firmware *fw;
-       const u8 *fw_ptr;
-       const u8 *fw_bin_ptr;
-       int err, dlen, i, status;
-       u8 flag, first_block, retry;
-       u32 section_num, dl_size, section_offset;
-       u8 cmd[64];
-
-       err = request_firmware(&fw, fwname, &hdev->dev);
-       if (err < 0) {
-               bt_dev_err(hdev, "Failed to load firmware file (%d)", err);
-               return err;
-       }
-
-       fw_ptr = fw->data;
-       fw_bin_ptr = fw_ptr;
-       globaldesc = (struct btmtk_global_desc *)(fw_ptr + MTK_FW_ROM_PATCH_HEADER_SIZE);
-       section_num = le32_to_cpu(globaldesc->section_num);
-
-       for (i = 0; i < section_num; i++) {
-               first_block = 1;
-               fw_ptr = fw_bin_ptr;
-               sectionmap = (struct btmtk_section_map *)(fw_ptr + MTK_FW_ROM_PATCH_HEADER_SIZE +
-                             MTK_FW_ROM_PATCH_GD_SIZE + MTK_FW_ROM_PATCH_SEC_MAP_SIZE * i);
-
-               section_offset = le32_to_cpu(sectionmap->secoffset);
-               dl_size = le32_to_cpu(sectionmap->bin_info_spec.dlsize);
-
-               if (dl_size > 0) {
-                       retry = 20;
-                       while (retry > 0) {
-                               cmd[0] = 0; /* 0 means legacy dl mode. */
-                               memcpy(cmd + 1,
-                                      fw_ptr + MTK_FW_ROM_PATCH_HEADER_SIZE +
-                                      MTK_FW_ROM_PATCH_GD_SIZE + MTK_FW_ROM_PATCH_SEC_MAP_SIZE * i +
-                                      MTK_SEC_MAP_COMMON_SIZE,
-                                      MTK_SEC_MAP_NEED_SEND_SIZE + 1);
-
-                               wmt_params.op = BTMTK_WMT_PATCH_DWNLD;
-                               wmt_params.status = &status;
-                               wmt_params.flag = 0;
-                               wmt_params.dlen = MTK_SEC_MAP_NEED_SEND_SIZE + 1;
-                               wmt_params.data = &cmd;
-
-                               err = btusb_mtk_hci_wmt_sync(hdev, &wmt_params);
-                               if (err < 0) {
-                                       bt_dev_err(hdev, "Failed to send wmt patch dwnld (%d)",
-                                                  err);
-                                       goto err_release_fw;
-                               }
-
-                               if (status == BTMTK_WMT_PATCH_UNDONE) {
-                                       break;
-                               } else if (status == BTMTK_WMT_PATCH_PROGRESS) {
-                                       msleep(100);
-                                       retry--;
-                               } else if (status == BTMTK_WMT_PATCH_DONE) {
-                                       goto next_section;
-                               } else {
-                                       bt_dev_err(hdev, "Failed wmt patch dwnld status (%d)",
-                                                  status);
-                                       goto err_release_fw;
-                               }
-                       }
-
-                       fw_ptr += section_offset;
-                       wmt_params.op = BTMTK_WMT_PATCH_DWNLD;
-                       wmt_params.status = NULL;
-
-                       while (dl_size > 0) {
-                               dlen = min_t(int, 250, dl_size);
-                               if (first_block == 1) {
-                                       flag = 1;
-                                       first_block = 0;
-                               } else if (dl_size - dlen <= 0) {
-                                       flag = 3;
-                               } else {
-                                       flag = 2;
-                               }
-
-                               wmt_params.flag = flag;
-                               wmt_params.dlen = dlen;
-                               wmt_params.data = fw_ptr;
-
-                               err = btusb_mtk_hci_wmt_sync(hdev, &wmt_params);
-                               if (err < 0) {
-                                       bt_dev_err(hdev, "Failed to send wmt patch dwnld (%d)",
-                                                  err);
-                                       goto err_release_fw;
-                               }
-
-                               dl_size -= dlen;
-                               fw_ptr += dlen;
-                       }
-               }
-next_section:
-               continue;
-       }
-       /* Wait a few moments for firmware activation done */
-       usleep_range(100000, 120000);
-
-err_release_fw:
-       release_firmware(fw);
-
-       return err;
-}
-
-static int btusb_mtk_setup_firmware(struct hci_dev *hdev, const char *fwname)
-{
-       struct btmtk_hci_wmt_params wmt_params;
-       const struct firmware *fw;
-       const u8 *fw_ptr;
-       size_t fw_size;
-       int err, dlen;
-       u8 flag, param;
-
-       err = request_firmware(&fw, fwname, &hdev->dev);
-       if (err < 0) {
-               bt_dev_err(hdev, "Failed to load firmware file (%d)", err);
-               return err;
-       }
-
-       /* Power on data RAM the firmware relies on. */
-       param = 1;
-       wmt_params.op = BTMTK_WMT_FUNC_CTRL;
-       wmt_params.flag = 3;
-       wmt_params.dlen = sizeof(param);
-       wmt_params.data = &param;
-       wmt_params.status = NULL;
-
-       err = btusb_mtk_hci_wmt_sync(hdev, &wmt_params);
-       if (err < 0) {
-               bt_dev_err(hdev, "Failed to power on data RAM (%d)", err);
-               goto err_release_fw;
-       }
-
-       fw_ptr = fw->data;
-       fw_size = fw->size;
-
-       /* The size of patch header is 30 bytes, should be skip */
-       if (fw_size < 30) {
-               err = -EINVAL;
-               goto err_release_fw;
-       }
-
-       fw_size -= 30;
-       fw_ptr += 30;
-       flag = 1;
-
-       wmt_params.op = BTMTK_WMT_PATCH_DWNLD;
-       wmt_params.status = NULL;
-
-       while (fw_size > 0) {
-               dlen = min_t(int, 250, fw_size);
-
-               /* Tell device the position in sequence */
-               if (fw_size - dlen <= 0)
-                       flag = 3;
-               else if (fw_size < fw->size - 30)
-                       flag = 2;
-
-               wmt_params.flag = flag;
-               wmt_params.dlen = dlen;
-               wmt_params.data = fw_ptr;
-
-               err = btusb_mtk_hci_wmt_sync(hdev, &wmt_params);
-               if (err < 0) {
-                       bt_dev_err(hdev, "Failed to send wmt patch dwnld (%d)",
-                                  err);
-                       goto err_release_fw;
-               }
-
-               fw_size -= dlen;
-               fw_ptr += dlen;
-       }
-
-       wmt_params.op = BTMTK_WMT_RST;
-       wmt_params.flag = 4;
-       wmt_params.dlen = 0;
-       wmt_params.data = NULL;
-       wmt_params.status = NULL;
-
-       /* Activate funciton the firmware providing to */
-       err = btusb_mtk_hci_wmt_sync(hdev, &wmt_params);
-       if (err < 0) {
-               bt_dev_err(hdev, "Failed to send wmt rst (%d)", err);
-               goto err_release_fw;
-       }
-
-       /* Wait a few moments for firmware activation done */
-       usleep_range(10000, 12000);
-
-err_release_fw:
-       release_firmware(fw);
-
-       return err;
-}
-
 static int btusb_mtk_func_query(struct hci_dev *hdev)
 {
        struct btmtk_hci_wmt_params wmt_params;
@@ -2857,7 +2544,8 @@ static int btusb_mtk_setup(struct hci_dev *hdev)
                snprintf(fw_bin_name, sizeof(fw_bin_name),
                        "mediatek/BT_RAM_CODE_MT%04x_1_%x_hdr.bin",
                         dev_id & 0xffff, (fw_version & 0xff) + 1);
-               err = btusb_mtk_setup_firmware_79xx(hdev, fw_bin_name);
+               err = btmtk_setup_firmware_79xx(hdev, fw_bin_name,
+                                               btusb_mtk_hci_wmt_sync);
 
                /* It's Device EndPoint Reset Option Register */
                btusb_mtk_uhw_reg_write(data, MTK_EP_RST_OPT, MTK_EP_RST_IN_OUT_OPT);
@@ -2877,6 +2565,7 @@ static int btusb_mtk_setup(struct hci_dev *hdev)
                }
 
                hci_set_msft_opcode(hdev, 0xFD30);
+               hci_set_aosp_capable(hdev);
                goto done;
        default:
                bt_dev_err(hdev, "Unsupported hardware variant (%08x)",
@@ -2903,7 +2592,8 @@ static int btusb_mtk_setup(struct hci_dev *hdev)
        }
 
        /* Setup a firmware which the device definitely requires */
-       err = btusb_mtk_setup_firmware(hdev, fwname);
+       err = btmtk_setup_firmware(hdev, fwname,
+                                  btusb_mtk_hci_wmt_sync);
        if (err < 0)
                return err;
 
@@ -3064,9 +2754,6 @@ static int btusb_recv_acl_mtk(struct hci_dev *hdev, struct sk_buff *skb)
        return hci_recv_frame(hdev, skb);
 }
 
-MODULE_FIRMWARE(FIRMWARE_MT7663);
-MODULE_FIRMWARE(FIRMWARE_MT7668);
-
 #ifdef CONFIG_PM
 /* Configure an out-of-band gpio as wake-up pin, if specified in device tree */
 static int marvell_config_oob_wake(struct hci_dev *hdev)
@@ -3190,6 +2877,9 @@ static int btusb_set_bdaddr_wcn6855(struct hci_dev *hdev,
 #define QCA_DFU_TIMEOUT                3000
 #define QCA_FLAG_MULTI_NVM      0x80
 
+#define WCN6855_2_0_RAM_VERSION_GF 0x400c1200
+#define WCN6855_2_1_RAM_VERSION_GF 0x400c1211
+
 struct qca_version {
        __le32  rom_version;
        __le32  patch_version;
@@ -3221,6 +2911,7 @@ static const struct qca_device_info qca_devices_table[] = {
        { 0x00000302, 28, 4, 16 }, /* Rome 3.2 */
        { 0x00130100, 40, 4, 16 }, /* WCN6855 1.0 */
        { 0x00130200, 40, 4, 16 }, /* WCN6855 2.0 */
+       { 0x00130201, 40, 4, 16 }, /* WCN6855 2.1 */
 };
 
 static int btusb_qca_send_vendor_req(struct usb_device *udev, u8 request,
@@ -3375,6 +3066,40 @@ done:
        return err;
 }
 
+static void btusb_generate_qca_nvm_name(char *fwname, size_t max_size,
+                                       const struct qca_version *ver)
+{
+       u32 rom_version = le32_to_cpu(ver->rom_version);
+       u16 flag = le16_to_cpu(ver->flag);
+
+       if (((flag >> 8) & 0xff) == QCA_FLAG_MULTI_NVM) {
+               u16 board_id = le16_to_cpu(ver->board_id);
+               const char *variant;
+
+               switch (le32_to_cpu(ver->ram_version)) {
+               case WCN6855_2_0_RAM_VERSION_GF:
+               case WCN6855_2_1_RAM_VERSION_GF:
+                       variant = "_gf";
+                       break;
+               default:
+                       variant = "";
+                       break;
+               }
+
+               if (board_id == 0) {
+                       snprintf(fwname, max_size, "qca/nvm_usb_%08x%s.bin",
+                               rom_version, variant);
+               } else {
+                       snprintf(fwname, max_size, "qca/nvm_usb_%08x%s_%04x.bin",
+                               rom_version, variant, board_id);
+               }
+       } else {
+               snprintf(fwname, max_size, "qca/nvm_usb_%08x.bin",
+                       rom_version);
+       }
+
+}
+
 static int btusb_setup_qca_load_nvm(struct hci_dev *hdev,
                                    struct qca_version *ver,
                                    const struct qca_device_info *info)
@@ -3383,20 +3108,7 @@ static int btusb_setup_qca_load_nvm(struct hci_dev *hdev,
        char fwname[64];
        int err;
 
-       if (((ver->flag >> 8) & 0xff) == QCA_FLAG_MULTI_NVM) {
-               /* if boardid equal 0, use default nvm without surfix */
-               if (le16_to_cpu(ver->board_id) == 0x0) {
-                       snprintf(fwname, sizeof(fwname), "qca/nvm_usb_%08x.bin",
-                                le32_to_cpu(ver->rom_version));
-               } else {
-                       snprintf(fwname, sizeof(fwname), "qca/nvm_usb_%08x_%04x.bin",
-                               le32_to_cpu(ver->rom_version),
-                               le16_to_cpu(ver->board_id));
-               }
-       } else {
-               snprintf(fwname, sizeof(fwname), "qca/nvm_usb_%08x.bin",
-                        le32_to_cpu(ver->rom_version));
-       }
+       btusb_generate_qca_nvm_name(fwname, sizeof(fwname), ver);
 
        err = request_firmware(&fw, fwname, &hdev->dev);
        if (err) {
@@ -3868,7 +3580,7 @@ static int btusb_probe(struct usb_interface *intf,
                hdev->shutdown = btusb_mtk_shutdown;
                hdev->manufacturer = 70;
                hdev->cmd_timeout = btusb_mtk_cmd_timeout;
-               hdev->set_bdaddr = btusb_set_bdaddr_mtk;
+               hdev->set_bdaddr = btmtk_set_bdaddr;
                set_bit(HCI_QUIRK_NON_PERSISTENT_SETUP, &hdev->quirks);
                data->recv_acl = btusb_recv_acl_mtk;
        }
index ef54afa..7852abf 100644 (file)
@@ -1508,7 +1508,6 @@ static const struct of_device_id bcm_bluetooth_of_match[] = {
        { .compatible = "brcm,bcm4330-bt" },
        { .compatible = "brcm,bcm4334-bt" },
        { .compatible = "brcm,bcm4345c5" },
-       { .compatible = "brcm,bcm4330-bt" },
        { .compatible = "brcm,bcm43438-bt", .data = &bcm43438_device_data },
        { .compatible = "brcm,bcm43540-bt", .data = &bcm4354_device_data },
        { .compatible = "brcm,bcm4335a0" },
index 4b3b14a..1d0cdf0 100644 (file)
@@ -252,7 +252,7 @@ struct sk_buff *h4_recv_buf(struct hci_dev *hdev, struct sk_buff *skb,
                        }
 
                        if (!dlen) {
-                               hu->padding = (skb->len - 1) % alignment;
+                               hu->padding = (skb->len + 1) % alignment;
                                hu->padding = (alignment - hu->padding) % alignment;
 
                                /* No more data, complete frame */
@@ -260,7 +260,7 @@ struct sk_buff *h4_recv_buf(struct hci_dev *hdev, struct sk_buff *skb,
                                skb = NULL;
                        }
                } else {
-                       hu->padding = (skb->len - 1) % alignment;
+                       hu->padding = (skb->len + 1) % alignment;
                        hu->padding = (alignment - hu->padding) % alignment;
 
                        /* Complete frame */
index b45db0d..49ac884 100644 (file)
@@ -38,9 +38,12 @@ struct vhci_data {
 
        struct mutex open_mutex;
        struct delayed_work open_timeout;
+       struct work_struct suspend_work;
 
        bool suspended;
        bool wakeup;
+       __u16 msft_opcode;
+       bool aosp_capable;
 };
 
 static int vhci_open_dev(struct hci_dev *hdev)
@@ -114,6 +117,17 @@ static ssize_t force_suspend_read(struct file *file, char __user *user_buf,
        return simple_read_from_buffer(user_buf, count, ppos, buf, 2);
 }
 
+static void vhci_suspend_work(struct work_struct *work)
+{
+       struct vhci_data *data = container_of(work, struct vhci_data,
+                                             suspend_work);
+
+       if (data->suspended)
+               hci_suspend_dev(data->hdev);
+       else
+               hci_resume_dev(data->hdev);
+}
+
 static ssize_t force_suspend_write(struct file *file,
                                   const char __user *user_buf,
                                   size_t count, loff_t *ppos)
@@ -129,16 +143,10 @@ static ssize_t force_suspend_write(struct file *file,
        if (data->suspended == enable)
                return -EALREADY;
 
-       if (enable)
-               err = hci_suspend_dev(data->hdev);
-       else
-               err = hci_resume_dev(data->hdev);
-
-       if (err)
-               return err;
-
        data->suspended = enable;
 
+       schedule_work(&data->suspend_work);
+
        return count;
 }
 
@@ -176,6 +184,8 @@ static ssize_t force_wakeup_write(struct file *file,
        if (data->wakeup == enable)
                return -EALREADY;
 
+       data->wakeup = enable;
+
        return count;
 }
 
@@ -186,6 +196,88 @@ static const struct file_operations force_wakeup_fops = {
        .llseek         = default_llseek,
 };
 
+static int msft_opcode_set(void *data, u64 val)
+{
+       struct vhci_data *vhci = data;
+
+       if (val > 0xffff || hci_opcode_ogf(val) != 0x3f)
+               return -EINVAL;
+
+       if (vhci->msft_opcode)
+               return -EALREADY;
+
+       vhci->msft_opcode = val;
+
+       return 0;
+}
+
+static int msft_opcode_get(void *data, u64 *val)
+{
+       struct vhci_data *vhci = data;
+
+       *val = vhci->msft_opcode;
+
+       return 0;
+}
+
+DEFINE_DEBUGFS_ATTRIBUTE(msft_opcode_fops, msft_opcode_get, msft_opcode_set,
+                        "%llu\n");
+
+static ssize_t aosp_capable_read(struct file *file, char __user *user_buf,
+                                size_t count, loff_t *ppos)
+{
+       struct vhci_data *vhci = file->private_data;
+       char buf[3];
+
+       buf[0] = vhci->aosp_capable ? 'Y' : 'N';
+       buf[1] = '\n';
+       buf[2] = '\0';
+       return simple_read_from_buffer(user_buf, count, ppos, buf, 2);
+}
+
+static ssize_t aosp_capable_write(struct file *file,
+                                 const char __user *user_buf, size_t count,
+                                 loff_t *ppos)
+{
+       struct vhci_data *vhci = file->private_data;
+       bool enable;
+       int err;
+
+       err = kstrtobool_from_user(user_buf, count, &enable);
+       if (err)
+               return err;
+
+       if (!enable)
+               return -EINVAL;
+
+       if (vhci->aosp_capable)
+               return -EALREADY;
+
+       vhci->aosp_capable = enable;
+
+       return count;
+}
+
+static const struct file_operations aosp_capable_fops = {
+       .open           = simple_open,
+       .read           = aosp_capable_read,
+       .write          = aosp_capable_write,
+       .llseek         = default_llseek,
+};
+
+static int vhci_setup(struct hci_dev *hdev)
+{
+       struct vhci_data *vhci = hci_get_drvdata(hdev);
+
+       if (vhci->msft_opcode)
+               hci_set_msft_opcode(hdev, vhci->msft_opcode);
+
+       if (vhci->aosp_capable)
+               hci_set_aosp_capable(hdev);
+
+       return 0;
+}
+
 static int __vhci_create_device(struct vhci_data *data, __u8 opcode)
 {
        struct hci_dev *hdev;
@@ -228,6 +320,8 @@ static int __vhci_create_device(struct vhci_data *data, __u8 opcode)
        hdev->get_data_path_id = vhci_get_data_path_id;
        hdev->get_codec_config_data = vhci_get_codec_config_data;
        hdev->wakeup = vhci_wakeup;
+       hdev->setup = vhci_setup;
+       set_bit(HCI_QUIRK_NON_PERSISTENT_SETUP, &hdev->quirks);
 
        /* bit 6 is for external configuration */
        if (opcode & 0x40)
@@ -251,6 +345,14 @@ static int __vhci_create_device(struct vhci_data *data, __u8 opcode)
        debugfs_create_file("force_wakeup", 0644, hdev->debugfs, data,
                            &force_wakeup_fops);
 
+       if (IS_ENABLED(CONFIG_BT_MSFTEXT))
+               debugfs_create_file("msft_opcode", 0644, hdev->debugfs, data,
+                                   &msft_opcode_fops);
+
+       if (IS_ENABLED(CONFIG_BT_AOSPEXT))
+               debugfs_create_file("aosp_capable", 0644, hdev->debugfs, data,
+                                   &aosp_capable_fops);
+
        hci_skb_pkt_type(skb) = HCI_VENDOR_PKT;
 
        skb_put_u8(skb, 0xff);
@@ -440,6 +542,7 @@ static int vhci_open(struct inode *inode, struct file *file)
 
        mutex_init(&data->open_mutex);
        INIT_DELAYED_WORK(&data->open_timeout, vhci_open_timeout);
+       INIT_WORK(&data->suspend_work, vhci_suspend_work);
 
        file->private_data = data;
        nonseekable_open(inode, file);
@@ -455,6 +558,7 @@ static int vhci_release(struct inode *inode, struct file *file)
        struct hci_dev *hdev;
 
        cancel_delayed_work_sync(&data->open_timeout);
+       flush_work(&data->suspend_work);
 
        hdev = data->hdev;
 
index 57908ce..076e494 100644 (file)
@@ -202,6 +202,9 @@ static void virtbt_rx_handle(struct virtio_bluetooth *vbt, struct sk_buff *skb)
                hci_skb_pkt_type(skb) = pkt_type;
                hci_recv_frame(vbt->hdev, skb);
                break;
+       default:
+               kfree_skb(skb);
+               break;
        }
 }
 
index a85c9f0..53f0efa 100644 (file)
 #define SDIO_VENDOR_ID_MEDIATEK                        0x037a
 #define SDIO_DEVICE_ID_MEDIATEK_MT7663         0x7663
 #define SDIO_DEVICE_ID_MEDIATEK_MT7668         0x7668
+#define SDIO_DEVICE_ID_MEDIATEK_MT7961         0x7961
 
 #define SDIO_VENDOR_ID_MICROCHIP_WILC          0x0296
 #define SDIO_DEVICE_ID_MICROCHIP_WILC1000      0x5347
index 3271870..2f31e57 100644 (file)
@@ -380,6 +380,7 @@ typedef void (*hci_req_complete_skb_t)(struct hci_dev *hdev, u8 status,
 #define HCI_REQ_SKB    BIT(1)
 
 struct hci_ctrl {
+       struct sock *sk;
        u16 opcode;
        u8 req_flags;
        u8 req_event;
@@ -405,6 +406,7 @@ struct bt_skb_cb {
 #define hci_skb_pkt_type(skb) bt_cb((skb))->pkt_type
 #define hci_skb_expect(skb) bt_cb((skb))->expect
 #define hci_skb_opcode(skb) bt_cb((skb))->hci.opcode
+#define hci_skb_sk(skb) bt_cb((skb))->hci.sk
 
 static inline struct sk_buff *bt_skb_alloc(unsigned int len, gfp_t how)
 {
index 63065bc..84db6b2 100644 (file)
@@ -566,6 +566,7 @@ enum {
 #define HCI_ERROR_INVALID_LL_PARAMS    0x1e
 #define HCI_ERROR_UNSPECIFIED          0x1f
 #define HCI_ERROR_ADVERTISING_TIMEOUT  0x3c
+#define HCI_ERROR_CANCELLED_BY_HOST    0x44
 
 /* Flow control modes */
 #define HCI_FLOW_CTL_MODE_PACKET_BASED 0x00
index dd8840e..2560cfe 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/rculist.h>
 
 #include <net/bluetooth/hci.h>
+#include <net/bluetooth/hci_sync.h>
 #include <net/bluetooth/hci_sock.h>
 
 /* HCI priority */
@@ -475,6 +476,9 @@ struct hci_dev {
        struct work_struct      power_on;
        struct delayed_work     power_off;
        struct work_struct      error_reset;
+       struct work_struct      cmd_sync_work;
+       struct list_head        cmd_sync_work_list;
+       struct mutex            cmd_sync_work_lock;
 
        __u16                   discov_timeout;
        struct delayed_work     discov_off;
@@ -489,10 +493,7 @@ struct hci_dev {
        struct work_struct      tx_work;
 
        struct work_struct      discov_update;
-       struct work_struct      bg_scan_update;
        struct work_struct      scan_update;
-       struct work_struct      connectable_update;
-       struct work_struct      discoverable_update;
        struct delayed_work     le_scan_disable;
        struct delayed_work     le_scan_restart;
 
@@ -519,7 +520,6 @@ struct hci_dev {
        bool                    advertising_paused;
 
        struct notifier_block   suspend_notifier;
-       struct work_struct      suspend_prepare;
        enum suspended_state    suspend_state_next;
        enum suspended_state    suspend_state;
        bool                    scanning_paused;
@@ -528,9 +528,6 @@ struct hci_dev {
        bdaddr_t                wake_addr;
        u8                      wake_addr_type;
 
-       wait_queue_head_t       suspend_wait_q;
-       DECLARE_BITMAP(suspend_tasks, __SUSPEND_NUM_TASKS);
-
        struct hci_conn_hash    conn_hash;
 
        struct list_head        mgmt_pending;
@@ -603,6 +600,7 @@ struct hci_dev {
 
 #if IS_ENABLED(CONFIG_BT_AOSPEXT)
        bool                    aosp_capable;
+       bool                    aosp_quality_report;
 #endif
 
        int (*open)(struct hci_dev *hdev);
@@ -1461,8 +1459,11 @@ void hci_conn_del_sysfs(struct hci_conn *conn);
 #define scan_coded(dev) (((dev)->le_tx_def_phys & HCI_LE_SET_PHY_CODED) || \
                         ((dev)->le_rx_def_phys & HCI_LE_SET_PHY_CODED))
 
+#define ll_privacy_capable(dev) ((dev)->le_features[0] & HCI_LE_LL_PRIVACY)
+
 /* Use LL Privacy based address resolution if supported */
-#define use_ll_privacy(dev) ((dev)->le_features[0] & HCI_LE_LL_PRIVACY)
+#define use_ll_privacy(dev) (ll_privacy_capable(dev) && \
+                            hci_dev_test_flag(dev, HCI_ENABLE_LL_PRIVACY))
 
 /* Use enhanced synchronous connection if command is supported */
 #define enhanced_sco_capable(dev) ((dev)->commands[29] & 0x08)
@@ -1690,10 +1691,6 @@ static inline int hci_check_conn_params(u16 min, u16 max, u16 latency,
 int hci_register_cb(struct hci_cb *hcb);
 int hci_unregister_cb(struct hci_cb *hcb);
 
-struct sk_buff *__hci_cmd_sync(struct hci_dev *hdev, u16 opcode, u32 plen,
-                              const void *param, u32 timeout);
-struct sk_buff *__hci_cmd_sync_ev(struct hci_dev *hdev, u16 opcode, u32 plen,
-                                 const void *param, u8 event, u32 timeout);
 int __hci_cmd_send(struct hci_dev *hdev, u16 opcode, u32 plen,
                   const void *param);
 
@@ -1704,9 +1701,6 @@ void hci_send_sco(struct hci_conn *conn, struct sk_buff *skb);
 
 void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 opcode);
 
-struct sk_buff *hci_cmd_sync(struct hci_dev *hdev, u16 opcode, u32 plen,
-                            const void *param, u32 timeout);
-
 u32 hci_conn_get_phy(struct hci_conn *conn);
 
 /* ----- HCI Sockets ----- */
@@ -1806,7 +1800,6 @@ int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
                             u8 entered);
 void mgmt_auth_failed(struct hci_conn *conn, u8 status);
 void mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status);
-void mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status);
 void mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
                                    u8 status);
 void mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status);
@@ -1831,8 +1824,6 @@ void mgmt_new_conn_param(struct hci_dev *hdev, bdaddr_t *bdaddr,
                         u16 max_interval, u16 latency, u16 timeout);
 void mgmt_smp_complete(struct hci_conn *conn, bool complete);
 bool mgmt_get_connectable(struct hci_dev *hdev);
-void mgmt_set_connectable_complete(struct hci_dev *hdev, u8 status);
-void mgmt_set_discoverable_complete(struct hci_dev *hdev, u8 status);
 u8 mgmt_get_adv_discov_flags(struct hci_dev *hdev);
 void mgmt_advertising_added(struct sock *sk, struct hci_dev *hdev,
                            u8 instance);
diff --git a/include/net/bluetooth/hci_sync.h b/include/net/bluetooth/hci_sync.h
new file mode 100644 (file)
index 0000000..0336c1b
--- /dev/null
@@ -0,0 +1,102 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2021 Intel Corporation
+ */
+
+typedef int (*hci_cmd_sync_work_func_t)(struct hci_dev *hdev, void *data);
+typedef void (*hci_cmd_sync_work_destroy_t)(struct hci_dev *hdev, void *data,
+                                           int err);
+
+struct hci_cmd_sync_work_entry {
+       struct list_head list;
+       hci_cmd_sync_work_func_t func;
+       void *data;
+       hci_cmd_sync_work_destroy_t destroy;
+};
+
+/* Function with sync suffix shall not be called with hdev->lock held as they
+ * wait the command to complete and in the meantime an event could be received
+ * which could attempt to acquire hdev->lock causing a deadlock.
+ */
+struct sk_buff *__hci_cmd_sync(struct hci_dev *hdev, u16 opcode, u32 plen,
+                              const void *param, u32 timeout);
+struct sk_buff *hci_cmd_sync(struct hci_dev *hdev, u16 opcode, u32 plen,
+                            const void *param, u32 timeout);
+struct sk_buff *__hci_cmd_sync_ev(struct hci_dev *hdev, u16 opcode, u32 plen,
+                                 const void *param, u8 event, u32 timeout);
+struct sk_buff *__hci_cmd_sync_sk(struct hci_dev *hdev, u16 opcode, u32 plen,
+                                 const void *param, u8 event, u32 timeout,
+                                 struct sock *sk);
+int __hci_cmd_sync_status(struct hci_dev *hdev, u16 opcode, u32 plen,
+                         const void *param, u32 timeout);
+int __hci_cmd_sync_status_sk(struct hci_dev *hdev, u16 opcode, u32 plen,
+                            const void *param, u8 event, u32 timeout,
+                            struct sock *sk);
+
+void hci_cmd_sync_init(struct hci_dev *hdev);
+void hci_cmd_sync_clear(struct hci_dev *hdev);
+
+int hci_cmd_sync_queue(struct hci_dev *hdev, hci_cmd_sync_work_func_t func,
+                      void *data, hci_cmd_sync_work_destroy_t destroy);
+
+int hci_update_eir_sync(struct hci_dev *hdev);
+int hci_update_class_sync(struct hci_dev *hdev);
+
+int hci_update_eir_sync(struct hci_dev *hdev);
+int hci_update_class_sync(struct hci_dev *hdev);
+int hci_update_name_sync(struct hci_dev *hdev);
+int hci_write_ssp_mode_sync(struct hci_dev *hdev, u8 mode);
+
+int hci_update_random_address_sync(struct hci_dev *hdev, bool require_privacy,
+                                  bool rpa, u8 *own_addr_type);
+
+int hci_update_scan_rsp_data_sync(struct hci_dev *hdev, u8 instance);
+int hci_update_adv_data_sync(struct hci_dev *hdev, u8 instance);
+int hci_schedule_adv_instance_sync(struct hci_dev *hdev, u8 instance,
+                                  bool force);
+
+int hci_setup_ext_adv_instance_sync(struct hci_dev *hdev, u8 instance);
+int hci_start_ext_adv_sync(struct hci_dev *hdev, u8 instance);
+int hci_enable_ext_advertising_sync(struct hci_dev *hdev, u8 instance);
+int hci_enable_advertising_sync(struct hci_dev *hdev);
+int hci_enable_advertising(struct hci_dev *hdev);
+
+int hci_remove_advertising_sync(struct hci_dev *hdev, struct sock *sk,
+                               u8 instance, bool force);
+int hci_disable_advertising_sync(struct hci_dev *hdev);
+
+int hci_update_passive_scan_sync(struct hci_dev *hdev);
+int hci_update_passive_scan(struct hci_dev *hdev);
+int hci_read_rssi_sync(struct hci_dev *hdev, __le16 handle);
+int hci_read_tx_power_sync(struct hci_dev *hdev, __le16 handle, u8 type);
+int hci_write_sc_support_sync(struct hci_dev *hdev, u8 val);
+int hci_read_clock_sync(struct hci_dev *hdev, struct hci_cp_read_clock *cp);
+
+int hci_write_fast_connectable_sync(struct hci_dev *hdev, bool enable);
+int hci_update_scan_sync(struct hci_dev *hdev);
+
+int hci_write_le_host_supported_sync(struct hci_dev *hdev, u8 le, u8 simul);
+int hci_remove_ext_adv_instance_sync(struct hci_dev *hdev, u8 instance,
+                                    struct sock *sk);
+struct sk_buff *hci_read_local_oob_data_sync(struct hci_dev *hdev, bool ext,
+                                            struct sock *sk);
+
+int hci_reset_sync(struct hci_dev *hdev);
+int hci_dev_open_sync(struct hci_dev *hdev);
+int hci_dev_close_sync(struct hci_dev *hdev);
+
+int hci_powered_update_sync(struct hci_dev *hdev);
+int hci_set_powered_sync(struct hci_dev *hdev, u8 val);
+
+int hci_update_discoverable_sync(struct hci_dev *hdev);
+int hci_update_discoverable(struct hci_dev *hdev);
+
+int hci_update_connectable_sync(struct hci_dev *hdev);
+
+int hci_start_discovery_sync(struct hci_dev *hdev);
+int hci_stop_discovery_sync(struct hci_dev *hdev);
+
+int hci_suspend_sync(struct hci_dev *hdev);
+int hci_resume_sync(struct hci_dev *hdev);
index 291770f..a52bba8 100644 (file)
@@ -15,7 +15,7 @@ bluetooth_6lowpan-y := 6lowpan.o
 bluetooth-y := af_bluetooth.o hci_core.o hci_conn.o hci_event.o mgmt.o \
        hci_sock.o hci_sysfs.o l2cap_core.o l2cap_sock.o smp.o lib.o \
        ecdh_helper.o hci_request.o mgmt_util.o mgmt_config.o hci_codec.o \
-       eir.o
+       eir.o hci_sync.o
 
 bluetooth-$(CONFIG_BT_BREDR) += sco.o
 bluetooth-$(CONFIG_BT_HS) += a2mp.o amp.o
index a1b7762..432ae3a 100644 (file)
@@ -8,9 +8,43 @@
 
 #include "aosp.h"
 
+/* Command complete parameters of LE_Get_Vendor_Capabilities_Command
+ * The parameters grow over time. The base version that declares the
+ * version_supported field is v0.95. Refer to
+ * https://cs.android.com/android/platform/superproject/+/master:system/
+ *         bt/gd/hci/controller.cc;l=452?q=le_get_vendor_capabilities_handler
+ */
+struct aosp_rp_le_get_vendor_capa {
+       /* v0.95: 15 octets */
+       __u8    status;
+       __u8    max_advt_instances;
+       __u8    offloaded_resolution_of_private_address;
+       __le16  total_scan_results_storage;
+       __u8    max_irk_list_sz;
+       __u8    filtering_support;
+       __u8    max_filter;
+       __u8    activity_energy_info_support;
+       __le16  version_supported;
+       __le16  total_num_of_advt_tracked;
+       __u8    extended_scan_support;
+       __u8    debug_logging_supported;
+       /* v0.96: 16 octets */
+       __u8    le_address_generation_offloading_support;
+       /* v0.98: 21 octets */
+       __le32  a2dp_source_offload_capability_mask;
+       __u8    bluetooth_quality_report_support;
+       /* v1.00: 25 octets */
+       __le32  dynamic_audio_buffer_support;
+} __packed;
+
+#define VENDOR_CAPA_BASE_SIZE          15
+#define VENDOR_CAPA_0_98_SIZE          21
+
 void aosp_do_open(struct hci_dev *hdev)
 {
        struct sk_buff *skb;
+       struct aosp_rp_le_get_vendor_capa *rp;
+       u16 version_supported;
 
        if (!hdev->aosp_capable)
                return;
@@ -20,9 +54,54 @@ void aosp_do_open(struct hci_dev *hdev)
        /* LE Get Vendor Capabilities Command */
        skb = __hci_cmd_sync(hdev, hci_opcode_pack(0x3f, 0x153), 0, NULL,
                             HCI_CMD_TIMEOUT);
-       if (IS_ERR(skb))
+       if (IS_ERR(skb)) {
+               bt_dev_err(hdev, "AOSP get vendor capabilities (%ld)",
+                          PTR_ERR(skb));
                return;
+       }
+
+       /* A basic length check */
+       if (skb->len < VENDOR_CAPA_BASE_SIZE)
+               goto length_error;
+
+       rp = (struct aosp_rp_le_get_vendor_capa *)skb->data;
+
+       version_supported = le16_to_cpu(rp->version_supported);
+       /* AOSP displays the verion number like v0.98, v1.00, etc. */
+       bt_dev_info(hdev, "AOSP extensions version v%u.%02u",
+                   version_supported >> 8, version_supported & 0xff);
+
+       /* Do not support very old versions. */
+       if (version_supported < 95) {
+               bt_dev_warn(hdev, "AOSP capabilities version %u too old",
+                           version_supported);
+               goto done;
+       }
+
+       if (version_supported < 98) {
+               bt_dev_warn(hdev, "AOSP quality report is not supported");
+               goto done;
+       }
+
+       if (skb->len < VENDOR_CAPA_0_98_SIZE)
+               goto length_error;
+
+       /* The bluetooth_quality_report_support is defined at version
+        * v0.98. Refer to
+        * https://cs.android.com/android/platform/superproject/+/
+        *         master:system/bt/gd/hci/controller.cc;l=477
+        */
+       if (rp->bluetooth_quality_report_support) {
+               hdev->aosp_quality_report = true;
+               bt_dev_info(hdev, "AOSP quality report is supported");
+       }
+
+       goto done;
+
+length_error:
+       bt_dev_err(hdev, "AOSP capabilities length %d too short", skb->len);
 
+done:
        kfree_skb(skb);
 }
 
@@ -33,3 +112,90 @@ void aosp_do_close(struct hci_dev *hdev)
 
        bt_dev_dbg(hdev, "Cleanup of AOSP extension");
 }
+
+/* BQR command */
+#define BQR_OPCODE                     hci_opcode_pack(0x3f, 0x015e)
+
+/* BQR report action */
+#define REPORT_ACTION_ADD              0x00
+#define REPORT_ACTION_DELETE           0x01
+#define REPORT_ACTION_CLEAR            0x02
+
+/* BQR event masks */
+#define QUALITY_MONITORING             BIT(0)
+#define APPRAOCHING_LSTO               BIT(1)
+#define A2DP_AUDIO_CHOPPY              BIT(2)
+#define SCO_VOICE_CHOPPY               BIT(3)
+
+#define DEFAULT_BQR_EVENT_MASK (QUALITY_MONITORING | APPRAOCHING_LSTO | \
+                                A2DP_AUDIO_CHOPPY | SCO_VOICE_CHOPPY)
+
+/* Reporting at milliseconds so as not to stress the controller too much.
+ * Range: 0 ~ 65535 ms
+ */
+#define DEFALUT_REPORT_INTERVAL_MS     5000
+
+struct aosp_bqr_cp {
+       __u8    report_action;
+       __u32   event_mask;
+       __u16   min_report_interval;
+} __packed;
+
+static int enable_quality_report(struct hci_dev *hdev)
+{
+       struct sk_buff *skb;
+       struct aosp_bqr_cp cp;
+
+       cp.report_action = REPORT_ACTION_ADD;
+       cp.event_mask = DEFAULT_BQR_EVENT_MASK;
+       cp.min_report_interval = DEFALUT_REPORT_INTERVAL_MS;
+
+       skb = __hci_cmd_sync(hdev, BQR_OPCODE, sizeof(cp), &cp,
+                            HCI_CMD_TIMEOUT);
+       if (IS_ERR(skb)) {
+               bt_dev_err(hdev, "Enabling Android BQR failed (%ld)",
+                          PTR_ERR(skb));
+               return PTR_ERR(skb);
+       }
+
+       kfree_skb(skb);
+       return 0;
+}
+
+static int disable_quality_report(struct hci_dev *hdev)
+{
+       struct sk_buff *skb;
+       struct aosp_bqr_cp cp = { 0 };
+
+       cp.report_action = REPORT_ACTION_CLEAR;
+
+       skb = __hci_cmd_sync(hdev, BQR_OPCODE, sizeof(cp), &cp,
+                            HCI_CMD_TIMEOUT);
+       if (IS_ERR(skb)) {
+               bt_dev_err(hdev, "Disabling Android BQR failed (%ld)",
+                          PTR_ERR(skb));
+               return PTR_ERR(skb);
+       }
+
+       kfree_skb(skb);
+       return 0;
+}
+
+bool aosp_has_quality_report(struct hci_dev *hdev)
+{
+       return hdev->aosp_quality_report;
+}
+
+int aosp_set_quality_report(struct hci_dev *hdev, bool enable)
+{
+       if (!aosp_has_quality_report(hdev))
+               return -EOPNOTSUPP;
+
+       bt_dev_dbg(hdev, "quality report enable %d", enable);
+
+       /* Enable or disable the quality report feature. */
+       if (enable)
+               return enable_quality_report(hdev);
+       else
+               return disable_quality_report(hdev);
+}
index 328fc6d..2fd8886 100644 (file)
@@ -8,9 +8,22 @@
 void aosp_do_open(struct hci_dev *hdev);
 void aosp_do_close(struct hci_dev *hdev);
 
+bool aosp_has_quality_report(struct hci_dev *hdev);
+int aosp_set_quality_report(struct hci_dev *hdev, bool enable);
+
 #else
 
 static inline void aosp_do_open(struct hci_dev *hdev) {}
 static inline void aosp_do_close(struct hci_dev *hdev) {}
 
+static inline bool aosp_has_quality_report(struct hci_dev *hdev)
+{
+       return false;
+}
+
+static inline int aosp_set_quality_report(struct hci_dev *hdev, bool enable)
+{
+       return -EOPNOTSUPP;
+}
+
 #endif
index 0a2d78e..83eb84e 100644 (file)
@@ -501,9 +501,7 @@ static int __init cmtp_init(void)
 {
        BT_INFO("CMTP (CAPI Emulation) ver %s", VERSION);
 
-       cmtp_init_sockets();
-
-       return 0;
+       return cmtp_init_sockets();
 }
 
 static void __exit cmtp_exit(void)
index f0421d0..3820153 100644 (file)
@@ -25,9 +25,11 @@ static int hci_codec_list_add(struct list_head *list,
        }
        entry->transport = sent->transport;
        entry->len = len;
-       entry->num_caps = rp->num_caps;
-       if (rp->num_caps)
+       entry->num_caps = 0;
+       if (rp) {
+               entry->num_caps = rp->num_caps;
                memcpy(entry->caps, caps, len);
+       }
        list_add(&entry->list, list);
 
        return 0;
@@ -58,6 +60,18 @@ static void hci_read_codec_capabilities(struct hci_dev *hdev, __u8 transport,
                        __u32 len;
 
                        cmd->transport = i;
+
+                       /* If Read_Codec_Capabilities command is not supported
+                        * then just add codec to the list without caps
+                        */
+                       if (!(hdev->commands[45] & 0x08)) {
+                               hci_dev_lock(hdev);
+                               hci_codec_list_add(&hdev->local_codecs, cmd,
+                                                  NULL, NULL, 0);
+                               hci_dev_unlock(hdev);
+                               continue;
+                       }
+
                        skb = __hci_cmd_sync(hdev, HCI_OP_READ_LOCAL_CODEC_CAPS,
                                             sizeof(*cmd), cmd,
                                             HCI_CMD_TIMEOUT);
index bd669c9..cd6e1cf 100644 (file)
@@ -108,7 +108,7 @@ static void hci_connect_le_scan_cleanup(struct hci_conn *conn)
                break;
        }
 
-       hci_update_background_scan(hdev);
+       hci_update_passive_scan(hdev);
 }
 
 static void hci_conn_cleanup(struct hci_conn *conn)
@@ -900,25 +900,15 @@ void hci_le_conn_failed(struct hci_conn *conn, u8 status)
 
        hci_conn_del(conn);
 
-       /* The suspend notifier is waiting for all devices to disconnect and an
-        * LE connect cancel will result in an hci_le_conn_failed. Once the last
-        * connection is deleted, we should also wake the suspend queue to
-        * complete suspend operations.
-        */
-       if (list_empty(&hdev->conn_hash.list) &&
-           test_and_clear_bit(SUSPEND_DISCONNECTING, hdev->suspend_tasks)) {
-               wake_up(&hdev->suspend_wait_q);
-       }
-
        /* Since we may have temporarily stopped the background scanning in
         * favor of connection establishment, we should restart it.
         */
-       hci_update_background_scan(hdev);
+       hci_update_passive_scan(hdev);
 
-       /* Re-enable advertising in case this was a failed connection
+       /* Enable advertising in case this was a failed connection
         * attempt as a peripheral.
         */
-       hci_req_reenable_advertising(hdev);
+       hci_enable_advertising(hdev);
 }
 
 static void create_le_conn_complete(struct hci_dev *hdev, u8 status, u16 opcode)
@@ -1411,7 +1401,7 @@ struct hci_conn *hci_connect_le_scan(struct hci_dev *hdev, bdaddr_t *dst,
        conn->conn_timeout = conn_timeout;
        conn->conn_reason = conn_reason;
 
-       hci_update_background_scan(hdev);
+       hci_update_passive_scan(hdev);
 
 done:
        hci_conn_hold(conn);
index 8d33aa6..fdc0dcf 100644 (file)
@@ -62,824 +62,6 @@ DEFINE_MUTEX(hci_cb_list_lock);
 /* HCI ID Numbering */
 static DEFINE_IDA(hci_index_ida);
 
-static int hci_reset_req(struct hci_request *req, unsigned long opt)
-{
-       BT_DBG("%s %ld", req->hdev->name, opt);
-
-       /* Reset device */
-       set_bit(HCI_RESET, &req->hdev->flags);
-       hci_req_add(req, HCI_OP_RESET, 0, NULL);
-       return 0;
-}
-
-static void bredr_init(struct hci_request *req)
-{
-       req->hdev->flow_ctl_mode = HCI_FLOW_CTL_MODE_PACKET_BASED;
-
-       /* Read Local Supported Features */
-       hci_req_add(req, HCI_OP_READ_LOCAL_FEATURES, 0, NULL);
-
-       /* Read Local Version */
-       hci_req_add(req, HCI_OP_READ_LOCAL_VERSION, 0, NULL);
-
-       /* Read BD Address */
-       hci_req_add(req, HCI_OP_READ_BD_ADDR, 0, NULL);
-}
-
-static void amp_init1(struct hci_request *req)
-{
-       req->hdev->flow_ctl_mode = HCI_FLOW_CTL_MODE_BLOCK_BASED;
-
-       /* Read Local Version */
-       hci_req_add(req, HCI_OP_READ_LOCAL_VERSION, 0, NULL);
-
-       /* Read Local Supported Commands */
-       hci_req_add(req, HCI_OP_READ_LOCAL_COMMANDS, 0, NULL);
-
-       /* Read Local AMP Info */
-       hci_req_add(req, HCI_OP_READ_LOCAL_AMP_INFO, 0, NULL);
-
-       /* Read Data Blk size */
-       hci_req_add(req, HCI_OP_READ_DATA_BLOCK_SIZE, 0, NULL);
-
-       /* Read Flow Control Mode */
-       hci_req_add(req, HCI_OP_READ_FLOW_CONTROL_MODE, 0, NULL);
-
-       /* Read Location Data */
-       hci_req_add(req, HCI_OP_READ_LOCATION_DATA, 0, NULL);
-}
-
-static int amp_init2(struct hci_request *req)
-{
-       /* Read Local Supported Features. Not all AMP controllers
-        * support this so it's placed conditionally in the second
-        * stage init.
-        */
-       if (req->hdev->commands[14] & 0x20)
-               hci_req_add(req, HCI_OP_READ_LOCAL_FEATURES, 0, NULL);
-
-       return 0;
-}
-
-static int hci_init1_req(struct hci_request *req, unsigned long opt)
-{
-       struct hci_dev *hdev = req->hdev;
-
-       BT_DBG("%s %ld", hdev->name, opt);
-
-       /* Reset */
-       if (!test_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks))
-               hci_reset_req(req, 0);
-
-       switch (hdev->dev_type) {
-       case HCI_PRIMARY:
-               bredr_init(req);
-               break;
-       case HCI_AMP:
-               amp_init1(req);
-               break;
-       default:
-               bt_dev_err(hdev, "Unknown device type %d", hdev->dev_type);
-               break;
-       }
-
-       return 0;
-}
-
-static void bredr_setup(struct hci_request *req)
-{
-       __le16 param;
-       __u8 flt_type;
-
-       /* Read Buffer Size (ACL mtu, max pkt, etc.) */
-       hci_req_add(req, HCI_OP_READ_BUFFER_SIZE, 0, NULL);
-
-       /* Read Class of Device */
-       hci_req_add(req, HCI_OP_READ_CLASS_OF_DEV, 0, NULL);
-
-       /* Read Local Name */
-       hci_req_add(req, HCI_OP_READ_LOCAL_NAME, 0, NULL);
-
-       /* Read Voice Setting */
-       hci_req_add(req, HCI_OP_READ_VOICE_SETTING, 0, NULL);
-
-       /* Read Number of Supported IAC */
-       hci_req_add(req, HCI_OP_READ_NUM_SUPPORTED_IAC, 0, NULL);
-
-       /* Read Current IAC LAP */
-       hci_req_add(req, HCI_OP_READ_CURRENT_IAC_LAP, 0, NULL);
-
-       /* Clear Event Filters */
-       flt_type = HCI_FLT_CLEAR_ALL;
-       hci_req_add(req, HCI_OP_SET_EVENT_FLT, 1, &flt_type);
-
-       /* Connection accept timeout ~20 secs */
-       param = cpu_to_le16(0x7d00);
-       hci_req_add(req, HCI_OP_WRITE_CA_TIMEOUT, 2, &param);
-}
-
-static void le_setup(struct hci_request *req)
-{
-       struct hci_dev *hdev = req->hdev;
-
-       /* Read LE Buffer Size */
-       hci_req_add(req, HCI_OP_LE_READ_BUFFER_SIZE, 0, NULL);
-
-       /* Read LE Local Supported Features */
-       hci_req_add(req, HCI_OP_LE_READ_LOCAL_FEATURES, 0, NULL);
-
-       /* Read LE Supported States */
-       hci_req_add(req, HCI_OP_LE_READ_SUPPORTED_STATES, 0, NULL);
-
-       /* LE-only controllers have LE implicitly enabled */
-       if (!lmp_bredr_capable(hdev))
-               hci_dev_set_flag(hdev, HCI_LE_ENABLED);
-}
-
-static void hci_setup_event_mask(struct hci_request *req)
-{
-       struct hci_dev *hdev = req->hdev;
-
-       /* The second byte is 0xff instead of 0x9f (two reserved bits
-        * disabled) since a Broadcom 1.2 dongle doesn't respond to the
-        * command otherwise.
-        */
-       u8 events[8] = { 0xff, 0xff, 0xfb, 0xff, 0x00, 0x00, 0x00, 0x00 };
-
-       /* CSR 1.1 dongles does not accept any bitfield so don't try to set
-        * any event mask for pre 1.2 devices.
-        */
-       if (hdev->hci_ver < BLUETOOTH_VER_1_2)
-               return;
-
-       if (lmp_bredr_capable(hdev)) {
-               events[4] |= 0x01; /* Flow Specification Complete */
-       } else {
-               /* Use a different default for LE-only devices */
-               memset(events, 0, sizeof(events));
-               events[1] |= 0x20; /* Command Complete */
-               events[1] |= 0x40; /* Command Status */
-               events[1] |= 0x80; /* Hardware Error */
-
-               /* If the controller supports the Disconnect command, enable
-                * the corresponding event. In addition enable packet flow
-                * control related events.
-                */
-               if (hdev->commands[0] & 0x20) {
-                       events[0] |= 0x10; /* Disconnection Complete */
-                       events[2] |= 0x04; /* Number of Completed Packets */
-                       events[3] |= 0x02; /* Data Buffer Overflow */
-               }
-
-               /* If the controller supports the Read Remote Version
-                * Information command, enable the corresponding event.
-                */
-               if (hdev->commands[2] & 0x80)
-                       events[1] |= 0x08; /* Read Remote Version Information
-                                           * Complete
-                                           */
-
-               if (hdev->le_features[0] & HCI_LE_ENCRYPTION) {
-                       events[0] |= 0x80; /* Encryption Change */
-                       events[5] |= 0x80; /* Encryption Key Refresh Complete */
-               }
-       }
-
-       if (lmp_inq_rssi_capable(hdev) ||
-           test_bit(HCI_QUIRK_FIXUP_INQUIRY_MODE, &hdev->quirks))
-               events[4] |= 0x02; /* Inquiry Result with RSSI */
-
-       if (lmp_ext_feat_capable(hdev))
-               events[4] |= 0x04; /* Read Remote Extended Features Complete */
-
-       if (lmp_esco_capable(hdev)) {
-               events[5] |= 0x08; /* Synchronous Connection Complete */
-               events[5] |= 0x10; /* Synchronous Connection Changed */
-       }
-
-       if (lmp_sniffsubr_capable(hdev))
-               events[5] |= 0x20; /* Sniff Subrating */
-
-       if (lmp_pause_enc_capable(hdev))
-               events[5] |= 0x80; /* Encryption Key Refresh Complete */
-
-       if (lmp_ext_inq_capable(hdev))
-               events[5] |= 0x40; /* Extended Inquiry Result */
-
-       if (lmp_no_flush_capable(hdev))
-               events[7] |= 0x01; /* Enhanced Flush Complete */
-
-       if (lmp_lsto_capable(hdev))
-               events[6] |= 0x80; /* Link Supervision Timeout Changed */
-
-       if (lmp_ssp_capable(hdev)) {
-               events[6] |= 0x01;      /* IO Capability Request */
-               events[6] |= 0x02;      /* IO Capability Response */
-               events[6] |= 0x04;      /* User Confirmation Request */
-               events[6] |= 0x08;      /* User Passkey Request */
-               events[6] |= 0x10;      /* Remote OOB Data Request */
-               events[6] |= 0x20;      /* Simple Pairing Complete */
-               events[7] |= 0x04;      /* User Passkey Notification */
-               events[7] |= 0x08;      /* Keypress Notification */
-               events[7] |= 0x10;      /* Remote Host Supported
-                                        * Features Notification
-                                        */
-       }
-
-       if (lmp_le_capable(hdev))
-               events[7] |= 0x20;      /* LE Meta-Event */
-
-       hci_req_add(req, HCI_OP_SET_EVENT_MASK, sizeof(events), events);
-}
-
-static int hci_init2_req(struct hci_request *req, unsigned long opt)
-{
-       struct hci_dev *hdev = req->hdev;
-
-       if (hdev->dev_type == HCI_AMP)
-               return amp_init2(req);
-
-       if (lmp_bredr_capable(hdev))
-               bredr_setup(req);
-       else
-               hci_dev_clear_flag(hdev, HCI_BREDR_ENABLED);
-
-       if (lmp_le_capable(hdev))
-               le_setup(req);
-
-       /* All Bluetooth 1.2 and later controllers should support the
-        * HCI command for reading the local supported commands.
-        *
-        * Unfortunately some controllers indicate Bluetooth 1.2 support,
-        * but do not have support for this command. If that is the case,
-        * the driver can quirk the behavior and skip reading the local
-        * supported commands.
-        */
-       if (hdev->hci_ver > BLUETOOTH_VER_1_1 &&
-           !test_bit(HCI_QUIRK_BROKEN_LOCAL_COMMANDS, &hdev->quirks))
-               hci_req_add(req, HCI_OP_READ_LOCAL_COMMANDS, 0, NULL);
-
-       if (lmp_ssp_capable(hdev)) {
-               /* When SSP is available, then the host features page
-                * should also be available as well. However some
-                * controllers list the max_page as 0 as long as SSP
-                * has not been enabled. To achieve proper debugging
-                * output, force the minimum max_page to 1 at least.
-                */
-               hdev->max_page = 0x01;
-
-               if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
-                       u8 mode = 0x01;
-
-                       hci_req_add(req, HCI_OP_WRITE_SSP_MODE,
-                                   sizeof(mode), &mode);
-               } else {
-                       struct hci_cp_write_eir cp;
-
-                       memset(hdev->eir, 0, sizeof(hdev->eir));
-                       memset(&cp, 0, sizeof(cp));
-
-                       hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
-               }
-       }
-
-       if (lmp_inq_rssi_capable(hdev) ||
-           test_bit(HCI_QUIRK_FIXUP_INQUIRY_MODE, &hdev->quirks)) {
-               u8 mode;
-
-               /* If Extended Inquiry Result events are supported, then
-                * they are clearly preferred over Inquiry Result with RSSI
-                * events.
-                */
-               mode = lmp_ext_inq_capable(hdev) ? 0x02 : 0x01;
-
-               hci_req_add(req, HCI_OP_WRITE_INQUIRY_MODE, 1, &mode);
-       }
-
-       if (lmp_inq_tx_pwr_capable(hdev))
-               hci_req_add(req, HCI_OP_READ_INQ_RSP_TX_POWER, 0, NULL);
-
-       if (lmp_ext_feat_capable(hdev)) {
-               struct hci_cp_read_local_ext_features cp;
-
-               cp.page = 0x01;
-               hci_req_add(req, HCI_OP_READ_LOCAL_EXT_FEATURES,
-                           sizeof(cp), &cp);
-       }
-
-       if (hci_dev_test_flag(hdev, HCI_LINK_SECURITY)) {
-               u8 enable = 1;
-               hci_req_add(req, HCI_OP_WRITE_AUTH_ENABLE, sizeof(enable),
-                           &enable);
-       }
-
-       return 0;
-}
-
-static void hci_setup_link_policy(struct hci_request *req)
-{
-       struct hci_dev *hdev = req->hdev;
-       struct hci_cp_write_def_link_policy cp;
-       u16 link_policy = 0;
-
-       if (lmp_rswitch_capable(hdev))
-               link_policy |= HCI_LP_RSWITCH;
-       if (lmp_hold_capable(hdev))
-               link_policy |= HCI_LP_HOLD;
-       if (lmp_sniff_capable(hdev))
-               link_policy |= HCI_LP_SNIFF;
-       if (lmp_park_capable(hdev))
-               link_policy |= HCI_LP_PARK;
-
-       cp.policy = cpu_to_le16(link_policy);
-       hci_req_add(req, HCI_OP_WRITE_DEF_LINK_POLICY, sizeof(cp), &cp);
-}
-
-static void hci_set_le_support(struct hci_request *req)
-{
-       struct hci_dev *hdev = req->hdev;
-       struct hci_cp_write_le_host_supported cp;
-
-       /* LE-only devices do not support explicit enablement */
-       if (!lmp_bredr_capable(hdev))
-               return;
-
-       memset(&cp, 0, sizeof(cp));
-
-       if (hci_dev_test_flag(hdev, HCI_LE_ENABLED)) {
-               cp.le = 0x01;
-               cp.simul = 0x00;
-       }
-
-       if (cp.le != lmp_host_le_capable(hdev))
-               hci_req_add(req, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(cp),
-                           &cp);
-}
-
-static void hci_set_event_mask_page_2(struct hci_request *req)
-{
-       struct hci_dev *hdev = req->hdev;
-       u8 events[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
-       bool changed = false;
-
-       /* If Connectionless Peripheral Broadcast central role is supported
-        * enable all necessary events for it.
-        */
-       if (lmp_cpb_central_capable(hdev)) {
-               events[1] |= 0x40;      /* Triggered Clock Capture */
-               events[1] |= 0x80;      /* Synchronization Train Complete */
-               events[2] |= 0x10;      /* Peripheral Page Response Timeout */
-               events[2] |= 0x20;      /* CPB Channel Map Change */
-               changed = true;
-       }
-
-       /* If Connectionless Peripheral Broadcast peripheral role is supported
-        * enable all necessary events for it.
-        */
-       if (lmp_cpb_peripheral_capable(hdev)) {
-               events[2] |= 0x01;      /* Synchronization Train Received */
-               events[2] |= 0x02;      /* CPB Receive */
-               events[2] |= 0x04;      /* CPB Timeout */
-               events[2] |= 0x08;      /* Truncated Page Complete */
-               changed = true;
-       }
-
-       /* Enable Authenticated Payload Timeout Expired event if supported */
-       if (lmp_ping_capable(hdev) || hdev->le_features[0] & HCI_LE_PING) {
-               events[2] |= 0x80;
-               changed = true;
-       }
-
-       /* Some Broadcom based controllers indicate support for Set Event
-        * Mask Page 2 command, but then actually do not support it. Since
-        * the default value is all bits set to zero, the command is only
-        * required if the event mask has to be changed. In case no change
-        * to the event mask is needed, skip this command.
-        */
-       if (changed)
-               hci_req_add(req, HCI_OP_SET_EVENT_MASK_PAGE_2,
-                           sizeof(events), events);
-}
-
-static int hci_init3_req(struct hci_request *req, unsigned long opt)
-{
-       struct hci_dev *hdev = req->hdev;
-       u8 p;
-
-       hci_setup_event_mask(req);
-
-       if (hdev->commands[6] & 0x20 &&
-           !test_bit(HCI_QUIRK_BROKEN_STORED_LINK_KEY, &hdev->quirks)) {
-               struct hci_cp_read_stored_link_key cp;
-
-               bacpy(&cp.bdaddr, BDADDR_ANY);
-               cp.read_all = 0x01;
-               hci_req_add(req, HCI_OP_READ_STORED_LINK_KEY, sizeof(cp), &cp);
-       }
-
-       if (hdev->commands[5] & 0x10)
-               hci_setup_link_policy(req);
-
-       if (hdev->commands[8] & 0x01)
-               hci_req_add(req, HCI_OP_READ_PAGE_SCAN_ACTIVITY, 0, NULL);
-
-       if (hdev->commands[18] & 0x04 &&
-           !test_bit(HCI_QUIRK_BROKEN_ERR_DATA_REPORTING, &hdev->quirks))
-               hci_req_add(req, HCI_OP_READ_DEF_ERR_DATA_REPORTING, 0, NULL);
-
-       /* Some older Broadcom based Bluetooth 1.2 controllers do not
-        * support the Read Page Scan Type command. Check support for
-        * this command in the bit mask of supported commands.
-        */
-       if (hdev->commands[13] & 0x01)
-               hci_req_add(req, HCI_OP_READ_PAGE_SCAN_TYPE, 0, NULL);
-
-       if (lmp_le_capable(hdev)) {
-               u8 events[8];
-
-               memset(events, 0, sizeof(events));
-
-               if (hdev->le_features[0] & HCI_LE_ENCRYPTION)
-                       events[0] |= 0x10;      /* LE Long Term Key Request */
-
-               /* If controller supports the Connection Parameters Request
-                * Link Layer Procedure, enable the corresponding event.
-                */
-               if (hdev->le_features[0] & HCI_LE_CONN_PARAM_REQ_PROC)
-                       events[0] |= 0x20;      /* LE Remote Connection
-                                                * Parameter Request
-                                                */
-
-               /* If the controller supports the Data Length Extension
-                * feature, enable the corresponding event.
-                */
-               if (hdev->le_features[0] & HCI_LE_DATA_LEN_EXT)
-                       events[0] |= 0x40;      /* LE Data Length Change */
-
-               /* If the controller supports LL Privacy feature, enable
-                * the corresponding event.
-                */
-               if (hdev->le_features[0] & HCI_LE_LL_PRIVACY)
-                       events[1] |= 0x02;      /* LE Enhanced Connection
-                                                * Complete
-                                                */
-
-               /* If the controller supports Extended Scanner Filter
-                * Policies, enable the corresponding event.
-                */
-               if (hdev->le_features[0] & HCI_LE_EXT_SCAN_POLICY)
-                       events[1] |= 0x04;      /* LE Direct Advertising
-                                                * Report
-                                                */
-
-               /* If the controller supports Channel Selection Algorithm #2
-                * feature, enable the corresponding event.
-                */
-               if (hdev->le_features[1] & HCI_LE_CHAN_SEL_ALG2)
-                       events[2] |= 0x08;      /* LE Channel Selection
-                                                * Algorithm
-                                                */
-
-               /* If the controller supports the LE Set Scan Enable command,
-                * enable the corresponding advertising report event.
-                */
-               if (hdev->commands[26] & 0x08)
-                       events[0] |= 0x02;      /* LE Advertising Report */
-
-               /* If the controller supports the LE Create Connection
-                * command, enable the corresponding event.
-                */
-               if (hdev->commands[26] & 0x10)
-                       events[0] |= 0x01;      /* LE Connection Complete */
-
-               /* If the controller supports the LE Connection Update
-                * command, enable the corresponding event.
-                */
-               if (hdev->commands[27] & 0x04)
-                       events[0] |= 0x04;      /* LE Connection Update
-                                                * Complete
-                                                */
-
-               /* If the controller supports the LE Read Remote Used Features
-                * command, enable the corresponding event.
-                */
-               if (hdev->commands[27] & 0x20)
-                       events[0] |= 0x08;      /* LE Read Remote Used
-                                                * Features Complete
-                                                */
-
-               /* If the controller supports the LE Read Local P-256
-                * Public Key command, enable the corresponding event.
-                */
-               if (hdev->commands[34] & 0x02)
-                       events[0] |= 0x80;      /* LE Read Local P-256
-                                                * Public Key Complete
-                                                */
-
-               /* If the controller supports the LE Generate DHKey
-                * command, enable the corresponding event.
-                */
-               if (hdev->commands[34] & 0x04)
-                       events[1] |= 0x01;      /* LE Generate DHKey Complete */
-
-               /* If the controller supports the LE Set Default PHY or
-                * LE Set PHY commands, enable the corresponding event.
-                */
-               if (hdev->commands[35] & (0x20 | 0x40))
-                       events[1] |= 0x08;        /* LE PHY Update Complete */
-
-               /* If the controller supports LE Set Extended Scan Parameters
-                * and LE Set Extended Scan Enable commands, enable the
-                * corresponding event.
-                */
-               if (use_ext_scan(hdev))
-                       events[1] |= 0x10;      /* LE Extended Advertising
-                                                * Report
-                                                */
-
-               /* If the controller supports the LE Extended Advertising
-                * command, enable the corresponding event.
-                */
-               if (ext_adv_capable(hdev))
-                       events[2] |= 0x02;      /* LE Advertising Set
-                                                * Terminated
-                                                */
-
-               hci_req_add(req, HCI_OP_LE_SET_EVENT_MASK, sizeof(events),
-                           events);
-
-               /* Read LE Advertising Channel TX Power */
-               if ((hdev->commands[25] & 0x40) && !ext_adv_capable(hdev)) {
-                       /* HCI TS spec forbids mixing of legacy and extended
-                        * advertising commands wherein READ_ADV_TX_POWER is
-                        * also included. So do not call it if extended adv
-                        * is supported otherwise controller will return
-                        * COMMAND_DISALLOWED for extended commands.
-                        */
-                       hci_req_add(req, HCI_OP_LE_READ_ADV_TX_POWER, 0, NULL);
-               }
-
-               if (hdev->commands[38] & 0x80) {
-                       /* Read LE Min/Max Tx Power*/
-                       hci_req_add(req, HCI_OP_LE_READ_TRANSMIT_POWER,
-                                   0, NULL);
-               }
-
-               if (hdev->commands[26] & 0x40) {
-                       /* Read LE Accept List Size */
-                       hci_req_add(req, HCI_OP_LE_READ_ACCEPT_LIST_SIZE,
-                                   0, NULL);
-               }
-
-               if (hdev->commands[26] & 0x80) {
-                       /* Clear LE Accept List */
-                       hci_req_add(req, HCI_OP_LE_CLEAR_ACCEPT_LIST, 0, NULL);
-               }
-
-               if (hdev->commands[34] & 0x40) {
-                       /* Read LE Resolving List Size */
-                       hci_req_add(req, HCI_OP_LE_READ_RESOLV_LIST_SIZE,
-                                   0, NULL);
-               }
-
-               if (hdev->commands[34] & 0x20) {
-                       /* Clear LE Resolving List */
-                       hci_req_add(req, HCI_OP_LE_CLEAR_RESOLV_LIST, 0, NULL);
-               }
-
-               if (hdev->commands[35] & 0x04) {
-                       __le16 rpa_timeout = cpu_to_le16(hdev->rpa_timeout);
-
-                       /* Set RPA timeout */
-                       hci_req_add(req, HCI_OP_LE_SET_RPA_TIMEOUT, 2,
-                                   &rpa_timeout);
-               }
-
-               if (hdev->le_features[0] & HCI_LE_DATA_LEN_EXT) {
-                       /* Read LE Maximum Data Length */
-                       hci_req_add(req, HCI_OP_LE_READ_MAX_DATA_LEN, 0, NULL);
-
-                       /* Read LE Suggested Default Data Length */
-                       hci_req_add(req, HCI_OP_LE_READ_DEF_DATA_LEN, 0, NULL);
-               }
-
-               if (ext_adv_capable(hdev)) {
-                       /* Read LE Number of Supported Advertising Sets */
-                       hci_req_add(req, HCI_OP_LE_READ_NUM_SUPPORTED_ADV_SETS,
-                                   0, NULL);
-               }
-
-               hci_set_le_support(req);
-       }
-
-       /* Read features beyond page 1 if available */
-       for (p = 2; p < HCI_MAX_PAGES && p <= hdev->max_page; p++) {
-               struct hci_cp_read_local_ext_features cp;
-
-               cp.page = p;
-               hci_req_add(req, HCI_OP_READ_LOCAL_EXT_FEATURES,
-                           sizeof(cp), &cp);
-       }
-
-       return 0;
-}
-
-static int hci_init4_req(struct hci_request *req, unsigned long opt)
-{
-       struct hci_dev *hdev = req->hdev;
-
-       /* Some Broadcom based Bluetooth controllers do not support the
-        * Delete Stored Link Key command. They are clearly indicating its
-        * absence in the bit mask of supported commands.
-        *
-        * Check the supported commands and only if the command is marked
-        * as supported send it. If not supported assume that the controller
-        * does not have actual support for stored link keys which makes this
-        * command redundant anyway.
-        *
-        * Some controllers indicate that they support handling deleting
-        * stored link keys, but they don't. The quirk lets a driver
-        * just disable this command.
-        */
-       if (hdev->commands[6] & 0x80 &&
-           !test_bit(HCI_QUIRK_BROKEN_STORED_LINK_KEY, &hdev->quirks)) {
-               struct hci_cp_delete_stored_link_key cp;
-
-               bacpy(&cp.bdaddr, BDADDR_ANY);
-               cp.delete_all = 0x01;
-               hci_req_add(req, HCI_OP_DELETE_STORED_LINK_KEY,
-                           sizeof(cp), &cp);
-       }
-
-       /* Set event mask page 2 if the HCI command for it is supported */
-       if (hdev->commands[22] & 0x04)
-               hci_set_event_mask_page_2(req);
-
-       /* Read local pairing options if the HCI command is supported */
-       if (hdev->commands[41] & 0x08)
-               hci_req_add(req, HCI_OP_READ_LOCAL_PAIRING_OPTS, 0, NULL);
-
-       /* Get MWS transport configuration if the HCI command is supported */
-       if (hdev->commands[30] & 0x08)
-               hci_req_add(req, HCI_OP_GET_MWS_TRANSPORT_CONFIG, 0, NULL);
-
-       /* Check for Synchronization Train support */
-       if (lmp_sync_train_capable(hdev))
-               hci_req_add(req, HCI_OP_READ_SYNC_TRAIN_PARAMS, 0, NULL);
-
-       /* Enable Secure Connections if supported and configured */
-       if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED) &&
-           bredr_sc_enabled(hdev)) {
-               u8 support = 0x01;
-
-               hci_req_add(req, HCI_OP_WRITE_SC_SUPPORT,
-                           sizeof(support), &support);
-       }
-
-       /* Set erroneous data reporting if supported to the wideband speech
-        * setting value
-        */
-       if (hdev->commands[18] & 0x08 &&
-           !test_bit(HCI_QUIRK_BROKEN_ERR_DATA_REPORTING, &hdev->quirks)) {
-               bool enabled = hci_dev_test_flag(hdev,
-                                                HCI_WIDEBAND_SPEECH_ENABLED);
-
-               if (enabled !=
-                   (hdev->err_data_reporting == ERR_DATA_REPORTING_ENABLED)) {
-                       struct hci_cp_write_def_err_data_reporting cp;
-
-                       cp.err_data_reporting = enabled ?
-                                               ERR_DATA_REPORTING_ENABLED :
-                                               ERR_DATA_REPORTING_DISABLED;
-
-                       hci_req_add(req, HCI_OP_WRITE_DEF_ERR_DATA_REPORTING,
-                                   sizeof(cp), &cp);
-               }
-       }
-
-       /* Set Suggested Default Data Length to maximum if supported */
-       if (hdev->le_features[0] & HCI_LE_DATA_LEN_EXT) {
-               struct hci_cp_le_write_def_data_len cp;
-
-               cp.tx_len = cpu_to_le16(hdev->le_max_tx_len);
-               cp.tx_time = cpu_to_le16(hdev->le_max_tx_time);
-               hci_req_add(req, HCI_OP_LE_WRITE_DEF_DATA_LEN, sizeof(cp), &cp);
-       }
-
-       /* Set Default PHY parameters if command is supported */
-       if (hdev->commands[35] & 0x20) {
-               struct hci_cp_le_set_default_phy cp;
-
-               cp.all_phys = 0x00;
-               cp.tx_phys = hdev->le_tx_def_phys;
-               cp.rx_phys = hdev->le_rx_def_phys;
-
-               hci_req_add(req, HCI_OP_LE_SET_DEFAULT_PHY, sizeof(cp), &cp);
-       }
-
-       return 0;
-}
-
-static int __hci_init(struct hci_dev *hdev)
-{
-       int err;
-
-       err = __hci_req_sync(hdev, hci_init1_req, 0, HCI_INIT_TIMEOUT, NULL);
-       if (err < 0)
-               return err;
-
-       if (hci_dev_test_flag(hdev, HCI_SETUP))
-               hci_debugfs_create_basic(hdev);
-
-       err = __hci_req_sync(hdev, hci_init2_req, 0, HCI_INIT_TIMEOUT, NULL);
-       if (err < 0)
-               return err;
-
-       /* HCI_PRIMARY covers both single-mode LE, BR/EDR and dual-mode
-        * BR/EDR/LE type controllers. AMP controllers only need the
-        * first two stages of init.
-        */
-       if (hdev->dev_type != HCI_PRIMARY)
-               return 0;
-
-       err = __hci_req_sync(hdev, hci_init3_req, 0, HCI_INIT_TIMEOUT, NULL);
-       if (err < 0)
-               return err;
-
-       err = __hci_req_sync(hdev, hci_init4_req, 0, HCI_INIT_TIMEOUT, NULL);
-       if (err < 0)
-               return err;
-
-       /* Read local codec list if the HCI command is supported */
-       if (hdev->commands[45] & 0x04)
-               hci_read_supported_codecs_v2(hdev);
-       else if (hdev->commands[29] & 0x20)
-               hci_read_supported_codecs(hdev);
-
-       /* This function is only called when the controller is actually in
-        * configured state. When the controller is marked as unconfigured,
-        * this initialization procedure is not run.
-        *
-        * It means that it is possible that a controller runs through its
-        * setup phase and then discovers missing settings. If that is the
-        * case, then this function will not be called. It then will only
-        * be called during the config phase.
-        *
-        * So only when in setup phase or config phase, create the debugfs
-        * entries and register the SMP channels.
-        */
-       if (!hci_dev_test_flag(hdev, HCI_SETUP) &&
-           !hci_dev_test_flag(hdev, HCI_CONFIG))
-               return 0;
-
-       hci_debugfs_create_common(hdev);
-
-       if (lmp_bredr_capable(hdev))
-               hci_debugfs_create_bredr(hdev);
-
-       if (lmp_le_capable(hdev))
-               hci_debugfs_create_le(hdev);
-
-       return 0;
-}
-
-static int hci_init0_req(struct hci_request *req, unsigned long opt)
-{
-       struct hci_dev *hdev = req->hdev;
-
-       BT_DBG("%s %ld", hdev->name, opt);
-
-       /* Reset */
-       if (!test_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks))
-               hci_reset_req(req, 0);
-
-       /* Read Local Version */
-       hci_req_add(req, HCI_OP_READ_LOCAL_VERSION, 0, NULL);
-
-       /* Read BD Address */
-       if (hdev->set_bdaddr)
-               hci_req_add(req, HCI_OP_READ_BD_ADDR, 0, NULL);
-
-       return 0;
-}
-
-static int __hci_unconf_init(struct hci_dev *hdev)
-{
-       int err;
-
-       if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
-               return 0;
-
-       err = __hci_req_sync(hdev, hci_init0_req, 0, HCI_INIT_TIMEOUT, NULL);
-       if (err < 0)
-               return err;
-
-       if (hci_dev_test_flag(hdev, HCI_SETUP))
-               hci_debugfs_create_basic(hdev);
-
-       return 0;
-}
-
 static int hci_scan_req(struct hci_request *req, unsigned long opt)
 {
        __u8 scan = opt;
@@ -975,7 +157,7 @@ void hci_discovery_set_state(struct hci_dev *hdev, int state)
 
        switch (state) {
        case DISCOVERY_STOPPED:
-               hci_update_background_scan(hdev);
+               hci_update_passive_scan(hdev);
 
                if (old_state != DISCOVERY_STARTING)
                        mgmt_discovering(hdev, 0);
@@ -1289,32 +471,6 @@ done:
        return err;
 }
 
-/**
- * hci_dev_get_bd_addr_from_property - Get the Bluetooth Device Address
- *                                    (BD_ADDR) for a HCI device from
- *                                    a firmware node property.
- * @hdev:      The HCI device
- *
- * Search the firmware node for 'local-bd-address'.
- *
- * All-zero BD addresses are rejected, because those could be properties
- * that exist in the firmware tables, but were not updated by the firmware. For
- * example, the DTS could define 'local-bd-address', with zero BD addresses.
- */
-static void hci_dev_get_bd_addr_from_property(struct hci_dev *hdev)
-{
-       struct fwnode_handle *fwnode = dev_fwnode(hdev->dev.parent);
-       bdaddr_t ba;
-       int ret;
-
-       ret = fwnode_property_read_u8_array(fwnode, "local-bd-address",
-                                           (u8 *)&ba, sizeof(ba));
-       if (ret < 0 || !bacmp(&ba, BDADDR_ANY))
-               return;
-
-       bacpy(&hdev->public_addr, &ba);
-}
-
 static int hci_dev_do_open(struct hci_dev *hdev)
 {
        int ret = 0;
@@ -1323,205 +479,8 @@ static int hci_dev_do_open(struct hci_dev *hdev)
 
        hci_req_sync_lock(hdev);
 
-       if (hci_dev_test_flag(hdev, HCI_UNREGISTER)) {
-               ret = -ENODEV;
-               goto done;
-       }
-
-       if (!hci_dev_test_flag(hdev, HCI_SETUP) &&
-           !hci_dev_test_flag(hdev, HCI_CONFIG)) {
-               /* Check for rfkill but allow the HCI setup stage to
-                * proceed (which in itself doesn't cause any RF activity).
-                */
-               if (hci_dev_test_flag(hdev, HCI_RFKILLED)) {
-                       ret = -ERFKILL;
-                       goto done;
-               }
-
-               /* Check for valid public address or a configured static
-                * random address, but let the HCI setup proceed to
-                * be able to determine if there is a public address
-                * or not.
-                *
-                * In case of user channel usage, it is not important
-                * if a public address or static random address is
-                * available.
-                *
-                * This check is only valid for BR/EDR controllers
-                * since AMP controllers do not have an address.
-                */
-               if (!hci_dev_test_flag(hdev, HCI_USER_CHANNEL) &&
-                   hdev->dev_type == HCI_PRIMARY &&
-                   !bacmp(&hdev->bdaddr, BDADDR_ANY) &&
-                   !bacmp(&hdev->static_addr, BDADDR_ANY)) {
-                       ret = -EADDRNOTAVAIL;
-                       goto done;
-               }
-       }
-
-       if (test_bit(HCI_UP, &hdev->flags)) {
-               ret = -EALREADY;
-               goto done;
-       }
-
-       if (hdev->open(hdev)) {
-               ret = -EIO;
-               goto done;
-       }
-
-       set_bit(HCI_RUNNING, &hdev->flags);
-       hci_sock_dev_event(hdev, HCI_DEV_OPEN);
-
-       atomic_set(&hdev->cmd_cnt, 1);
-       set_bit(HCI_INIT, &hdev->flags);
-
-       if (hci_dev_test_flag(hdev, HCI_SETUP) ||
-           test_bit(HCI_QUIRK_NON_PERSISTENT_SETUP, &hdev->quirks)) {
-               bool invalid_bdaddr;
-
-               hci_sock_dev_event(hdev, HCI_DEV_SETUP);
-
-               if (hdev->setup)
-                       ret = hdev->setup(hdev);
-
-               /* The transport driver can set the quirk to mark the
-                * BD_ADDR invalid before creating the HCI device or in
-                * its setup callback.
-                */
-               invalid_bdaddr = test_bit(HCI_QUIRK_INVALID_BDADDR,
-                                         &hdev->quirks);
-
-               if (ret)
-                       goto setup_failed;
-
-               if (test_bit(HCI_QUIRK_USE_BDADDR_PROPERTY, &hdev->quirks)) {
-                       if (!bacmp(&hdev->public_addr, BDADDR_ANY))
-                               hci_dev_get_bd_addr_from_property(hdev);
-
-                       if (bacmp(&hdev->public_addr, BDADDR_ANY) &&
-                           hdev->set_bdaddr) {
-                               ret = hdev->set_bdaddr(hdev,
-                                                      &hdev->public_addr);
-
-                               /* If setting of the BD_ADDR from the device
-                                * property succeeds, then treat the address
-                                * as valid even if the invalid BD_ADDR
-                                * quirk indicates otherwise.
-                                */
-                               if (!ret)
-                                       invalid_bdaddr = false;
-                       }
-               }
-
-setup_failed:
-               /* The transport driver can set these quirks before
-                * creating the HCI device or in its setup callback.
-                *
-                * For the invalid BD_ADDR quirk it is possible that
-                * it becomes a valid address if the bootloader does
-                * provide it (see above).
-                *
-                * In case any of them is set, the controller has to
-                * start up as unconfigured.
-                */
-               if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks) ||
-                   invalid_bdaddr)
-                       hci_dev_set_flag(hdev, HCI_UNCONFIGURED);
-
-               /* For an unconfigured controller it is required to
-                * read at least the version information provided by
-                * the Read Local Version Information command.
-                *
-                * If the set_bdaddr driver callback is provided, then
-                * also the original Bluetooth public device address
-                * will be read using the Read BD Address command.
-                */
-               if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED))
-                       ret = __hci_unconf_init(hdev);
-       }
-
-       if (hci_dev_test_flag(hdev, HCI_CONFIG)) {
-               /* If public address change is configured, ensure that
-                * the address gets programmed. If the driver does not
-                * support changing the public address, fail the power
-                * on procedure.
-                */
-               if (bacmp(&hdev->public_addr, BDADDR_ANY) &&
-                   hdev->set_bdaddr)
-                       ret = hdev->set_bdaddr(hdev, &hdev->public_addr);
-               else
-                       ret = -EADDRNOTAVAIL;
-       }
-
-       if (!ret) {
-               if (!hci_dev_test_flag(hdev, HCI_UNCONFIGURED) &&
-                   !hci_dev_test_flag(hdev, HCI_USER_CHANNEL)) {
-                       ret = __hci_init(hdev);
-                       if (!ret && hdev->post_init)
-                               ret = hdev->post_init(hdev);
-               }
-       }
-
-       /* If the HCI Reset command is clearing all diagnostic settings,
-        * then they need to be reprogrammed after the init procedure
-        * completed.
-        */
-       if (test_bit(HCI_QUIRK_NON_PERSISTENT_DIAG, &hdev->quirks) &&
-           !hci_dev_test_flag(hdev, HCI_USER_CHANNEL) &&
-           hci_dev_test_flag(hdev, HCI_VENDOR_DIAG) && hdev->set_diag)
-               ret = hdev->set_diag(hdev, true);
-
-       msft_do_open(hdev);
-       aosp_do_open(hdev);
-
-       clear_bit(HCI_INIT, &hdev->flags);
-
-       if (!ret) {
-               hci_dev_hold(hdev);
-               hci_dev_set_flag(hdev, HCI_RPA_EXPIRED);
-               hci_adv_instances_set_rpa_expired(hdev, true);
-               set_bit(HCI_UP, &hdev->flags);
-               hci_sock_dev_event(hdev, HCI_DEV_UP);
-               hci_leds_update_powered(hdev, true);
-               if (!hci_dev_test_flag(hdev, HCI_SETUP) &&
-                   !hci_dev_test_flag(hdev, HCI_CONFIG) &&
-                   !hci_dev_test_flag(hdev, HCI_UNCONFIGURED) &&
-                   !hci_dev_test_flag(hdev, HCI_USER_CHANNEL) &&
-                   hci_dev_test_flag(hdev, HCI_MGMT) &&
-                   hdev->dev_type == HCI_PRIMARY) {
-                       ret = __hci_req_hci_power_on(hdev);
-                       mgmt_power_on(hdev, ret);
-               }
-       } else {
-               /* Init failed, cleanup */
-               flush_work(&hdev->tx_work);
-
-               /* Since hci_rx_work() is possible to awake new cmd_work
-                * it should be flushed first to avoid unexpected call of
-                * hci_cmd_work()
-                */
-               flush_work(&hdev->rx_work);
-               flush_work(&hdev->cmd_work);
-
-               skb_queue_purge(&hdev->cmd_q);
-               skb_queue_purge(&hdev->rx_q);
-
-               if (hdev->flush)
-                       hdev->flush(hdev);
-
-               if (hdev->sent_cmd) {
-                       kfree_skb(hdev->sent_cmd);
-                       hdev->sent_cmd = NULL;
-               }
-
-               clear_bit(HCI_RUNNING, &hdev->flags);
-               hci_sock_dev_event(hdev, HCI_DEV_CLOSE);
-
-               hdev->close(hdev);
-               hdev->flags &= BIT(HCI_RAW);
-       }
+       ret = hci_dev_open_sync(hdev);
 
-done:
        hci_req_sync_unlock(hdev);
        return ret;
 }
@@ -1583,155 +542,18 @@ done:
        return err;
 }
 
-/* This function requires the caller holds hdev->lock */
-static void hci_pend_le_actions_clear(struct hci_dev *hdev)
-{
-       struct hci_conn_params *p;
-
-       list_for_each_entry(p, &hdev->le_conn_params, list) {
-               if (p->conn) {
-                       hci_conn_drop(p->conn);
-                       hci_conn_put(p->conn);
-                       p->conn = NULL;
-               }
-               list_del_init(&p->action);
-       }
-
-       BT_DBG("All LE pending actions cleared");
-}
-
 int hci_dev_do_close(struct hci_dev *hdev)
 {
-       bool auto_off;
-       int err = 0;
+       int err;
 
        BT_DBG("%s %p", hdev->name, hdev);
 
-       cancel_delayed_work(&hdev->power_off);
-       cancel_delayed_work(&hdev->ncmd_timer);
-
-       hci_request_cancel_all(hdev);
        hci_req_sync_lock(hdev);
 
-       if (!hci_dev_test_flag(hdev, HCI_UNREGISTER) &&
-           !hci_dev_test_flag(hdev, HCI_USER_CHANNEL) &&
-           test_bit(HCI_UP, &hdev->flags)) {
-               /* Execute vendor specific shutdown routine */
-               if (hdev->shutdown)
-                       err = hdev->shutdown(hdev);
-       }
-
-       if (!test_and_clear_bit(HCI_UP, &hdev->flags)) {
-               cancel_delayed_work_sync(&hdev->cmd_timer);
-               hci_req_sync_unlock(hdev);
-               return err;
-       }
-
-       hci_leds_update_powered(hdev, false);
-
-       /* Flush RX and TX works */
-       flush_work(&hdev->tx_work);
-       flush_work(&hdev->rx_work);
-
-       if (hdev->discov_timeout > 0) {
-               hdev->discov_timeout = 0;
-               hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
-               hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
-       }
-
-       if (hci_dev_test_and_clear_flag(hdev, HCI_SERVICE_CACHE))
-               cancel_delayed_work(&hdev->service_cache);
-
-       if (hci_dev_test_flag(hdev, HCI_MGMT)) {
-               struct adv_info *adv_instance;
-
-               cancel_delayed_work_sync(&hdev->rpa_expired);
-
-               list_for_each_entry(adv_instance, &hdev->adv_instances, list)
-                       cancel_delayed_work_sync(&adv_instance->rpa_expired_cb);
-       }
-
-       /* Avoid potential lockdep warnings from the *_flush() calls by
-        * ensuring the workqueue is empty up front.
-        */
-       drain_workqueue(hdev->workqueue);
-
-       hci_dev_lock(hdev);
-
-       hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
-
-       auto_off = hci_dev_test_and_clear_flag(hdev, HCI_AUTO_OFF);
-
-       if (!auto_off && hdev->dev_type == HCI_PRIMARY &&
-           !hci_dev_test_flag(hdev, HCI_USER_CHANNEL) &&
-           hci_dev_test_flag(hdev, HCI_MGMT))
-               __mgmt_power_off(hdev);
-
-       hci_inquiry_cache_flush(hdev);
-       hci_pend_le_actions_clear(hdev);
-       hci_conn_hash_flush(hdev);
-       hci_dev_unlock(hdev);
-
-       smp_unregister(hdev);
-
-       hci_sock_dev_event(hdev, HCI_DEV_DOWN);
-
-       aosp_do_close(hdev);
-       msft_do_close(hdev);
-
-       if (hdev->flush)
-               hdev->flush(hdev);
-
-       /* Reset device */
-       skb_queue_purge(&hdev->cmd_q);
-       atomic_set(&hdev->cmd_cnt, 1);
-       if (test_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks) &&
-           !auto_off && !hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) {
-               set_bit(HCI_INIT, &hdev->flags);
-               __hci_req_sync(hdev, hci_reset_req, 0, HCI_CMD_TIMEOUT, NULL);
-               clear_bit(HCI_INIT, &hdev->flags);
-       }
-
-       /* flush cmd  work */
-       flush_work(&hdev->cmd_work);
-
-       /* Drop queues */
-       skb_queue_purge(&hdev->rx_q);
-       skb_queue_purge(&hdev->cmd_q);
-       skb_queue_purge(&hdev->raw_q);
-
-       /* Drop last sent command */
-       if (hdev->sent_cmd) {
-               cancel_delayed_work_sync(&hdev->cmd_timer);
-               kfree_skb(hdev->sent_cmd);
-               hdev->sent_cmd = NULL;
-       }
-
-       clear_bit(HCI_RUNNING, &hdev->flags);
-       hci_sock_dev_event(hdev, HCI_DEV_CLOSE);
-
-       if (test_and_clear_bit(SUSPEND_POWERING_DOWN, hdev->suspend_tasks))
-               wake_up(&hdev->suspend_wait_q);
-
-       /* After this point our queues are empty
-        * and no tasks are scheduled. */
-       hdev->close(hdev);
-
-       /* Clear flags */
-       hdev->flags &= BIT(HCI_RAW);
-       hci_dev_clear_volatile_flags(hdev);
-
-       /* Controller radio is available but is currently powered down */
-       hdev->amp_status = AMP_STATUS_POWERED_DOWN;
-
-       memset(hdev->eir, 0, sizeof(hdev->eir));
-       memset(hdev->dev_class, 0, sizeof(hdev->dev_class));
-       bacpy(&hdev->random_addr, BDADDR_ANY);
-       hci_codec_list_clear(&hdev->local_codecs);
+       err = hci_dev_close_sync(hdev);
 
        hci_req_sync_unlock(hdev);
 
-       hci_dev_put(hdev);
        return err;
 }
 
@@ -1787,7 +609,7 @@ static int hci_dev_do_reset(struct hci_dev *hdev)
        atomic_set(&hdev->cmd_cnt, 1);
        hdev->acl_cnt = 0; hdev->sco_cnt = 0; hdev->le_cnt = 0;
 
-       ret = __hci_req_sync(hdev, hci_reset_req, 0, HCI_INIT_TIMEOUT, NULL);
+       ret = hci_reset_sync(hdev);
 
        hci_req_sync_unlock(hdev);
        return ret;
@@ -1850,7 +672,7 @@ done:
        return ret;
 }
 
-static void hci_update_scan_state(struct hci_dev *hdev, u8 scan)
+static void hci_update_passive_scan_state(struct hci_dev *hdev, u8 scan)
 {
        bool conn_changed, discov_changed;
 
@@ -1951,7 +773,7 @@ int hci_dev_cmd(unsigned int cmd, void __user *arg)
                 * get correctly modified as this was a non-mgmt change.
                 */
                if (!err)
-                       hci_update_scan_state(hdev, dr.dev_opt);
+                       hci_update_passive_scan_state(hdev, dr.dev_opt);
                break;
 
        case HCISETLINKPOL:
@@ -2133,9 +955,7 @@ static void hci_power_on(struct work_struct *work)
            hci_dev_test_flag(hdev, HCI_MGMT) &&
            hci_dev_test_and_clear_flag(hdev, HCI_AUTO_OFF)) {
                cancel_delayed_work(&hdev->power_off);
-               hci_req_sync_lock(hdev);
-               err = __hci_req_hci_power_on(hdev);
-               hci_req_sync_unlock(hdev);
+               err = hci_powered_update_sync(hdev);
                mgmt_power_on(hdev, err);
                return;
        }
@@ -3096,7 +1916,7 @@ bool hci_add_adv_monitor(struct hci_dev *hdev, struct adv_monitor *monitor,
 
        switch (hci_get_adv_monitor_offload_ext(hdev)) {
        case HCI_ADV_MONITOR_EXT_NONE:
-               hci_update_background_scan(hdev);
+               hci_update_passive_scan(hdev);
                bt_dev_dbg(hdev, "%s add monitor status %d", hdev->name, *err);
                /* Message was not forwarded to controller - not an error */
                return false;
@@ -3160,7 +1980,7 @@ bool hci_remove_single_adv_monitor(struct hci_dev *hdev, u16 handle, int *err)
 
        pending = hci_remove_adv_monitor(hdev, monitor, handle, err);
        if (!*err && !pending)
-               hci_update_background_scan(hdev);
+               hci_update_passive_scan(hdev);
 
        bt_dev_dbg(hdev, "%s remove monitor handle %d, status %d, %spending",
                   hdev->name, handle, *err, pending ? "" : "not ");
@@ -3192,7 +2012,7 @@ bool hci_remove_all_adv_monitor(struct hci_dev *hdev, int *err)
        }
 
        if (update)
-               hci_update_background_scan(hdev);
+               hci_update_passive_scan(hdev);
 
        bt_dev_dbg(hdev, "%s remove all monitors status %d, %spending",
                   hdev->name, *err, pending ? "" : "not ");
@@ -3486,7 +2306,7 @@ void hci_conn_params_del(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type)
 
        hci_conn_params_free(params);
 
-       hci_update_background_scan(hdev);
+       hci_update_passive_scan(hdev);
 
        BT_DBG("addr %pMR (type %u)", addr, addr_type);
 }
@@ -3554,61 +2374,6 @@ void hci_copy_identity_address(struct hci_dev *hdev, bdaddr_t *bdaddr,
        }
 }
 
-static void hci_suspend_clear_tasks(struct hci_dev *hdev)
-{
-       int i;
-
-       for (i = 0; i < __SUSPEND_NUM_TASKS; i++)
-               clear_bit(i, hdev->suspend_tasks);
-
-       wake_up(&hdev->suspend_wait_q);
-}
-
-static int hci_suspend_wait_event(struct hci_dev *hdev)
-{
-#define WAKE_COND                                                              \
-       (find_first_bit(hdev->suspend_tasks, __SUSPEND_NUM_TASKS) ==           \
-        __SUSPEND_NUM_TASKS)
-
-       int i;
-       int ret = wait_event_timeout(hdev->suspend_wait_q,
-                                    WAKE_COND, SUSPEND_NOTIFIER_TIMEOUT);
-
-       if (ret == 0) {
-               bt_dev_err(hdev, "Timed out waiting for suspend events");
-               for (i = 0; i < __SUSPEND_NUM_TASKS; ++i) {
-                       if (test_bit(i, hdev->suspend_tasks))
-                               bt_dev_err(hdev, "Suspend timeout bit: %d", i);
-                       clear_bit(i, hdev->suspend_tasks);
-               }
-
-               ret = -ETIMEDOUT;
-       } else {
-               ret = 0;
-       }
-
-       return ret;
-}
-
-static void hci_prepare_suspend(struct work_struct *work)
-{
-       struct hci_dev *hdev =
-               container_of(work, struct hci_dev, suspend_prepare);
-
-       hci_dev_lock(hdev);
-       hci_req_prepare_suspend(hdev, hdev->suspend_state_next);
-       hci_dev_unlock(hdev);
-}
-
-static int hci_change_suspend_state(struct hci_dev *hdev,
-                                   enum suspended_state next)
-{
-       hdev->suspend_state_next = next;
-       set_bit(SUSPEND_PREPARE_NOTIFIER, hdev->suspend_tasks);
-       queue_work(hdev->req_workqueue, &hdev->suspend_prepare);
-       return hci_suspend_wait_event(hdev);
-}
-
 static void hci_clear_wake_reason(struct hci_dev *hdev)
 {
        hci_dev_lock(hdev);
@@ -3745,7 +2510,8 @@ struct hci_dev *hci_alloc_dev_priv(int sizeof_priv)
        INIT_WORK(&hdev->tx_work, hci_tx_work);
        INIT_WORK(&hdev->power_on, hci_power_on);
        INIT_WORK(&hdev->error_reset, hci_error_reset);
-       INIT_WORK(&hdev->suspend_prepare, hci_prepare_suspend);
+
+       hci_cmd_sync_init(hdev);
 
        INIT_DELAYED_WORK(&hdev->power_off, hci_power_off);
 
@@ -3754,7 +2520,6 @@ struct hci_dev *hci_alloc_dev_priv(int sizeof_priv)
        skb_queue_head_init(&hdev->raw_q);
 
        init_waitqueue_head(&hdev->req_wait_q);
-       init_waitqueue_head(&hdev->suspend_wait_q);
 
        INIT_DELAYED_WORK(&hdev->cmd_timer, hci_cmd_timeout);
        INIT_DELAYED_WORK(&hdev->ncmd_timer, hci_ncmd_timeout);
@@ -3882,6 +2647,7 @@ int hci_register_dev(struct hci_dev *hdev)
        return id;
 
 err_wqueue:
+       debugfs_remove_recursive(hdev->debugfs);
        destroy_workqueue(hdev->workqueue);
        destroy_workqueue(hdev->req_workqueue);
 err:
@@ -3904,11 +2670,10 @@ void hci_unregister_dev(struct hci_dev *hdev)
 
        cancel_work_sync(&hdev->power_on);
 
-       if (!test_bit(HCI_QUIRK_NO_SUSPEND_NOTIFIER, &hdev->quirks)) {
-               hci_suspend_clear_tasks(hdev);
+       hci_cmd_sync_clear(hdev);
+
+       if (!test_bit(HCI_QUIRK_NO_SUSPEND_NOTIFIER, &hdev->quirks))
                unregister_pm_notifier(&hdev->suspend_notifier);
-               cancel_work_sync(&hdev->suspend_prepare);
-       }
 
        msft_unregister(hdev);
 
@@ -3975,7 +2740,6 @@ EXPORT_SYMBOL(hci_release_dev);
 int hci_suspend_dev(struct hci_dev *hdev)
 {
        int ret;
-       u8 state = BT_RUNNING;
 
        bt_dev_dbg(hdev, "");
 
@@ -3984,40 +2748,17 @@ int hci_suspend_dev(struct hci_dev *hdev)
            hci_dev_test_flag(hdev, HCI_UNREGISTER))
                return 0;
 
-       /* If powering down, wait for completion. */
-       if (mgmt_powering_down(hdev)) {
-               set_bit(SUSPEND_POWERING_DOWN, hdev->suspend_tasks);
-               ret = hci_suspend_wait_event(hdev);
-               if (ret)
-                       goto done;
-       }
-
-       /* Suspend consists of two actions:
-        *  - First, disconnect everything and make the controller not
-        *    connectable (disabling scanning)
-        *  - Second, program event filter/accept list and enable scan
-        */
-       ret = hci_change_suspend_state(hdev, BT_SUSPEND_DISCONNECT);
-       if (ret)
-               goto clear;
-
-       state = BT_SUSPEND_DISCONNECT;
+       /* If powering down don't attempt to suspend */
+       if (mgmt_powering_down(hdev))
+               return 0;
 
-       /* Only configure accept list if device may wakeup. */
-       if (hdev->wakeup && hdev->wakeup(hdev)) {
-               ret = hci_change_suspend_state(hdev, BT_SUSPEND_CONFIGURE_WAKE);
-               if (!ret)
-                       state = BT_SUSPEND_CONFIGURE_WAKE;
-       }
+       hci_req_sync_lock(hdev);
+       ret = hci_suspend_sync(hdev);
+       hci_req_sync_unlock(hdev);
 
-clear:
        hci_clear_wake_reason(hdev);
-       mgmt_suspending(hdev, state);
+       mgmt_suspending(hdev, hdev->suspend_state);
 
-done:
-       /* We always allow suspend even if suspend preparation failed and
-        * attempt to recover in resume.
-        */
        hci_sock_dev_event(hdev, HCI_DEV_SUSPEND);
        return ret;
 }
@@ -4039,10 +2780,12 @@ int hci_resume_dev(struct hci_dev *hdev)
        if (mgmt_powering_down(hdev))
                return 0;
 
-       ret = hci_change_suspend_state(hdev, BT_RUNNING);
+       hci_req_sync_lock(hdev);
+       ret = hci_resume_sync(hdev);
+       hci_req_sync_unlock(hdev);
 
        mgmt_resuming(hdev, hdev->wake_reason, &hdev->wake_addr,
-                             hdev->wake_addr_type);
+                     hdev->wake_addr_type);
 
        hci_sock_dev_event(hdev, HCI_DEV_RESUME);
        return ret;
@@ -4270,25 +3013,6 @@ void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 opcode)
        return hdev->sent_cmd->data + HCI_COMMAND_HDR_SIZE;
 }
 
-/* Send HCI command and wait for command complete event */
-struct sk_buff *hci_cmd_sync(struct hci_dev *hdev, u16 opcode, u32 plen,
-                            const void *param, u32 timeout)
-{
-       struct sk_buff *skb;
-
-       if (!test_bit(HCI_UP, &hdev->flags))
-               return ERR_PTR(-ENETDOWN);
-
-       bt_dev_dbg(hdev, "opcode 0x%4.4x plen %d", opcode, plen);
-
-       hci_req_sync_lock(hdev);
-       skb = __hci_cmd_sync(hdev, opcode, plen, param, timeout);
-       hci_req_sync_unlock(hdev);
-
-       return skb;
-}
-EXPORT_SYMBOL(hci_cmd_sync);
-
 /* Send ACL data */
 static void hci_add_acl_hdr(struct sk_buff *skb, __u16 handle, __u16 flags)
 {
index 7d0db1c..efc5458 100644 (file)
@@ -545,9 +545,7 @@ static void hci_cc_write_ssp_mode(struct hci_dev *hdev, struct sk_buff *skb)
                        hdev->features[1][0] &= ~LMP_HOST_SSP;
        }
 
-       if (hci_dev_test_flag(hdev, HCI_MGMT))
-               mgmt_ssp_enable_complete(hdev, sent->mode, status);
-       else if (!status) {
+       if (!status) {
                if (sent->mode)
                        hci_dev_set_flag(hdev, HCI_SSP_ENABLED);
                else
@@ -1239,6 +1237,55 @@ static void hci_cc_le_set_adv_set_random_addr(struct hci_dev *hdev,
        hci_dev_unlock(hdev);
 }
 
+static void hci_cc_le_remove_adv_set(struct hci_dev *hdev, struct sk_buff *skb)
+{
+       __u8 status = *((__u8 *)skb->data);
+       u8 *instance;
+       int err;
+
+       if (status)
+               return;
+
+       instance = hci_sent_cmd_data(hdev, HCI_OP_LE_REMOVE_ADV_SET);
+       if (!instance)
+               return;
+
+       hci_dev_lock(hdev);
+
+       err = hci_remove_adv_instance(hdev, *instance);
+       if (!err)
+               mgmt_advertising_removed(hci_skb_sk(hdev->sent_cmd), hdev,
+                                        *instance);
+
+       hci_dev_unlock(hdev);
+}
+
+static void hci_cc_le_clear_adv_sets(struct hci_dev *hdev, struct sk_buff *skb)
+{
+       __u8 status = *((__u8 *)skb->data);
+       struct adv_info *adv, *n;
+       int err;
+
+       if (status)
+               return;
+
+       if (!hci_sent_cmd_data(hdev, HCI_OP_LE_CLEAR_ADV_SETS))
+               return;
+
+       hci_dev_lock(hdev);
+
+       list_for_each_entry_safe(adv, n, &hdev->adv_instances, list) {
+               u8 instance = adv->instance;
+
+               err = hci_remove_adv_instance(hdev, instance);
+               if (!err)
+                       mgmt_advertising_removed(hci_skb_sk(hdev->sent_cmd),
+                                                hdev, instance);
+       }
+
+       hci_dev_unlock(hdev);
+}
+
 static void hci_cc_le_read_transmit_power(struct hci_dev *hdev,
                                          struct sk_buff *skb)
 {
@@ -1326,8 +1373,10 @@ static void hci_cc_le_set_ext_adv_enable(struct hci_dev *hdev,
                                           &conn->le_conn_timeout,
                                           conn->conn_timeout);
        } else {
-               if (adv) {
-                       adv->enabled = false;
+               if (cp->num_of_sets) {
+                       if (adv)
+                               adv->enabled = false;
+
                        /* If just one instance was disabled check if there are
                         * any other instance enabled before clearing HCI_LE_ADV
                         */
@@ -1463,16 +1512,10 @@ static void le_set_scan_enable_complete(struct hci_dev *hdev, u8 enable)
 
                /* The HCI_LE_SCAN_INTERRUPTED flag indicates that we
                 * interrupted scanning due to a connect request. Mark
-                * therefore discovery as stopped. If this was not
-                * because of a connect request advertising might have
-                * been disabled because of active scanning, so
-                * re-enable it again if necessary.
+                * therefore discovery as stopped.
                 */
                if (hci_dev_test_and_clear_flag(hdev, HCI_LE_SCAN_INTERRUPTED))
                        hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
-               else if (!hci_dev_test_flag(hdev, HCI_LE_ADV) &&
-                        hdev->discovery.state == DISCOVERY_FINDING)
-                       hci_req_reenable_advertising(hdev);
 
                break;
 
@@ -2371,9 +2414,14 @@ static void hci_cs_exit_sniff_mode(struct hci_dev *hdev, __u8 status)
 static void hci_cs_disconnect(struct hci_dev *hdev, u8 status)
 {
        struct hci_cp_disconnect *cp;
+       struct hci_conn_params *params;
        struct hci_conn *conn;
+       bool mgmt_conn;
 
-       if (!status)
+       /* Wait for HCI_EV_DISCONN_COMPLETE if status 0x00 and not suspended
+        * otherwise cleanup the connection immediately.
+        */
+       if (!status && !hdev->suspended)
                return;
 
        cp = hci_sent_cmd_data(hdev, HCI_OP_DISCONNECT);
@@ -2383,23 +2431,60 @@ static void hci_cs_disconnect(struct hci_dev *hdev, u8 status)
        hci_dev_lock(hdev);
 
        conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(cp->handle));
-       if (conn) {
+       if (!conn)
+               goto unlock;
+
+       if (status) {
                mgmt_disconnect_failed(hdev, &conn->dst, conn->type,
                                       conn->dst_type, status);
 
                if (conn->type == LE_LINK && conn->role == HCI_ROLE_SLAVE) {
                        hdev->cur_adv_instance = conn->adv_instance;
-                       hci_req_reenable_advertising(hdev);
+                       hci_enable_advertising(hdev);
                }
 
-               /* If the disconnection failed for any reason, the upper layer
-                * does not retry to disconnect in current implementation.
-                * Hence, we need to do some basic cleanup here and re-enable
-                * advertising if necessary.
-                */
-               hci_conn_del(conn);
+               goto done;
+       }
+
+       mgmt_conn = test_and_clear_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags);
+
+       if (conn->type == ACL_LINK) {
+               if (test_bit(HCI_CONN_FLUSH_KEY, &conn->flags))
+                       hci_remove_link_key(hdev, &conn->dst);
+       }
+
+       params = hci_conn_params_lookup(hdev, &conn->dst, conn->dst_type);
+       if (params) {
+               switch (params->auto_connect) {
+               case HCI_AUTO_CONN_LINK_LOSS:
+                       if (cp->reason != HCI_ERROR_CONNECTION_TIMEOUT)
+                               break;
+                       fallthrough;
+
+               case HCI_AUTO_CONN_DIRECT:
+               case HCI_AUTO_CONN_ALWAYS:
+                       list_del_init(&params->action);
+                       list_add(&params->action, &hdev->pend_le_conns);
+                       break;
+
+               default:
+                       break;
+               }
        }
 
+       mgmt_device_disconnected(hdev, &conn->dst, conn->type, conn->dst_type,
+                                cp->reason, mgmt_conn);
+
+       hci_disconn_cfm(conn, cp->reason);
+
+done:
+       /* If the disconnection failed for any reason, the upper layer
+        * does not retry to disconnect in current implementation.
+        * Hence, we need to do some basic cleanup here and re-enable
+        * advertising if necessary.
+        */
+       hci_conn_del(conn);
+unlock:
        hci_dev_unlock(hdev);
 }
 
@@ -2977,7 +3062,7 @@ static void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
                case HCI_AUTO_CONN_ALWAYS:
                        list_del_init(&params->action);
                        list_add(&params->action, &hdev->pend_le_conns);
-                       hci_update_background_scan(hdev);
+                       hci_update_passive_scan(hdev);
                        break;
 
                default:
@@ -2987,14 +3072,6 @@ static void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
 
        hci_disconn_cfm(conn, ev->reason);
 
-       /* The suspend notifier is waiting for all devices to disconnect so
-        * clear the bit from pending tasks and inform the wait queue.
-        */
-       if (list_empty(&hdev->conn_hash.list) &&
-           test_and_clear_bit(SUSPEND_DISCONNECTING, hdev->suspend_tasks)) {
-               wake_up(&hdev->suspend_wait_q);
-       }
-
        /* Re-enable advertising if necessary, since it might
         * have been disabled by the connection. From the
         * HCI_LE_Set_Advertise_Enable command description in
@@ -3007,7 +3084,7 @@ static void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
         */
        if (conn->type == LE_LINK && conn->role == HCI_ROLE_SLAVE) {
                hdev->cur_adv_instance = conn->adv_instance;
-               hci_req_reenable_advertising(hdev);
+               hci_enable_advertising(hdev);
        }
 
        hci_conn_del(conn);
@@ -3723,6 +3800,14 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb,
                hci_cc_le_set_adv_set_random_addr(hdev, skb);
                break;
 
+       case HCI_OP_LE_REMOVE_ADV_SET:
+               hci_cc_le_remove_adv_set(hdev, skb);
+               break;
+
+       case HCI_OP_LE_CLEAR_ADV_SETS:
+               hci_cc_le_clear_adv_sets(hdev, skb);
+               break;
+
        case HCI_OP_LE_READ_TRANSMIT_POWER:
                hci_cc_le_read_transmit_power(hdev, skb);
                break;
@@ -4445,7 +4530,6 @@ static void hci_sync_conn_complete_evt(struct hci_dev *hdev,
 {
        struct hci_ev_sync_conn_complete *ev = (void *) skb->data;
        struct hci_conn *conn;
-       unsigned int notify_evt;
 
        BT_DBG("%s status 0x%2.2x", hdev->name, ev->status);
 
@@ -4517,22 +4601,18 @@ static void hci_sync_conn_complete_evt(struct hci_dev *hdev,
        }
 
        bt_dev_dbg(hdev, "SCO connected with air mode: %02x", ev->air_mode);
-
-       switch (ev->air_mode) {
-       case 0x02:
-               notify_evt = HCI_NOTIFY_ENABLE_SCO_CVSD;
-               break;
-       case 0x03:
-               notify_evt = HCI_NOTIFY_ENABLE_SCO_TRANSP;
-               break;
-       }
-
        /* Notify only in case of SCO over HCI transport data path which
         * is zero and non-zero value shall be non-HCI transport data path
         */
-       if (conn->codec.data_path == 0) {
-               if (hdev->notify)
-                       hdev->notify(hdev, notify_evt);
+       if (conn->codec.data_path == 0 && hdev->notify) {
+               switch (ev->air_mode) {
+               case 0x02:
+                       hdev->notify(hdev, HCI_NOTIFY_ENABLE_SCO_CVSD);
+                       break;
+               case 0x03:
+                       hdev->notify(hdev, HCI_NOTIFY_ENABLE_SCO_TRANSP);
+                       break;
+               }
        }
 
        hci_connect_cfm(conn, ev->status);
@@ -5412,7 +5492,7 @@ static void le_conn_complete_evt(struct hci_dev *hdev, u8 status,
        }
 
 unlock:
-       hci_update_background_scan(hdev);
+       hci_update_passive_scan(hdev);
        hci_dev_unlock(hdev);
 }
 
@@ -5441,23 +5521,30 @@ static void hci_le_enh_conn_complete_evt(struct hci_dev *hdev,
                             le16_to_cpu(ev->interval),
                             le16_to_cpu(ev->latency),
                             le16_to_cpu(ev->supervision_timeout));
-
-       if (use_ll_privacy(hdev) &&
-           hci_dev_test_flag(hdev, HCI_ENABLE_LL_PRIVACY) &&
-           hci_dev_test_flag(hdev, HCI_LL_RPA_RESOLUTION))
-               hci_req_disable_address_resolution(hdev);
 }
 
 static void hci_le_ext_adv_term_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
        struct hci_evt_le_ext_adv_set_term *ev = (void *) skb->data;
        struct hci_conn *conn;
-       struct adv_info *adv;
+       struct adv_info *adv, *n;
 
        BT_DBG("%s status 0x%2.2x", hdev->name, ev->status);
 
        adv = hci_find_adv_instance(hdev, ev->handle);
 
+       /* The Bluetooth Core 5.3 specification clearly states that this event
+        * shall not be sent when the Host disables the advertising set. So in
+        * case of HCI_ERROR_CANCELLED_BY_HOST, just ignore the event.
+        *
+        * When the Host disables an advertising set, all cleanup is done via
+        * its command callback and not needed to be duplicated here.
+        */
+       if (ev->status == HCI_ERROR_CANCELLED_BY_HOST) {
+               bt_dev_warn_ratelimited(hdev, "Unexpected advertising set terminated event");
+               return;
+       }
+
        if (ev->status) {
                if (!adv)
                        return;
@@ -5466,6 +5553,13 @@ static void hci_le_ext_adv_term_evt(struct hci_dev *hdev, struct sk_buff *skb)
                hci_remove_adv_instance(hdev, ev->handle);
                mgmt_advertising_removed(NULL, hdev, ev->handle);
 
+               list_for_each_entry_safe(adv, n, &hdev->adv_instances, list) {
+                       if (adv->enabled)
+                               return;
+               }
+
+               /* We are no longer advertising, clear HCI_LE_ADV */
+               hci_dev_clear_flag(hdev, HCI_LE_ADV);
                return;
        }
 
@@ -5529,8 +5623,9 @@ static struct hci_conn *check_pending_le_conn(struct hci_dev *hdev,
        if (adv_type != LE_ADV_IND && adv_type != LE_ADV_DIRECT_IND)
                return NULL;
 
-       /* Ignore if the device is blocked */
-       if (hci_bdaddr_list_lookup(&hdev->reject_list, addr, addr_type))
+       /* Ignore if the device is blocked or hdev is suspended */
+       if (hci_bdaddr_list_lookup(&hdev->reject_list, addr, addr_type) ||
+           hdev->suspended)
                return NULL;
 
        /* Most controller will fail if we try to create new connections
@@ -5825,7 +5920,8 @@ static void hci_le_adv_report_evt(struct hci_dev *hdev, struct sk_buff *skb)
                struct hci_ev_le_advertising_info *ev = ptr;
                s8 rssi;
 
-               if (ev->length <= HCI_MAX_AD_LENGTH) {
+               if (ev->length <= HCI_MAX_AD_LENGTH &&
+                   ev->data + ev->length <= skb_tail_pointer(skb)) {
                        rssi = ev->data[ev->length];
                        process_adv_report(hdev, ev->evt_type, &ev->bdaddr,
                                           ev->bdaddr_type, NULL, 0, rssi,
@@ -5835,6 +5931,11 @@ static void hci_le_adv_report_evt(struct hci_dev *hdev, struct sk_buff *skb)
                }
 
                ptr += sizeof(*ev) + ev->length + 1;
+
+               if (ptr > (void *) skb_tail_pointer(skb) - sizeof(*ev)) {
+                       bt_dev_err(hdev, "Malicious advertising data. Stopping processing");
+                       break;
+               }
        }
 
        hci_dev_unlock(hdev);
index 92611bf..8b3205e 100644 (file)
 #include "msft.h"
 #include "eir.h"
 
-#define HCI_REQ_DONE     0
-#define HCI_REQ_PEND     1
-#define HCI_REQ_CANCELED  2
-
 void hci_req_init(struct hci_request *req, struct hci_dev *hdev)
 {
        skb_queue_head_init(&req->cmd_q);
@@ -101,8 +97,8 @@ int hci_req_run_skb(struct hci_request *req, hci_req_complete_skb_t complete)
        return req_run(req, NULL, complete);
 }
 
-static void hci_req_sync_complete(struct hci_dev *hdev, u8 result, u16 opcode,
-                                 struct sk_buff *skb)
+void hci_req_sync_complete(struct hci_dev *hdev, u8 result, u16 opcode,
+                          struct sk_buff *skb)
 {
        bt_dev_dbg(hdev, "result 0x%2.2x", result);
 
@@ -126,70 +122,6 @@ void hci_req_sync_cancel(struct hci_dev *hdev, int err)
        }
 }
 
-struct sk_buff *__hci_cmd_sync_ev(struct hci_dev *hdev, u16 opcode, u32 plen,
-                                 const void *param, u8 event, u32 timeout)
-{
-       struct hci_request req;
-       struct sk_buff *skb;
-       int err = 0;
-
-       bt_dev_dbg(hdev, "");
-
-       hci_req_init(&req, hdev);
-
-       hci_req_add_ev(&req, opcode, plen, param, event);
-
-       hdev->req_status = HCI_REQ_PEND;
-
-       err = hci_req_run_skb(&req, hci_req_sync_complete);
-       if (err < 0)
-               return ERR_PTR(err);
-
-       err = wait_event_interruptible_timeout(hdev->req_wait_q,
-                       hdev->req_status != HCI_REQ_PEND, timeout);
-
-       if (err == -ERESTARTSYS)
-               return ERR_PTR(-EINTR);
-
-       switch (hdev->req_status) {
-       case HCI_REQ_DONE:
-               err = -bt_to_errno(hdev->req_result);
-               break;
-
-       case HCI_REQ_CANCELED:
-               err = -hdev->req_result;
-               break;
-
-       default:
-               err = -ETIMEDOUT;
-               break;
-       }
-
-       hdev->req_status = hdev->req_result = 0;
-       skb = hdev->req_skb;
-       hdev->req_skb = NULL;
-
-       bt_dev_dbg(hdev, "end: err %d", err);
-
-       if (err < 0) {
-               kfree_skb(skb);
-               return ERR_PTR(err);
-       }
-
-       if (!skb)
-               return ERR_PTR(-ENODATA);
-
-       return skb;
-}
-EXPORT_SYMBOL(__hci_cmd_sync_ev);
-
-struct sk_buff *__hci_cmd_sync(struct hci_dev *hdev, u16 opcode, u32 plen,
-                              const void *param, u32 timeout)
-{
-       return __hci_cmd_sync_ev(hdev, opcode, plen, param, 0, timeout);
-}
-EXPORT_SYMBOL(__hci_cmd_sync);
-
 /* Execute request and wait for completion. */
 int __hci_req_sync(struct hci_dev *hdev, int (*func)(struct hci_request *req,
                                                     unsigned long opt),
@@ -436,82 +368,6 @@ static bool __hci_update_interleaved_scan(struct hci_dev *hdev)
        return false;
 }
 
-/* This function controls the background scanning based on hdev->pend_le_conns
- * list. If there are pending LE connection we start the background scanning,
- * otherwise we stop it.
- *
- * This function requires the caller holds hdev->lock.
- */
-static void __hci_update_background_scan(struct hci_request *req)
-{
-       struct hci_dev *hdev = req->hdev;
-
-       if (!test_bit(HCI_UP, &hdev->flags) ||
-           test_bit(HCI_INIT, &hdev->flags) ||
-           hci_dev_test_flag(hdev, HCI_SETUP) ||
-           hci_dev_test_flag(hdev, HCI_CONFIG) ||
-           hci_dev_test_flag(hdev, HCI_AUTO_OFF) ||
-           hci_dev_test_flag(hdev, HCI_UNREGISTER))
-               return;
-
-       /* No point in doing scanning if LE support hasn't been enabled */
-       if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
-               return;
-
-       /* If discovery is active don't interfere with it */
-       if (hdev->discovery.state != DISCOVERY_STOPPED)
-               return;
-
-       /* Reset RSSI and UUID filters when starting background scanning
-        * since these filters are meant for service discovery only.
-        *
-        * The Start Discovery and Start Service Discovery operations
-        * ensure to set proper values for RSSI threshold and UUID
-        * filter list. So it is safe to just reset them here.
-        */
-       hci_discovery_filter_clear(hdev);
-
-       bt_dev_dbg(hdev, "ADV monitoring is %s",
-                  hci_is_adv_monitoring(hdev) ? "on" : "off");
-
-       if (list_empty(&hdev->pend_le_conns) &&
-           list_empty(&hdev->pend_le_reports) &&
-           !hci_is_adv_monitoring(hdev)) {
-               /* If there is no pending LE connections or devices
-                * to be scanned for or no ADV monitors, we should stop the
-                * background scanning.
-                */
-
-               /* If controller is not scanning we are done. */
-               if (!hci_dev_test_flag(hdev, HCI_LE_SCAN))
-                       return;
-
-               hci_req_add_le_scan_disable(req, false);
-
-               bt_dev_dbg(hdev, "stopping background scanning");
-       } else {
-               /* If there is at least one pending LE connection, we should
-                * keep the background scan running.
-                */
-
-               /* If controller is connecting, we should not start scanning
-                * since some controllers are not able to scan and connect at
-                * the same time.
-                */
-               if (hci_lookup_le_connect(hdev))
-                       return;
-
-               /* If controller is currently scanning, we stop it to ensure we
-                * don't miss any advertising (due to duplicates filter).
-                */
-               if (hci_dev_test_flag(hdev, HCI_LE_SCAN))
-                       hci_req_add_le_scan_disable(req, false);
-
-               hci_req_add_le_passive_scan(req);
-               bt_dev_dbg(hdev, "starting background scanning");
-       }
-}
-
 void __hci_req_update_name(struct hci_request *req)
 {
        struct hci_dev *hdev = req->hdev;
@@ -560,9 +416,6 @@ void hci_req_add_le_scan_disable(struct hci_request *req, bool rpa_le_conn)
                return;
        }
 
-       if (hdev->suspended)
-               set_bit(SUSPEND_SCAN_DISABLE, hdev->suspend_tasks);
-
        if (use_ext_scan(hdev)) {
                struct hci_cp_le_set_ext_scan_enable cp;
 
@@ -579,9 +432,7 @@ void hci_req_add_le_scan_disable(struct hci_request *req, bool rpa_le_conn)
        }
 
        /* Disable address resolution */
-       if (use_ll_privacy(hdev) &&
-           hci_dev_test_flag(hdev, HCI_ENABLE_LL_PRIVACY) &&
-           hci_dev_test_flag(hdev, HCI_LL_RPA_RESOLUTION) && !rpa_le_conn) {
+       if (hci_dev_test_flag(hdev, HCI_LL_RPA_RESOLUTION) && !rpa_le_conn) {
                __u8 enable = 0x00;
 
                hci_req_add(req, HCI_OP_LE_SET_ADDR_RESOLV_ENABLE, 1, &enable);
@@ -600,8 +451,7 @@ static void del_from_accept_list(struct hci_request *req, bdaddr_t *bdaddr,
                   cp.bdaddr_type);
        hci_req_add(req, HCI_OP_LE_DEL_FROM_ACCEPT_LIST, sizeof(cp), &cp);
 
-       if (use_ll_privacy(req->hdev) &&
-           hci_dev_test_flag(req->hdev, HCI_ENABLE_LL_PRIVACY)) {
+       if (use_ll_privacy(req->hdev)) {
                struct smp_irk *irk;
 
                irk = hci_find_irk_by_addr(req->hdev, bdaddr, bdaddr_type);
@@ -654,8 +504,7 @@ static int add_to_accept_list(struct hci_request *req,
                   cp.bdaddr_type);
        hci_req_add(req, HCI_OP_LE_ADD_TO_ACCEPT_LIST, sizeof(cp), &cp);
 
-       if (use_ll_privacy(hdev) &&
-           hci_dev_test_flag(hdev, HCI_ENABLE_LL_PRIVACY)) {
+       if (use_ll_privacy(hdev)) {
                struct smp_irk *irk;
 
                irk = hci_find_irk_by_addr(hdev, &params->addr,
@@ -694,8 +543,7 @@ static u8 update_accept_list(struct hci_request *req)
         */
        bool allow_rpa = hdev->suspended;
 
-       if (use_ll_privacy(hdev) &&
-           hci_dev_test_flag(hdev, HCI_ENABLE_LL_PRIVACY))
+       if (use_ll_privacy(hdev))
                allow_rpa = true;
 
        /* Go through the current accept list programmed into the
@@ -784,9 +632,7 @@ static void hci_req_start_scan(struct hci_request *req, u8 type, u16 interval,
                return;
        }
 
-       if (use_ll_privacy(hdev) &&
-           hci_dev_test_flag(hdev, HCI_ENABLE_LL_PRIVACY) &&
-           addr_resolv) {
+       if (use_ll_privacy(hdev) && addr_resolv) {
                u8 enable = 0x01;
 
                hci_req_add(req, HCI_OP_LE_SET_ADDR_RESOLV_ENABLE, 1, &enable);
@@ -943,8 +789,6 @@ void hci_req_add_le_passive_scan(struct hci_request *req)
        if (hdev->suspended) {
                window = hdev->le_scan_window_suspend;
                interval = hdev->le_scan_int_suspend;
-
-               set_bit(SUSPEND_SCAN_ENABLE, hdev->suspend_tasks);
        } else if (hci_is_le_conn_scanning(hdev)) {
                window = hdev->le_scan_window_connect;
                interval = hdev->le_scan_int_connect;
@@ -977,59 +821,6 @@ void hci_req_add_le_passive_scan(struct hci_request *req)
                           addr_resolv);
 }
 
-static void hci_req_clear_event_filter(struct hci_request *req)
-{
-       struct hci_cp_set_event_filter f;
-
-       if (!hci_dev_test_flag(req->hdev, HCI_BREDR_ENABLED))
-               return;
-
-       if (hci_dev_test_flag(req->hdev, HCI_EVENT_FILTER_CONFIGURED)) {
-               memset(&f, 0, sizeof(f));
-               f.flt_type = HCI_FLT_CLEAR_ALL;
-               hci_req_add(req, HCI_OP_SET_EVENT_FLT, 1, &f);
-       }
-}
-
-static void hci_req_set_event_filter(struct hci_request *req)
-{
-       struct bdaddr_list_with_flags *b;
-       struct hci_cp_set_event_filter f;
-       struct hci_dev *hdev = req->hdev;
-       u8 scan = SCAN_DISABLED;
-       bool scanning = test_bit(HCI_PSCAN, &hdev->flags);
-
-       if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
-               return;
-
-       /* Always clear event filter when starting */
-       hci_req_clear_event_filter(req);
-
-       list_for_each_entry(b, &hdev->accept_list, list) {
-               if (!hci_conn_test_flag(HCI_CONN_FLAG_REMOTE_WAKEUP,
-                                       b->current_flags))
-                       continue;
-
-               memset(&f, 0, sizeof(f));
-               bacpy(&f.addr_conn_flt.bdaddr, &b->bdaddr);
-               f.flt_type = HCI_FLT_CONN_SETUP;
-               f.cond_type = HCI_CONN_SETUP_ALLOW_BDADDR;
-               f.addr_conn_flt.auto_accept = HCI_CONN_SETUP_AUTO_ON;
-
-               bt_dev_dbg(hdev, "Adding event filters for %pMR", &b->bdaddr);
-               hci_req_add(req, HCI_OP_SET_EVENT_FLT, sizeof(f), &f);
-               scan = SCAN_PAGE;
-       }
-
-       if (scan && !scanning) {
-               set_bit(SUSPEND_SCAN_ENABLE, hdev->suspend_tasks);
-               hci_req_add(req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
-       } else if (!scan && scanning) {
-               set_bit(SUSPEND_SCAN_DISABLE, hdev->suspend_tasks);
-               hci_req_add(req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
-       }
-}
-
 static void cancel_adv_timeout(struct hci_dev *hdev)
 {
        if (hdev->adv_instance_timeout) {
@@ -1088,185 +879,6 @@ int hci_req_resume_adv_instances(struct hci_dev *hdev)
        return hci_req_run(&req, NULL);
 }
 
-static void suspend_req_complete(struct hci_dev *hdev, u8 status, u16 opcode)
-{
-       bt_dev_dbg(hdev, "Request complete opcode=0x%x, status=0x%x", opcode,
-                  status);
-       if (test_bit(SUSPEND_SCAN_ENABLE, hdev->suspend_tasks) ||
-           test_bit(SUSPEND_SCAN_DISABLE, hdev->suspend_tasks)) {
-               clear_bit(SUSPEND_SCAN_ENABLE, hdev->suspend_tasks);
-               clear_bit(SUSPEND_SCAN_DISABLE, hdev->suspend_tasks);
-               wake_up(&hdev->suspend_wait_q);
-       }
-
-       if (test_bit(SUSPEND_SET_ADV_FILTER, hdev->suspend_tasks)) {
-               clear_bit(SUSPEND_SET_ADV_FILTER, hdev->suspend_tasks);
-               wake_up(&hdev->suspend_wait_q);
-       }
-}
-
-static void hci_req_prepare_adv_monitor_suspend(struct hci_request *req,
-                                               bool suspending)
-{
-       struct hci_dev *hdev = req->hdev;
-
-       switch (hci_get_adv_monitor_offload_ext(hdev)) {
-       case HCI_ADV_MONITOR_EXT_MSFT:
-               if (suspending)
-                       msft_suspend(hdev);
-               else
-                       msft_resume(hdev);
-               break;
-       default:
-               return;
-       }
-
-       /* No need to block when enabling since it's on resume path */
-       if (hdev->suspended && suspending)
-               set_bit(SUSPEND_SET_ADV_FILTER, hdev->suspend_tasks);
-}
-
-/* Call with hci_dev_lock */
-void hci_req_prepare_suspend(struct hci_dev *hdev, enum suspended_state next)
-{
-       int old_state;
-       struct hci_conn *conn;
-       struct hci_request req;
-       u8 page_scan;
-       int disconnect_counter;
-
-       if (next == hdev->suspend_state) {
-               bt_dev_dbg(hdev, "Same state before and after: %d", next);
-               goto done;
-       }
-
-       hdev->suspend_state = next;
-       hci_req_init(&req, hdev);
-
-       if (next == BT_SUSPEND_DISCONNECT) {
-               /* Mark device as suspended */
-               hdev->suspended = true;
-
-               /* Pause discovery if not already stopped */
-               old_state = hdev->discovery.state;
-               if (old_state != DISCOVERY_STOPPED) {
-                       set_bit(SUSPEND_PAUSE_DISCOVERY, hdev->suspend_tasks);
-                       hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
-                       queue_work(hdev->req_workqueue, &hdev->discov_update);
-               }
-
-               hdev->discovery_paused = true;
-               hdev->discovery_old_state = old_state;
-
-               /* Stop directed advertising */
-               old_state = hci_dev_test_flag(hdev, HCI_ADVERTISING);
-               if (old_state) {
-                       set_bit(SUSPEND_PAUSE_ADVERTISING, hdev->suspend_tasks);
-                       cancel_delayed_work(&hdev->discov_off);
-                       queue_delayed_work(hdev->req_workqueue,
-                                          &hdev->discov_off, 0);
-               }
-
-               /* Pause other advertisements */
-               if (hdev->adv_instance_cnt)
-                       __hci_req_pause_adv_instances(&req);
-
-               hdev->advertising_paused = true;
-               hdev->advertising_old_state = old_state;
-
-               /* Disable page scan if enabled */
-               if (test_bit(HCI_PSCAN, &hdev->flags)) {
-                       page_scan = SCAN_DISABLED;
-                       hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1,
-                                   &page_scan);
-                       set_bit(SUSPEND_SCAN_DISABLE, hdev->suspend_tasks);
-               }
-
-               /* Disable LE passive scan if enabled */
-               if (hci_dev_test_flag(hdev, HCI_LE_SCAN)) {
-                       cancel_interleave_scan(hdev);
-                       hci_req_add_le_scan_disable(&req, false);
-               }
-
-               /* Disable advertisement filters */
-               hci_req_prepare_adv_monitor_suspend(&req, true);
-
-               /* Prevent disconnects from causing scanning to be re-enabled */
-               hdev->scanning_paused = true;
-
-               /* Run commands before disconnecting */
-               hci_req_run(&req, suspend_req_complete);
-
-               disconnect_counter = 0;
-               /* Soft disconnect everything (power off) */
-               list_for_each_entry(conn, &hdev->conn_hash.list, list) {
-                       hci_disconnect(conn, HCI_ERROR_REMOTE_POWER_OFF);
-                       disconnect_counter++;
-               }
-
-               if (disconnect_counter > 0) {
-                       bt_dev_dbg(hdev,
-                                  "Had %d disconnects. Will wait on them",
-                                  disconnect_counter);
-                       set_bit(SUSPEND_DISCONNECTING, hdev->suspend_tasks);
-               }
-       } else if (next == BT_SUSPEND_CONFIGURE_WAKE) {
-               /* Unpause to take care of updating scanning params */
-               hdev->scanning_paused = false;
-               /* Enable event filter for paired devices */
-               hci_req_set_event_filter(&req);
-               /* Enable passive scan at lower duty cycle */
-               __hci_update_background_scan(&req);
-               /* Pause scan changes again. */
-               hdev->scanning_paused = true;
-               hci_req_run(&req, suspend_req_complete);
-       } else {
-               hdev->suspended = false;
-               hdev->scanning_paused = false;
-
-               /* Clear any event filters and restore scan state */
-               hci_req_clear_event_filter(&req);
-               __hci_req_update_scan(&req);
-
-               /* Reset passive/background scanning to normal */
-               __hci_update_background_scan(&req);
-               /* Enable all of the advertisement filters */
-               hci_req_prepare_adv_monitor_suspend(&req, false);
-
-               /* Unpause directed advertising */
-               hdev->advertising_paused = false;
-               if (hdev->advertising_old_state) {
-                       set_bit(SUSPEND_UNPAUSE_ADVERTISING,
-                               hdev->suspend_tasks);
-                       hci_dev_set_flag(hdev, HCI_ADVERTISING);
-                       queue_work(hdev->req_workqueue,
-                                  &hdev->discoverable_update);
-                       hdev->advertising_old_state = 0;
-               }
-
-               /* Resume other advertisements */
-               if (hdev->adv_instance_cnt)
-                       __hci_req_resume_adv_instances(&req);
-
-               /* Unpause discovery */
-               hdev->discovery_paused = false;
-               if (hdev->discovery_old_state != DISCOVERY_STOPPED &&
-                   hdev->discovery_old_state != DISCOVERY_STOPPING) {
-                       set_bit(SUSPEND_UNPAUSE_DISCOVERY, hdev->suspend_tasks);
-                       hci_discovery_set_state(hdev, DISCOVERY_STARTING);
-                       queue_work(hdev->req_workqueue, &hdev->discov_update);
-               }
-
-               hci_req_run(&req, suspend_req_complete);
-       }
-
-       hdev->suspend_state = next;
-
-done:
-       clear_bit(SUSPEND_PREPARE_NOTIFIER, hdev->suspend_tasks);
-       wake_up(&hdev->suspend_wait_q);
-}
-
 static bool adv_cur_instance_is_scannable(struct hci_dev *hdev)
 {
        return hci_adv_instance_is_scannable(hdev, hdev->cur_adv_instance);
@@ -1548,8 +1160,7 @@ void hci_req_disable_address_resolution(struct hci_dev *hdev)
        struct hci_request req;
        __u8 enable = 0x00;
 
-       if (!use_ll_privacy(hdev) &&
-           !hci_dev_test_flag(hdev, HCI_LL_RPA_RESOLUTION))
+       if (!hci_dev_test_flag(hdev, HCI_LL_RPA_RESOLUTION))
                return;
 
        hci_req_init(&req, hdev);
@@ -1692,8 +1303,7 @@ int hci_get_random_address(struct hci_dev *hdev, bool require_privacy,
                /* If Controller supports LL Privacy use own address type is
                 * 0x03
                 */
-               if (use_ll_privacy(hdev) &&
-                   hci_dev_test_flag(hdev, HCI_ENABLE_LL_PRIVACY))
+               if (use_ll_privacy(hdev))
                        *own_addr_type = ADDR_LE_DEV_RANDOM_RESOLVED;
                else
                        *own_addr_type = ADDR_LE_DEV_RANDOM;
@@ -1871,7 +1481,8 @@ int __hci_req_setup_ext_adv_instance(struct hci_request *req, u8 instance)
 
        hci_req_add(req, HCI_OP_LE_SET_EXT_ADV_PARAMS, sizeof(cp), &cp);
 
-       if (own_addr_type == ADDR_LE_DEV_RANDOM &&
+       if ((own_addr_type == ADDR_LE_DEV_RANDOM ||
+            own_addr_type == ADDR_LE_DEV_RANDOM_RESOLVED) &&
            bacmp(&random_addr, BDADDR_ANY)) {
                struct hci_cp_le_set_adv_set_rand_addr cp;
 
@@ -2160,8 +1771,7 @@ int hci_update_random_address(struct hci_request *req, bool require_privacy,
                /* If Controller supports LL Privacy use own address type is
                 * 0x03
                 */
-               if (use_ll_privacy(hdev) &&
-                   hci_dev_test_flag(hdev, HCI_ENABLE_LL_PRIVACY))
+               if (use_ll_privacy(hdev))
                        *own_addr_type = ADDR_LE_DEV_RANDOM_RESOLVED;
                else
                        *own_addr_type = ADDR_LE_DEV_RANDOM;
@@ -2301,47 +1911,6 @@ static void scan_update_work(struct work_struct *work)
        hci_req_sync(hdev, update_scan, 0, HCI_CMD_TIMEOUT, NULL);
 }
 
-static int connectable_update(struct hci_request *req, unsigned long opt)
-{
-       struct hci_dev *hdev = req->hdev;
-
-       hci_dev_lock(hdev);
-
-       __hci_req_update_scan(req);
-
-       /* If BR/EDR is not enabled and we disable advertising as a
-        * by-product of disabling connectable, we need to update the
-        * advertising flags.
-        */
-       if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
-               __hci_req_update_adv_data(req, hdev->cur_adv_instance);
-
-       /* Update the advertising parameters if necessary */
-       if (hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
-           !list_empty(&hdev->adv_instances)) {
-               if (ext_adv_capable(hdev))
-                       __hci_req_start_ext_adv(req, hdev->cur_adv_instance);
-               else
-                       __hci_req_enable_advertising(req);
-       }
-
-       __hci_update_background_scan(req);
-
-       hci_dev_unlock(hdev);
-
-       return 0;
-}
-
-static void connectable_update_work(struct work_struct *work)
-{
-       struct hci_dev *hdev = container_of(work, struct hci_dev,
-                                           connectable_update);
-       u8 status;
-
-       hci_req_sync(hdev, connectable_update, 0, HCI_CMD_TIMEOUT, &status);
-       mgmt_set_connectable_complete(hdev, status);
-}
-
 static u8 get_service_classes(struct hci_dev *hdev)
 {
        struct bt_uuid *uuid;
@@ -2445,16 +2014,6 @@ static int discoverable_update(struct hci_request *req, unsigned long opt)
        return 0;
 }
 
-static void discoverable_update_work(struct work_struct *work)
-{
-       struct hci_dev *hdev = container_of(work, struct hci_dev,
-                                           discoverable_update);
-       u8 status;
-
-       hci_req_sync(hdev, discoverable_update, 0, HCI_CMD_TIMEOUT, &status);
-       mgmt_set_discoverable_complete(hdev, status);
-}
-
 void __hci_abort_conn(struct hci_request *req, struct hci_conn *conn,
                      u8 reason)
 {
@@ -2548,35 +2107,6 @@ int hci_abort_conn(struct hci_conn *conn, u8 reason)
        return 0;
 }
 
-static int update_bg_scan(struct hci_request *req, unsigned long opt)
-{
-       hci_dev_lock(req->hdev);
-       __hci_update_background_scan(req);
-       hci_dev_unlock(req->hdev);
-       return 0;
-}
-
-static void bg_scan_update(struct work_struct *work)
-{
-       struct hci_dev *hdev = container_of(work, struct hci_dev,
-                                           bg_scan_update);
-       struct hci_conn *conn;
-       u8 status;
-       int err;
-
-       err = hci_req_sync(hdev, update_bg_scan, 0, HCI_CMD_TIMEOUT, &status);
-       if (!err)
-               return;
-
-       hci_dev_lock(hdev);
-
-       conn = hci_conn_hash_lookup_state(hdev, LE_LINK, BT_CONNECT);
-       if (conn)
-               hci_le_conn_failed(conn, status);
-
-       hci_dev_unlock(hdev);
-}
-
 static int le_scan_disable(struct hci_request *req, unsigned long opt)
 {
        hci_req_add_le_scan_disable(req, false);
@@ -3163,10 +2693,7 @@ int __hci_req_hci_power_on(struct hci_dev *hdev)
 void hci_request_setup(struct hci_dev *hdev)
 {
        INIT_WORK(&hdev->discov_update, discov_update);
-       INIT_WORK(&hdev->bg_scan_update, bg_scan_update);
        INIT_WORK(&hdev->scan_update, scan_update_work);
-       INIT_WORK(&hdev->connectable_update, connectable_update_work);
-       INIT_WORK(&hdev->discoverable_update, discoverable_update_work);
        INIT_DELAYED_WORK(&hdev->discov_off, discov_off);
        INIT_DELAYED_WORK(&hdev->le_scan_disable, le_scan_disable_work);
        INIT_DELAYED_WORK(&hdev->le_scan_restart, le_scan_restart_work);
@@ -3179,10 +2706,7 @@ void hci_request_cancel_all(struct hci_dev *hdev)
        hci_req_sync_cancel(hdev, ENODEV);
 
        cancel_work_sync(&hdev->discov_update);
-       cancel_work_sync(&hdev->bg_scan_update);
        cancel_work_sync(&hdev->scan_update);
-       cancel_work_sync(&hdev->connectable_update);
-       cancel_work_sync(&hdev->discoverable_update);
        cancel_delayed_work_sync(&hdev->discov_off);
        cancel_delayed_work_sync(&hdev->le_scan_disable);
        cancel_delayed_work_sync(&hdev->le_scan_restart);
index f31420f..5f8e884 100644 (file)
 
 #include <asm/unaligned.h>
 
+#define HCI_REQ_DONE     0
+#define HCI_REQ_PEND     1
+#define HCI_REQ_CANCELED  2
+
 #define hci_req_sync_lock(hdev)   mutex_lock(&hdev->req_lock)
 #define hci_req_sync_unlock(hdev) mutex_unlock(&hdev->req_lock)
 
+#define HCI_REQ_DONE     0
+#define HCI_REQ_PEND     1
+#define HCI_REQ_CANCELED  2
+
 struct hci_request {
        struct hci_dev          *hdev;
        struct sk_buff_head     cmd_q;
@@ -40,6 +48,8 @@ void hci_req_purge(struct hci_request *req);
 bool hci_req_status_pend(struct hci_dev *hdev);
 int hci_req_run(struct hci_request *req, hci_req_complete_t complete);
 int hci_req_run_skb(struct hci_request *req, hci_req_complete_skb_t complete);
+void hci_req_sync_complete(struct hci_dev *hdev, u8 result, u16 opcode,
+                          struct sk_buff *skb);
 void hci_req_add(struct hci_request *req, u16 opcode, u32 plen,
                 const void *param);
 void hci_req_add_ev(struct hci_request *req, u16 opcode, u32 plen,
@@ -117,10 +127,5 @@ int hci_abort_conn(struct hci_conn *conn, u8 reason);
 void __hci_abort_conn(struct hci_request *req, struct hci_conn *conn,
                      u8 reason);
 
-static inline void hci_update_background_scan(struct hci_dev *hdev)
-{
-       queue_work(hdev->req_workqueue, &hdev->bg_scan_update);
-}
-
 void hci_request_setup(struct hci_dev *hdev);
 void hci_request_cancel_all(struct hci_dev *hdev);
index d0dad1f..446573a 100644 (file)
@@ -889,10 +889,6 @@ static int hci_sock_release(struct socket *sock)
        }
 
        sock_orphan(sk);
-
-       skb_queue_purge(&sk->sk_receive_queue);
-       skb_queue_purge(&sk->sk_write_queue);
-
        release_sock(sk);
        sock_put(sk);
        return 0;
@@ -2058,6 +2054,12 @@ static int hci_sock_getsockopt(struct socket *sock, int level, int optname,
        return err;
 }
 
+static void hci_sock_destruct(struct sock *sk)
+{
+       skb_queue_purge(&sk->sk_receive_queue);
+       skb_queue_purge(&sk->sk_write_queue);
+}
+
 static const struct proto_ops hci_sock_ops = {
        .family         = PF_BLUETOOTH,
        .owner          = THIS_MODULE,
@@ -2111,6 +2113,7 @@ static int hci_sock_create(struct net *net, struct socket *sock, int protocol,
 
        sock->state = SS_UNCONNECTED;
        sk->sk_state = BT_OPEN;
+       sk->sk_destruct = hci_sock_destruct;
 
        bt_sock_link(&hci_sk_list, sk);
        return 0;
diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c
new file mode 100644 (file)
index 0000000..ad86caf
--- /dev/null
@@ -0,0 +1,4922 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2021 Intel Corporation
+ */
+
+#include <linux/property.h>
+
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci_core.h>
+#include <net/bluetooth/mgmt.h>
+
+#include "hci_request.h"
+#include "hci_debugfs.h"
+#include "smp.h"
+#include "eir.h"
+#include "msft.h"
+#include "aosp.h"
+#include "leds.h"
+
+static void hci_cmd_sync_complete(struct hci_dev *hdev, u8 result, u16 opcode,
+                                 struct sk_buff *skb)
+{
+       bt_dev_dbg(hdev, "result 0x%2.2x", result);
+
+       if (hdev->req_status != HCI_REQ_PEND)
+               return;
+
+       hdev->req_result = result;
+       hdev->req_status = HCI_REQ_DONE;
+
+       if (skb) {
+               struct sock *sk = hci_skb_sk(skb);
+
+               /* Drop sk reference if set */
+               if (sk)
+                       sock_put(sk);
+
+               hdev->req_skb = skb_get(skb);
+       }
+
+       wake_up_interruptible(&hdev->req_wait_q);
+}
+
+static struct sk_buff *hci_cmd_sync_alloc(struct hci_dev *hdev, u16 opcode,
+                                         u32 plen, const void *param,
+                                         struct sock *sk)
+{
+       int len = HCI_COMMAND_HDR_SIZE + plen;
+       struct hci_command_hdr *hdr;
+       struct sk_buff *skb;
+
+       skb = bt_skb_alloc(len, GFP_ATOMIC);
+       if (!skb)
+               return NULL;
+
+       hdr = skb_put(skb, HCI_COMMAND_HDR_SIZE);
+       hdr->opcode = cpu_to_le16(opcode);
+       hdr->plen   = plen;
+
+       if (plen)
+               skb_put_data(skb, param, plen);
+
+       bt_dev_dbg(hdev, "skb len %d", skb->len);
+
+       hci_skb_pkt_type(skb) = HCI_COMMAND_PKT;
+       hci_skb_opcode(skb) = opcode;
+
+       /* Grab a reference if command needs to be associated with a sock (e.g.
+        * likely mgmt socket that initiated the command).
+        */
+       if (sk) {
+               hci_skb_sk(skb) = sk;
+               sock_hold(sk);
+       }
+
+       return skb;
+}
+
+static void hci_cmd_sync_add(struct hci_request *req, u16 opcode, u32 plen,
+                            const void *param, u8 event, struct sock *sk)
+{
+       struct hci_dev *hdev = req->hdev;
+       struct sk_buff *skb;
+
+       bt_dev_dbg(hdev, "opcode 0x%4.4x plen %d", opcode, plen);
+
+       /* If an error occurred during request building, there is no point in
+        * queueing the HCI command. We can simply return.
+        */
+       if (req->err)
+               return;
+
+       skb = hci_cmd_sync_alloc(hdev, opcode, plen, param, sk);
+       if (!skb) {
+               bt_dev_err(hdev, "no memory for command (opcode 0x%4.4x)",
+                          opcode);
+               req->err = -ENOMEM;
+               return;
+       }
+
+       if (skb_queue_empty(&req->cmd_q))
+               bt_cb(skb)->hci.req_flags |= HCI_REQ_START;
+
+       bt_cb(skb)->hci.req_event = event;
+
+       skb_queue_tail(&req->cmd_q, skb);
+}
+
+static int hci_cmd_sync_run(struct hci_request *req)
+{
+       struct hci_dev *hdev = req->hdev;
+       struct sk_buff *skb;
+       unsigned long flags;
+
+       bt_dev_dbg(hdev, "length %u", skb_queue_len(&req->cmd_q));
+
+       /* If an error occurred during request building, remove all HCI
+        * commands queued on the HCI request queue.
+        */
+       if (req->err) {
+               skb_queue_purge(&req->cmd_q);
+               return req->err;
+       }
+
+       /* Do not allow empty requests */
+       if (skb_queue_empty(&req->cmd_q))
+               return -ENODATA;
+
+       skb = skb_peek_tail(&req->cmd_q);
+       bt_cb(skb)->hci.req_complete_skb = hci_cmd_sync_complete;
+       bt_cb(skb)->hci.req_flags |= HCI_REQ_SKB;
+
+       spin_lock_irqsave(&hdev->cmd_q.lock, flags);
+       skb_queue_splice_tail(&req->cmd_q, &hdev->cmd_q);
+       spin_unlock_irqrestore(&hdev->cmd_q.lock, flags);
+
+       queue_work(hdev->workqueue, &hdev->cmd_work);
+
+       return 0;
+}
+
+/* This function requires the caller holds hdev->req_lock. */
+struct sk_buff *__hci_cmd_sync_sk(struct hci_dev *hdev, u16 opcode, u32 plen,
+                                 const void *param, u8 event, u32 timeout,
+                                 struct sock *sk)
+{
+       struct hci_request req;
+       struct sk_buff *skb;
+       int err = 0;
+
+       bt_dev_dbg(hdev, "Opcode 0x%4x", opcode);
+
+       hci_req_init(&req, hdev);
+
+       hci_cmd_sync_add(&req, opcode, plen, param, event, sk);
+
+       hdev->req_status = HCI_REQ_PEND;
+
+       err = hci_cmd_sync_run(&req);
+       if (err < 0)
+               return ERR_PTR(err);
+
+       err = wait_event_interruptible_timeout(hdev->req_wait_q,
+                                              hdev->req_status != HCI_REQ_PEND,
+                                              timeout);
+
+       if (err == -ERESTARTSYS)
+               return ERR_PTR(-EINTR);
+
+       switch (hdev->req_status) {
+       case HCI_REQ_DONE:
+               err = -bt_to_errno(hdev->req_result);
+               break;
+
+       case HCI_REQ_CANCELED:
+               err = -hdev->req_result;
+               break;
+
+       default:
+               err = -ETIMEDOUT;
+               break;
+       }
+
+       hdev->req_status = 0;
+       hdev->req_result = 0;
+       skb = hdev->req_skb;
+       hdev->req_skb = NULL;
+
+       bt_dev_dbg(hdev, "end: err %d", err);
+
+       if (err < 0) {
+               kfree_skb(skb);
+               return ERR_PTR(err);
+       }
+
+       return skb;
+}
+EXPORT_SYMBOL(__hci_cmd_sync_sk);
+
+/* This function requires the caller holds hdev->req_lock. */
+struct sk_buff *__hci_cmd_sync(struct hci_dev *hdev, u16 opcode, u32 plen,
+                              const void *param, u32 timeout)
+{
+       return __hci_cmd_sync_sk(hdev, opcode, plen, param, 0, timeout, NULL);
+}
+EXPORT_SYMBOL(__hci_cmd_sync);
+
+/* Send HCI command and wait for command complete event */
+struct sk_buff *hci_cmd_sync(struct hci_dev *hdev, u16 opcode, u32 plen,
+                            const void *param, u32 timeout)
+{
+       struct sk_buff *skb;
+
+       if (!test_bit(HCI_UP, &hdev->flags))
+               return ERR_PTR(-ENETDOWN);
+
+       bt_dev_dbg(hdev, "opcode 0x%4.4x plen %d", opcode, plen);
+
+       hci_req_sync_lock(hdev);
+       skb = __hci_cmd_sync(hdev, opcode, plen, param, timeout);
+       hci_req_sync_unlock(hdev);
+
+       return skb;
+}
+EXPORT_SYMBOL(hci_cmd_sync);
+
+/* This function requires the caller holds hdev->req_lock. */
+struct sk_buff *__hci_cmd_sync_ev(struct hci_dev *hdev, u16 opcode, u32 plen,
+                                 const void *param, u8 event, u32 timeout)
+{
+       return __hci_cmd_sync_sk(hdev, opcode, plen, param, event, timeout,
+                                NULL);
+}
+EXPORT_SYMBOL(__hci_cmd_sync_ev);
+
+/* This function requires the caller holds hdev->req_lock. */
+int __hci_cmd_sync_status_sk(struct hci_dev *hdev, u16 opcode, u32 plen,
+                            const void *param, u8 event, u32 timeout,
+                            struct sock *sk)
+{
+       struct sk_buff *skb;
+       u8 status;
+
+       skb = __hci_cmd_sync_sk(hdev, opcode, plen, param, event, timeout, sk);
+       if (IS_ERR(skb)) {
+               bt_dev_err(hdev, "Opcode 0x%4x failed: %ld", opcode,
+                          PTR_ERR(skb));
+               return PTR_ERR(skb);
+       }
+
+       /* If command return a status event skb will be set to NULL as there are
+        * no parameters, in case of failure IS_ERR(skb) would have be set to
+        * the actual error would be found with PTR_ERR(skb).
+        */
+       if (!skb)
+               return 0;
+
+       status = skb->data[0];
+
+       kfree_skb(skb);
+
+       return status;
+}
+EXPORT_SYMBOL(__hci_cmd_sync_status_sk);
+
+int __hci_cmd_sync_status(struct hci_dev *hdev, u16 opcode, u32 plen,
+                         const void *param, u32 timeout)
+{
+       return __hci_cmd_sync_status_sk(hdev, opcode, plen, param, 0, timeout,
+                                       NULL);
+}
+EXPORT_SYMBOL(__hci_cmd_sync_status);
+
+static void hci_cmd_sync_work(struct work_struct *work)
+{
+       struct hci_dev *hdev = container_of(work, struct hci_dev, cmd_sync_work);
+       struct hci_cmd_sync_work_entry *entry;
+       hci_cmd_sync_work_func_t func;
+       hci_cmd_sync_work_destroy_t destroy;
+       void *data;
+
+       bt_dev_dbg(hdev, "");
+
+       mutex_lock(&hdev->cmd_sync_work_lock);
+       entry = list_first_entry(&hdev->cmd_sync_work_list,
+                                struct hci_cmd_sync_work_entry, list);
+       if (entry) {
+               list_del(&entry->list);
+               func = entry->func;
+               data = entry->data;
+               destroy = entry->destroy;
+               kfree(entry);
+       } else {
+               func = NULL;
+               data = NULL;
+               destroy = NULL;
+       }
+       mutex_unlock(&hdev->cmd_sync_work_lock);
+
+       if (func) {
+               int err;
+
+               hci_req_sync_lock(hdev);
+
+               err = func(hdev, data);
+
+               if (destroy)
+                       destroy(hdev, data, err);
+
+               hci_req_sync_unlock(hdev);
+       }
+}
+
+void hci_cmd_sync_init(struct hci_dev *hdev)
+{
+       INIT_WORK(&hdev->cmd_sync_work, hci_cmd_sync_work);
+       INIT_LIST_HEAD(&hdev->cmd_sync_work_list);
+       mutex_init(&hdev->cmd_sync_work_lock);
+}
+
+void hci_cmd_sync_clear(struct hci_dev *hdev)
+{
+       struct hci_cmd_sync_work_entry *entry, *tmp;
+
+       cancel_work_sync(&hdev->cmd_sync_work);
+
+       list_for_each_entry_safe(entry, tmp, &hdev->cmd_sync_work_list, list) {
+               if (entry->destroy)
+                       entry->destroy(hdev, entry->data, -ECANCELED);
+
+               list_del(&entry->list);
+               kfree(entry);
+       }
+}
+
+int hci_cmd_sync_queue(struct hci_dev *hdev, hci_cmd_sync_work_func_t func,
+                      void *data, hci_cmd_sync_work_destroy_t destroy)
+{
+       struct hci_cmd_sync_work_entry *entry;
+
+       entry = kmalloc(sizeof(*entry), GFP_KERNEL);
+       if (!entry)
+               return -ENOMEM;
+
+       entry->func = func;
+       entry->data = data;
+       entry->destroy = destroy;
+
+       mutex_lock(&hdev->cmd_sync_work_lock);
+       list_add_tail(&entry->list, &hdev->cmd_sync_work_list);
+       mutex_unlock(&hdev->cmd_sync_work_lock);
+
+       queue_work(hdev->req_workqueue, &hdev->cmd_sync_work);
+
+       return 0;
+}
+EXPORT_SYMBOL(hci_cmd_sync_queue);
+
+int hci_update_eir_sync(struct hci_dev *hdev)
+{
+       struct hci_cp_write_eir cp;
+
+       bt_dev_dbg(hdev, "");
+
+       if (!hdev_is_powered(hdev))
+               return 0;
+
+       if (!lmp_ext_inq_capable(hdev))
+               return 0;
+
+       if (!hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
+               return 0;
+
+       if (hci_dev_test_flag(hdev, HCI_SERVICE_CACHE))
+               return 0;
+
+       memset(&cp, 0, sizeof(cp));
+
+       eir_create(hdev, cp.data);
+
+       if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
+               return 0;
+
+       memcpy(hdev->eir, cp.data, sizeof(cp.data));
+
+       return __hci_cmd_sync_status(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp,
+                                    HCI_CMD_TIMEOUT);
+}
+
+static u8 get_service_classes(struct hci_dev *hdev)
+{
+       struct bt_uuid *uuid;
+       u8 val = 0;
+
+       list_for_each_entry(uuid, &hdev->uuids, list)
+               val |= uuid->svc_hint;
+
+       return val;
+}
+
+int hci_update_class_sync(struct hci_dev *hdev)
+{
+       u8 cod[3];
+
+       bt_dev_dbg(hdev, "");
+
+       if (!hdev_is_powered(hdev))
+               return 0;
+
+       if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
+               return 0;
+
+       if (hci_dev_test_flag(hdev, HCI_SERVICE_CACHE))
+               return 0;
+
+       cod[0] = hdev->minor_class;
+       cod[1] = hdev->major_class;
+       cod[2] = get_service_classes(hdev);
+
+       if (hci_dev_test_flag(hdev, HCI_LIMITED_DISCOVERABLE))
+               cod[1] |= 0x20;
+
+       if (memcmp(cod, hdev->dev_class, 3) == 0)
+               return 0;
+
+       return __hci_cmd_sync_status(hdev, HCI_OP_WRITE_CLASS_OF_DEV,
+                                    sizeof(cod), cod, HCI_CMD_TIMEOUT);
+}
+
+static bool is_advertising_allowed(struct hci_dev *hdev, bool connectable)
+{
+       /* If there is no connection we are OK to advertise. */
+       if (hci_conn_num(hdev, LE_LINK) == 0)
+               return true;
+
+       /* Check le_states if there is any connection in peripheral role. */
+       if (hdev->conn_hash.le_num_peripheral > 0) {
+               /* Peripheral connection state and non connectable mode
+                * bit 20.
+                */
+               if (!connectable && !(hdev->le_states[2] & 0x10))
+                       return false;
+
+               /* Peripheral connection state and connectable mode bit 38
+                * and scannable bit 21.
+                */
+               if (connectable && (!(hdev->le_states[4] & 0x40) ||
+                                   !(hdev->le_states[2] & 0x20)))
+                       return false;
+       }
+
+       /* Check le_states if there is any connection in central role. */
+       if (hci_conn_num(hdev, LE_LINK) != hdev->conn_hash.le_num_peripheral) {
+               /* Central connection state and non connectable mode bit 18. */
+               if (!connectable && !(hdev->le_states[2] & 0x02))
+                       return false;
+
+               /* Central connection state and connectable mode bit 35 and
+                * scannable 19.
+                */
+               if (connectable && (!(hdev->le_states[4] & 0x08) ||
+                                   !(hdev->le_states[2] & 0x08)))
+                       return false;
+       }
+
+       return true;
+}
+
+static bool adv_use_rpa(struct hci_dev *hdev, uint32_t flags)
+{
+       /* If privacy is not enabled don't use RPA */
+       if (!hci_dev_test_flag(hdev, HCI_PRIVACY))
+               return false;
+
+       /* If basic privacy mode is enabled use RPA */
+       if (!hci_dev_test_flag(hdev, HCI_LIMITED_PRIVACY))
+               return true;
+
+       /* If limited privacy mode is enabled don't use RPA if we're
+        * both discoverable and bondable.
+        */
+       if ((flags & MGMT_ADV_FLAG_DISCOV) &&
+           hci_dev_test_flag(hdev, HCI_BONDABLE))
+               return false;
+
+       /* We're neither bondable nor discoverable in the limited
+        * privacy mode, therefore use RPA.
+        */
+       return true;
+}
+
+static int hci_set_random_addr_sync(struct hci_dev *hdev, bdaddr_t *rpa)
+{
+       /* If we're advertising or initiating an LE connection we can't
+        * go ahead and change the random address at this time. This is
+        * because the eventual initiator address used for the
+        * subsequently created connection will be undefined (some
+        * controllers use the new address and others the one we had
+        * when the operation started).
+        *
+        * In this kind of scenario skip the update and let the random
+        * address be updated at the next cycle.
+        */
+       if (hci_dev_test_flag(hdev, HCI_LE_ADV) ||
+           hci_lookup_le_connect(hdev)) {
+               bt_dev_dbg(hdev, "Deferring random address update");
+               hci_dev_set_flag(hdev, HCI_RPA_EXPIRED);
+               return 0;
+       }
+
+       return __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_RANDOM_ADDR,
+                                    6, rpa, HCI_CMD_TIMEOUT);
+}
+
+int hci_update_random_address_sync(struct hci_dev *hdev, bool require_privacy,
+                                  bool rpa, u8 *own_addr_type)
+{
+       int err;
+
+       /* If privacy is enabled use a resolvable private address. If
+        * current RPA has expired or there is something else than
+        * the current RPA in use, then generate a new one.
+        */
+       if (rpa) {
+               /* If Controller supports LL Privacy use own address type is
+                * 0x03
+                */
+               if (use_ll_privacy(hdev))
+                       *own_addr_type = ADDR_LE_DEV_RANDOM_RESOLVED;
+               else
+                       *own_addr_type = ADDR_LE_DEV_RANDOM;
+
+               /* Check if RPA is valid */
+               if (rpa_valid(hdev))
+                       return 0;
+
+               err = smp_generate_rpa(hdev, hdev->irk, &hdev->rpa);
+               if (err < 0) {
+                       bt_dev_err(hdev, "failed to generate new RPA");
+                       return err;
+               }
+
+               err = hci_set_random_addr_sync(hdev, &hdev->rpa);
+               if (err)
+                       return err;
+
+               return 0;
+       }
+
+       /* In case of required privacy without resolvable private address,
+        * use an non-resolvable private address. This is useful for active
+        * scanning and non-connectable advertising.
+        */
+       if (require_privacy) {
+               bdaddr_t nrpa;
+
+               while (true) {
+                       /* The non-resolvable private address is generated
+                        * from random six bytes with the two most significant
+                        * bits cleared.
+                        */
+                       get_random_bytes(&nrpa, 6);
+                       nrpa.b[5] &= 0x3f;
+
+                       /* The non-resolvable private address shall not be
+                        * equal to the public address.
+                        */
+                       if (bacmp(&hdev->bdaddr, &nrpa))
+                               break;
+               }
+
+               *own_addr_type = ADDR_LE_DEV_RANDOM;
+
+               return hci_set_random_addr_sync(hdev, &nrpa);
+       }
+
+       /* If forcing static address is in use or there is no public
+        * address use the static address as random address (but skip
+        * the HCI command if the current random address is already the
+        * static one.
+        *
+        * In case BR/EDR has been disabled on a dual-mode controller
+        * and a static address has been configured, then use that
+        * address instead of the public BR/EDR address.
+        */
+       if (hci_dev_test_flag(hdev, HCI_FORCE_STATIC_ADDR) ||
+           !bacmp(&hdev->bdaddr, BDADDR_ANY) ||
+           (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
+            bacmp(&hdev->static_addr, BDADDR_ANY))) {
+               *own_addr_type = ADDR_LE_DEV_RANDOM;
+               if (bacmp(&hdev->static_addr, &hdev->random_addr))
+                       return hci_set_random_addr_sync(hdev,
+                                                       &hdev->static_addr);
+               return 0;
+       }
+
+       /* Neither privacy nor static address is being used so use a
+        * public address.
+        */
+       *own_addr_type = ADDR_LE_DEV_PUBLIC;
+
+       return 0;
+}
+
+static int hci_disable_ext_adv_instance_sync(struct hci_dev *hdev, u8 instance)
+{
+       struct hci_cp_le_set_ext_adv_enable *cp;
+       struct hci_cp_ext_adv_set *set;
+       u8 data[sizeof(*cp) + sizeof(*set) * 1];
+       u8 size;
+
+       /* If request specifies an instance that doesn't exist, fail */
+       if (instance > 0) {
+               struct adv_info *adv;
+
+               adv = hci_find_adv_instance(hdev, instance);
+               if (!adv)
+                       return -EINVAL;
+
+               /* If not enabled there is nothing to do */
+               if (!adv->enabled)
+                       return 0;
+       }
+
+       memset(data, 0, sizeof(data));
+
+       cp = (void *)data;
+       set = (void *)cp->data;
+
+       /* Instance 0x00 indicates all advertising instances will be disabled */
+       cp->num_of_sets = !!instance;
+       cp->enable = 0x00;
+
+       set->handle = instance;
+
+       size = sizeof(*cp) + sizeof(*set) * cp->num_of_sets;
+
+       return __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_EXT_ADV_ENABLE,
+                                    size, data, HCI_CMD_TIMEOUT);
+}
+
+static int hci_set_adv_set_random_addr_sync(struct hci_dev *hdev, u8 instance,
+                                           bdaddr_t *random_addr)
+{
+       struct hci_cp_le_set_adv_set_rand_addr cp;
+       int err;
+
+       if (!instance) {
+               /* Instance 0x00 doesn't have an adv_info, instead it uses
+                * hdev->random_addr to track its address so whenever it needs
+                * to be updated this also set the random address since
+                * hdev->random_addr is shared with scan state machine.
+                */
+               err = hci_set_random_addr_sync(hdev, random_addr);
+               if (err)
+                       return err;
+       }
+
+       memset(&cp, 0, sizeof(cp));
+
+       cp.handle = instance;
+       bacpy(&cp.bdaddr, random_addr);
+
+       return __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_ADV_SET_RAND_ADDR,
+                                    sizeof(cp), &cp, HCI_CMD_TIMEOUT);
+}
+
+int hci_setup_ext_adv_instance_sync(struct hci_dev *hdev, u8 instance)
+{
+       struct hci_cp_le_set_ext_adv_params cp;
+       bool connectable;
+       u32 flags;
+       bdaddr_t random_addr;
+       u8 own_addr_type;
+       int err;
+       struct adv_info *adv;
+       bool secondary_adv;
+
+       if (instance > 0) {
+               adv = hci_find_adv_instance(hdev, instance);
+               if (!adv)
+                       return -EINVAL;
+       } else {
+               adv = NULL;
+       }
+
+       /* Updating parameters of an active instance will return a
+        * Command Disallowed error, so we must first disable the
+        * instance if it is active.
+        */
+       if (adv && !adv->pending) {
+               err = hci_disable_ext_adv_instance_sync(hdev, instance);
+               if (err)
+                       return err;
+       }
+
+       flags = hci_adv_instance_flags(hdev, instance);
+
+       /* If the "connectable" instance flag was not set, then choose between
+        * ADV_IND and ADV_NONCONN_IND based on the global connectable setting.
+        */
+       connectable = (flags & MGMT_ADV_FLAG_CONNECTABLE) ||
+                     mgmt_get_connectable(hdev);
+
+       if (!is_advertising_allowed(hdev, connectable))
+               return -EPERM;
+
+       /* Set require_privacy to true only when non-connectable
+        * advertising is used. In that case it is fine to use a
+        * non-resolvable private address.
+        */
+       err = hci_get_random_address(hdev, !connectable,
+                                    adv_use_rpa(hdev, flags), adv,
+                                    &own_addr_type, &random_addr);
+       if (err < 0)
+               return err;
+
+       memset(&cp, 0, sizeof(cp));
+
+       if (adv) {
+               hci_cpu_to_le24(adv->min_interval, cp.min_interval);
+               hci_cpu_to_le24(adv->max_interval, cp.max_interval);
+               cp.tx_power = adv->tx_power;
+       } else {
+               hci_cpu_to_le24(hdev->le_adv_min_interval, cp.min_interval);
+               hci_cpu_to_le24(hdev->le_adv_max_interval, cp.max_interval);
+               cp.tx_power = HCI_ADV_TX_POWER_NO_PREFERENCE;
+       }
+
+       secondary_adv = (flags & MGMT_ADV_FLAG_SEC_MASK);
+
+       if (connectable) {
+               if (secondary_adv)
+                       cp.evt_properties = cpu_to_le16(LE_EXT_ADV_CONN_IND);
+               else
+                       cp.evt_properties = cpu_to_le16(LE_LEGACY_ADV_IND);
+       } else if (hci_adv_instance_is_scannable(hdev, instance) ||
+                  (flags & MGMT_ADV_PARAM_SCAN_RSP)) {
+               if (secondary_adv)
+                       cp.evt_properties = cpu_to_le16(LE_EXT_ADV_SCAN_IND);
+               else
+                       cp.evt_properties = cpu_to_le16(LE_LEGACY_ADV_SCAN_IND);
+       } else {
+               if (secondary_adv)
+                       cp.evt_properties = cpu_to_le16(LE_EXT_ADV_NON_CONN_IND);
+               else
+                       cp.evt_properties = cpu_to_le16(LE_LEGACY_NONCONN_IND);
+       }
+
+       /* If Own_Address_Type equals 0x02 or 0x03, the Peer_Address parameter
+        * contains the peer’s Identity Address and the Peer_Address_Type
+        * parameter contains the peer’s Identity Type (i.e., 0x00 or 0x01).
+        * These parameters are used to locate the corresponding local IRK in
+        * the resolving list; this IRK is used to generate their own address
+        * used in the advertisement.
+        */
+       if (own_addr_type == ADDR_LE_DEV_RANDOM_RESOLVED)
+               hci_copy_identity_address(hdev, &cp.peer_addr,
+                                         &cp.peer_addr_type);
+
+       cp.own_addr_type = own_addr_type;
+       cp.channel_map = hdev->le_adv_channel_map;
+       cp.handle = instance;
+
+       if (flags & MGMT_ADV_FLAG_SEC_2M) {
+               cp.primary_phy = HCI_ADV_PHY_1M;
+               cp.secondary_phy = HCI_ADV_PHY_2M;
+       } else if (flags & MGMT_ADV_FLAG_SEC_CODED) {
+               cp.primary_phy = HCI_ADV_PHY_CODED;
+               cp.secondary_phy = HCI_ADV_PHY_CODED;
+       } else {
+               /* In all other cases use 1M */
+               cp.primary_phy = HCI_ADV_PHY_1M;
+               cp.secondary_phy = HCI_ADV_PHY_1M;
+       }
+
+       err = __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_EXT_ADV_PARAMS,
+                                   sizeof(cp), &cp, HCI_CMD_TIMEOUT);
+       if (err)
+               return err;
+
+       if ((own_addr_type == ADDR_LE_DEV_RANDOM ||
+            own_addr_type == ADDR_LE_DEV_RANDOM_RESOLVED) &&
+           bacmp(&random_addr, BDADDR_ANY)) {
+               /* Check if random address need to be updated */
+               if (adv) {
+                       if (!bacmp(&random_addr, &adv->random_addr))
+                               return 0;
+               } else {
+                       if (!bacmp(&random_addr, &hdev->random_addr))
+                               return 0;
+               }
+
+               return hci_set_adv_set_random_addr_sync(hdev, instance,
+                                                       &random_addr);
+       }
+
+       return 0;
+}
+
+static int hci_set_ext_scan_rsp_data_sync(struct hci_dev *hdev, u8 instance)
+{
+       struct {
+               struct hci_cp_le_set_ext_scan_rsp_data cp;
+               u8 data[HCI_MAX_EXT_AD_LENGTH];
+       } pdu;
+       u8 len;
+
+       memset(&pdu, 0, sizeof(pdu));
+
+       len = eir_create_scan_rsp(hdev, instance, pdu.data);
+
+       if (hdev->scan_rsp_data_len == len &&
+           !memcmp(pdu.data, hdev->scan_rsp_data, len))
+               return 0;
+
+       memcpy(hdev->scan_rsp_data, pdu.data, len);
+       hdev->scan_rsp_data_len = len;
+
+       pdu.cp.handle = instance;
+       pdu.cp.length = len;
+       pdu.cp.operation = LE_SET_ADV_DATA_OP_COMPLETE;
+       pdu.cp.frag_pref = LE_SET_ADV_DATA_NO_FRAG;
+
+       return __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_EXT_SCAN_RSP_DATA,
+                                    sizeof(pdu.cp) + len, &pdu.cp,
+                                    HCI_CMD_TIMEOUT);
+}
+
+static int __hci_set_scan_rsp_data_sync(struct hci_dev *hdev, u8 instance)
+{
+       struct hci_cp_le_set_scan_rsp_data cp;
+       u8 len;
+
+       memset(&cp, 0, sizeof(cp));
+
+       len = eir_create_scan_rsp(hdev, instance, cp.data);
+
+       if (hdev->scan_rsp_data_len == len &&
+           !memcmp(cp.data, hdev->scan_rsp_data, len))
+               return 0;
+
+       memcpy(hdev->scan_rsp_data, cp.data, sizeof(cp.data));
+       hdev->scan_rsp_data_len = len;
+
+       cp.length = len;
+
+       return __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_SCAN_RSP_DATA,
+                                    sizeof(cp), &cp, HCI_CMD_TIMEOUT);
+}
+
+int hci_update_scan_rsp_data_sync(struct hci_dev *hdev, u8 instance)
+{
+       if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
+               return 0;
+
+       if (ext_adv_capable(hdev))
+               return hci_set_ext_scan_rsp_data_sync(hdev, instance);
+
+       return __hci_set_scan_rsp_data_sync(hdev, instance);
+}
+
+int hci_enable_ext_advertising_sync(struct hci_dev *hdev, u8 instance)
+{
+       struct hci_cp_le_set_ext_adv_enable *cp;
+       struct hci_cp_ext_adv_set *set;
+       u8 data[sizeof(*cp) + sizeof(*set) * 1];
+       struct adv_info *adv;
+
+       if (instance > 0) {
+               adv = hci_find_adv_instance(hdev, instance);
+               if (!adv)
+                       return -EINVAL;
+               /* If already enabled there is nothing to do */
+               if (adv->enabled)
+                       return 0;
+       } else {
+               adv = NULL;
+       }
+
+       cp = (void *)data;
+       set = (void *)cp->data;
+
+       memset(cp, 0, sizeof(*cp));
+
+       cp->enable = 0x01;
+       cp->num_of_sets = 0x01;
+
+       memset(set, 0, sizeof(*set));
+
+       set->handle = instance;
+
+       /* Set duration per instance since controller is responsible for
+        * scheduling it.
+        */
+       if (adv && adv->timeout) {
+               u16 duration = adv->timeout * MSEC_PER_SEC;
+
+               /* Time = N * 10 ms */
+               set->duration = cpu_to_le16(duration / 10);
+       }
+
+       return __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_EXT_ADV_ENABLE,
+                                    sizeof(*cp) +
+                                    sizeof(*set) * cp->num_of_sets,
+                                    data, HCI_CMD_TIMEOUT);
+}
+
+int hci_start_ext_adv_sync(struct hci_dev *hdev, u8 instance)
+{
+       int err;
+
+       err = hci_setup_ext_adv_instance_sync(hdev, instance);
+       if (err)
+               return err;
+
+       err = hci_set_ext_scan_rsp_data_sync(hdev, instance);
+       if (err)
+               return err;
+
+       return hci_enable_ext_advertising_sync(hdev, instance);
+}
+
+static int hci_start_adv_sync(struct hci_dev *hdev, u8 instance)
+{
+       int err;
+
+       if (ext_adv_capable(hdev))
+               return hci_start_ext_adv_sync(hdev, instance);
+
+       err = hci_update_adv_data_sync(hdev, instance);
+       if (err)
+               return err;
+
+       err = hci_update_scan_rsp_data_sync(hdev, instance);
+       if (err)
+               return err;
+
+       return hci_enable_advertising_sync(hdev);
+}
+
+int hci_enable_advertising_sync(struct hci_dev *hdev)
+{
+       struct adv_info *adv_instance;
+       struct hci_cp_le_set_adv_param cp;
+       u8 own_addr_type, enable = 0x01;
+       bool connectable;
+       u16 adv_min_interval, adv_max_interval;
+       u32 flags;
+       u8 status;
+
+       if (ext_adv_capable(hdev))
+               return hci_enable_ext_advertising_sync(hdev,
+                                                      hdev->cur_adv_instance);
+
+       flags = hci_adv_instance_flags(hdev, hdev->cur_adv_instance);
+       adv_instance = hci_find_adv_instance(hdev, hdev->cur_adv_instance);
+
+       /* If the "connectable" instance flag was not set, then choose between
+        * ADV_IND and ADV_NONCONN_IND based on the global connectable setting.
+        */
+       connectable = (flags & MGMT_ADV_FLAG_CONNECTABLE) ||
+                     mgmt_get_connectable(hdev);
+
+       if (!is_advertising_allowed(hdev, connectable))
+               return -EINVAL;
+
+       status = hci_disable_advertising_sync(hdev);
+       if (status)
+               return status;
+
+       /* 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.
+        */
+       hci_dev_clear_flag(hdev, HCI_LE_ADV);
+
+       /* Set require_privacy to true only when non-connectable
+        * advertising is used. In that case it is fine to use a
+        * non-resolvable private address.
+        */
+       status = hci_update_random_address_sync(hdev, !connectable,
+                                               adv_use_rpa(hdev, flags),
+                                               &own_addr_type);
+       if (status)
+               return status;
+
+       memset(&cp, 0, sizeof(cp));
+
+       if (adv_instance) {
+               adv_min_interval = adv_instance->min_interval;
+               adv_max_interval = adv_instance->max_interval;
+       } else {
+               adv_min_interval = hdev->le_adv_min_interval;
+               adv_max_interval = hdev->le_adv_max_interval;
+       }
+
+       if (connectable) {
+               cp.type = LE_ADV_IND;
+       } else {
+               if (hci_adv_instance_is_scannable(hdev, hdev->cur_adv_instance))
+                       cp.type = LE_ADV_SCAN_IND;
+               else
+                       cp.type = LE_ADV_NONCONN_IND;
+
+               if (!hci_dev_test_flag(hdev, HCI_DISCOVERABLE) ||
+                   hci_dev_test_flag(hdev, HCI_LIMITED_DISCOVERABLE)) {
+                       adv_min_interval = DISCOV_LE_FAST_ADV_INT_MIN;
+                       adv_max_interval = DISCOV_LE_FAST_ADV_INT_MAX;
+               }
+       }
+
+       cp.min_interval = cpu_to_le16(adv_min_interval);
+       cp.max_interval = cpu_to_le16(adv_max_interval);
+       cp.own_address_type = own_addr_type;
+       cp.channel_map = hdev->le_adv_channel_map;
+
+       status = __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_ADV_PARAM,
+                                      sizeof(cp), &cp, HCI_CMD_TIMEOUT);
+       if (status)
+               return status;
+
+       return __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_ADV_ENABLE,
+                                    sizeof(enable), &enable, HCI_CMD_TIMEOUT);
+}
+
+static int enable_advertising_sync(struct hci_dev *hdev, void *data)
+{
+       return hci_enable_advertising_sync(hdev);
+}
+
+int hci_enable_advertising(struct hci_dev *hdev)
+{
+       if (!hci_dev_test_flag(hdev, HCI_ADVERTISING) &&
+           list_empty(&hdev->adv_instances))
+               return 0;
+
+       return hci_cmd_sync_queue(hdev, enable_advertising_sync, NULL, NULL);
+}
+
+int hci_remove_ext_adv_instance_sync(struct hci_dev *hdev, u8 instance,
+                                    struct sock *sk)
+{
+       int err;
+
+       if (!ext_adv_capable(hdev))
+               return 0;
+
+       err = hci_disable_ext_adv_instance_sync(hdev, instance);
+       if (err)
+               return err;
+
+       /* If request specifies an instance that doesn't exist, fail */
+       if (instance > 0 && !hci_find_adv_instance(hdev, instance))
+               return -EINVAL;
+
+       return __hci_cmd_sync_status_sk(hdev, HCI_OP_LE_REMOVE_ADV_SET,
+                                       sizeof(instance), &instance, 0,
+                                       HCI_CMD_TIMEOUT, sk);
+}
+
+static void cancel_adv_timeout(struct hci_dev *hdev)
+{
+       if (hdev->adv_instance_timeout) {
+               hdev->adv_instance_timeout = 0;
+               cancel_delayed_work(&hdev->adv_instance_expire);
+       }
+}
+
+static int hci_set_ext_adv_data_sync(struct hci_dev *hdev, u8 instance)
+{
+       struct {
+               struct hci_cp_le_set_ext_adv_data cp;
+               u8 data[HCI_MAX_EXT_AD_LENGTH];
+       } pdu;
+       u8 len;
+
+       memset(&pdu, 0, sizeof(pdu));
+
+       len = eir_create_adv_data(hdev, instance, pdu.data);
+
+       /* There's nothing to do if the data hasn't changed */
+       if (hdev->adv_data_len == len &&
+           memcmp(pdu.data, hdev->adv_data, len) == 0)
+               return 0;
+
+       memcpy(hdev->adv_data, pdu.data, len);
+       hdev->adv_data_len = len;
+
+       pdu.cp.length = len;
+       pdu.cp.handle = instance;
+       pdu.cp.operation = LE_SET_ADV_DATA_OP_COMPLETE;
+       pdu.cp.frag_pref = LE_SET_ADV_DATA_NO_FRAG;
+
+       return __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_EXT_ADV_DATA,
+                                    sizeof(pdu.cp) + len, &pdu.cp,
+                                    HCI_CMD_TIMEOUT);
+}
+
+static int hci_set_adv_data_sync(struct hci_dev *hdev, u8 instance)
+{
+       struct hci_cp_le_set_adv_data cp;
+       u8 len;
+
+       memset(&cp, 0, sizeof(cp));
+
+       len = eir_create_adv_data(hdev, instance, cp.data);
+
+       /* There's nothing to do if the data hasn't changed */
+       if (hdev->adv_data_len == len &&
+           memcmp(cp.data, hdev->adv_data, len) == 0)
+               return 0;
+
+       memcpy(hdev->adv_data, cp.data, sizeof(cp.data));
+       hdev->adv_data_len = len;
+
+       cp.length = len;
+
+       return __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_ADV_DATA,
+                                    sizeof(cp), &cp, HCI_CMD_TIMEOUT);
+}
+
+int hci_update_adv_data_sync(struct hci_dev *hdev, u8 instance)
+{
+       if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
+               return 0;
+
+       if (ext_adv_capable(hdev))
+               return hci_set_ext_adv_data_sync(hdev, instance);
+
+       return hci_set_adv_data_sync(hdev, instance);
+}
+
+int hci_schedule_adv_instance_sync(struct hci_dev *hdev, u8 instance,
+                                  bool force)
+{
+       struct adv_info *adv = NULL;
+       u16 timeout;
+
+       if (hci_dev_test_flag(hdev, HCI_ADVERTISING) && !ext_adv_capable(hdev))
+               return -EPERM;
+
+       if (hdev->adv_instance_timeout)
+               return -EBUSY;
+
+       adv = hci_find_adv_instance(hdev, instance);
+       if (!adv)
+               return -ENOENT;
+
+       /* A zero timeout means unlimited advertising. As long as there is
+        * only one instance, duration should be ignored. We still set a timeout
+        * in case further instances are being added later on.
+        *
+        * If the remaining lifetime of the instance is more than the duration
+        * then the timeout corresponds to the duration, otherwise it will be
+        * reduced to the remaining instance lifetime.
+        */
+       if (adv->timeout == 0 || adv->duration <= adv->remaining_time)
+               timeout = adv->duration;
+       else
+               timeout = adv->remaining_time;
+
+       /* The remaining time is being reduced unless the instance is being
+        * advertised without time limit.
+        */
+       if (adv->timeout)
+               adv->remaining_time = adv->remaining_time - timeout;
+
+       /* Only use work for scheduling instances with legacy advertising */
+       if (!ext_adv_capable(hdev)) {
+               hdev->adv_instance_timeout = timeout;
+               queue_delayed_work(hdev->req_workqueue,
+                                  &hdev->adv_instance_expire,
+                                  msecs_to_jiffies(timeout * 1000));
+       }
+
+       /* If we're just re-scheduling the same instance again then do not
+        * execute any HCI commands. This happens when a single instance is
+        * being advertised.
+        */
+       if (!force && hdev->cur_adv_instance == instance &&
+           hci_dev_test_flag(hdev, HCI_LE_ADV))
+               return 0;
+
+       hdev->cur_adv_instance = instance;
+
+       return hci_start_adv_sync(hdev, instance);
+}
+
+static int hci_clear_adv_sets_sync(struct hci_dev *hdev, struct sock *sk)
+{
+       int err;
+
+       if (!ext_adv_capable(hdev))
+               return 0;
+
+       /* Disable instance 0x00 to disable all instances */
+       err = hci_disable_ext_adv_instance_sync(hdev, 0x00);
+       if (err)
+               return err;
+
+       return __hci_cmd_sync_status_sk(hdev, HCI_OP_LE_CLEAR_ADV_SETS,
+                                       0, NULL, 0, HCI_CMD_TIMEOUT, sk);
+}
+
+static int hci_clear_adv_sync(struct hci_dev *hdev, struct sock *sk, bool force)
+{
+       struct adv_info *adv, *n;
+
+       if (ext_adv_capable(hdev))
+               /* Remove all existing sets */
+               return hci_clear_adv_sets_sync(hdev, sk);
+
+       /* This is safe as long as there is no command send while the lock is
+        * held.
+        */
+       hci_dev_lock(hdev);
+
+       /* Cleanup non-ext instances */
+       list_for_each_entry_safe(adv, n, &hdev->adv_instances, list) {
+               u8 instance = adv->instance;
+               int err;
+
+               if (!(force || adv->timeout))
+                       continue;
+
+               err = hci_remove_adv_instance(hdev, instance);
+               if (!err)
+                       mgmt_advertising_removed(sk, hdev, instance);
+       }
+
+       hci_dev_unlock(hdev);
+
+       return 0;
+}
+
+static int hci_remove_adv_sync(struct hci_dev *hdev, u8 instance,
+                              struct sock *sk)
+{
+       int err;
+
+       /* If we use extended advertising, instance has to be removed first. */
+       if (ext_adv_capable(hdev))
+               return hci_remove_ext_adv_instance_sync(hdev, instance, sk);
+
+       /* This is safe as long as there is no command send while the lock is
+        * held.
+        */
+       hci_dev_lock(hdev);
+
+       err = hci_remove_adv_instance(hdev, instance);
+       if (!err)
+               mgmt_advertising_removed(sk, hdev, instance);
+
+       hci_dev_unlock(hdev);
+
+       return err;
+}
+
+/* For a single instance:
+ * - force == true: The instance will be removed even when its remaining
+ *   lifetime is not zero.
+ * - force == false: the instance will be deactivated but kept stored unless
+ *   the remaining lifetime is zero.
+ *
+ * For instance == 0x00:
+ * - force == true: All instances will be removed regardless of their timeout
+ *   setting.
+ * - force == false: Only instances that have a timeout will be removed.
+ */
+int hci_remove_advertising_sync(struct hci_dev *hdev, struct sock *sk,
+                               u8 instance, bool force)
+{
+       struct adv_info *next = NULL;
+       int err;
+
+       /* Cancel any timeout concerning the removed instance(s). */
+       if (!instance || hdev->cur_adv_instance == instance)
+               cancel_adv_timeout(hdev);
+
+       /* Get the next instance to advertise BEFORE we remove
+        * the current one. This can be the same instance again
+        * if there is only one instance.
+        */
+       if (hdev->cur_adv_instance == instance)
+               next = hci_get_next_instance(hdev, instance);
+
+       if (!instance) {
+               err = hci_clear_adv_sync(hdev, sk, force);
+               if (err)
+                       return err;
+       } else {
+               struct adv_info *adv = hci_find_adv_instance(hdev, instance);
+
+               if (force || (adv && adv->timeout && !adv->remaining_time)) {
+                       /* Don't advertise a removed instance. */
+                       if (next && next->instance == instance)
+                               next = NULL;
+
+                       err = hci_remove_adv_sync(hdev, instance, sk);
+                       if (err)
+                               return err;
+               }
+       }
+
+       if (!hdev_is_powered(hdev) || hci_dev_test_flag(hdev, HCI_ADVERTISING))
+               return 0;
+
+       if (next && !ext_adv_capable(hdev))
+               hci_schedule_adv_instance_sync(hdev, next->instance, false);
+
+       return 0;
+}
+
+int hci_read_rssi_sync(struct hci_dev *hdev, __le16 handle)
+{
+       struct hci_cp_read_rssi cp;
+
+       cp.handle = handle;
+       return __hci_cmd_sync_status(hdev, HCI_OP_READ_RSSI,
+                                       sizeof(cp), &cp, HCI_CMD_TIMEOUT);
+}
+
+int hci_read_clock_sync(struct hci_dev *hdev, struct hci_cp_read_clock *cp)
+{
+       return __hci_cmd_sync_status(hdev, HCI_OP_READ_CLOCK,
+                                       sizeof(*cp), cp, HCI_CMD_TIMEOUT);
+}
+
+int hci_read_tx_power_sync(struct hci_dev *hdev, __le16 handle, u8 type)
+{
+       struct hci_cp_read_tx_power cp;
+
+       cp.handle = handle;
+       cp.type = type;
+       return __hci_cmd_sync_status(hdev, HCI_OP_READ_TX_POWER,
+                                       sizeof(cp), &cp, HCI_CMD_TIMEOUT);
+}
+
+int hci_disable_advertising_sync(struct hci_dev *hdev)
+{
+       u8 enable = 0x00;
+
+       /* If controller is not advertising we are done. */
+       if (!hci_dev_test_flag(hdev, HCI_LE_ADV))
+               return 0;
+
+       if (ext_adv_capable(hdev))
+               return hci_disable_ext_adv_instance_sync(hdev, 0x00);
+
+       return __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_ADV_ENABLE,
+                                    sizeof(enable), &enable, HCI_CMD_TIMEOUT);
+}
+
+static int hci_le_set_ext_scan_enable_sync(struct hci_dev *hdev, u8 val,
+                                          u8 filter_dup)
+{
+       struct hci_cp_le_set_ext_scan_enable cp;
+
+       memset(&cp, 0, sizeof(cp));
+       cp.enable = val;
+       cp.filter_dup = filter_dup;
+
+       return __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_EXT_SCAN_ENABLE,
+                                    sizeof(cp), &cp, HCI_CMD_TIMEOUT);
+}
+
+static int hci_le_set_scan_enable_sync(struct hci_dev *hdev, u8 val,
+                                      u8 filter_dup)
+{
+       struct hci_cp_le_set_scan_enable cp;
+
+       if (use_ext_scan(hdev))
+               return hci_le_set_ext_scan_enable_sync(hdev, val, filter_dup);
+
+       memset(&cp, 0, sizeof(cp));
+       cp.enable = val;
+       cp.filter_dup = filter_dup;
+
+       return __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
+                                    sizeof(cp), &cp, HCI_CMD_TIMEOUT);
+}
+
+static int hci_le_set_addr_resolution_enable_sync(struct hci_dev *hdev, u8 val)
+{
+       if (!use_ll_privacy(hdev))
+               return 0;
+
+       /* If controller is not/already resolving we are done. */
+       if (val == hci_dev_test_flag(hdev, HCI_LL_RPA_RESOLUTION))
+               return 0;
+
+       return __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_ADDR_RESOLV_ENABLE,
+                                    sizeof(val), &val, HCI_CMD_TIMEOUT);
+}
+
+static int hci_scan_disable_sync(struct hci_dev *hdev)
+{
+       int err;
+
+       /* If controller is not scanning we are done. */
+       if (!hci_dev_test_flag(hdev, HCI_LE_SCAN))
+               return 0;
+
+       if (hdev->scanning_paused) {
+               bt_dev_dbg(hdev, "Scanning is paused for suspend");
+               return 0;
+       }
+
+       err = hci_le_set_scan_enable_sync(hdev, LE_SCAN_DISABLE, 0x00);
+       if (err) {
+               bt_dev_err(hdev, "Unable to disable scanning: %d", err);
+               return err;
+       }
+
+       return err;
+}
+
+static bool scan_use_rpa(struct hci_dev *hdev)
+{
+       return hci_dev_test_flag(hdev, HCI_PRIVACY);
+}
+
+static void hci_start_interleave_scan(struct hci_dev *hdev)
+{
+       hdev->interleave_scan_state = INTERLEAVE_SCAN_NO_FILTER;
+       queue_delayed_work(hdev->req_workqueue,
+                          &hdev->interleave_scan, 0);
+}
+
+static bool is_interleave_scanning(struct hci_dev *hdev)
+{
+       return hdev->interleave_scan_state != INTERLEAVE_SCAN_NONE;
+}
+
+static void cancel_interleave_scan(struct hci_dev *hdev)
+{
+       bt_dev_dbg(hdev, "cancelling interleave scan");
+
+       cancel_delayed_work_sync(&hdev->interleave_scan);
+
+       hdev->interleave_scan_state = INTERLEAVE_SCAN_NONE;
+}
+
+/* Return true if interleave_scan wasn't started until exiting this function,
+ * otherwise, return false
+ */
+static bool hci_update_interleaved_scan_sync(struct hci_dev *hdev)
+{
+       /* Do interleaved scan only if all of the following are true:
+        * - There is at least one ADV monitor
+        * - At least one pending LE connection or one device to be scanned for
+        * - Monitor offloading is not supported
+        * If so, we should alternate between allowlist scan and one without
+        * any filters to save power.
+        */
+       bool use_interleaving = hci_is_adv_monitoring(hdev) &&
+                               !(list_empty(&hdev->pend_le_conns) &&
+                                 list_empty(&hdev->pend_le_reports)) &&
+                               hci_get_adv_monitor_offload_ext(hdev) ==
+                                   HCI_ADV_MONITOR_EXT_NONE;
+       bool is_interleaving = is_interleave_scanning(hdev);
+
+       if (use_interleaving && !is_interleaving) {
+               hci_start_interleave_scan(hdev);
+               bt_dev_dbg(hdev, "starting interleave scan");
+               return true;
+       }
+
+       if (!use_interleaving && is_interleaving)
+               cancel_interleave_scan(hdev);
+
+       return false;
+}
+
+/* Removes connection to resolve list if needed.*/
+static int hci_le_del_resolve_list_sync(struct hci_dev *hdev,
+                                       bdaddr_t *bdaddr, u8 bdaddr_type)
+{
+       struct hci_cp_le_del_from_resolv_list cp;
+       struct bdaddr_list_with_irk *entry;
+
+       if (!use_ll_privacy(hdev))
+               return 0;
+
+       /* Check if the IRK has been programmed */
+       entry = hci_bdaddr_list_lookup_with_irk(&hdev->le_resolv_list, bdaddr,
+                                               bdaddr_type);
+       if (!entry)
+               return 0;
+
+       cp.bdaddr_type = bdaddr_type;
+       bacpy(&cp.bdaddr, bdaddr);
+
+       return __hci_cmd_sync_status(hdev, HCI_OP_LE_DEL_FROM_RESOLV_LIST,
+                                    sizeof(cp), &cp, HCI_CMD_TIMEOUT);
+}
+
+static int hci_le_del_accept_list_sync(struct hci_dev *hdev,
+                                      bdaddr_t *bdaddr, u8 bdaddr_type)
+{
+       struct hci_cp_le_del_from_accept_list cp;
+       int err;
+
+       /* Check if device is on accept list before removing it */
+       if (!hci_bdaddr_list_lookup(&hdev->le_accept_list, bdaddr, bdaddr_type))
+               return 0;
+
+       cp.bdaddr_type = bdaddr_type;
+       bacpy(&cp.bdaddr, bdaddr);
+
+       /* Ignore errors when removing from resolving list as that is likely
+        * that the device was never added.
+        */
+       hci_le_del_resolve_list_sync(hdev, &cp.bdaddr, cp.bdaddr_type);
+
+       err = __hci_cmd_sync_status(hdev, HCI_OP_LE_DEL_FROM_ACCEPT_LIST,
+                                   sizeof(cp), &cp, HCI_CMD_TIMEOUT);
+       if (err) {
+               bt_dev_err(hdev, "Unable to remove from allow list: %d", err);
+               return err;
+       }
+
+       bt_dev_dbg(hdev, "Remove %pMR (0x%x) from allow list", &cp.bdaddr,
+                  cp.bdaddr_type);
+
+       return 0;
+}
+
+/* Adds connection to resolve list if needed.
+ * Setting params to NULL programs local hdev->irk
+ */
+static int hci_le_add_resolve_list_sync(struct hci_dev *hdev,
+                                       struct hci_conn_params *params)
+{
+       struct hci_cp_le_add_to_resolv_list cp;
+       struct smp_irk *irk;
+       struct bdaddr_list_with_irk *entry;
+
+       if (!use_ll_privacy(hdev))
+               return 0;
+
+       /* Attempt to program local identity address, type and irk if params is
+        * NULL.
+        */
+       if (!params) {
+               if (!hci_dev_test_flag(hdev, HCI_PRIVACY))
+                       return 0;
+
+               hci_copy_identity_address(hdev, &cp.bdaddr, &cp.bdaddr_type);
+               memcpy(cp.peer_irk, hdev->irk, 16);
+               goto done;
+       }
+
+       irk = hci_find_irk_by_addr(hdev, &params->addr, params->addr_type);
+       if (!irk)
+               return 0;
+
+       /* Check if the IK has _not_ been programmed yet. */
+       entry = hci_bdaddr_list_lookup_with_irk(&hdev->le_resolv_list,
+                                               &params->addr,
+                                               params->addr_type);
+       if (entry)
+               return 0;
+
+       cp.bdaddr_type = params->addr_type;
+       bacpy(&cp.bdaddr, &params->addr);
+       memcpy(cp.peer_irk, irk->val, 16);
+
+done:
+       if (hci_dev_test_flag(hdev, HCI_PRIVACY))
+               memcpy(cp.local_irk, hdev->irk, 16);
+       else
+               memset(cp.local_irk, 0, 16);
+
+       return __hci_cmd_sync_status(hdev, HCI_OP_LE_ADD_TO_RESOLV_LIST,
+                                    sizeof(cp), &cp, HCI_CMD_TIMEOUT);
+}
+
+/* Adds connection to allow list if needed, if the device uses RPA (has IRK)
+ * this attempts to program the device in the resolving list as well.
+ */
+static int hci_le_add_accept_list_sync(struct hci_dev *hdev,
+                                      struct hci_conn_params *params,
+                                      u8 *num_entries)
+{
+       struct hci_cp_le_add_to_accept_list cp;
+       int err;
+
+       /* Already in accept list */
+       if (hci_bdaddr_list_lookup(&hdev->le_accept_list, &params->addr,
+                                  params->addr_type))
+               return 0;
+
+       /* Select filter policy to accept all advertising */
+       if (*num_entries >= hdev->le_accept_list_size)
+               return -ENOSPC;
+
+       /* Accept list can not be used with RPAs */
+       if (!use_ll_privacy(hdev) &&
+           hci_find_irk_by_addr(hdev, &params->addr, params->addr_type)) {
+               return -EINVAL;
+       }
+
+       /* During suspend, only wakeable devices can be in acceptlist */
+       if (hdev->suspended && !hci_conn_test_flag(HCI_CONN_FLAG_REMOTE_WAKEUP,
+                                                  params->current_flags))
+               return 0;
+
+       /* Attempt to program the device in the resolving list first to avoid
+        * having to rollback in case it fails since the resolving list is
+        * dynamic it can probably be smaller than the accept list.
+        */
+       err = hci_le_add_resolve_list_sync(hdev, params);
+       if (err) {
+               bt_dev_err(hdev, "Unable to add to resolve list: %d", err);
+               return err;
+       }
+
+       *num_entries += 1;
+       cp.bdaddr_type = params->addr_type;
+       bacpy(&cp.bdaddr, &params->addr);
+
+       err = __hci_cmd_sync_status(hdev, HCI_OP_LE_ADD_TO_ACCEPT_LIST,
+                                   sizeof(cp), &cp, HCI_CMD_TIMEOUT);
+       if (err) {
+               bt_dev_err(hdev, "Unable to add to allow list: %d", err);
+               /* Rollback the device from the resolving list */
+               hci_le_del_resolve_list_sync(hdev, &cp.bdaddr, cp.bdaddr_type);
+               return err;
+       }
+
+       bt_dev_dbg(hdev, "Add %pMR (0x%x) to allow list", &cp.bdaddr,
+                  cp.bdaddr_type);
+
+       return 0;
+}
+
+/* This function disables/pause all advertising instances */
+static int hci_pause_advertising_sync(struct hci_dev *hdev)
+{
+       int err;
+       int old_state;
+
+       /* If there are no instances or advertising has already been paused
+        * there is nothing to do.
+        */
+       if (!hdev->adv_instance_cnt || hdev->advertising_paused)
+               return 0;
+
+       bt_dev_dbg(hdev, "Pausing directed advertising");
+
+       /* Stop directed advertising */
+       old_state = hci_dev_test_flag(hdev, HCI_ADVERTISING);
+       if (old_state) {
+               /* When discoverable timeout triggers, then just make sure
+                * the limited discoverable flag is cleared. Even in the case
+                * of a timeout triggered from general discoverable, it is
+                * safe to unconditionally clear the flag.
+                */
+               hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
+               hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
+               hdev->discov_timeout = 0;
+       }
+
+       bt_dev_dbg(hdev, "Pausing advertising instances");
+
+       /* Call to disable any advertisements active on the controller.
+        * This will succeed even if no advertisements are configured.
+        */
+       err = hci_disable_advertising_sync(hdev);
+       if (err)
+               return err;
+
+       /* If we are using software rotation, pause the loop */
+       if (!ext_adv_capable(hdev))
+               cancel_adv_timeout(hdev);
+
+       hdev->advertising_paused = true;
+       hdev->advertising_old_state = old_state;
+
+       return 0;
+}
+
+/* This function enables all user advertising instances */
+static int hci_resume_advertising_sync(struct hci_dev *hdev)
+{
+       struct adv_info *adv, *tmp;
+       int err;
+
+       /* If advertising has not been paused there is nothing  to do. */
+       if (!hdev->advertising_paused)
+               return 0;
+
+       /* Resume directed advertising */
+       hdev->advertising_paused = false;
+       if (hdev->advertising_old_state) {
+               hci_dev_set_flag(hdev, HCI_ADVERTISING);
+               hdev->advertising_old_state = 0;
+       }
+
+       bt_dev_dbg(hdev, "Resuming advertising instances");
+
+       if (ext_adv_capable(hdev)) {
+               /* Call for each tracked instance to be re-enabled */
+               list_for_each_entry_safe(adv, tmp, &hdev->adv_instances, list) {
+                       err = hci_enable_ext_advertising_sync(hdev,
+                                                             adv->instance);
+                       if (!err)
+                               continue;
+
+                       /* If the instance cannot be resumed remove it */
+                       hci_remove_ext_adv_instance_sync(hdev, adv->instance,
+                                                        NULL);
+               }
+       } else {
+               /* Schedule for most recent instance to be restarted and begin
+                * the software rotation loop
+                */
+               err = hci_schedule_adv_instance_sync(hdev,
+                                                    hdev->cur_adv_instance,
+                                                    true);
+       }
+
+       hdev->advertising_paused = false;
+
+       return err;
+}
+
+struct sk_buff *hci_read_local_oob_data_sync(struct hci_dev *hdev,
+                                            bool extended, struct sock *sk)
+{
+       u16 opcode = extended ? HCI_OP_READ_LOCAL_OOB_EXT_DATA :
+                                       HCI_OP_READ_LOCAL_OOB_DATA;
+
+       return __hci_cmd_sync_sk(hdev, opcode, 0, NULL, 0, HCI_CMD_TIMEOUT, sk);
+}
+
+/* Device must not be scanning when updating the accept list.
+ *
+ * Update is done using the following sequence:
+ *
+ * use_ll_privacy((Disable Advertising) -> Disable Resolving List) ->
+ * Remove Devices From Accept List ->
+ * (has IRK && use_ll_privacy(Remove Devices From Resolving List))->
+ * Add Devices to Accept List ->
+ * (has IRK && use_ll_privacy(Remove Devices From Resolving List)) ->
+ * use_ll_privacy(Enable Resolving List -> (Enable Advertising)) ->
+ * Enable Scanning
+ *
+ * In case of failure advertising shall be restored to its original state and
+ * return would disable accept list since either accept or resolving list could
+ * not be programmed.
+ *
+ */
+static u8 hci_update_accept_list_sync(struct hci_dev *hdev)
+{
+       struct hci_conn_params *params;
+       struct bdaddr_list *b, *t;
+       u8 num_entries = 0;
+       bool pend_conn, pend_report;
+       int err;
+
+       /* Pause advertising if resolving list can be used as controllers are
+        * cannot accept resolving list modifications while advertising.
+        */
+       if (use_ll_privacy(hdev)) {
+               err = hci_pause_advertising_sync(hdev);
+               if (err) {
+                       bt_dev_err(hdev, "pause advertising failed: %d", err);
+                       return 0x00;
+               }
+       }
+
+       /* Disable address resolution while reprogramming accept list since
+        * devices that do have an IRK will be programmed in the resolving list
+        * when LL Privacy is enabled.
+        */
+       err = hci_le_set_addr_resolution_enable_sync(hdev, 0x00);
+       if (err) {
+               bt_dev_err(hdev, "Unable to disable LL privacy: %d", err);
+               goto done;
+       }
+
+       /* Go through the current accept list programmed into the
+        * controller one by one and check if that address is still
+        * in the list of pending connections or list of devices to
+        * report. If not present in either list, then remove it from
+        * the controller.
+        */
+       list_for_each_entry_safe(b, t, &hdev->le_accept_list, list) {
+               pend_conn = hci_pend_le_action_lookup(&hdev->pend_le_conns,
+                                                     &b->bdaddr,
+                                                     b->bdaddr_type);
+               pend_report = hci_pend_le_action_lookup(&hdev->pend_le_reports,
+                                                       &b->bdaddr,
+                                                       b->bdaddr_type);
+
+               /* If the device is not likely to connect or report,
+                * remove it from the acceptlist.
+                */
+               if (!pend_conn && !pend_report) {
+                       hci_le_del_accept_list_sync(hdev, &b->bdaddr,
+                                                   b->bdaddr_type);
+                       continue;
+               }
+
+               num_entries++;
+       }
+
+       /* Since all no longer valid accept list entries have been
+        * removed, walk through the list of pending connections
+        * and ensure that any new device gets programmed into
+        * the controller.
+        *
+        * If the list of the devices is larger than the list of
+        * available accept list entries in the controller, then
+        * just abort and return filer policy value to not use the
+        * accept list.
+        */
+       list_for_each_entry(params, &hdev->pend_le_conns, action) {
+               err = hci_le_add_accept_list_sync(hdev, params, &num_entries);
+               if (err)
+                       goto done;
+       }
+
+       /* After adding all new pending connections, walk through
+        * the list of pending reports and also add these to the
+        * accept list if there is still space. Abort if space runs out.
+        */
+       list_for_each_entry(params, &hdev->pend_le_reports, action) {
+               err = hci_le_add_accept_list_sync(hdev, params, &num_entries);
+               if (err)
+                       goto done;
+       }
+
+       /* Use the allowlist unless the following conditions are all true:
+        * - We are not currently suspending
+        * - There are 1 or more ADV monitors registered and it's not offloaded
+        * - Interleaved scanning is not currently using the allowlist
+        */
+       if (!idr_is_empty(&hdev->adv_monitors_idr) && !hdev->suspended &&
+           hci_get_adv_monitor_offload_ext(hdev) == HCI_ADV_MONITOR_EXT_NONE &&
+           hdev->interleave_scan_state != INTERLEAVE_SCAN_ALLOWLIST)
+               err = -EINVAL;
+
+done:
+       /* Enable address resolution when LL Privacy is enabled. */
+       err = hci_le_set_addr_resolution_enable_sync(hdev, 0x01);
+       if (err)
+               bt_dev_err(hdev, "Unable to enable LL privacy: %d", err);
+
+       /* Resume advertising if it was paused */
+       if (use_ll_privacy(hdev))
+               hci_resume_advertising_sync(hdev);
+
+       /* Select filter policy to use accept list */
+       return err ? 0x00 : 0x01;
+}
+
+/* Returns true if an le connection is in the scanning state */
+static inline bool hci_is_le_conn_scanning(struct hci_dev *hdev)
+{
+       struct hci_conn_hash *h = &hdev->conn_hash;
+       struct hci_conn  *c;
+
+       rcu_read_lock();
+
+       list_for_each_entry_rcu(c, &h->list, list) {
+               if (c->type == LE_LINK && c->state == BT_CONNECT &&
+                   test_bit(HCI_CONN_SCANNING, &c->flags)) {
+                       rcu_read_unlock();
+                       return true;
+               }
+       }
+
+       rcu_read_unlock();
+
+       return false;
+}
+
+static int hci_le_set_ext_scan_param_sync(struct hci_dev *hdev, u8 type,
+                                         u16 interval, u16 window,
+                                         u8 own_addr_type, u8 filter_policy)
+{
+       struct hci_cp_le_set_ext_scan_params *cp;
+       struct hci_cp_le_scan_phy_params *phy;
+       u8 data[sizeof(*cp) + sizeof(*phy) * 2];
+       u8 num_phy = 0;
+
+       cp = (void *)data;
+       phy = (void *)cp->data;
+
+       memset(data, 0, sizeof(data));
+
+       cp->own_addr_type = own_addr_type;
+       cp->filter_policy = filter_policy;
+
+       if (scan_1m(hdev) || scan_2m(hdev)) {
+               cp->scanning_phys |= LE_SCAN_PHY_1M;
+
+               phy->type = type;
+               phy->interval = cpu_to_le16(interval);
+               phy->window = cpu_to_le16(window);
+
+               num_phy++;
+               phy++;
+       }
+
+       if (scan_coded(hdev)) {
+               cp->scanning_phys |= LE_SCAN_PHY_CODED;
+
+               phy->type = type;
+               phy->interval = cpu_to_le16(interval);
+               phy->window = cpu_to_le16(window);
+
+               num_phy++;
+               phy++;
+       }
+
+       return __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_EXT_SCAN_PARAMS,
+                                    sizeof(*cp) + sizeof(*phy) * num_phy,
+                                    data, HCI_CMD_TIMEOUT);
+}
+
+static int hci_le_set_scan_param_sync(struct hci_dev *hdev, u8 type,
+                                     u16 interval, u16 window,
+                                     u8 own_addr_type, u8 filter_policy)
+{
+       struct hci_cp_le_set_scan_param cp;
+
+       if (use_ext_scan(hdev))
+               return hci_le_set_ext_scan_param_sync(hdev, type, interval,
+                                                     window, own_addr_type,
+                                                     filter_policy);
+
+       memset(&cp, 0, sizeof(cp));
+       cp.type = type;
+       cp.interval = cpu_to_le16(interval);
+       cp.window = cpu_to_le16(window);
+       cp.own_address_type = own_addr_type;
+       cp.filter_policy = filter_policy;
+
+       return __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_SCAN_PARAM,
+                                    sizeof(cp), &cp, HCI_CMD_TIMEOUT);
+}
+
+static int hci_start_scan_sync(struct hci_dev *hdev, u8 type, u16 interval,
+                              u16 window, u8 own_addr_type, u8 filter_policy,
+                              u8 filter_dup)
+{
+       int err;
+
+       if (hdev->scanning_paused) {
+               bt_dev_dbg(hdev, "Scanning is paused for suspend");
+               return 0;
+       }
+
+       err = hci_le_set_scan_param_sync(hdev, type, interval, window,
+                                        own_addr_type, filter_policy);
+       if (err)
+               return err;
+
+       return hci_le_set_scan_enable_sync(hdev, LE_SCAN_ENABLE, filter_dup);
+}
+
+static int hci_passive_scan_sync(struct hci_dev *hdev)
+{
+       u8 own_addr_type;
+       u8 filter_policy;
+       u16 window, interval;
+       int err;
+
+       if (hdev->scanning_paused) {
+               bt_dev_dbg(hdev, "Scanning is paused for suspend");
+               return 0;
+       }
+
+       err = hci_scan_disable_sync(hdev);
+       if (err) {
+               bt_dev_err(hdev, "disable scanning failed: %d", err);
+               return err;
+       }
+
+       /* Set require_privacy to false since no SCAN_REQ are send
+        * during passive scanning. Not using an non-resolvable address
+        * here is important so that peer devices using direct
+        * advertising with our address will be correctly reported
+        * by the controller.
+        */
+       if (hci_update_random_address_sync(hdev, false, scan_use_rpa(hdev),
+                                          &own_addr_type))
+               return 0;
+
+       if (hdev->enable_advmon_interleave_scan &&
+           hci_update_interleaved_scan_sync(hdev))
+               return 0;
+
+       bt_dev_dbg(hdev, "interleave state %d", hdev->interleave_scan_state);
+
+       /* Adding or removing entries from the accept list must
+        * happen before enabling scanning. The controller does
+        * not allow accept list modification while scanning.
+        */
+       filter_policy = hci_update_accept_list_sync(hdev);
+
+       /* When the controller is using random resolvable addresses and
+        * with that having LE privacy enabled, then controllers with
+        * Extended Scanner Filter Policies support can now enable support
+        * for handling directed advertising.
+        *
+        * So instead of using filter polices 0x00 (no acceptlist)
+        * and 0x01 (acceptlist enabled) use the new filter policies
+        * 0x02 (no acceptlist) and 0x03 (acceptlist enabled).
+        */
+       if (hci_dev_test_flag(hdev, HCI_PRIVACY) &&
+           (hdev->le_features[0] & HCI_LE_EXT_SCAN_POLICY))
+               filter_policy |= 0x02;
+
+       if (hdev->suspended) {
+               window = hdev->le_scan_window_suspend;
+               interval = hdev->le_scan_int_suspend;
+       } else if (hci_is_le_conn_scanning(hdev)) {
+               window = hdev->le_scan_window_connect;
+               interval = hdev->le_scan_int_connect;
+       } else if (hci_is_adv_monitoring(hdev)) {
+               window = hdev->le_scan_window_adv_monitor;
+               interval = hdev->le_scan_int_adv_monitor;
+       } else {
+               window = hdev->le_scan_window;
+               interval = hdev->le_scan_interval;
+       }
+
+       bt_dev_dbg(hdev, "LE passive scan with acceptlist = %d", filter_policy);
+
+       return hci_start_scan_sync(hdev, LE_SCAN_PASSIVE, interval, window,
+                                  own_addr_type, filter_policy,
+                                  LE_SCAN_FILTER_DUP_ENABLE);
+}
+
+/* This function controls the passive scanning based on hdev->pend_le_conns
+ * list. If there are pending LE connection we start the background scanning,
+ * otherwise we stop it in the following sequence:
+ *
+ * If there are devices to scan:
+ *
+ * Disable Scanning -> Update Accept List ->
+ * use_ll_privacy((Disable Advertising) -> Disable Resolving List ->
+ * Update Resolving List -> Enable Resolving List -> (Enable Advertising)) ->
+ * Enable Scanning
+ *
+ * Otherwise:
+ *
+ * Disable Scanning
+ */
+int hci_update_passive_scan_sync(struct hci_dev *hdev)
+{
+       int err;
+
+       if (!test_bit(HCI_UP, &hdev->flags) ||
+           test_bit(HCI_INIT, &hdev->flags) ||
+           hci_dev_test_flag(hdev, HCI_SETUP) ||
+           hci_dev_test_flag(hdev, HCI_CONFIG) ||
+           hci_dev_test_flag(hdev, HCI_AUTO_OFF) ||
+           hci_dev_test_flag(hdev, HCI_UNREGISTER))
+               return 0;
+
+       /* No point in doing scanning if LE support hasn't been enabled */
+       if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
+               return 0;
+
+       /* If discovery is active don't interfere with it */
+       if (hdev->discovery.state != DISCOVERY_STOPPED)
+               return 0;
+
+       /* Reset RSSI and UUID filters when starting background scanning
+        * since these filters are meant for service discovery only.
+        *
+        * The Start Discovery and Start Service Discovery operations
+        * ensure to set proper values for RSSI threshold and UUID
+        * filter list. So it is safe to just reset them here.
+        */
+       hci_discovery_filter_clear(hdev);
+
+       bt_dev_dbg(hdev, "ADV monitoring is %s",
+                  hci_is_adv_monitoring(hdev) ? "on" : "off");
+
+       if (list_empty(&hdev->pend_le_conns) &&
+           list_empty(&hdev->pend_le_reports) &&
+           !hci_is_adv_monitoring(hdev)) {
+               /* If there is no pending LE connections or devices
+                * to be scanned for or no ADV monitors, we should stop the
+                * background scanning.
+                */
+
+               bt_dev_dbg(hdev, "stopping background scanning");
+
+               err = hci_scan_disable_sync(hdev);
+               if (err)
+                       bt_dev_err(hdev, "stop background scanning failed: %d",
+                                  err);
+       } else {
+               /* If there is at least one pending LE connection, we should
+                * keep the background scan running.
+                */
+
+               /* If controller is connecting, we should not start scanning
+                * since some controllers are not able to scan and connect at
+                * the same time.
+                */
+               if (hci_lookup_le_connect(hdev))
+                       return 0;
+
+               bt_dev_dbg(hdev, "start background scanning");
+
+               err = hci_passive_scan_sync(hdev);
+               if (err)
+                       bt_dev_err(hdev, "start background scanning failed: %d",
+                                  err);
+       }
+
+       return err;
+}
+
+static int update_passive_scan_sync(struct hci_dev *hdev, void *data)
+{
+       return hci_update_passive_scan_sync(hdev);
+}
+
+int hci_update_passive_scan(struct hci_dev *hdev)
+{
+       /* Only queue if it would have any effect */
+       if (!test_bit(HCI_UP, &hdev->flags) ||
+           test_bit(HCI_INIT, &hdev->flags) ||
+           hci_dev_test_flag(hdev, HCI_SETUP) ||
+           hci_dev_test_flag(hdev, HCI_CONFIG) ||
+           hci_dev_test_flag(hdev, HCI_AUTO_OFF) ||
+           hci_dev_test_flag(hdev, HCI_UNREGISTER))
+               return 0;
+
+       return hci_cmd_sync_queue(hdev, update_passive_scan_sync, NULL, NULL);
+}
+
+int hci_write_sc_support_sync(struct hci_dev *hdev, u8 val)
+{
+       int err;
+
+       if (!bredr_sc_enabled(hdev) || lmp_host_sc_capable(hdev))
+               return 0;
+
+       err = __hci_cmd_sync_status(hdev, HCI_OP_WRITE_SC_SUPPORT,
+                                   sizeof(val), &val, HCI_CMD_TIMEOUT);
+
+       if (!err) {
+               if (val) {
+                       hdev->features[1][0] |= LMP_HOST_SC;
+                       hci_dev_set_flag(hdev, HCI_SC_ENABLED);
+               } else {
+                       hdev->features[1][0] &= ~LMP_HOST_SC;
+                       hci_dev_clear_flag(hdev, HCI_SC_ENABLED);
+               }
+       }
+
+       return err;
+}
+
+int hci_write_ssp_mode_sync(struct hci_dev *hdev, u8 mode)
+{
+       int err;
+
+       if (!hci_dev_test_flag(hdev, HCI_SSP_ENABLED) ||
+           lmp_host_ssp_capable(hdev))
+               return 0;
+
+       if (!mode && hci_dev_test_flag(hdev, HCI_USE_DEBUG_KEYS)) {
+               __hci_cmd_sync_status(hdev, HCI_OP_WRITE_SSP_DEBUG_MODE,
+                                     sizeof(mode), &mode, HCI_CMD_TIMEOUT);
+       }
+
+       err = __hci_cmd_sync_status(hdev, HCI_OP_WRITE_SSP_MODE,
+                                   sizeof(mode), &mode, HCI_CMD_TIMEOUT);
+       if (err)
+               return err;
+
+       return hci_write_sc_support_sync(hdev, 0x01);
+}
+
+int hci_write_le_host_supported_sync(struct hci_dev *hdev, u8 le, u8 simul)
+{
+       struct hci_cp_write_le_host_supported cp;
+
+       if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED) ||
+           !lmp_bredr_capable(hdev))
+               return 0;
+
+       /* Check first if we already have the right host state
+        * (host features set)
+        */
+       if (le == lmp_host_le_capable(hdev) &&
+           simul == lmp_host_le_br_capable(hdev))
+               return 0;
+
+       memset(&cp, 0, sizeof(cp));
+
+       cp.le = le;
+       cp.simul = simul;
+
+       return __hci_cmd_sync_status(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED,
+                                    sizeof(cp), &cp, HCI_CMD_TIMEOUT);
+}
+
+static int hci_powered_update_adv_sync(struct hci_dev *hdev)
+{
+       struct adv_info *adv, *tmp;
+       int err;
+
+       if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
+               return 0;
+
+       /* If RPA Resolution has not been enable yet it means the
+        * resolving list is empty and we should attempt to program the
+        * local IRK in order to support using own_addr_type
+        * ADDR_LE_DEV_RANDOM_RESOLVED (0x03).
+        */
+       if (!hci_dev_test_flag(hdev, HCI_LL_RPA_RESOLUTION)) {
+               hci_le_add_resolve_list_sync(hdev, NULL);
+               hci_le_set_addr_resolution_enable_sync(hdev, 0x01);
+       }
+
+       /* Make sure the controller has a good default for
+        * advertising data. This also applies to the case
+        * where BR/EDR was toggled during the AUTO_OFF phase.
+        */
+       if (hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
+           list_empty(&hdev->adv_instances)) {
+               if (ext_adv_capable(hdev)) {
+                       err = hci_setup_ext_adv_instance_sync(hdev, 0x00);
+                       if (!err)
+                               hci_update_scan_rsp_data_sync(hdev, 0x00);
+               } else {
+                       err = hci_update_adv_data_sync(hdev, 0x00);
+                       if (!err)
+                               hci_update_scan_rsp_data_sync(hdev, 0x00);
+               }
+
+               if (hci_dev_test_flag(hdev, HCI_ADVERTISING))
+                       hci_enable_advertising_sync(hdev);
+       }
+
+       /* Call for each tracked instance to be scheduled */
+       list_for_each_entry_safe(adv, tmp, &hdev->adv_instances, list)
+               hci_schedule_adv_instance_sync(hdev, adv->instance, true);
+
+       return 0;
+}
+
+static int hci_write_auth_enable_sync(struct hci_dev *hdev)
+{
+       u8 link_sec;
+
+       link_sec = hci_dev_test_flag(hdev, HCI_LINK_SECURITY);
+       if (link_sec == test_bit(HCI_AUTH, &hdev->flags))
+               return 0;
+
+       return __hci_cmd_sync_status(hdev, HCI_OP_WRITE_AUTH_ENABLE,
+                                    sizeof(link_sec), &link_sec,
+                                    HCI_CMD_TIMEOUT);
+}
+
+int hci_write_fast_connectable_sync(struct hci_dev *hdev, bool enable)
+{
+       struct hci_cp_write_page_scan_activity cp;
+       u8 type;
+       int err = 0;
+
+       if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
+               return 0;
+
+       if (hdev->hci_ver < BLUETOOTH_VER_1_2)
+               return 0;
+
+       memset(&cp, 0, sizeof(cp));
+
+       if (enable) {
+               type = PAGE_SCAN_TYPE_INTERLACED;
+
+               /* 160 msec page scan interval */
+               cp.interval = cpu_to_le16(0x0100);
+       } else {
+               type = hdev->def_page_scan_type;
+               cp.interval = cpu_to_le16(hdev->def_page_scan_int);
+       }
+
+       cp.window = cpu_to_le16(hdev->def_page_scan_window);
+
+       if (__cpu_to_le16(hdev->page_scan_interval) != cp.interval ||
+           __cpu_to_le16(hdev->page_scan_window) != cp.window) {
+               err = __hci_cmd_sync_status(hdev,
+                                           HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
+                                           sizeof(cp), &cp, HCI_CMD_TIMEOUT);
+               if (err)
+                       return err;
+       }
+
+       if (hdev->page_scan_type != type)
+               err = __hci_cmd_sync_status(hdev,
+                                           HCI_OP_WRITE_PAGE_SCAN_TYPE,
+                                           sizeof(type), &type,
+                                           HCI_CMD_TIMEOUT);
+
+       return err;
+}
+
+static bool disconnected_accept_list_entries(struct hci_dev *hdev)
+{
+       struct bdaddr_list *b;
+
+       list_for_each_entry(b, &hdev->accept_list, list) {
+               struct hci_conn *conn;
+
+               conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &b->bdaddr);
+               if (!conn)
+                       return true;
+
+               if (conn->state != BT_CONNECTED && conn->state != BT_CONFIG)
+                       return true;
+       }
+
+       return false;
+}
+
+static int hci_write_scan_enable_sync(struct hci_dev *hdev, u8 val)
+{
+       return __hci_cmd_sync_status(hdev, HCI_OP_WRITE_SCAN_ENABLE,
+                                           sizeof(val), &val,
+                                           HCI_CMD_TIMEOUT);
+}
+
+int hci_update_scan_sync(struct hci_dev *hdev)
+{
+       u8 scan;
+
+       if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
+               return 0;
+
+       if (!hdev_is_powered(hdev))
+               return 0;
+
+       if (mgmt_powering_down(hdev))
+               return 0;
+
+       if (hdev->scanning_paused)
+               return 0;
+
+       if (hci_dev_test_flag(hdev, HCI_CONNECTABLE) ||
+           disconnected_accept_list_entries(hdev))
+               scan = SCAN_PAGE;
+       else
+               scan = SCAN_DISABLED;
+
+       if (hci_dev_test_flag(hdev, HCI_DISCOVERABLE))
+               scan |= SCAN_INQUIRY;
+
+       if (test_bit(HCI_PSCAN, &hdev->flags) == !!(scan & SCAN_PAGE) &&
+           test_bit(HCI_ISCAN, &hdev->flags) == !!(scan & SCAN_INQUIRY))
+               return 0;
+
+       return hci_write_scan_enable_sync(hdev, scan);
+}
+
+int hci_update_name_sync(struct hci_dev *hdev)
+{
+       struct hci_cp_write_local_name cp;
+
+       memset(&cp, 0, sizeof(cp));
+
+       memcpy(cp.name, hdev->dev_name, sizeof(cp.name));
+
+       return __hci_cmd_sync_status(hdev, HCI_OP_WRITE_LOCAL_NAME,
+                                           sizeof(cp), &cp,
+                                           HCI_CMD_TIMEOUT);
+}
+
+/* This function perform powered update HCI command sequence after the HCI init
+ * sequence which end up resetting all states, the sequence is as follows:
+ *
+ * HCI_SSP_ENABLED(Enable SSP)
+ * HCI_LE_ENABLED(Enable LE)
+ * HCI_LE_ENABLED(use_ll_privacy(Add local IRK to Resolving List) ->
+ * Update adv data)
+ * Enable Authentication
+ * lmp_bredr_capable(Set Fast Connectable -> Set Scan Type -> Set Class ->
+ * Set Name -> Set EIR)
+ */
+int hci_powered_update_sync(struct hci_dev *hdev)
+{
+       int err;
+
+       /* Register the available SMP channels (BR/EDR and LE) only when
+        * successfully powering on the controller. This late
+        * registration is required so that LE SMP can clearly decide if
+        * the public address or static address is used.
+        */
+       smp_register(hdev);
+
+       err = hci_write_ssp_mode_sync(hdev, 0x01);
+       if (err)
+               return err;
+
+       err = hci_write_le_host_supported_sync(hdev, 0x01, 0x00);
+       if (err)
+               return err;
+
+       err = hci_powered_update_adv_sync(hdev);
+       if (err)
+               return err;
+
+       err = hci_write_auth_enable_sync(hdev);
+       if (err)
+               return err;
+
+       if (lmp_bredr_capable(hdev)) {
+               if (hci_dev_test_flag(hdev, HCI_FAST_CONNECTABLE))
+                       hci_write_fast_connectable_sync(hdev, true);
+               else
+                       hci_write_fast_connectable_sync(hdev, false);
+               hci_update_scan_sync(hdev);
+               hci_update_class_sync(hdev);
+               hci_update_name_sync(hdev);
+               hci_update_eir_sync(hdev);
+       }
+
+       return 0;
+}
+
+/**
+ * hci_dev_get_bd_addr_from_property - Get the Bluetooth Device Address
+ *                                    (BD_ADDR) for a HCI device from
+ *                                    a firmware node property.
+ * @hdev:      The HCI device
+ *
+ * Search the firmware node for 'local-bd-address'.
+ *
+ * All-zero BD addresses are rejected, because those could be properties
+ * that exist in the firmware tables, but were not updated by the firmware. For
+ * example, the DTS could define 'local-bd-address', with zero BD addresses.
+ */
+static void hci_dev_get_bd_addr_from_property(struct hci_dev *hdev)
+{
+       struct fwnode_handle *fwnode = dev_fwnode(hdev->dev.parent);
+       bdaddr_t ba;
+       int ret;
+
+       ret = fwnode_property_read_u8_array(fwnode, "local-bd-address",
+                                           (u8 *)&ba, sizeof(ba));
+       if (ret < 0 || !bacmp(&ba, BDADDR_ANY))
+               return;
+
+       bacpy(&hdev->public_addr, &ba);
+}
+
+struct hci_init_stage {
+       int (*func)(struct hci_dev *hdev);
+};
+
+/* Run init stage NULL terminated function table */
+static int hci_init_stage_sync(struct hci_dev *hdev,
+                              const struct hci_init_stage *stage)
+{
+       size_t i;
+
+       for (i = 0; stage[i].func; i++) {
+               int err;
+
+               err = stage[i].func(hdev);
+               if (err)
+                       return err;
+       }
+
+       return 0;
+}
+
+/* Read Local Version */
+static int hci_read_local_version_sync(struct hci_dev *hdev)
+{
+       return __hci_cmd_sync_status(hdev, HCI_OP_READ_LOCAL_VERSION,
+                                    0, NULL, HCI_CMD_TIMEOUT);
+}
+
+/* Read BD Address */
+static int hci_read_bd_addr_sync(struct hci_dev *hdev)
+{
+       return __hci_cmd_sync_status(hdev, HCI_OP_READ_BD_ADDR,
+                                    0, NULL, HCI_CMD_TIMEOUT);
+}
+
+#define HCI_INIT(_func) \
+{ \
+       .func = _func, \
+}
+
+static const struct hci_init_stage hci_init0[] = {
+       /* HCI_OP_READ_LOCAL_VERSION */
+       HCI_INIT(hci_read_local_version_sync),
+       /* HCI_OP_READ_BD_ADDR */
+       HCI_INIT(hci_read_bd_addr_sync),
+       {}
+};
+
+int hci_reset_sync(struct hci_dev *hdev)
+{
+       int err;
+
+       set_bit(HCI_RESET, &hdev->flags);
+
+       err = __hci_cmd_sync_status(hdev, HCI_OP_RESET, 0, NULL,
+                                   HCI_CMD_TIMEOUT);
+       if (err)
+               return err;
+
+       return 0;
+}
+
+static int hci_init0_sync(struct hci_dev *hdev)
+{
+       int err;
+
+       bt_dev_dbg(hdev, "");
+
+       /* Reset */
+       if (!test_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks)) {
+               err = hci_reset_sync(hdev);
+               if (err)
+                       return err;
+       }
+
+       return hci_init_stage_sync(hdev, hci_init0);
+}
+
+static int hci_unconf_init_sync(struct hci_dev *hdev)
+{
+       int err;
+
+       if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
+               return 0;
+
+       err = hci_init0_sync(hdev);
+       if (err < 0)
+               return err;
+
+       if (hci_dev_test_flag(hdev, HCI_SETUP))
+               hci_debugfs_create_basic(hdev);
+
+       return 0;
+}
+
+/* Read Local Supported Features. */
+static int hci_read_local_features_sync(struct hci_dev *hdev)
+{
+        /* Not all AMP controllers support this command */
+       if (hdev->dev_type == HCI_AMP && !(hdev->commands[14] & 0x20))
+               return 0;
+
+       return __hci_cmd_sync_status(hdev, HCI_OP_READ_LOCAL_FEATURES,
+                                    0, NULL, HCI_CMD_TIMEOUT);
+}
+
+/* BR Controller init stage 1 command sequence */
+static const struct hci_init_stage br_init1[] = {
+       /* HCI_OP_READ_LOCAL_FEATURES */
+       HCI_INIT(hci_read_local_features_sync),
+       /* HCI_OP_READ_LOCAL_VERSION */
+       HCI_INIT(hci_read_local_version_sync),
+       /* HCI_OP_READ_BD_ADDR */
+       HCI_INIT(hci_read_bd_addr_sync),
+       {}
+};
+
+/* Read Local Commands */
+static int hci_read_local_cmds_sync(struct hci_dev *hdev)
+{
+       /* All Bluetooth 1.2 and later controllers should support the
+        * HCI command for reading the local supported commands.
+        *
+        * Unfortunately some controllers indicate Bluetooth 1.2 support,
+        * but do not have support for this command. If that is the case,
+        * the driver can quirk the behavior and skip reading the local
+        * supported commands.
+        */
+       if (hdev->hci_ver > BLUETOOTH_VER_1_1 &&
+           !test_bit(HCI_QUIRK_BROKEN_LOCAL_COMMANDS, &hdev->quirks))
+               return __hci_cmd_sync_status(hdev, HCI_OP_READ_LOCAL_COMMANDS,
+                                            0, NULL, HCI_CMD_TIMEOUT);
+
+       return 0;
+}
+
+/* Read Local AMP Info */
+static int hci_read_local_amp_info_sync(struct hci_dev *hdev)
+{
+       return __hci_cmd_sync_status(hdev, HCI_OP_READ_LOCAL_AMP_INFO,
+                                    0, NULL, HCI_CMD_TIMEOUT);
+}
+
+/* Read Data Blk size */
+static int hci_read_data_block_size_sync(struct hci_dev *hdev)
+{
+       return __hci_cmd_sync_status(hdev, HCI_OP_READ_DATA_BLOCK_SIZE,
+                                    0, NULL, HCI_CMD_TIMEOUT);
+}
+
+/* Read Flow Control Mode */
+static int hci_read_flow_control_mode_sync(struct hci_dev *hdev)
+{
+       return __hci_cmd_sync_status(hdev, HCI_OP_READ_FLOW_CONTROL_MODE,
+                                    0, NULL, HCI_CMD_TIMEOUT);
+}
+
+/* Read Location Data */
+static int hci_read_location_data_sync(struct hci_dev *hdev)
+{
+       return __hci_cmd_sync_status(hdev, HCI_OP_READ_LOCATION_DATA,
+                                    0, NULL, HCI_CMD_TIMEOUT);
+}
+
+/* AMP Controller init stage 1 command sequence */
+static const struct hci_init_stage amp_init1[] = {
+       /* HCI_OP_READ_LOCAL_VERSION */
+       HCI_INIT(hci_read_local_version_sync),
+       /* HCI_OP_READ_LOCAL_COMMANDS */
+       HCI_INIT(hci_read_local_cmds_sync),
+       /* HCI_OP_READ_LOCAL_AMP_INFO */
+       HCI_INIT(hci_read_local_amp_info_sync),
+       /* HCI_OP_READ_DATA_BLOCK_SIZE */
+       HCI_INIT(hci_read_data_block_size_sync),
+       /* HCI_OP_READ_FLOW_CONTROL_MODE */
+       HCI_INIT(hci_read_flow_control_mode_sync),
+       /* HCI_OP_READ_LOCATION_DATA */
+       HCI_INIT(hci_read_location_data_sync),
+};
+
+static int hci_init1_sync(struct hci_dev *hdev)
+{
+       int err;
+
+       bt_dev_dbg(hdev, "");
+
+       /* Reset */
+       if (!test_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks)) {
+               err = hci_reset_sync(hdev);
+               if (err)
+                       return err;
+       }
+
+       switch (hdev->dev_type) {
+       case HCI_PRIMARY:
+               hdev->flow_ctl_mode = HCI_FLOW_CTL_MODE_PACKET_BASED;
+               return hci_init_stage_sync(hdev, br_init1);
+       case HCI_AMP:
+               hdev->flow_ctl_mode = HCI_FLOW_CTL_MODE_BLOCK_BASED;
+               return hci_init_stage_sync(hdev, amp_init1);
+       default:
+               bt_dev_err(hdev, "Unknown device type %d", hdev->dev_type);
+               break;
+       }
+
+       return 0;
+}
+
+/* AMP Controller init stage 2 command sequence */
+static const struct hci_init_stage amp_init2[] = {
+       /* HCI_OP_READ_LOCAL_FEATURES */
+       HCI_INIT(hci_read_local_features_sync),
+};
+
+/* Read Buffer Size (ACL mtu, max pkt, etc.) */
+static int hci_read_buffer_size_sync(struct hci_dev *hdev)
+{
+       return __hci_cmd_sync_status(hdev, HCI_OP_READ_BUFFER_SIZE,
+                                    0, NULL, HCI_CMD_TIMEOUT);
+}
+
+/* Read Class of Device */
+static int hci_read_dev_class_sync(struct hci_dev *hdev)
+{
+       return __hci_cmd_sync_status(hdev, HCI_OP_READ_CLASS_OF_DEV,
+                                    0, NULL, HCI_CMD_TIMEOUT);
+}
+
+/* Read Local Name */
+static int hci_read_local_name_sync(struct hci_dev *hdev)
+{
+       return __hci_cmd_sync_status(hdev, HCI_OP_READ_LOCAL_NAME,
+                                    0, NULL, HCI_CMD_TIMEOUT);
+}
+
+/* Read Voice Setting */
+static int hci_read_voice_setting_sync(struct hci_dev *hdev)
+{
+       return __hci_cmd_sync_status(hdev, HCI_OP_READ_VOICE_SETTING,
+                                    0, NULL, HCI_CMD_TIMEOUT);
+}
+
+/* Read Number of Supported IAC */
+static int hci_read_num_supported_iac_sync(struct hci_dev *hdev)
+{
+       return __hci_cmd_sync_status(hdev, HCI_OP_READ_NUM_SUPPORTED_IAC,
+                                    0, NULL, HCI_CMD_TIMEOUT);
+}
+
+/* Read Current IAC LAP */
+static int hci_read_current_iac_lap_sync(struct hci_dev *hdev)
+{
+       return __hci_cmd_sync_status(hdev, HCI_OP_READ_CURRENT_IAC_LAP,
+                                    0, NULL, HCI_CMD_TIMEOUT);
+}
+
+static int hci_set_event_filter_sync(struct hci_dev *hdev, u8 flt_type,
+                                    u8 cond_type, bdaddr_t *bdaddr,
+                                    u8 auto_accept)
+{
+       struct hci_cp_set_event_filter cp;
+
+       if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
+               return 0;
+
+       memset(&cp, 0, sizeof(cp));
+       cp.flt_type = flt_type;
+
+       if (flt_type != HCI_FLT_CLEAR_ALL) {
+               cp.cond_type = cond_type;
+               bacpy(&cp.addr_conn_flt.bdaddr, bdaddr);
+               cp.addr_conn_flt.auto_accept = auto_accept;
+       }
+
+       return __hci_cmd_sync_status(hdev, HCI_OP_SET_EVENT_FLT,
+                                    flt_type == HCI_FLT_CLEAR_ALL ?
+                                    sizeof(cp.flt_type) : sizeof(cp), &cp,
+                                    HCI_CMD_TIMEOUT);
+}
+
+static int hci_clear_event_filter_sync(struct hci_dev *hdev)
+{
+       if (!hci_dev_test_flag(hdev, HCI_EVENT_FILTER_CONFIGURED))
+               return 0;
+
+       return hci_set_event_filter_sync(hdev, HCI_FLT_CLEAR_ALL, 0x00,
+                                        BDADDR_ANY, 0x00);
+}
+
+/* Connection accept timeout ~20 secs */
+static int hci_write_ca_timeout_sync(struct hci_dev *hdev)
+{
+       __le16 param = cpu_to_le16(0x7d00);
+
+       return __hci_cmd_sync_status(hdev, HCI_OP_WRITE_CA_TIMEOUT,
+                                    sizeof(param), &param, HCI_CMD_TIMEOUT);
+}
+
+/* BR Controller init stage 2 command sequence */
+static const struct hci_init_stage br_init2[] = {
+       /* HCI_OP_READ_BUFFER_SIZE */
+       HCI_INIT(hci_read_buffer_size_sync),
+       /* HCI_OP_READ_CLASS_OF_DEV */
+       HCI_INIT(hci_read_dev_class_sync),
+       /* HCI_OP_READ_LOCAL_NAME */
+       HCI_INIT(hci_read_local_name_sync),
+       /* HCI_OP_READ_VOICE_SETTING */
+       HCI_INIT(hci_read_voice_setting_sync),
+       /* HCI_OP_READ_NUM_SUPPORTED_IAC */
+       HCI_INIT(hci_read_num_supported_iac_sync),
+       /* HCI_OP_READ_CURRENT_IAC_LAP */
+       HCI_INIT(hci_read_current_iac_lap_sync),
+       /* HCI_OP_SET_EVENT_FLT */
+       HCI_INIT(hci_clear_event_filter_sync),
+       /* HCI_OP_WRITE_CA_TIMEOUT */
+       HCI_INIT(hci_write_ca_timeout_sync),
+       {}
+};
+
+static int hci_write_ssp_mode_1_sync(struct hci_dev *hdev)
+{
+       u8 mode = 0x01;
+
+       if (!lmp_ssp_capable(hdev) || !hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
+               return 0;
+
+       /* When SSP is available, then the host features page
+        * should also be available as well. However some
+        * controllers list the max_page as 0 as long as SSP
+        * has not been enabled. To achieve proper debugging
+        * output, force the minimum max_page to 1 at least.
+        */
+       hdev->max_page = 0x01;
+
+       return __hci_cmd_sync_status(hdev, HCI_OP_WRITE_SSP_MODE,
+                                    sizeof(mode), &mode, HCI_CMD_TIMEOUT);
+}
+
+static int hci_write_eir_sync(struct hci_dev *hdev)
+{
+       struct hci_cp_write_eir cp;
+
+       if (!lmp_ssp_capable(hdev) || hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
+               return 0;
+
+       memset(hdev->eir, 0, sizeof(hdev->eir));
+       memset(&cp, 0, sizeof(cp));
+
+       return __hci_cmd_sync_status(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp,
+                                    HCI_CMD_TIMEOUT);
+}
+
+static int hci_write_inquiry_mode_sync(struct hci_dev *hdev)
+{
+       u8 mode;
+
+       if (!lmp_inq_rssi_capable(hdev) &&
+           !test_bit(HCI_QUIRK_FIXUP_INQUIRY_MODE, &hdev->quirks))
+               return 0;
+
+       /* If Extended Inquiry Result events are supported, then
+        * they are clearly preferred over Inquiry Result with RSSI
+        * events.
+        */
+       mode = lmp_ext_inq_capable(hdev) ? 0x02 : 0x01;
+
+       return __hci_cmd_sync_status(hdev, HCI_OP_WRITE_INQUIRY_MODE,
+                                    sizeof(mode), &mode, HCI_CMD_TIMEOUT);
+}
+
+static int hci_read_inq_rsp_tx_power_sync(struct hci_dev *hdev)
+{
+       if (!lmp_inq_tx_pwr_capable(hdev))
+               return 0;
+
+       return __hci_cmd_sync_status(hdev, HCI_OP_READ_INQ_RSP_TX_POWER,
+                                    0, NULL, HCI_CMD_TIMEOUT);
+}
+
+static int hci_read_local_ext_features_sync(struct hci_dev *hdev, u8 page)
+{
+       struct hci_cp_read_local_ext_features cp;
+
+       if (!lmp_ext_feat_capable(hdev))
+               return 0;
+
+       memset(&cp, 0, sizeof(cp));
+       cp.page = page;
+
+       return __hci_cmd_sync_status(hdev, HCI_OP_READ_LOCAL_EXT_FEATURES,
+                                    sizeof(cp), &cp, HCI_CMD_TIMEOUT);
+}
+
+static int hci_read_local_ext_features_1_sync(struct hci_dev *hdev)
+{
+       return hci_read_local_ext_features_sync(hdev, 0x01);
+}
+
+/* HCI Controller init stage 2 command sequence */
+static const struct hci_init_stage hci_init2[] = {
+       /* HCI_OP_READ_LOCAL_COMMANDS */
+       HCI_INIT(hci_read_local_cmds_sync),
+       /* HCI_OP_WRITE_SSP_MODE */
+       HCI_INIT(hci_write_ssp_mode_1_sync),
+       /* HCI_OP_WRITE_EIR */
+       HCI_INIT(hci_write_eir_sync),
+       /* HCI_OP_WRITE_INQUIRY_MODE */
+       HCI_INIT(hci_write_inquiry_mode_sync),
+       /* HCI_OP_READ_INQ_RSP_TX_POWER */
+       HCI_INIT(hci_read_inq_rsp_tx_power_sync),
+       /* HCI_OP_READ_LOCAL_EXT_FEATURES */
+       HCI_INIT(hci_read_local_ext_features_1_sync),
+       /* HCI_OP_WRITE_AUTH_ENABLE */
+       HCI_INIT(hci_write_auth_enable_sync),
+       {}
+};
+
+/* Read LE Buffer Size */
+static int hci_le_read_buffer_size_sync(struct hci_dev *hdev)
+{
+       return __hci_cmd_sync_status(hdev, HCI_OP_LE_READ_BUFFER_SIZE,
+                                    0, NULL, HCI_CMD_TIMEOUT);
+}
+
+/* Read LE Local Supported Features */
+static int hci_le_read_local_features_sync(struct hci_dev *hdev)
+{
+       return __hci_cmd_sync_status(hdev, HCI_OP_LE_READ_LOCAL_FEATURES,
+                                    0, NULL, HCI_CMD_TIMEOUT);
+}
+
+/* Read LE Supported States */
+static int hci_le_read_supported_states_sync(struct hci_dev *hdev)
+{
+       return __hci_cmd_sync_status(hdev, HCI_OP_LE_READ_SUPPORTED_STATES,
+                                    0, NULL, HCI_CMD_TIMEOUT);
+}
+
+/* LE Controller init stage 2 command sequence */
+static const struct hci_init_stage le_init2[] = {
+       /* HCI_OP_LE_READ_BUFFER_SIZE */
+       HCI_INIT(hci_le_read_buffer_size_sync),
+       /* HCI_OP_LE_READ_LOCAL_FEATURES */
+       HCI_INIT(hci_le_read_local_features_sync),
+       /* HCI_OP_LE_READ_SUPPORTED_STATES */
+       HCI_INIT(hci_le_read_supported_states_sync),
+       {}
+};
+
+static int hci_init2_sync(struct hci_dev *hdev)
+{
+       int err;
+
+       bt_dev_dbg(hdev, "");
+
+       if (hdev->dev_type == HCI_AMP)
+               return hci_init_stage_sync(hdev, amp_init2);
+
+       if (lmp_bredr_capable(hdev)) {
+               err = hci_init_stage_sync(hdev, br_init2);
+               if (err)
+                       return err;
+       } else {
+               hci_dev_clear_flag(hdev, HCI_BREDR_ENABLED);
+       }
+
+       if (lmp_le_capable(hdev)) {
+               err = hci_init_stage_sync(hdev, le_init2);
+               if (err)
+                       return err;
+               /* LE-only controllers have LE implicitly enabled */
+               if (!lmp_bredr_capable(hdev))
+                       hci_dev_set_flag(hdev, HCI_LE_ENABLED);
+       }
+
+       return hci_init_stage_sync(hdev, hci_init2);
+}
+
+static int hci_set_event_mask_sync(struct hci_dev *hdev)
+{
+       /* The second byte is 0xff instead of 0x9f (two reserved bits
+        * disabled) since a Broadcom 1.2 dongle doesn't respond to the
+        * command otherwise.
+        */
+       u8 events[8] = { 0xff, 0xff, 0xfb, 0xff, 0x00, 0x00, 0x00, 0x00 };
+
+       /* CSR 1.1 dongles does not accept any bitfield so don't try to set
+        * any event mask for pre 1.2 devices.
+        */
+       if (hdev->hci_ver < BLUETOOTH_VER_1_2)
+               return 0;
+
+       if (lmp_bredr_capable(hdev)) {
+               events[4] |= 0x01; /* Flow Specification Complete */
+
+               /* Don't set Disconnect Complete when suspended as that
+                * would wakeup the host when disconnecting due to
+                * suspend.
+                */
+               if (hdev->suspended)
+                       events[0] &= 0xef;
+       } else {
+               /* Use a different default for LE-only devices */
+               memset(events, 0, sizeof(events));
+               events[1] |= 0x20; /* Command Complete */
+               events[1] |= 0x40; /* Command Status */
+               events[1] |= 0x80; /* Hardware Error */
+
+               /* If the controller supports the Disconnect command, enable
+                * the corresponding event. In addition enable packet flow
+                * control related events.
+                */
+               if (hdev->commands[0] & 0x20) {
+                       /* Don't set Disconnect Complete when suspended as that
+                        * would wakeup the host when disconnecting due to
+                        * suspend.
+                        */
+                       if (!hdev->suspended)
+                               events[0] |= 0x10; /* Disconnection Complete */
+                       events[2] |= 0x04; /* Number of Completed Packets */
+                       events[3] |= 0x02; /* Data Buffer Overflow */
+               }
+
+               /* If the controller supports the Read Remote Version
+                * Information command, enable the corresponding event.
+                */
+               if (hdev->commands[2] & 0x80)
+                       events[1] |= 0x08; /* Read Remote Version Information
+                                           * Complete
+                                           */
+
+               if (hdev->le_features[0] & HCI_LE_ENCRYPTION) {
+                       events[0] |= 0x80; /* Encryption Change */
+                       events[5] |= 0x80; /* Encryption Key Refresh Complete */
+               }
+       }
+
+       if (lmp_inq_rssi_capable(hdev) ||
+           test_bit(HCI_QUIRK_FIXUP_INQUIRY_MODE, &hdev->quirks))
+               events[4] |= 0x02; /* Inquiry Result with RSSI */
+
+       if (lmp_ext_feat_capable(hdev))
+               events[4] |= 0x04; /* Read Remote Extended Features Complete */
+
+       if (lmp_esco_capable(hdev)) {
+               events[5] |= 0x08; /* Synchronous Connection Complete */
+               events[5] |= 0x10; /* Synchronous Connection Changed */
+       }
+
+       if (lmp_sniffsubr_capable(hdev))
+               events[5] |= 0x20; /* Sniff Subrating */
+
+       if (lmp_pause_enc_capable(hdev))
+               events[5] |= 0x80; /* Encryption Key Refresh Complete */
+
+       if (lmp_ext_inq_capable(hdev))
+               events[5] |= 0x40; /* Extended Inquiry Result */
+
+       if (lmp_no_flush_capable(hdev))
+               events[7] |= 0x01; /* Enhanced Flush Complete */
+
+       if (lmp_lsto_capable(hdev))
+               events[6] |= 0x80; /* Link Supervision Timeout Changed */
+
+       if (lmp_ssp_capable(hdev)) {
+               events[6] |= 0x01;      /* IO Capability Request */
+               events[6] |= 0x02;      /* IO Capability Response */
+               events[6] |= 0x04;      /* User Confirmation Request */
+               events[6] |= 0x08;      /* User Passkey Request */
+               events[6] |= 0x10;      /* Remote OOB Data Request */
+               events[6] |= 0x20;      /* Simple Pairing Complete */
+               events[7] |= 0x04;      /* User Passkey Notification */
+               events[7] |= 0x08;      /* Keypress Notification */
+               events[7] |= 0x10;      /* Remote Host Supported
+                                        * Features Notification
+                                        */
+       }
+
+       if (lmp_le_capable(hdev))
+               events[7] |= 0x20;      /* LE Meta-Event */
+
+       return __hci_cmd_sync_status(hdev, HCI_OP_SET_EVENT_MASK,
+                                    sizeof(events), events, HCI_CMD_TIMEOUT);
+}
+
+static int hci_read_stored_link_key_sync(struct hci_dev *hdev)
+{
+       struct hci_cp_read_stored_link_key cp;
+
+       if (!(hdev->commands[6] & 0x20) ||
+           test_bit(HCI_QUIRK_BROKEN_STORED_LINK_KEY, &hdev->quirks))
+               return 0;
+
+       memset(&cp, 0, sizeof(cp));
+       bacpy(&cp.bdaddr, BDADDR_ANY);
+       cp.read_all = 0x01;
+
+       return __hci_cmd_sync_status(hdev, HCI_OP_READ_STORED_LINK_KEY,
+                                    sizeof(cp), &cp, HCI_CMD_TIMEOUT);
+}
+
+static int hci_setup_link_policy_sync(struct hci_dev *hdev)
+{
+       struct hci_cp_write_def_link_policy cp;
+       u16 link_policy = 0;
+
+       if (!(hdev->commands[5] & 0x10))
+               return 0;
+
+       memset(&cp, 0, sizeof(cp));
+
+       if (lmp_rswitch_capable(hdev))
+               link_policy |= HCI_LP_RSWITCH;
+       if (lmp_hold_capable(hdev))
+               link_policy |= HCI_LP_HOLD;
+       if (lmp_sniff_capable(hdev))
+               link_policy |= HCI_LP_SNIFF;
+       if (lmp_park_capable(hdev))
+               link_policy |= HCI_LP_PARK;
+
+       cp.policy = cpu_to_le16(link_policy);
+
+       return __hci_cmd_sync_status(hdev, HCI_OP_WRITE_DEF_LINK_POLICY,
+                                    sizeof(cp), &cp, HCI_CMD_TIMEOUT);
+}
+
+static int hci_read_page_scan_activity_sync(struct hci_dev *hdev)
+{
+       if (!(hdev->commands[8] & 0x01))
+               return 0;
+
+       return __hci_cmd_sync_status(hdev, HCI_OP_READ_PAGE_SCAN_ACTIVITY,
+                                    0, NULL, HCI_CMD_TIMEOUT);
+}
+
+static int hci_read_def_err_data_reporting_sync(struct hci_dev *hdev)
+{
+       if (!(hdev->commands[18] & 0x04) ||
+           test_bit(HCI_QUIRK_BROKEN_ERR_DATA_REPORTING, &hdev->quirks))
+               return 0;
+
+       return __hci_cmd_sync_status(hdev, HCI_OP_READ_DEF_ERR_DATA_REPORTING,
+                                    0, NULL, HCI_CMD_TIMEOUT);
+}
+
+static int hci_read_page_scan_type_sync(struct hci_dev *hdev)
+{
+       /* Some older Broadcom based Bluetooth 1.2 controllers do not
+        * support the Read Page Scan Type command. Check support for
+        * this command in the bit mask of supported commands.
+        */
+       if (!(hdev->commands[13] & 0x01))
+               return 0;
+
+       return __hci_cmd_sync_status(hdev, HCI_OP_READ_PAGE_SCAN_TYPE,
+                                    0, NULL, HCI_CMD_TIMEOUT);
+}
+
+/* Read features beyond page 1 if available */
+static int hci_read_local_ext_features_all_sync(struct hci_dev *hdev)
+{
+       u8 page;
+       int err;
+
+       if (!lmp_ext_feat_capable(hdev))
+               return 0;
+
+       for (page = 2; page < HCI_MAX_PAGES && page <= hdev->max_page;
+            page++) {
+               err = hci_read_local_ext_features_sync(hdev, page);
+               if (err)
+                       return err;
+       }
+
+       return 0;
+}
+
+/* HCI Controller init stage 3 command sequence */
+static const struct hci_init_stage hci_init3[] = {
+       /* HCI_OP_SET_EVENT_MASK */
+       HCI_INIT(hci_set_event_mask_sync),
+       /* HCI_OP_READ_STORED_LINK_KEY */
+       HCI_INIT(hci_read_stored_link_key_sync),
+       /* HCI_OP_WRITE_DEF_LINK_POLICY */
+       HCI_INIT(hci_setup_link_policy_sync),
+       /* HCI_OP_READ_PAGE_SCAN_ACTIVITY */
+       HCI_INIT(hci_read_page_scan_activity_sync),
+       /* HCI_OP_READ_DEF_ERR_DATA_REPORTING */
+       HCI_INIT(hci_read_def_err_data_reporting_sync),
+       /* HCI_OP_READ_PAGE_SCAN_TYPE */
+       HCI_INIT(hci_read_page_scan_type_sync),
+       /* HCI_OP_READ_LOCAL_EXT_FEATURES */
+       HCI_INIT(hci_read_local_ext_features_all_sync),
+       {}
+};
+
+static int hci_le_set_event_mask_sync(struct hci_dev *hdev)
+{
+       u8 events[8];
+
+       if (!lmp_le_capable(hdev))
+               return 0;
+
+       memset(events, 0, sizeof(events));
+
+       if (hdev->le_features[0] & HCI_LE_ENCRYPTION)
+               events[0] |= 0x10;      /* LE Long Term Key Request */
+
+       /* If controller supports the Connection Parameters Request
+        * Link Layer Procedure, enable the corresponding event.
+        */
+       if (hdev->le_features[0] & HCI_LE_CONN_PARAM_REQ_PROC)
+               /* LE Remote Connection Parameter Request */
+               events[0] |= 0x20;
+
+       /* If the controller supports the Data Length Extension
+        * feature, enable the corresponding event.
+        */
+       if (hdev->le_features[0] & HCI_LE_DATA_LEN_EXT)
+               events[0] |= 0x40;      /* LE Data Length Change */
+
+       /* If the controller supports LL Privacy feature, enable
+        * the corresponding event.
+        */
+       if (hdev->le_features[0] & HCI_LE_LL_PRIVACY)
+               events[1] |= 0x02;      /* LE Enhanced Connection Complete */
+
+       /* If the controller supports Extended Scanner Filter
+        * Policies, enable the corresponding event.
+        */
+       if (hdev->le_features[0] & HCI_LE_EXT_SCAN_POLICY)
+               events[1] |= 0x04;      /* LE Direct Advertising Report */
+
+       /* If the controller supports Channel Selection Algorithm #2
+        * feature, enable the corresponding event.
+        */
+       if (hdev->le_features[1] & HCI_LE_CHAN_SEL_ALG2)
+               events[2] |= 0x08;      /* LE Channel Selection Algorithm */
+
+       /* If the controller supports the LE Set Scan Enable command,
+        * enable the corresponding advertising report event.
+        */
+       if (hdev->commands[26] & 0x08)
+               events[0] |= 0x02;      /* LE Advertising Report */
+
+       /* If the controller supports the LE Create Connection
+        * command, enable the corresponding event.
+        */
+       if (hdev->commands[26] & 0x10)
+               events[0] |= 0x01;      /* LE Connection Complete */
+
+       /* If the controller supports the LE Connection Update
+        * command, enable the corresponding event.
+        */
+       if (hdev->commands[27] & 0x04)
+               events[0] |= 0x04;      /* LE Connection Update Complete */
+
+       /* If the controller supports the LE Read Remote Used Features
+        * command, enable the corresponding event.
+        */
+       if (hdev->commands[27] & 0x20)
+               /* LE Read Remote Used Features Complete */
+               events[0] |= 0x08;
+
+       /* If the controller supports the LE Read Local P-256
+        * Public Key command, enable the corresponding event.
+        */
+       if (hdev->commands[34] & 0x02)
+               /* LE Read Local P-256 Public Key Complete */
+               events[0] |= 0x80;
+
+       /* If the controller supports the LE Generate DHKey
+        * command, enable the corresponding event.
+        */
+       if (hdev->commands[34] & 0x04)
+               events[1] |= 0x01;      /* LE Generate DHKey Complete */
+
+       /* If the controller supports the LE Set Default PHY or
+        * LE Set PHY commands, enable the corresponding event.
+        */
+       if (hdev->commands[35] & (0x20 | 0x40))
+               events[1] |= 0x08;        /* LE PHY Update Complete */
+
+       /* If the controller supports LE Set Extended Scan Parameters
+        * and LE Set Extended Scan Enable commands, enable the
+        * corresponding event.
+        */
+       if (use_ext_scan(hdev))
+               events[1] |= 0x10;      /* LE Extended Advertising Report */
+
+       /* If the controller supports the LE Extended Advertising
+        * command, enable the corresponding event.
+        */
+       if (ext_adv_capable(hdev))
+               events[2] |= 0x02;      /* LE Advertising Set Terminated */
+
+       return __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_EVENT_MASK,
+                                    sizeof(events), events, HCI_CMD_TIMEOUT);
+}
+
+/* Read LE Advertising Channel TX Power */
+static int hci_le_read_adv_tx_power_sync(struct hci_dev *hdev)
+{
+       if ((hdev->commands[25] & 0x40) && !ext_adv_capable(hdev)) {
+               /* HCI TS spec forbids mixing of legacy and extended
+                * advertising commands wherein READ_ADV_TX_POWER is
+                * also included. So do not call it if extended adv
+                * is supported otherwise controller will return
+                * COMMAND_DISALLOWED for extended commands.
+                */
+               return __hci_cmd_sync_status(hdev,
+                                              HCI_OP_LE_READ_ADV_TX_POWER,
+                                              0, NULL, HCI_CMD_TIMEOUT);
+       }
+
+       return 0;
+}
+
+/* Read LE Min/Max Tx Power*/
+static int hci_le_read_tx_power_sync(struct hci_dev *hdev)
+{
+       if (!(hdev->commands[38] & 0x80))
+               return 0;
+
+       return __hci_cmd_sync_status(hdev, HCI_OP_LE_READ_TRANSMIT_POWER,
+                                    0, NULL, HCI_CMD_TIMEOUT);
+}
+
+/* Read LE Accept List Size */
+static int hci_le_read_accept_list_size_sync(struct hci_dev *hdev)
+{
+       if (!(hdev->commands[26] & 0x40))
+               return 0;
+
+       return __hci_cmd_sync_status(hdev, HCI_OP_LE_READ_ACCEPT_LIST_SIZE,
+                                    0, NULL, HCI_CMD_TIMEOUT);
+}
+
+/* Clear LE Accept List */
+static int hci_le_clear_accept_list_sync(struct hci_dev *hdev)
+{
+       if (!(hdev->commands[26] & 0x80))
+               return 0;
+
+       return __hci_cmd_sync_status(hdev, HCI_OP_LE_CLEAR_ACCEPT_LIST, 0, NULL,
+                                    HCI_CMD_TIMEOUT);
+}
+
+/* Read LE Resolving List Size */
+static int hci_le_read_resolv_list_size_sync(struct hci_dev *hdev)
+{
+       if (!(hdev->commands[34] & 0x40))
+               return 0;
+
+       return __hci_cmd_sync_status(hdev, HCI_OP_LE_READ_RESOLV_LIST_SIZE,
+                                    0, NULL, HCI_CMD_TIMEOUT);
+}
+
+/* Clear LE Resolving List */
+static int hci_le_clear_resolv_list_sync(struct hci_dev *hdev)
+{
+       if (!(hdev->commands[34] & 0x20))
+               return 0;
+
+       return __hci_cmd_sync_status(hdev, HCI_OP_LE_CLEAR_RESOLV_LIST, 0, NULL,
+                                    HCI_CMD_TIMEOUT);
+}
+
+/* Set RPA timeout */
+static int hci_le_set_rpa_timeout_sync(struct hci_dev *hdev)
+{
+       __le16 timeout = cpu_to_le16(hdev->rpa_timeout);
+
+       if (!(hdev->commands[35] & 0x04))
+               return 0;
+
+       return __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_RPA_TIMEOUT,
+                                    sizeof(timeout), &timeout,
+                                    HCI_CMD_TIMEOUT);
+}
+
+/* Read LE Maximum Data Length */
+static int hci_le_read_max_data_len_sync(struct hci_dev *hdev)
+{
+       if (!(hdev->le_features[0] & HCI_LE_DATA_LEN_EXT))
+               return 0;
+
+       return __hci_cmd_sync_status(hdev, HCI_OP_LE_READ_MAX_DATA_LEN, 0, NULL,
+                                    HCI_CMD_TIMEOUT);
+}
+
+/* Read LE Suggested Default Data Length */
+static int hci_le_read_def_data_len_sync(struct hci_dev *hdev)
+{
+       if (!(hdev->le_features[0] & HCI_LE_DATA_LEN_EXT))
+               return 0;
+
+       return __hci_cmd_sync_status(hdev, HCI_OP_LE_READ_DEF_DATA_LEN, 0, NULL,
+                                    HCI_CMD_TIMEOUT);
+}
+
+/* Read LE Number of Supported Advertising Sets */
+static int hci_le_read_num_support_adv_sets_sync(struct hci_dev *hdev)
+{
+       if (!ext_adv_capable(hdev))
+               return 0;
+
+       return __hci_cmd_sync_status(hdev,
+                                    HCI_OP_LE_READ_NUM_SUPPORTED_ADV_SETS,
+                                    0, NULL, HCI_CMD_TIMEOUT);
+}
+
+/* Write LE Host Supported */
+static int hci_set_le_support_sync(struct hci_dev *hdev)
+{
+       struct hci_cp_write_le_host_supported cp;
+
+       /* LE-only devices do not support explicit enablement */
+       if (!lmp_bredr_capable(hdev))
+               return 0;
+
+       memset(&cp, 0, sizeof(cp));
+
+       if (hci_dev_test_flag(hdev, HCI_LE_ENABLED)) {
+               cp.le = 0x01;
+               cp.simul = 0x00;
+       }
+
+       if (cp.le == lmp_host_le_capable(hdev))
+               return 0;
+
+       return __hci_cmd_sync_status(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED,
+                                    sizeof(cp), &cp, HCI_CMD_TIMEOUT);
+}
+
+/* LE Controller init stage 3 command sequence */
+static const struct hci_init_stage le_init3[] = {
+       /* HCI_OP_LE_SET_EVENT_MASK */
+       HCI_INIT(hci_le_set_event_mask_sync),
+       /* HCI_OP_LE_READ_ADV_TX_POWER */
+       HCI_INIT(hci_le_read_adv_tx_power_sync),
+       /* HCI_OP_LE_READ_TRANSMIT_POWER */
+       HCI_INIT(hci_le_read_tx_power_sync),
+       /* HCI_OP_LE_READ_ACCEPT_LIST_SIZE */
+       HCI_INIT(hci_le_read_accept_list_size_sync),
+       /* HCI_OP_LE_CLEAR_ACCEPT_LIST */
+       HCI_INIT(hci_le_clear_accept_list_sync),
+       /* HCI_OP_LE_READ_RESOLV_LIST_SIZE */
+       HCI_INIT(hci_le_read_resolv_list_size_sync),
+       /* HCI_OP_LE_CLEAR_RESOLV_LIST */
+       HCI_INIT(hci_le_clear_resolv_list_sync),
+       /* HCI_OP_LE_SET_RPA_TIMEOUT */
+       HCI_INIT(hci_le_set_rpa_timeout_sync),
+       /* HCI_OP_LE_READ_MAX_DATA_LEN */
+       HCI_INIT(hci_le_read_max_data_len_sync),
+       /* HCI_OP_LE_READ_DEF_DATA_LEN */
+       HCI_INIT(hci_le_read_def_data_len_sync),
+       /* HCI_OP_LE_READ_NUM_SUPPORTED_ADV_SETS */
+       HCI_INIT(hci_le_read_num_support_adv_sets_sync),
+       /* HCI_OP_WRITE_LE_HOST_SUPPORTED */
+       HCI_INIT(hci_set_le_support_sync),
+       {}
+};
+
+static int hci_init3_sync(struct hci_dev *hdev)
+{
+       int err;
+
+       bt_dev_dbg(hdev, "");
+
+       err = hci_init_stage_sync(hdev, hci_init3);
+       if (err)
+               return err;
+
+       if (lmp_le_capable(hdev))
+               return hci_init_stage_sync(hdev, le_init3);
+
+       return 0;
+}
+
+static int hci_delete_stored_link_key_sync(struct hci_dev *hdev)
+{
+       struct hci_cp_delete_stored_link_key cp;
+
+       /* Some Broadcom based Bluetooth controllers do not support the
+        * Delete Stored Link Key command. They are clearly indicating its
+        * absence in the bit mask of supported commands.
+        *
+        * Check the supported commands and only if the command is marked
+        * as supported send it. If not supported assume that the controller
+        * does not have actual support for stored link keys which makes this
+        * command redundant anyway.
+        *
+        * Some controllers indicate that they support handling deleting
+        * stored link keys, but they don't. The quirk lets a driver
+        * just disable this command.
+        */
+       if (!(hdev->commands[6] & 0x80) ||
+           test_bit(HCI_QUIRK_BROKEN_STORED_LINK_KEY, &hdev->quirks))
+               return 0;
+
+       memset(&cp, 0, sizeof(cp));
+       bacpy(&cp.bdaddr, BDADDR_ANY);
+       cp.delete_all = 0x01;
+
+       return __hci_cmd_sync_status(hdev, HCI_OP_DELETE_STORED_LINK_KEY,
+                                    sizeof(cp), &cp, HCI_CMD_TIMEOUT);
+}
+
+static int hci_set_event_mask_page_2_sync(struct hci_dev *hdev)
+{
+       u8 events[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+       bool changed = false;
+
+       /* Set event mask page 2 if the HCI command for it is supported */
+       if (!(hdev->commands[22] & 0x04))
+               return 0;
+
+       /* If Connectionless Peripheral Broadcast central role is supported
+        * enable all necessary events for it.
+        */
+       if (lmp_cpb_central_capable(hdev)) {
+               events[1] |= 0x40;      /* Triggered Clock Capture */
+               events[1] |= 0x80;      /* Synchronization Train Complete */
+               events[2] |= 0x10;      /* Peripheral Page Response Timeout */
+               events[2] |= 0x20;      /* CPB Channel Map Change */
+               changed = true;
+       }
+
+       /* If Connectionless Peripheral Broadcast peripheral role is supported
+        * enable all necessary events for it.
+        */
+       if (lmp_cpb_peripheral_capable(hdev)) {
+               events[2] |= 0x01;      /* Synchronization Train Received */
+               events[2] |= 0x02;      /* CPB Receive */
+               events[2] |= 0x04;      /* CPB Timeout */
+               events[2] |= 0x08;      /* Truncated Page Complete */
+               changed = true;
+       }
+
+       /* Enable Authenticated Payload Timeout Expired event if supported */
+       if (lmp_ping_capable(hdev) || hdev->le_features[0] & HCI_LE_PING) {
+               events[2] |= 0x80;
+               changed = true;
+       }
+
+       /* Some Broadcom based controllers indicate support for Set Event
+        * Mask Page 2 command, but then actually do not support it. Since
+        * the default value is all bits set to zero, the command is only
+        * required if the event mask has to be changed. In case no change
+        * to the event mask is needed, skip this command.
+        */
+       if (!changed)
+               return 0;
+
+       return __hci_cmd_sync_status(hdev, HCI_OP_SET_EVENT_MASK_PAGE_2,
+                                    sizeof(events), events, HCI_CMD_TIMEOUT);
+}
+
+/* Read local codec list if the HCI command is supported */
+static int hci_read_local_codecs_sync(struct hci_dev *hdev)
+{
+       if (!(hdev->commands[29] & 0x20))
+               return 0;
+
+       return __hci_cmd_sync_status(hdev, HCI_OP_READ_LOCAL_CODECS, 0, NULL,
+                                    HCI_CMD_TIMEOUT);
+}
+
+/* Read local pairing options if the HCI command is supported */
+static int hci_read_local_pairing_opts_sync(struct hci_dev *hdev)
+{
+       if (!(hdev->commands[41] & 0x08))
+               return 0;
+
+       return __hci_cmd_sync_status(hdev, HCI_OP_READ_LOCAL_PAIRING_OPTS,
+                                    0, NULL, HCI_CMD_TIMEOUT);
+}
+
+/* Get MWS transport configuration if the HCI command is supported */
+static int hci_get_mws_transport_config_sync(struct hci_dev *hdev)
+{
+       if (!(hdev->commands[30] & 0x08))
+               return 0;
+
+       return __hci_cmd_sync_status(hdev, HCI_OP_GET_MWS_TRANSPORT_CONFIG,
+                                    0, NULL, HCI_CMD_TIMEOUT);
+}
+
+/* Check for Synchronization Train support */
+static int hci_read_sync_train_params_sync(struct hci_dev *hdev)
+{
+       if (!lmp_sync_train_capable(hdev))
+               return 0;
+
+       return __hci_cmd_sync_status(hdev, HCI_OP_READ_SYNC_TRAIN_PARAMS,
+                                    0, NULL, HCI_CMD_TIMEOUT);
+}
+
+/* Enable Secure Connections if supported and configured */
+static int hci_write_sc_support_1_sync(struct hci_dev *hdev)
+{
+       u8 support = 0x01;
+
+       if (!hci_dev_test_flag(hdev, HCI_SSP_ENABLED) ||
+           !bredr_sc_enabled(hdev))
+               return 0;
+
+       return __hci_cmd_sync_status(hdev, HCI_OP_WRITE_SC_SUPPORT,
+                                    sizeof(support), &support,
+                                    HCI_CMD_TIMEOUT);
+}
+
+/* Set erroneous data reporting if supported to the wideband speech
+ * setting value
+ */
+static int hci_set_err_data_report_sync(struct hci_dev *hdev)
+{
+       struct hci_cp_write_def_err_data_reporting cp;
+       bool enabled = hci_dev_test_flag(hdev, HCI_WIDEBAND_SPEECH_ENABLED);
+
+       if (!(hdev->commands[18] & 0x08) ||
+           test_bit(HCI_QUIRK_BROKEN_ERR_DATA_REPORTING, &hdev->quirks))
+               return 0;
+
+       if (enabled == hdev->err_data_reporting)
+               return 0;
+
+       memset(&cp, 0, sizeof(cp));
+       cp.err_data_reporting = enabled ? ERR_DATA_REPORTING_ENABLED :
+                               ERR_DATA_REPORTING_DISABLED;
+
+       return __hci_cmd_sync_status(hdev, HCI_OP_WRITE_DEF_ERR_DATA_REPORTING,
+                                   sizeof(cp), &cp, HCI_CMD_TIMEOUT);
+}
+
+static const struct hci_init_stage hci_init4[] = {
+        /* HCI_OP_DELETE_STORED_LINK_KEY */
+       HCI_INIT(hci_delete_stored_link_key_sync),
+       /* HCI_OP_SET_EVENT_MASK_PAGE_2 */
+       HCI_INIT(hci_set_event_mask_page_2_sync),
+       /* HCI_OP_READ_LOCAL_CODECS */
+       HCI_INIT(hci_read_local_codecs_sync),
+        /* HCI_OP_READ_LOCAL_PAIRING_OPTS */
+       HCI_INIT(hci_read_local_pairing_opts_sync),
+        /* HCI_OP_GET_MWS_TRANSPORT_CONFIG */
+       HCI_INIT(hci_get_mws_transport_config_sync),
+        /* HCI_OP_READ_SYNC_TRAIN_PARAMS */
+       HCI_INIT(hci_read_sync_train_params_sync),
+       /* HCI_OP_WRITE_SC_SUPPORT */
+       HCI_INIT(hci_write_sc_support_1_sync),
+       /* HCI_OP_WRITE_DEF_ERR_DATA_REPORTING */
+       HCI_INIT(hci_set_err_data_report_sync),
+       {}
+};
+
+/* Set Suggested Default Data Length to maximum if supported */
+static int hci_le_set_write_def_data_len_sync(struct hci_dev *hdev)
+{
+       struct hci_cp_le_write_def_data_len cp;
+
+       if (!(hdev->le_features[0] & HCI_LE_DATA_LEN_EXT))
+               return 0;
+
+       memset(&cp, 0, sizeof(cp));
+       cp.tx_len = cpu_to_le16(hdev->le_max_tx_len);
+       cp.tx_time = cpu_to_le16(hdev->le_max_tx_time);
+
+       return __hci_cmd_sync_status(hdev, HCI_OP_LE_WRITE_DEF_DATA_LEN,
+                                    sizeof(cp), &cp, HCI_CMD_TIMEOUT);
+}
+
+/* Set Default PHY parameters if command is supported */
+static int hci_le_set_default_phy_sync(struct hci_dev *hdev)
+{
+       struct hci_cp_le_set_default_phy cp;
+
+       if (!(hdev->commands[35] & 0x20))
+               return 0;
+
+       memset(&cp, 0, sizeof(cp));
+       cp.all_phys = 0x00;
+       cp.tx_phys = hdev->le_tx_def_phys;
+       cp.rx_phys = hdev->le_rx_def_phys;
+
+       return __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_DEFAULT_PHY,
+                                    sizeof(cp), &cp, HCI_CMD_TIMEOUT);
+}
+
+static const struct hci_init_stage le_init4[] = {
+       /* HCI_OP_LE_WRITE_DEF_DATA_LEN */
+       HCI_INIT(hci_le_set_write_def_data_len_sync),
+       /* HCI_OP_LE_SET_DEFAULT_PHY */
+       HCI_INIT(hci_le_set_default_phy_sync),
+       {}
+};
+
+static int hci_init4_sync(struct hci_dev *hdev)
+{
+       int err;
+
+       bt_dev_dbg(hdev, "");
+
+       err = hci_init_stage_sync(hdev, hci_init4);
+       if (err)
+               return err;
+
+       if (lmp_le_capable(hdev))
+               return hci_init_stage_sync(hdev, le_init4);
+
+       return 0;
+}
+
+static int hci_init_sync(struct hci_dev *hdev)
+{
+       int err;
+
+       err = hci_init1_sync(hdev);
+       if (err < 0)
+               return err;
+
+       if (hci_dev_test_flag(hdev, HCI_SETUP))
+               hci_debugfs_create_basic(hdev);
+
+       err = hci_init2_sync(hdev);
+       if (err < 0)
+               return err;
+
+       /* HCI_PRIMARY covers both single-mode LE, BR/EDR and dual-mode
+        * BR/EDR/LE type controllers. AMP controllers only need the
+        * first two stages of init.
+        */
+       if (hdev->dev_type != HCI_PRIMARY)
+               return 0;
+
+       err = hci_init3_sync(hdev);
+       if (err < 0)
+               return err;
+
+       err = hci_init4_sync(hdev);
+       if (err < 0)
+               return err;
+
+       /* This function is only called when the controller is actually in
+        * configured state. When the controller is marked as unconfigured,
+        * this initialization procedure is not run.
+        *
+        * It means that it is possible that a controller runs through its
+        * setup phase and then discovers missing settings. If that is the
+        * case, then this function will not be called. It then will only
+        * be called during the config phase.
+        *
+        * So only when in setup phase or config phase, create the debugfs
+        * entries and register the SMP channels.
+        */
+       if (!hci_dev_test_flag(hdev, HCI_SETUP) &&
+           !hci_dev_test_flag(hdev, HCI_CONFIG))
+               return 0;
+
+       hci_debugfs_create_common(hdev);
+
+       if (lmp_bredr_capable(hdev))
+               hci_debugfs_create_bredr(hdev);
+
+       if (lmp_le_capable(hdev))
+               hci_debugfs_create_le(hdev);
+
+       return 0;
+}
+
+int hci_dev_open_sync(struct hci_dev *hdev)
+{
+       int ret = 0;
+
+       bt_dev_dbg(hdev, "");
+
+       if (hci_dev_test_flag(hdev, HCI_UNREGISTER)) {
+               ret = -ENODEV;
+               goto done;
+       }
+
+       if (!hci_dev_test_flag(hdev, HCI_SETUP) &&
+           !hci_dev_test_flag(hdev, HCI_CONFIG)) {
+               /* Check for rfkill but allow the HCI setup stage to
+                * proceed (which in itself doesn't cause any RF activity).
+                */
+               if (hci_dev_test_flag(hdev, HCI_RFKILLED)) {
+                       ret = -ERFKILL;
+                       goto done;
+               }
+
+               /* Check for valid public address or a configured static
+                * random address, but let the HCI setup proceed to
+                * be able to determine if there is a public address
+                * or not.
+                *
+                * In case of user channel usage, it is not important
+                * if a public address or static random address is
+                * available.
+                *
+                * This check is only valid for BR/EDR controllers
+                * since AMP controllers do not have an address.
+                */
+               if (!hci_dev_test_flag(hdev, HCI_USER_CHANNEL) &&
+                   hdev->dev_type == HCI_PRIMARY &&
+                   !bacmp(&hdev->bdaddr, BDADDR_ANY) &&
+                   !bacmp(&hdev->static_addr, BDADDR_ANY)) {
+                       ret = -EADDRNOTAVAIL;
+                       goto done;
+               }
+       }
+
+       if (test_bit(HCI_UP, &hdev->flags)) {
+               ret = -EALREADY;
+               goto done;
+       }
+
+       if (hdev->open(hdev)) {
+               ret = -EIO;
+               goto done;
+       }
+
+       set_bit(HCI_RUNNING, &hdev->flags);
+       hci_sock_dev_event(hdev, HCI_DEV_OPEN);
+
+       atomic_set(&hdev->cmd_cnt, 1);
+       set_bit(HCI_INIT, &hdev->flags);
+
+       if (hci_dev_test_flag(hdev, HCI_SETUP) ||
+           test_bit(HCI_QUIRK_NON_PERSISTENT_SETUP, &hdev->quirks)) {
+               bool invalid_bdaddr;
+
+               hci_sock_dev_event(hdev, HCI_DEV_SETUP);
+
+               if (hdev->setup)
+                       ret = hdev->setup(hdev);
+
+               /* The transport driver can set the quirk to mark the
+                * BD_ADDR invalid before creating the HCI device or in
+                * its setup callback.
+                */
+               invalid_bdaddr = test_bit(HCI_QUIRK_INVALID_BDADDR,
+                                         &hdev->quirks);
+
+               if (ret)
+                       goto setup_failed;
+
+               if (test_bit(HCI_QUIRK_USE_BDADDR_PROPERTY, &hdev->quirks)) {
+                       if (!bacmp(&hdev->public_addr, BDADDR_ANY))
+                               hci_dev_get_bd_addr_from_property(hdev);
+
+                       if (bacmp(&hdev->public_addr, BDADDR_ANY) &&
+                           hdev->set_bdaddr) {
+                               ret = hdev->set_bdaddr(hdev,
+                                                      &hdev->public_addr);
+
+                               /* If setting of the BD_ADDR from the device
+                                * property succeeds, then treat the address
+                                * as valid even if the invalid BD_ADDR
+                                * quirk indicates otherwise.
+                                */
+                               if (!ret)
+                                       invalid_bdaddr = false;
+                       }
+               }
+
+setup_failed:
+               /* The transport driver can set these quirks before
+                * creating the HCI device or in its setup callback.
+                *
+                * For the invalid BD_ADDR quirk it is possible that
+                * it becomes a valid address if the bootloader does
+                * provide it (see above).
+                *
+                * In case any of them is set, the controller has to
+                * start up as unconfigured.
+                */
+               if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks) ||
+                   invalid_bdaddr)
+                       hci_dev_set_flag(hdev, HCI_UNCONFIGURED);
+
+               /* For an unconfigured controller it is required to
+                * read at least the version information provided by
+                * the Read Local Version Information command.
+                *
+                * If the set_bdaddr driver callback is provided, then
+                * also the original Bluetooth public device address
+                * will be read using the Read BD Address command.
+                */
+               if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED))
+                       ret = hci_unconf_init_sync(hdev);
+       }
+
+       if (hci_dev_test_flag(hdev, HCI_CONFIG)) {
+               /* If public address change is configured, ensure that
+                * the address gets programmed. If the driver does not
+                * support changing the public address, fail the power
+                * on procedure.
+                */
+               if (bacmp(&hdev->public_addr, BDADDR_ANY) &&
+                   hdev->set_bdaddr)
+                       ret = hdev->set_bdaddr(hdev, &hdev->public_addr);
+               else
+                       ret = -EADDRNOTAVAIL;
+       }
+
+       if (!ret) {
+               if (!hci_dev_test_flag(hdev, HCI_UNCONFIGURED) &&
+                   !hci_dev_test_flag(hdev, HCI_USER_CHANNEL)) {
+                       ret = hci_init_sync(hdev);
+                       if (!ret && hdev->post_init)
+                               ret = hdev->post_init(hdev);
+               }
+       }
+
+       /* If the HCI Reset command is clearing all diagnostic settings,
+        * then they need to be reprogrammed after the init procedure
+        * completed.
+        */
+       if (test_bit(HCI_QUIRK_NON_PERSISTENT_DIAG, &hdev->quirks) &&
+           !hci_dev_test_flag(hdev, HCI_USER_CHANNEL) &&
+           hci_dev_test_flag(hdev, HCI_VENDOR_DIAG) && hdev->set_diag)
+               ret = hdev->set_diag(hdev, true);
+
+       if (!hci_dev_test_flag(hdev, HCI_USER_CHANNEL)) {
+               msft_do_open(hdev);
+               aosp_do_open(hdev);
+       }
+
+       clear_bit(HCI_INIT, &hdev->flags);
+
+       if (!ret) {
+               hci_dev_hold(hdev);
+               hci_dev_set_flag(hdev, HCI_RPA_EXPIRED);
+               hci_adv_instances_set_rpa_expired(hdev, true);
+               set_bit(HCI_UP, &hdev->flags);
+               hci_sock_dev_event(hdev, HCI_DEV_UP);
+               hci_leds_update_powered(hdev, true);
+               if (!hci_dev_test_flag(hdev, HCI_SETUP) &&
+                   !hci_dev_test_flag(hdev, HCI_CONFIG) &&
+                   !hci_dev_test_flag(hdev, HCI_UNCONFIGURED) &&
+                   !hci_dev_test_flag(hdev, HCI_USER_CHANNEL) &&
+                   hci_dev_test_flag(hdev, HCI_MGMT) &&
+                   hdev->dev_type == HCI_PRIMARY) {
+                       ret = hci_powered_update_sync(hdev);
+               }
+       } else {
+               /* Init failed, cleanup */
+               flush_work(&hdev->tx_work);
+
+               /* Since hci_rx_work() is possible to awake new cmd_work
+                * it should be flushed first to avoid unexpected call of
+                * hci_cmd_work()
+                */
+               flush_work(&hdev->rx_work);
+               flush_work(&hdev->cmd_work);
+
+               skb_queue_purge(&hdev->cmd_q);
+               skb_queue_purge(&hdev->rx_q);
+
+               if (hdev->flush)
+                       hdev->flush(hdev);
+
+               if (hdev->sent_cmd) {
+                       kfree_skb(hdev->sent_cmd);
+                       hdev->sent_cmd = NULL;
+               }
+
+               clear_bit(HCI_RUNNING, &hdev->flags);
+               hci_sock_dev_event(hdev, HCI_DEV_CLOSE);
+
+               hdev->close(hdev);
+               hdev->flags &= BIT(HCI_RAW);
+       }
+
+done:
+       return ret;
+}
+
+/* This function requires the caller holds hdev->lock */
+static void hci_pend_le_actions_clear(struct hci_dev *hdev)
+{
+       struct hci_conn_params *p;
+
+       list_for_each_entry(p, &hdev->le_conn_params, list) {
+               if (p->conn) {
+                       hci_conn_drop(p->conn);
+                       hci_conn_put(p->conn);
+                       p->conn = NULL;
+               }
+               list_del_init(&p->action);
+       }
+
+       BT_DBG("All LE pending actions cleared");
+}
+
+int hci_dev_close_sync(struct hci_dev *hdev)
+{
+       bool auto_off;
+       int err = 0;
+
+       bt_dev_dbg(hdev, "");
+
+       cancel_delayed_work(&hdev->power_off);
+       cancel_delayed_work(&hdev->ncmd_timer);
+
+       hci_request_cancel_all(hdev);
+
+       if (!hci_dev_test_flag(hdev, HCI_UNREGISTER) &&
+           !hci_dev_test_flag(hdev, HCI_USER_CHANNEL) &&
+           test_bit(HCI_UP, &hdev->flags)) {
+               /* Execute vendor specific shutdown routine */
+               if (hdev->shutdown)
+                       err = hdev->shutdown(hdev);
+       }
+
+       if (!test_and_clear_bit(HCI_UP, &hdev->flags)) {
+               cancel_delayed_work_sync(&hdev->cmd_timer);
+               return err;
+       }
+
+       hci_leds_update_powered(hdev, false);
+
+       /* Flush RX and TX works */
+       flush_work(&hdev->tx_work);
+       flush_work(&hdev->rx_work);
+
+       if (hdev->discov_timeout > 0) {
+               hdev->discov_timeout = 0;
+               hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
+               hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
+       }
+
+       if (hci_dev_test_and_clear_flag(hdev, HCI_SERVICE_CACHE))
+               cancel_delayed_work(&hdev->service_cache);
+
+       if (hci_dev_test_flag(hdev, HCI_MGMT)) {
+               struct adv_info *adv_instance;
+
+               cancel_delayed_work_sync(&hdev->rpa_expired);
+
+               list_for_each_entry(adv_instance, &hdev->adv_instances, list)
+                       cancel_delayed_work_sync(&adv_instance->rpa_expired_cb);
+       }
+
+       /* Avoid potential lockdep warnings from the *_flush() calls by
+        * ensuring the workqueue is empty up front.
+        */
+       drain_workqueue(hdev->workqueue);
+
+       hci_dev_lock(hdev);
+
+       hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
+
+       auto_off = hci_dev_test_and_clear_flag(hdev, HCI_AUTO_OFF);
+
+       if (!auto_off && hdev->dev_type == HCI_PRIMARY &&
+           !hci_dev_test_flag(hdev, HCI_USER_CHANNEL) &&
+           hci_dev_test_flag(hdev, HCI_MGMT))
+               __mgmt_power_off(hdev);
+
+       hci_inquiry_cache_flush(hdev);
+       hci_pend_le_actions_clear(hdev);
+       hci_conn_hash_flush(hdev);
+       hci_dev_unlock(hdev);
+
+       smp_unregister(hdev);
+
+       hci_sock_dev_event(hdev, HCI_DEV_DOWN);
+
+       if (!hci_dev_test_flag(hdev, HCI_USER_CHANNEL)) {
+               aosp_do_close(hdev);
+               msft_do_close(hdev);
+       }
+
+       if (hdev->flush)
+               hdev->flush(hdev);
+
+       /* Reset device */
+       skb_queue_purge(&hdev->cmd_q);
+       atomic_set(&hdev->cmd_cnt, 1);
+       if (test_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks) &&
+           !auto_off && !hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) {
+               set_bit(HCI_INIT, &hdev->flags);
+               hci_reset_sync(hdev);
+               clear_bit(HCI_INIT, &hdev->flags);
+       }
+
+       /* flush cmd  work */
+       flush_work(&hdev->cmd_work);
+
+       /* Drop queues */
+       skb_queue_purge(&hdev->rx_q);
+       skb_queue_purge(&hdev->cmd_q);
+       skb_queue_purge(&hdev->raw_q);
+
+       /* Drop last sent command */
+       if (hdev->sent_cmd) {
+               cancel_delayed_work_sync(&hdev->cmd_timer);
+               kfree_skb(hdev->sent_cmd);
+               hdev->sent_cmd = NULL;
+       }
+
+       clear_bit(HCI_RUNNING, &hdev->flags);
+       hci_sock_dev_event(hdev, HCI_DEV_CLOSE);
+
+       /* After this point our queues are empty and no tasks are scheduled. */
+       hdev->close(hdev);
+
+       /* Clear flags */
+       hdev->flags &= BIT(HCI_RAW);
+       hci_dev_clear_volatile_flags(hdev);
+
+       /* Controller radio is available but is currently powered down */
+       hdev->amp_status = AMP_STATUS_POWERED_DOWN;
+
+       memset(hdev->eir, 0, sizeof(hdev->eir));
+       memset(hdev->dev_class, 0, sizeof(hdev->dev_class));
+       bacpy(&hdev->random_addr, BDADDR_ANY);
+
+       hci_dev_put(hdev);
+       return err;
+}
+
+/* This function perform power on HCI command sequence as follows:
+ *
+ * If controller is already up (HCI_UP) performs hci_powered_update_sync
+ * sequence otherwise run hci_dev_open_sync which will follow with
+ * hci_powered_update_sync after the init sequence is completed.
+ */
+static int hci_power_on_sync(struct hci_dev *hdev)
+{
+       int err;
+
+       if (test_bit(HCI_UP, &hdev->flags) &&
+           hci_dev_test_flag(hdev, HCI_MGMT) &&
+           hci_dev_test_and_clear_flag(hdev, HCI_AUTO_OFF)) {
+               cancel_delayed_work(&hdev->power_off);
+               return hci_powered_update_sync(hdev);
+       }
+
+       err = hci_dev_open_sync(hdev);
+       if (err < 0)
+               return err;
+
+       /* During the HCI setup phase, a few error conditions are
+        * ignored and they need to be checked now. If they are still
+        * valid, it is important to return the device back off.
+        */
+       if (hci_dev_test_flag(hdev, HCI_RFKILLED) ||
+           hci_dev_test_flag(hdev, HCI_UNCONFIGURED) ||
+           (hdev->dev_type == HCI_PRIMARY &&
+            !bacmp(&hdev->bdaddr, BDADDR_ANY) &&
+            !bacmp(&hdev->static_addr, BDADDR_ANY))) {
+               hci_dev_clear_flag(hdev, HCI_AUTO_OFF);
+               hci_dev_close_sync(hdev);
+       } else if (hci_dev_test_flag(hdev, HCI_AUTO_OFF)) {
+               queue_delayed_work(hdev->req_workqueue, &hdev->power_off,
+                                  HCI_AUTO_OFF_TIMEOUT);
+       }
+
+       if (hci_dev_test_and_clear_flag(hdev, HCI_SETUP)) {
+               /* For unconfigured devices, set the HCI_RAW flag
+                * so that userspace can easily identify them.
+                */
+               if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED))
+                       set_bit(HCI_RAW, &hdev->flags);
+
+               /* For fully configured devices, this will send
+                * the Index Added event. For unconfigured devices,
+                * it will send Unconfigued Index Added event.
+                *
+                * Devices with HCI_QUIRK_RAW_DEVICE are ignored
+                * and no event will be send.
+                */
+               mgmt_index_added(hdev);
+       } else if (hci_dev_test_and_clear_flag(hdev, HCI_CONFIG)) {
+               /* When the controller is now configured, then it
+                * is important to clear the HCI_RAW flag.
+                */
+               if (!hci_dev_test_flag(hdev, HCI_UNCONFIGURED))
+                       clear_bit(HCI_RAW, &hdev->flags);
+
+               /* Powering on the controller with HCI_CONFIG set only
+                * happens with the transition from unconfigured to
+                * configured. This will send the Index Added event.
+                */
+               mgmt_index_added(hdev);
+       }
+
+       return 0;
+}
+
+static int hci_remote_name_cancel_sync(struct hci_dev *hdev, bdaddr_t *addr)
+{
+       struct hci_cp_remote_name_req_cancel cp;
+
+       memset(&cp, 0, sizeof(cp));
+       bacpy(&cp.bdaddr, addr);
+
+       return __hci_cmd_sync_status(hdev, HCI_OP_REMOTE_NAME_REQ_CANCEL,
+                                    sizeof(cp), &cp, HCI_CMD_TIMEOUT);
+}
+
+int hci_stop_discovery_sync(struct hci_dev *hdev)
+{
+       struct discovery_state *d = &hdev->discovery;
+       struct inquiry_entry *e;
+       int err;
+
+       bt_dev_dbg(hdev, "state %u", hdev->discovery.state);
+
+       if (d->state == DISCOVERY_FINDING || d->state == DISCOVERY_STOPPING) {
+               if (test_bit(HCI_INQUIRY, &hdev->flags)) {
+                       err = __hci_cmd_sync_status(hdev, HCI_OP_INQUIRY_CANCEL,
+                                                   0, NULL, HCI_CMD_TIMEOUT);
+                       if (err)
+                               return err;
+               }
+
+               if (hci_dev_test_flag(hdev, HCI_LE_SCAN)) {
+                       cancel_delayed_work(&hdev->le_scan_disable);
+                       cancel_delayed_work(&hdev->le_scan_restart);
+
+                       err = hci_scan_disable_sync(hdev);
+                       if (err)
+                               return err;
+               }
+
+       } else {
+               err = hci_scan_disable_sync(hdev);
+               if (err)
+                       return err;
+       }
+
+       /* Resume advertising if it was paused */
+       if (use_ll_privacy(hdev))
+               hci_resume_advertising_sync(hdev);
+
+       /* No further actions needed for LE-only discovery */
+       if (d->type == DISCOV_TYPE_LE)
+               return 0;
+
+       if (d->state == DISCOVERY_RESOLVING || d->state == DISCOVERY_STOPPING) {
+               e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY,
+                                                    NAME_PENDING);
+               if (!e)
+                       return 0;
+
+               return hci_remote_name_cancel_sync(hdev, &e->data.bdaddr);
+       }
+
+       return 0;
+}
+
+static int hci_disconnect_phy_link_sync(struct hci_dev *hdev, u16 handle,
+                                       u8 reason)
+{
+       struct hci_cp_disconn_phy_link cp;
+
+       memset(&cp, 0, sizeof(cp));
+       cp.phy_handle = HCI_PHY_HANDLE(handle);
+       cp.reason = reason;
+
+       return __hci_cmd_sync_status(hdev, HCI_OP_DISCONN_PHY_LINK,
+                                    sizeof(cp), &cp, HCI_CMD_TIMEOUT);
+}
+
+static int hci_disconnect_sync(struct hci_dev *hdev, struct hci_conn *conn,
+                              u8 reason)
+{
+       struct hci_cp_disconnect cp;
+
+       if (conn->type == AMP_LINK)
+               return hci_disconnect_phy_link_sync(hdev, conn->handle, reason);
+
+       memset(&cp, 0, sizeof(cp));
+       cp.handle = cpu_to_le16(conn->handle);
+       cp.reason = reason;
+
+       /* Wait for HCI_EV_DISCONN_COMPLETE not HCI_EV_CMD_STATUS when not
+        * suspending.
+        */
+       if (!hdev->suspended)
+               return __hci_cmd_sync_status_sk(hdev, HCI_OP_DISCONNECT,
+                                               sizeof(cp), &cp,
+                                               HCI_EV_DISCONN_COMPLETE,
+                                               HCI_CMD_TIMEOUT, NULL);
+
+       return __hci_cmd_sync_status(hdev, HCI_OP_DISCONNECT, sizeof(cp), &cp,
+                                    HCI_CMD_TIMEOUT);
+}
+
+static int hci_le_connect_cancel_sync(struct hci_dev *hdev,
+                                     struct hci_conn *conn)
+{
+       if (test_bit(HCI_CONN_SCANNING, &conn->flags))
+               return 0;
+
+       return __hci_cmd_sync_status(hdev, HCI_OP_LE_CREATE_CONN_CANCEL,
+                                    6, &conn->dst, HCI_CMD_TIMEOUT);
+}
+
+static int hci_connect_cancel_sync(struct hci_dev *hdev, struct hci_conn *conn)
+{
+       if (conn->type == LE_LINK)
+               return hci_le_connect_cancel_sync(hdev, conn);
+
+       if (hdev->hci_ver < BLUETOOTH_VER_1_2)
+               return 0;
+
+       return __hci_cmd_sync_status(hdev, HCI_OP_CREATE_CONN_CANCEL,
+                                    6, &conn->dst, HCI_CMD_TIMEOUT);
+}
+
+static int hci_reject_sco_sync(struct hci_dev *hdev, struct hci_conn *conn,
+                              u8 reason)
+{
+       struct hci_cp_reject_sync_conn_req cp;
+
+       memset(&cp, 0, sizeof(cp));
+       bacpy(&cp.bdaddr, &conn->dst);
+       cp.reason = reason;
+
+       /* SCO rejection has its own limited set of
+        * allowed error values (0x0D-0x0F).
+        */
+       if (reason < 0x0d || reason > 0x0f)
+               cp.reason = HCI_ERROR_REJ_LIMITED_RESOURCES;
+
+       return __hci_cmd_sync_status(hdev, HCI_OP_REJECT_SYNC_CONN_REQ,
+                                    sizeof(cp), &cp, HCI_CMD_TIMEOUT);
+}
+
+static int hci_reject_conn_sync(struct hci_dev *hdev, struct hci_conn *conn,
+                               u8 reason)
+{
+       struct hci_cp_reject_conn_req cp;
+
+       if (conn->type == SCO_LINK || conn->type == ESCO_LINK)
+               return hci_reject_sco_sync(hdev, conn, reason);
+
+       memset(&cp, 0, sizeof(cp));
+       bacpy(&cp.bdaddr, &conn->dst);
+       cp.reason = reason;
+
+       return __hci_cmd_sync_status(hdev, HCI_OP_REJECT_CONN_REQ,
+                                    sizeof(cp), &cp, HCI_CMD_TIMEOUT);
+}
+
+static int hci_abort_conn_sync(struct hci_dev *hdev, struct hci_conn *conn,
+                              u8 reason)
+{
+       switch (conn->state) {
+       case BT_CONNECTED:
+       case BT_CONFIG:
+               return hci_disconnect_sync(hdev, conn, reason);
+       case BT_CONNECT:
+               return hci_connect_cancel_sync(hdev, conn);
+       case BT_CONNECT2:
+               return hci_reject_conn_sync(hdev, conn, reason);
+       default:
+               conn->state = BT_CLOSED;
+               break;
+       }
+
+       return 0;
+}
+
+static int hci_disconnect_all_sync(struct hci_dev *hdev, u8 reason)
+{
+       struct hci_conn *conn, *tmp;
+       int err;
+
+       list_for_each_entry_safe(conn, tmp, &hdev->conn_hash.list, list) {
+               err = hci_abort_conn_sync(hdev, conn, reason);
+               if (err)
+                       return err;
+       }
+
+       return err;
+}
+
+/* This function perform power off HCI command sequence as follows:
+ *
+ * Clear Advertising
+ * Stop Discovery
+ * Disconnect all connections
+ * hci_dev_close_sync
+ */
+static int hci_power_off_sync(struct hci_dev *hdev)
+{
+       int err;
+
+       /* If controller is already down there is nothing to do */
+       if (!test_bit(HCI_UP, &hdev->flags))
+               return 0;
+
+       if (test_bit(HCI_ISCAN, &hdev->flags) ||
+           test_bit(HCI_PSCAN, &hdev->flags)) {
+               err = hci_write_scan_enable_sync(hdev, 0x00);
+               if (err)
+                       return err;
+       }
+
+       err = hci_clear_adv_sync(hdev, NULL, false);
+       if (err)
+               return err;
+
+       err = hci_stop_discovery_sync(hdev);
+       if (err)
+               return err;
+
+       /* Terminated due to Power Off */
+       err = hci_disconnect_all_sync(hdev, HCI_ERROR_REMOTE_POWER_OFF);
+       if (err)
+               return err;
+
+       return hci_dev_close_sync(hdev);
+}
+
+int hci_set_powered_sync(struct hci_dev *hdev, u8 val)
+{
+       if (val)
+               return hci_power_on_sync(hdev);
+
+       return hci_power_off_sync(hdev);
+}
+
+static int hci_write_iac_sync(struct hci_dev *hdev)
+{
+       struct hci_cp_write_current_iac_lap cp;
+
+       if (!hci_dev_test_flag(hdev, HCI_DISCOVERABLE))
+               return 0;
+
+       memset(&cp, 0, sizeof(cp));
+
+       if (hci_dev_test_flag(hdev, HCI_LIMITED_DISCOVERABLE)) {
+               /* Limited discoverable mode */
+               cp.num_iac = min_t(u8, hdev->num_iac, 2);
+               cp.iac_lap[0] = 0x00;   /* LIAC */
+               cp.iac_lap[1] = 0x8b;
+               cp.iac_lap[2] = 0x9e;
+               cp.iac_lap[3] = 0x33;   /* GIAC */
+               cp.iac_lap[4] = 0x8b;
+               cp.iac_lap[5] = 0x9e;
+       } else {
+               /* General discoverable mode */
+               cp.num_iac = 1;
+               cp.iac_lap[0] = 0x33;   /* GIAC */
+               cp.iac_lap[1] = 0x8b;
+               cp.iac_lap[2] = 0x9e;
+       }
+
+       return __hci_cmd_sync_status(hdev, HCI_OP_WRITE_CURRENT_IAC_LAP,
+                                    (cp.num_iac * 3) + 1, &cp,
+                                    HCI_CMD_TIMEOUT);
+}
+
+int hci_update_discoverable_sync(struct hci_dev *hdev)
+{
+       int err = 0;
+
+       if (hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
+               err = hci_write_iac_sync(hdev);
+               if (err)
+                       return err;
+
+               err = hci_update_scan_sync(hdev);
+               if (err)
+                       return err;
+
+               err = hci_update_class_sync(hdev);
+               if (err)
+                       return err;
+       }
+
+       /* Advertising instances don't use the global discoverable setting, so
+        * only update AD if advertising was enabled using Set Advertising.
+        */
+       if (hci_dev_test_flag(hdev, HCI_ADVERTISING)) {
+               err = hci_update_adv_data_sync(hdev, 0x00);
+               if (err)
+                       return err;
+
+               /* Discoverable mode affects the local advertising
+                * address in limited privacy mode.
+                */
+               if (hci_dev_test_flag(hdev, HCI_LIMITED_PRIVACY)) {
+                       if (ext_adv_capable(hdev))
+                               err = hci_start_ext_adv_sync(hdev, 0x00);
+                       else
+                               err = hci_enable_advertising_sync(hdev);
+               }
+       }
+
+       return err;
+}
+
+static int update_discoverable_sync(struct hci_dev *hdev, void *data)
+{
+       return hci_update_discoverable_sync(hdev);
+}
+
+int hci_update_discoverable(struct hci_dev *hdev)
+{
+       /* Only queue if it would have any effect */
+       if (hdev_is_powered(hdev) &&
+           hci_dev_test_flag(hdev, HCI_ADVERTISING) &&
+           hci_dev_test_flag(hdev, HCI_DISCOVERABLE) &&
+           hci_dev_test_flag(hdev, HCI_LIMITED_PRIVACY))
+               return hci_cmd_sync_queue(hdev, update_discoverable_sync, NULL,
+                                         NULL);
+
+       return 0;
+}
+
+int hci_update_connectable_sync(struct hci_dev *hdev)
+{
+       int err;
+
+       err = hci_update_scan_sync(hdev);
+       if (err)
+               return err;
+
+       /* If BR/EDR is not enabled and we disable advertising as a
+        * by-product of disabling connectable, we need to update the
+        * advertising flags.
+        */
+       if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
+               err = hci_update_adv_data_sync(hdev, hdev->cur_adv_instance);
+
+       /* Update the advertising parameters if necessary */
+       if (hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
+           !list_empty(&hdev->adv_instances)) {
+               if (ext_adv_capable(hdev))
+                       err = hci_start_ext_adv_sync(hdev,
+                                                    hdev->cur_adv_instance);
+               else
+                       err = hci_enable_advertising_sync(hdev);
+
+               if (err)
+                       return err;
+       }
+
+       return hci_update_passive_scan_sync(hdev);
+}
+
+static int hci_inquiry_sync(struct hci_dev *hdev, u8 length)
+{
+       const u8 giac[3] = { 0x33, 0x8b, 0x9e };
+       const u8 liac[3] = { 0x00, 0x8b, 0x9e };
+       struct hci_cp_inquiry cp;
+
+       bt_dev_dbg(hdev, "");
+
+       if (hci_dev_test_flag(hdev, HCI_INQUIRY))
+               return 0;
+
+       hci_dev_lock(hdev);
+       hci_inquiry_cache_flush(hdev);
+       hci_dev_unlock(hdev);
+
+       memset(&cp, 0, sizeof(cp));
+
+       if (hdev->discovery.limited)
+               memcpy(&cp.lap, liac, sizeof(cp.lap));
+       else
+               memcpy(&cp.lap, giac, sizeof(cp.lap));
+
+       cp.length = length;
+
+       return __hci_cmd_sync_status(hdev, HCI_OP_INQUIRY,
+                                    sizeof(cp), &cp, HCI_CMD_TIMEOUT);
+}
+
+static int hci_active_scan_sync(struct hci_dev *hdev, uint16_t interval)
+{
+       u8 own_addr_type;
+       /* Accept list is not used for discovery */
+       u8 filter_policy = 0x00;
+       /* Default is to enable duplicates filter */
+       u8 filter_dup = LE_SCAN_FILTER_DUP_ENABLE;
+       int err;
+
+       bt_dev_dbg(hdev, "");
+
+       /* If controller is scanning, it means the passive scanning is
+        * running. Thus, we should temporarily stop it in order to set the
+        * discovery scanning parameters.
+        */
+       err = hci_scan_disable_sync(hdev);
+       if (err) {
+               bt_dev_err(hdev, "Unable to disable scanning: %d", err);
+               return err;
+       }
+
+       cancel_interleave_scan(hdev);
+
+       /* Pause advertising since active scanning disables address resolution
+        * which advertising depend on in order to generate its RPAs.
+        */
+       if (use_ll_privacy(hdev)) {
+               err = hci_pause_advertising_sync(hdev);
+               if (err) {
+                       bt_dev_err(hdev, "pause advertising failed: %d", err);
+                       goto failed;
+               }
+       }
+
+       /* Disable address resolution while doing active scanning since the
+        * accept list shall not be used and all reports shall reach the host
+        * anyway.
+        */
+       err = hci_le_set_addr_resolution_enable_sync(hdev, 0x00);
+       if (err) {
+               bt_dev_err(hdev, "Unable to disable Address Resolution: %d",
+                          err);
+               goto failed;
+       }
+
+       /* All active scans will be done with either a resolvable private
+        * address (when privacy feature has been enabled) or non-resolvable
+        * private address.
+        */
+       err = hci_update_random_address_sync(hdev, true, scan_use_rpa(hdev),
+                                            &own_addr_type);
+       if (err < 0)
+               own_addr_type = ADDR_LE_DEV_PUBLIC;
+
+       if (hci_is_adv_monitoring(hdev)) {
+               /* Duplicate filter should be disabled when some advertisement
+                * monitor is activated, otherwise AdvMon can only receive one
+                * advertisement for one peer(*) during active scanning, and
+                * might report loss to these peers.
+                *
+                * Note that different controllers have different meanings of
+                * |duplicate|. Some of them consider packets with the same
+                * address as duplicate, and others consider packets with the
+                * same address and the same RSSI as duplicate. Although in the
+                * latter case we don't need to disable duplicate filter, but
+                * it is common to have active scanning for a short period of
+                * time, the power impact should be neglectable.
+                */
+               filter_dup = LE_SCAN_FILTER_DUP_DISABLE;
+       }
+
+       err = hci_start_scan_sync(hdev, LE_SCAN_ACTIVE, interval,
+                                 hdev->le_scan_window_discovery,
+                                 own_addr_type, filter_policy, filter_dup);
+       if (!err)
+               return err;
+
+failed:
+       /* Resume advertising if it was paused */
+       if (use_ll_privacy(hdev))
+               hci_resume_advertising_sync(hdev);
+
+       /* Resume passive scanning */
+       hci_update_passive_scan_sync(hdev);
+       return err;
+}
+
+static int hci_start_interleaved_discovery_sync(struct hci_dev *hdev)
+{
+       int err;
+
+       bt_dev_dbg(hdev, "");
+
+       err = hci_active_scan_sync(hdev, hdev->le_scan_int_discovery * 2);
+       if (err)
+               return err;
+
+       return hci_inquiry_sync(hdev, DISCOV_BREDR_INQUIRY_LEN);
+}
+
+int hci_start_discovery_sync(struct hci_dev *hdev)
+{
+       unsigned long timeout;
+       int err;
+
+       bt_dev_dbg(hdev, "type %u", hdev->discovery.type);
+
+       switch (hdev->discovery.type) {
+       case DISCOV_TYPE_BREDR:
+               return hci_inquiry_sync(hdev, DISCOV_BREDR_INQUIRY_LEN);
+       case DISCOV_TYPE_INTERLEAVED:
+               /* When running simultaneous discovery, the LE scanning time
+                * should occupy the whole discovery time sine BR/EDR inquiry
+                * and LE scanning are scheduled by the controller.
+                *
+                * For interleaving discovery in comparison, BR/EDR inquiry
+                * and LE scanning are done sequentially with separate
+                * timeouts.
+                */
+               if (test_bit(HCI_QUIRK_SIMULTANEOUS_DISCOVERY,
+                            &hdev->quirks)) {
+                       timeout = msecs_to_jiffies(DISCOV_LE_TIMEOUT);
+                       /* During simultaneous discovery, we double LE scan
+                        * interval. We must leave some time for the controller
+                        * to do BR/EDR inquiry.
+                        */
+                       err = hci_start_interleaved_discovery_sync(hdev);
+                       break;
+               }
+
+               timeout = msecs_to_jiffies(hdev->discov_interleaved_timeout);
+               err = hci_active_scan_sync(hdev, hdev->le_scan_int_discovery);
+               break;
+       case DISCOV_TYPE_LE:
+               timeout = msecs_to_jiffies(DISCOV_LE_TIMEOUT);
+               err = hci_active_scan_sync(hdev, hdev->le_scan_int_discovery);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       if (err)
+               return err;
+
+       bt_dev_dbg(hdev, "timeout %u ms", jiffies_to_msecs(timeout));
+
+       /* When service discovery is used and the controller has a
+        * strict duplicate filter, it is important to remember the
+        * start and duration of the scan. This is required for
+        * restarting scanning during the discovery phase.
+        */
+       if (test_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks) &&
+           hdev->discovery.result_filtering) {
+               hdev->discovery.scan_start = jiffies;
+               hdev->discovery.scan_duration = timeout;
+       }
+
+       queue_delayed_work(hdev->req_workqueue, &hdev->le_scan_disable,
+                          timeout);
+       return 0;
+}
+
+static void hci_suspend_monitor_sync(struct hci_dev *hdev)
+{
+       switch (hci_get_adv_monitor_offload_ext(hdev)) {
+       case HCI_ADV_MONITOR_EXT_MSFT:
+               msft_suspend_sync(hdev);
+               break;
+       default:
+               return;
+       }
+}
+
+/* This function disables discovery and mark it as paused */
+static int hci_pause_discovery_sync(struct hci_dev *hdev)
+{
+       int old_state = hdev->discovery.state;
+       int err;
+
+       /* If discovery already stopped/stopping/paused there nothing to do */
+       if (old_state == DISCOVERY_STOPPED || old_state == DISCOVERY_STOPPING ||
+           hdev->discovery_paused)
+               return 0;
+
+       hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
+       err = hci_stop_discovery_sync(hdev);
+       if (err)
+               return err;
+
+       hdev->discovery_paused = true;
+       hdev->discovery_old_state = old_state;
+       hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
+
+       return 0;
+}
+
+static int hci_update_event_filter_sync(struct hci_dev *hdev)
+{
+       struct bdaddr_list_with_flags *b;
+       u8 scan = SCAN_DISABLED;
+       bool scanning = test_bit(HCI_PSCAN, &hdev->flags);
+       int err;
+
+       if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
+               return 0;
+
+       /* Always clear event filter when starting */
+       hci_clear_event_filter_sync(hdev);
+
+       list_for_each_entry(b, &hdev->accept_list, list) {
+               if (!hci_conn_test_flag(HCI_CONN_FLAG_REMOTE_WAKEUP,
+                                       b->current_flags))
+                       continue;
+
+               bt_dev_dbg(hdev, "Adding event filters for %pMR", &b->bdaddr);
+
+               err =  hci_set_event_filter_sync(hdev, HCI_FLT_CONN_SETUP,
+                                                HCI_CONN_SETUP_ALLOW_BDADDR,
+                                                &b->bdaddr,
+                                                HCI_CONN_SETUP_AUTO_ON);
+               if (err)
+                       bt_dev_dbg(hdev, "Failed to set event filter for %pMR",
+                                  &b->bdaddr);
+               else
+                       scan = SCAN_PAGE;
+       }
+
+       if (scan && !scanning)
+               hci_write_scan_enable_sync(hdev, scan);
+       else if (!scan && scanning)
+               hci_write_scan_enable_sync(hdev, scan);
+
+       return 0;
+}
+
+/* This function performs the HCI suspend procedures in the follow order:
+ *
+ * Pause discovery (active scanning/inquiry)
+ * Pause Directed Advertising/Advertising
+ * Disconnect all connections
+ * Set suspend_status to BT_SUSPEND_DISCONNECT if hdev cannot wakeup
+ * otherwise:
+ * Update event mask (only set events that are allowed to wake up the host)
+ * Update event filter (with devices marked with HCI_CONN_FLAG_REMOTE_WAKEUP)
+ * Update passive scanning (lower duty cycle)
+ * Set suspend_status to BT_SUSPEND_CONFIGURE_WAKE
+ */
+int hci_suspend_sync(struct hci_dev *hdev)
+{
+       int err;
+
+       /* If marked as suspended there nothing to do */
+       if (hdev->suspended)
+               return 0;
+
+       /* Mark device as suspended */
+       hdev->suspended = true;
+
+       /* Pause discovery if not already stopped */
+       hci_pause_discovery_sync(hdev);
+
+       /* Pause other advertisements */
+       hci_pause_advertising_sync(hdev);
+
+       /* Disable page scan if enabled */
+       if (test_bit(HCI_PSCAN, &hdev->flags))
+               hci_write_scan_enable_sync(hdev, SCAN_DISABLED);
+
+       /* Suspend monitor filters */
+       hci_suspend_monitor_sync(hdev);
+
+       /* Prevent disconnects from causing scanning to be re-enabled */
+       hdev->scanning_paused = true;
+
+       /* Soft disconnect everything (power off) */
+       err = hci_disconnect_all_sync(hdev, HCI_ERROR_REMOTE_POWER_OFF);
+       if (err) {
+               /* Set state to BT_RUNNING so resume doesn't notify */
+               hdev->suspend_state = BT_RUNNING;
+               hci_resume_sync(hdev);
+               return err;
+       }
+
+       /* Only configure accept list if disconnect succeeded and wake
+        * isn't being prevented.
+        */
+       if (!hdev->wakeup || !hdev->wakeup(hdev)) {
+               hdev->suspend_state = BT_SUSPEND_DISCONNECT;
+               return 0;
+       }
+
+       /* Unpause to take care of updating scanning params */
+       hdev->scanning_paused = false;
+
+       /* Update event mask so only the allowed event can wakeup the host */
+       hci_set_event_mask_sync(hdev);
+
+       /* Enable event filter for paired devices */
+       hci_update_event_filter_sync(hdev);
+
+       /* Update LE passive scan if enabled */
+       hci_update_passive_scan_sync(hdev);
+
+       /* Pause scan changes again. */
+       hdev->scanning_paused = true;
+
+       hdev->suspend_state = BT_SUSPEND_CONFIGURE_WAKE;
+
+       return 0;
+}
+
+/* This function resumes discovery */
+static int hci_resume_discovery_sync(struct hci_dev *hdev)
+{
+       int err;
+
+       /* If discovery not paused there nothing to do */
+       if (!hdev->discovery_paused)
+               return 0;
+
+       hdev->discovery_paused = false;
+
+       hci_discovery_set_state(hdev, DISCOVERY_STARTING);
+
+       err = hci_start_discovery_sync(hdev);
+
+       hci_discovery_set_state(hdev, err ? DISCOVERY_STOPPED :
+                               DISCOVERY_FINDING);
+
+       return err;
+}
+
+static void hci_resume_monitor_sync(struct hci_dev *hdev)
+{
+       switch (hci_get_adv_monitor_offload_ext(hdev)) {
+       case HCI_ADV_MONITOR_EXT_MSFT:
+               msft_resume_sync(hdev);
+               break;
+       default:
+               return;
+       }
+}
+
+/* This function performs the HCI suspend procedures in the follow order:
+ *
+ * Restore event mask
+ * Clear event filter
+ * Update passive scanning (normal duty cycle)
+ * Resume Directed Advertising/Advertising
+ * Resume discovery (active scanning/inquiry)
+ */
+int hci_resume_sync(struct hci_dev *hdev)
+{
+       /* If not marked as suspended there nothing to do */
+       if (!hdev->suspended)
+               return 0;
+
+       hdev->suspended = false;
+       hdev->scanning_paused = false;
+
+       /* Restore event mask */
+       hci_set_event_mask_sync(hdev);
+
+       /* Clear any event filters and restore scan state */
+       hci_clear_event_filter_sync(hdev);
+       hci_update_scan_sync(hdev);
+
+       /* Reset passive scanning to normal */
+       hci_update_passive_scan_sync(hdev);
+
+       /* Resume monitor filters */
+       hci_resume_monitor_sync(hdev);
+
+       /* Resume other advertisements */
+       hci_resume_advertising_sync(hdev);
+
+       /* Resume discovery */
+       hci_resume_discovery_sync(hdev);
+
+       return 0;
+}
index 7827639..4e3e045 100644 (file)
@@ -86,6 +86,8 @@ static void bt_host_release(struct device *dev)
 
        if (hci_dev_test_flag(hdev, HCI_UNREGISTER))
                hci_release_dev(hdev);
+       else
+               kfree(hdev);
        module_put(THIS_MODULE);
 }
 
index 160c016..4574c5c 100644 (file)
@@ -172,6 +172,21 @@ done:
        return err;
 }
 
+static void l2cap_sock_init_pid(struct sock *sk)
+{
+       struct l2cap_chan *chan = l2cap_pi(sk)->chan;
+
+       /* Only L2CAP_MODE_EXT_FLOWCTL ever need to access the PID in order to
+        * group the channels being requested.
+        */
+       if (chan->mode != L2CAP_MODE_EXT_FLOWCTL)
+               return;
+
+       spin_lock(&sk->sk_peer_lock);
+       sk->sk_peer_pid = get_pid(task_tgid(current));
+       spin_unlock(&sk->sk_peer_lock);
+}
+
 static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr,
                              int alen, int flags)
 {
@@ -243,6 +258,8 @@ static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr,
        if (chan->psm && bdaddr_type_is_le(chan->src_type) && !chan->mode)
                chan->mode = L2CAP_MODE_LE_FLOWCTL;
 
+       l2cap_sock_init_pid(sk);
+
        err = l2cap_chan_connect(chan, la.l2_psm, __le16_to_cpu(la.l2_cid),
                                 &la.l2_bdaddr, la.l2_bdaddr_type);
        if (err)
@@ -298,6 +315,8 @@ static int l2cap_sock_listen(struct socket *sock, int backlog)
                goto done;
        }
 
+       l2cap_sock_init_pid(sk);
+
        sk->sk_max_ack_backlog = backlog;
        sk->sk_ack_backlog = 0;
 
index 3e52836..f8f74d3 100644 (file)
@@ -39,6 +39,7 @@
 #include "mgmt_config.h"
 #include "msft.h"
 #include "eir.h"
+#include "aosp.h"
 
 #define MGMT_VERSION   1
 #define MGMT_REVISION  21
@@ -276,10 +277,39 @@ static const u8 mgmt_status_table[] = {
        MGMT_STATUS_CONNECT_FAILED,     /* MAC Connection Failed */
 };
 
-static u8 mgmt_status(u8 hci_status)
+static u8 mgmt_errno_status(int err)
 {
-       if (hci_status < ARRAY_SIZE(mgmt_status_table))
-               return mgmt_status_table[hci_status];
+       switch (err) {
+       case 0:
+               return MGMT_STATUS_SUCCESS;
+       case -EPERM:
+               return MGMT_STATUS_REJECTED;
+       case -EINVAL:
+               return MGMT_STATUS_INVALID_PARAMS;
+       case -EOPNOTSUPP:
+               return MGMT_STATUS_NOT_SUPPORTED;
+       case -EBUSY:
+               return MGMT_STATUS_BUSY;
+       case -ETIMEDOUT:
+               return MGMT_STATUS_AUTH_FAILED;
+       case -ENOMEM:
+               return MGMT_STATUS_NO_RESOURCES;
+       case -EISCONN:
+               return MGMT_STATUS_ALREADY_CONNECTED;
+       case -ENOTCONN:
+               return MGMT_STATUS_DISCONNECTED;
+       }
+
+       return MGMT_STATUS_FAILED;
+}
+
+static u8 mgmt_status(int err)
+{
+       if (err < 0)
+               return mgmt_errno_status(err);
+
+       if (err < ARRAY_SIZE(mgmt_status_table))
+               return mgmt_status_table[err];
 
        return MGMT_STATUS_FAILED;
 }
@@ -810,12 +840,7 @@ static u32 get_supported_settings(struct hci_dev *hdev)
                settings |= MGMT_SETTING_SECURE_CONN;
                settings |= MGMT_SETTING_PRIVACY;
                settings |= MGMT_SETTING_STATIC_ADDRESS;
-
-               /* When the experimental feature for LL Privacy support is
-                * enabled, then advertising is no longer supported.
-                */
-               if (!hci_dev_test_flag(hdev, HCI_ENABLE_LL_PRIVACY))
-                       settings |= MGMT_SETTING_ADVERTISING;
+               settings |= MGMT_SETTING_ADVERTISING;
        }
 
        if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks) ||
@@ -903,13 +928,6 @@ static struct mgmt_pending_cmd *pending_find(u16 opcode, struct hci_dev *hdev)
        return mgmt_pending_find(HCI_CHANNEL_CONTROL, opcode, hdev);
 }
 
-static struct mgmt_pending_cmd *pending_find_data(u16 opcode,
-                                                 struct hci_dev *hdev,
-                                                 const void *data)
-{
-       return mgmt_pending_find_data(HCI_CHANNEL_CONTROL, opcode, hdev, data);
-}
-
 u8 mgmt_get_adv_discov_flags(struct hci_dev *hdev)
 {
        struct mgmt_pending_cmd *cmd;
@@ -951,32 +969,41 @@ bool mgmt_get_connectable(struct hci_dev *hdev)
        return hci_dev_test_flag(hdev, HCI_CONNECTABLE);
 }
 
+static int service_cache_sync(struct hci_dev *hdev, void *data)
+{
+       hci_update_eir_sync(hdev);
+       hci_update_class_sync(hdev);
+
+       return 0;
+}
+
 static void service_cache_off(struct work_struct *work)
 {
        struct hci_dev *hdev = container_of(work, struct hci_dev,
                                            service_cache.work);
-       struct hci_request req;
 
        if (!hci_dev_test_and_clear_flag(hdev, HCI_SERVICE_CACHE))
                return;
 
-       hci_req_init(&req, hdev);
-
-       hci_dev_lock(hdev);
-
-       __hci_req_update_eir(&req);
-       __hci_req_update_class(&req);
-
-       hci_dev_unlock(hdev);
+       hci_cmd_sync_queue(hdev, service_cache_sync, NULL, NULL);
+}
 
-       hci_req_run(&req, NULL);
+static int rpa_expired_sync(struct hci_dev *hdev, void *data)
+{
+       /* The generation of a new RPA and programming it into the
+        * controller happens in the hci_req_enable_advertising()
+        * function.
+        */
+       if (ext_adv_capable(hdev))
+               return hci_start_ext_adv_sync(hdev, hdev->cur_adv_instance);
+       else
+               return hci_enable_advertising_sync(hdev);
 }
 
 static void rpa_expired(struct work_struct *work)
 {
        struct hci_dev *hdev = container_of(work, struct hci_dev,
                                            rpa_expired.work);
-       struct hci_request req;
 
        bt_dev_dbg(hdev, "");
 
@@ -985,16 +1012,7 @@ static void rpa_expired(struct work_struct *work)
        if (!hci_dev_test_flag(hdev, HCI_ADVERTISING))
                return;
 
-       /* The generation of a new RPA and programming it into the
-        * controller happens in the hci_req_enable_advertising()
-        * function.
-        */
-       hci_req_init(&req, hdev);
-       if (ext_adv_capable(hdev))
-               __hci_req_start_ext_adv(&req, hdev->cur_adv_instance);
-       else
-               __hci_req_enable_advertising(&req);
-       hci_req_run(&req, NULL);
+       hci_cmd_sync_queue(hdev, rpa_expired_sync, NULL, NULL);
 }
 
 static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev)
@@ -1131,16 +1149,6 @@ static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
                                 sizeof(settings));
 }
 
-static void clean_up_hci_complete(struct hci_dev *hdev, u8 status, u16 opcode)
-{
-       bt_dev_dbg(hdev, "status 0x%02x", status);
-
-       if (hci_conn_count(hdev) == 0) {
-               cancel_delayed_work(&hdev->power_off);
-               queue_work(hdev->req_workqueue, &hdev->power_off.work);
-       }
-}
-
 void mgmt_advertising_added(struct sock *sk, struct hci_dev *hdev, u8 instance)
 {
        struct mgmt_ev_advertising_added ev;
@@ -1168,38 +1176,77 @@ static void cancel_adv_timeout(struct hci_dev *hdev)
        }
 }
 
-static int clean_up_hci_state(struct hci_dev *hdev)
+/* This function requires the caller holds hdev->lock */
+static void restart_le_actions(struct hci_dev *hdev)
 {
-       struct hci_request req;
-       struct hci_conn *conn;
-       bool discov_stopped;
-       int err;
+       struct hci_conn_params *p;
 
-       hci_req_init(&req, hdev);
+       list_for_each_entry(p, &hdev->le_conn_params, list) {
+               /* Needed for AUTO_OFF case where might not "really"
+                * have been powered off.
+                */
+               list_del_init(&p->action);
 
-       if (test_bit(HCI_ISCAN, &hdev->flags) ||
-           test_bit(HCI_PSCAN, &hdev->flags)) {
-               u8 scan = 0x00;
-               hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
+               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;
+               }
        }
+}
+
+static int new_settings(struct hci_dev *hdev, struct sock *skip)
+{
+       __le32 ev = cpu_to_le32(get_current_settings(hdev));
+
+       return mgmt_limited_event(MGMT_EV_NEW_SETTINGS, hdev, &ev,
+                                 sizeof(ev), HCI_MGMT_SETTING_EVENTS, skip);
+}
 
-       hci_req_clear_adv_instance(hdev, NULL, NULL, 0x00, false);
+static void mgmt_set_powered_complete(struct hci_dev *hdev, void *data, int err)
+{
+       struct mgmt_pending_cmd *cmd = data;
+       struct mgmt_mode *cp = cmd->param;
 
-       if (hci_dev_test_flag(hdev, HCI_LE_ADV))
-               __hci_req_disable_advertising(&req);
+       bt_dev_dbg(hdev, "err %d", err);
+
+       if (!err) {
+               if (cp->val) {
+                       hci_dev_lock(hdev);
+                       restart_le_actions(hdev);
+                       hci_update_passive_scan(hdev);
+                       hci_dev_unlock(hdev);
+               }
 
-       discov_stopped = hci_req_stop_discovery(&req);
+               send_settings_rsp(cmd->sk, cmd->opcode, hdev);
 
-       list_for_each_entry(conn, &hdev->conn_hash.list, list) {
-               /* 0x15 == Terminated due to Power Off */
-               __hci_abort_conn(&req, conn, 0x15);
+               /* Only call new_setting for power on as power off is deferred
+                * to hdev->power_off work which does call hci_dev_do_close.
+                */
+               if (cp->val)
+                       new_settings(hdev, cmd->sk);
+       } else {
+               mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_POWERED,
+                               mgmt_status(err));
        }
 
-       err = hci_req_run(&req, clean_up_hci_complete);
-       if (!err && discov_stopped)
-               hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
+       mgmt_pending_free(cmd);
+}
 
-       return err;
+static int set_powered_sync(struct hci_dev *hdev, void *data)
+{
+       struct mgmt_pending_cmd *cmd = data;
+       struct mgmt_mode *cp = cmd->param;
+
+       BT_DBG("%s", hdev->name);
+
+       return hci_set_powered_sync(hdev, cp->val);
 }
 
 static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
@@ -1228,43 +1275,20 @@ static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
                goto failed;
        }
 
-       cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
+       cmd = mgmt_pending_new(sk, MGMT_OP_SET_POWERED, hdev, data, len);
        if (!cmd) {
                err = -ENOMEM;
                goto failed;
        }
 
-       if (cp->val) {
-               queue_work(hdev->req_workqueue, &hdev->power_on);
-               err = 0;
-       } else {
-               /* Disconnect connections, stop scans, etc */
-               err = clean_up_hci_state(hdev);
-               if (!err)
-                       queue_delayed_work(hdev->req_workqueue, &hdev->power_off,
-                                          HCI_POWER_OFF_TIMEOUT);
-
-               /* ENODATA means there were no HCI commands queued */
-               if (err == -ENODATA) {
-                       cancel_delayed_work(&hdev->power_off);
-                       queue_work(hdev->req_workqueue, &hdev->power_off.work);
-                       err = 0;
-               }
-       }
+       err = hci_cmd_sync_queue(hdev, set_powered_sync, cmd,
+                                mgmt_set_powered_complete);
 
 failed:
        hci_dev_unlock(hdev);
        return err;
 }
 
-static int new_settings(struct hci_dev *hdev, struct sock *skip)
-{
-       __le32 ev = cpu_to_le32(get_current_settings(hdev));
-
-       return mgmt_limited_event(MGMT_EV_NEW_SETTINGS, hdev, &ev,
-                                 sizeof(ev), HCI_MGMT_SETTING_EVENTS, skip);
-}
-
 int mgmt_new_settings(struct hci_dev *hdev)
 {
        return new_settings(hdev, NULL);
@@ -1346,23 +1370,20 @@ static u8 mgmt_le_support(struct hci_dev *hdev)
                return MGMT_STATUS_SUCCESS;
 }
 
-void mgmt_set_discoverable_complete(struct hci_dev *hdev, u8 status)
+static void mgmt_set_discoverable_complete(struct hci_dev *hdev, void *data,
+                                          int err)
 {
-       struct mgmt_pending_cmd *cmd;
+       struct mgmt_pending_cmd *cmd = data;
 
-       bt_dev_dbg(hdev, "status 0x%02x", status);
+       bt_dev_dbg(hdev, "err %d", err);
 
        hci_dev_lock(hdev);
 
-       cmd = pending_find(MGMT_OP_SET_DISCOVERABLE, hdev);
-       if (!cmd)
-               goto unlock;
-
-       if (status) {
-               u8 mgmt_err = mgmt_status(status);
+       if (err) {
+               u8 mgmt_err = mgmt_status(err);
                mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
                hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
-               goto remove_cmd;
+               goto done;
        }
 
        if (hci_dev_test_flag(hdev, HCI_DISCOVERABLE) &&
@@ -1374,13 +1395,18 @@ void mgmt_set_discoverable_complete(struct hci_dev *hdev, u8 status)
        send_settings_rsp(cmd->sk, MGMT_OP_SET_DISCOVERABLE, hdev);
        new_settings(hdev, cmd->sk);
 
-remove_cmd:
-       mgmt_pending_remove(cmd);
-
-unlock:
+done:
+       mgmt_pending_free(cmd);
        hci_dev_unlock(hdev);
 }
 
+static int set_discoverable_sync(struct hci_dev *hdev, void *data)
+{
+       BT_DBG("%s", hdev->name);
+
+       return hci_update_discoverable_sync(hdev);
+}
+
 static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
                            u16 len)
 {
@@ -1479,7 +1505,7 @@ static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
                goto failed;
        }
 
-       cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
+       cmd = mgmt_pending_new(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
        if (!cmd) {
                err = -ENOMEM;
                goto failed;
@@ -1503,39 +1529,34 @@ static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
        else
                hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
 
-       queue_work(hdev->req_workqueue, &hdev->discoverable_update);
-       err = 0;
+       err = hci_cmd_sync_queue(hdev, set_discoverable_sync, cmd,
+                                mgmt_set_discoverable_complete);
 
 failed:
        hci_dev_unlock(hdev);
        return err;
 }
 
-void mgmt_set_connectable_complete(struct hci_dev *hdev, u8 status)
+static void mgmt_set_connectable_complete(struct hci_dev *hdev, void *data,
+                                         int err)
 {
-       struct mgmt_pending_cmd *cmd;
+       struct mgmt_pending_cmd *cmd = data;
 
-       bt_dev_dbg(hdev, "status 0x%02x", status);
+       bt_dev_dbg(hdev, "err %d", err);
 
        hci_dev_lock(hdev);
 
-       cmd = pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
-       if (!cmd)
-               goto unlock;
-
-       if (status) {
-               u8 mgmt_err = mgmt_status(status);
+       if (err) {
+               u8 mgmt_err = mgmt_status(err);
                mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
-               goto remove_cmd;
+               goto done;
        }
 
        send_settings_rsp(cmd->sk, MGMT_OP_SET_CONNECTABLE, hdev);
        new_settings(hdev, cmd->sk);
 
-remove_cmd:
-       mgmt_pending_remove(cmd);
-
-unlock:
+done:
+       mgmt_pending_free(cmd);
        hci_dev_unlock(hdev);
 }
 
@@ -1561,13 +1582,20 @@ static int set_connectable_update_settings(struct hci_dev *hdev,
 
        if (changed) {
                hci_req_update_scan(hdev);
-               hci_update_background_scan(hdev);
+               hci_update_passive_scan(hdev);
                return new_settings(hdev, sk);
        }
 
        return 0;
 }
 
+static int set_connectable_sync(struct hci_dev *hdev, void *data)
+{
+       BT_DBG("%s", hdev->name);
+
+       return hci_update_connectable_sync(hdev);
+}
+
 static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
                           u16 len)
 {
@@ -1600,7 +1628,7 @@ static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
                goto failed;
        }
 
-       cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
+       cmd = mgmt_pending_new(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
        if (!cmd) {
                err = -ENOMEM;
                goto failed;
@@ -1617,8 +1645,8 @@ static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
                hci_dev_clear_flag(hdev, HCI_CONNECTABLE);
        }
 
-       queue_work(hdev->req_workqueue, &hdev->connectable_update);
-       err = 0;
+       err = hci_cmd_sync_queue(hdev, set_connectable_sync, cmd,
+                                mgmt_set_connectable_complete);
 
 failed:
        hci_dev_unlock(hdev);
@@ -1653,12 +1681,7 @@ static int set_bondable(struct sock *sk, struct hci_dev *hdev, void *data,
                /* In limited privacy mode the change of bondable mode
                 * may affect the local advertising address.
                 */
-               if (hdev_is_powered(hdev) &&
-                   hci_dev_test_flag(hdev, HCI_ADVERTISING) &&
-                   hci_dev_test_flag(hdev, HCI_DISCOVERABLE) &&
-                   hci_dev_test_flag(hdev, HCI_LIMITED_PRIVACY))
-                       queue_work(hdev->req_workqueue,
-                                  &hdev->discoverable_update);
+               hci_update_discoverable(hdev);
 
                err = new_settings(hdev, sk);
        }
@@ -1737,6 +1760,69 @@ failed:
        return err;
 }
 
+static void set_ssp_complete(struct hci_dev *hdev, void *data, int err)
+{
+       struct cmd_lookup match = { NULL, hdev };
+       struct mgmt_pending_cmd *cmd = data;
+       struct mgmt_mode *cp = cmd->param;
+       u8 enable = cp->val;
+       bool changed;
+
+       if (err) {
+               u8 mgmt_err = mgmt_status(err);
+
+               if (enable && hci_dev_test_and_clear_flag(hdev,
+                                                         HCI_SSP_ENABLED)) {
+                       hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
+                       new_settings(hdev, NULL);
+               }
+
+               mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
+                                    &mgmt_err);
+               return;
+       }
+
+       if (enable) {
+               changed = !hci_dev_test_and_set_flag(hdev, HCI_SSP_ENABLED);
+       } else {
+               changed = hci_dev_test_and_clear_flag(hdev, HCI_SSP_ENABLED);
+
+               if (!changed)
+                       changed = hci_dev_test_and_clear_flag(hdev,
+                                                             HCI_HS_ENABLED);
+               else
+                       hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
+       }
+
+       mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
+
+       if (changed)
+               new_settings(hdev, match.sk);
+
+       if (match.sk)
+               sock_put(match.sk);
+
+       hci_update_eir_sync(hdev);
+}
+
+static int set_ssp_sync(struct hci_dev *hdev, void *data)
+{
+       struct mgmt_pending_cmd *cmd = data;
+       struct mgmt_mode *cp = cmd->param;
+       bool changed = false;
+       int err;
+
+       if (cp->val)
+               changed = !hci_dev_test_and_set_flag(hdev, HCI_SSP_ENABLED);
+
+       err = hci_write_ssp_mode_sync(hdev, cp->val);
+
+       if (!err && changed)
+               hci_dev_clear_flag(hdev, HCI_SSP_ENABLED);
+
+       return err;
+}
+
 static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
 {
        struct mgmt_mode *cp = data;
@@ -1798,19 +1884,18 @@ static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
        }
 
        cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
-       if (!cmd) {
+       if (!cmd)
                err = -ENOMEM;
-               goto failed;
-       }
-
-       if (!cp->val && hci_dev_test_flag(hdev, HCI_USE_DEBUG_KEYS))
-               hci_send_cmd(hdev, HCI_OP_WRITE_SSP_DEBUG_MODE,
-                            sizeof(cp->val), &cp->val);
+       else
+               err = hci_cmd_sync_queue(hdev, set_ssp_sync, cmd,
+                                        set_ssp_complete);
 
-       err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, 1, &cp->val);
        if (err < 0) {
-               mgmt_pending_remove(cmd);
-               goto failed;
+               err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
+                                     MGMT_STATUS_FAILED);
+
+               if (cmd)
+                       mgmt_pending_remove(cmd);
        }
 
 failed:
@@ -1879,18 +1964,17 @@ unlock:
        return err;
 }
 
-static void le_enable_complete(struct hci_dev *hdev, u8 status, u16 opcode)
+static void set_le_complete(struct hci_dev *hdev, void *data, int err)
 {
        struct cmd_lookup match = { NULL, hdev };
+       u8 status = mgmt_status(err);
 
-       hci_dev_lock(hdev);
+       bt_dev_dbg(hdev, "err %d", err);
 
        if (status) {
-               u8 mgmt_err = mgmt_status(status);
-
                mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, cmd_status_rsp,
-                                    &mgmt_err);
-               goto unlock;
+                                                       &status);
+               return;
        }
 
        mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
@@ -1899,39 +1983,54 @@ static void le_enable_complete(struct hci_dev *hdev, u8 status, u16 opcode)
 
        if (match.sk)
                sock_put(match.sk);
+}
+
+static int set_le_sync(struct hci_dev *hdev, void *data)
+{
+       struct mgmt_pending_cmd *cmd = data;
+       struct mgmt_mode *cp = cmd->param;
+       u8 val = !!cp->val;
+       int err;
+
+       if (!val) {
+               if (hci_dev_test_flag(hdev, HCI_LE_ADV))
+                       hci_disable_advertising_sync(hdev);
+
+               if (ext_adv_capable(hdev))
+                       hci_remove_ext_adv_instance_sync(hdev, 0, cmd->sk);
+       } else {
+               hci_dev_set_flag(hdev, HCI_LE_ENABLED);
+       }
+
+       err = hci_write_le_host_supported_sync(hdev, val, 0);
 
        /* Make sure the controller has a good default for
         * advertising data. Restrict the update to when LE
         * has actually been enabled. During power on, the
         * update in powered_update_hci will take care of it.
         */
-       if (hci_dev_test_flag(hdev, HCI_LE_ENABLED)) {
-               struct hci_request req;
-               hci_req_init(&req, hdev);
+       if (!err && hci_dev_test_flag(hdev, HCI_LE_ENABLED)) {
                if (ext_adv_capable(hdev)) {
-                       int err;
+                       int status;
 
-                       err = __hci_req_setup_ext_adv_instance(&req, 0x00);
-                       if (!err)
-                               __hci_req_update_scan_rsp_data(&req, 0x00);
+                       status = hci_setup_ext_adv_instance_sync(hdev, 0x00);
+                       if (!status)
+                               hci_update_scan_rsp_data_sync(hdev, 0x00);
                } else {
-                       __hci_req_update_adv_data(&req, 0x00);
-                       __hci_req_update_scan_rsp_data(&req, 0x00);
+                       hci_update_adv_data_sync(hdev, 0x00);
+                       hci_update_scan_rsp_data_sync(hdev, 0x00);
                }
-               hci_req_run(&req, NULL);
-               hci_update_background_scan(hdev);
+
+               hci_update_passive_scan(hdev);
        }
 
-unlock:
-       hci_dev_unlock(hdev);
+       return err;
 }
 
 static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
 {
        struct mgmt_mode *cp = data;
-       struct hci_cp_write_le_host_supported hci_cp;
        struct mgmt_pending_cmd *cmd;
-       struct hci_request req;
        int err;
        u8 val, enabled;
 
@@ -2001,33 +2100,20 @@ static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
        }
 
        cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
-       if (!cmd) {
+       if (!cmd)
                err = -ENOMEM;
-               goto unlock;
-       }
-
-       hci_req_init(&req, hdev);
-
-       memset(&hci_cp, 0, sizeof(hci_cp));
+       else
+               err = hci_cmd_sync_queue(hdev, set_le_sync, cmd,
+                                        set_le_complete);
 
-       if (val) {
-               hci_cp.le = val;
-               hci_cp.simul = 0x00;
-       } else {
-               if (hci_dev_test_flag(hdev, HCI_LE_ADV))
-                       __hci_req_disable_advertising(&req);
+       if (err < 0) {
+               err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
+                                     MGMT_STATUS_FAILED);
 
-               if (ext_adv_capable(hdev))
-                       __hci_req_clear_ext_adv_sets(&req);
+               if (cmd)
+                       mgmt_pending_remove(cmd);
        }
 
-       hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp),
-                   &hci_cp);
-
-       err = hci_req_run(&req, le_enable_complete);
-       if (err < 0)
-               mgmt_pending_remove(cmd);
-
 unlock:
        hci_dev_unlock(hdev);
        return err;
@@ -2075,37 +2161,33 @@ static u8 get_uuid_size(const u8 *uuid)
        return 16;
 }
 
-static void mgmt_class_complete(struct hci_dev *hdev, u16 mgmt_op, u8 status)
+static void mgmt_class_complete(struct hci_dev *hdev, void *data, int err)
 {
-       struct mgmt_pending_cmd *cmd;
+       struct mgmt_pending_cmd *cmd = data;
 
-       hci_dev_lock(hdev);
-
-       cmd = pending_find(mgmt_op, hdev);
-       if (!cmd)
-               goto unlock;
+       bt_dev_dbg(hdev, "err %d", err);
 
        mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
-                         mgmt_status(status), hdev->dev_class, 3);
-
-       mgmt_pending_remove(cmd);
+                         mgmt_status(err), hdev->dev_class, 3);
 
-unlock:
-       hci_dev_unlock(hdev);
+       mgmt_pending_free(cmd);
 }
 
-static void add_uuid_complete(struct hci_dev *hdev, u8 status, u16 opcode)
+static int add_uuid_sync(struct hci_dev *hdev, void *data)
 {
-       bt_dev_dbg(hdev, "status 0x%02x", status);
+       int err;
+
+       err = hci_update_class_sync(hdev);
+       if (err)
+               return err;
 
-       mgmt_class_complete(hdev, MGMT_OP_ADD_UUID, status);
+       return hci_update_eir_sync(hdev);
 }
 
 static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
 {
        struct mgmt_cp_add_uuid *cp = data;
        struct mgmt_pending_cmd *cmd;
-       struct hci_request req;
        struct bt_uuid *uuid;
        int err;
 
@@ -2131,28 +2213,17 @@ static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
 
        list_add_tail(&uuid->list, &hdev->uuids);
 
-       hci_req_init(&req, hdev);
-
-       __hci_req_update_class(&req);
-       __hci_req_update_eir(&req);
-
-       err = hci_req_run(&req, add_uuid_complete);
-       if (err < 0) {
-               if (err != -ENODATA)
-                       goto failed;
-
-               err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0,
-                                       hdev->dev_class, 3);
-               goto failed;
-       }
-
-       cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
+       cmd = mgmt_pending_new(sk, MGMT_OP_ADD_UUID, hdev, data, len);
        if (!cmd) {
                err = -ENOMEM;
                goto failed;
        }
 
-       err = 0;
+       err = hci_cmd_sync_queue(hdev, add_uuid_sync, cmd, mgmt_class_complete);
+       if (err < 0) {
+               mgmt_pending_free(cmd);
+               goto failed;
+       }
 
 failed:
        hci_dev_unlock(hdev);
@@ -2173,11 +2244,15 @@ static bool enable_service_cache(struct hci_dev *hdev)
        return false;
 }
 
-static void remove_uuid_complete(struct hci_dev *hdev, u8 status, u16 opcode)
+static int remove_uuid_sync(struct hci_dev *hdev, void *data)
 {
-       bt_dev_dbg(hdev, "status 0x%02x", status);
+       int err;
 
-       mgmt_class_complete(hdev, MGMT_OP_REMOVE_UUID, status);
+       err = hci_update_class_sync(hdev);
+       if (err)
+               return err;
+
+       return hci_update_eir_sync(hdev);
 }
 
 static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
@@ -2187,7 +2262,6 @@ static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
        struct mgmt_pending_cmd *cmd;
        struct bt_uuid *match, *tmp;
        u8 bt_uuid_any[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
-       struct hci_request req;
        int err, found;
 
        bt_dev_dbg(hdev, "sock %p", sk);
@@ -2231,39 +2305,35 @@ static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
        }
 
 update_class:
-       hci_req_init(&req, hdev);
-
-       __hci_req_update_class(&req);
-       __hci_req_update_eir(&req);
-
-       err = hci_req_run(&req, remove_uuid_complete);
-       if (err < 0) {
-               if (err != -ENODATA)
-                       goto unlock;
-
-               err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0,
-                                       hdev->dev_class, 3);
-               goto unlock;
-       }
-
-       cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
+       cmd = mgmt_pending_new(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
        if (!cmd) {
                err = -ENOMEM;
                goto unlock;
        }
 
-       err = 0;
+       err = hci_cmd_sync_queue(hdev, remove_uuid_sync, cmd,
+                                mgmt_class_complete);
+       if (err < 0)
+               mgmt_pending_free(cmd);
 
 unlock:
        hci_dev_unlock(hdev);
        return err;
 }
 
-static void set_class_complete(struct hci_dev *hdev, u8 status, u16 opcode)
+static int set_class_sync(struct hci_dev *hdev, void *data)
 {
-       bt_dev_dbg(hdev, "status 0x%02x", status);
+       int err = 0;
+
+       if (hci_dev_test_and_clear_flag(hdev, HCI_SERVICE_CACHE)) {
+               cancel_delayed_work_sync(&hdev->service_cache);
+               err = hci_update_eir_sync(hdev);
+       }
+
+       if (err)
+               return err;
 
-       mgmt_class_complete(hdev, MGMT_OP_SET_DEV_CLASS, status);
+       return hci_update_class_sync(hdev);
 }
 
 static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
@@ -2271,7 +2341,6 @@ static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
 {
        struct mgmt_cp_set_dev_class *cp = data;
        struct mgmt_pending_cmd *cmd;
-       struct hci_request req;
        int err;
 
        bt_dev_dbg(hdev, "sock %p", sk);
@@ -2303,34 +2372,16 @@ static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
                goto unlock;
        }
 
-       hci_req_init(&req, hdev);
-
-       if (hci_dev_test_and_clear_flag(hdev, HCI_SERVICE_CACHE)) {
-               hci_dev_unlock(hdev);
-               cancel_delayed_work_sync(&hdev->service_cache);
-               hci_dev_lock(hdev);
-               __hci_req_update_eir(&req);
-       }
-
-       __hci_req_update_class(&req);
-
-       err = hci_req_run(&req, set_class_complete);
-       if (err < 0) {
-               if (err != -ENODATA)
-                       goto unlock;
-
-               err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
-                                       hdev->dev_class, 3);
-               goto unlock;
-       }
-
-       cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
+       cmd = mgmt_pending_new(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
        if (!cmd) {
                err = -ENOMEM;
                goto unlock;
        }
 
-       err = 0;
+       err = hci_cmd_sync_queue(hdev, set_class_sync, cmd,
+                                mgmt_class_complete);
+       if (err < 0)
+               mgmt_pending_free(cmd);
 
 unlock:
        hci_dev_unlock(hdev);
@@ -3228,65 +3279,70 @@ static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
                                 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
 }
 
-static void adv_expire(struct hci_dev *hdev, u32 flags)
+static int adv_expire_sync(struct hci_dev *hdev, u32 flags)
 {
        struct adv_info *adv_instance;
-       struct hci_request req;
-       int err;
 
        adv_instance = hci_find_adv_instance(hdev, hdev->cur_adv_instance);
        if (!adv_instance)
-               return;
+               return 0;
 
        /* stop if current instance doesn't need to be changed */
        if (!(adv_instance->flags & flags))
-               return;
+               return 0;
 
        cancel_adv_timeout(hdev);
 
        adv_instance = hci_get_next_instance(hdev, adv_instance->instance);
        if (!adv_instance)
-               return;
+               return 0;
 
-       hci_req_init(&req, hdev);
-       err = __hci_req_schedule_adv_instance(&req, adv_instance->instance,
-                                             true);
-       if (err)
-               return;
+       hci_schedule_adv_instance_sync(hdev, adv_instance->instance, true);
 
-       hci_req_run(&req, NULL);
+       return 0;
 }
 
-static void set_name_complete(struct hci_dev *hdev, u8 status, u16 opcode)
+static int name_changed_sync(struct hci_dev *hdev, void *data)
 {
-       struct mgmt_cp_set_local_name *cp;
-       struct mgmt_pending_cmd *cmd;
-
-       bt_dev_dbg(hdev, "status 0x%02x", status);
-
-       hci_dev_lock(hdev);
+       return adv_expire_sync(hdev, MGMT_ADV_FLAG_LOCAL_NAME);
+}
 
-       cmd = pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
-       if (!cmd)
-               goto unlock;
+static void set_name_complete(struct hci_dev *hdev, void *data, int err)
+{
+       struct mgmt_pending_cmd *cmd = data;
+       struct mgmt_cp_set_local_name *cp = cmd->param;
+       u8 status = mgmt_status(err);
 
-       cp = cmd->param;
+       bt_dev_dbg(hdev, "err %d", err);
 
        if (status) {
                mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
-                               mgmt_status(status));
+                               status);
        } else {
                mgmt_cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
                                  cp, sizeof(*cp));
 
                if (hci_dev_test_flag(hdev, HCI_LE_ADV))
-                       adv_expire(hdev, MGMT_ADV_FLAG_LOCAL_NAME);
+                       hci_cmd_sync_queue(hdev, name_changed_sync, NULL, NULL);
        }
 
        mgmt_pending_remove(cmd);
+}
 
-unlock:
-       hci_dev_unlock(hdev);
+static int set_name_sync(struct hci_dev *hdev, void *data)
+{
+       if (lmp_bredr_capable(hdev)) {
+               hci_update_name_sync(hdev);
+               hci_update_eir_sync(hdev);
+       }
+
+       /* The name is stored in the scan response data and so
+        * no need to update the advertising data here.
+        */
+       if (lmp_le_capable(hdev) && hci_dev_test_flag(hdev, HCI_ADVERTISING))
+               hci_update_scan_rsp_data_sync(hdev, hdev->cur_adv_instance);
+
+       return 0;
 }
 
 static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
@@ -3294,7 +3350,6 @@ static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
 {
        struct mgmt_cp_set_local_name *cp = data;
        struct mgmt_pending_cmd *cmd;
-       struct hci_request req;
        int err;
 
        bt_dev_dbg(hdev, "sock %p", sk);
@@ -3330,35 +3385,34 @@ static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
        }
 
        cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
-       if (!cmd) {
+       if (!cmd)
                err = -ENOMEM;
-               goto failed;
-       }
+       else
+               err = hci_cmd_sync_queue(hdev, set_name_sync, cmd,
+                                        set_name_complete);
 
-       memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
+       if (err < 0) {
+               err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
+                                     MGMT_STATUS_FAILED);
 
-       hci_req_init(&req, hdev);
+               if (cmd)
+                       mgmt_pending_remove(cmd);
 
-       if (lmp_bredr_capable(hdev)) {
-               __hci_req_update_name(&req);
-               __hci_req_update_eir(&req);
+               goto failed;
        }
 
-       /* The name is stored in the scan response data and so
-        * no need to update the advertising data here.
-        */
-       if (lmp_le_capable(hdev) && hci_dev_test_flag(hdev, HCI_ADVERTISING))
-               __hci_req_update_scan_rsp_data(&req, hdev->cur_adv_instance);
-
-       err = hci_req_run(&req, set_name_complete);
-       if (err < 0)
-               mgmt_pending_remove(cmd);
+       memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
 
 failed:
        hci_dev_unlock(hdev);
        return err;
 }
 
+static int appearance_changed_sync(struct hci_dev *hdev, void *data)
+{
+       return adv_expire_sync(hdev, MGMT_ADV_FLAG_APPEARANCE);
+}
+
 static int set_appearance(struct sock *sk, struct hci_dev *hdev, void *data,
                          u16 len)
 {
@@ -3380,7 +3434,8 @@ static int set_appearance(struct sock *sk, struct hci_dev *hdev, void *data,
                hdev->appearance = appearance;
 
                if (hci_dev_test_flag(hdev, HCI_LE_ADV))
-                       adv_expire(hdev, MGMT_ADV_FLAG_APPEARANCE);
+                       hci_cmd_sync_queue(hdev, appearance_changed_sync, NULL,
+                                          NULL);
 
                ext_info_changed(hdev, sk);
        }
@@ -3426,23 +3481,26 @@ int mgmt_phy_configuration_changed(struct hci_dev *hdev, struct sock *skip)
                          sizeof(ev), skip);
 }
 
-static void set_default_phy_complete(struct hci_dev *hdev, u8 status,
-                                    u16 opcode, struct sk_buff *skb)
+static void set_default_phy_complete(struct hci_dev *hdev, void *data, int err)
 {
-       struct mgmt_pending_cmd *cmd;
+       struct mgmt_pending_cmd *cmd = data;
+       struct sk_buff *skb = cmd->skb;
+       u8 status = mgmt_status(err);
 
-       bt_dev_dbg(hdev, "status 0x%02x", status);
-
-       hci_dev_lock(hdev);
+       if (!status) {
+               if (!skb)
+                       status = MGMT_STATUS_FAILED;
+               else if (IS_ERR(skb))
+                       status = mgmt_status(PTR_ERR(skb));
+               else
+                       status = mgmt_status(skb->data[0]);
+       }
 
-       cmd = pending_find(MGMT_OP_SET_PHY_CONFIGURATION, hdev);
-       if (!cmd)
-               goto unlock;
+       bt_dev_dbg(hdev, "status %d", status);
 
        if (status) {
                mgmt_cmd_status(cmd->sk, hdev->id,
-                               MGMT_OP_SET_PHY_CONFIGURATION,
-                               mgmt_status(status));
+                               MGMT_OP_SET_PHY_CONFIGURATION, status);
        } else {
                mgmt_cmd_complete(cmd->sk, hdev->id,
                                  MGMT_OP_SET_PHY_CONFIGURATION, 0,
@@ -3451,19 +3509,56 @@ static void set_default_phy_complete(struct hci_dev *hdev, u8 status,
                mgmt_phy_configuration_changed(hdev, cmd->sk);
        }
 
+       if (skb && !IS_ERR(skb))
+               kfree_skb(skb);
+
        mgmt_pending_remove(cmd);
+}
 
-unlock:
-       hci_dev_unlock(hdev);
+static int set_default_phy_sync(struct hci_dev *hdev, void *data)
+{
+       struct mgmt_pending_cmd *cmd = data;
+       struct mgmt_cp_set_phy_configuration *cp = cmd->param;
+       struct hci_cp_le_set_default_phy cp_phy;
+       u32 selected_phys = __le32_to_cpu(cp->selected_phys);
+
+       memset(&cp_phy, 0, sizeof(cp_phy));
+
+       if (!(selected_phys & MGMT_PHY_LE_TX_MASK))
+               cp_phy.all_phys |= 0x01;
+
+       if (!(selected_phys & MGMT_PHY_LE_RX_MASK))
+               cp_phy.all_phys |= 0x02;
+
+       if (selected_phys & MGMT_PHY_LE_1M_TX)
+               cp_phy.tx_phys |= HCI_LE_SET_PHY_1M;
+
+       if (selected_phys & MGMT_PHY_LE_2M_TX)
+               cp_phy.tx_phys |= HCI_LE_SET_PHY_2M;
+
+       if (selected_phys & MGMT_PHY_LE_CODED_TX)
+               cp_phy.tx_phys |= HCI_LE_SET_PHY_CODED;
+
+       if (selected_phys & MGMT_PHY_LE_1M_RX)
+               cp_phy.rx_phys |= HCI_LE_SET_PHY_1M;
+
+       if (selected_phys & MGMT_PHY_LE_2M_RX)
+               cp_phy.rx_phys |= HCI_LE_SET_PHY_2M;
+
+       if (selected_phys & MGMT_PHY_LE_CODED_RX)
+               cp_phy.rx_phys |= HCI_LE_SET_PHY_CODED;
+
+       cmd->skb =  __hci_cmd_sync(hdev, HCI_OP_LE_SET_DEFAULT_PHY,
+                                  sizeof(cp_phy), &cp_phy, HCI_CMD_TIMEOUT);
+
+       return 0;
 }
 
 static int set_phy_configuration(struct sock *sk, struct hci_dev *hdev,
                                 void *data, u16 len)
 {
        struct mgmt_cp_set_phy_configuration *cp = data;
-       struct hci_cp_le_set_default_phy cp_phy;
        struct mgmt_pending_cmd *cmd;
-       struct hci_request req;
        u32 selected_phys, configurable_phys, supported_phys, unconfigure_phys;
        u16 pkt_type = (HCI_DH1 | HCI_DM1);
        bool changed = false;
@@ -3567,44 +3662,20 @@ static int set_phy_configuration(struct sock *sk, struct hci_dev *hdev,
 
        cmd = mgmt_pending_add(sk, MGMT_OP_SET_PHY_CONFIGURATION, hdev, data,
                               len);
-       if (!cmd) {
+       if (!cmd)
                err = -ENOMEM;
-               goto unlock;
-       }
-
-       hci_req_init(&req, hdev);
-
-       memset(&cp_phy, 0, sizeof(cp_phy));
-
-       if (!(selected_phys & MGMT_PHY_LE_TX_MASK))
-               cp_phy.all_phys |= 0x01;
-
-       if (!(selected_phys & MGMT_PHY_LE_RX_MASK))
-               cp_phy.all_phys |= 0x02;
-
-       if (selected_phys & MGMT_PHY_LE_1M_TX)
-               cp_phy.tx_phys |= HCI_LE_SET_PHY_1M;
-
-       if (selected_phys & MGMT_PHY_LE_2M_TX)
-               cp_phy.tx_phys |= HCI_LE_SET_PHY_2M;
-
-       if (selected_phys & MGMT_PHY_LE_CODED_TX)
-               cp_phy.tx_phys |= HCI_LE_SET_PHY_CODED;
-
-       if (selected_phys & MGMT_PHY_LE_1M_RX)
-               cp_phy.rx_phys |= HCI_LE_SET_PHY_1M;
-
-       if (selected_phys & MGMT_PHY_LE_2M_RX)
-               cp_phy.rx_phys |= HCI_LE_SET_PHY_2M;
-
-       if (selected_phys & MGMT_PHY_LE_CODED_RX)
-               cp_phy.rx_phys |= HCI_LE_SET_PHY_CODED;
+       else
+               err = hci_cmd_sync_queue(hdev, set_default_phy_sync, cmd,
+                                        set_default_phy_complete);
 
-       hci_req_add(&req, HCI_OP_LE_SET_DEFAULT_PHY, sizeof(cp_phy), &cp_phy);
+       if (err < 0) {
+               err = mgmt_cmd_status(sk, hdev->id,
+                                     MGMT_OP_SET_PHY_CONFIGURATION,
+                                     MGMT_STATUS_FAILED);
 
-       err = hci_req_run_skb(&req, set_default_phy_complete);
-       if (err < 0)
-               mgmt_pending_remove(cmd);
+               if (cmd)
+                       mgmt_pending_remove(cmd);
+       }
 
 unlock:
        hci_dev_unlock(hdev);
@@ -3852,7 +3923,7 @@ static int read_exp_features_info(struct sock *sk, struct hci_dev *hdev,
                idx++;
        }
 
-       if (hdev && use_ll_privacy(hdev)) {
+       if (hdev && ll_privacy_capable(hdev)) {
                if (hci_dev_test_flag(hdev, HCI_ENABLE_LL_PRIVACY))
                        flags = BIT(0) | BIT(1);
                else
@@ -3863,7 +3934,8 @@ static int read_exp_features_info(struct sock *sk, struct hci_dev *hdev,
                idx++;
        }
 
-       if (hdev && hdev->set_quality_report) {
+       if (hdev && (aosp_has_quality_report(hdev) ||
+                    hdev->set_quality_report)) {
                if (hci_dev_test_flag(hdev, HCI_QUALITY_REPORT))
                        flags = BIT(0);
                else
@@ -3927,7 +3999,9 @@ static int exp_debug_feature_changed(bool enabled, struct sock *skip)
 }
 #endif
 
-static int exp_quality_report_feature_changed(bool enabled, struct sock *skip)
+static int exp_quality_report_feature_changed(bool enabled,
+                                             struct hci_dev *hdev,
+                                             struct sock *skip)
 {
        struct mgmt_ev_exp_feature_changed ev;
 
@@ -3935,7 +4009,7 @@ static int exp_quality_report_feature_changed(bool enabled, struct sock *skip)
        memcpy(ev.uuid, quality_report_uuid, 16);
        ev.flags = cpu_to_le32(enabled ? BIT(0) : 0);
 
-       return mgmt_limited_event(MGMT_EV_EXP_FEATURE_CHANGED, NULL,
+       return mgmt_limited_event(MGMT_EV_EXP_FEATURE_CHANGED, hdev,
                                  &ev, sizeof(ev),
                                  HCI_MGMT_EXP_FEATURE_EVENTS, skip);
 }
@@ -4125,7 +4199,7 @@ static int set_quality_report_func(struct sock *sk, struct hci_dev *hdev,
        val = !!cp->param[0];
        changed = (val != hci_dev_test_flag(hdev, HCI_QUALITY_REPORT));
 
-       if (!hdev->set_quality_report) {
+       if (!aosp_has_quality_report(hdev) && !hdev->set_quality_report) {
                err = mgmt_cmd_status(sk, hdev->id,
                                      MGMT_OP_SET_EXP_FEATURE,
                                      MGMT_STATUS_NOT_SUPPORTED);
@@ -4133,13 +4207,18 @@ static int set_quality_report_func(struct sock *sk, struct hci_dev *hdev,
        }
 
        if (changed) {
-               err = hdev->set_quality_report(hdev, val);
+               if (hdev->set_quality_report)
+                       err = hdev->set_quality_report(hdev, val);
+               else
+                       err = aosp_set_quality_report(hdev, val);
+
                if (err) {
                        err = mgmt_cmd_status(sk, hdev->id,
                                              MGMT_OP_SET_EXP_FEATURE,
                                              MGMT_STATUS_FAILED);
                        goto unlock_quality_report;
                }
+
                if (val)
                        hci_dev_set_flag(hdev, HCI_QUALITY_REPORT);
                else
@@ -4151,19 +4230,20 @@ static int set_quality_report_func(struct sock *sk, struct hci_dev *hdev,
        memcpy(rp.uuid, quality_report_uuid, 16);
        rp.flags = cpu_to_le32(val ? BIT(0) : 0);
        hci_sock_set_flag(sk, HCI_MGMT_EXP_FEATURE_EVENTS);
-       err = mgmt_cmd_complete(sk, hdev->id,
-                               MGMT_OP_SET_EXP_FEATURE, 0,
+
+       err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_EXP_FEATURE, 0,
                                &rp, sizeof(rp));
 
        if (changed)
-               exp_quality_report_feature_changed(val, sk);
+               exp_quality_report_feature_changed(val, hdev, sk);
 
 unlock_quality_report:
        hci_req_sync_unlock(hdev);
        return err;
 }
 
-static int exp_offload_codec_feature_changed(bool enabled, struct sock *skip)
+static int exp_offload_codec_feature_changed(bool enabled, struct hci_dev *hdev,
+                                            struct sock *skip)
 {
        struct mgmt_ev_exp_feature_changed ev;
 
@@ -4171,7 +4251,7 @@ static int exp_offload_codec_feature_changed(bool enabled, struct sock *skip)
        memcpy(ev.uuid, offload_codecs_uuid, 16);
        ev.flags = cpu_to_le32(enabled ? BIT(0) : 0);
 
-       return mgmt_limited_event(MGMT_EV_EXP_FEATURE_CHANGED, NULL,
+       return mgmt_limited_event(MGMT_EV_EXP_FEATURE_CHANGED, hdev,
                                  &ev, sizeof(ev),
                                  HCI_MGMT_EXP_FEATURE_EVENTS, skip);
 }
@@ -4229,7 +4309,7 @@ static int set_offload_codec_func(struct sock *sk, struct hci_dev *hdev,
                                &rp, sizeof(rp));
 
        if (changed)
-               exp_offload_codec_feature_changed(val, sk);
+               exp_offload_codec_feature_changed(val, hdev, sk);
 
        return err;
 }
@@ -4496,7 +4576,7 @@ int mgmt_add_adv_patterns_monitor_complete(struct hci_dev *hdev, u8 status)
                hdev->adv_monitors_cnt++;
                if (monitor->state == ADV_MONITOR_STATE_NOT_REGISTERED)
                        monitor->state = ADV_MONITOR_STATE_REGISTERED;
-               hci_update_background_scan(hdev);
+               hci_update_passive_scan(hdev);
        }
 
        err = mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
@@ -4722,7 +4802,7 @@ int mgmt_remove_adv_monitor_complete(struct hci_dev *hdev, u8 status)
        rp.monitor_handle = cp->monitor_handle;
 
        if (!status)
-               hci_update_background_scan(hdev);
+               hci_update_passive_scan(hdev);
 
        err = mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
                                mgmt_status(status), &rp, sizeof(rp));
@@ -4801,28 +4881,33 @@ unlock:
                               status);
 }
 
-static void read_local_oob_data_complete(struct hci_dev *hdev, u8 status,
-                                        u16 opcode, struct sk_buff *skb)
+static void read_local_oob_data_complete(struct hci_dev *hdev, void *data, int err)
 {
        struct mgmt_rp_read_local_oob_data mgmt_rp;
        size_t rp_size = sizeof(mgmt_rp);
-       struct mgmt_pending_cmd *cmd;
+       struct mgmt_pending_cmd *cmd = data;
+       struct sk_buff *skb = cmd->skb;
+       u8 status = mgmt_status(err);
 
-       bt_dev_dbg(hdev, "status %u", status);
+       if (!status) {
+               if (!skb)
+                       status = MGMT_STATUS_FAILED;
+               else if (IS_ERR(skb))
+                       status = mgmt_status(PTR_ERR(skb));
+               else
+                       status = mgmt_status(skb->data[0]);
+       }
 
-       cmd = pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
-       if (!cmd)
-               return;
+       bt_dev_dbg(hdev, "status %d", status);
 
-       if (status || !skb) {
-               mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
-                               status ? mgmt_status(status) : MGMT_STATUS_FAILED);
+       if (status) {
+               mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA, status);
                goto remove;
        }
 
        memset(&mgmt_rp, 0, sizeof(mgmt_rp));
 
-       if (opcode == HCI_OP_READ_LOCAL_OOB_DATA) {
+       if (!bredr_sc_enabled(hdev)) {
                struct hci_rp_read_local_oob_data *rp = (void *) skb->data;
 
                if (skb->len < sizeof(*rp)) {
@@ -4857,14 +4942,31 @@ static void read_local_oob_data_complete(struct hci_dev *hdev, u8 status,
                          MGMT_STATUS_SUCCESS, &mgmt_rp, rp_size);
 
 remove:
-       mgmt_pending_remove(cmd);
+       if (skb && !IS_ERR(skb))
+               kfree_skb(skb);
+
+       mgmt_pending_free(cmd);
+}
+
+static int read_local_oob_data_sync(struct hci_dev *hdev, void *data)
+{
+       struct mgmt_pending_cmd *cmd = data;
+
+       if (bredr_sc_enabled(hdev))
+               cmd->skb = hci_read_local_oob_data_sync(hdev, true, cmd->sk);
+       else
+               cmd->skb = hci_read_local_oob_data_sync(hdev, false, cmd->sk);
+
+       if (IS_ERR(cmd->skb))
+               return PTR_ERR(cmd->skb);
+       else
+               return 0;
 }
 
 static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
                               void *data, u16 data_len)
 {
        struct mgmt_pending_cmd *cmd;
-       struct hci_request req;
        int err;
 
        bt_dev_dbg(hdev, "sock %p", sk);
@@ -4889,24 +4991,22 @@ static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
                goto unlock;
        }
 
-       cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
-       if (!cmd) {
+       cmd = mgmt_pending_new(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
+       if (!cmd)
                err = -ENOMEM;
-               goto unlock;
-       }
-
-       hci_req_init(&req, hdev);
-
-       if (bredr_sc_enabled(hdev))
-               hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_EXT_DATA, 0, NULL);
        else
-               hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
+               err = hci_cmd_sync_queue(hdev, read_local_oob_data_sync, cmd,
+                                        read_local_oob_data_complete);
 
-       err = hci_req_run_skb(&req, read_local_oob_data_complete);
-       if (err < 0)
-               mgmt_pending_remove(cmd);
+       if (err < 0) {
+               err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
+                                     MGMT_STATUS_FAILED);
 
-unlock:
+               if (cmd)
+                       mgmt_pending_free(cmd);
+       }
+
+unlock:
        hci_dev_unlock(hdev);
        return err;
 }
@@ -5077,13 +5177,6 @@ void mgmt_start_discovery_complete(struct hci_dev *hdev, u8 status)
        }
 
        hci_dev_unlock(hdev);
-
-       /* Handle suspend notifier */
-       if (test_and_clear_bit(SUSPEND_UNPAUSE_DISCOVERY,
-                              hdev->suspend_tasks)) {
-               bt_dev_dbg(hdev, "Unpaused discovery");
-               wake_up(&hdev->suspend_wait_q);
-       }
 }
 
 static bool discovery_type_is_valid(struct hci_dev *hdev, uint8_t type,
@@ -5113,6 +5206,25 @@ static bool discovery_type_is_valid(struct hci_dev *hdev, uint8_t type,
        return true;
 }
 
+static void start_discovery_complete(struct hci_dev *hdev, void *data, int err)
+{
+       struct mgmt_pending_cmd *cmd = data;
+
+       bt_dev_dbg(hdev, "err %d", err);
+
+       mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, mgmt_status(err),
+                         cmd->param, 1);
+       mgmt_pending_free(cmd);
+
+       hci_discovery_set_state(hdev, err ? DISCOVERY_STOPPED:
+                               DISCOVERY_FINDING);
+}
+
+static int start_discovery_sync(struct hci_dev *hdev, void *data)
+{
+       return hci_start_discovery_sync(hdev);
+}
+
 static int start_discovery_internal(struct sock *sk, struct hci_dev *hdev,
                                    u16 op, void *data, u16 len)
 {
@@ -5164,17 +5276,20 @@ static int start_discovery_internal(struct sock *sk, struct hci_dev *hdev,
        else
                hdev->discovery.limited = false;
 
-       cmd = mgmt_pending_add(sk, op, hdev, data, len);
+       cmd = mgmt_pending_new(sk, op, hdev, data, len);
        if (!cmd) {
                err = -ENOMEM;
                goto failed;
        }
 
-       cmd->cmd_complete = generic_cmd_complete;
+       err = hci_cmd_sync_queue(hdev, start_discovery_sync, cmd,
+                                start_discovery_complete);
+       if (err < 0) {
+               mgmt_pending_free(cmd);
+               goto failed;
+       }
 
        hci_discovery_set_state(hdev, DISCOVERY_STARTING);
-       queue_work(hdev->req_workqueue, &hdev->discov_update);
-       err = 0;
 
 failed:
        hci_dev_unlock(hdev);
@@ -5196,13 +5311,6 @@ static int start_limited_discovery(struct sock *sk, struct hci_dev *hdev,
                                        data, len);
 }
 
-static int service_discovery_cmd_complete(struct mgmt_pending_cmd *cmd,
-                                         u8 status)
-{
-       return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status,
-                                cmd->param, 1);
-}
-
 static int start_service_discovery(struct sock *sk, struct hci_dev *hdev,
                                   void *data, u16 len)
 {
@@ -5271,15 +5379,13 @@ static int start_service_discovery(struct sock *sk, struct hci_dev *hdev,
                goto failed;
        }
 
-       cmd = mgmt_pending_add(sk, MGMT_OP_START_SERVICE_DISCOVERY,
+       cmd = mgmt_pending_new(sk, MGMT_OP_START_SERVICE_DISCOVERY,
                               hdev, data, len);
        if (!cmd) {
                err = -ENOMEM;
                goto failed;
        }
 
-       cmd->cmd_complete = service_discovery_cmd_complete;
-
        /* Clear the discovery filter first to free any previously
         * allocated memory for the UUID list.
         */
@@ -5303,9 +5409,14 @@ static int start_service_discovery(struct sock *sk, struct hci_dev *hdev,
                }
        }
 
+       err = hci_cmd_sync_queue(hdev, start_discovery_sync, cmd,
+                                start_discovery_complete);
+       if (err < 0) {
+               mgmt_pending_free(cmd);
+               goto failed;
+       }
+
        hci_discovery_set_state(hdev, DISCOVERY_STARTING);
-       queue_work(hdev->req_workqueue, &hdev->discov_update);
-       err = 0;
 
 failed:
        hci_dev_unlock(hdev);
@@ -5327,12 +5438,25 @@ void mgmt_stop_discovery_complete(struct hci_dev *hdev, u8 status)
        }
 
        hci_dev_unlock(hdev);
+}
 
-       /* Handle suspend notifier */
-       if (test_and_clear_bit(SUSPEND_PAUSE_DISCOVERY, hdev->suspend_tasks)) {
-               bt_dev_dbg(hdev, "Paused discovery");
-               wake_up(&hdev->suspend_wait_q);
-       }
+static void stop_discovery_complete(struct hci_dev *hdev, void *data, int err)
+{
+       struct mgmt_pending_cmd *cmd = data;
+
+       bt_dev_dbg(hdev, "err %d", err);
+
+       mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, mgmt_status(err),
+                         cmd->param, 1);
+       mgmt_pending_free(cmd);
+
+       if (!err)
+               hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
+}
+
+static int stop_discovery_sync(struct hci_dev *hdev, void *data)
+{
+       return hci_stop_discovery_sync(hdev);
 }
 
 static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
@@ -5360,17 +5484,20 @@ static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
                goto unlock;
        }
 
-       cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, data, len);
+       cmd = mgmt_pending_new(sk, MGMT_OP_STOP_DISCOVERY, hdev, data, len);
        if (!cmd) {
                err = -ENOMEM;
                goto unlock;
        }
 
-       cmd->cmd_complete = generic_cmd_complete;
+       err = hci_cmd_sync_queue(hdev, stop_discovery_sync, cmd,
+                                stop_discovery_complete);
+       if (err < 0) {
+               mgmt_pending_free(cmd);
+               goto unlock;
+       }
 
        hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
-       queue_work(hdev->req_workqueue, &hdev->discov_update);
-       err = 0;
 
 unlock:
        hci_dev_unlock(hdev);
@@ -5491,11 +5618,15 @@ done:
        return err;
 }
 
+static int set_device_id_sync(struct hci_dev *hdev, void *data)
+{
+       return hci_update_eir_sync(hdev);
+}
+
 static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
                         u16 len)
 {
        struct mgmt_cp_set_device_id *cp = data;
-       struct hci_request req;
        int err;
        __u16 source;
 
@@ -5517,38 +5648,32 @@ static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
        err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0,
                                NULL, 0);
 
-       hci_req_init(&req, hdev);
-       __hci_req_update_eir(&req);
-       hci_req_run(&req, NULL);
+       hci_cmd_sync_queue(hdev, set_device_id_sync, NULL, NULL);
 
        hci_dev_unlock(hdev);
 
        return err;
 }
 
-static void enable_advertising_instance(struct hci_dev *hdev, u8 status,
-                                       u16 opcode)
+static void enable_advertising_instance(struct hci_dev *hdev, int err)
 {
-       bt_dev_dbg(hdev, "status %u", status);
+       if (err)
+               bt_dev_err(hdev, "failed to re-configure advertising %d", err);
+       else
+               bt_dev_dbg(hdev, "status %d", err);
 }
 
-static void set_advertising_complete(struct hci_dev *hdev, u8 status,
-                                    u16 opcode)
+static void set_advertising_complete(struct hci_dev *hdev, void *data, int err)
 {
        struct cmd_lookup match = { NULL, hdev };
-       struct hci_request req;
        u8 instance;
        struct adv_info *adv_instance;
-       int err;
-
-       hci_dev_lock(hdev);
+       u8 status = mgmt_status(err);
 
        if (status) {
-               u8 mgmt_err = mgmt_status(status);
-
                mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev,
-                                    cmd_status_rsp, &mgmt_err);
-               goto unlock;
+                                    cmd_status_rsp, &status);
+               return;
        }
 
        if (hci_dev_test_flag(hdev, HCI_LE_ADV))
@@ -5564,46 +5689,60 @@ static void set_advertising_complete(struct hci_dev *hdev, u8 status,
        if (match.sk)
                sock_put(match.sk);
 
-       /* Handle suspend notifier */
-       if (test_and_clear_bit(SUSPEND_PAUSE_ADVERTISING,
-                              hdev->suspend_tasks)) {
-               bt_dev_dbg(hdev, "Paused advertising");
-               wake_up(&hdev->suspend_wait_q);
-       } else if (test_and_clear_bit(SUSPEND_UNPAUSE_ADVERTISING,
-                                     hdev->suspend_tasks)) {
-               bt_dev_dbg(hdev, "Unpaused advertising");
-               wake_up(&hdev->suspend_wait_q);
-       }
-
        /* If "Set Advertising" was just disabled and instance advertising was
         * set up earlier, then re-enable multi-instance advertising.
         */
        if (hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
            list_empty(&hdev->adv_instances))
-               goto unlock;
+               return;
 
        instance = hdev->cur_adv_instance;
        if (!instance) {
                adv_instance = list_first_entry_or_null(&hdev->adv_instances,
                                                        struct adv_info, list);
                if (!adv_instance)
-                       goto unlock;
+                       return;
 
                instance = adv_instance->instance;
        }
 
-       hci_req_init(&req, hdev);
+       err = hci_schedule_adv_instance_sync(hdev, instance, true);
 
-       err = __hci_req_schedule_adv_instance(&req, instance, true);
+       enable_advertising_instance(hdev, err);
+}
 
-       if (!err)
-               err = hci_req_run(&req, enable_advertising_instance);
+static int set_adv_sync(struct hci_dev *hdev, void *data)
+{
+       struct mgmt_pending_cmd *cmd = data;
+       struct mgmt_mode *cp = cmd->param;
+       u8 val = !!cp->val;
 
-       if (err)
-               bt_dev_err(hdev, "failed to re-configure advertising");
+       if (cp->val == 0x02)
+               hci_dev_set_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
+       else
+               hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
 
-unlock:
-       hci_dev_unlock(hdev);
+       cancel_adv_timeout(hdev);
+
+       if (val) {
+               /* Switch to instance "0" for the Set Advertising setting.
+                * We cannot use update_[adv|scan_rsp]_data() here as the
+                * HCI_ADVERTISING flag is not yet set.
+                */
+               hdev->cur_adv_instance = 0x00;
+
+               if (ext_adv_capable(hdev)) {
+                       hci_start_ext_adv_sync(hdev, 0x00);
+               } else {
+                       hci_update_adv_data_sync(hdev, 0x00);
+                       hci_update_scan_rsp_data_sync(hdev, 0x00);
+                       hci_enable_advertising_sync(hdev);
+               }
+       } else {
+               hci_disable_advertising_sync(hdev);
+       }
+
+       return 0;
 }
 
 static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data,
@@ -5611,7 +5750,6 @@ static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data,
 {
        struct mgmt_mode *cp = data;
        struct mgmt_pending_cmd *cmd;
-       struct hci_request req;
        u8 val, status;
        int err;
 
@@ -5622,13 +5760,6 @@ static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data,
                return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
                                       status);
 
-       /* Enabling the experimental LL Privay support disables support for
-        * advertising.
-        */
-       if (hci_dev_test_flag(hdev, HCI_ENABLE_LL_PRIVACY))
-               return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
-                                      MGMT_STATUS_NOT_SUPPORTED);
-
        if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
                return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
                                       MGMT_STATUS_INVALID_PARAMS);
@@ -5684,40 +5815,13 @@ static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data,
        }
 
        cmd = mgmt_pending_add(sk, MGMT_OP_SET_ADVERTISING, hdev, data, len);
-       if (!cmd) {
+       if (!cmd)
                err = -ENOMEM;
-               goto unlock;
-       }
-
-       hci_req_init(&req, hdev);
-
-       if (cp->val == 0x02)
-               hci_dev_set_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
        else
-               hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
-
-       cancel_adv_timeout(hdev);
-
-       if (val) {
-               /* Switch to instance "0" for the Set Advertising setting.
-                * We cannot use update_[adv|scan_rsp]_data() here as the
-                * HCI_ADVERTISING flag is not yet set.
-                */
-               hdev->cur_adv_instance = 0x00;
-
-               if (ext_adv_capable(hdev)) {
-                       __hci_req_start_ext_adv(&req, 0x00);
-               } else {
-                       __hci_req_update_adv_data(&req, 0x00);
-                       __hci_req_update_scan_rsp_data(&req, 0x00);
-                       __hci_req_enable_advertising(&req);
-               }
-       } else {
-               __hci_req_disable_advertising(&req);
-       }
+               err = hci_cmd_sync_queue(hdev, set_adv_sync, cmd,
+                                        set_advertising_complete);
 
-       err = hci_req_run(&req, set_advertising_complete);
-       if (err < 0)
+       if (err < 0 && cmd)
                mgmt_pending_remove(cmd);
 
 unlock:
@@ -5810,38 +5914,23 @@ static int set_scan_params(struct sock *sk, struct hci_dev *hdev,
         * loaded.
         */
        if (hci_dev_test_flag(hdev, HCI_LE_SCAN) &&
-           hdev->discovery.state == DISCOVERY_STOPPED) {
-               struct hci_request req;
-
-               hci_req_init(&req, hdev);
-
-               hci_req_add_le_scan_disable(&req, false);
-               hci_req_add_le_passive_scan(&req);
-
-               hci_req_run(&req, NULL);
-       }
+           hdev->discovery.state == DISCOVERY_STOPPED)
+               hci_update_passive_scan(hdev);
 
        hci_dev_unlock(hdev);
 
        return err;
 }
 
-static void fast_connectable_complete(struct hci_dev *hdev, u8 status,
-                                     u16 opcode)
+static void fast_connectable_complete(struct hci_dev *hdev, void *data, int err)
 {
-       struct mgmt_pending_cmd *cmd;
-
-       bt_dev_dbg(hdev, "status 0x%02x", status);
-
-       hci_dev_lock(hdev);
+       struct mgmt_pending_cmd *cmd = data;
 
-       cmd = pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev);
-       if (!cmd)
-               goto unlock;
+       bt_dev_dbg(hdev, "err %d", err);
 
-       if (status) {
+       if (err) {
                mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
-                               mgmt_status(status));
+                               mgmt_status(err));
        } else {
                struct mgmt_mode *cp = cmd->param;
 
@@ -5854,10 +5943,15 @@ static void fast_connectable_complete(struct hci_dev *hdev, u8 status,
                new_settings(hdev, cmd->sk);
        }
 
-       mgmt_pending_remove(cmd);
+       mgmt_pending_free(cmd);
+}
 
-unlock:
-       hci_dev_unlock(hdev);
+static int write_fast_connectable_sync(struct hci_dev *hdev, void *data)
+{
+       struct mgmt_pending_cmd *cmd = data;
+       struct mgmt_mode *cp = cmd->param;
+
+       return hci_write_fast_connectable_sync(hdev, cp->val);
 }
 
 static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
@@ -5865,58 +5959,49 @@ static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
 {
        struct mgmt_mode *cp = data;
        struct mgmt_pending_cmd *cmd;
-       struct hci_request req;
        int err;
 
        bt_dev_dbg(hdev, "sock %p", sk);
 
        if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) ||
            hdev->hci_ver < BLUETOOTH_VER_1_2)
-               return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
+               return mgmt_cmd_status(sk, hdev->id,
+                                      MGMT_OP_SET_FAST_CONNECTABLE,
                                       MGMT_STATUS_NOT_SUPPORTED);
 
        if (cp->val != 0x00 && cp->val != 0x01)
-               return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
+               return mgmt_cmd_status(sk, hdev->id,
+                                      MGMT_OP_SET_FAST_CONNECTABLE,
                                       MGMT_STATUS_INVALID_PARAMS);
 
        hci_dev_lock(hdev);
 
-       if (pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev)) {
-               err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
-                                     MGMT_STATUS_BUSY);
-               goto unlock;
-       }
-
        if (!!cp->val == hci_dev_test_flag(hdev, HCI_FAST_CONNECTABLE)) {
-               err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
-                                       hdev);
+               err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev);
                goto unlock;
        }
 
        if (!hdev_is_powered(hdev)) {
                hci_dev_change_flag(hdev, HCI_FAST_CONNECTABLE);
-               err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
-                                       hdev);
+               err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev);
                new_settings(hdev, sk);
                goto unlock;
        }
 
-       cmd = mgmt_pending_add(sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev,
-                              data, len);
-       if (!cmd) {
+       cmd = mgmt_pending_new(sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev, data,
+                              len);
+       if (!cmd)
                err = -ENOMEM;
-               goto unlock;
-       }
-
-       hci_req_init(&req, hdev);
-
-       __hci_req_write_fast_connectable(&req, cp->val);
+       else
+               err = hci_cmd_sync_queue(hdev, write_fast_connectable_sync, cmd,
+                                        fast_connectable_complete);
 
-       err = hci_req_run(&req, fast_connectable_complete);
        if (err < 0) {
-               err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
-                                     MGMT_STATUS_FAILED);
-               mgmt_pending_remove(cmd);
+               mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
+                               MGMT_STATUS_FAILED);
+
+               if (cmd)
+                       mgmt_pending_free(cmd);
        }
 
 unlock:
@@ -5925,20 +6010,14 @@ unlock:
        return err;
 }
 
-static void set_bredr_complete(struct hci_dev *hdev, u8 status, u16 opcode)
+static void set_bredr_complete(struct hci_dev *hdev, void *data, int err)
 {
-       struct mgmt_pending_cmd *cmd;
-
-       bt_dev_dbg(hdev, "status 0x%02x", status);
+       struct mgmt_pending_cmd *cmd = data;
 
-       hci_dev_lock(hdev);
-
-       cmd = pending_find(MGMT_OP_SET_BREDR, hdev);
-       if (!cmd)
-               goto unlock;
+       bt_dev_dbg(hdev, "err %d", err);
 
-       if (status) {
-               u8 mgmt_err = mgmt_status(status);
+       if (err) {
+               u8 mgmt_err = mgmt_status(err);
 
                /* We need to restore the flag if related HCI commands
                 * failed.
@@ -5951,17 +6030,31 @@ static void set_bredr_complete(struct hci_dev *hdev, u8 status, u16 opcode)
                new_settings(hdev, cmd->sk);
        }
 
-       mgmt_pending_remove(cmd);
+       mgmt_pending_free(cmd);
+}
 
-unlock:
-       hci_dev_unlock(hdev);
+static int set_bredr_sync(struct hci_dev *hdev, void *data)
+{
+       int status;
+
+       status = hci_write_fast_connectable_sync(hdev, false);
+
+       if (!status)
+               status = hci_update_scan_sync(hdev);
+
+       /* Since only the advertising data flags will change, there
+        * is no need to update the scan response data.
+        */
+       if (!status)
+               status = hci_update_adv_data_sync(hdev, hdev->cur_adv_instance);
+
+       return status;
 }
 
 static int set_bredr(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
 {
        struct mgmt_mode *cp = data;
        struct mgmt_pending_cmd *cmd;
-       struct hci_request req;
        int err;
 
        bt_dev_dbg(hdev, "sock %p", sk);
@@ -6033,15 +6126,19 @@ static int set_bredr(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
                }
        }
 
-       if (pending_find(MGMT_OP_SET_BREDR, hdev)) {
-               err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
-                                     MGMT_STATUS_BUSY);
-               goto unlock;
-       }
-
-       cmd = mgmt_pending_add(sk, MGMT_OP_SET_BREDR, hdev, data, len);
-       if (!cmd) {
+       cmd = mgmt_pending_new(sk, MGMT_OP_SET_BREDR, hdev, data, len);
+       if (!cmd)
                err = -ENOMEM;
+       else
+               err = hci_cmd_sync_queue(hdev, set_bredr_sync, cmd,
+                                        set_bredr_complete);
+
+       if (err < 0) {
+               mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
+                               MGMT_STATUS_FAILED);
+               if (cmd)
+                       mgmt_pending_free(cmd);
+
                goto unlock;
        }
 
@@ -6050,42 +6147,23 @@ static int set_bredr(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
         */
        hci_dev_set_flag(hdev, HCI_BREDR_ENABLED);
 
-       hci_req_init(&req, hdev);
-
-       __hci_req_write_fast_connectable(&req, false);
-       __hci_req_update_scan(&req);
-
-       /* Since only the advertising data flags will change, there
-        * is no need to update the scan response data.
-        */
-       __hci_req_update_adv_data(&req, hdev->cur_adv_instance);
-
-       err = hci_req_run(&req, set_bredr_complete);
-       if (err < 0)
-               mgmt_pending_remove(cmd);
-
 unlock:
        hci_dev_unlock(hdev);
        return err;
 }
 
-static void sc_enable_complete(struct hci_dev *hdev, u8 status, u16 opcode)
+static void set_secure_conn_complete(struct hci_dev *hdev, void *data, int err)
 {
-       struct mgmt_pending_cmd *cmd;
+       struct mgmt_pending_cmd *cmd = data;
        struct mgmt_mode *cp;
 
-       bt_dev_dbg(hdev, "status %u", status);
-
-       hci_dev_lock(hdev);
+       bt_dev_dbg(hdev, "err %d", err);
 
-       cmd = pending_find(MGMT_OP_SET_SECURE_CONN, hdev);
-       if (!cmd)
-               goto unlock;
+       if (err) {
+               u8 mgmt_err = mgmt_status(err);
 
-       if (status) {
-               mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode,
-                               mgmt_status(status));
-               goto remove;
+               mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
+               goto done;
        }
 
        cp = cmd->param;
@@ -6105,13 +6183,23 @@ static void sc_enable_complete(struct hci_dev *hdev, u8 status, u16 opcode)
                break;
        }
 
-       send_settings_rsp(cmd->sk, MGMT_OP_SET_SECURE_CONN, hdev);
+       send_settings_rsp(cmd->sk, cmd->opcode, hdev);
        new_settings(hdev, cmd->sk);
 
-remove:
-       mgmt_pending_remove(cmd);
-unlock:
-       hci_dev_unlock(hdev);
+done:
+       mgmt_pending_free(cmd);
+}
+
+static int set_secure_conn_sync(struct hci_dev *hdev, void *data)
+{
+       struct mgmt_pending_cmd *cmd = data;
+       struct mgmt_mode *cp = cmd->param;
+       u8 val = !!cp->val;
+
+       /* Force write of val */
+       hci_dev_set_flag(hdev, HCI_SC_ENABLED);
+
+       return hci_write_sc_support_sync(hdev, val);
 }
 
 static int set_secure_conn(struct sock *sk, struct hci_dev *hdev,
@@ -6119,7 +6207,6 @@ static int set_secure_conn(struct sock *sk, struct hci_dev *hdev,
 {
        struct mgmt_mode *cp = data;
        struct mgmt_pending_cmd *cmd;
-       struct hci_request req;
        u8 val;
        int err;
 
@@ -6138,7 +6225,7 @@ static int set_secure_conn(struct sock *sk, struct hci_dev *hdev,
 
        if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
                return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
-                                 MGMT_STATUS_INVALID_PARAMS);
+                                      MGMT_STATUS_INVALID_PARAMS);
 
        hci_dev_lock(hdev);
 
@@ -6169,12 +6256,6 @@ static int set_secure_conn(struct sock *sk, struct hci_dev *hdev,
                goto failed;
        }
 
-       if (pending_find(MGMT_OP_SET_SECURE_CONN, hdev)) {
-               err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
-                                     MGMT_STATUS_BUSY);
-               goto failed;
-       }
-
        val = !!cp->val;
 
        if (val == hci_dev_test_flag(hdev, HCI_SC_ENABLED) &&
@@ -6183,18 +6264,18 @@ static int set_secure_conn(struct sock *sk, struct hci_dev *hdev,
                goto failed;
        }
 
-       cmd = mgmt_pending_add(sk, MGMT_OP_SET_SECURE_CONN, hdev, data, len);
-       if (!cmd) {
+       cmd = mgmt_pending_new(sk, MGMT_OP_SET_SECURE_CONN, hdev, data, len);
+       if (!cmd)
                err = -ENOMEM;
-               goto failed;
-       }
+       else
+               err = hci_cmd_sync_queue(hdev, set_secure_conn_sync, cmd,
+                                        set_secure_conn_complete);
 
-       hci_req_init(&req, hdev);
-       hci_req_add(&req, HCI_OP_WRITE_SC_SUPPORT, 1, &val);
-       err = hci_req_run(&req, sc_enable_complete);
        if (err < 0) {
-               mgmt_pending_remove(cmd);
-               goto failed;
+               mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
+                               MGMT_STATUS_FAILED);
+               if (cmd)
+                       mgmt_pending_free(cmd);
        }
 
 failed:
@@ -6508,14 +6589,19 @@ static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
        return err;
 }
 
-static int conn_info_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
+static void get_conn_info_complete(struct hci_dev *hdev, void *data, int err)
 {
+       struct mgmt_pending_cmd *cmd = data;
        struct hci_conn *conn = cmd->user_data;
+       struct mgmt_cp_get_conn_info *cp = cmd->param;
        struct mgmt_rp_get_conn_info rp;
-       int err;
+       u8 status;
+
+       bt_dev_dbg(hdev, "err %d", err);
 
-       memcpy(&rp.addr, cmd->param, sizeof(rp.addr));
+       memcpy(&rp.addr, &cp->addr.bdaddr, sizeof(rp.addr));
 
+       status = mgmt_status(err);
        if (status == MGMT_STATUS_SUCCESS) {
                rp.rssi = conn->rssi;
                rp.tx_power = conn->tx_power;
@@ -6526,67 +6612,58 @@ static int conn_info_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
                rp.max_tx_power = HCI_TX_POWER_INVALID;
        }
 
-       err = mgmt_cmd_complete(cmd->sk, cmd->index, MGMT_OP_GET_CONN_INFO,
-                               status, &rp, sizeof(rp));
+       mgmt_cmd_complete(cmd->sk, cmd->index, MGMT_OP_GET_CONN_INFO, status,
+                         &rp, sizeof(rp));
 
-       hci_conn_drop(conn);
-       hci_conn_put(conn);
+       if (conn) {
+               hci_conn_drop(conn);
+               hci_conn_put(conn);
+       }
 
-       return err;
+       mgmt_pending_free(cmd);
 }
 
-static void conn_info_refresh_complete(struct hci_dev *hdev, u8 hci_status,
-                                      u16 opcode)
+static int get_conn_info_sync(struct hci_dev *hdev, void *data)
 {
-       struct hci_cp_read_rssi *cp;
-       struct mgmt_pending_cmd *cmd;
+       struct mgmt_pending_cmd *cmd = data;
+       struct mgmt_cp_get_conn_info *cp = cmd->param;
        struct hci_conn *conn;
-       u16 handle;
-       u8 status;
-
-       bt_dev_dbg(hdev, "status 0x%02x", hci_status);
+       int err;
+       __le16   handle;
 
-       hci_dev_lock(hdev);
+       /* Make sure we are still connected */
+       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);
 
-       /* 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 = MGMT_STATUS_SUCCESS;
-       } else {
-               status = mgmt_status(hci_status);
+       if (!conn || conn != cmd->user_data || conn->state != BT_CONNECTED) {
+               if (cmd->user_data) {
+                       hci_conn_drop(cmd->user_data);
+                       hci_conn_put(cmd->user_data);
+                       cmd->user_data = NULL;
+               }
+               return MGMT_STATUS_NOT_CONNECTED;
        }
 
-       if (!cp) {
-               bt_dev_err(hdev, "invalid sent_cmd in conn_info response");
-               goto unlock;
-       }
+       handle = cpu_to_le16(conn->handle);
 
-       handle = __le16_to_cpu(cp->handle);
-       conn = hci_conn_hash_lookup_handle(hdev, handle);
-       if (!conn) {
-               bt_dev_err(hdev, "unknown handle (%u) in conn_info response",
-                          handle);
-               goto unlock;
-       }
+       /* Refresh RSSI each time */
+       err = hci_read_rssi_sync(hdev, handle);
 
-       cmd = pending_find_data(MGMT_OP_GET_CONN_INFO, hdev, conn);
-       if (!cmd)
-               goto unlock;
+       /* For LE links TX power does not change thus we don't need to
+        * query for it once value is known.
+        */
+       if (!err && (!bdaddr_type_is_le(cp->addr.type) ||
+                    conn->tx_power == HCI_TX_POWER_INVALID))
+               err = hci_read_tx_power_sync(hdev, handle, 0x00);
 
-       cmd->cmd_complete(cmd, status);
-       mgmt_pending_remove(cmd);
+       /* Max TX power needs to be read only once per connection */
+       if (!err && conn->max_tx_power == HCI_TX_POWER_INVALID)
+               err = hci_read_tx_power_sync(hdev, handle, 0x01);
 
-unlock:
-       hci_dev_unlock(hdev);
+       return err;
 }
 
 static int get_conn_info(struct sock *sk, struct hci_dev *hdev, void *data,
@@ -6631,12 +6708,6 @@ static int get_conn_info(struct sock *sk, struct hci_dev *hdev, void *data,
                goto unlock;
        }
 
-       if (pending_find_data(MGMT_OP_GET_CONN_INFO, hdev, conn)) {
-               err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
-                                       MGMT_STATUS_BUSY, &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.
         */
@@ -6650,49 +6721,28 @@ static int get_conn_info(struct sock *sk, struct hci_dev *hdev, void *data,
        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 mgmt_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);
-               }
+               cmd = mgmt_pending_new(sk, MGMT_OP_GET_CONN_INFO, hdev, data,
+                                      len);
+               if (!cmd)
+                       err = -ENOMEM;
+               else
+                       err = hci_cmd_sync_queue(hdev, get_conn_info_sync,
+                                                cmd, get_conn_info_complete);
 
-               /* 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);
-               }
+               if (err < 0) {
+                       mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
+                                         MGMT_STATUS_FAILED, &rp, sizeof(rp));
 
-               err = hci_req_run(&req, conn_info_refresh_complete);
-               if (err < 0)
-                       goto unlock;
+                       if (cmd)
+                               mgmt_pending_free(cmd);
 
-               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 = hci_conn_get(conn);
-               cmd->cmd_complete = conn_info_cmd_complete;
 
                conn->conn_info_timestamp = jiffies;
        } else {
@@ -6710,82 +6760,76 @@ unlock:
        return err;
 }
 
-static int clock_info_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
+static void get_clock_info_complete(struct hci_dev *hdev, void *data, int err)
 {
-       struct hci_conn *conn = cmd->user_data;
+       struct mgmt_pending_cmd *cmd = data;
+       struct mgmt_cp_get_clock_info *cp = cmd->param;
        struct mgmt_rp_get_clock_info rp;
-       struct hci_dev *hdev;
-       int err;
+       struct hci_conn *conn = cmd->user_data;
+       u8 status = mgmt_status(err);
+
+       bt_dev_dbg(hdev, "err %d", err);
 
        memset(&rp, 0, sizeof(rp));
-       memcpy(&rp.addr, cmd->param, sizeof(rp.addr));
+       bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
+       rp.addr.type = cp->addr.type;
 
-       if (status)
+       if (err)
                goto complete;
 
-       hdev = hci_dev_get(cmd->index);
-       if (hdev) {
-               rp.local_clock = cpu_to_le32(hdev->clock);
-               hci_dev_put(hdev);
-       }
+       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);
-       }
-
-complete:
-       err = mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status, &rp,
-                               sizeof(rp));
-
-       if (conn) {
                hci_conn_drop(conn);
                hci_conn_put(conn);
        }
 
-       return err;
+complete:
+       mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status, &rp,
+                         sizeof(rp));
+
+       mgmt_pending_free(cmd);
 }
 
-static void get_clock_info_complete(struct hci_dev *hdev, u8 status, u16 opcode)
+static int get_clock_info_sync(struct hci_dev *hdev, void *data)
 {
-       struct hci_cp_read_clock *hci_cp;
-       struct mgmt_pending_cmd *cmd;
-       struct hci_conn *conn;
-
-       bt_dev_dbg(hdev, "status %u", status);
+       struct mgmt_pending_cmd *cmd = data;
+       struct mgmt_cp_get_clock_info *cp = cmd->param;
+       struct hci_cp_read_clock hci_cp;
+       struct hci_conn *conn = cmd->user_data;
+       int err;
 
-       hci_dev_lock(hdev);
+       memset(&hci_cp, 0, sizeof(hci_cp));
+       err = hci_read_clock_sync(hdev, &hci_cp);
 
-       hci_cp = hci_sent_cmd_data(hdev, HCI_OP_READ_CLOCK);
-       if (!hci_cp)
-               goto unlock;
+       if (conn) {
+               /* Make sure connection still exists */
+               conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
+                                              &cp->addr.bdaddr);
 
-       if (hci_cp->which) {
-               u16 handle = __le16_to_cpu(hci_cp->handle);
-               conn = hci_conn_hash_lookup_handle(hdev, handle);
-       } else {
-               conn = NULL;
+               if (conn && conn == cmd->user_data &&
+                   conn->state == BT_CONNECTED) {
+                       hci_cp.handle = cpu_to_le16(conn->handle);
+                       hci_cp.which = 0x01; /* Piconet clock */
+                       err = hci_read_clock_sync(hdev, &hci_cp);
+               } else if (cmd->user_data) {
+                       hci_conn_drop(cmd->user_data);
+                       hci_conn_put(cmd->user_data);
+                       cmd->user_data = NULL;
+               }
        }
 
-       cmd = pending_find_data(MGMT_OP_GET_CLOCK_INFO, hdev, conn);
-       if (!cmd)
-               goto unlock;
-
-       cmd->cmd_complete(cmd, mgmt_status(status));
-       mgmt_pending_remove(cmd);
-
-unlock:
-       hci_dev_unlock(hdev);
+       return err;
 }
 
 static int get_clock_info(struct sock *sk, struct hci_dev *hdev, void *data,
-                        u16 len)
+                                                               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 mgmt_pending_cmd *cmd;
-       struct hci_request req;
        struct hci_conn *conn;
        int err;
 
@@ -6823,31 +6867,25 @@ static int get_clock_info(struct sock *sk, struct hci_dev *hdev, void *data,
                conn = NULL;
        }
 
-       cmd = mgmt_pending_add(sk, MGMT_OP_GET_CLOCK_INFO, hdev, data, len);
-       if (!cmd) {
+       cmd = mgmt_pending_new(sk, MGMT_OP_GET_CLOCK_INFO, hdev, data, len);
+       if (!cmd)
                err = -ENOMEM;
-               goto unlock;
-       }
-
-       cmd->cmd_complete = clock_info_cmd_complete;
+       else
+               err = hci_cmd_sync_queue(hdev, get_clock_info_sync, cmd,
+                                        get_clock_info_complete);
 
-       hci_req_init(&req, hdev);
+       if (err < 0) {
+               err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CLOCK_INFO,
+                                       MGMT_STATUS_FAILED, &rp, sizeof(rp));
 
-       memset(&hci_cp, 0, sizeof(hci_cp));
-       hci_req_add(&req, HCI_OP_READ_CLOCK, sizeof(hci_cp), &hci_cp);
+               if (cmd)
+                       mgmt_pending_free(cmd);
 
-       if (conn) {
+       } else 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);
@@ -6928,6 +6966,11 @@ static void device_added(struct sock *sk, struct hci_dev *hdev,
        mgmt_event(MGMT_EV_DEVICE_ADDED, hdev, &ev, sizeof(ev), sk);
 }
 
+static int add_device_sync(struct hci_dev *hdev, void *data)
+{
+       return hci_update_passive_scan_sync(hdev);
+}
+
 static int add_device(struct sock *sk, struct hci_dev *hdev,
                      void *data, u16 len)
 {
@@ -7010,7 +7053,9 @@ static int add_device(struct sock *sk, struct hci_dev *hdev,
                        current_flags = params->current_flags;
        }
 
-       hci_update_background_scan(hdev);
+       err = hci_cmd_sync_queue(hdev, add_device_sync, NULL, NULL);
+       if (err < 0)
+               goto unlock;
 
 added:
        device_added(sk, hdev, &cp->addr.bdaddr, cp->addr.type, cp->action);
@@ -7037,6 +7082,11 @@ static void device_removed(struct sock *sk, struct hci_dev *hdev,
        mgmt_event(MGMT_EV_DEVICE_REMOVED, hdev, &ev, sizeof(ev), sk);
 }
 
+static int remove_device_sync(struct hci_dev *hdev, void *data)
+{
+       return hci_update_passive_scan_sync(hdev);
+}
+
 static int remove_device(struct sock *sk, struct hci_dev *hdev,
                         void *data, u16 len)
 {
@@ -7116,7 +7166,6 @@ static int remove_device(struct sock *sk, struct hci_dev *hdev,
                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 {
@@ -7153,10 +7202,10 @@ static int remove_device(struct sock *sk, struct hci_dev *hdev,
                }
 
                bt_dev_dbg(hdev, "All LE connection parameters were removed");
-
-               hci_update_background_scan(hdev);
        }
 
+       hci_cmd_sync_queue(hdev, remove_device_sync, NULL, NULL);
+
 complete:
        err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_DEVICE,
                                MGMT_STATUS_SUCCESS, &cp->addr,
@@ -7359,21 +7408,27 @@ unlock:
        return err;
 }
 
-static void read_local_oob_ext_data_complete(struct hci_dev *hdev, u8 status,
-                                            u16 opcode, struct sk_buff *skb)
+static void read_local_oob_ext_data_complete(struct hci_dev *hdev, void *data,
+                                            int err)
 {
        const struct mgmt_cp_read_local_oob_ext_data *mgmt_cp;
        struct mgmt_rp_read_local_oob_ext_data *mgmt_rp;
        u8 *h192, *r192, *h256, *r256;
-       struct mgmt_pending_cmd *cmd;
+       struct mgmt_pending_cmd *cmd = data;
+       struct sk_buff *skb = cmd->skb;
+       u8 status = mgmt_status(err);
        u16 eir_len;
-       int err;
 
-       bt_dev_dbg(hdev, "status %u", status);
+       if (!status) {
+               if (!skb)
+                       status = MGMT_STATUS_FAILED;
+               else if (IS_ERR(skb))
+                       status = mgmt_status(PTR_ERR(skb));
+               else
+                       status = mgmt_status(skb->data[0]);
+       }
 
-       cmd = pending_find(MGMT_OP_READ_LOCAL_OOB_EXT_DATA, hdev);
-       if (!cmd)
-               return;
+       bt_dev_dbg(hdev, "status %u", status);
 
        mgmt_cp = cmd->param;
 
@@ -7385,7 +7440,7 @@ static void read_local_oob_ext_data_complete(struct hci_dev *hdev, u8 status,
                r192 = NULL;
                h256 = NULL;
                r256 = NULL;
-       } else if (opcode == HCI_OP_READ_LOCAL_OOB_DATA) {
+       } else if (!bredr_sc_enabled(hdev)) {
                struct hci_rp_read_local_oob_data *rp;
 
                if (skb->len != sizeof(*rp)) {
@@ -7466,6 +7521,9 @@ send_rsp:
                                 mgmt_rp, sizeof(*mgmt_rp) + eir_len,
                                 HCI_MGMT_OOB_DATA_EVENTS, cmd->sk);
 done:
+       if (skb && !IS_ERR(skb))
+               kfree_skb(skb);
+
        kfree(mgmt_rp);
        mgmt_pending_remove(cmd);
 }
@@ -7474,7 +7532,6 @@ static int read_local_ssp_oob_req(struct hci_dev *hdev, struct sock *sk,
                                  struct mgmt_cp_read_local_oob_ext_data *cp)
 {
        struct mgmt_pending_cmd *cmd;
-       struct hci_request req;
        int err;
 
        cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_EXT_DATA, hdev,
@@ -7482,14 +7539,9 @@ static int read_local_ssp_oob_req(struct hci_dev *hdev, struct sock *sk,
        if (!cmd)
                return -ENOMEM;
 
-       hci_req_init(&req, hdev);
+       err = hci_cmd_sync_queue(hdev, read_local_oob_data_sync, cmd,
+                                read_local_oob_ext_data_complete);
 
-       if (bredr_sc_enabled(hdev))
-               hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_EXT_DATA, 0, NULL);
-       else
-               hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
-
-       err = hci_req_run_skb(&req, read_local_oob_ext_data_complete);
        if (err < 0) {
                mgmt_pending_remove(cmd);
                return err;
@@ -7713,13 +7765,6 @@ static int read_adv_features(struct sock *sk, struct hci_dev *hdev,
                return mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_ADV_FEATURES,
                                       MGMT_STATUS_REJECTED);
 
-       /* Enabling the experimental LL Privay support disables support for
-        * advertising.
-        */
-       if (hci_dev_test_flag(hdev, HCI_ENABLE_LL_PRIVACY))
-               return mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_ADV_FEATURES,
-                                      MGMT_STATUS_NOT_SUPPORTED);
-
        hci_dev_lock(hdev);
 
        rp_len = sizeof(*rp) + hdev->adv_instance_cnt;
@@ -7876,58 +7921,66 @@ static bool adv_busy(struct hci_dev *hdev)
                pending_find(MGMT_OP_ADD_EXT_ADV_DATA, hdev));
 }
 
-static void add_advertising_complete(struct hci_dev *hdev, u8 status,
-                                    u16 opcode)
+static void add_adv_complete(struct hci_dev *hdev, struct sock *sk, u8 instance,
+                            int err)
 {
-       struct mgmt_pending_cmd *cmd;
-       struct mgmt_cp_add_advertising *cp;
-       struct mgmt_rp_add_advertising rp;
-       struct adv_info *adv_instance, *n;
-       u8 instance;
+       struct adv_info *adv, *n;
 
-       bt_dev_dbg(hdev, "status %u", status);
+       bt_dev_dbg(hdev, "err %d", err);
 
        hci_dev_lock(hdev);
 
-       cmd = pending_find(MGMT_OP_ADD_ADVERTISING, hdev);
-       if (!cmd)
-               cmd = pending_find(MGMT_OP_ADD_EXT_ADV_DATA, hdev);
+       list_for_each_entry_safe(adv, n, &hdev->adv_instances, list) {
+               u8 instance;
 
-       list_for_each_entry_safe(adv_instance, n, &hdev->adv_instances, list) {
-               if (!adv_instance->pending)
+               if (!adv->pending)
                        continue;
 
-               if (!status) {
-                       adv_instance->pending = false;
+               if (!err) {
+                       adv->pending = false;
                        continue;
                }
 
-               instance = adv_instance->instance;
+               instance = adv->instance;
 
                if (hdev->cur_adv_instance == instance)
                        cancel_adv_timeout(hdev);
 
                hci_remove_adv_instance(hdev, instance);
-               mgmt_advertising_removed(cmd ? cmd->sk : NULL, hdev, instance);
+               mgmt_advertising_removed(sk, hdev, instance);
        }
 
-       if (!cmd)
-               goto unlock;
+       hci_dev_unlock(hdev);
+}
+
+static void add_advertising_complete(struct hci_dev *hdev, void *data, int err)
+{
+       struct mgmt_pending_cmd *cmd = data;
+       struct mgmt_cp_add_advertising *cp = cmd->param;
+       struct mgmt_rp_add_advertising rp;
+
+       memset(&rp, 0, sizeof(rp));
 
-       cp = cmd->param;
        rp.instance = cp->instance;
 
-       if (status)
+       if (err)
                mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode,
-                               mgmt_status(status));
+                               mgmt_status(err));
        else
                mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
-                                 mgmt_status(status), &rp, sizeof(rp));
+                                 mgmt_status(err), &rp, sizeof(rp));
 
-       mgmt_pending_remove(cmd);
+       add_adv_complete(hdev, cmd->sk, cp->instance, err);
 
-unlock:
-       hci_dev_unlock(hdev);
+       mgmt_pending_free(cmd);
+}
+
+static int add_advertising_sync(struct hci_dev *hdev, void *data)
+{
+       struct mgmt_pending_cmd *cmd = data;
+       struct mgmt_cp_add_advertising *cp = cmd->param;
+
+       return hci_schedule_adv_instance_sync(hdev, cp->instance, true);
 }
 
 static int add_advertising(struct sock *sk, struct hci_dev *hdev,
@@ -7943,7 +7996,6 @@ static int add_advertising(struct sock *sk, struct hci_dev *hdev,
        struct adv_info *next_instance;
        int err;
        struct mgmt_pending_cmd *cmd;
-       struct hci_request req;
 
        bt_dev_dbg(hdev, "sock %p", sk);
 
@@ -7952,13 +8004,6 @@ static int add_advertising(struct sock *sk, struct hci_dev *hdev,
                return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
                                       status);
 
-       /* Enabling the experimental LL Privay support disables support for
-        * advertising.
-        */
-       if (hci_dev_test_flag(hdev, HCI_ENABLE_LL_PRIVACY))
-               return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
-                                      MGMT_STATUS_NOT_SUPPORTED);
-
        if (cp->instance < 1 || cp->instance > hdev->le_num_of_adv_sets)
                return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
                                       MGMT_STATUS_INVALID_PARAMS);
@@ -8051,25 +8096,19 @@ static int add_advertising(struct sock *sk, struct hci_dev *hdev,
        /* We're good to go, update advertising data, parameters, and start
         * advertising.
         */
-       cmd = mgmt_pending_add(sk, MGMT_OP_ADD_ADVERTISING, hdev, data,
+       cmd = mgmt_pending_new(sk, MGMT_OP_ADD_ADVERTISING, hdev, data,
                               data_len);
        if (!cmd) {
                err = -ENOMEM;
                goto unlock;
        }
 
-       hci_req_init(&req, hdev);
+       cp->instance = schedule_instance;
 
-       err = __hci_req_schedule_adv_instance(&req, schedule_instance, true);
-
-       if (!err)
-               err = hci_req_run(&req, add_advertising_complete);
-
-       if (err < 0) {
-               err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
-                                     MGMT_STATUS_FAILED);
-               mgmt_pending_remove(cmd);
-       }
+       err = hci_cmd_sync_queue(hdev, add_advertising_sync, cmd,
+                                add_advertising_complete);
+       if (err < 0)
+               mgmt_pending_free(cmd);
 
 unlock:
        hci_dev_unlock(hdev);
@@ -8077,30 +8116,25 @@ unlock:
        return err;
 }
 
-static void add_ext_adv_params_complete(struct hci_dev *hdev, u8 status,
-                                       u16 opcode)
+static void add_ext_adv_params_complete(struct hci_dev *hdev, void *data,
+                                       int err)
 {
-       struct mgmt_pending_cmd *cmd;
-       struct mgmt_cp_add_ext_adv_params *cp;
+       struct mgmt_pending_cmd *cmd = data;
+       struct mgmt_cp_add_ext_adv_params *cp = cmd->param;
        struct mgmt_rp_add_ext_adv_params rp;
-       struct adv_info *adv_instance;
+       struct adv_info *adv;
        u32 flags;
 
        BT_DBG("%s", hdev->name);
 
        hci_dev_lock(hdev);
 
-       cmd = pending_find(MGMT_OP_ADD_EXT_ADV_PARAMS, hdev);
-       if (!cmd)
-               goto unlock;
-
-       cp = cmd->param;
-       adv_instance = hci_find_adv_instance(hdev, cp->instance);
-       if (!adv_instance)
+       adv = hci_find_adv_instance(hdev, cp->instance);
+       if (!adv)
                goto unlock;
 
        rp.instance = cp->instance;
-       rp.tx_power = adv_instance->tx_power;
+       rp.tx_power = adv->tx_power;
 
        /* While we're at it, inform userspace of the available space for this
         * advertisement, given the flags that will be used.
@@ -8109,39 +8143,44 @@ static void add_ext_adv_params_complete(struct hci_dev *hdev, u8 status,
        rp.max_adv_data_len = tlv_data_max_len(hdev, flags, true);
        rp.max_scan_rsp_len = tlv_data_max_len(hdev, flags, false);
 
-       if (status) {
+       if (err) {
                /* If this advertisement was previously advertising and we
                 * failed to update it, we signal that it has been removed and
                 * delete its structure
                 */
-               if (!adv_instance->pending)
+               if (!adv->pending)
                        mgmt_advertising_removed(cmd->sk, hdev, cp->instance);
 
                hci_remove_adv_instance(hdev, cp->instance);
 
                mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode,
-                               mgmt_status(status));
-
+                               mgmt_status(err));
        } else {
                mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
-                                 mgmt_status(status), &rp, sizeof(rp));
+                                 mgmt_status(err), &rp, sizeof(rp));
        }
 
 unlock:
        if (cmd)
-               mgmt_pending_remove(cmd);
+               mgmt_pending_free(cmd);
 
        hci_dev_unlock(hdev);
 }
 
+static int add_ext_adv_params_sync(struct hci_dev *hdev, void *data)
+{
+       struct mgmt_pending_cmd *cmd = data;
+       struct mgmt_cp_add_ext_adv_params *cp = cmd->param;
+
+       return hci_setup_ext_adv_instance_sync(hdev, cp->instance);
+}
+
 static int add_ext_adv_params(struct sock *sk, struct hci_dev *hdev,
                              void *data, u16 data_len)
 {
        struct mgmt_cp_add_ext_adv_params *cp = data;
        struct mgmt_rp_add_ext_adv_params rp;
        struct mgmt_pending_cmd *cmd = NULL;
-       struct adv_info *adv_instance;
-       struct hci_request req;
        u32 flags, min_interval, max_interval;
        u16 timeout, duration;
        u8 status;
@@ -8223,29 +8262,18 @@ static int add_ext_adv_params(struct sock *sk, struct hci_dev *hdev,
 
        /* Submit request for advertising params if ext adv available */
        if (ext_adv_capable(hdev)) {
-               hci_req_init(&req, hdev);
-               adv_instance = hci_find_adv_instance(hdev, cp->instance);
-
-               /* Updating parameters of an active instance will return a
-                * Command Disallowed error, so we must first disable the
-                * instance if it is active.
-                */
-               if (!adv_instance->pending)
-                       __hci_req_disable_ext_adv_instance(&req, cp->instance);
-
-               __hci_req_setup_ext_adv_instance(&req, cp->instance);
-
-               err = hci_req_run(&req, add_ext_adv_params_complete);
-
-               if (!err)
-                       cmd = mgmt_pending_add(sk, MGMT_OP_ADD_EXT_ADV_PARAMS,
-                                              hdev, data, data_len);
+               cmd = mgmt_pending_new(sk, MGMT_OP_ADD_EXT_ADV_PARAMS, hdev,
+                                      data, data_len);
                if (!cmd) {
                        err = -ENOMEM;
                        hci_remove_adv_instance(hdev, cp->instance);
                        goto unlock;
                }
 
+               err = hci_cmd_sync_queue(hdev, add_ext_adv_params_sync, cmd,
+                                        add_ext_adv_params_complete);
+               if (err < 0)
+                       mgmt_pending_free(cmd);
        } else {
                rp.instance = cp->instance;
                rp.tx_power = HCI_ADV_TX_POWER_NO_PREFERENCE;
@@ -8262,6 +8290,49 @@ unlock:
        return err;
 }
 
+static void add_ext_adv_data_complete(struct hci_dev *hdev, void *data, int err)
+{
+       struct mgmt_pending_cmd *cmd = data;
+       struct mgmt_cp_add_ext_adv_data *cp = cmd->param;
+       struct mgmt_rp_add_advertising rp;
+
+       add_adv_complete(hdev, cmd->sk, cp->instance, err);
+
+       memset(&rp, 0, sizeof(rp));
+
+       rp.instance = cp->instance;
+
+       if (err)
+               mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode,
+                               mgmt_status(err));
+       else
+               mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
+                                 mgmt_status(err), &rp, sizeof(rp));
+
+       mgmt_pending_free(cmd);
+}
+
+static int add_ext_adv_data_sync(struct hci_dev *hdev, void *data)
+{
+       struct mgmt_pending_cmd *cmd = data;
+       struct mgmt_cp_add_ext_adv_data *cp = cmd->param;
+       int err;
+
+       if (ext_adv_capable(hdev)) {
+               err = hci_update_adv_data_sync(hdev, cp->instance);
+               if (err)
+                       return err;
+
+               err = hci_update_scan_rsp_data_sync(hdev, cp->instance);
+               if (err)
+                       return err;
+
+               return hci_enable_ext_advertising_sync(hdev, cp->instance);
+       }
+
+       return hci_schedule_adv_instance_sync(hdev, cp->instance, true);
+}
+
 static int add_ext_adv_data(struct sock *sk, struct hci_dev *hdev, void *data,
                            u16 data_len)
 {
@@ -8272,7 +8343,6 @@ static int add_ext_adv_data(struct sock *sk, struct hci_dev *hdev, void *data,
        struct adv_info *adv_instance;
        int err = 0;
        struct mgmt_pending_cmd *cmd;
-       struct hci_request req;
 
        BT_DBG("%s", hdev->name);
 
@@ -8314,78 +8384,52 @@ static int add_ext_adv_data(struct sock *sk, struct hci_dev *hdev, void *data,
                                  cp->data, cp->scan_rsp_len,
                                  cp->data + cp->adv_data_len);
 
-       /* We're good to go, update advertising data, parameters, and start
-        * advertising.
-        */
-
-       hci_req_init(&req, hdev);
-
-       hci_req_add(&req, HCI_OP_READ_LOCAL_NAME, 0, NULL);
-
-       if (ext_adv_capable(hdev)) {
-               __hci_req_update_adv_data(&req, cp->instance);
-               __hci_req_update_scan_rsp_data(&req, cp->instance);
-               __hci_req_enable_ext_advertising(&req, cp->instance);
-
-       } else {
-               /* If using software rotation, determine next instance to use */
-
-               if (hdev->cur_adv_instance == cp->instance) {
-                       /* If the currently advertised instance is being changed
-                        * then cancel the current advertising and schedule the
-                        * next instance. If there is only one instance then the
-                        * overridden advertising data will be visible right
-                        * away
-                        */
-                       cancel_adv_timeout(hdev);
-
-                       next_instance = hci_get_next_instance(hdev,
-                                                             cp->instance);
-                       if (next_instance)
-                               schedule_instance = next_instance->instance;
-               } else if (!hdev->adv_instance_timeout) {
-                       /* Immediately advertise the new instance if no other
-                        * instance is currently being advertised.
-                        */
-                       schedule_instance = cp->instance;
-               }
+       /* If using software rotation, determine next instance to use */
+       if (hdev->cur_adv_instance == cp->instance) {
+               /* If the currently advertised instance is being changed
+                * then cancel the current advertising and schedule the
+                * next instance. If there is only one instance then the
+                * overridden advertising data will be visible right
+                * away
+                */
+               cancel_adv_timeout(hdev);
 
-               /* If the HCI_ADVERTISING flag is set or there is no instance to
-                * be advertised then we have no HCI communication to make.
-                * Simply return.
+               next_instance = hci_get_next_instance(hdev, cp->instance);
+               if (next_instance)
+                       schedule_instance = next_instance->instance;
+       } else if (!hdev->adv_instance_timeout) {
+               /* Immediately advertise the new instance if no other
+                * instance is currently being advertised.
                 */
-               if (hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
-                   !schedule_instance) {
-                       if (adv_instance->pending) {
-                               mgmt_advertising_added(sk, hdev, cp->instance);
-                               adv_instance->pending = false;
-                       }
-                       rp.instance = cp->instance;
-                       err = mgmt_cmd_complete(sk, hdev->id,
-                                               MGMT_OP_ADD_EXT_ADV_DATA,
-                                               MGMT_STATUS_SUCCESS, &rp,
-                                               sizeof(rp));
-                       goto unlock;
-               }
+               schedule_instance = cp->instance;
+       }
 
-               err = __hci_req_schedule_adv_instance(&req, schedule_instance,
-                                                     true);
+       /* If the HCI_ADVERTISING flag is set or there is no instance to
+        * be advertised then we have no HCI communication to make.
+        * Simply return.
+        */
+       if (hci_dev_test_flag(hdev, HCI_ADVERTISING) || !schedule_instance) {
+               if (adv_instance->pending) {
+                       mgmt_advertising_added(sk, hdev, cp->instance);
+                       adv_instance->pending = false;
+               }
+               rp.instance = cp->instance;
+               err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_EXT_ADV_DATA,
+                                       MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
+               goto unlock;
        }
 
-       cmd = mgmt_pending_add(sk, MGMT_OP_ADD_EXT_ADV_DATA, hdev, data,
+       cmd = mgmt_pending_new(sk, MGMT_OP_ADD_EXT_ADV_DATA, hdev, data,
                               data_len);
        if (!cmd) {
                err = -ENOMEM;
                goto clear_new_instance;
        }
 
-       if (!err)
-               err = hci_req_run(&req, add_advertising_complete);
-
+       err = hci_cmd_sync_queue(hdev, add_ext_adv_data_sync, cmd,
+                                add_ext_adv_data_complete);
        if (err < 0) {
-               err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_EXT_ADV_DATA,
-                                     MGMT_STATUS_FAILED);
-               mgmt_pending_remove(cmd);
+               mgmt_pending_free(cmd);
                goto clear_new_instance;
        }
 
@@ -8408,54 +8452,53 @@ unlock:
        return err;
 }
 
-static void remove_advertising_complete(struct hci_dev *hdev, u8 status,
-                                       u16 opcode)
+static void remove_advertising_complete(struct hci_dev *hdev, void *data,
+                                       int err)
 {
-       struct mgmt_pending_cmd *cmd;
-       struct mgmt_cp_remove_advertising *cp;
+       struct mgmt_pending_cmd *cmd = data;
+       struct mgmt_cp_remove_advertising *cp = cmd->param;
        struct mgmt_rp_remove_advertising rp;
 
-       bt_dev_dbg(hdev, "status %u", status);
+       bt_dev_dbg(hdev, "err %d", err);
 
-       hci_dev_lock(hdev);
+       memset(&rp, 0, sizeof(rp));
+       rp.instance = cp->instance;
 
-       /* A failure status here only means that we failed to disable
-        * advertising. Otherwise, the advertising instance has been removed,
-        * so report success.
-        */
-       cmd = pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev);
-       if (!cmd)
-               goto unlock;
+       if (err)
+               mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode,
+                               mgmt_status(err));
+       else
+               mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
+                                 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
 
-       cp = cmd->param;
-       rp.instance = cp->instance;
+       mgmt_pending_free(cmd);
+}
 
-       mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, MGMT_STATUS_SUCCESS,
-                         &rp, sizeof(rp));
-       mgmt_pending_remove(cmd);
+static int remove_advertising_sync(struct hci_dev *hdev, void *data)
+{
+       struct mgmt_pending_cmd *cmd = data;
+       struct mgmt_cp_remove_advertising *cp = cmd->param;
+       int err;
 
-unlock:
-       hci_dev_unlock(hdev);
+       err = hci_remove_advertising_sync(hdev, cmd->sk, cp->instance, true);
+       if (err)
+               return err;
+
+       if (list_empty(&hdev->adv_instances))
+               err = hci_disable_advertising_sync(hdev);
+
+       return err;
 }
 
 static int remove_advertising(struct sock *sk, struct hci_dev *hdev,
                              void *data, u16 data_len)
 {
        struct mgmt_cp_remove_advertising *cp = data;
-       struct mgmt_rp_remove_advertising rp;
        struct mgmt_pending_cmd *cmd;
-       struct hci_request req;
        int err;
 
        bt_dev_dbg(hdev, "sock %p", sk);
 
-       /* Enabling the experimental LL Privay support disables support for
-        * advertising.
-        */
-       if (hci_dev_test_flag(hdev, HCI_ENABLE_LL_PRIVACY))
-               return mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_ADVERTISING,
-                                      MGMT_STATUS_NOT_SUPPORTED);
-
        hci_dev_lock(hdev);
 
        if (cp->instance && !hci_find_adv_instance(hdev, cp->instance)) {
@@ -8479,44 +8522,17 @@ static int remove_advertising(struct sock *sk, struct hci_dev *hdev,
                goto unlock;
        }
 
-       hci_req_init(&req, hdev);
-
-       /* If we use extended advertising, instance is disabled and removed */
-       if (ext_adv_capable(hdev)) {
-               __hci_req_disable_ext_adv_instance(&req, cp->instance);
-               __hci_req_remove_ext_adv_instance(&req, cp->instance);
-       }
-
-       hci_req_clear_adv_instance(hdev, sk, &req, cp->instance, true);
-
-       if (list_empty(&hdev->adv_instances))
-               __hci_req_disable_advertising(&req);
-
-       /* If no HCI commands have been collected so far or the HCI_ADVERTISING
-        * flag is set or the device isn't powered then we have no HCI
-        * communication to make. Simply return.
-        */
-       if (skb_queue_empty(&req.cmd_q) ||
-           !hdev_is_powered(hdev) ||
-           hci_dev_test_flag(hdev, HCI_ADVERTISING)) {
-               hci_req_purge(&req);
-               rp.instance = cp->instance;
-               err = mgmt_cmd_complete(sk, hdev->id,
-                                       MGMT_OP_REMOVE_ADVERTISING,
-                                       MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
-               goto unlock;
-       }
-
-       cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_ADVERTISING, hdev, data,
+       cmd = mgmt_pending_new(sk, MGMT_OP_REMOVE_ADVERTISING, hdev, data,
                               data_len);
        if (!cmd) {
                err = -ENOMEM;
                goto unlock;
        }
 
-       err = hci_req_run(&req, remove_advertising_complete);
+       err = hci_cmd_sync_queue(hdev, remove_advertising_sync, cmd,
+                                remove_advertising_complete);
        if (err < 0)
-               mgmt_pending_remove(cmd);
+               mgmt_pending_free(cmd);
 
 unlock:
        hci_dev_unlock(hdev);
@@ -8758,31 +8774,6 @@ void mgmt_index_removed(struct hci_dev *hdev)
                         HCI_MGMT_EXT_INDEX_EVENTS);
 }
 
-/* This function requires the caller holds hdev->lock */
-static void restart_le_actions(struct hci_dev *hdev)
-{
-       struct hci_conn_params *p;
-
-       list_for_each_entry(p, &hdev->le_conn_params, list) {
-               /* 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;
-               }
-       }
-}
-
 void mgmt_power_on(struct hci_dev *hdev, int err)
 {
        struct cmd_lookup match = { NULL, hdev };
@@ -8793,7 +8784,7 @@ void mgmt_power_on(struct hci_dev *hdev, int err)
 
        if (!err) {
                restart_le_actions(hdev);
-               hci_update_background_scan(hdev);
+               hci_update_passive_scan(hdev);
        }
 
        mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
@@ -9349,74 +9340,6 @@ void mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
                sock_put(match.sk);
 }
 
-static void clear_eir(struct hci_request *req)
-{
-       struct hci_dev *hdev = req->hdev;
-       struct hci_cp_write_eir cp;
-
-       if (!lmp_ext_inq_capable(hdev))
-               return;
-
-       memset(hdev->eir, 0, sizeof(hdev->eir));
-
-       memset(&cp, 0, sizeof(cp));
-
-       hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
-}
-
-void mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
-{
-       struct cmd_lookup match = { NULL, hdev };
-       struct hci_request req;
-       bool changed = false;
-
-       if (status) {
-               u8 mgmt_err = mgmt_status(status);
-
-               if (enable && hci_dev_test_and_clear_flag(hdev,
-                                                         HCI_SSP_ENABLED)) {
-                       hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
-                       new_settings(hdev, NULL);
-               }
-
-               mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
-                                    &mgmt_err);
-               return;
-       }
-
-       if (enable) {
-               changed = !hci_dev_test_and_set_flag(hdev, HCI_SSP_ENABLED);
-       } else {
-               changed = hci_dev_test_and_clear_flag(hdev, HCI_SSP_ENABLED);
-               if (!changed)
-                       changed = hci_dev_test_and_clear_flag(hdev,
-                                                             HCI_HS_ENABLED);
-               else
-                       hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
-       }
-
-       mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
-
-       if (changed)
-               new_settings(hdev, match.sk);
-
-       if (match.sk)
-               sock_put(match.sk);
-
-       hci_req_init(&req, hdev);
-
-       if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
-               if (hci_dev_test_flag(hdev, HCI_USE_DEBUG_KEYS))
-                       hci_req_add(&req, HCI_OP_WRITE_SSP_DEBUG_MODE,
-                                   sizeof(enable), &enable);
-               __hci_req_update_eir(&req);
-       } else {
-               clear_eir(&req);
-       }
-
-       hci_req_run(&req, NULL);
-}
-
 static void sk_lookup(struct mgmt_pending_cmd *cmd, void *data)
 {
        struct cmd_lookup *match = data;
index 0d0a6d7..83875f2 100644 (file)
@@ -227,7 +227,7 @@ void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
        }
 }
 
-struct mgmt_pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
+struct mgmt_pending_cmd *mgmt_pending_new(struct sock *sk, u16 opcode,
                                          struct hci_dev *hdev,
                                          void *data, u16 len)
 {
@@ -251,6 +251,19 @@ struct mgmt_pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
        cmd->sk = sk;
        sock_hold(sk);
 
+       return cmd;
+}
+
+struct mgmt_pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
+                                         struct hci_dev *hdev,
+                                         void *data, u16 len)
+{
+       struct mgmt_pending_cmd *cmd;
+
+       cmd = mgmt_pending_new(sk, opcode, hdev, data, len);
+       if (!cmd)
+               return NULL;
+
        list_add(&cmd->list, &hdev->mgmt_pending);
 
        return cmd;
index 6559f18..63b965e 100644 (file)
@@ -27,6 +27,7 @@ struct mgmt_pending_cmd {
        void *param;
        size_t param_len;
        struct sock *sk;
+       struct sk_buff *skb;
        void *user_data;
        int (*cmd_complete)(struct mgmt_pending_cmd *cmd, u8 status);
 };
@@ -49,5 +50,8 @@ void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
 struct mgmt_pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
                                          struct hci_dev *hdev,
                                          void *data, u16 len);
+struct mgmt_pending_cmd *mgmt_pending_new(struct sock *sk, u16 opcode,
+                                         struct hci_dev *hdev,
+                                         void *data, u16 len);
 void mgmt_pending_free(struct mgmt_pending_cmd *cmd);
 void mgmt_pending_remove(struct mgmt_pending_cmd *cmd);
index 255cffa..1122097 100644 (file)
@@ -93,7 +93,7 @@ struct msft_data {
        struct list_head handle_map;
        __u16 pending_add_handle;
        __u16 pending_remove_handle;
-       __u8 reregistering;
+       __u8 resuming;
        __u8 suspending;
        __u8 filter_enabled;
 };
@@ -156,7 +156,6 @@ failed:
        return false;
 }
 
-/* This function requires the caller holds hdev->lock */
 static void reregister_monitor(struct hci_dev *hdev, int handle)
 {
        struct adv_monitor *monitor;
@@ -166,9 +165,9 @@ static void reregister_monitor(struct hci_dev *hdev, int handle)
        while (1) {
                monitor = idr_get_next(&hdev->adv_monitors_idr, &handle);
                if (!monitor) {
-                       /* All monitors have been reregistered */
-                       msft->reregistering = false;
-                       hci_update_background_scan(hdev);
+                       /* All monitors have been resumed */
+                       msft->resuming = false;
+                       hci_update_passive_scan(hdev);
                        return;
                }
 
@@ -185,67 +184,317 @@ static void reregister_monitor(struct hci_dev *hdev, int handle)
        }
 }
 
-/* This function requires the caller holds hdev->lock */
-static void remove_monitor_on_suspend(struct hci_dev *hdev, int handle)
+/* is_mgmt = true matches the handle exposed to userspace via mgmt.
+ * is_mgmt = false matches the handle used by the msft controller.
+ * This function requires the caller holds hdev->lock
+ */
+static struct msft_monitor_advertisement_handle_data *msft_find_handle_data
+                               (struct hci_dev *hdev, u16 handle, bool is_mgmt)
+{
+       struct msft_monitor_advertisement_handle_data *entry;
+       struct msft_data *msft = hdev->msft_data;
+
+       list_for_each_entry(entry, &msft->handle_map, list) {
+               if (is_mgmt && entry->mgmt_handle == handle)
+                       return entry;
+               if (!is_mgmt && entry->msft_handle == handle)
+                       return entry;
+       }
+
+       return NULL;
+}
+
+static void msft_le_monitor_advertisement_cb(struct hci_dev *hdev,
+                                            u8 status, u16 opcode,
+                                            struct sk_buff *skb)
+{
+       struct msft_rp_le_monitor_advertisement *rp;
+       struct adv_monitor *monitor;
+       struct msft_monitor_advertisement_handle_data *handle_data;
+       struct msft_data *msft = hdev->msft_data;
+
+       hci_dev_lock(hdev);
+
+       monitor = idr_find(&hdev->adv_monitors_idr, msft->pending_add_handle);
+       if (!monitor) {
+               bt_dev_err(hdev, "msft add advmon: monitor %u is not found!",
+                          msft->pending_add_handle);
+               status = HCI_ERROR_UNSPECIFIED;
+               goto unlock;
+       }
+
+       if (status)
+               goto unlock;
+
+       rp = (struct msft_rp_le_monitor_advertisement *)skb->data;
+       if (skb->len < sizeof(*rp)) {
+               status = HCI_ERROR_UNSPECIFIED;
+               goto unlock;
+       }
+
+       handle_data = kmalloc(sizeof(*handle_data), GFP_KERNEL);
+       if (!handle_data) {
+               status = HCI_ERROR_UNSPECIFIED;
+               goto unlock;
+       }
+
+       handle_data->mgmt_handle = monitor->handle;
+       handle_data->msft_handle = rp->handle;
+       INIT_LIST_HEAD(&handle_data->list);
+       list_add(&handle_data->list, &msft->handle_map);
+
+       monitor->state = ADV_MONITOR_STATE_OFFLOADED;
+
+unlock:
+       if (status && monitor)
+               hci_free_adv_monitor(hdev, monitor);
+
+       hci_dev_unlock(hdev);
+
+       if (!msft->resuming)
+               hci_add_adv_patterns_monitor_complete(hdev, status);
+}
+
+static void msft_le_cancel_monitor_advertisement_cb(struct hci_dev *hdev,
+                                                   u8 status, u16 opcode,
+                                                   struct sk_buff *skb)
 {
+       struct msft_cp_le_cancel_monitor_advertisement *cp;
+       struct msft_rp_le_cancel_monitor_advertisement *rp;
        struct adv_monitor *monitor;
+       struct msft_monitor_advertisement_handle_data *handle_data;
        struct msft_data *msft = hdev->msft_data;
        int err;
+       bool pending;
 
-       while (1) {
-               monitor = idr_get_next(&hdev->adv_monitors_idr, &handle);
-               if (!monitor) {
-                       /* All monitors have been removed */
-                       msft->suspending = false;
-                       hci_update_background_scan(hdev);
+       if (status)
+               goto done;
+
+       rp = (struct msft_rp_le_cancel_monitor_advertisement *)skb->data;
+       if (skb->len < sizeof(*rp)) {
+               status = HCI_ERROR_UNSPECIFIED;
+               goto done;
+       }
+
+       hci_dev_lock(hdev);
+
+       cp = hci_sent_cmd_data(hdev, hdev->msft_opcode);
+       handle_data = msft_find_handle_data(hdev, cp->handle, false);
+
+       if (handle_data) {
+               monitor = idr_find(&hdev->adv_monitors_idr,
+                                  handle_data->mgmt_handle);
+
+               if (monitor && monitor->state == ADV_MONITOR_STATE_OFFLOADED)
+                       monitor->state = ADV_MONITOR_STATE_REGISTERED;
+
+               /* Do not free the monitor if it is being removed due to
+                * suspend. It will be re-monitored on resume.
+                */
+               if (monitor && !msft->suspending)
+                       hci_free_adv_monitor(hdev, monitor);
+
+               list_del(&handle_data->list);
+               kfree(handle_data);
+       }
+
+       /* If remove all monitors is required, we need to continue the process
+        * here because the earlier it was paused when waiting for the
+        * response from controller.
+        */
+       if (msft->pending_remove_handle == 0) {
+               pending = hci_remove_all_adv_monitor(hdev, &err);
+               if (pending) {
+                       hci_dev_unlock(hdev);
                        return;
                }
 
-               msft->pending_remove_handle = (u16)handle;
-               err = __msft_remove_monitor(hdev, monitor, handle);
+               if (err)
+                       status = HCI_ERROR_UNSPECIFIED;
+       }
 
-               /* If success, return and wait for monitor removed callback */
-               if (!err)
-                       return;
+       hci_dev_unlock(hdev);
+
+done:
+       if (!msft->suspending)
+               hci_remove_adv_monitor_complete(hdev, status);
+}
+
+static int msft_remove_monitor_sync(struct hci_dev *hdev,
+                                   struct adv_monitor *monitor)
+{
+       struct msft_cp_le_cancel_monitor_advertisement cp;
+       struct msft_monitor_advertisement_handle_data *handle_data;
+       struct sk_buff *skb;
+       u8 status;
+
+       handle_data = msft_find_handle_data(hdev, monitor->handle, true);
+
+       /* If no matched handle, just remove without telling controller */
+       if (!handle_data)
+               return -ENOENT;
+
+       cp.sub_opcode = MSFT_OP_LE_CANCEL_MONITOR_ADVERTISEMENT;
+       cp.handle = handle_data->msft_handle;
+
+       skb = __hci_cmd_sync(hdev, hdev->msft_opcode, sizeof(cp), &cp,
+                            HCI_CMD_TIMEOUT);
+       if (IS_ERR(skb))
+               return PTR_ERR(skb);
+
+       status = skb->data[0];
+       skb_pull(skb, 1);
+
+       msft_le_cancel_monitor_advertisement_cb(hdev, status, hdev->msft_opcode,
+                                               skb);
+
+       return status;
+}
+
+/* This function requires the caller holds hci_req_sync_lock */
+int msft_suspend_sync(struct hci_dev *hdev)
+{
+       struct msft_data *msft = hdev->msft_data;
+       struct adv_monitor *monitor;
+       int handle = 0;
+
+       if (!msft || !msft_monitor_supported(hdev))
+               return 0;
+
+       msft->suspending = true;
+
+       while (1) {
+               monitor = idr_get_next(&hdev->adv_monitors_idr, &handle);
+               if (!monitor)
+                       break;
+
+               msft_remove_monitor_sync(hdev, monitor);
 
-               /* Otherwise free the monitor and keep removing */
-               hci_free_adv_monitor(hdev, monitor);
                handle++;
        }
+
+       /* All monitors have been removed */
+       msft->suspending = false;
+
+       return 0;
 }
 
-/* This function requires the caller holds hdev->lock */
-void msft_suspend(struct hci_dev *hdev)
+static bool msft_monitor_rssi_valid(struct adv_monitor *monitor)
 {
-       struct msft_data *msft = hdev->msft_data;
+       struct adv_rssi_thresholds *r = &monitor->rssi;
 
-       if (!msft)
-               return;
+       if (r->high_threshold < MSFT_RSSI_THRESHOLD_VALUE_MIN ||
+           r->high_threshold > MSFT_RSSI_THRESHOLD_VALUE_MAX ||
+           r->low_threshold < MSFT_RSSI_THRESHOLD_VALUE_MIN ||
+           r->low_threshold > MSFT_RSSI_THRESHOLD_VALUE_MAX)
+               return false;
 
-       if (msft_monitor_supported(hdev)) {
-               msft->suspending = true;
-               /* Quitely remove all monitors on suspend to avoid waking up
-                * the system.
-                */
-               remove_monitor_on_suspend(hdev, 0);
+       /* High_threshold_timeout is not supported,
+        * once high_threshold is reached, events are immediately reported.
+        */
+       if (r->high_threshold_timeout != 0)
+               return false;
+
+       if (r->low_threshold_timeout > MSFT_RSSI_LOW_TIMEOUT_MAX)
+               return false;
+
+       /* Sampling period from 0x00 to 0xFF are all allowed */
+       return true;
+}
+
+static bool msft_monitor_pattern_valid(struct adv_monitor *monitor)
+{
+       return msft_monitor_rssi_valid(monitor);
+       /* No additional check needed for pattern-based monitor */
+}
+
+static int msft_add_monitor_sync(struct hci_dev *hdev,
+                                struct adv_monitor *monitor)
+{
+       struct msft_cp_le_monitor_advertisement *cp;
+       struct msft_le_monitor_advertisement_pattern_data *pattern_data;
+       struct msft_le_monitor_advertisement_pattern *pattern;
+       struct adv_pattern *entry;
+       size_t total_size = sizeof(*cp) + sizeof(*pattern_data);
+       ptrdiff_t offset = 0;
+       u8 pattern_count = 0;
+       struct sk_buff *skb;
+       u8 status;
+
+       if (!msft_monitor_pattern_valid(monitor))
+               return -EINVAL;
+
+       list_for_each_entry(entry, &monitor->patterns, list) {
+               pattern_count++;
+               total_size += sizeof(*pattern) + entry->length;
        }
+
+       cp = kmalloc(total_size, GFP_KERNEL);
+       if (!cp)
+               return -ENOMEM;
+
+       cp->sub_opcode = MSFT_OP_LE_MONITOR_ADVERTISEMENT;
+       cp->rssi_high = monitor->rssi.high_threshold;
+       cp->rssi_low = monitor->rssi.low_threshold;
+       cp->rssi_low_interval = (u8)monitor->rssi.low_threshold_timeout;
+       cp->rssi_sampling_period = monitor->rssi.sampling_period;
+
+       cp->cond_type = MSFT_MONITOR_ADVERTISEMENT_TYPE_PATTERN;
+
+       pattern_data = (void *)cp->data;
+       pattern_data->count = pattern_count;
+
+       list_for_each_entry(entry, &monitor->patterns, list) {
+               pattern = (void *)(pattern_data->data + offset);
+               /* the length also includes data_type and offset */
+               pattern->length = entry->length + 2;
+               pattern->data_type = entry->ad_type;
+               pattern->start_byte = entry->offset;
+               memcpy(pattern->pattern, entry->value, entry->length);
+               offset += sizeof(*pattern) + entry->length;
+       }
+
+       skb = __hci_cmd_sync(hdev, hdev->msft_opcode, total_size, cp,
+                            HCI_CMD_TIMEOUT);
+       kfree(cp);
+
+       if (IS_ERR(skb))
+               return PTR_ERR(skb);
+
+       status = skb->data[0];
+       skb_pull(skb, 1);
+
+       msft_le_monitor_advertisement_cb(hdev, status, hdev->msft_opcode, skb);
+
+       return status;
 }
 
-/* This function requires the caller holds hdev->lock */
-void msft_resume(struct hci_dev *hdev)
+/* This function requires the caller holds hci_req_sync_lock */
+int msft_resume_sync(struct hci_dev *hdev)
 {
        struct msft_data *msft = hdev->msft_data;
+       struct adv_monitor *monitor;
+       int handle = 0;
 
-       if (!msft)
-               return;
+       if (!msft || !msft_monitor_supported(hdev))
+               return 0;
 
-       if (msft_monitor_supported(hdev)) {
-               msft->reregistering = true;
-               /* Monitors are removed on suspend, so we need to add all
-                * monitors on resume.
-                */
-               reregister_monitor(hdev, 0);
+       msft->resuming = true;
+
+       while (1) {
+               monitor = idr_get_next(&hdev->adv_monitors_idr, &handle);
+               if (!monitor)
+                       break;
+
+               msft_add_monitor_sync(hdev, monitor);
+
+               handle++;
        }
+
+       /* All monitors have been resumed */
+       msft->resuming = false;
+
+       return 0;
 }
 
 void msft_do_open(struct hci_dev *hdev)
@@ -275,7 +524,7 @@ void msft_do_open(struct hci_dev *hdev)
        }
 
        if (msft_monitor_supported(hdev)) {
-               msft->reregistering = true;
+               msft->resuming = true;
                msft_set_filter_enable(hdev, true);
                /* Monitors get removed on power off, so we need to explicitly
                 * tell the controller to re-monitor.
@@ -381,151 +630,6 @@ __u64 msft_get_features(struct hci_dev *hdev)
        return msft ? msft->features : 0;
 }
 
-/* is_mgmt = true matches the handle exposed to userspace via mgmt.
- * is_mgmt = false matches the handle used by the msft controller.
- * This function requires the caller holds hdev->lock
- */
-static struct msft_monitor_advertisement_handle_data *msft_find_handle_data
-                               (struct hci_dev *hdev, u16 handle, bool is_mgmt)
-{
-       struct msft_monitor_advertisement_handle_data *entry;
-       struct msft_data *msft = hdev->msft_data;
-
-       list_for_each_entry(entry, &msft->handle_map, list) {
-               if (is_mgmt && entry->mgmt_handle == handle)
-                       return entry;
-               if (!is_mgmt && entry->msft_handle == handle)
-                       return entry;
-       }
-
-       return NULL;
-}
-
-static void msft_le_monitor_advertisement_cb(struct hci_dev *hdev,
-                                            u8 status, u16 opcode,
-                                            struct sk_buff *skb)
-{
-       struct msft_rp_le_monitor_advertisement *rp;
-       struct adv_monitor *monitor;
-       struct msft_monitor_advertisement_handle_data *handle_data;
-       struct msft_data *msft = hdev->msft_data;
-
-       hci_dev_lock(hdev);
-
-       monitor = idr_find(&hdev->adv_monitors_idr, msft->pending_add_handle);
-       if (!monitor) {
-               bt_dev_err(hdev, "msft add advmon: monitor %u is not found!",
-                          msft->pending_add_handle);
-               status = HCI_ERROR_UNSPECIFIED;
-               goto unlock;
-       }
-
-       if (status)
-               goto unlock;
-
-       rp = (struct msft_rp_le_monitor_advertisement *)skb->data;
-       if (skb->len < sizeof(*rp)) {
-               status = HCI_ERROR_UNSPECIFIED;
-               goto unlock;
-       }
-
-       handle_data = kmalloc(sizeof(*handle_data), GFP_KERNEL);
-       if (!handle_data) {
-               status = HCI_ERROR_UNSPECIFIED;
-               goto unlock;
-       }
-
-       handle_data->mgmt_handle = monitor->handle;
-       handle_data->msft_handle = rp->handle;
-       INIT_LIST_HEAD(&handle_data->list);
-       list_add(&handle_data->list, &msft->handle_map);
-
-       monitor->state = ADV_MONITOR_STATE_OFFLOADED;
-
-unlock:
-       if (status && monitor)
-               hci_free_adv_monitor(hdev, monitor);
-
-       /* If in restart/reregister sequence, keep registering. */
-       if (msft->reregistering)
-               reregister_monitor(hdev, msft->pending_add_handle + 1);
-
-       hci_dev_unlock(hdev);
-
-       if (!msft->reregistering)
-               hci_add_adv_patterns_monitor_complete(hdev, status);
-}
-
-static void msft_le_cancel_monitor_advertisement_cb(struct hci_dev *hdev,
-                                                   u8 status, u16 opcode,
-                                                   struct sk_buff *skb)
-{
-       struct msft_cp_le_cancel_monitor_advertisement *cp;
-       struct msft_rp_le_cancel_monitor_advertisement *rp;
-       struct adv_monitor *monitor;
-       struct msft_monitor_advertisement_handle_data *handle_data;
-       struct msft_data *msft = hdev->msft_data;
-       int err;
-       bool pending;
-
-       if (status)
-               goto done;
-
-       rp = (struct msft_rp_le_cancel_monitor_advertisement *)skb->data;
-       if (skb->len < sizeof(*rp)) {
-               status = HCI_ERROR_UNSPECIFIED;
-               goto done;
-       }
-
-       hci_dev_lock(hdev);
-
-       cp = hci_sent_cmd_data(hdev, hdev->msft_opcode);
-       handle_data = msft_find_handle_data(hdev, cp->handle, false);
-
-       if (handle_data) {
-               monitor = idr_find(&hdev->adv_monitors_idr,
-                                  handle_data->mgmt_handle);
-
-               if (monitor && monitor->state == ADV_MONITOR_STATE_OFFLOADED)
-                       monitor->state = ADV_MONITOR_STATE_REGISTERED;
-
-               /* Do not free the monitor if it is being removed due to
-                * suspend. It will be re-monitored on resume.
-                */
-               if (monitor && !msft->suspending)
-                       hci_free_adv_monitor(hdev, monitor);
-
-               list_del(&handle_data->list);
-               kfree(handle_data);
-       }
-
-       /* If in suspend/remove sequence, keep removing. */
-       if (msft->suspending)
-               remove_monitor_on_suspend(hdev,
-                                         msft->pending_remove_handle + 1);
-
-       /* If remove all monitors is required, we need to continue the process
-        * here because the earlier it was paused when waiting for the
-        * response from controller.
-        */
-       if (msft->pending_remove_handle == 0) {
-               pending = hci_remove_all_adv_monitor(hdev, &err);
-               if (pending) {
-                       hci_dev_unlock(hdev);
-                       return;
-               }
-
-               if (err)
-                       status = HCI_ERROR_UNSPECIFIED;
-       }
-
-       hci_dev_unlock(hdev);
-
-done:
-       if (!msft->suspending)
-               hci_remove_adv_monitor_complete(hdev, status);
-}
-
 static void msft_le_set_advertisement_filter_enable_cb(struct hci_dev *hdev,
                                                       u8 status, u16 opcode,
                                                       struct sk_buff *skb)
@@ -560,35 +664,6 @@ static void msft_le_set_advertisement_filter_enable_cb(struct hci_dev *hdev,
        hci_dev_unlock(hdev);
 }
 
-static bool msft_monitor_rssi_valid(struct adv_monitor *monitor)
-{
-       struct adv_rssi_thresholds *r = &monitor->rssi;
-
-       if (r->high_threshold < MSFT_RSSI_THRESHOLD_VALUE_MIN ||
-           r->high_threshold > MSFT_RSSI_THRESHOLD_VALUE_MAX ||
-           r->low_threshold < MSFT_RSSI_THRESHOLD_VALUE_MIN ||
-           r->low_threshold > MSFT_RSSI_THRESHOLD_VALUE_MAX)
-               return false;
-
-       /* High_threshold_timeout is not supported,
-        * once high_threshold is reached, events are immediately reported.
-        */
-       if (r->high_threshold_timeout != 0)
-               return false;
-
-       if (r->low_threshold_timeout > MSFT_RSSI_LOW_TIMEOUT_MAX)
-               return false;
-
-       /* Sampling period from 0x00 to 0xFF are all allowed */
-       return true;
-}
-
-static bool msft_monitor_pattern_valid(struct adv_monitor *monitor)
-{
-       return msft_monitor_rssi_valid(monitor);
-       /* No additional check needed for pattern-based monitor */
-}
-
 /* This function requires the caller holds hdev->lock */
 static int __msft_add_monitor_pattern(struct hci_dev *hdev,
                                      struct adv_monitor *monitor)
@@ -656,7 +731,7 @@ int msft_add_monitor_pattern(struct hci_dev *hdev, struct adv_monitor *monitor)
        if (!msft)
                return -EOPNOTSUPP;
 
-       if (msft->reregistering || msft->suspending)
+       if (msft->resuming || msft->suspending)
                return -EBUSY;
 
        return __msft_add_monitor_pattern(hdev, monitor);
@@ -700,7 +775,7 @@ int msft_remove_monitor(struct hci_dev *hdev, struct adv_monitor *monitor,
        if (!msft)
                return -EOPNOTSUPP;
 
-       if (msft->reregistering || msft->suspending)
+       if (msft->resuming || msft->suspending)
                return -EBUSY;
 
        return __msft_remove_monitor(hdev, monitor, handle);
index 59c6e08..b59b63d 100644 (file)
@@ -24,8 +24,8 @@ int msft_remove_monitor(struct hci_dev *hdev, struct adv_monitor *monitor,
                        u16 handle);
 void msft_req_add_set_filter_enable(struct hci_request *req, bool enable);
 int msft_set_filter_enable(struct hci_dev *hdev, bool enable);
-void msft_suspend(struct hci_dev *hdev);
-void msft_resume(struct hci_dev *hdev);
+int msft_suspend_sync(struct hci_dev *hdev);
+int msft_resume_sync(struct hci_dev *hdev);
 bool msft_curve_validity(struct hci_dev *hdev);
 
 #else
@@ -61,8 +61,15 @@ static inline int msft_set_filter_enable(struct hci_dev *hdev, bool enable)
        return -EOPNOTSUPP;
 }
 
-static inline void msft_suspend(struct hci_dev *hdev) {}
-static inline void msft_resume(struct hci_dev *hdev) {}
+static inline int msft_suspend_sync(struct hci_dev *hdev)
+{
+       return -EOPNOTSUPP;
+}
+
+static inline int msft_resume_sync(struct hci_dev *hdev)
+{
+       return -EOPNOTSUPP;
+}
 
 static inline bool msft_curve_validity(struct hci_dev *hdev)
 {