bluetooth-next pull request for net-next:

- Add support for Foxconn MT7922A
  - Add support for Realtek RTL8852AE
  - Rework HCI event handling to use skb_pull_data
 -----BEGIN PGP SIGNATURE-----
 
 iQJNBAABCAA3FiEE7E6oRXp8w05ovYr/9JCA4xAyCykFAmHMzl8ZHGx1aXoudm9u
 LmRlbnR6QGludGVsLmNvbQAKCRD0kIDjEDILKSpcD/0dP8yVmlPztQwV/O/DjIHc
 rVCplr+pzdOcuW4qXDsKhDt9y5E6KgIhIqnksHV3fM58yY1L6sm9n0Qpihys0mIS
 GHQ7VtqCE8WMpifkCTqdKV34Guy9BP0GGQpWTh7jNTeiwHT1t5pjA6ajYE3qaSS/
 z4opVFz/eGqinPLPxjP7GBP4VqaLG0QMNo3pSz0hi+E/krIwnjT+VoKNKteDkHf9
 klmHrGF2OYtXC8VezvquFgmUgoN+yL/63Ci1DlkF3mRUEc6jMHFMs7BiQov2eENt
 Hq9E1ye5Hlf5IedtJ80QdkLvW/JgE1jZKATB7x7E09j9QBP2gxJRP9z6sSJiVIVm
 53MRRYaA9jOPCfaVPKGMp+4NQMa7F2gahoI1k7LVS0ksc0RGC/nixtdiZWSjwU6E
 cYiQOk5CD3hK+lPSYBvjMOnm+h4w4FZ5W70g5VKKnAGCUBvERSwh2qmUdpG4j1vq
 4oeg64DsLP5n7MWbHn7zbtviiJVbMg+a0D4GlExlxu06OOx7yra3s+LbcHoZbG4B
 T3ivhx9oX+ho7fG3rjBPrENoZB62n48x/mzxsLyFHt/m3uSgsXVSCVIm9dwwsdBM
 P2OzX/dSx/3AhnH0wNPtENAoU4/ETuMOKuFCoU9pL0cjJbQ3M9FipoZakzF/B1se
 18+x0pq2o4PT9W1JUPMfvA==
 =AVll
 -----END PGP SIGNATURE-----

Merge tag 'for-net-next-2021-12-29' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next

Luiz Augusto von Dentz says:

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

 - Add support for Foxconn MT7922A
 - Add support for Realtek RTL8852AE
 - Rework HCI event handling to use skb_pull_data

* tag 'for-net-next-2021-12-29' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next: (62 commits)
  Bluetooth: MGMT: Fix spelling mistake "simultanous" -> "simultaneous"
  Bluetooth: vhci: Set HCI_QUIRK_VALID_LE_STATES
  Bluetooth: MGMT: Fix LE simultaneous roles UUID if not supported
  Bluetooth: hci_sync: Add check simultaneous roles support
  Bluetooth: hci_sync: Wait for proper events when connecting LE
  Bluetooth: hci_sync: Add support for waiting specific LE subevents
  Bluetooth: hci_sync: Add hci_le_create_conn_sync
  Bluetooth: hci_event: Use skb_pull_data when processing inquiry results
  Bluetooth: hci_sync: Push sync command cancellation to workqueue
  Bluetooth: hci_qca: Stop IBS timer during BT OFF
  Bluetooth: btusb: Add support for Foxconn MT7922A
  Bluetooth: btintel: Add missing quirks and msft ext for legacy bootloader
  Bluetooth: btusb: Add two more Bluetooth parts for WCN6855
  Bluetooth: L2CAP: Fix using wrong mode
  Bluetooth: hci_sync: Fix not always pausing advertising when necessary
  Bluetooth: mgmt: Make use of mgmt_send_event_skb in MGMT_EV_DEVICE_CONNECTED
  Bluetooth: mgmt: Make use of mgmt_send_event_skb in MGMT_EV_DEVICE_FOUND
  Bluetooth: mgmt: Introduce mgmt_alloc_skb and mgmt_send_event_skb
  Bluetooth: btusb: Return error code when getting patch status failed
  Bluetooth: btusb: Handle download_firmware failure cases
  ...
====================

Link: https://lore.kernel.org/r/20211229211258.2290966-1-luiz.dentz@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Jakub Kicinski 2021-12-29 14:14:38 -08:00
commit e2dfb94f27
27 changed files with 2794 additions and 2006 deletions

View File

@ -8,6 +8,7 @@
#include <linux/module.h>
#include <linux/firmware.h>
#include <linux/dmi.h>
#include <asm/unaligned.h>
#include <net/bluetooth/bluetooth.h>
@ -343,6 +344,40 @@ static struct sk_buff *btbcm_read_usb_product(struct hci_dev *hdev)
return skb;
}
static const struct dmi_system_id disable_broken_read_transmit_power[] = {
{
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "Apple Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro16,1"),
},
},
{
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "Apple Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro16,2"),
},
},
{
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "Apple Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro16,4"),
},
},
{
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "Apple Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "iMac20,1"),
},
},
{
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "Apple Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "iMac20,2"),
},
},
{ }
};
static int btbcm_read_info(struct hci_dev *hdev)
{
struct sk_buff *skb;
@ -363,6 +398,10 @@ static int btbcm_read_info(struct hci_dev *hdev)
bt_dev_info(hdev, "BCM: features 0x%2.2x", skb->data[1]);
kfree_skb(skb);
/* Read DMI and disable broken Read LE Min/Max Tx Power */
if (dmi_first_match(disable_broken_read_transmit_power))
set_bit(HCI_QUIRK_BROKEN_READ_TRANSMIT_POWER, &hdev->quirks);
return 0;
}

View File

@ -2498,10 +2498,14 @@ static int btintel_setup_combined(struct hci_dev *hdev)
case 0x12: /* ThP */
case 0x13: /* HrP */
case 0x14: /* CcP */
/* Some legacy bootloader devices from JfP supports both old
* and TLV based HCI_Intel_Read_Version command. But we don't
* want to use the TLV based setup routines for those legacy
* bootloader device.
/* Some legacy bootloader devices starting from JfP,
* the operational firmware supports both old and TLV based
* HCI_Intel_Read_Version command based on the command
* parameter.
*
* For upgrading firmware case, the TLV based version cannot
* be used because the firmware filename for legacy bootloader
* is based on the old format.
*
* Also, it is not easy to convert TLV based version from the
* legacy version format.
@ -2513,6 +2517,20 @@ static int btintel_setup_combined(struct hci_dev *hdev)
err = btintel_read_version(hdev, &ver);
if (err)
return err;
/* Apply the device specific HCI quirks
*
* All Legacy bootloader devices support WBS
*/
set_bit(HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED, &hdev->quirks);
/* Valid LE States quirk for JfP/ThP familiy */
if (ver.hw_variant == 0x11 || ver.hw_variant == 0x12)
set_bit(HCI_QUIRK_VALID_LE_STATES, &hdev->quirks);
/* Setup MSFT Extension support */
btintel_set_msft_opcode(hdev, ver.hw_variant);
err = btintel_bootloader_setup(hdev, &ver);
break;
case 0x17:

View File

@ -121,6 +121,7 @@ int btmtk_setup_firmware_79xx(struct hci_dev *hdev, const char *fwname,
} else {
bt_dev_err(hdev, "Failed wmt patch dwnld status (%d)",
status);
err = -EIO;
goto err_release_fw;
}
}

View File

