Commit 89bc22d2 authored by Marcel Holtmann's avatar Marcel Holtmann Committed by Johan Hedberg

Bluetooth: Add quirk for invalid controller address setting

When a Bluetooth controller does not have a valid public Bluetooth
address, then allow the driver to indicate this. If the quirk is
set, the Bluetooth core will switch to unconfigured state first
and will allow userspace to configure the address before starting
the full initialization of the controller.
Signed-off-by: default avatarMarcel Holtmann <marcel@holtmann.org>
Signed-off-by: default avatarJohan Hedberg <johan.hedberg@intel.com>
parent 118305b5
...@@ -110,6 +110,16 @@ enum { ...@@ -110,6 +110,16 @@ enum {
* This quirk must be set before hci_register_dev is called. * This quirk must be set before hci_register_dev is called.
*/ */
HCI_QUIRK_BROKEN_STORED_LINK_KEY, HCI_QUIRK_BROKEN_STORED_LINK_KEY,
/* When this quirk is set, the public Bluetooth address
* initially reported by HCI Read BD Address command
* is considered invalid. Controller configuration is
* required before this device can be used.
*
* This quirk can be set before hci_register_dev is called or
* during the hdev->setup vendor callback.
*/
HCI_QUIRK_INVALID_BDADDR,
}; };
/* HCI device flags */ /* HCI device flags */
......
...@@ -2246,9 +2246,13 @@ static int hci_dev_do_open(struct hci_dev *hdev) ...@@ -2246,9 +2246,13 @@ static int hci_dev_do_open(struct hci_dev *hdev)
atomic_set(&hdev->cmd_cnt, 1); atomic_set(&hdev->cmd_cnt, 1);
set_bit(HCI_INIT, &hdev->flags); set_bit(HCI_INIT, &hdev->flags);
if (hdev->setup && test_bit(HCI_SETUP, &hdev->dev_flags)) if (hdev->setup && test_bit(HCI_SETUP, &hdev->dev_flags)) {
ret = hdev->setup(hdev); ret = hdev->setup(hdev);
if (test_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks))
set_bit(HCI_UNCONFIGURED, &hdev->dev_flags);
}
/* If public address change is configured, ensure that the /* If public address change is configured, ensure that the
* address gets programmed. If the driver does not support * address gets programmed. If the driver does not support
* changing the public address, fail the power on procedure. * changing the public address, fail the power on procedure.
......
...@@ -441,10 +441,22 @@ static int read_unconf_index_list(struct sock *sk, struct hci_dev *hdev, ...@@ -441,10 +441,22 @@ static int read_unconf_index_list(struct sock *sk, struct hci_dev *hdev,
return err; return err;
} }
static __le32 get_missing_options(struct hci_dev *hdev)
{
u32 options = 0;
if (test_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks) &&
!bacmp(&hdev->public_addr, BDADDR_ANY))
options |= MGMT_OPTION_PUBLIC_ADDRESS;
return cpu_to_le32(options);
}
static int read_config_info(struct sock *sk, struct hci_dev *hdev, static int read_config_info(struct sock *sk, struct hci_dev *hdev,
void *data, u16 data_len) void *data, u16 data_len)
{ {
struct mgmt_rp_read_config_info rp; struct mgmt_rp_read_config_info rp;
u32 options = 0;
BT_DBG("sock %p %s", sk, hdev->name); BT_DBG("sock %p %s", sk, hdev->name);
...@@ -452,11 +464,12 @@ static int read_config_info(struct sock *sk, struct hci_dev *hdev, ...@@ -452,11 +464,12 @@ static int read_config_info(struct sock *sk, struct hci_dev *hdev,
memset(&rp, 0, sizeof(rp)); memset(&rp, 0, sizeof(rp));
rp.manufacturer = cpu_to_le16(hdev->manufacturer); rp.manufacturer = cpu_to_le16(hdev->manufacturer);
if (hdev->set_bdaddr) if (hdev->set_bdaddr)
rp.supported_options = cpu_to_le32(MGMT_OPTION_PUBLIC_ADDRESS); options |= MGMT_OPTION_PUBLIC_ADDRESS;
else
rp.supported_options = cpu_to_le32(0); rp.supported_options = cpu_to_le32(options);
rp.missing_options = cpu_to_le32(0); rp.missing_options = get_missing_options(hdev);
hci_dev_unlock(hdev); hci_dev_unlock(hdev);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment