Commit e445dd5f authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'for-upstream' of...

Merge branch 'for-upstream' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next



Johan Hedberg says:

====================
pull request: bluetooth-next 2015-01-16

Here are some more bluetooth & ieee802154 patches intended for 3.20:

 - Refactoring & cleanups of ieee802154 & 6lowpan code
 - Various fixes to the btmrvl driver
 - Fixes for Bluetooth Low Energy Privacy feature handling
 - Added build-time sanity checks for sockaddr sizes
 - Fixes for Security Manager registration on LE-only controllers
 - Refactoring of broken inquiry mode handling to a generic quirk

Please let me know if there are any issues pulling. Thanks.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 3aeb6617 0026b655
......@@ -28,9 +28,9 @@
#define BTM_UPLD_SIZE 2312
/* Time to wait until Host Sleep state change in millisecond */
#define WAIT_UNTIL_HS_STATE_CHANGED 5000
#define WAIT_UNTIL_HS_STATE_CHANGED msecs_to_jiffies(5000)
/* Time to wait for command response in millisecond */
#define WAIT_UNTIL_CMD_RESP 5000
#define WAIT_UNTIL_CMD_RESP msecs_to_jiffies(5000)
enum rdwr_status {
RDWR_STATUS_SUCCESS = 0,
......@@ -104,6 +104,7 @@ struct btmrvl_private {
#ifdef CONFIG_DEBUG_FS
void *debugfs_data;
#endif
bool surprise_removed;
};
#define MRVL_VENDOR_PKT 0xFE
......
......@@ -178,6 +178,11 @@ static int btmrvl_send_sync_cmd(struct btmrvl_private *priv, u16 opcode,
struct sk_buff *skb;
struct hci_command_hdr *hdr;
if (priv->surprise_removed) {
BT_ERR("Card is removed");
return -EFAULT;
}
skb = bt_skb_alloc(HCI_COMMAND_HDR_SIZE + len, GFP_ATOMIC);
if (skb == NULL) {
BT_ERR("No free skb");
......@@ -202,10 +207,14 @@ static int btmrvl_send_sync_cmd(struct btmrvl_private *priv, u16 opcode,
wake_up_interruptible(&priv->main_thread.wait_q);
if (!wait_event_interruptible_timeout(priv->adapter->cmd_wait_q,
priv->adapter->cmd_complete,
msecs_to_jiffies(WAIT_UNTIL_CMD_RESP)))
priv->adapter->cmd_complete ||
priv->surprise_removed,
WAIT_UNTIL_CMD_RESP))
return -ETIMEDOUT;
if (priv->surprise_removed)
return -EFAULT;
return 0;
}
......@@ -287,9 +296,10 @@ int btmrvl_enable_hs(struct btmrvl_private *priv)
}
ret = wait_event_interruptible_timeout(adapter->event_hs_wait_q,
adapter->hs_state,
msecs_to_jiffies(WAIT_UNTIL_HS_STATE_CHANGED));
if (ret < 0) {
adapter->hs_state ||
priv->surprise_removed,
WAIT_UNTIL_HS_STATE_CHANGED);
if (ret < 0 || priv->surprise_removed) {
BT_ERR("event_hs_wait_q terminated (%d): %d,%d,%d",
ret, adapter->hs_state, adapter->ps_state,
adapter->wakeup_tries);
......@@ -538,8 +548,11 @@ static int btmrvl_check_device_tree(struct btmrvl_private *priv)
static int btmrvl_setup(struct hci_dev *hdev)
{
struct btmrvl_private *priv = hci_get_drvdata(hdev);
int ret;
btmrvl_send_module_cfg_cmd(priv, MODULE_BRINGUP_REQ);
ret = btmrvl_send_module_cfg_cmd(priv, MODULE_BRINGUP_REQ);
if (ret)
return ret;
priv->btmrvl_dev.gpio_gap = 0xffff;
......@@ -597,7 +610,7 @@ static int btmrvl_service_main_thread(void *data)
add_wait_queue(&thread->wait_q, &wait);
set_current_state(TASK_INTERRUPTIBLE);
if (kthread_should_stop()) {
if (kthread_should_stop() || priv->surprise_removed) {
BT_DBG("main_thread: break from main thread");
break;
}
......@@ -616,6 +629,11 @@ static int btmrvl_service_main_thread(void *data)
BT_DBG("main_thread woke up");
if (kthread_should_stop() || priv->surprise_removed) {
BT_DBG("main_thread: break from main thread");
break;
}
spin_lock_irqsave(&priv->driver_lock, flags);
if (adapter->int_count) {
adapter->int_count = 0;
......
......@@ -573,7 +573,7 @@ static int btmrvl_sdio_download_fw_w_helper(struct btmrvl_sdio_card *card)
offset += txlen;
} while (true);
BT_DBG("FW download over, size %d bytes", offset);
BT_INFO("FW download over, size %d bytes", offset);
ret = 0;
......@@ -798,6 +798,9 @@ static void btmrvl_sdio_interrupt(struct sdio_func *func)
priv = card->priv;
if (priv->surprise_removed)
return;
if (card->reg->int_read_to_clear)
ret = btmrvl_sdio_read_to_clear(card, &ireg);
else
......@@ -1466,6 +1469,7 @@ static void btmrvl_sdio_remove(struct sdio_func *func)
btmrvl_sdio_disable_host_int(card);
}
BT_DBG("unregester dev");
card->priv->surprise_removed = true;
btmrvl_sdio_unregister_dev(card);
btmrvl_remove_card(card->priv);
}
......
......@@ -49,7 +49,7 @@ static struct usb_driver btusb_driver;
#define BTUSB_INTEL_BOOT 0x200
#define BTUSB_BCM_PATCHRAM 0x400
#define BTUSB_MARVELL 0x800
#define BTUSB_AVM 0x1000
#define BTUSB_SWAVE 0x1000
static const struct usb_device_id btusb_table[] = {
/* Generic Bluetooth USB device */
......@@ -86,7 +86,7 @@ static const struct usb_device_id btusb_table[] = {
{ USB_DEVICE(0x05ac, 0x8281) },
/* AVM BlueFRITZ! USB v2.0 */
{ USB_DEVICE(0x057c, 0x3800), .driver_info = BTUSB_AVM },
{ USB_DEVICE(0x057c, 0x3800), .driver_info = BTUSB_SWAVE },
/* Bluetooth Ultraport Module from IBM */
{ USB_DEVICE(0x04bf, 0x030a) },
......@@ -238,6 +238,9 @@ static const struct usb_device_id blacklist_table[] = {
/* CONWISE Technology based adapters with buggy SCO support */
{ USB_DEVICE(0x0e5e, 0x6622), .driver_info = BTUSB_BROKEN_ISOC },
/* Roper Class 1 Bluetooth Dongle (Silicon Wave based) */
{ USB_DEVICE(0x1300, 0x0001), .driver_info = BTUSB_SWAVE },
/* Digianswer devices */
{ USB_DEVICE(0x08fd, 0x0001), .driver_info = BTUSB_DIGIANSWER },
{ USB_DEVICE(0x08fd, 0x0002), .driver_info = BTUSB_IGNORE },
......@@ -306,6 +309,7 @@ struct btusb_data {
int isoc_altsetting;
int suspend_count;
int (*recv_event)(struct hci_dev *hdev, struct sk_buff *skb);
int (*recv_bulk)(struct btusb_data *data, void *buffer, int count);
};
......@@ -371,7 +375,7 @@ static int btusb_recv_intr(struct btusb_data *data, void *buffer, int count)
if (bt_cb(skb)->expect == 0) {
/* Complete frame */
hci_recv_frame(data->hdev, skb);
data->recv_event(data->hdev, skb);
skb = NULL;
}
}
......@@ -2045,6 +2049,7 @@ static int btusb_probe(struct usb_interface *intf,
init_usb_anchor(&data->isoc_anchor);
spin_lock_init(&data->rxlock);
data->recv_event = hci_recv_frame;
data->recv_bulk = btusb_recv_bulk;
hdev = hci_alloc_dev();
......@@ -2081,8 +2086,10 @@ static int btusb_probe(struct usb_interface *intf,
if (id->driver_info & BTUSB_MARVELL)
hdev->set_bdaddr = btusb_set_bdaddr_marvell;
if (id->driver_info & BTUSB_AVM)
if (id->driver_info & BTUSB_SWAVE) {
set_bit(HCI_QUIRK_FIXUP_INQUIRY_MODE, &hdev->quirks);
set_bit(HCI_QUIRK_BROKEN_LOCAL_COMMANDS, &hdev->quirks);
}
if (id->driver_info & BTUSB_INTEL_BOOT)
set_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks);
......
......@@ -273,7 +273,7 @@ struct l2cap_ctrl {
struct hci_dev;
typedef void (*hci_req_complete_t)(struct hci_dev *hdev, u8 status);
typedef void (*hci_req_complete_t)(struct hci_dev *hdev, u8 status, u16 opcode);
struct hci_req_ctrl {
bool start;
......
......@@ -102,6 +102,18 @@ enum {
*/
HCI_QUIRK_FIXUP_BUFFER_SIZE,
/* When this quirk is set, then a controller that does not
* indicate support for Inquiry Result with RSSI is assumed to
* support it anyway. Some early Bluetooth 1.2 controllers had
* wrongly configured local features that will require forcing
* them to enable this mode. Getting RSSI information with the
* inquiry responses is preferred since it allows for a better
* user expierence.
*
* This quirk must be set before hci_register_dev is called.
*/
HCI_QUIRK_FIXUP_INQUIRY_MODE,
/* When this quirk is set, then the HCI Read Local Supported
* Commands command is not supported. In general Bluetooth 1.2
* and later controllers should support this command. However
......@@ -172,8 +184,7 @@ enum {
*/
enum {
HCI_DUT_MODE,
HCI_FORCE_SC,
HCI_FORCE_LESC,
HCI_FORCE_BREDR_SMP,
HCI_FORCE_STATIC_ADDR,
};
......@@ -844,11 +855,26 @@ struct hci_cp_set_event_flt {
#define HCI_CONN_SETUP_AUTO_OFF 0x01
#define HCI_CONN_SETUP_AUTO_ON 0x02
#define HCI_OP_READ_STORED_LINK_KEY 0x0c0d
struct hci_cp_read_stored_link_key {
bdaddr_t bdaddr;
__u8 read_all;
} __packed;
struct hci_rp_read_stored_link_key {
__u8 status;
__u8 max_keys;
__u8 num_keys;
} __packed;
#define HCI_OP_DELETE_STORED_LINK_KEY 0x0c12
struct hci_cp_delete_stored_link_key {
bdaddr_t bdaddr;
__u8 delete_all;
} __packed;
struct hci_rp_delete_stored_link_key {
__u8 status;
__u8 num_keys;
} __packed;
#define HCI_MAX_NAME_LENGTH 248
......
......@@ -205,6 +205,8 @@ struct hci_dev {
__u16 lmp_subver;
__u16 voice_setting;
__u8 num_iac;
__u8 stored_max_keys;
__u8 stored_num_keys;
__u8 io_capability;
__s8 inq_tx_power;
__u16 page_scan_interval;
......@@ -779,7 +781,6 @@ int hci_conn_check_link_mode(struct hci_conn *conn);
int hci_conn_check_secure(struct hci_conn *conn, __u8 sec_level);
int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type,
bool initiator);
int hci_conn_change_link_key(struct hci_conn *conn);
int hci_conn_switch_role(struct hci_conn *conn, __u8 role);
void hci_conn_enter_active_mode(struct hci_conn *conn, __u8 force_active);
......@@ -1017,8 +1018,7 @@ void hci_conn_del_sysfs(struct hci_conn *conn);
#define hdev_is_powered(hdev) (test_bit(HCI_UP, &hdev->flags) && \
!test_bit(HCI_AUTO_OFF, &hdev->dev_flags))
#define bredr_sc_enabled(dev) ((lmp_sc_capable(dev) || \
test_bit(HCI_FORCE_SC, &(dev)->dbg_flags)) && \
#define bredr_sc_enabled(dev) (lmp_sc_capable(dev) && \
test_bit(HCI_SC_ENABLED, &(dev)->dev_flags))
/* ----- HCI protocols ----- */
......
......@@ -31,7 +31,7 @@
#define VERSION "0.1"
static struct dentry *lowpan_psm_debugfs;
static struct dentry *lowpan_enable_debugfs;
static struct dentry *lowpan_control_debugfs;
#define IFACE_NAME_TEMPLATE "bt%d"
......@@ -55,11 +55,7 @@ struct skb_cb {
static LIST_HEAD(bt_6lowpan_devices);
static DEFINE_SPINLOCK(devices_lock);
/* If psm is set to 0 (default value), then 6lowpan is disabled.
* Other values are used to indicate a Protocol Service Multiplexer
* value for 6lowpan.
*/
static u16 psm_6lowpan;
static bool enable_6lowpan;
/* We are listening incoming connections via this channel
*/
......@@ -761,7 +757,7 @@ static bool is_bt_6lowpan(struct hci_conn *hcon)
if (hcon->type != LE_LINK)
return false;
if (!psm_6lowpan)
if (!enable_6lowpan)
return false;
return true;
......@@ -1085,7 +1081,7 @@ static int bt_6lowpan_connect(bdaddr_t *addr, u8 dst_type)
if (!pchan)
return -EINVAL;
err = l2cap_chan_connect(pchan, cpu_to_le16(psm_6lowpan), 0,
err = l2cap_chan_connect(pchan, cpu_to_le16(L2CAP_PSM_IPSP), 0,
addr, dst_type);
BT_DBG("chan %p err %d", pchan, err);
......@@ -1118,7 +1114,7 @@ static struct l2cap_chan *bt_6lowpan_listen(void)
struct l2cap_chan *pchan;
int err;
if (psm_6lowpan == 0)
if (!enable_6lowpan)
return NULL;
pchan = chan_get();
......@@ -1130,10 +1126,9 @@ static struct l2cap_chan *bt_6lowpan_listen(void)
atomic_set(&pchan->nesting, L2CAP_NESTING_PARENT);
BT_DBG("psm 0x%04x chan %p src type %d", psm_6lowpan, pchan,
pchan->src_type);
BT_DBG("chan %p src type %d", pchan, pchan->src_type);
err = l2cap_add_psm(pchan, addr, cpu_to_le16(psm_6lowpan));
err = l2cap_add_psm(pchan, addr, cpu_to_le16(L2CAP_PSM_IPSP));
if (err) {
l2cap_chan_put(pchan);
BT_ERR("psm cannot be added err %d", err);
......@@ -1219,22 +1214,23 @@ static void disconnect_all_peers(void)
spin_unlock(&devices_lock);
}
struct set_psm {
struct set_enable {
struct work_struct work;
u16 psm;
bool flag;
};
static void do_psm_set(struct work_struct *work)
static void do_enable_set(struct work_struct *work)
{
struct set_psm *set_psm = container_of(work, struct set_psm, work);
struct set_enable *set_enable = container_of(work,
struct set_enable, work);
if (set_psm->psm == 0 || psm_6lowpan != set_psm->psm)
if (!set_enable->flag || enable_6lowpan != set_enable->flag)
/* Disconnect existing connections if 6lowpan is
* disabled (psm = 0), or if psm changes.
* disabled
*/
disconnect_all_peers();
psm_6lowpan = set_psm->psm;
enable_6lowpan = set_enable->flag;
if (listen_chan) {
l2cap_chan_close(listen_chan, 0);
......@@ -1243,33 +1239,33 @@ static void do_psm_set(struct work_struct *work)
listen_chan = bt_6lowpan_listen();
kfree(set_psm);
kfree(set_enable);
}
static int lowpan_psm_set(void *data, u64 val)
static int lowpan_enable_set(void *data, u64 val)
{
struct set_psm *set_psm;
struct set_enable *set_enable;
set_psm = kzalloc(sizeof(*set_psm), GFP_KERNEL);
if (!set_psm)
set_enable = kzalloc(sizeof(*set_enable), GFP_KERNEL);
if (!set_enable)
return -ENOMEM;
set_psm->psm = val;
INIT_WORK(&set_psm->work, do_psm_set);
set_enable->flag = !!val;
INIT_WORK(&set_enable->work, do_enable_set);
schedule_work(&set_psm->work);
schedule_work(&set_enable->work);
return 0;
}
static int lowpan_psm_get(void *data, u64 *val)
static int lowpan_enable_get(void *data, u64 *val)
{
*val = psm_6lowpan;
*val = enable_6lowpan;
return 0;
}
DEFINE_SIMPLE_ATTRIBUTE(lowpan_psm_fops, lowpan_psm_get,
lowpan_psm_set, "%llu\n");
DEFINE_SIMPLE_ATTRIBUTE(lowpan_enable_fops, lowpan_enable_get,
lowpan_enable_set, "%llu\n");
static ssize_t lowpan_control_write(struct file *fp,
const char __user *user_buffer,
......@@ -1439,9 +1435,9 @@ static struct notifier_block bt_6lowpan_dev_notifier = {
static int __init bt_6lowpan_init(void)
{
lowpan_psm_debugfs = debugfs_create_file("6lowpan_psm", 0644,
bt_debugfs, NULL,
&lowpan_psm_fops);
lowpan_enable_debugfs = debugfs_create_file("6lowpan_enable", 0644,
bt_debugfs, NULL,
&lowpan_enable_fops);
lowpan_control_debugfs = debugfs_create_file("6lowpan_control", 0644,
bt_debugfs, NULL,
&lowpan_control_fops);
......@@ -1451,7 +1447,7 @@ static int __init bt_6lowpan_init(void)
static void __exit bt_6lowpan_exit(void)
{
debugfs_remove(lowpan_psm_debugfs);
debugfs_remove(lowpan_enable_debugfs);
debugfs_remove(lowpan_control_debugfs);
if (listen_chan) {
......
......@@ -253,8 +253,6 @@ static void cmtp_recv_interopmsg(struct cmtp_session *session, struct sk_buff *s
if (skb->len < CAPI_MSG_BASELEN + 15)
break;
controller = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 10);
if (!info && ctrl) {
int len = min_t(uint, CAPI_MANUFACTURER_LEN,
skb->data[CAPI_MSG_BASELEN + 14]);
......@@ -270,8 +268,6 @@ static void cmtp_recv_interopmsg(struct cmtp_session *session, struct sk_buff *s
if (skb->len < CAPI_MSG_BASELEN + 32)
break;
controller = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 12);
if (!info && ctrl) {
ctrl->version.majorversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 16);
ctrl->version.minorversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 20);
......@@ -285,8 +281,6 @@ static void cmtp_recv_interopmsg(struct cmtp_session *session, struct sk_buff *s
if (skb->len < CAPI_MSG_BASELEN + 17)
break;
controller = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 12);
if (!info && ctrl) {
int len = min_t(uint, CAPI_SERIAL_LEN,
skb->data[CAPI_MSG_BASELEN + 16]);
......
......@@ -633,7 +633,7 @@ void hci_le_conn_failed(struct hci_conn *conn, u8 status)
mgmt_reenable_advertising(hdev);
}
static void create_le_conn_complete(struct hci_dev *hdev, u8 status)
static void create_le_conn_complete(struct hci_dev *hdev, u8 status, u16 opcode)
{
struct hci_conn *conn;
......@@ -1084,21 +1084,6 @@ int hci_conn_check_secure(struct hci_conn *conn, __u8 sec_level)
}
EXPORT_SYMBOL(hci_conn_check_secure);
/* Change link key */
int hci_conn_change_link_key(struct hci_conn *conn)
{
BT_DBG("hcon %p", conn);
if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->flags)) {
struct hci_cp_change_conn_link_key cp;
cp.handle = cpu_to_le16(conn->handle);
hci_send_cmd(conn->hdev, HCI_OP_CHANGE_CONN_LINK_KEY,
sizeof(cp), &cp);
}
return 0;
}
/* Switch role */
int hci_conn_switch_role(struct hci_conn *conn, __u8 role)
{
......
......@@ -141,7 +141,7 @@ static const struct file_operations dut_mode_fops = {
/* ---- HCI requests ---- */
static void hci_req_sync_complete(struct hci_dev *hdev, u8 result)
static void hci_req_sync_complete(struct hci_dev *hdev, u8 result, u16 opcode)
{
BT_DBG("%s result 0x%2.2x", hdev->name, result);
......@@ -497,43 +497,6 @@ static void le_setup(struct hci_request *req)
set_bit(HCI_LE_ENABLED, &hdev->dev_flags);
}
static u8 hci_get_inquiry_mode(struct hci_dev *hdev)
{
if (lmp_ext_inq_capable(hdev))
return 0x02;
if (lmp_inq_rssi_capable(hdev))
return 0x01;
if (hdev->manufacturer == 11 && hdev->hci_rev == 0x00 &&
hdev->lmp_subver == 0x0757)
return 0x01;
if (hdev->manufacturer == 15) {
if (hdev->hci_rev == 0x03 && hdev->lmp_subver == 0x6963)
return 0x01;
if (hdev->hci_rev == 0x09 && hdev->lmp_subver == 0x6963)
return 0x01;
if (hdev->hci_rev == 0x00 && hdev->lmp_subver == 0x6965)
return 0x01;
}
if (hdev->manufacturer == 31 && hdev->hci_rev == 0x2005 &&
hdev->lmp_subver == 0x1805)
return 0x01;
return 0x00;
}
static void hci_setup_inquiry_mode(struct hci_request *req)
{
u8 mode;
mode = hci_get_inquiry_mode(req->hdev);
hci_req_add(req, HCI_OP_WRITE_INQUIRY_MODE, 1, &mode);
}
static void hci_setup_event_mask(struct hci_request *req)
{
struct hci_dev *hdev = req->hdev;
......@@ -658,8 +621,18 @@ static void hci_init2_req(struct hci_request *req, unsigned long opt)
}
}
if (lmp_inq_rssi_capable(hdev))
hci_setup_inquiry_mode(req);
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);
......@@ -758,27 +731,12 @@ static void hci_init3_req(struct hci_request *req, unsigned long opt)
hci_setup_event_mask(req);
/* 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 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;
if (hdev->commands[6] & 0x20) {
struct hci_cp_read_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);
cp.read_all = 0x01;
hci_req_add(req, HCI_OP_READ_STORED_LINK_KEY, sizeof(cp), &cp);
}
if (hdev->commands[5] & 0x10)
......@@ -872,6 +830,29 @@ static void 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 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;