@ -98,6 +98,8 @@ MODULE_DEVICE_TABLE(sdio, btmtksdio_table);
#define MTK_SDIO_BLOCK_SIZE 256
#define BTMTKSDIO_TX_WAIT_VND_EVT 1
#define BTMTKSDIO_HW_TX_READY 2
#define BTMTKSDIO_FUNC_ENABLED 3
struct mtkbtsdio_hdr {
__le16 len;
@ -113,7 +115,6 @@ struct btmtksdio_dev {
struct work_struct txrx_work;
unsigned long tx_state;
struct sk_buff_head txq;
bool hw_tx_ready;
struct sk_buff *evt_skb;
@ -254,7 +255,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;
clear_bit(BTMTKSDIO_HW_TX_READY, &bdev->tx_state);
err = sdio_writesb(bdev->func, MTK_REG_CTDR, skb->data,
round_up(skb->len, MTK_SDIO_BLOCK_SIZE));
if (err < 0)
@ -324,8 +325,29 @@ err_out:
return err;
}
static int btmtksdio_recv_acl(struct hci_dev *hdev, struct sk_buff *skb)
{
struct btmtksdio_dev *bdev = hci_get_drvdata(hdev);
u16 handle = le16_to_cpu(hci_acl_hdr(skb)->handle);
switch (handle) {
case 0xfc6f:
/* Firmware dump from device: when the firmware hangs, the
* device can no longer suspend and thus disable auto-suspend.
*/
pm_runtime_forbid(bdev->dev);
fallthrough;
case 0x05ff:
case 0x05fe:
/* Firmware debug logging */
return hci_recv_diag(hdev, skb);
}
return hci_recv_frame(hdev, skb);
}
static const struct h4_recv_pkt mtk_recv_pkts[] = {
{ H4_RECV_ACL, .recv = hci_recv_frame },
{ H4_RECV_ACL, .recv = btmtksdio_recv_acl },
{ H4_RECV_SCO, .recv = hci_recv_frame },
{ H4_RECV_EVENT, .recv = btmtksdio_recv_event },
};
@ -463,11 +485,12 @@ static void btmtksdio_txrx_work(struct work_struct *work)
bt_dev_dbg(bdev->hdev, "Get fw own back");
if (int_status & TX_EMPTY)
bdev->hw_tx_ready = true;
set_bit(BTMTKSDIO_HW_TX_READY, &bdev->tx_state);
else if (unlikely(int_status & TX_FIFO_OVERFLOW))
bt_dev_warn(bdev->hdev, "Tx fifo overflow");
if (bdev->hw_tx_ready) {
if (test_bit(BTMTKSDIO_HW_TX_READY, &bdev->tx_state)) {
skb = skb_dequeue(&bdev->txq);
if (skb) {
err = btmtksdio_tx_packet(bdev, skb);
@ -517,6 +540,8 @@ static int btmtksdio_open(struct hci_dev *hdev)
if (err < 0)
goto err_release_host;
set_bit(BTMTKSDIO_FUNC_ENABLED, &bdev->tx_state);
/* Get ownership from the device */
sdio_writel(bdev->func, C_FW_OWN_REQ_CLR, MTK_REG_CHLPCR, &err);
if (err < 0)
@ -618,6 +643,7 @@ static int btmtksdio_close(struct hci_dev *hdev)
if (err < 0)
bt_dev_err(bdev->hdev, "Cannot return ownership to device");
clear_bit(BTMTKSDIO_FUNC_ENABLED, &bdev->tx_state);
sdio_disable_func(bdev->func);
sdio_release_host(bdev->func);
@ -765,6 +791,9 @@ static int mt79xx_setup(struct hci_dev *hdev, const char *fwname)
return err;
}
hci_set_msft_opcode(hdev, 0xFD30);
hci_set_aosp_capable(hdev);
return err;
}
@ -811,7 +840,7 @@ static int btmtksdio_setup(struct hci_dev *hdev)
u32 fw_version = 0;
calltime = ktime_get();
bdev->hw_tx_ready = true;
set_bit(BTMTKSDIO_HW_TX_READY, &bdev->tx_state);
switch (bdev->data->chipid) {
case 0x7921:
@ -1036,6 +1065,11 @@ static int btmtksdio_runtime_suspend(struct device *dev)
if (!bdev)
return 0;
if (!test_bit(BTMTKSDIO_FUNC_ENABLED, &bdev->tx_state))
return 0;
sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER);
sdio_claim_host(bdev->func);
sdio_writel(bdev->func, C_FW_OWN_REQ_SET, MTK_REG_CHLPCR, &err);
@ -1063,6 +1097,9 @@ static int btmtksdio_runtime_resume(struct device *dev)
if (!bdev)
return 0;
if (!test_bit(BTMTKSDIO_FUNC_ENABLED, &bdev->tx_state))
return 0;
sdio_claim_host(bdev->func);
sdio_writel(bdev->func, C_FW_OWN_REQ_CLR, MTK_REG_CHLPCR, &err);

View File

@ -16,6 +16,7 @@
#include <linux/of_irq.h>
#include <linux/suspend.h>
#include <linux/gpio/consumer.h>
#include <linux/debugfs.h>
#include <asm/unaligned.h>
#include <net/bluetooth/bluetooth.h>
@ -31,7 +32,6 @@
static bool disable_scofix;
static bool force_scofix;
static bool enable_autosuspend = IS_ENABLED(CONFIG_BT_HCIBTUSB_AUTOSUSPEND);
static bool reset = true;
static struct usb_driver btusb_driver;
@ -296,6 +296,21 @@ static const struct usb_device_id blacklist_table[] = {
{ USB_DEVICE(0x0cf3, 0xe600), .driver_info = BTUSB_QCA_WCN6855 |
BTUSB_WIDEBAND_SPEECH |
BTUSB_VALID_LE_STATES },
{ USB_DEVICE(0x0489, 0xe0cc), .driver_info = BTUSB_QCA_WCN6855 |
BTUSB_WIDEBAND_SPEECH |
BTUSB_VALID_LE_STATES },
{ USB_DEVICE(0x0489, 0xe0d6), .driver_info = BTUSB_QCA_WCN6855 |
BTUSB_WIDEBAND_SPEECH |
BTUSB_VALID_LE_STATES },
{ USB_DEVICE(0x0489, 0xe0e3), .driver_info = BTUSB_QCA_WCN6855 |
BTUSB_WIDEBAND_SPEECH |
BTUSB_VALID_LE_STATES },
{ USB_DEVICE(0x10ab, 0x9309), .driver_info = BTUSB_QCA_WCN6855 |
BTUSB_WIDEBAND_SPEECH |
BTUSB_VALID_LE_STATES },
{ USB_DEVICE(0x10ab, 0x9409), .driver_info = BTUSB_QCA_WCN6855 |
BTUSB_WIDEBAND_SPEECH |
BTUSB_VALID_LE_STATES },
/* Broadcom BCM2035 */
{ USB_DEVICE(0x0a5c, 0x2009), .driver_info = BTUSB_BCM92035 },
@ -385,6 +400,8 @@ static const struct usb_device_id blacklist_table[] = {
/* Realtek 8852AE Bluetooth devices */
{ USB_DEVICE(0x0bda, 0xc852), .driver_info = BTUSB_REALTEK |
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x0bda, 0x385a), .driver_info = BTUSB_REALTEK |
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x0bda, 0x4852), .driver_info = BTUSB_REALTEK |
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x04c5, 0x165c), .driver_info = BTUSB_REALTEK |
@ -424,6 +441,14 @@ static const struct usb_device_id blacklist_table[] = {
BTUSB_WIDEBAND_SPEECH |
BTUSB_VALID_LE_STATES },
/* MediaTek MT7922A Bluetooth devices */
{ USB_DEVICE(0x0489, 0xe0d8), .driver_info = BTUSB_MEDIATEK |
BTUSB_WIDEBAND_SPEECH |
BTUSB_VALID_LE_STATES },
{ USB_DEVICE(0x0489, 0xe0d9), .driver_info = BTUSB_MEDIATEK |
BTUSB_WIDEBAND_SPEECH |
BTUSB_VALID_LE_STATES },
/* Additional Realtek 8723AE Bluetooth devices */
{ USB_DEVICE(0x0930, 0x021d), .driver_info = BTUSB_REALTEK },
{ USB_DEVICE(0x13d3, 0x3394), .driver_info = BTUSB_REALTEK },
@ -550,8 +575,13 @@ struct btusb_data {
unsigned long flags;
bool poll_sync;
int intr_interval;
struct work_struct work;
struct work_struct waker;
struct delayed_work rx_work;
struct sk_buff_head acl_q;
struct usb_anchor deferred;
struct usb_anchor tx_anchor;
@ -716,6 +746,16 @@ static inline void btusb_free_frags(struct btusb_data *data)
spin_unlock_irqrestore(&data->rxlock, flags);
}
static int btusb_recv_event(struct btusb_data *data, struct sk_buff *skb)
{
if (data->intr_interval) {
/* Trigger dequeue immediatelly if an event is received */
schedule_delayed_work(&data->rx_work, 0);
}
return data->recv_event(data->hdev, skb);
}
static int btusb_recv_intr(struct btusb_data *data, void *buffer, int count)
{
struct sk_buff *skb;
@ -761,7 +801,7 @@ static int btusb_recv_intr(struct btusb_data *data, void *buffer, int count)
if (!hci_skb_expect(skb)) {
/* Complete frame */
data->recv_event(data->hdev, skb);
btusb_recv_event(data, skb);
skb = NULL;
}
}
@ -772,6 +812,20 @@ static int btusb_recv_intr(struct btusb_data *data, void *buffer, int count)
return err;
}
static int btusb_recv_acl(struct btusb_data *data, struct sk_buff *skb)
{
/* Only queue ACL packet if intr_interval is set as it means
* force_poll_sync has been enabled.
*/
if (!data->intr_interval)
return data->recv_acl(data->hdev, skb);
skb_queue_tail(&data->acl_q, skb);
schedule_delayed_work(&data->rx_work, data->intr_interval);
return 0;
}
static int btusb_recv_bulk(struct btusb_data *data, void *buffer, int count)
{
struct sk_buff *skb;
@ -819,7 +873,7 @@ static int btusb_recv_bulk(struct btusb_data *data, void *buffer, int count)
if (!hci_skb_expect(skb)) {
/* Complete frame */
data->recv_acl(data->hdev, skb);
btusb_recv_acl(data, skb);
skb = NULL;
}
}
@ -925,6 +979,8 @@ static void btusb_intr_complete(struct urb *urb)
if (err != -EPERM && err != -ENODEV)
bt_dev_err(hdev, "urb %p failed to resubmit (%d)",
urb, -err);
if (err != -EPERM)
hci_cmd_sync_cancel(hdev, -err);
usb_unanchor_urb(urb);
}
}
@ -968,9 +1024,33 @@ static int btusb_submit_intr_urb(struct hci_dev *hdev, gfp_t mem_flags)
if (err != -EPERM && err != -ENODEV)
bt_dev_err(hdev, "urb %p submission failed (%d)",
urb, -err);
if (err != -EPERM)
hci_cmd_sync_cancel(hdev, -err);
usb_unanchor_urb(urb);
}
/* Only initialize intr_interval if URB poll sync is enabled */
if (!data->poll_sync)
goto done;
/* The units are frames (milliseconds) for full and low speed devices,
* and microframes (1/8 millisecond) for highspeed and SuperSpeed
* devices.
*
* This is done once on open/resume so it shouldn't change even if
* force_poll_sync changes.
*/
switch (urb->dev->speed) {
case USB_SPEED_SUPER_PLUS:
case USB_SPEED_SUPER: /* units are 125us */
data->intr_interval = usecs_to_jiffies(urb->interval * 125);
break;
default:
data->intr_interval = msecs_to_jiffies(urb->interval);
break;
}
done:
usb_free_urb(urb);
return err;
@ -1323,10 +1403,13 @@ static void btusb_tx_complete(struct urb *urb)
if (!test_bit(HCI_RUNNING, &hdev->flags))
goto done;
if (!urb->status)
if (!urb->status) {
hdev->stat.byte_tx += urb->transfer_buffer_length;
else
} else {
if (hci_skb_pkt_type(skb) == HCI_COMMAND_PKT)
hci_cmd_sync_cancel(hdev, -urb->status);
hdev->stat.err_tx++;
}
done:
spin_lock_irqsave(&data->txlock, flags);
@ -1430,9 +1513,12 @@ static int btusb_close(struct hci_dev *hdev)
BT_DBG("%s", hdev->name);
cancel_delayed_work(&data->rx_work);
cancel_work_sync(&data->work);
cancel_work_sync(&data->waker);
skb_queue_purge(&data->acl_q);
clear_bit(BTUSB_ISOC_RUNNING, &data->flags);
clear_bit(BTUSB_BULK_RUNNING, &data->flags);
clear_bit(BTUSB_INTR_RUNNING, &data->flags);
@ -1464,6 +1550,10 @@ static int btusb_flush(struct hci_dev *hdev)
BT_DBG("%s", hdev->name);
cancel_delayed_work(&data->rx_work);
skb_queue_purge(&data->acl_q);
usb_kill_anchored_urbs(&data->tx_anchor);
btusb_free_frags(data);
@ -1827,6 +1917,17 @@ static void btusb_waker(struct work_struct *work)
usb_autopm_put_interface(data->intf);
}
static void btusb_rx_work(struct work_struct *work)
{
struct btusb_data *data = container_of(work, struct btusb_data,
rx_work.work);
struct sk_buff *skb;
/* Dequeue ACL data received during the interval */
while ((skb = skb_dequeue(&data->acl_q)))
data->recv_acl(data->hdev, skb);
}
static int btusb_setup_bcm92035(struct hci_dev *hdev)
{
struct sk_buff *skb;
@ -2546,6 +2647,10 @@ static int btusb_mtk_setup(struct hci_dev *hdev)
dev_id & 0xffff, (fw_version & 0xff) + 1);
err = btmtk_setup_firmware_79xx(hdev, fw_bin_name,
btusb_mtk_hci_wmt_sync);
if (err < 0) {
bt_dev_err(hdev, "Failed to set up firmware (%d)", err);
return err;
}
/* It's Device EndPoint Reset Option Register */
btusb_mtk_uhw_reg_write(data, MTK_EP_RST_OPT, MTK_EP_RST_IN_OUT_OPT);
@ -2884,7 +2989,8 @@ struct qca_version {
__le32 rom_version;
__le32 patch_version;
__le32 ram_version;
__le16 board_id;
__u8 chip_id;
__u8 platform_id;
__le16 flag;
__u8 reserved[4];
} __packed;
@ -3073,7 +3179,17 @@ static void btusb_generate_qca_nvm_name(char *fwname, size_t max_size,
u16 flag = le16_to_cpu(ver->flag);
if (((flag >> 8) & 0xff) == QCA_FLAG_MULTI_NVM) {
u16 board_id = le16_to_cpu(ver->board_id);
/* The board_id should be split into two bytes
* The 1st byte is chip ID, and the 2nd byte is platform ID
* For example, board ID 0x010A, 0x01 is platform ID. 0x0A is chip ID
* we have several platforms, and platform IDs are continuously added
* Platform ID:
* 0x00 is for Mobile
* 0x01 is for X86
* 0x02 is for Automotive
* 0x03 is for Consumer electronic
*/
u16 board_id = (ver->chip_id << 8) + ver->platform_id;
const char *variant;
switch (le32_to_cpu(ver->ram_version)) {
@ -3373,6 +3489,49 @@ static int btusb_shutdown_qca(struct hci_dev *hdev)
return 0;
}
static ssize_t force_poll_sync_read(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
struct btusb_data *data = file->private_data;
char buf[3];
buf[0] = data->poll_sync ? 'Y' : 'N';
buf[1] = '\n';
buf[2] = '\0';
return simple_read_from_buffer(user_buf, count, ppos, buf, 2);
}
static ssize_t force_poll_sync_write(struct file *file,
const char __user *user_buf,
size_t count, loff_t *ppos)
{
struct btusb_data *data = file->private_data;
bool enable;
int err;
err = kstrtobool_from_user(user_buf, count, &enable);
if (err)
return err;
/* Only allow changes while the adapter is down */
if (test_bit(HCI_UP, &data->hdev->flags))
return -EPERM;
if (data->poll_sync == enable)
return -EALREADY;
data->poll_sync = enable;
return count;
}
static const struct file_operations force_poll_sync_fops = {
.open = simple_open,
.read = force_poll_sync_read,
.write = force_poll_sync_write,
.llseek = default_llseek,
};
static int btusb_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
@ -3456,6 +3615,10 @@ static int btusb_probe(struct usb_interface *intf,
INIT_WORK(&data->work, btusb_work);
INIT_WORK(&data->waker, btusb_waker);
INIT_DELAYED_WORK(&data->rx_work, btusb_rx_work);
skb_queue_head_init(&data->acl_q);
init_usb_anchor(&data->deferred);
init_usb_anchor(&data->tx_anchor);
spin_lock_init(&data->txlock);
@ -3721,6 +3884,9 @@ static int btusb_probe(struct usb_interface *intf,
usb_set_intfdata(intf, data);
debugfs_create_file("force_poll_sync", 0644, hdev->debugfs, data,
&force_poll_sync_fops);
return 0;
out_free_dev:

View File

@ -1928,6 +1928,9 @@ static int qca_power_off(struct hci_dev *hdev)
hu->hdev->hw_error = NULL;
hu->hdev->cmd_timeout = NULL;
del_timer_sync(&qca->wake_retrans_timer);
del_timer_sync(&qca->tx_idle_timer);
/* Stop sending shutdown command if soc crashes. */
if (soc_type != QCA_ROME
&& qca->memdump_state == QCA_MEMDUMP_IDLE) {

View File

@ -331,6 +331,8 @@ static int __vhci_create_device(struct vhci_data *data, __u8 opcode)
if (opcode & 0x80)
set_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks);
set_bit(HCI_QUIRK_VALID_LE_STATES, &hdev->quirks);
if (hci_register_dev(hdev) < 0) {
BT_ERR("Can't register HCI device");
hci_free_dev(hdev);

View File

@ -2376,6 +2376,8 @@ static inline void *skb_pull_inline(struct sk_buff *skb, unsigned int len)
return unlikely(len > skb->len) ? NULL : __skb_pull(skb, len);
}
void *skb_pull_data(struct sk_buff *skb, size_t len);
void *__pskb_pull_tail(struct sk_buff *skb, int delta);
static inline void *__pskb_pull(struct sk_buff *skb, unsigned int len)

View File

@ -390,6 +390,11 @@ struct hci_ctrl {
};
};
struct mgmt_ctrl {
struct hci_dev *hdev;
u16 opcode;
};
struct bt_skb_cb {
u8 pkt_type;
u8 force_active;
@ -399,6 +404,7 @@ struct bt_skb_cb {
struct l2cap_ctrl l2cap;
struct sco_ctrl sco;
struct hci_ctrl hci;
struct mgmt_ctrl mgmt;
};
};
#define bt_cb(skb) ((struct bt_skb_cb *)((skb)->cb))
@ -406,6 +412,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_event(skb) bt_cb((skb))->hci.req_event
#define hci_skb_sk(skb) bt_cb((skb))->hci.sk
static inline struct sk_buff *bt_skb_alloc(unsigned int len, gfp_t how)

View File

@ -246,6 +246,15 @@ enum {
* HCI after resume.
*/
HCI_QUIRK_NO_SUSPEND_NOTIFIER,
/*
* When this quirk is set, LE tx power is not queried on startup
* and the min/max tx power values default to HCI_TX_POWER_INVALID.
*
* This quirk can be set before hci_register_dev is called or
* during the hdev->setup vendor callback.
*/
HCI_QUIRK_BROKEN_READ_TRANSMIT_POWER,
};
/* HCI device flags */
@ -332,6 +341,7 @@ enum {
HCI_FORCE_NO_MITM,
HCI_QUALITY_REPORT,
HCI_OFFLOAD_CODECS_ENABLED,
HCI_LE_SIMULTANEOUS_ROLES,
__HCI_NUM_FLAGS,
};
@ -1047,8 +1057,8 @@ struct hci_cp_read_stored_link_key {
} __packed;
struct hci_rp_read_stored_link_key {
__u8 status;
__u8 max_keys;
__u8 num_keys;
__le16 max_keys;
__le16 num_keys;
} __packed;
#define HCI_OP_DELETE_STORED_LINK_KEY 0x0c12
@ -1058,7 +1068,7 @@ struct hci_cp_delete_stored_link_key {
} __packed;
struct hci_rp_delete_stored_link_key {
__u8 status;
__u8 num_keys;
__le16 num_keys;
} __packed;
#define HCI_MAX_NAME_LENGTH 248
@ -1931,6 +1941,16 @@ struct hci_rp_le_read_transmit_power {
__s8 max_le_tx_power;
} __packed;
#define HCI_NETWORK_PRIVACY 0x00
#define HCI_DEVICE_PRIVACY 0x01
#define HCI_OP_LE_SET_PRIVACY_MODE 0x204e
struct hci_cp_le_set_privacy_mode {
__u8 bdaddr_type;
bdaddr_t bdaddr;
__u8 mode;
} __packed;
#define HCI_OP_LE_READ_BUFFER_SIZE_V2 0x2060
struct hci_rp_le_read_buffer_size_v2 {
__u8 status;
@ -2012,6 +2032,10 @@ struct hci_cp_le_reject_cis {
} __packed;
/* ---- HCI Events ---- */
struct hci_ev_status {
__u8 status;
} __packed;
#define HCI_EV_INQUIRY_COMPLETE 0x01
#define HCI_EV_INQUIRY_RESULT 0x02
@ -2024,6 +2048,11 @@ struct inquiry_info {
__le16 clock_offset;
} __packed;
struct hci_ev_inquiry_result {
__u8 num;
struct inquiry_info info[];
};
#define HCI_EV_CONN_COMPLETE 0x03
struct hci_ev_conn_complete {
__u8 status;
@ -2135,7 +2164,7 @@ struct hci_comp_pkts_info {
} __packed;
struct hci_ev_num_comp_pkts {
__u8 num_hndl;
__u8 num;
struct hci_comp_pkts_info handles[];
} __packed;
@ -2185,7 +2214,7 @@ struct hci_ev_pscan_rep_mode {
} __packed;
#define HCI_EV_INQUIRY_RESULT_WITH_RSSI 0x22
struct inquiry_info_with_rssi {
struct inquiry_info_rssi {
bdaddr_t bdaddr;
__u8 pscan_rep_mode;
__u8 pscan_period_mode;
@ -2193,7 +2222,7 @@ struct inquiry_info_with_rssi {
__le16 clock_offset;
__s8 rssi;
} __packed;
struct inquiry_info_with_rssi_and_pscan_mode {
struct inquiry_info_rssi_pscan {
bdaddr_t bdaddr;
__u8 pscan_rep_mode;
__u8 pscan_period_mode;
@ -2202,6 +2231,14 @@ struct inquiry_info_with_rssi_and_pscan_mode {
__le16 clock_offset;
__s8 rssi;
} __packed;
struct hci_ev_inquiry_result_rssi {
__u8 num;
struct inquiry_info_rssi info[];
} __packed;
struct hci_ev_inquiry_result_rssi_pscan {
__u8 num;
struct inquiry_info_rssi_pscan info[];
} __packed;
#define HCI_EV_REMOTE_EXT_FEATURES 0x23
struct hci_ev_remote_ext_features {
@ -2256,6 +2293,11 @@ struct extended_inquiry_info {
__u8 data[240];
} __packed;
struct hci_ev_ext_inquiry_result {
__u8 num;
struct extended_inquiry_info info[];
} __packed;
#define HCI_EV_KEY_REFRESH_COMPLETE 0x30
struct hci_ev_key_refresh_complete {
__u8 status;
@ -2423,13 +2465,18 @@ struct hci_ev_le_conn_complete {
#define HCI_EV_LE_ADVERTISING_REPORT 0x02
struct hci_ev_le_advertising_info {
__u8 evt_type;
__u8 type;
__u8 bdaddr_type;
bdaddr_t bdaddr;
__u8 length;
__u8 data[];
} __packed;
struct hci_ev_le_advertising_report {
__u8 num;
struct hci_ev_le_advertising_info info[];
} __packed;
#define HCI_EV_LE_CONN_UPDATE_COMPLETE 0x03
struct hci_ev_le_conn_update_complete {
__u8 status;
@ -2473,7 +2520,7 @@ struct hci_ev_le_data_len_change {
#define HCI_EV_LE_DIRECT_ADV_REPORT 0x0B
struct hci_ev_le_direct_adv_info {
__u8 evt_type;
__u8 type;
__u8 bdaddr_type;
bdaddr_t bdaddr;
__u8 direct_addr_type;
@ -2481,6 +2528,11 @@ struct hci_ev_le_direct_adv_info {
__s8 rssi;
} __packed;
struct hci_ev_le_direct_adv_report {
__u8 num;
struct hci_ev_le_direct_adv_info info[];
} __packed;
#define HCI_EV_LE_PHY_UPDATE_COMPLETE 0x0c
struct hci_ev_le_phy_update_complete {
__u8 status;
@ -2490,8 +2542,8 @@ struct hci_ev_le_phy_update_complete {
} __packed;
#define HCI_EV_LE_EXT_ADV_REPORT 0x0d
struct hci_ev_le_ext_adv_report {
__le16 evt_type;
struct hci_ev_le_ext_adv_info {
__le16 type;
__u8 bdaddr_type;
bdaddr_t bdaddr;
__u8 primary_phy;
@ -2506,6 +2558,11 @@ struct hci_ev_le_ext_adv_report {
__u8 data[];
} __packed;
struct hci_ev_le_ext_adv_report {
__u8 num;
struct hci_ev_le_ext_adv_info info[];
} __packed;
#define HCI_EV_LE_ENHANCED_CONN_COMPLETE 0x0a
struct hci_ev_le_enh_conn_complete {
__u8 status;

View File

@ -88,6 +88,7 @@ struct discovery_state {
u8 (*uuids)[16];
unsigned long scan_start;
unsigned long scan_duration;
unsigned long name_resolve_timeout;
};
#define SUSPEND_NOTIFIER_TIMEOUT msecs_to_jiffies(2000) /* 2 seconds */
@ -151,23 +152,23 @@ struct bdaddr_list_with_irk {
u8 local_irk[16];
};
enum hci_conn_flags {
HCI_CONN_FLAG_REMOTE_WAKEUP,
HCI_CONN_FLAG_DEVICE_PRIVACY,
__HCI_CONN_NUM_FLAGS,
};
/* Make sure number of flags doesn't exceed sizeof(current_flags) */
static_assert(__HCI_CONN_NUM_FLAGS < 32);
struct bdaddr_list_with_flags {
struct list_head list;
bdaddr_t bdaddr;
u8 bdaddr_type;
u32 current_flags;
DECLARE_BITMAP(flags, __HCI_CONN_NUM_FLAGS);
};
enum hci_conn_flags {
HCI_CONN_FLAG_REMOTE_WAKEUP,
HCI_CONN_FLAG_MAX
};
#define hci_conn_test_flag(nr, flags) ((flags) & (1U << nr))
/* Make sure number of flags doesn't exceed sizeof(current_flags) */
static_assert(HCI_CONN_FLAG_MAX < 32);
struct bt_uuid {
struct list_head list;
u8 uuid[16];
@ -352,8 +353,8 @@ struct hci_dev {
__u16 lmp_subver;
__u16 voice_setting;
__u8 num_iac;
__u8 stored_max_keys;
__u8 stored_num_keys;
__u16 stored_max_keys;
__u16 stored_num_keys;
__u8 io_capability;
__s8 inq_tx_power;
__u8 err_data_reporting;
@ -479,6 +480,7 @@ struct hci_dev {
struct work_struct cmd_sync_work;
struct list_head cmd_sync_work_list;
struct mutex cmd_sync_work_lock;
struct work_struct cmd_sync_cancel_work;
__u16 discov_timeout;
struct delayed_work discov_off;
@ -559,6 +561,7 @@ struct hci_dev {
struct rfkill *rfkill;
DECLARE_BITMAP(dev_flags, __HCI_NUM_FLAGS);
DECLARE_BITMAP(conn_flags, __HCI_CONN_NUM_FLAGS);
__s8 adv_tx_power;
__u8 adv_data[HCI_MAX_EXT_AD_LENGTH];
@ -754,7 +757,8 @@ struct hci_conn_params {
struct hci_conn *conn;
bool explicit_connect;
u32 current_flags;
DECLARE_BITMAP(flags, __HCI_CONN_NUM_FLAGS);
u8 privacy_mode;
};
extern struct list_head hci_dev_list;
@ -779,6 +783,12 @@ extern struct mutex hci_cb_list_lock;
hci_dev_clear_flag(hdev, HCI_QUALITY_REPORT); \
} while (0)
#define hci_dev_le_state_simultaneous(hdev) \
(test_bit(HCI_QUIRK_VALID_LE_STATES, &hdev->quirks) && \
(hdev->le_states[4] & 0x08) && /* Central */ \
(hdev->le_states[4] & 0x40) && /* Peripheral */ \
(hdev->le_states[3] & 0x10)) /* Simultaneous */
/* ----- HCI interface to upper protocols ----- */
int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr);
int l2cap_disconn_ind(struct hci_conn *hcon);
@ -1117,8 +1127,7 @@ struct hci_conn *hci_connect_le_scan(struct hci_dev *hdev, bdaddr_t *dst,
enum conn_reasons conn_reason);
struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst,
u8 dst_type, bool dst_resolved, u8 sec_level,
u16 conn_timeout, u8 role,
bdaddr_t *direct_rpa);
u16 conn_timeout, u8 role);
struct hci_conn *hci_connect_acl(struct hci_dev *hdev, bdaddr_t *dst,
u8 sec_level, u8 auth_type,
enum conn_reasons conn_reason);
@ -1465,6 +1474,9 @@ void hci_conn_del_sysfs(struct hci_conn *conn);
#define use_ll_privacy(dev) (ll_privacy_capable(dev) && \
hci_dev_test_flag(dev, HCI_ENABLE_LL_PRIVACY))
#define privacy_mode_capable(dev) (use_ll_privacy(dev) && \
(hdev->commands[39] & 0x04))
/* Use enhanced synchronous connection if command is supported */
#define enhanced_sco_capable(dev) ((dev)->commands[29] & 0x08)
@ -1759,6 +1771,8 @@ void hci_mgmt_chan_unregister(struct hci_mgmt_chan *c);
#define DISCOV_LE_FAST_ADV_INT_MIN 0x00A0 /* 100 msec */
#define DISCOV_LE_FAST_ADV_INT_MAX 0x00F0 /* 150 msec */
#define NAME_RESOLVE_DURATION msecs_to_jiffies(10240) /* 10.24 sec */
void mgmt_fill_version_info(void *ver);
int mgmt_new_settings(struct hci_dev *hdev);
void mgmt_index_added(struct hci_dev *hdev);

View File

@ -37,6 +37,8 @@ int __hci_cmd_sync_status_sk(struct hci_dev *hdev, u16 opcode, u32 plen,
void hci_cmd_sync_init(struct hci_dev *hdev);
void hci_cmd_sync_clear(struct hci_dev *hdev);
void hci_cmd_sync_cancel(struct hci_dev *hdev, int err);
void __hci_cmd_sync_cancel(struct hci_dev *hdev, int err);
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);
@ -100,3 +102,7 @@ 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);
struct hci_conn;
int hci_le_create_conn_sync(struct hci_dev *hdev, struct hci_conn *conn);

View File

@ -940,6 +940,7 @@ struct mgmt_ev_auth_failed {
#define MGMT_DEV_FOUND_LEGACY_PAIRING 0x02
#define MGMT_DEV_FOUND_NOT_CONNECTABLE 0x04
#define MGMT_DEV_FOUND_INITIATED_CONN 0x08
#define MGMT_DEV_FOUND_NAME_REQUEST_FAILED 0x10
#define MGMT_EV_DEVICE_FOUND 0x0012
struct mgmt_ev_device_found {

View File

@ -911,267 +911,45 @@ void hci_le_conn_failed(struct hci_conn *conn, u8 status)
hci_enable_advertising(hdev);
}
static void create_le_conn_complete(struct hci_dev *hdev, u8 status, u16 opcode)
static void create_le_conn_complete(struct hci_dev *hdev, void *data, int err)
{
struct hci_conn *conn;
struct hci_conn *conn = data;
hci_dev_lock(hdev);
conn = hci_lookup_le_connect(hdev);
if (hdev->adv_instance_cnt)
hci_req_resume_adv_instances(hdev);
if (!status) {
if (!err) {
hci_connect_le_scan_cleanup(conn);
goto done;
}
bt_dev_err(hdev, "request failed to create LE connection: "
"status 0x%2.2x", status);
bt_dev_err(hdev, "request failed to create LE connection: err %d", err);
if (!conn)
goto done;
hci_le_conn_failed(conn, status);
hci_le_conn_failed(conn, err);
done:
hci_dev_unlock(hdev);
}
static bool conn_use_rpa(struct hci_conn *conn)
static int hci_connect_le_sync(struct hci_dev *hdev, void *data)
{
struct hci_dev *hdev = conn->hdev;
struct hci_conn *conn = data;
return hci_dev_test_flag(hdev, HCI_PRIVACY);
}
bt_dev_dbg(hdev, "conn %p", conn);
static void set_ext_conn_params(struct hci_conn *conn,
struct hci_cp_le_ext_conn_param *p)
{
struct hci_dev *hdev = conn->hdev;
memset(p, 0, sizeof(*p));
p->scan_interval = cpu_to_le16(hdev->le_scan_int_connect);
p->scan_window = cpu_to_le16(hdev->le_scan_window_connect);
p->conn_interval_min = cpu_to_le16(conn->le_conn_min_interval);
p->conn_interval_max = cpu_to_le16(conn->le_conn_max_interval);
p->conn_latency = cpu_to_le16(conn->le_conn_latency);
p->supervision_timeout = cpu_to_le16(conn->le_supv_timeout);
p->min_ce_len = cpu_to_le16(0x0000);
p->max_ce_len = cpu_to_le16(0x0000);
}
static void hci_req_add_le_create_conn(struct hci_request *req,
struct hci_conn *conn,
bdaddr_t *direct_rpa)
{
struct hci_dev *hdev = conn->hdev;
u8 own_addr_type;
/* If direct address was provided we use it instead of current
* address.
*/
if (direct_rpa) {
if (bacmp(&req->hdev->random_addr, direct_rpa))
hci_req_add(req, HCI_OP_LE_SET_RANDOM_ADDR, 6,
direct_rpa);
/* direct address is always RPA */
own_addr_type = ADDR_LE_DEV_RANDOM;
} else {
/* Update random address, but set require_privacy to false so
* that we never connect with an non-resolvable address.
*/
if (hci_update_random_address(req, false, conn_use_rpa(conn),
&own_addr_type))
return;
}
if (use_ext_conn(hdev)) {
struct hci_cp_le_ext_create_conn *cp;
struct hci_cp_le_ext_conn_param *p;
u8 data[sizeof(*cp) + sizeof(*p) * 3];
u32 plen;
cp = (void *) data;
p = (void *) cp->data;
memset(cp, 0, sizeof(*cp));
bacpy(&cp->peer_addr, &conn->dst);
cp->peer_addr_type = conn->dst_type;
cp->own_addr_type = own_addr_type;
plen = sizeof(*cp);
if (scan_1m(hdev)) {
cp->phys |= LE_SCAN_PHY_1M;
set_ext_conn_params(conn, p);
p++;
plen += sizeof(*p);
}
if (scan_2m(hdev)) {
cp->phys |= LE_SCAN_PHY_2M;
set_ext_conn_params(conn, p);
p++;
plen += sizeof(*p);
}
if (scan_coded(hdev)) {
cp->phys |= LE_SCAN_PHY_CODED;
set_ext_conn_params(conn, p);
plen += sizeof(*p);
}
hci_req_add(req, HCI_OP_LE_EXT_CREATE_CONN, plen, data);
} else {
struct hci_cp_le_create_conn cp;
memset(&cp, 0, sizeof(cp));
cp.scan_interval = cpu_to_le16(hdev->le_scan_int_connect);
cp.scan_window = cpu_to_le16(hdev->le_scan_window_connect);
bacpy(&cp.peer_addr, &conn->dst);
cp.peer_addr_type = conn->dst_type;
cp.own_address_type = own_addr_type;
cp.conn_interval_min = cpu_to_le16(conn->le_conn_min_interval);
cp.conn_interval_max = cpu_to_le16(conn->le_conn_max_interval);
cp.conn_latency = cpu_to_le16(conn->le_conn_latency);
cp.supervision_timeout = cpu_to_le16(conn->le_supv_timeout);
cp.min_ce_len = cpu_to_le16(0x0000);
cp.max_ce_len = cpu_to_le16(0x0000);
hci_req_add(req, HCI_OP_LE_CREATE_CONN, sizeof(cp), &cp);
}
conn->state = BT_CONNECT;
clear_bit(HCI_CONN_SCANNING, &conn->flags);
}
static void hci_req_directed_advertising(struct hci_request *req,
struct hci_conn *conn)
{
struct hci_dev *hdev = req->hdev;
u8 own_addr_type;
u8 enable;
if (ext_adv_capable(hdev)) {
struct hci_cp_le_set_ext_adv_params cp;
bdaddr_t random_addr;
/* Set require_privacy to false so that the remote device has a
* chance of identifying us.
*/
if (hci_get_random_address(hdev, false, conn_use_rpa(conn), NULL,
&own_addr_type, &random_addr) < 0)
return;
memset(&cp, 0, sizeof(cp));
cp.evt_properties = cpu_to_le16(LE_LEGACY_ADV_DIRECT_IND);
cp.own_addr_type = own_addr_type;
cp.channel_map = hdev->le_adv_channel_map;
cp.tx_power = HCI_TX_POWER_INVALID;
cp.primary_phy = HCI_ADV_PHY_1M;
cp.secondary_phy = HCI_ADV_PHY_1M;
cp.handle = 0; /* Use instance 0 for directed adv */
cp.own_addr_type = own_addr_type;
cp.peer_addr_type = conn->dst_type;
bacpy(&cp.peer_addr, &conn->dst);
/* As per Core Spec 5.2 Vol 2, PART E, Sec 7.8.53, for
* advertising_event_property LE_LEGACY_ADV_DIRECT_IND
* does not supports advertising data when the advertising set already
* contains some, the controller shall return erroc code 'Invalid
* HCI Command Parameters(0x12).
* So it is required to remove adv set for handle 0x00. since we use
* instance 0 for directed adv.
*/
__hci_req_remove_ext_adv_instance(req, cp.handle);
hci_req_add(req, HCI_OP_LE_SET_EXT_ADV_PARAMS, sizeof(cp), &cp);
if (own_addr_type == ADDR_LE_DEV_RANDOM &&
bacmp(&random_addr, BDADDR_ANY) &&
bacmp(&random_addr, &hdev->random_addr)) {
struct hci_cp_le_set_adv_set_rand_addr cp;
memset(&cp, 0, sizeof(cp));
cp.handle = 0;
bacpy(&cp.bdaddr, &random_addr);
hci_req_add(req,
HCI_OP_LE_SET_ADV_SET_RAND_ADDR,
sizeof(cp), &cp);
}
__hci_req_enable_ext_advertising(req, 0x00);
} else {
struct hci_cp_le_set_adv_param cp;
/* 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 false so that the remote device has a
* chance of identifying us.
*/
if (hci_update_random_address(req, false, conn_use_rpa(conn),
&own_addr_type) < 0)
return;
memset(&cp, 0, sizeof(cp));
/* Some controllers might reject command if intervals are not
* within range for undirected advertising.
* BCM20702A0 is known to be affected by this.
*/
cp.min_interval = cpu_to_le16(0x0020);
cp.max_interval = cpu_to_le16(0x0020);
cp.type = LE_ADV_DIRECT_IND;
cp.own_address_type = own_addr_type;
cp.direct_addr_type = conn->dst_type;
bacpy(&cp.direct_addr, &conn->dst);
cp.channel_map = hdev->le_adv_channel_map;
hci_req_add(req, HCI_OP_LE_SET_ADV_PARAM, sizeof(cp), &cp);
enable = 0x01;
hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable),
&enable);
}
conn->state = BT_CONNECT;
return hci_le_create_conn_sync(hdev, conn);
}
struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst,
u8 dst_type, bool dst_resolved, u8 sec_level,
u16 conn_timeout, u8 role, bdaddr_t *direct_rpa)
u16 conn_timeout, u8 role)
{
struct hci_conn_params *params;
struct hci_conn *conn;
struct smp_irk *irk;
struct hci_request req;
int err;
/* This ensures that during disable le_scan address resolution
* will not be disabled if it is followed by le_create_conn
*/
bool rpa_le_conn = true;
/* Let's make sure that le is enabled.*/
if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED)) {
if (lmp_le_capable(hdev))
@ -1230,68 +1008,13 @@ struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst,
conn->sec_level = BT_SECURITY_LOW;
conn->conn_timeout = conn_timeout;
hci_req_init(&req, hdev);
conn->state = BT_CONNECT;
clear_bit(HCI_CONN_SCANNING, &conn->flags);
/* Disable advertising if we're active. For central role
* connections most controllers will refuse to connect if
* advertising is enabled, and for peripheral role connections we
* anyway have to disable it in order to start directed
* advertising. Any registered advertisements will be
* re-enabled after the connection attempt is finished.
*/
if (hci_dev_test_flag(hdev, HCI_LE_ADV))
__hci_req_pause_adv_instances(&req);
/* If requested to connect as peripheral use directed advertising */
if (conn->role == HCI_ROLE_SLAVE) {
/* If we're active scanning most controllers are unable
* to initiate advertising. Simply reject the attempt.
*/
if (hci_dev_test_flag(hdev, HCI_LE_SCAN) &&
hdev->le_scan_type == LE_SCAN_ACTIVE) {
hci_req_purge(&req);
hci_conn_del(conn);
return ERR_PTR(-EBUSY);
}
hci_req_directed_advertising(&req, conn);
goto create_conn;
}
params = hci_conn_params_lookup(hdev, &conn->dst, conn->dst_type);
if (params) {
conn->le_conn_min_interval = params->conn_min_interval;
conn->le_conn_max_interval = params->conn_max_interval;
conn->le_conn_latency = params->conn_latency;
conn->le_supv_timeout = params->supervision_timeout;
} else {
conn->le_conn_min_interval = hdev->le_conn_min_interval;
conn->le_conn_max_interval = hdev->le_conn_max_interval;
conn->le_conn_latency = hdev->le_conn_latency;
conn->le_supv_timeout = hdev->le_supv_timeout;
}
/* If controller is scanning, we stop it since some controllers are
* not able to scan and connect at the same time. Also set the
* HCI_LE_SCAN_INTERRUPTED flag so that the command complete
* handler for scan disabling knows to set the correct discovery
* state.
*/
if (hci_dev_test_flag(hdev, HCI_LE_SCAN)) {
hci_req_add_le_scan_disable(&req, rpa_le_conn);
hci_dev_set_flag(hdev, HCI_LE_SCAN_INTERRUPTED);
}
hci_req_add_le_create_conn(&req, conn, direct_rpa);
create_conn:
err = hci_req_run(&req, create_le_conn_complete);
err = hci_cmd_sync_queue(hdev, hci_connect_le_sync, conn,
create_le_conn_complete);
if (err) {
hci_conn_del(conn);
if (hdev->adv_instance_cnt)
hci_req_resume_adv_instances(hdev);
return ERR_PTR(err);
}

View File

@ -2153,7 +2153,7 @@ int hci_bdaddr_list_add_with_flags(struct list_head *list, bdaddr_t *bdaddr,
bacpy(&entry->bdaddr, bdaddr);
entry->bdaddr_type = type;
entry->current_flags = flags;
bitmap_from_u64(entry->flags, flags);
list_add(&entry->list, list);
@ -2629,6 +2629,12 @@ int hci_register_dev(struct hci_dev *hdev)
if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
hci_dev_set_flag(hdev, HCI_UNCONFIGURED);
/* Mark Remote Wakeup connection flag as supported if driver has wakeup
* callback.
*/
if (hdev->wakeup)
set_bit(HCI_CONN_FLAG_REMOTE_WAKEUP, hdev->conn_flags);
hci_sock_dev_event(hdev, HCI_DEV_REG);
hci_dev_hold(hdev);
@ -2906,7 +2912,7 @@ int hci_unregister_cb(struct hci_cb *cb)
}
EXPORT_SYMBOL(hci_unregister_cb);
static void hci_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
static int hci_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
{
int err;
@ -2929,14 +2935,17 @@ static void hci_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
if (!test_bit(HCI_RUNNING, &hdev->flags)) {
kfree_skb(skb);
return;
return -EINVAL;
}
err = hdev->send(hdev, skb);
if (err < 0) {
bt_dev_err(hdev, "sending frame failed (%d)", err);
kfree_skb(skb);
return err;
}
return 0;
}
/* Send HCI command */
@ -3843,10 +3852,15 @@ static void hci_cmd_work(struct work_struct *work)
hdev->sent_cmd = skb_clone(skb, GFP_KERNEL);
if (hdev->sent_cmd) {
int res;
if (hci_req_status_pend(hdev))
hci_dev_set_flag(hdev, HCI_CMD_PENDING);
atomic_dec(&hdev->cmd_cnt);
hci_send_frame(hdev, skb);
res = hci_send_frame(hdev, skb);
if (res < 0)
__hci_cmd_sync_cancel(hdev, -res);
if (test_bit(HCI_RESET, &hdev->flags))
cancel_delayed_work(&hdev->cmd_timer);
else

File diff suppressed because it is too large Load Diff

View File

@ -111,17 +111,6 @@ void hci_req_sync_complete(struct hci_dev *hdev, u8 result, u16 opcode,
}
}
void hci_req_sync_cancel(struct hci_dev *hdev, int err)
{
bt_dev_dbg(hdev, "err 0x%2.2x", err);
if (hdev->req_status == HCI_REQ_PEND) {
hdev->req_result = err;
hdev->req_status = HCI_REQ_CANCELED;
wake_up_interruptible(&hdev->req_wait_q);
}
}
/* Execute request and wait for completion. */
int __hci_req_sync(struct hci_dev *hdev, int (*func)(struct hci_request *req,
unsigned long opt),
@ -492,8 +481,8 @@ static int add_to_accept_list(struct hci_request *req,
}
/* During suspend, only wakeable devices can be in accept list */
if (hdev->suspended && !hci_conn_test_flag(HCI_CONN_FLAG_REMOTE_WAKEUP,
params->current_flags))
if (hdev->suspended &&
!test_bit(HCI_CONN_FLAG_REMOTE_WAKEUP, params->flags))
return 0;
*num_entries += 1;
@ -829,56 +818,6 @@ static void cancel_adv_timeout(struct hci_dev *hdev)
}
}
/* This function requires the caller holds hdev->lock */
void __hci_req_pause_adv_instances(struct hci_request *req)
{
bt_dev_dbg(req->hdev, "Pausing advertising instances");
/* Call to disable any advertisements active on the controller.
* This will succeed even if no advertisements are configured.
*/
__hci_req_disable_advertising(req);
/* If we are using software rotation, pause the loop */
if (!ext_adv_capable(req->hdev))
cancel_adv_timeout(req->hdev);
}
/* This function requires the caller holds hdev->lock */
static void __hci_req_resume_adv_instances(struct hci_request *req)
{
struct adv_info *adv;
bt_dev_dbg(req->hdev, "Resuming advertising instances");
if (ext_adv_capable(req->hdev)) {
/* Call for each tracked instance to be re-enabled */
list_for_each_entry(adv, &req->hdev->adv_instances, list) {
__hci_req_enable_ext_advertising(req,
adv->instance);
}
} else {
/* Schedule for most recent instance to be restarted and begin
* the software rotation loop
*/
__hci_req_schedule_adv_instance(req,
req->hdev->cur_adv_instance,
true);
}
}
/* This function requires the caller holds hdev->lock */
int hci_req_resume_adv_instances(struct hci_dev *hdev)
{
struct hci_request req;
hci_req_init(&req, hdev);
__hci_req_resume_adv_instances(&req);
return hci_req_run(&req, NULL);
}
static bool adv_cur_instance_is_scannable(struct hci_dev *hdev)
{
return hci_adv_instance_is_scannable(hdev, hdev->cur_adv_instance);
@ -2703,7 +2642,7 @@ void hci_request_setup(struct hci_dev *hdev)
void hci_request_cancel_all(struct hci_dev *hdev)
{
hci_req_sync_cancel(hdev, ENODEV);
__hci_cmd_sync_cancel(hdev, ENODEV);
cancel_work_sync(&hdev->discov_update);
cancel_work_sync(&hdev->scan_update);

View File

@ -64,7 +64,6 @@ int hci_req_sync(struct hci_dev *hdev, int (*req)(struct hci_request *req,
int __hci_req_sync(struct hci_dev *hdev, int (*func)(struct hci_request *req,
unsigned long opt),
unsigned long opt, u32 timeout, u8 *hci_status);
void hci_req_sync_cancel(struct hci_dev *hdev, int err);
struct sk_buff *hci_prepare_cmd(struct hci_dev *hdev, u16 opcode, u32 plen,
const void *param);
@ -81,8 +80,6 @@ void hci_req_add_le_passive_scan(struct hci_request *req);
void hci_req_prepare_suspend(struct hci_dev *hdev, enum suspended_state next);
void hci_req_disable_address_resolution(struct hci_dev *hdev);
void __hci_req_pause_adv_instances(struct hci_request *req);
int hci_req_resume_adv_instances(struct hci_dev *hdev);
void hci_req_reenable_advertising(struct hci_dev *hdev);
void __hci_req_enable_advertising(struct hci_request *req);
void __hci_req_disable_advertising(struct hci_request *req);

View File

@ -103,7 +103,7 @@ static void hci_cmd_sync_add(struct hci_request *req, u16 opcode, u32 plen,
if (skb_queue_empty(&req->cmd_q))
bt_cb(skb)->hci.req_flags |= HCI_REQ_START;
bt_cb(skb)->hci.req_event = event;
hci_skb_event(skb) = event;
skb_queue_tail(&req->cmd_q, skb);
}
@ -313,11 +313,24 @@ static void hci_cmd_sync_work(struct work_struct *work)
}
}
static void hci_cmd_sync_cancel_work(struct work_struct *work)
{
struct hci_dev *hdev = container_of(work, struct hci_dev, cmd_sync_cancel_work);
cancel_delayed_work_sync(&hdev->cmd_timer);
cancel_delayed_work_sync(&hdev->ncmd_timer);
atomic_set(&hdev->cmd_cnt, 1);
wake_up_interruptible(&hdev->req_wait_q);
}
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);
INIT_WORK(&hdev->cmd_sync_cancel_work, hci_cmd_sync_cancel_work);
}
void hci_cmd_sync_clear(struct hci_dev *hdev)
@ -335,6 +348,35 @@ void hci_cmd_sync_clear(struct hci_dev *hdev)
}
}
void __hci_cmd_sync_cancel(struct hci_dev *hdev, int err)
{
bt_dev_dbg(hdev, "err 0x%2.2x", err);
if (hdev->req_status == HCI_REQ_PEND) {
hdev->req_result = err;
hdev->req_status = HCI_REQ_CANCELED;
cancel_delayed_work_sync(&hdev->cmd_timer);
cancel_delayed_work_sync(&hdev->ncmd_timer);
atomic_set(&hdev->cmd_cnt, 1);
wake_up_interruptible(&hdev->req_wait_q);
}
}
void hci_cmd_sync_cancel(struct hci_dev *hdev, int err)
{
bt_dev_dbg(hdev, "err 0x%2.2x", err);
if (hdev->req_status == HCI_REQ_PEND) {
hdev->req_result = err;
hdev->req_status = HCI_REQ_CANCELED;
queue_work(hdev->workqueue, &hdev->cmd_sync_cancel_work);
}
}
EXPORT_SYMBOL(hci_cmd_sync_cancel);
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)
{
@ -1580,8 +1622,40 @@ done:
sizeof(cp), &cp, HCI_CMD_TIMEOUT);
}
/* Set Device Privacy Mode. */
static int hci_le_set_privacy_mode_sync(struct hci_dev *hdev,
struct hci_conn_params *params)
{
struct hci_cp_le_set_privacy_mode cp;
struct smp_irk *irk;
/* If device privacy mode has already been set there is nothing to do */
if (params->privacy_mode == HCI_DEVICE_PRIVACY)
return 0;
/* Check if HCI_CONN_FLAG_DEVICE_PRIVACY has been set as it also
* indicates that LL Privacy has been enabled and
* HCI_OP_LE_SET_PRIVACY_MODE is supported.
*/
if (!test_bit(HCI_CONN_FLAG_DEVICE_PRIVACY, params->flags))
return 0;
irk = hci_find_irk_by_addr(hdev, &params->addr, params->addr_type);
if (!irk)
return 0;
memset(&cp, 0, sizeof(cp));
cp.bdaddr_type = irk->addr_type;
bacpy(&cp.bdaddr, &irk->bdaddr);
cp.mode = HCI_DEVICE_PRIVACY;
return __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_PRIVACY_MODE,
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.
* this attempts to program the device in the resolving list as well and
* properly set the privacy mode.
*/
static int hci_le_add_accept_list_sync(struct hci_dev *hdev,
struct hci_conn_params *params,
@ -1590,11 +1664,6 @@ static int hci_le_add_accept_list_sync(struct hci_dev *hdev,
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;
@ -1606,8 +1675,8 @@ static int hci_le_add_accept_list_sync(struct hci_dev *hdev,
}
/* During suspend, only wakeable devices can be in acceptlist */
if (hdev->suspended && !hci_conn_test_flag(HCI_CONN_FLAG_REMOTE_WAKEUP,
params->current_flags))
if (hdev->suspended &&
!test_bit(HCI_CONN_FLAG_REMOTE_WAKEUP, params->flags))
return 0;
/* Attempt to program the device in the resolving list first to avoid
@ -1620,6 +1689,18 @@ static int hci_le_add_accept_list_sync(struct hci_dev *hdev,
return err;
}
/* Set Privacy Mode */
err = hci_le_set_privacy_mode_sync(hdev, params);
if (err) {
bt_dev_err(hdev, "Unable to set privacy mode: %d", err);
return err;
}
/* Check if already in accept list */
if (hci_bdaddr_list_lookup(&hdev->le_accept_list, &params->addr,
params->addr_type))
return 0;
*num_entries += 1;
cp.bdaddr_type = params->addr_type;
bacpy(&cp.bdaddr, &params->addr);
@ -1645,10 +1726,8 @@ 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)
/* If already been paused there is nothing to do. */
if (hdev->advertising_paused)
return 0;
bt_dev_dbg(hdev, "Pausing directed advertising");
@ -3283,7 +3362,8 @@ static int hci_le_read_adv_tx_power_sync(struct hci_dev *hdev)
/* Read LE Min/Max Tx Power*/
static int hci_le_read_tx_power_sync(struct hci_dev *hdev)
{
if (!(hdev->commands[38] & 0x80))
if (!(hdev->commands[38] & 0x80) ||
test_bit(HCI_QUIRK_BROKEN_READ_TRANSMIT_POWER, &hdev->quirks))
return 0;
return __hci_cmd_sync_status(hdev, HCI_OP_LE_READ_TRANSMIT_POWER,
@ -4749,8 +4829,7 @@ static int hci_update_event_filter_sync(struct hci_dev *hdev)
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))
if (!test_bit(HCI_CONN_FLAG_REMOTE_WAKEUP, b->flags))
continue;
bt_dev_dbg(hdev, "Adding event filters for %pMR", &b->bdaddr);
@ -4920,3 +4999,283 @@ int hci_resume_sync(struct hci_dev *hdev)
return 0;
}
static bool conn_use_rpa(struct hci_conn *conn)
{
struct hci_dev *hdev = conn->hdev;
return hci_dev_test_flag(hdev, HCI_PRIVACY);
}
static int hci_le_ext_directed_advertising_sync(struct hci_dev *hdev,
struct hci_conn *conn)
{
struct hci_cp_le_set_ext_adv_params cp;
int err;
bdaddr_t random_addr;
u8 own_addr_type;
err = hci_update_random_address_sync(hdev, false, conn_use_rpa(conn),
&own_addr_type);
if (err)
return err;
/* Set require_privacy to false so that the remote device has a
* chance of identifying us.
*/
err = hci_get_random_address(hdev, false, conn_use_rpa(conn), NULL,
&own_addr_type, &random_addr);
if (err)
return err;
memset(&cp, 0, sizeof(cp));
cp.evt_properties = cpu_to_le16(LE_LEGACY_ADV_DIRECT_IND);
cp.own_addr_type = own_addr_type;
cp.channel_map = hdev->le_adv_channel_map;
cp.tx_power = HCI_TX_POWER_INVALID;
cp.primary_phy = HCI_ADV_PHY_1M;
cp.secondary_phy = HCI_ADV_PHY_1M;
cp.handle = 0x00; /* Use instance 0 for directed adv */
cp.own_addr_type = own_addr_type;
cp.peer_addr_type = conn->dst_type;
bacpy(&cp.peer_addr, &conn->dst);
/* As per Core Spec 5.2 Vol 2, PART E, Sec 7.8.53, for
* advertising_event_property LE_LEGACY_ADV_DIRECT_IND
* does not supports advertising data when the advertising set already
* contains some, the controller shall return erroc code 'Invalid
* HCI Command Parameters(0x12).
* So it is required to remove adv set for handle 0x00. since we use
* instance 0 for directed adv.
*/
err = hci_remove_ext_adv_instance_sync(hdev, cp.handle, NULL);
if (err)
return err;
err = __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_EXT_ADV_PARAMS,
sizeof(cp), &cp, HCI_CMD_TIMEOUT);
if (err)
return err;
/* Check if random address need to be updated */
if (own_addr_type == ADDR_LE_DEV_RANDOM &&
bacmp(&random_addr, BDADDR_ANY) &&
bacmp(&random_addr, &hdev->random_addr)) {
err = hci_set_adv_set_random_addr_sync(hdev, 0x00,
&random_addr);
if (err)
return err;
}
return hci_enable_ext_advertising_sync(hdev, 0x00);
}
static int hci_le_directed_advertising_sync(struct hci_dev *hdev,
struct hci_conn *conn)
{
struct hci_cp_le_set_adv_param cp;
u8 status;
u8 own_addr_type;
u8 enable;
if (ext_adv_capable(hdev))
return hci_le_ext_directed_advertising_sync(hdev, conn);
/* 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 false so that the remote device has a
* chance of identifying us.
*/
status = hci_update_random_address_sync(hdev, false, conn_use_rpa(conn),
&own_addr_type);
if (status)
return status;
memset(&cp, 0, sizeof(cp));
/* Some controllers might reject command if intervals are not
* within range for undirected advertising.
* BCM20702A0 is known to be affected by this.
*/
cp.min_interval = cpu_to_le16(0x0020);
cp.max_interval = cpu_to_le16(0x0020);
cp.type = LE_ADV_DIRECT_IND;
cp.own_address_type = own_addr_type;
cp.direct_addr_type = conn->dst_type;
bacpy(&cp.direct_addr, &conn->dst);
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;
enable = 0x01;
return __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_ADV_ENABLE,
sizeof(enable), &enable, HCI_CMD_TIMEOUT);
}
static void set_ext_conn_params(struct hci_conn *conn,
struct hci_cp_le_ext_conn_param *p)
{
struct hci_dev *hdev = conn->hdev;
memset(p, 0, sizeof(*p));
p->scan_interval = cpu_to_le16(hdev->le_scan_int_connect);
p->scan_window = cpu_to_le16(hdev->le_scan_window_connect);
p->conn_interval_min = cpu_to_le16(conn->le_conn_min_interval);
p->conn_interval_max = cpu_to_le16(conn->le_conn_max_interval);
p->conn_latency = cpu_to_le16(conn->le_conn_latency);
p->supervision_timeout = cpu_to_le16(conn->le_supv_timeout);
p->min_ce_len = cpu_to_le16(0x0000);
p->max_ce_len = cpu_to_le16(0x0000);
}
int hci_le_ext_create_conn_sync(struct hci_dev *hdev, struct hci_conn *conn,
u8 own_addr_type)
{
struct hci_cp_le_ext_create_conn *cp;
struct hci_cp_le_ext_conn_param *p;
u8 data[sizeof(*cp) + sizeof(*p) * 3];
u32 plen;
cp = (void *)data;
p = (void *)cp->data;
memset(cp, 0, sizeof(*cp));
bacpy(&cp->peer_addr, &conn->dst);
cp->peer_addr_type = conn->dst_type;
cp->own_addr_type = own_addr_type;
plen = sizeof(*cp);
if (scan_1m(hdev)) {
cp->phys |= LE_SCAN_PHY_1M;
set_ext_conn_params(conn, p);
p++;
plen += sizeof(*p);
}
if (scan_2m(hdev)) {
cp->phys |= LE_SCAN_PHY_2M;
set_ext_conn_params(conn, p);
p++;
plen += sizeof(*p);
}
if (scan_coded(hdev)) {
cp->phys |= LE_SCAN_PHY_CODED;
set_ext_conn_params(conn, p);
plen += sizeof(*p);
}
return __hci_cmd_sync_status_sk(hdev, HCI_OP_LE_EXT_CREATE_CONN,
plen, data,
HCI_EV_LE_ENHANCED_CONN_COMPLETE,
HCI_CMD_TIMEOUT, NULL);
}
int hci_le_create_conn_sync(struct hci_dev *hdev, struct hci_conn *conn)
{
struct hci_cp_le_create_conn cp;
struct hci_conn_params *params;
u8 own_addr_type;
int err;
/* If requested to connect as peripheral use directed advertising */
if (conn->role == HCI_ROLE_SLAVE) {
/* If we're active scanning and simultaneous roles is not
* enabled simply reject the attempt.
*/
if (hci_dev_test_flag(hdev, HCI_LE_SCAN) &&
hdev->le_scan_type == LE_SCAN_ACTIVE &&
!hci_dev_test_flag(hdev, HCI_LE_SIMULTANEOUS_ROLES)) {
hci_conn_del(conn);
return -EBUSY;
}
/* Pause advertising while doing directed advertising. */
hci_pause_advertising_sync(hdev);
err = hci_le_directed_advertising_sync(hdev, conn);
goto done;
}
/* Disable advertising if simultaneous roles is not in use. */
if (!hci_dev_test_flag(hdev, HCI_LE_SIMULTANEOUS_ROLES))
hci_pause_advertising_sync(hdev);
params = hci_conn_params_lookup(hdev, &conn->dst, conn->dst_type);
if (params) {
conn->le_conn_min_interval = params->conn_min_interval;
conn->le_conn_max_interval = params->conn_max_interval;
conn->le_conn_latency = params->conn_latency;
conn->le_supv_timeout = params->supervision_timeout;
} else {
conn->le_conn_min_interval = hdev->le_conn_min_interval;
conn->le_conn_max_interval = hdev->le_conn_max_interval;
conn->le_conn_latency = hdev->le_conn_latency;
conn->le_supv_timeout = hdev->le_supv_timeout;
}
/* If controller is scanning, we stop it since some controllers are
* not able to scan and connect at the same time. Also set the
* HCI_LE_SCAN_INTERRUPTED flag so that the command complete
* handler for scan disabling knows to set the correct discovery
* state.
*/
if (hci_dev_test_flag(hdev, HCI_LE_SCAN)) {
hci_scan_disable_sync(hdev);
hci_dev_set_flag(hdev, HCI_LE_SCAN_INTERRUPTED);
}
/* Update random address, but set require_privacy to false so
* that we never connect with an non-resolvable address.
*/
err = hci_update_random_address_sync(hdev, false, conn_use_rpa(conn),
&own_addr_type);
if (err)
goto done;
if (use_ext_conn(hdev)) {
err = hci_le_ext_create_conn_sync(hdev, conn, own_addr_type);
goto done;
}
memset(&cp, 0, sizeof(cp));
cp.scan_interval = cpu_to_le16(hdev->le_scan_int_connect);
cp.scan_window = cpu_to_le16(hdev->le_scan_window_connect);
bacpy(&cp.peer_addr, &conn->dst);
cp.peer_addr_type = conn->dst_type;
cp.own_address_type = own_addr_type;
cp.conn_interval_min = cpu_to_le16(conn->le_conn_min_interval);
cp.conn_interval_max = cpu_to_le16(conn->le_conn_max_interval);
cp.conn_latency = cpu_to_le16(conn->le_conn_latency);
cp.supervision_timeout = cpu_to_le16(conn->le_supv_timeout);
cp.min_ce_len = cpu_to_le16(0x0000);
cp.max_ce_len = cpu_to_le16(0x0000);
err = __hci_cmd_sync_status_sk(hdev, HCI_OP_LE_CREATE_CONN,
sizeof(cp), &cp, HCI_EV_LE_CONN_COMPLETE,
HCI_CMD_TIMEOUT, NULL);
done:
/* Re-enable advertising after the connection attempt is finished. */
hci_resume_advertising_sync(hdev);
return err;
}

View File

@ -7905,7 +7905,7 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid,
hcon = hci_connect_le(hdev, dst, dst_type, false,
chan->sec_level,
HCI_LE_CONN_TIMEOUT,
HCI_ROLE_SLAVE, NULL);
HCI_ROLE_SLAVE);
else
hcon = hci_connect_le_scan(hdev, dst, dst_type,
chan->sec_level,

View File

@ -161,7 +161,11 @@ static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen)
break;
}
if (chan->psm && bdaddr_type_is_le(chan->src_type))
/* Use L2CAP_MODE_LE_FLOWCTL (CoC) in case of LE address and
* L2CAP_MODE_EXT_FLOWCTL (ECRED) has not been set.
*/
if (chan->psm && bdaddr_type_is_le(chan->src_type) &&
chan->mode != L2CAP_MODE_EXT_FLOWCTL)
chan->mode = L2CAP_MODE_LE_FLOWCTL;
chan->state = BT_BOUND;
@ -255,7 +259,11 @@ static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr,
return -EINVAL;
}
if (chan->psm && bdaddr_type_is_le(chan->src_type) && !chan->mode)
/* Use L2CAP_MODE_LE_FLOWCTL (CoC) in case of LE address and
* L2CAP_MODE_EXT_FLOWCTL (ECRED) has not been set.
*/
if (chan->psm && bdaddr_type_is_le(chan->src_type) &&
chan->mode != L2CAP_MODE_EXT_FLOWCTL)
chan->mode = L2CAP_MODE_LE_FLOWCTL;
l2cap_sock_init_pid(sk);

View File

@ -335,6 +335,12 @@ static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, u16 len,
HCI_SOCK_TRUSTED, skip_sk);
}
static int mgmt_event_skb(struct sk_buff *skb, struct sock *skip_sk)
{
return mgmt_send_event_skb(HCI_CHANNEL_CONTROL, skb, HCI_SOCK_TRUSTED,
skip_sk);
}
static u8 le_addr_type(u8 mgmt_addr_type)
{
if (mgmt_addr_type == BDADDR_LE_PUBLIC)
@ -3876,7 +3882,7 @@ static const u8 offload_codecs_uuid[16] = {
};
/* 671b10b5-42c0-4696-9227-eb28d1b049d6 */
static const u8 simult_central_periph_uuid[16] = {
static const u8 le_simultaneous_roles_uuid[16] = {
0xd6, 0x49, 0xb0, 0xd1, 0x28, 0xeb, 0x27, 0x92,
0x96, 0x46, 0xc0, 0x42, 0xb5, 0x10, 0x1b, 0x67,
};
@ -3909,16 +3915,13 @@ static int read_exp_features_info(struct sock *sk, struct hci_dev *hdev,
}
#endif
if (hdev) {
if (test_bit(HCI_QUIRK_VALID_LE_STATES, &hdev->quirks) &&
(hdev->le_states[4] & 0x08) && /* Central */
(hdev->le_states[4] & 0x40) && /* Peripheral */
(hdev->le_states[3] & 0x10)) /* Simultaneous */
if (hdev && hci_dev_le_state_simultaneous(hdev)) {
if (hci_dev_test_flag(hdev, HCI_LE_SIMULTANEOUS_ROLES))
flags = BIT(0);
else
flags = 0;
memcpy(rp->features[idx].uuid, simult_central_periph_uuid, 16);
memcpy(rp->features[idx].uuid, le_simultaneous_roles_uuid, 16);
rp->features[idx].flags = cpu_to_le32(flags);
idx++;
}
@ -3978,35 +3981,24 @@ static int exp_ll_privacy_feature_changed(bool enabled, struct hci_dev *hdev,
memcpy(ev.uuid, rpa_resolution_uuid, 16);
ev.flags = cpu_to_le32((enabled ? BIT(0) : 0) | BIT(1));
if (enabled && privacy_mode_capable(hdev))
set_bit(HCI_CONN_FLAG_DEVICE_PRIVACY, hdev->conn_flags);
else
clear_bit(HCI_CONN_FLAG_DEVICE_PRIVACY, hdev->conn_flags);
return mgmt_limited_event(MGMT_EV_EXP_FEATURE_CHANGED, hdev,
&ev, sizeof(ev),
HCI_MGMT_EXP_FEATURE_EVENTS, skip);
}
#ifdef CONFIG_BT_FEATURE_DEBUG
static int exp_debug_feature_changed(bool enabled, struct sock *skip)
static int exp_feature_changed(struct hci_dev *hdev, const u8 *uuid,
bool enabled, struct sock *skip)
{
struct mgmt_ev_exp_feature_changed ev;
memset(&ev, 0, sizeof(ev));
memcpy(ev.uuid, debug_uuid, 16);
ev.flags = cpu_to_le32(enabled ? BIT(0) : 0);
return mgmt_limited_event(MGMT_EV_EXP_FEATURE_CHANGED, NULL,
&ev, sizeof(ev),
HCI_MGMT_EXP_FEATURE_EVENTS, skip);
}
#endif
static int exp_quality_report_feature_changed(bool enabled,
struct hci_dev *hdev,
struct sock *skip)
{
struct mgmt_ev_exp_feature_changed ev;
memset(&ev, 0, sizeof(ev));
memcpy(ev.uuid, quality_report_uuid, 16);
memcpy(ev.uuid, uuid, 16);
ev.flags = cpu_to_le32(enabled ? BIT(0) : 0);
return mgmt_limited_event(MGMT_EV_EXP_FEATURE_CHANGED, hdev,
@ -4036,17 +4028,18 @@ static int set_zero_key_func(struct sock *sk, struct hci_dev *hdev,
bt_dbg_set(false);
if (changed)
exp_debug_feature_changed(false, sk);
exp_feature_changed(NULL, ZERO_KEY, false, sk);
}
#endif
if (hdev && use_ll_privacy(hdev) && !hdev_is_powered(hdev)) {
bool changed = hci_dev_test_flag(hdev, HCI_ENABLE_LL_PRIVACY);
hci_dev_clear_flag(hdev, HCI_ENABLE_LL_PRIVACY);
bool changed;
changed = hci_dev_test_and_clear_flag(hdev,
HCI_ENABLE_LL_PRIVACY);
if (changed)
exp_ll_privacy_feature_changed(false, hdev, sk);
exp_feature_changed(hdev, rpa_resolution_uuid, false,
sk);
}
hci_sock_set_flag(sk, HCI_MGMT_EXP_FEATURE_EVENTS);
@ -4097,7 +4090,7 @@ static int set_debug_func(struct sock *sk, struct hci_dev *hdev,
&rp, sizeof(rp));
if (changed)
exp_debug_feature_changed(val, sk);
exp_feature_changed(hdev, debug_uuid, val, sk);
return err;
}
@ -4139,15 +4132,15 @@ static int set_rpa_resolution_func(struct sock *sk, struct hci_dev *hdev,
val = !!cp->param[0];
if (val) {
changed = !hci_dev_test_flag(hdev, HCI_ENABLE_LL_PRIVACY);
hci_dev_set_flag(hdev, HCI_ENABLE_LL_PRIVACY);
changed = !hci_dev_test_and_set_flag(hdev,
HCI_ENABLE_LL_PRIVACY);
hci_dev_clear_flag(hdev, HCI_ADVERTISING);
/* Enable LL privacy + supported settings changed */
flags = BIT(0) | BIT(1);
} else {
changed = hci_dev_test_flag(hdev, HCI_ENABLE_LL_PRIVACY);
hci_dev_clear_flag(hdev, HCI_ENABLE_LL_PRIVACY);
changed = hci_dev_test_and_clear_flag(hdev,
HCI_ENABLE_LL_PRIVACY);
/* Disable LL privacy + supported settings changed */
flags = BIT(1);
@ -4235,27 +4228,13 @@ static int set_quality_report_func(struct sock *sk, struct hci_dev *hdev,
&rp, sizeof(rp));
if (changed)
exp_quality_report_feature_changed(val, hdev, sk);
exp_feature_changed(hdev, quality_report_uuid, val, sk);
unlock_quality_report:
hci_req_sync_unlock(hdev);
return err;
}
static int exp_offload_codec_feature_changed(bool enabled, struct hci_dev *hdev,
struct sock *skip)
{
struct mgmt_ev_exp_feature_changed ev;
memset(&ev, 0, sizeof(ev));
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, hdev,
&ev, sizeof(ev),
HCI_MGMT_EXP_FEATURE_EVENTS, skip);
}
static int set_offload_codec_func(struct sock *sk, struct hci_dev *hdev,
struct mgmt_cp_set_exp_feature *cp,
u16 data_len)
@ -4309,7 +4288,65 @@ static int set_offload_codec_func(struct sock *sk, struct hci_dev *hdev,
&rp, sizeof(rp));
if (changed)
exp_offload_codec_feature_changed(val, hdev, sk);
exp_feature_changed(hdev, offload_codecs_uuid, val, sk);
return err;
}
static int set_le_simultaneous_roles_func(struct sock *sk, struct hci_dev *hdev,
struct mgmt_cp_set_exp_feature *cp,
u16 data_len)
{
bool val, changed;
int err;
struct mgmt_rp_set_exp_feature rp;
/* Command requires to use a valid controller index */
if (!hdev)
return mgmt_cmd_status(sk, MGMT_INDEX_NONE,
MGMT_OP_SET_EXP_FEATURE,
MGMT_STATUS_INVALID_INDEX);
/* Parameters are limited to a single octet */
if (data_len != MGMT_SET_EXP_FEATURE_SIZE + 1)
return mgmt_cmd_status(sk, hdev->id,
MGMT_OP_SET_EXP_FEATURE,
MGMT_STATUS_INVALID_PARAMS);
/* Only boolean on/off is supported */
if (cp->param[0] != 0x00 && cp->param[0] != 0x01)
return mgmt_cmd_status(sk, hdev->id,
MGMT_OP_SET_EXP_FEATURE,
MGMT_STATUS_INVALID_PARAMS);
val = !!cp->param[0];
changed = (val != hci_dev_test_flag(hdev, HCI_LE_SIMULTANEOUS_ROLES));
if (!hci_dev_le_state_simultaneous(hdev)) {
return mgmt_cmd_status(sk, hdev->id,
MGMT_OP_SET_EXP_FEATURE,
MGMT_STATUS_NOT_SUPPORTED);
}
if (changed) {
if (val)
hci_dev_set_flag(hdev, HCI_LE_SIMULTANEOUS_ROLES);
else
hci_dev_clear_flag(hdev, HCI_LE_SIMULTANEOUS_ROLES);
}
bt_dev_info(hdev, "LE simultaneous roles enable %d changed %d",
val, changed);
memcpy(rp.uuid, le_simultaneous_roles_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,
&rp, sizeof(rp));
if (changed)
exp_feature_changed(hdev, le_simultaneous_roles_uuid, val, sk);
return err;
}
@ -4326,6 +4363,7 @@ static const struct mgmt_exp_feature {
EXP_FEAT(rpa_resolution_uuid, set_rpa_resolution_func),
EXP_FEAT(quality_report_uuid, set_quality_report_func),
EXP_FEAT(offload_codecs_uuid, set_offload_codec_func),
EXP_FEAT(le_simultaneous_roles_uuid, set_le_simultaneous_roles_func),
/* end with a null feature */
EXP_FEAT(NULL, NULL)
@ -4349,8 +4387,6 @@ static int set_exp_feature(struct sock *sk, struct hci_dev *hdev,
MGMT_STATUS_NOT_SUPPORTED);
}
#define SUPPORTED_DEVICE_FLAGS() ((1U << HCI_CONN_FLAG_MAX) - 1)
static int get_device_flags(struct sock *sk, struct hci_dev *hdev, void *data,
u16 data_len)
{
@ -4358,7 +4394,7 @@ static int get_device_flags(struct sock *sk, struct hci_dev *hdev, void *data,
struct mgmt_rp_get_device_flags rp;
struct bdaddr_list_with_flags *br_params;
struct hci_conn_params *params;
u32 supported_flags = SUPPORTED_DEVICE_FLAGS();
u32 supported_flags;
u32 current_flags = 0;
u8 status = MGMT_STATUS_INVALID_PARAMS;
@ -4367,6 +4403,9 @@ static int get_device_flags(struct sock *sk, struct hci_dev *hdev, void *data,
hci_dev_lock(hdev);
bitmap_to_arr32(&supported_flags, hdev->conn_flags,
__HCI_CONN_NUM_FLAGS);
memset(&rp, 0, sizeof(rp));
if (cp->addr.type == BDADDR_BREDR) {
@ -4376,7 +4415,8 @@ static int get_device_flags(struct sock *sk, struct hci_dev *hdev, void *data,
if (!br_params)
goto done;
current_flags = br_params->current_flags;
bitmap_to_arr32(&current_flags, br_params->flags,
__HCI_CONN_NUM_FLAGS);
} else {
params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr,
le_addr_type(cp->addr.type));
@ -4384,7 +4424,8 @@ static int get_device_flags(struct sock *sk, struct hci_dev *hdev, void *data,
if (!params)
goto done;
current_flags = params->current_flags;
bitmap_to_arr32(&current_flags, params->flags,
__HCI_CONN_NUM_FLAGS);
}
bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
@ -4422,13 +4463,16 @@ static int set_device_flags(struct sock *sk, struct hci_dev *hdev, void *data,
struct bdaddr_list_with_flags *br_params;
struct hci_conn_params *params;
u8 status = MGMT_STATUS_INVALID_PARAMS;
u32 supported_flags = SUPPORTED_DEVICE_FLAGS();
u32 supported_flags;
u32 current_flags = __le32_to_cpu(cp->current_flags);
bt_dev_dbg(hdev, "Set device flags %pMR (type 0x%x) = 0x%x",
&cp->addr.bdaddr, cp->addr.type,
__le32_to_cpu(current_flags));
bitmap_to_arr32(&supported_flags, hdev->conn_flags,
__HCI_CONN_NUM_FLAGS);
if ((supported_flags | current_flags) != supported_flags) {
bt_dev_warn(hdev, "Bad flag given (0x%x) vs supported (0x%0x)",
current_flags, supported_flags);
@ -4443,7 +4487,7 @@ static int set_device_flags(struct sock *sk, struct hci_dev *hdev, void *data,
cp->addr.type);
if (br_params) {
br_params->current_flags = current_flags;
bitmap_from_u64(br_params->flags, current_flags);
status = MGMT_STATUS_SUCCESS;
} else {
bt_dev_warn(hdev, "No such BR/EDR device %pMR (0x%x)",
@ -4453,8 +4497,15 @@ static int set_device_flags(struct sock *sk, struct hci_dev *hdev, void *data,
params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr,
le_addr_type(cp->addr.type));
if (params) {
params->current_flags = current_flags;
bitmap_from_u64(params->flags, current_flags);
status = MGMT_STATUS_SUCCESS;
/* Update passive scan if HCI_CONN_FLAG_DEVICE_PRIVACY
* has been set.
*/
if (test_bit(HCI_CONN_FLAG_DEVICE_PRIVACY,
params->flags))
hci_update_passive_scan(hdev);
} else {
bt_dev_warn(hdev, "No such LE device %pMR (0x%x)",
&cp->addr.bdaddr,
@ -6979,6 +7030,7 @@ static int add_device(struct sock *sk, struct hci_dev *hdev,
struct hci_conn_params *params;
int err;
u32 current_flags = 0;
u32 supported_flags;
bt_dev_dbg(hdev, "sock %p", sk);
@ -7050,7 +7102,8 @@ static int add_device(struct sock *sk, struct hci_dev *hdev,
params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr,
addr_type);
if (params)
current_flags = params->current_flags;
bitmap_to_arr32(&current_flags, params->flags,
__HCI_CONN_NUM_FLAGS);
}
err = hci_cmd_sync_queue(hdev, add_device_sync, NULL, NULL);
@ -7059,8 +7112,10 @@ static int add_device(struct sock *sk, struct hci_dev *hdev,
added:
device_added(sk, hdev, &cp->addr.bdaddr, cp->addr.type, cp->action);
bitmap_to_arr32(&supported_flags, hdev->conn_flags,
__HCI_CONN_NUM_FLAGS);
device_flags_changed(NULL, hdev, &cp->addr.bdaddr, cp->addr.type,
SUPPORTED_DEVICE_FLAGS(), current_flags);
supported_flags, current_flags);
err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
MGMT_STATUS_SUCCESS, &cp->addr,
@ -8999,11 +9054,19 @@ void mgmt_new_conn_param(struct hci_dev *hdev, bdaddr_t *bdaddr,
void mgmt_device_connected(struct hci_dev *hdev, struct hci_conn *conn,
u8 *name, u8 name_len)
{
char buf[512];
struct mgmt_ev_device_connected *ev = (void *) buf;
struct sk_buff *skb;
struct mgmt_ev_device_connected *ev;
u16 eir_len = 0;
u32 flags = 0;
if (conn->le_adv_data_len > 0)
skb = mgmt_alloc_skb(hdev, MGMT_EV_DEVICE_CONNECTED,
conn->le_adv_data_len);
else
skb = mgmt_alloc_skb(hdev, MGMT_EV_DEVICE_CONNECTED,
2 + name_len + 5);
ev = skb_put(skb, sizeof(*ev));
bacpy(&ev->addr.bdaddr, &conn->dst);
ev->addr.type = link_to_bdaddr(conn->type, conn->dst_type);
@ -9017,24 +9080,26 @@ void mgmt_device_connected(struct hci_dev *hdev, struct hci_conn *conn,
* adding any BR/EDR data to the LE adv.
*/
if (conn->le_adv_data_len > 0) {
memcpy(&ev->eir[eir_len],
conn->le_adv_data, conn->le_adv_data_len);
skb_put_data(skb, conn->le_adv_data, conn->le_adv_data_len);
eir_len = conn->le_adv_data_len;
} else {
if (name_len > 0)
if (name_len > 0) {
eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
name, name_len);
skb_put(skb, eir_len);
}
if (memcmp(conn->dev_class, "\0\0\0", 3) != 0)
if (memcmp(conn->dev_class, "\0\0\0", 3) != 0) {
eir_len = eir_append_data(ev->eir, eir_len,
EIR_CLASS_OF_DEV,
conn->dev_class, 3);
skb_put(skb, 5);
}
}
ev->eir_len = cpu_to_le16(eir_len);
mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
sizeof(*ev) + eir_len, NULL);
mgmt_event_skb(skb, NULL);
}
static void disconnect_rsp(struct mgmt_pending_cmd *cmd, void *data)
@ -9528,9 +9593,8 @@ void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
u8 addr_type, u8 *dev_class, s8 rssi, u32 flags,
u8 *eir, u16 eir_len, u8 *scan_rsp, u8 scan_rsp_len)
{
char buf[512];
struct mgmt_ev_device_found *ev = (void *)buf;
size_t ev_size;
struct sk_buff *skb;
struct mgmt_ev_device_found *ev;
/* Don't send events for a non-kernel initiated discovery. With
* LE one exception is if we have pend_le_reports > 0 in which
@ -9565,13 +9629,13 @@ void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
}
}
/* Make sure that the buffer is big enough. The 5 extra bytes
* are for the potential CoD field.
*/
if (sizeof(*ev) + eir_len + scan_rsp_len + 5 > sizeof(buf))
/* Allocate skb. The 5 extra bytes are for the potential CoD field */
skb = mgmt_alloc_skb(hdev, MGMT_EV_DEVICE_FOUND,
sizeof(*ev) + eir_len + scan_rsp_len + 5);
if (!skb)
return;
memset(buf, 0, sizeof(buf));
ev = skb_put(skb, sizeof(*ev));
/* In case of device discovery with BR/EDR devices (pre 1.2), the
* RSSI value was reported as 0 when not available. This behavior
@ -9592,44 +9656,57 @@ void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
if (eir_len > 0)
/* Copy EIR or advertising data into event */
memcpy(ev->eir, eir, eir_len);
skb_put_data(skb, eir, eir_len);
if (dev_class && !eir_get_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
NULL))
eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
if (dev_class && !eir_get_data(eir, eir_len, EIR_CLASS_OF_DEV, NULL)) {
u8 eir_cod[5];
eir_len += eir_append_data(eir_cod, 0, EIR_CLASS_OF_DEV,
dev_class, 3);
skb_put_data(skb, eir_cod, sizeof(eir_cod));
}
if (scan_rsp_len > 0)
/* Append scan response data to event */
memcpy(ev->eir + eir_len, scan_rsp, scan_rsp_len);
skb_put_data(skb, scan_rsp, scan_rsp_len);
ev->eir_len = cpu_to_le16(eir_len + scan_rsp_len);
ev_size = sizeof(*ev) + eir_len + scan_rsp_len;
mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
mgmt_event_skb(skb, NULL);
}
void mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
u8 addr_type, s8 rssi, u8 *name, u8 name_len)
{
struct sk_buff *skb;
struct mgmt_ev_device_found *ev;
char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
u16 eir_len;
u32 flags;
ev = (struct mgmt_ev_device_found *) buf;
memset(buf, 0, sizeof(buf));
if (name_len)
skb = mgmt_alloc_skb(hdev, MGMT_EV_DEVICE_FOUND, 2 + name_len);
else
skb = mgmt_alloc_skb(hdev, MGMT_EV_DEVICE_FOUND, 0);
ev = skb_put(skb, sizeof(*ev));
bacpy(&ev->addr.bdaddr, bdaddr);
ev->addr.type = link_to_bdaddr(link_type, addr_type);
ev->rssi = rssi;
if (name) {
eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
name_len);
flags = 0;
skb_put(skb, eir_len);
} else {
eir_len = 0;
flags = MGMT_DEV_FOUND_NAME_REQUEST_FAILED;
}
ev->eir_len = cpu_to_le16(eir_len);
ev->flags = cpu_to_le32(flags);
mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, sizeof(*ev) + eir_len, NULL);
mgmt_event_skb(skb, NULL);
}
void mgmt_discovering(struct hci_dev *hdev, u8 discovering)

View File

@ -56,40 +56,72 @@ static struct sk_buff *create_monitor_ctrl_event(__le16 index, u32 cookie,
return skb;
}
int mgmt_send_event(u16 event, struct hci_dev *hdev, unsigned short channel,
void *data, u16 data_len, int flag, struct sock *skip_sk)
struct sk_buff *mgmt_alloc_skb(struct hci_dev *hdev, u16 opcode,
unsigned int size)
{
struct sk_buff *skb;
struct mgmt_hdr *hdr;
skb = alloc_skb(sizeof(*hdr) + data_len, GFP_KERNEL);
skb = alloc_skb(sizeof(struct mgmt_hdr) + size, GFP_KERNEL);
if (!skb)
return -ENOMEM;
return skb;
hdr = skb_put(skb, sizeof(*hdr));
hdr->opcode = cpu_to_le16(event);
if (hdev)
hdr->index = cpu_to_le16(hdev->id);
else
hdr->index = cpu_to_le16(MGMT_INDEX_NONE);
hdr->len = cpu_to_le16(data_len);
skb_reserve(skb, sizeof(struct mgmt_hdr));
bt_cb(skb)->mgmt.hdev = hdev;
bt_cb(skb)->mgmt.opcode = opcode;
if (data)
skb_put_data(skb, data, data_len);
return skb;
}
int mgmt_send_event_skb(unsigned short channel, struct sk_buff *skb, int flag,
struct sock *skip_sk)
{
struct hci_dev *hdev;
struct mgmt_hdr *hdr;
int len = skb->len;
if (!skb)
return -EINVAL;
hdev = bt_cb(skb)->mgmt.hdev;
/* Time stamp */
__net_timestamp(skb);
hci_send_to_channel(channel, skb, flag, skip_sk);
/* Send just the data, without headers, to the monitor */
if (channel == HCI_CHANNEL_CONTROL)
hci_send_monitor_ctrl_event(hdev, event, data, data_len,
hci_send_monitor_ctrl_event(hdev, bt_cb(skb)->mgmt.opcode,
skb->data, skb->len,
skb_get_ktime(skb), flag, skip_sk);
hdr = skb_push(skb, sizeof(*hdr));
hdr->opcode = cpu_to_le16(bt_cb(skb)->mgmt.opcode);
if (hdev)
hdr->index = cpu_to_le16(hdev->id);
else
hdr->index = cpu_to_le16(MGMT_INDEX_NONE);
hdr->len = cpu_to_le16(len);
hci_send_to_channel(channel, skb, flag, skip_sk);
kfree_skb(skb);
return 0;
}
int mgmt_send_event(u16 event, struct hci_dev *hdev, unsigned short channel,
void *data, u16 data_len, int flag, struct sock *skip_sk)
{
struct sk_buff *skb;
skb = mgmt_alloc_skb(hdev, event, data_len);
if (!skb)
return -ENOMEM;
if (data)
skb_put_data(skb, data, data_len);
return mgmt_send_event_skb(channel, skb, flag, skip_sk);
}
int mgmt_cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
{
struct sk_buff *skb, *mskb;

View File

@ -32,6 +32,10 @@ struct mgmt_pending_cmd {
int (*cmd_complete)(struct mgmt_pending_cmd *cmd, u8 status);
};
struct sk_buff *mgmt_alloc_skb(struct hci_dev *hdev, u16 opcode,
unsigned int size);
int mgmt_send_event_skb(unsigned short channel, struct sk_buff *skb, int flag,
struct sock *skip_sk);
int mgmt_send_event(u16 event, struct hci_dev *hdev, unsigned short channel,
void *data, u16 data_len, int flag, struct sock *skip_sk);
int mgmt_cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status);

View File

@ -590,7 +590,7 @@ void msft_unregister(struct hci_dev *hdev)
kfree(msft);
}
void msft_vendor_evt(struct hci_dev *hdev, struct sk_buff *skb)
void msft_vendor_evt(struct hci_dev *hdev, void *data, struct sk_buff *skb)
{
struct msft_data *msft = hdev->msft_data;
u8 event;

View File

@ -17,7 +17,7 @@ void msft_register(struct hci_dev *hdev);
void msft_unregister(struct hci_dev *hdev);
void msft_do_open(struct hci_dev *hdev);
void msft_do_close(struct hci_dev *hdev);
void msft_vendor_evt(struct hci_dev *hdev, struct sk_buff *skb);
void msft_vendor_evt(struct hci_dev *hdev, void *data, struct sk_buff *skb);
__u64 msft_get_features(struct hci_dev *hdev);
int msft_add_monitor_pattern(struct hci_dev *hdev, struct adv_monitor *monitor);
int msft_remove_monitor(struct hci_dev *hdev, struct adv_monitor *monitor,
@ -39,7 +39,8 @@ static inline void msft_register(struct hci_dev *hdev) {}
static inline void msft_unregister(struct hci_dev *hdev) {}
static inline void msft_do_open(struct hci_dev *hdev) {}
static inline void msft_do_close(struct hci_dev *hdev) {}
static inline void msft_vendor_evt(struct hci_dev *hdev, struct sk_buff *skb) {}
static inline void msft_vendor_evt(struct hci_dev *hdev, void *data,
struct sk_buff *skb) {}
static inline __u64 msft_get_features(struct hci_dev *hdev) { return 0; }
static inline int msft_add_monitor_pattern(struct hci_dev *hdev,
struct adv_monitor *monitor)

View File

@ -2023,6 +2023,30 @@ void *skb_pull(struct sk_buff *skb, unsigned int len)
}
EXPORT_SYMBOL(skb_pull);
/**
* skb_pull_data - remove data from the start of a buffer returning its
* original position.
* @skb: buffer to use
* @len: amount of data to remove
*
* This function removes data from the start of a buffer, returning
* the memory to the headroom. A pointer to the original data in the buffer
* is returned after checking if there is enough data to pull. Once the
* data has been pulled future pushes will overwrite the old data.
*/
void *skb_pull_data(struct sk_buff *skb, size_t len)
{
void *data = skb->data;
if (skb->len < len)
return NULL;
skb_pull(skb, len);
return data;
}
EXPORT_SYMBOL(skb_pull_data);
/**
* skb_trim - remove end from a buffer
* @skb: buffer to alter