aboutsummaryrefslogtreecommitdiffstats
diff options
authorStephen Rothwell <sfr@canb.auug.org.au>2022-06-28 11:09:18 +1000
committerStephen Rothwell <sfr@canb.auug.org.au>2022-06-28 11:09:18 +1000
commit1dee38f27563b03541d55ea721795e9fd86e45ba (patch)
tree65c235dbf5339acbc0eeccd25da767ca415ef75f
parent0b823981cccee3b7a391027d7e6bbfdb13e391e1 (diff)
parent681ec6abcd7f051f7fc318068a3ac09772ebef7e (diff)
downloadlinux-next-1dee38f27563b03541d55ea721795e9fd86e45ba.tar.gz
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next.git
-rw-r--r--Documentation/devicetree/bindings/net/broadcom-bluetooth.yaml8
-rw-r--r--drivers/bluetooth/btbcm.c33
-rw-r--r--drivers/bluetooth/btbcm.h8
-rw-r--r--drivers/bluetooth/btmtksdio.c15
-rw-r--r--drivers/bluetooth/btusb.c3
-rw-r--r--drivers/bluetooth/hci_bcm.c17
-rw-r--r--drivers/bluetooth/hci_intel.c6
-rw-r--r--drivers/bluetooth/hci_qca.c2
-rw-r--r--include/net/bluetooth/hci.h1
-rw-r--r--include/net/bluetooth/hci_core.h13
-rw-r--r--net/bluetooth/eir.c41
-rw-r--r--net/bluetooth/hci_conn.c3
-rw-r--r--net/bluetooth/hci_core.c86
-rw-r--r--net/bluetooth/hci_event.c9
-rw-r--r--net/bluetooth/hci_sock.c11
-rw-r--r--net/bluetooth/hci_sync.c66
-rw-r--r--net/bluetooth/l2cap_core.c1
-rw-r--r--net/bluetooth/mgmt.c14
18 files changed, 241 insertions, 96 deletions
diff --git a/Documentation/devicetree/bindings/net/broadcom-bluetooth.yaml b/Documentation/devicetree/bindings/net/broadcom-bluetooth.yaml
index 5aac094fd2172..df59575840fe3 100644
--- a/Documentation/devicetree/bindings/net/broadcom-bluetooth.yaml
+++ b/Documentation/devicetree/bindings/net/broadcom-bluetooth.yaml
@@ -23,6 +23,7 @@ properties:
- brcm,bcm4345c5
- brcm,bcm43540-bt
- brcm,bcm4335a0
+ - brcm,bcm4349-bt
shutdown-gpios:
maxItems: 1
@@ -92,6 +93,13 @@ properties:
pcm-sync-mode: slave, master
pcm-clock-mode: slave, master
+ brcm,requires-autobaud-mode:
+ type: boolean
+ description:
+ Set this property if autobaud mode is required. Autobaud mode is required
+ if the device's initial baud rate in normal mode is not supported by the
+ host or if the device requires autobaud mode startup before loading FW.
+
interrupts:
items:
- description: Handle to the line HOST_WAKE used to wake
diff --git a/drivers/bluetooth/btbcm.c b/drivers/bluetooth/btbcm.c
index 76fbb046bdbe8..3006e2a0f37e1 100644
--- a/drivers/bluetooth/btbcm.c
+++ b/drivers/bluetooth/btbcm.c
@@ -403,6 +403,13 @@ static int btbcm_read_info(struct hci_dev *hdev)
bt_dev_info(hdev, "BCM: chip id %u", skb->data[1]);
kfree_skb(skb);
+ return 0;
+}
+
+static int btbcm_print_controller_features(struct hci_dev *hdev)
+{
+ struct sk_buff *skb;
+
/* Read Controller Features */
skb = btbcm_read_controller_features(hdev);
if (IS_ERR(skb))
@@ -454,6 +461,8 @@ static const struct bcm_subver_table bcm_uart_subver_table[] = {
{ 0x6606, "BCM4345C5" }, /* 003.006.006 */
{ 0x230f, "BCM4356A2" }, /* 001.003.015 */
{ 0x220e, "BCM20702A1" }, /* 001.002.014 */
+ { 0x420d, "BCM4349B1" }, /* 002.002.013 */
+ { 0x420e, "BCM4349B1" }, /* 002.002.014 */
{ 0x4217, "BCM4329B1" }, /* 002.002.023 */
{ 0x6106, "BCM4359C0" }, /* 003.001.006 */
{ 0x4106, "BCM4335A0" }, /* 002.001.006 */
@@ -514,7 +523,7 @@ static const char *btbcm_get_board_name(struct device *dev)
#endif
}
-int btbcm_initialize(struct hci_dev *hdev, bool *fw_load_done)
+int btbcm_initialize(struct hci_dev *hdev, bool *fw_load_done, bool use_autobaud_mode)
{
u16 subver, rev, pid, vid;
struct sk_buff *skb;
@@ -551,9 +560,16 @@ int btbcm_initialize(struct hci_dev *hdev, bool *fw_load_done)
if (err)
return err;
}
- err = btbcm_print_local_name(hdev);
- if (err)
- return err;
+
+ if (!use_autobaud_mode) {
+ err = btbcm_print_controller_features(hdev);
+ if (err)
+ return err;
+
+ err = btbcm_print_local_name(hdev);
+ if (err)
+ return err;
+ }
bcm_subver_table = (hdev->bus == HCI_USB) ? bcm_usb_subver_table :
bcm_uart_subver_table;
@@ -636,13 +652,13 @@ int btbcm_initialize(struct hci_dev *hdev, bool *fw_load_done)
}
EXPORT_SYMBOL_GPL(btbcm_initialize);
-int btbcm_finalize(struct hci_dev *hdev, bool *fw_load_done)
+int btbcm_finalize(struct hci_dev *hdev, bool *fw_load_done, bool use_autobaud_mode)
{
int err;
/* Re-initialize if necessary */
if (*fw_load_done) {
- err = btbcm_initialize(hdev, fw_load_done);
+ err = btbcm_initialize(hdev, fw_load_done, use_autobaud_mode);
if (err)
return err;
}
@@ -658,15 +674,16 @@ EXPORT_SYMBOL_GPL(btbcm_finalize);
int btbcm_setup_patchram(struct hci_dev *hdev)
{
bool fw_load_done = false;
+ bool use_autobaud_mode = false;
int err;
/* Initialize */
- err = btbcm_initialize(hdev, &fw_load_done);
+ err = btbcm_initialize(hdev, &fw_load_done, use_autobaud_mode);
if (err)
return err;
/* Re-initialize after loading Patch */
- return btbcm_finalize(hdev, &fw_load_done);
+ return btbcm_finalize(hdev, &fw_load_done, use_autobaud_mode);
}
EXPORT_SYMBOL_GPL(btbcm_setup_patchram);
diff --git a/drivers/bluetooth/btbcm.h b/drivers/bluetooth/btbcm.h
index 8bf01565fdfca..b4cb24231a202 100644
--- a/drivers/bluetooth/btbcm.h
+++ b/drivers/bluetooth/btbcm.h
@@ -62,8 +62,8 @@ int btbcm_write_pcm_int_params(struct hci_dev *hdev,
int btbcm_setup_patchram(struct hci_dev *hdev);
int btbcm_setup_apple(struct hci_dev *hdev);
-int btbcm_initialize(struct hci_dev *hdev, bool *fw_load_done);
-int btbcm_finalize(struct hci_dev *hdev, bool *fw_load_done);
+int btbcm_initialize(struct hci_dev *hdev, bool *fw_load_done, bool use_autobaud_mode);
+int btbcm_finalize(struct hci_dev *hdev, bool *fw_load_done, bool use_autobaud_mode);
#else
@@ -104,12 +104,12 @@ static inline int btbcm_setup_apple(struct hci_dev *hdev)
return 0;
}
-static inline int btbcm_initialize(struct hci_dev *hdev, bool *fw_load_done)
+static inline int btbcm_initialize(struct hci_dev *hdev, bool *fw_load_done, bool use_autobaud_mode)
{
return 0;
}
-static inline int btbcm_finalize(struct hci_dev *hdev, bool *fw_load_done)
+static inline int btbcm_finalize(struct hci_dev *hdev, bool *fw_load_done, bool use_autobaud_mode)
{
return 0;
}
diff --git a/drivers/bluetooth/btmtksdio.c b/drivers/bluetooth/btmtksdio.c
index d6700efcfe8cd..f9a3444753c2b 100644
--- a/drivers/bluetooth/btmtksdio.c
+++ b/drivers/bluetooth/btmtksdio.c
@@ -1282,6 +1282,13 @@ err:
hci_reset_dev(hdev);
}
+static bool btmtksdio_sdio_inband_wakeup(struct hci_dev *hdev)
+{
+ struct btmtksdio_dev *bdev = hci_get_drvdata(hdev);
+
+ return device_may_wakeup(bdev->dev);
+}
+
static bool btmtksdio_sdio_wakeup(struct hci_dev *hdev)
{
struct btmtksdio_dev *bdev = hci_get_drvdata(hdev);
@@ -1349,6 +1356,14 @@ static int btmtksdio_probe(struct sdio_func *func,
hdev->shutdown = btmtksdio_shutdown;
hdev->send = btmtksdio_send_frame;
hdev->wakeup = btmtksdio_sdio_wakeup;
+ /*
+ * If SDIO controller supports wake on Bluetooth, sending a wakeon
+ * command is not necessary.
+ */
+ if (device_can_wakeup(func->card->host->parent))
+ hdev->wakeup = btmtksdio_sdio_inband_wakeup;
+ else
+ hdev->wakeup = btmtksdio_sdio_wakeup;
hdev->set_bdaddr = btmtk_set_bdaddr;
SET_HCIDEV_DEV(hdev, &func->dev);
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index e25fcd49db702..fb1a671894124 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -477,6 +477,9 @@ static const struct usb_device_id blacklist_table[] = {
{ USB_DEVICE(0x0489, 0xe0d9), .driver_info = BTUSB_MEDIATEK |
BTUSB_WIDEBAND_SPEECH |
BTUSB_VALID_LE_STATES },
+ { USB_DEVICE(0x13d3, 0x3568), .driver_info = BTUSB_MEDIATEK |
+ BTUSB_WIDEBAND_SPEECH |
+ BTUSB_VALID_LE_STATES },
/* Additional Realtek 8723AE Bluetooth devices */
{ USB_DEVICE(0x0930, 0x021d), .driver_info = BTUSB_REALTEK },
diff --git a/drivers/bluetooth/hci_bcm.c b/drivers/bluetooth/hci_bcm.c
index 785f445dd60d5..6f834ff1b44b1 100644
--- a/drivers/bluetooth/hci_bcm.c
+++ b/drivers/bluetooth/hci_bcm.c
@@ -99,6 +99,7 @@ struct bcm_device_data {
* @no_early_set_baudrate: don't set_baudrate before setup()
* @drive_rts_on_open: drive RTS signal on ->open() when platform requires it
* @pcm_int_params: keep the initial PCM configuration
+ * @use_autobaud_mode: start Bluetooth device in autobaud mode
*/
struct bcm_device {
/* Must be the first member, hci_serdev.c expects this. */
@@ -136,6 +137,7 @@ struct bcm_device {
#endif
bool no_early_set_baudrate;
bool drive_rts_on_open;
+ bool use_autobaud_mode;
u8 pcm_int_params[5];
};
@@ -472,7 +474,9 @@ static int bcm_open(struct hci_uart *hu)
out:
if (bcm->dev) {
- if (bcm->dev->drive_rts_on_open)
+ if (bcm->dev->use_autobaud_mode)
+ hci_uart_set_flow_control(hu, false); /* Assert BT_UART_CTS_N */
+ else if (bcm->dev->drive_rts_on_open)
hci_uart_set_flow_control(hu, true);
hu->init_speed = bcm->dev->init_speed;
@@ -564,6 +568,7 @@ static int bcm_setup(struct hci_uart *hu)
{
struct bcm_data *bcm = hu->priv;
bool fw_load_done = false;
+ bool use_autobaud_mode = (bcm->dev ? bcm->dev->use_autobaud_mode : 0);
unsigned int speed;
int err;
@@ -572,7 +577,7 @@ static int bcm_setup(struct hci_uart *hu)
hu->hdev->set_diag = bcm_set_diag;
hu->hdev->set_bdaddr = btbcm_set_bdaddr;
- err = btbcm_initialize(hu->hdev, &fw_load_done);
+ err = btbcm_initialize(hu->hdev, &fw_load_done, use_autobaud_mode);
if (err)
return err;
@@ -616,7 +621,7 @@ static int bcm_setup(struct hci_uart *hu)
btbcm_write_pcm_int_params(hu->hdev, &params);
}
- err = btbcm_finalize(hu->hdev, &fw_load_done);
+ err = btbcm_finalize(hu->hdev, &fw_load_done, use_autobaud_mode);
if (err)
return err;
@@ -1197,6 +1202,11 @@ static int bcm_acpi_probe(struct bcm_device *dev)
static int bcm_of_probe(struct bcm_device *bdev)
{
+ bdev->use_autobaud_mode = device_property_read_bool(bdev->dev,
+ "brcm,requires-autobaud-mode");
+ if (bdev->use_autobaud_mode)
+ bdev->no_early_set_baudrate = true;
+
device_property_read_u32(bdev->dev, "max-speed", &bdev->oper_speed);
device_property_read_u8_array(bdev->dev, "brcm,bt-pcm-int-params",
bdev->pcm_int_params, 5);
@@ -1544,6 +1554,7 @@ static const struct of_device_id bcm_bluetooth_of_match[] = {
{ .compatible = "brcm,bcm43430a0-bt" },
{ .compatible = "brcm,bcm43430a1-bt" },
{ .compatible = "brcm,bcm43438-bt", .data = &bcm43438_device_data },
+ { .compatible = "brcm,bcm4349-bt", .data = &bcm43438_device_data },
{ .compatible = "brcm,bcm43540-bt", .data = &bcm4354_device_data },
{ .compatible = "brcm,bcm4335a0" },
{ },
diff --git a/drivers/bluetooth/hci_intel.c b/drivers/bluetooth/hci_intel.c
index 7249b91d9b91a..78afb9a348e70 100644
--- a/drivers/bluetooth/hci_intel.c
+++ b/drivers/bluetooth/hci_intel.c
@@ -1217,7 +1217,11 @@ static struct platform_driver intel_driver = {
int __init intel_init(void)
{
- platform_driver_register(&intel_driver);
+ int err;
+
+ err = platform_driver_register(&intel_driver);
+ if (err)
+ return err;
return hci_uart_register_proto(&intel_proto);
}
diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c
index eab34e24d9446..8df11016fd51b 100644
--- a/drivers/bluetooth/hci_qca.c
+++ b/drivers/bluetooth/hci_qca.c
@@ -1588,7 +1588,7 @@ static bool qca_wakeup(struct hci_dev *hdev)
wakeup = device_may_wakeup(hu->serdev->ctrl->dev.parent);
bt_dev_dbg(hu->hdev, "wakeup status : %d", wakeup);
- return !wakeup;
+ return wakeup;
}
static int qca_regulator_init(struct hci_uart *hu)
diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index fe7935be7dc44..4a45c48eb0d25 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -361,6 +361,7 @@ enum {
HCI_QUALITY_REPORT,
HCI_OFFLOAD_CODECS_ENABLED,
HCI_LE_SIMULTANEOUS_ROLES,
+ HCI_CMD_DRAIN_WORKQUEUE,
__HCI_NUM_FLAGS,
};
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index c0ea2a4892b16..6d32e3e942b77 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -243,8 +243,10 @@ struct adv_info {
__u16 duration;
__u16 adv_data_len;
__u8 adv_data[HCI_MAX_EXT_AD_LENGTH];
+ bool adv_data_changed;
__u16 scan_rsp_len;
__u8 scan_rsp_data[HCI_MAX_EXT_AD_LENGTH];
+ bool scan_rsp_changed;
__s8 tx_power;
__u32 min_interval;
__u32 max_interval;
@@ -258,6 +260,15 @@ struct adv_info {
#define HCI_ADV_TX_POWER_NO_PREFERENCE 0x7F
+#define DATA_CMP(_d1, _l1, _d2, _l2) \
+ (_l1 == _l2 ? memcmp(_d1, _d2, _l1) : _l1 - _l2)
+
+#define ADV_DATA_CMP(_adv, _data, _len) \
+ DATA_CMP((_adv)->adv_data, (_adv)->adv_data_len, _data, _len)
+
+#define SCAN_RSP_CMP(_adv, _data, _len) \
+ DATA_CMP((_adv)->scan_rsp_data, (_adv)->scan_rsp_len, _data, _len)
+
struct monitored_device {
struct list_head list;
@@ -1286,6 +1297,8 @@ void hci_free_dev(struct hci_dev *hdev);
int hci_register_dev(struct hci_dev *hdev);
void hci_unregister_dev(struct hci_dev *hdev);
void hci_release_dev(struct hci_dev *hdev);
+int hci_register_suspend_notifier(struct hci_dev *hdev);
+int hci_unregister_suspend_notifier(struct hci_dev *hdev);
int hci_suspend_dev(struct hci_dev *hdev);
int hci_resume_dev(struct hci_dev *hdev);
int hci_reset_dev(struct hci_dev *hdev);
diff --git a/net/bluetooth/eir.c b/net/bluetooth/eir.c
index 7d77fb00c2bf3..776d27f7e18d5 100644
--- a/net/bluetooth/eir.c
+++ b/net/bluetooth/eir.c
@@ -13,6 +13,20 @@
#define PNP_INFO_SVCLASS_ID 0x1200
+static u8 eir_append_name(u8 *eir, u16 eir_len, u8 type, u8 *data, u8 data_len)
+{
+ u8 name[HCI_MAX_SHORT_NAME_LENGTH + 1];
+
+ /* If data is already NULL terminated just pass it directly */
+ if (data[data_len - 1] == '\0')
+ return eir_append_data(eir, eir_len, type, data, data_len);
+
+ memcpy(name, data, HCI_MAX_SHORT_NAME_LENGTH);
+ name[HCI_MAX_SHORT_NAME_LENGTH] = '\0';
+
+ return eir_append_data(eir, eir_len, type, name, sizeof(name));
+}
+
u8 eir_append_local_name(struct hci_dev *hdev, u8 *ptr, u8 ad_len)
{
size_t short_len;
@@ -23,29 +37,26 @@ u8 eir_append_local_name(struct hci_dev *hdev, u8 *ptr, u8 ad_len)
return ad_len;
/* use complete name if present and fits */
- complete_len = strlen(hdev->dev_name);
+ complete_len = strnlen(hdev->dev_name, sizeof(hdev->dev_name));
if (complete_len && complete_len <= HCI_MAX_SHORT_NAME_LENGTH)
- return eir_append_data(ptr, ad_len, EIR_NAME_COMPLETE,
+ return eir_append_name(ptr, ad_len, EIR_NAME_COMPLETE,
hdev->dev_name, complete_len + 1);
/* use short name if present */
- short_len = strlen(hdev->short_name);
+ short_len = strnlen(hdev->short_name, sizeof(hdev->short_name));
if (short_len)
- return eir_append_data(ptr, ad_len, EIR_NAME_SHORT,
- hdev->short_name, short_len + 1);
+ return eir_append_name(ptr, ad_len, EIR_NAME_SHORT,
+ hdev->short_name,
+ short_len == HCI_MAX_SHORT_NAME_LENGTH ?
+ short_len : short_len + 1);
/* use shortened full name if present, we already know that name
* is longer then HCI_MAX_SHORT_NAME_LENGTH
*/
- if (complete_len) {
- u8 name[HCI_MAX_SHORT_NAME_LENGTH + 1];
-
- memcpy(name, hdev->dev_name, HCI_MAX_SHORT_NAME_LENGTH);
- name[HCI_MAX_SHORT_NAME_LENGTH] = '\0';
-
- return eir_append_data(ptr, ad_len, EIR_NAME_SHORT, name,
- sizeof(name));
- }
+ if (complete_len)
+ return eir_append_name(ptr, ad_len, EIR_NAME_SHORT,
+ hdev->dev_name,
+ HCI_MAX_SHORT_NAME_LENGTH);
return ad_len;
}
@@ -181,7 +192,7 @@ void eir_create(struct hci_dev *hdev, u8 *data)
u8 *ptr = data;
size_t name_len;
- name_len = strlen(hdev->dev_name);
+ name_len = strnlen(hdev->dev_name, sizeof(hdev->dev_name));
if (name_len > 0) {
/* EIR Data type */
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index ac06c9724c7f3..7829433d54c15 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -118,6 +118,9 @@ static void hci_conn_cleanup(struct hci_conn *conn)
if (test_bit(HCI_CONN_PARAM_REMOVAL_PEND, &conn->flags))
hci_conn_params_del(conn->hdev, &conn->dst, conn->dst_type);
+ if (test_and_clear_bit(HCI_CONN_FLUSH_KEY, &conn->flags))
+ hci_remove_link_key(hdev, &conn->dst);
+
hci_chan_list_flush(conn);
hci_conn_hash_del(hdev, conn);
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 59a5c1341c26a..ca8ee715a36d5 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -593,6 +593,11 @@ static int hci_dev_do_reset(struct hci_dev *hdev)
skb_queue_purge(&hdev->rx_q);
skb_queue_purge(&hdev->cmd_q);
+ /* Cancel these to avoid queueing non-chained pending work */
+ hci_dev_set_flag(hdev, HCI_CMD_DRAIN_WORKQUEUE);
+ cancel_delayed_work(&hdev->cmd_timer);
+ cancel_delayed_work(&hdev->ncmd_timer);
+
/* Avoid potential lockdep warnings from the *_flush() calls by
* ensuring the workqueue is empty up front.
*/
@@ -606,6 +611,8 @@ static int hci_dev_do_reset(struct hci_dev *hdev)
if (hdev->flush)
hdev->flush(hdev);
+ hci_dev_clear_flag(hdev, HCI_CMD_DRAIN_WORKQUEUE);
+
atomic_set(&hdev->cmd_cnt, 1);
hdev->acl_cnt = 0; hdev->sco_cnt = 0; hdev->le_cnt = 0;
@@ -1720,18 +1727,12 @@ int hci_add_adv_instance(struct hci_dev *hdev, u8 instance, u32 flags,
}
adv_instance->flags = flags;
- adv_instance->adv_data_len = adv_data_len;
- adv_instance->scan_rsp_len = scan_rsp_len;
adv_instance->min_interval = min_interval;
adv_instance->max_interval = max_interval;
adv_instance->tx_power = tx_power;
- if (adv_data_len)
- memcpy(adv_instance->adv_data, adv_data, adv_data_len);
-
- if (scan_rsp_len)
- memcpy(adv_instance->scan_rsp_data,
- scan_rsp_data, scan_rsp_len);
+ hci_set_adv_instance_data(hdev, instance, adv_data_len, adv_data,
+ scan_rsp_len, scan_rsp_data);
adv_instance->timeout = timeout;
adv_instance->remaining_time = timeout;
@@ -1754,29 +1755,33 @@ int hci_set_adv_instance_data(struct hci_dev *hdev, u8 instance,
u16 adv_data_len, u8 *adv_data,
u16 scan_rsp_len, u8 *scan_rsp_data)
{
- struct adv_info *adv_instance;
+ struct adv_info *adv;
- adv_instance = hci_find_adv_instance(hdev, instance);
+ adv = hci_find_adv_instance(hdev, instance);
/* If advertisement doesn't exist, we can't modify its data */
- if (!adv_instance)
+ if (!adv)
return -ENOENT;
- if (adv_data_len) {
- memset(adv_instance->adv_data, 0,
- sizeof(adv_instance->adv_data));
- memcpy(adv_instance->adv_data, adv_data, adv_data_len);
- adv_instance->adv_data_len = adv_data_len;
+ if (adv_data_len && ADV_DATA_CMP(adv, adv_data, adv_data_len)) {
+ memset(adv->adv_data, 0, sizeof(adv->adv_data));
+ memcpy(adv->adv_data, adv_data, adv_data_len);
+ adv->adv_data_len = adv_data_len;
+ adv->adv_data_changed = true;
}
- if (scan_rsp_len) {
- memset(adv_instance->scan_rsp_data, 0,
- sizeof(adv_instance->scan_rsp_data));
- memcpy(adv_instance->scan_rsp_data,
- scan_rsp_data, scan_rsp_len);
- adv_instance->scan_rsp_len = scan_rsp_len;
+ if (scan_rsp_len && SCAN_RSP_CMP(adv, scan_rsp_data, scan_rsp_len)) {
+ memset(adv->scan_rsp_data, 0, sizeof(adv->scan_rsp_data));
+ memcpy(adv->scan_rsp_data, scan_rsp_data, scan_rsp_len);
+ adv->scan_rsp_len = scan_rsp_len;
+ adv->scan_rsp_changed = true;
}
+ /* Mark as changed if there are flags which would affect it */
+ if (((adv->flags & MGMT_ADV_FLAG_APPEARANCE) && hdev->appearance) ||
+ adv->flags & MGMT_ADV_FLAG_LOCAL_NAME)
+ adv->scan_rsp_changed = true;
+
return 0;
}
@@ -2639,12 +2644,9 @@ int hci_register_dev(struct hci_dev *hdev)
hci_sock_dev_event(hdev, HCI_DEV_REG);
hci_dev_hold(hdev);
- if (!test_bit(HCI_QUIRK_NO_SUSPEND_NOTIFIER, &hdev->quirks)) {
- hdev->suspend_notifier.notifier_call = hci_suspend_notifier;
- error = register_pm_notifier(&hdev->suspend_notifier);
- if (error)
- goto err_wqueue;
- }
+ error = hci_register_suspend_notifier(hdev);
+ if (error)
+ goto err_wqueue;
queue_work(hdev->req_workqueue, &hdev->power_on);
@@ -2677,8 +2679,7 @@ void hci_unregister_dev(struct hci_dev *hdev)
hci_cmd_sync_clear(hdev);
- if (!test_bit(HCI_QUIRK_NO_SUSPEND_NOTIFIER, &hdev->quirks))
- unregister_pm_notifier(&hdev->suspend_notifier);
+ hci_unregister_suspend_notifier(hdev);
msft_unregister(hdev);
@@ -2742,6 +2743,28 @@ void hci_release_dev(struct hci_dev *hdev)
}
EXPORT_SYMBOL(hci_release_dev);
+int hci_register_suspend_notifier(struct hci_dev *hdev)
+{
+ int ret = 0;
+
+ if (!test_bit(HCI_QUIRK_NO_SUSPEND_NOTIFIER, &hdev->quirks)) {
+ hdev->suspend_notifier.notifier_call = hci_suspend_notifier;
+ ret = register_pm_notifier(&hdev->suspend_notifier);
+ }
+
+ return ret;
+}
+
+int hci_unregister_suspend_notifier(struct hci_dev *hdev)
+{
+ int ret = 0;
+
+ if (!test_bit(HCI_QUIRK_NO_SUSPEND_NOTIFIER, &hdev->quirks))
+ ret = unregister_pm_notifier(&hdev->suspend_notifier);
+
+ return ret;
+}
+
/* Suspend HCI device */
int hci_suspend_dev(struct hci_dev *hdev)
{
@@ -3861,7 +3884,8 @@ static void hci_cmd_work(struct work_struct *work)
if (res < 0)
__hci_cmd_sync_cancel(hdev, -res);
- if (test_bit(HCI_RESET, &hdev->flags))
+ if (test_bit(HCI_RESET, &hdev->flags) ||
+ hci_dev_test_flag(hdev, HCI_CMD_DRAIN_WORKQUEUE))
cancel_delayed_work(&hdev->cmd_timer);
else
schedule_delayed_work(&hdev->cmd_timer,
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index af17dfb20e017..34bec7446d005 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -2741,7 +2741,7 @@ static void hci_cs_disconnect(struct hci_dev *hdev, u8 status)
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))
+ if (test_and_clear_bit(HCI_CONN_FLUSH_KEY, &conn->flags))
hci_remove_link_key(hdev, &conn->dst);
}
@@ -3368,7 +3368,7 @@ static void hci_disconn_complete_evt(struct hci_dev *hdev, void *data,
reason, mgmt_connected);
if (conn->type == ACL_LINK) {
- if (test_bit(HCI_CONN_FLUSH_KEY, &conn->flags))
+ if (test_and_clear_bit(HCI_CONN_FLUSH_KEY, &conn->flags))
hci_remove_link_key(hdev, &conn->dst);
hci_req_update_scan(hdev);
@@ -3768,8 +3768,9 @@ static inline void handle_cmd_cnt_and_timer(struct hci_dev *hdev, u8 ncmd)
cancel_delayed_work(&hdev->ncmd_timer);
atomic_set(&hdev->cmd_cnt, 1);
} else {
- schedule_delayed_work(&hdev->ncmd_timer,
- HCI_NCMD_TIMEOUT);
+ if (!hci_dev_test_flag(hdev, HCI_CMD_DRAIN_WORKQUEUE))
+ schedule_delayed_work(&hdev->ncmd_timer,
+ HCI_NCMD_TIMEOUT);
}
}
}
diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c
index 189e3115c8c62..0d015d4a8e414 100644
--- a/net/bluetooth/hci_sock.c
+++ b/net/bluetooth/hci_sock.c
@@ -869,7 +869,8 @@ static int hci_sock_release(struct socket *sock)
hdev = hci_pi(sk)->hdev;
if (hdev) {
- if (hci_pi(sk)->channel == HCI_CHANNEL_USER) {
+ if (hci_pi(sk)->channel == HCI_CHANNEL_USER &&
+ !hci_dev_test_flag(hdev, HCI_UNREGISTER)) {
/* When releasing a user channel exclusive access,
* call hci_dev_do_close directly instead of calling
* hci_dev_close to ensure the exclusive access will
@@ -878,9 +879,15 @@ static int hci_sock_release(struct socket *sock)
* The checking of HCI_AUTO_OFF is not needed in this
* case since it will have been cleared already when
* opening the user channel.
+ *
+ * Make sure to also check that we haven't already
+ * unregistered since all the cleanup will have already
+ * been complete and hdev will get released when we put
+ * below.
*/
hci_dev_do_close(hdev);
hci_dev_clear_flag(hdev, HCI_USER_CHANNEL);
+ hci_register_suspend_notifier(hdev);
mgmt_index_added(hdev);
}
@@ -1209,6 +1216,7 @@ static int hci_sock_bind(struct socket *sock, struct sockaddr *addr,
}
mgmt_index_removed(hdev);
+ hci_unregister_suspend_notifier(hdev);
err = hci_dev_open(hdev->id);
if (err) {
@@ -1223,6 +1231,7 @@ static int hci_sock_bind(struct socket *sock, struct sockaddr *addr,
err = 0;
} else {
hci_dev_clear_flag(hdev, HCI_USER_CHANNEL);
+ hci_register_suspend_notifier(hdev);
mgmt_index_added(hdev);
hci_dev_put(hdev);
goto done;
diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c
index 286d6767f0177..017b5b70decb9 100644
--- a/net/bluetooth/hci_sync.c
+++ b/net/bluetooth/hci_sync.c
@@ -849,26 +849,38 @@ static int hci_set_ext_scan_rsp_data_sync(struct hci_dev *hdev, u8 instance)
u8 data[HCI_MAX_EXT_AD_LENGTH];
} pdu;
u8 len;
+ struct adv_info *adv = NULL;
+ int err;
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;
+ if (instance) {
+ adv = hci_find_adv_instance(hdev, instance);
+ if (!adv || !adv->scan_rsp_changed)
+ return 0;
+ }
- memcpy(hdev->scan_rsp_data, pdu.data, len);
- hdev->scan_rsp_data_len = len;
+ len = eir_create_scan_rsp(hdev, instance, pdu.data);
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);
+ err = __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_EXT_SCAN_RSP_DATA,
+ sizeof(pdu.cp) + len, &pdu.cp,
+ HCI_CMD_TIMEOUT);
+ if (err)
+ return err;
+
+ if (adv) {
+ adv->scan_rsp_changed = false;
+ } else {
+ memcpy(hdev->scan_rsp_data, pdu.data, len);
+ hdev->scan_rsp_data_len = len;
+ }
+
+ return 0;
}
static int __hci_set_scan_rsp_data_sync(struct hci_dev *hdev, u8 instance)
@@ -1119,27 +1131,39 @@ static int hci_set_ext_adv_data_sync(struct hci_dev *hdev, u8 instance)
u8 data[HCI_MAX_EXT_AD_LENGTH];
} pdu;
u8 len;
+ struct adv_info *adv = NULL;
+ int err;
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;
+ if (instance) {
+ adv = hci_find_adv_instance(hdev, instance);
+ if (!adv || !adv->adv_data_changed)
+ return 0;
+ }
- memcpy(hdev->adv_data, pdu.data, len);
- hdev->adv_data_len = len;
+ len = eir_create_adv_data(hdev, instance, pdu.data);
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);
+ err = __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_EXT_ADV_DATA,
+ sizeof(pdu.cp) + len, &pdu.cp,
+ HCI_CMD_TIMEOUT);
+ if (err)
+ return err;
+
+ /* Update data if the command succeed */
+ if (adv) {
+ adv->adv_data_changed = false;
+ } else {
+ memcpy(hdev->adv_data, pdu.data, len);
+ hdev->adv_data_len = len;
+ }
+
+ return 0;
}
static int hci_set_adv_data_sync(struct hci_dev *hdev, u8 instance)
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index ae78490ecd3d4..09ecaf556de56 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -1369,6 +1369,7 @@ static void l2cap_le_connect(struct l2cap_chan *chan)
l2cap_le_flowctl_init(chan, 0);
+ memset(&req, 0, sizeof(req));
req.psm = chan->psm;
req.scid = cpu_to_le16(chan->scid);
req.mtu = cpu_to_le16(chan->imtu);
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index ae758ab1b558d..f3e4e2c9ec7a7 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -1082,11 +1082,11 @@ static u16 append_eir_data_to_buf(struct hci_dev *hdev, u8 *eir)
eir_len = eir_append_le16(eir, eir_len, EIR_APPEARANCE,
hdev->appearance);
- name_len = strlen(hdev->dev_name);
+ name_len = strnlen(hdev->dev_name, sizeof(hdev->dev_name));
eir_len = eir_append_data(eir, eir_len, EIR_NAME_COMPLETE,
hdev->dev_name, name_len);
- name_len = strlen(hdev->short_name);
+ name_len = strnlen(hdev->short_name, sizeof(hdev->short_name));
eir_len = eir_append_data(eir, eir_len, EIR_NAME_SHORT,
hdev->short_name, name_len);
@@ -6821,11 +6821,14 @@ static int get_conn_info(struct sock *sk, struct hci_dev *hdev, void *data,
cmd = mgmt_pending_new(sk, MGMT_OP_GET_CONN_INFO, hdev, data,
len);
- if (!cmd)
+ if (!cmd) {
err = -ENOMEM;
- else
+ } else {
+ hci_conn_hold(conn);
+ cmd->user_data = hci_conn_get(conn);
err = hci_cmd_sync_queue(hdev, get_conn_info_sync,
cmd, get_conn_info_complete);
+ }
if (err < 0) {
mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
@@ -6837,9 +6840,6 @@ static int get_conn_info(struct sock *sk, struct hci_dev *hdev, void *data,
goto unlock;
}
- hci_conn_hold(conn);
- cmd->user_data = hci_conn_get(conn);
-
conn->conn_info_timestamp = jiffies;
} else {
/* Cache is valid, just reply with values cached in hci_conn */