Commit d0f1c248 authored by Jakub Kicinski's avatar Jakub Kicinski

Merge tag 'for-net-next-2021-10-01' of...

Merge tag 'for-net-next-2021-10-01' 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 MediaTek MT7922 and MT7921
 - Enable support for AOSP extention in Qualcomm WCN399x and Realtek
   8822C/8852A.
 - Add initial support for link quality and audio/codec offload.
 - Rework of sockets sendmsg to avoid locking issues.
 - Add vhci suspend/resume emulation.

====================

Link: https://lore.kernel.org/r/20211001230850.3635543-1-luiz.dentz@gmail.comSigned-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents 49ed8dde 4539ca67
......@@ -1037,8 +1037,9 @@ static bool btintel_firmware_version(struct hci_dev *hdev,
params = (void *)(fw_ptr + sizeof(*cmd));
bt_dev_info(hdev, "Boot Address: 0x%x",
le32_to_cpu(params->boot_addr));
*boot_addr = le32_to_cpu(params->boot_addr);
bt_dev_info(hdev, "Boot Address: 0x%x", *boot_addr);
bt_dev_info(hdev, "Firmware Version: %u-%u.%u",
params->fw_build_num, params->fw_build_ww,
......@@ -1071,9 +1072,6 @@ int btintel_download_firmware(struct hci_dev *hdev,
/* Skip version checking */
break;
default:
/* Skip reading firmware file version in bootloader mode */
if (ver->fw_variant == 0x06)
break;
/* Skip download if firmware has the same version */
if (btintel_firmware_version(hdev, ver->fw_build_num,
......@@ -1114,19 +1112,16 @@ static int btintel_download_fw_tlv(struct hci_dev *hdev,
int err;
u32 css_header_ver;
/* Skip reading firmware file version in bootloader mode */
if (ver->img_type != 0x01) {
/* Skip download if firmware has the same version */
if (btintel_firmware_version(hdev, ver->min_fw_build_nn,
ver->min_fw_build_cw,
ver->min_fw_build_yy,
fw, boot_param)) {
bt_dev_info(hdev, "Firmware already loaded");
/* Return -EALREADY to indicate that firmware has
* already been loaded.
*/
return -EALREADY;
}
/* Skip download if firmware has the same version */
if (btintel_firmware_version(hdev, ver->min_fw_build_nn,
ver->min_fw_build_cw,
ver->min_fw_build_yy,
fw, boot_param)) {
bt_dev_info(hdev, "Firmware already loaded");
/* Return -EALREADY to indicate that firmware has
* already been loaded.
*/
return -EALREADY;
}
/* The firmware variant determines if the device is in bootloader
......@@ -1285,12 +1280,16 @@ static int btintel_read_debug_features(struct hci_dev *hdev,
static int btintel_set_debug_features(struct hci_dev *hdev,
const struct intel_debug_features *features)
{
u8 mask[11] = { 0x0a, 0x92, 0x02, 0x07, 0x00, 0x00, 0x00, 0x00,
u8 mask[11] = { 0x0a, 0x92, 0x02, 0x7f, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00 };
u8 period[5] = { 0x04, 0x91, 0x02, 0x05, 0x00 };
u8 trace_enable = 0x02;
struct sk_buff *skb;
if (!features)
if (!features) {
bt_dev_warn(hdev, "Debug features not read");
return -EINVAL;
}
if (!(features->page1[0] & 0x3f)) {
bt_dev_info(hdev, "Telemetry exception format not supported");
......@@ -1303,11 +1302,95 @@ static int btintel_set_debug_features(struct hci_dev *hdev,
PTR_ERR(skb));
return PTR_ERR(skb);
}
kfree_skb(skb);
skb = __hci_cmd_sync(hdev, 0xfc8b, 5, period, HCI_INIT_TIMEOUT);
if (IS_ERR(skb)) {
bt_dev_err(hdev, "Setting periodicity for link statistics traces failed (%ld)",
PTR_ERR(skb));
return PTR_ERR(skb);
}
kfree_skb(skb);
skb = __hci_cmd_sync(hdev, 0xfca1, 1, &trace_enable, HCI_INIT_TIMEOUT);
if (IS_ERR(skb)) {
bt_dev_err(hdev, "Enable tracing of link statistics events failed (%ld)",
PTR_ERR(skb));
return PTR_ERR(skb);
}
kfree_skb(skb);
bt_dev_info(hdev, "set debug features: trace_enable 0x%02x mask 0x%02x",
trace_enable, mask[3]);
return 0;
}
static int btintel_reset_debug_features(struct hci_dev *hdev,
const struct intel_debug_features *features)
{
u8 mask[11] = { 0x0a, 0x92, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00 };
u8 trace_enable = 0x00;
struct sk_buff *skb;
if (!features) {
bt_dev_warn(hdev, "Debug features not read");
return -EINVAL;
}
if (!(features->page1[0] & 0x3f)) {
bt_dev_info(hdev, "Telemetry exception format not supported");
return 0;
}
/* Should stop the trace before writing ddc event mask. */
skb = __hci_cmd_sync(hdev, 0xfca1, 1, &trace_enable, HCI_INIT_TIMEOUT);
if (IS_ERR(skb)) {
bt_dev_err(hdev, "Stop tracing of link statistics events failed (%ld)",
PTR_ERR(skb));
return PTR_ERR(skb);
}
kfree_skb(skb);
skb = __hci_cmd_sync(hdev, 0xfc8b, 11, mask, HCI_INIT_TIMEOUT);
if (IS_ERR(skb)) {
bt_dev_err(hdev, "Setting Intel telemetry ddc write event mask failed (%ld)",
PTR_ERR(skb));
return PTR_ERR(skb);
}
kfree_skb(skb);
bt_dev_info(hdev, "reset debug features: trace_enable 0x%02x mask 0x%02x",
trace_enable, mask[3]);
return 0;
}
int btintel_set_quality_report(struct hci_dev *hdev, bool enable)
{
struct intel_debug_features features;
int err;
bt_dev_dbg(hdev, "enable %d", enable);
/* Read the Intel supported features and if new exception formats
* supported, need to load the additional DDC config to enable.
*/
err = btintel_read_debug_features(hdev, &features);
if (err)
return err;
/* Set or reset the debug features. */
if (enable)
err = btintel_set_debug_features(hdev, &features);
else
err = btintel_reset_debug_features(hdev, &features);
return err;
}
EXPORT_SYMBOL_GPL(btintel_set_quality_report);
static const struct firmware *btintel_legacy_rom_get_fw(struct hci_dev *hdev,
struct intel_version *ver)
{
......@@ -1893,7 +1976,6 @@ static int btintel_bootloader_setup(struct hci_dev *hdev,
u32 boot_param;
char ddcname[64];
int err;
struct intel_debug_features features;
BT_DBG("%s", hdev->name);
......@@ -1934,14 +2016,7 @@ static int btintel_bootloader_setup(struct hci_dev *hdev,
btintel_load_ddc_config(hdev, ddcname);
}
/* Read the Intel supported features and if new exception formats
* supported, need to load the additional DDC config to enable.
*/
err = btintel_read_debug_features(hdev, &features);
if (!err) {
/* Set DDC mask for available debug features */
btintel_set_debug_features(hdev, &features);
}
hci_dev_clear_flag(hdev, HCI_QUALITY_REPORT);
/* Read the Intel version information after loading the FW */
err = btintel_read_version(hdev, &new_ver);
......@@ -2083,13 +2158,102 @@ static int btintel_prepare_fw_download_tlv(struct hci_dev *hdev,
return err;
}
static int btintel_get_codec_config_data(struct hci_dev *hdev,
__u8 link, struct bt_codec *codec,
__u8 *ven_len, __u8 **ven_data)
{
int err = 0;
if (!ven_data || !ven_len)
return -EINVAL;
*ven_len = 0;
*ven_data = NULL;
if (link != ESCO_LINK) {
bt_dev_err(hdev, "Invalid link type(%u)", link);
return -EINVAL;
}
*ven_data = kmalloc(sizeof(__u8), GFP_KERNEL);
if (!*ven_data) {
err = -ENOMEM;
goto error;
}
/* supports only CVSD and mSBC offload codecs */
switch (codec->id) {
case 0x02:
**ven_data = 0x00;
break;
case 0x05:
**ven_data = 0x01;
break;
default:
err = -EINVAL;
bt_dev_err(hdev, "Invalid codec id(%u)", codec->id);
goto error;
}
/* codec and its capabilities are pre-defined to ids
* preset id = 0x00 represents CVSD codec with sampling rate 8K
* preset id = 0x01 represents mSBC codec with sampling rate 16K
*/
*ven_len = sizeof(__u8);
return err;
error:
kfree(*ven_data);
*ven_data = NULL;
return err;
}
static int btintel_get_data_path_id(struct hci_dev *hdev, __u8 *data_path_id)
{
/* Intel uses 1 as data path id for all the usecases */
*data_path_id = 1;
return 0;
}
static int btintel_configure_offload(struct hci_dev *hdev)
{
struct sk_buff *skb;
int err = 0;
struct intel_offload_use_cases *use_cases;
skb = __hci_cmd_sync(hdev, 0xfc86, 0, NULL, HCI_INIT_TIMEOUT);
if (IS_ERR(skb)) {
bt_dev_err(hdev, "Reading offload use cases failed (%ld)",
PTR_ERR(skb));
return PTR_ERR(skb);
}
if (skb->len < sizeof(*use_cases)) {
err = -EIO;
goto error;
}
use_cases = (void *)skb->data;
if (use_cases->status) {
err = -bt_to_errno(skb->data[0]);
goto error;
}
if (use_cases->preset[0] & 0x03) {
hdev->get_data_path_id = btintel_get_data_path_id;
hdev->get_codec_config_data = btintel_get_codec_config_data;
}
error:
kfree_skb(skb);
return err;
}
static int btintel_bootloader_setup_tlv(struct hci_dev *hdev,
struct intel_version_tlv *ver)
{
u32 boot_param;
char ddcname[64];
int err;
struct intel_debug_features features;
struct intel_version_tlv new_ver;
bt_dev_dbg(hdev, "");
......@@ -2125,14 +2289,10 @@ static int btintel_bootloader_setup_tlv(struct hci_dev *hdev,
*/
btintel_load_ddc_config(hdev, ddcname);
/* Read the Intel supported features and if new exception formats
* supported, need to load the additional DDC config to enable.
*/
err = btintel_read_debug_features(hdev, &features);
if (!err) {
/* Set DDC mask for available debug features */
btintel_set_debug_features(hdev, &features);
}
/* Read supported use cases and set callbacks to fetch datapath id */
btintel_configure_offload(hdev);
hci_dev_clear_flag(hdev, HCI_QUALITY_REPORT);
/* Read the Intel version information after loading the FW */
err = btintel_read_version_tlv(hdev, &new_ver);
......@@ -2232,6 +2392,9 @@ static int btintel_setup_combined(struct hci_dev *hdev)
set_bit(HCI_QUIRK_SIMULTANEOUS_DISCOVERY, &hdev->quirks);
set_bit(HCI_QUIRK_NON_PERSISTENT_DIAG, &hdev->quirks);
/* Set up the quality report callback for Intel devices */
hdev->set_quality_report = btintel_set_quality_report;
/* For Legacy device, check the HW platform value and size */
if (skb->len == sizeof(ver) && skb->data[1] == 0x37) {
bt_dev_dbg(hdev, "Read the legacy Intel version information");
......
......@@ -132,6 +132,11 @@ struct intel_debug_features {
__u8 page1[16];
} __packed;
struct intel_offload_use_cases {
__u8 status;
__u8 preset[8];
} __packed;
#define INTEL_HW_PLATFORM(cnvx_bt) ((u8)(((cnvx_bt) & 0x0000ff00) >> 8))
#define INTEL_HW_VARIANT(cnvx_bt) ((u8)(((cnvx_bt) & 0x003f0000) >> 16))
#define INTEL_CNVX_TOP_TYPE(cnvx_top) ((cnvx_top) & 0x00000fff)
......@@ -204,6 +209,7 @@ int btintel_configure_setup(struct hci_dev *hdev);
void btintel_bootup(struct hci_dev *hdev, const void *ptr, unsigned int len);
void btintel_secure_send_result(struct hci_dev *hdev,
const void *ptr, unsigned int len);
int btintel_set_quality_report(struct hci_dev *hdev, bool enable);
#else
static inline int btintel_check_bdaddr(struct hci_dev *hdev)
......@@ -294,4 +300,9 @@ static inline void btintel_secure_send_result(struct hci_dev *hdev,
const void *ptr, unsigned int len)
{
}
static inline int btintel_set_quality_report(struct hci_dev *hdev, bool enable)
{
return -ENODEV;
}
#endif
......@@ -587,12 +587,12 @@ static int btmrvl_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr)
return 0;
}
static bool btmrvl_prevent_wake(struct hci_dev *hdev)
static bool btmrvl_wakeup(struct hci_dev *hdev)
{
struct btmrvl_private *priv = hci_get_drvdata(hdev);
struct btmrvl_sdio_card *card = priv->btmrvl_dev.card;
return !device_may_wakeup(&card->func->dev);
return device_may_wakeup(&card->func->dev);
}
/*
......@@ -696,7 +696,7 @@ int btmrvl_register_hdev(struct btmrvl_private *priv)
hdev->send = btmrvl_send_frame;
hdev->setup = btmrvl_setup;
hdev->set_bdaddr = btmrvl_set_bdaddr;
hdev->prevent_wake = btmrvl_prevent_wake;
hdev->wakeup = btmrvl_wakeup;
SET_HCIDEV_DEV(hdev, &card->func->dev);
hdev->dev_type = priv->btmrvl_dev.dev_type;
......
......@@ -158,8 +158,10 @@ static int mtk_hci_wmt_sync(struct hci_dev *hdev,
int err;
hlen = sizeof(*hdr) + wmt_params->dlen;
if (hlen > 255)
return -EINVAL;
if (hlen > 255) {
err = -EINVAL;
goto err_free_skb;
}
hdr = (struct mtk_wmt_hdr *)&wc;
hdr->dir = 1;
......@@ -173,7 +175,7 @@ static int mtk_hci_wmt_sync(struct hci_dev *hdev,
err = __hci_cmd_send(hdev, 0xfc6f, hlen, &wc);
if (err < 0) {
clear_bit(BTMTKUART_TX_WAIT_VND_EVT, &bdev->tx_state);
return err;
goto err_free_skb;
}
/* The vendor specific WMT commands are all answered by a vendor
......@@ -190,13 +192,14 @@ static int mtk_hci_wmt_sync(struct hci_dev *hdev,
if (err == -EINTR) {
bt_dev_err(hdev, "Execution of wmt command interrupted");
clear_bit(BTMTKUART_TX_WAIT_VND_EVT, &bdev->tx_state);
return err;
goto err_free_skb;
}
if (err) {
bt_dev_err(hdev, "Execution of wmt command timed out");
clear_bit(BTMTKUART_TX_WAIT_VND_EVT, &bdev->tx_state);
return -ETIMEDOUT;
err = -ETIMEDOUT;
goto err_free_skb;
}
/* Parse and handle the return WMT event */
......
......@@ -19,7 +19,6 @@
#include <net/bluetooth/hci_core.h>
#include <asm/unaligned.h>
#include <net/rsi_91x.h>
#include <net/genetlink.h>
#define RSI_DMA_ALIGN 8
#define RSI_FRAME_DESC_SIZE 16
......
......@@ -59,6 +59,7 @@ struct id_table {
__u8 hci_bus;
bool config_needed;
bool has_rom_version;
bool has_msft_ext;
char *fw_name;
char *cfg_name;
};
......@@ -121,6 +122,7 @@ static const struct id_table ic_id_table[] = {
{ IC_INFO(RTL_ROM_LMP_8821A, 0xc, 0x8, HCI_USB),
.config_needed = false,
.has_rom_version = true,
.has_msft_ext = true,
.fw_name = "rtl_bt/rtl8821c_fw.bin",
.cfg_name = "rtl_bt/rtl8821c_config" },
......@@ -135,6 +137,7 @@ static const struct id_table ic_id_table[] = {
{ IC_INFO(RTL_ROM_LMP_8761A, 0xb, 0xa, HCI_UART),
.config_needed = false,
.has_rom_version = true,
.has_msft_ext = true,
.fw_name = "rtl_bt/rtl8761b_fw.bin",
.cfg_name = "rtl_bt/rtl8761b_config" },
......@@ -149,6 +152,7 @@ static const struct id_table ic_id_table[] = {
{ IC_INFO(RTL_ROM_LMP_8822B, 0xc, 0xa, HCI_UART),
.config_needed = true,
.has_rom_version = true,
.has_msft_ext = true,
.fw_name = "rtl_bt/rtl8822cs_fw.bin",
.cfg_name = "rtl_bt/rtl8822cs_config" },
......@@ -156,6 +160,7 @@ static const struct id_table ic_id_table[] = {
{ IC_INFO(RTL_ROM_LMP_8822B, 0xc, 0xa, HCI_USB),
.config_needed = false,
.has_rom_version = true,
.has_msft_ext = true,
.fw_name = "rtl_bt/rtl8822cu_fw.bin",
.cfg_name = "rtl_bt/rtl8822cu_config" },
......@@ -163,6 +168,7 @@ static const struct id_table ic_id_table[] = {
{ IC_INFO(RTL_ROM_LMP_8822B, 0xb, 0x7, HCI_USB),
.config_needed = true,
.has_rom_version = true,
.has_msft_ext = true,
.fw_name = "rtl_bt/rtl8822b_fw.bin",
.cfg_name = "rtl_bt/rtl8822b_config" },
......@@ -170,6 +176,7 @@ static const struct id_table ic_id_table[] = {
{ IC_INFO(RTL_ROM_LMP_8852A, 0xa, 0xb, HCI_USB),
.config_needed = false,
.has_rom_version = true,
.has_msft_ext = true,
.fw_name = "rtl_bt/rtl8852au_fw.bin",
.cfg_name = "rtl_bt/rtl8852au_config" },
};
......@@ -594,8 +601,10 @@ struct btrtl_device_info *btrtl_initialize(struct hci_dev *hdev,
hci_rev = le16_to_cpu(resp->hci_rev);
lmp_subver = le16_to_cpu(resp->lmp_subver);
if (resp->hci_ver == 0x8 && le16_to_cpu(resp->hci_rev) == 0x826c &&
resp->lmp_ver == 0x8 && le16_to_cpu(resp->lmp_subver) == 0xa99e)
btrtl_dev->ic_info = btrtl_match_ic(lmp_subver, hci_rev, hci_ver,
hdev->bus);
if (!btrtl_dev->ic_info)
btrtl_dev->drop_fw = true;
if (btrtl_dev->drop_fw) {
......@@ -634,13 +643,13 @@ struct btrtl_device_info *btrtl_initialize(struct hci_dev *hdev,
hci_ver = resp->hci_ver;
hci_rev = le16_to_cpu(resp->hci_rev);
lmp_subver = le16_to_cpu(resp->lmp_subver);
btrtl_dev->ic_info = btrtl_match_ic(lmp_subver, hci_rev, hci_ver,
hdev->bus);
}
out_free:
kfree_skb(skb);
btrtl_dev->ic_info = btrtl_match_ic(lmp_subver, hci_rev, hci_ver,
hdev->bus);
if (!btrtl_dev->ic_info) {
rtl_dev_info(hdev, "unknown IC info, lmp subver %04x, hci rev %04x, hci ver %04x",
lmp_subver, hci_rev, hci_ver);
......@@ -684,12 +693,8 @@ struct btrtl_device_info *btrtl_initialize(struct hci_dev *hdev,
/* The following chips supports the Microsoft vendor extension,
* therefore set the corresponding VsMsftOpCode.
*/
switch (lmp_subver) {
case RTL_ROM_LMP_8822B:
case RTL_ROM_LMP_8852A:
if (btrtl_dev->ic_info->has_msft_ext)
hci_set_msft_opcode(hdev, 0xFCF0);
break;
}
return btrtl_dev;
......@@ -746,6 +751,7 @@ void btrtl_set_quirks(struct hci_dev *hdev, struct btrtl_device_info *btrtl_dev)
case CHIP_ID_8852A:
set_bit(HCI_QUIRK_VALID_LE_STATES, &hdev->quirks);
set_bit(HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED, &hdev->quirks);
hci_set_aosp_capable(hdev);
break;
default:
rtl_dev_dbg(hdev, "Central-peripheral role not enabled.");
......
......@@ -384,6 +384,12 @@ 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, 0x4852), .driver_info = BTUSB_REALTEK |
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x04c5, 0x165c), .driver_info = BTUSB_REALTEK |
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x04ca, 0x4006), .driver_info = BTUSB_REALTEK |
BTUSB_WIDEBAND_SPEECH },
/* Realtek Bluetooth devices */
{ USB_VENDOR_AND_INTERFACE_INFO(0x0bda, 0xe0, 0x01, 0x01),
......@@ -410,6 +416,9 @@ static const struct usb_device_id blacklist_table[] = {
{ USB_DEVICE(0x13d3, 0x3563), .driver_info = BTUSB_MEDIATEK |
BTUSB_WIDEBAND_SPEECH |
BTUSB_VALID_LE_STATES },
{ USB_DEVICE(0x13d3, 0x3564), .driver_info = BTUSB_MEDIATEK |
BTUSB_WIDEBAND_SPEECH |
BTUSB_VALID_LE_STATES },
{ USB_DEVICE(0x0489, 0xe0cd), .driver_info = BTUSB_MEDIATEK |
BTUSB_WIDEBAND_SPEECH |
BTUSB_VALID_LE_STATES },
......@@ -433,6 +442,10 @@ static const struct usb_device_id blacklist_table[] = {
{ USB_DEVICE(0x0bda, 0xb009), .driver_info = BTUSB_REALTEK },
{ USB_DEVICE(0x2ff8, 0xb011), .driver_info = BTUSB_REALTEK },
/* Additional Realtek 8761B Bluetooth devices */
{ USB_DEVICE(0x2357, 0x0604), .driver_info = BTUSB_REALTEK |
BTUSB_WIDEBAND_SPEECH },
/* Additional Realtek 8761BU Bluetooth devices */
{ USB_DEVICE(0x0b05, 0x190e), .driver_info = BTUSB_REALTEK |
BTUSB_WIDEBAND_SPEECH },
......@@ -451,10 +464,6 @@ static const struct usb_device_id blacklist_table[] = {
/* Additional Realtek 8822CE Bluetooth devices */
{ USB_DEVICE(0x04ca, 0x4005), .driver_info = BTUSB_REALTEK |
BTUSB_WIDEBAND_SPEECH },
/* Bluetooth component of Realtek 8852AE device */
{ USB_DEVICE(0x04ca, 0x4006), .driver_info = BTUSB_REALTEK |
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x04c5, 0x161f), .driver_info = BTUSB_REALTEK |
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x0b05, 0x18ef), .driver_info = BTUSB_REALTEK |
......@@ -652,11 +661,33 @@ static void btusb_rtl_cmd_timeout(struct hci_dev *hdev)
static void btusb_qca_cmd_timeout(struct hci_dev *hdev)
{
struct btusb_data *data = hci_get_drvdata(hdev);
struct gpio_desc *reset_gpio = data->reset_gpio;
int err;
if (++data->cmd_timeout_cnt < 5)
return;
if (reset_gpio) {
bt_dev_err(hdev, "Reset qca device via bt_en gpio");
/* Toggle the hard reset line. The qca bt device is going to
* yank itself off the USB and then replug. The cleanup is handled
* correctly on the way out (standard USB disconnect), and the new
* device is detected cleanly and bound to the driver again like
* it should be.
*/
if (test_and_set_bit(BTUSB_HW_RESET_ACTIVE, &data->flags)) {
bt_dev_err(hdev, "last reset failed? Not resetting again");
return;
}
gpiod_set_value_cansleep(reset_gpio, 0);
msleep(200);
gpiod_set_value_cansleep(reset_gpio, 1);
return;
}
bt_dev_err(hdev, "Multiple cmd timeouts seen. Resetting usb device.");
/* This is not an unbalanced PM reference since the device will reset */
err = usb_autopm_get_interface(data->intf);
......@@ -2200,6 +2231,23 @@ struct btmtk_section_map {
};
} __packed;
static int btusb_set_bdaddr_mtk(struct hci_dev *hdev, const bdaddr_t *bdaddr)
{
struct sk_buff *skb;
long ret;
skb = __hci_cmd_sync(hdev, 0xfc1a, sizeof(bdaddr), bdaddr, HCI_INIT_TIMEOUT);
if (IS_ERR(skb)) {
ret = PTR_ERR(skb);
bt_dev_err(hdev, "changing Mediatek device address failed (%ld)",
ret);
return ret;
}
kfree_skb(skb);
return 0;
}
static void btusb_mtk_wmt_recv(struct urb *urb)
{
struct hci_dev *hdev = urb->context;
......@@ -2804,6 +2852,7 @@ static int btusb_mtk_setup(struct hci_dev *hdev)
case 0x7668:
fwname = FIRMWARE_MT7668;
break;
case 0x7922:
case 0x7961:
snprintf(fw_bin_name, sizeof(fw_bin_name),
"mediatek/BT_RAM_CODE_MT%04x_1_%x_hdr.bin",
......@@ -3591,11 +3640,11 @@ static void btusb_check_needs_reset_resume(struct usb_interface *intf)
interface_to_usbdev(intf)->quirks |= USB_QUIRK_RESET_RESUME;
}
static bool btusb_prevent_wake(struct hci_dev *hdev)
static bool btusb_wakeup(struct hci_dev *hdev)
{
struct btusb_data *data = hci_get_drvdata(hdev);
return !device_may_wakeup(&data->udev->dev);
return device_may_wakeup(&data->udev->dev);
}
static int btusb_shutdown_qca(struct hci_dev *hdev)
......@@ -3752,7 +3801,7 @@ static int btusb_probe(struct usb_interface *intf,
hdev->flush = btusb_flush;
hdev->send = btusb_send_frame;
hdev->notify = btusb_notify;
hdev->prevent_wake = btusb_prevent_wake;
hdev->wakeup = btusb_wakeup;
#ifdef CONFIG_PM
err = btusb_config_oob_wake(hdev);
......@@ -3819,6 +3868,7 @@ static int btusb_probe(struct usb_interface *intf,
hdev->shutdown = btusb_mtk_shutdown;
hdev->manufacturer = 70;
hdev->cmd_timeout = btusb_mtk_cmd_timeout;
hdev->set_bdaddr = btusb_set_bdaddr_mtk;
set_bit(HCI_QUIRK_NON_PERSISTENT_SETUP, &hdev->quirks);
data->recv_acl = btusb_recv_acl_mtk;
}
......
......@@ -587,9 +587,11 @@ static int h5_recv(struct hci_uart *hu, const void *data, int count)
count -= processed;
}
pm_runtime_get(&hu->serdev->dev);
pm_runtime_mark_last_busy(&hu->serdev->dev);
pm_runtime_put_autosuspend(&hu->serdev->dev);
if (hu->serdev) {
pm_runtime_get(&hu->serdev->dev);
pm_runtime_mark_last_busy(&hu->serdev->dev);
pm_runtime_put_autosuspend(&hu->serdev->dev);
}
return 0;
}
......@@ -814,7 +816,6 @@ static int h5_serdev_probe(struct serdev_device *serdev)
struct device *dev = &serdev->dev;
struct h5 *h5;
const struct h5_device_data *data;
int err;
h5 = devm_kzalloc(dev, sizeof(*h5), GFP_KERNEL);
if (!h5)
......@@ -846,6 +847,8 @@ static int h5_serdev_probe(struct serdev_device *serdev)
h5->vnd = data->vnd;
}
if (data->driver_info & H5_INFO_WAKEUP_DISABLE)
set_bit(H5_WAKEUP_DISABLE, &h5->flags);
h5->enable_gpio = devm_gpiod_get_optional(dev, "enable", GPIOD_OUT_LOW);
if (IS_ERR(h5->enable_gpio))
......@@ -856,14 +859,7 @@ static int h5_serdev_probe(struct serdev_device *serdev)
if (IS_ERR(h5->device_wake_gpio))
return PTR_ERR(h5->device_wake_gpio);
err = hci_uart_register_device(&h5->serdev_hu, &h5p);
if (err)
return err;
if (data->driver_info & H5_INFO_WAKEUP_DISABLE)
set_bit(H5_WAKEUP_DISABLE, &h5->flags);
return 0;
return hci_uart_register_device(&h5->serdev_hu, &h5p);
}
static void h5_serdev_remove(struct serdev_device *serdev)
......@@ -962,11 +958,13 @@ static void h5_btrtl_open(struct h5 *h5)
serdev_device_set_parity(h5->hu->serdev, SERDEV_PARITY_EVEN);
serdev_device_set_baudrate(h5->hu->serdev, 115200);
pm_runtime_set_active(&h5->hu->serdev->dev);
pm_runtime_use_autosuspend(&h5->hu->serdev->dev);
pm_runtime_set_autosuspend_delay(&h5->hu->serdev->dev,
SUSPEND_TIMEOUT_MS);
pm_runtime_enable(&h5->hu->serdev->dev);
if (!test_bit(H5_WAKEUP_DISABLE, &h5->flags)) {
pm_runtime_set_active(&h5->hu->serdev->dev);
pm_runtime_use_autosuspend(&h5->hu->serdev->dev);
pm_runtime_set_autosuspend_delay(&h5->hu->serdev->dev,
SUSPEND_TIMEOUT_MS);
pm_runtime_enable(&h5->hu->serdev->dev);
}
/* The controller needs up to 500ms to wakeup */
gpiod_set_value_cansleep(h5->enable_gpio, 1);
......@@ -976,7 +974,8 @@ static void h5_btrtl_open(struct h5 *h5)
static void h5_btrtl_close(struct h5 *h5)
{
pm_runtime_disable(&h5->hu->serdev->dev);
if (!test_bit(H5_WAKEUP_DISABLE, &h5->flags))
pm_runtime_disable(&h5->hu->serdev->dev);
gpiod_set_value_cansleep(h5->device_wake_gpio, 0);
gpiod_set_value_cansleep(h5->enable_gpio, 0);
......
......@@ -479,6 +479,9 @@ static int hci_uart_tty_open(struct tty_struct *tty)
BT_DBG("tty %p", tty);
if (!capable(CAP_NET_ADMIN))
return -EPERM;
/* Error if the tty has no write op instead of leaving an exploitable
* hole
*/
......
......@@ -1577,7 +1577,7 @@ static void qca_cmd_timeout(struct hci_dev *hdev)
mutex_unlock(&qca->hci_memdump_lock);
}
static bool qca_prevent_wake(struct hci_dev *hdev)
static bool qca_wakeup(struct hci_dev *hdev)
{
struct hci_uart *hu = hci_get_drvdata(hdev);
bool wakeup;
......@@ -1730,6 +1730,7 @@ static int qca_setup(struct hci_uart *hu)
if (qca_is_wcn399x(soc_type) ||
qca_is_wcn6750(soc_type)) {
set_bit(HCI_QUIRK_USE_BDADDR_PROPERTY, &hdev->quirks);
hci_set_aosp_capable(hdev);
ret = qca_read_soc_version(hdev, &ver, soc_type);
if (ret)
......@@ -1764,7 +1765,7 @@ static int qca_setup(struct hci_uart *hu)
qca_debugfs_init(hdev);
hu->hdev->hw_error = qca_hw_error;
hu->hdev->cmd_timeout = qca_cmd_timeout;
hu->hdev->prevent_wake = qca_prevent_wake;
hu->hdev->wakeup = qca_wakeup;
} else if (ret == -ENOENT) {
/* No patch/nvm-config found, run with original fw/config */
set_bit(QCA_ROM_FW, &qca->flags);
......
......@@ -21,6 +21,7 @@
#include <linux/skbuff.h>
#include <linux/miscdevice.h>
#include <linux/debugfs.h>
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>
......@@ -37,6 +38,9 @@ struct vhci_data {
struct mutex open_mutex;
struct delayed_work open_timeout;
bool suspended;
bool wakeup;
};
static int vhci_open_dev(struct hci_dev *hdev)
......@@ -73,6 +77,115 @@ static int vhci_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
return 0;
}
static int vhci_get_data_path_id(struct hci_dev *hdev, u8 *data_path_id)
{
*data_path_id = 0;
return 0;
}
static int vhci_get_codec_config_data(struct hci_dev *hdev, __u8 type,
struct bt_codec *codec, __u8 *vnd_len,
__u8 **vnd_data)
{
if (type != ESCO_LINK)
return -EINVAL;
*vnd_len = 0;
*vnd_data = NULL;
return 0;
}
static bool vhci_wakeup(struct hci_dev *hdev)
{
struct vhci_data *data = hci_get_drvdata(hdev);
return data->wakeup;
}
static ssize_t force_suspend_read(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
struct vhci_data *data = file->private_data;
char buf[3];
buf[0] = data->suspended ? 'Y' : 'N';
buf[1] = '\n';
buf[2] = '\0';
return simple_read_from_buffer(user_buf, count, ppos, buf, 2);
}
static ssize_t force_suspend_write(struct file *file,
const char __user *user_buf,
size_t count, loff_t *ppos)
{
struct vhci_data *data = file->private_data;
bool enable;
int err;
err = kstrtobool_from_user(user_buf, count, &enable);
if (err)
return err;
if (data->suspended == enable)
return -EALREADY;
if (enable)
err = hci_suspend_dev(data->hdev);
else
err = hci_resume_dev(data->hdev);
if (err)
return err;
data->suspended = enable;
return count;
}
static const struct file_operations force_suspend_fops = {
.open = simple_open,
.read = force_suspend_read,
.write = force_suspend_write,
.llseek = default_llseek,
};
static ssize_t force_wakeup_read(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
struct vhci_data *data = file->private_data;
char buf[3];
buf[0] = data->wakeup ? 'Y' : 'N';
buf[1] = '\n';
buf[2] = '\0';
return simple_read_from_buffer(user_buf, count, ppos, buf, 2);
}
static ssize_t force_wakeup_write(struct file *file,
const char __user *user_buf, size_t count,
loff_t *ppos)
{
struct vhci_data *data = file->private_data;
bool enable;
int err;
err = kstrtobool_from_user(user_buf, count, &enable);
if (err)
return err;
if (data->wakeup == enable)
return -EALREADY;
return count;
}
static const struct file_operations force_wakeup_fops = {
.open = simple_open,
.read = force_wakeup_read,
.write = force_wakeup_write,
.llseek = default_llseek,
};
static int __vhci_create_device(struct vhci_data *data, __u8 opcode)
{
struct hci_dev *hdev;
......@@ -112,6 +225,9 @@ static int __vhci_create_device(struct vhci_data *data, __u8 opcode)
hdev->close = vhci_close_dev;
hdev->flush = vhci_flush;
hdev->send = vhci_send_frame;
hdev->get_data_path_id = vhci_get_data_path_id;
hdev->get_codec_config_data = vhci_get_codec_config_data;
hdev->wakeup = vhci_wakeup;
/* bit 6 is for external configuration */
if (opcode & 0x40)
......@@ -129,6 +245,12 @@ static int __vhci_create_device(struct vhci_data *data, __u8 opcode)
return -EBUSY;
}
debugfs_create_file("force_suspend", 0644, hdev->debugfs, data,
&force_suspend_fops);
debugfs_create_file("force_wakeup", 0644, hdev->debugfs, data,
&force_wakeup_fops);
hci_skb_pkt_type(skb) = HCI_VENDOR_PKT;
skb_put_u8(skb, 0xff);
......
......@@ -153,6 +153,30 @@ struct bt_voice {
#define BT_SCM_PKT_STATUS 0x03
#define BT_CODEC 19
struct bt_codec_caps {
__u8 len;
__u8 data[];
} __packed;
struct bt_codec {
__u8 id;
__u16 cid;
__u16 vid;
__u8 data_path;
__u8 num_caps;
} __packed;
struct bt_codecs {
__u8 num_codecs;
struct bt_codec codecs[];
} __packed;
#define BT_CODEC_CVSD 0x02
#define BT_CODEC_TRANSPARENT 0x03
#define BT_CODEC_MSBC 0x05
__printf(1, 2)
void bt_info(const char *fmt, ...);
__printf(1, 2)
......@@ -420,6 +444,72 @@ static inline struct sk_buff *bt_skb_send_alloc(struct sock *sk,
return NULL;
}
/* Shall not be called with lock_sock held */
static inline struct sk_buff *bt_skb_sendmsg(struct sock *sk,
struct msghdr *msg,
size_t len, size_t mtu,
size_t headroom, size_t tailroom)
{
struct sk_buff *skb;
size_t size = min_t(size_t, len, mtu);
int err;
skb = bt_skb_send_alloc(sk, size + headroom + tailroom,
msg->msg_flags & MSG_DONTWAIT, &err);
if (!skb)
return ERR_PTR(err);
skb_reserve(skb, headroom);
skb_tailroom_reserve(skb, mtu, tailroom);
if (!copy_from_iter_full(skb_put(skb, size), size, &msg->msg_iter)) {
kfree_skb(skb);
return ERR_PTR(-EFAULT);
}
skb->priority = sk->sk_priority;
return skb;
}
/* Similar to bt_skb_sendmsg but can split the msg into multiple fragments
* accourding to the MTU.
*/
static inline struct sk_buff *bt_skb_sendmmsg(struct sock *sk,
struct msghdr *msg,
size_t len, size_t mtu,
size_t headroom, size_t tailroom)
{
struct sk_buff *skb, **frag;
skb = bt_skb_sendmsg(sk, msg, len, mtu, headroom, tailroom);
if (IS_ERR_OR_NULL(skb))
return skb;
len -= skb->len;
if (!len)
return skb;
/* Add remaining data over MTU as continuation fragments */
frag = &skb_shinfo(skb)->frag_list;
while (len) {
struct sk_buff *tmp;
tmp = bt_skb_sendmsg(sk, msg, len, mtu, headroom, tailroom);
if (IS_ERR(tmp)) {
kfree_skb(skb);
return tmp;
}
len -= tmp->len;
*frag = tmp;
frag = &(*frag)->next;
}
return skb;
}
int bt_to_errno(u16 code);
void hci_sock_set_flag(struct sock *sk, int nr);
......
......@@ -330,6 +330,8 @@ enum {
HCI_ENABLE_LL_PRIVACY,
HCI_CMD_PENDING,
HCI_FORCE_NO_MITM,
HCI_QUALITY_REPORT,
HCI_OFFLOAD_CODECS_ENABLED,
__HCI_NUM_FLAGS,
};
......@@ -871,6 +873,40 @@ struct hci_cp_logical_link_cancel {
__u8 flow_spec_id;
} __packed;
#define HCI_OP_ENHANCED_SETUP_SYNC_CONN 0x043d
struct hci_coding_format {
__u8 id;
__le16 cid;
__le16 vid;
} __packed;
struct hci_cp_enhanced_setup_sync_conn {
__le16 handle;
__le32 tx_bandwidth;
__le32 rx_bandwidth;
struct hci_coding_format tx_coding_format;
struct hci_coding_format rx_coding_format;
__le16 tx_codec_frame_size;
__le16 rx_codec_frame_size;
__le32 in_bandwidth;
__le32 out_bandwidth;
struct hci_coding_format in_coding_format;
struct hci_coding_format out_coding_format;
__le16 in_coded_data_size;
__le16 out_coded_data_size;
__u8 in_pcm_data_format;
__u8 out_pcm_data_format;
__u8 in_pcm_sample_payload_msb_pos;
__u8 out_pcm_sample_payload_msb_pos;
__u8 in_data_path;
__u8 out_data_path;
__u8 in_transport_unit_size;
__u8 out_transport_unit_size;
__le16 max_latency;
__le16 pkt_type;
__u8 retrans_effort;
} __packed;
struct hci_rp_logical_link_cancel {
__u8 status;
__u8 phy_handle;
......@@ -1250,6 +1286,14 @@ struct hci_rp_read_local_oob_ext_data {
__u8 rand256[16];
} __packed;
#define HCI_CONFIGURE_DATA_PATH 0x0c83
struct hci_op_configure_data_path {
__u8 direction;
__u8 data_path_id;
__u8 vnd_len;
__u8 vnd_data[];
} __packed;
#define HCI_OP_READ_LOCAL_VERSION 0x1001
struct hci_rp_read_local_version {
__u8 status;
......@@ -1307,6 +1351,28 @@ struct hci_rp_read_data_block_size {
} __packed;
#define HCI_OP_READ_LOCAL_CODECS 0x100b
struct hci_std_codecs {
__u8 num;
__u8 codec[];
} __packed;
struct hci_vnd_codec {
/* company id */
__le16 cid;
/* vendor codec id */
__le16 vid;
} __packed;
struct hci_vnd_codecs {
__u8 num;
struct hci_vnd_codec codec[];
} __packed;
struct hci_rp_read_local_supported_codecs {
__u8 status;
struct hci_std_codecs std_codecs;
struct hci_vnd_codecs vnd_codecs;
} __packed;
#define HCI_OP_READ_LOCAL_PAIRING_OPTS 0x100c
struct hci_rp_read_local_pairing_opts {
......@@ -1315,6 +1381,54 @@ struct hci_rp_read_local_pairing_opts {
__u8 max_key_size;
} __packed;
#define HCI_OP_READ_LOCAL_CODECS_V2 0x100d
struct hci_std_codec_v2 {
__u8 id;
__u8 transport;
} __packed;
struct hci_std_codecs_v2 {
__u8 num;
struct hci_std_codec_v2 codec[];
} __packed;
struct hci_vnd_codec_v2 {
__u8 id;
__le16 cid;
__le16 vid;
__u8 transport;
} __packed;
struct hci_vnd_codecs_v2 {
__u8 num;
struct hci_vnd_codec_v2 codec[];
} __packed;
struct hci_rp_read_local_supported_codecs_v2 {
__u8 status;
struct hci_std_codecs_v2 std_codecs;
struct hci_vnd_codecs_v2 vendor_codecs;
} __packed;
#define HCI_OP_READ_LOCAL_CODEC_CAPS 0x100e
struct hci_op_read_local_codec_caps {
__u8 id;
__le16 cid;
__le16 vid;
__u8 transport;
__u8 direction;
} __packed;
struct hci_codec_caps {
__u8 len;
__u8 data[];
} __packed;
struct hci_rp_read_local_codec_caps {
__u8 status;
__u8 num_caps;
} __packed;
#define HCI_OP_READ_PAGE_SCAN_ACTIVITY 0x0c1b
struct hci_rp_read_page_scan_activity {
__u8 status;
......@@ -2551,6 +2665,9 @@ static inline struct hci_sco_hdr *hci_sco_hdr(const struct sk_buff *skb)
#define hci_iso_data_len(h) ((h) & 0x3fff)
#define hci_iso_data_flags(h) ((h) >> 14)
/* codec transport types */
#define HCI_TRANSPORT_SCO_ESCO 0x01
/* le24 support */
static inline void hci_cpu_to_le24(__u32 val, __u8 dst[3])
{
......
......@@ -131,6 +131,17 @@ struct bdaddr_list {
u8 bdaddr_type;
};
struct codec_list {
struct list_head list;
u8 id;
__u16 cid;
__u16 vid;
u8 transport;
u8 num_caps;
u32 len;
struct hci_codec_caps caps[];
};
struct bdaddr_list_with_irk {
struct list_head list;
bdaddr_t bdaddr;
......@@ -536,6 +547,7 @@ struct hci_dev {
struct list_head pend_le_conns;
struct list_head pend_le_reports;
struct list_head blocked_keys;
struct list_head local_codecs;
struct hci_dev_stats stat;
......@@ -605,7 +617,12 @@ struct hci_dev {
int (*set_diag)(struct hci_dev *hdev, bool enable);
int (*set_bdaddr)(struct hci_dev *hdev, const bdaddr_t *bdaddr);
void (*cmd_timeout)(struct hci_dev *hdev);
bool (*prevent_wake)(struct hci_dev *hdev);
bool (*wakeup)(struct hci_dev *hdev);
int (*set_quality_report)(struct hci_dev *hdev, bool enable);
int (*get_data_path_id)(struct hci_dev *hdev, __u8 *data_path);
int (*get_codec_config_data)(struct hci_dev *hdev, __u8 type,
struct bt_codec *codec, __u8 *vnd_len,
__u8 **vnd_data);
};
#define HCI_PHY_HANDLE(handle) (handle & 0xff)
......@@ -699,6 +716,7 @@ struct hci_conn {
struct amp_mgr *amp_mgr;
struct hci_conn *link;
struct bt_codec codec;
void (*connect_cfm_cb) (struct hci_conn *conn, u8 status);
void (*security_cfm_cb) (struct hci_conn *conn, u8 status);
......@@ -760,6 +778,7 @@ extern struct mutex hci_cb_list_lock;
hci_dev_clear_flag(hdev, HCI_LE_ADV); \
hci_dev_clear_flag(hdev, HCI_LL_RPA_RESOLUTION);\
hci_dev_clear_flag(hdev, HCI_PERIODIC_INQ); \
hci_dev_clear_flag(hdev, HCI_QUALITY_REPORT); \
} while (0)
/* ----- HCI interface to upper protocols ----- */
......@@ -1099,13 +1118,14 @@ struct hci_conn *hci_connect_le_scan(struct hci_dev *hdev, bdaddr_t *dst,
u16 conn_timeout,
enum conn_reasons conn_reason);
struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst,
u8 dst_type, u8 sec_level, u16 conn_timeout,
u8 role, bdaddr_t *direct_rpa);
u8 dst_type, bool dst_resolved, u8 sec_level,
u16 conn_timeout, u8 role,
bdaddr_t *direct_rpa);
struct hci_conn *hci_connect_acl(struct hci_dev *hdev, bdaddr_t *dst,
u8 sec_level, u8 auth_type,
enum conn_reasons conn_reason);
struct hci_conn *hci_connect_sco(struct hci_dev *hdev, int type, bdaddr_t *dst,
__u16 setting);
__u16 setting, struct bt_codec *codec);
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,
......@@ -1360,6 +1380,8 @@ int hci_set_adv_instance_data(struct hci_dev *hdev, u8 instance,
u16 scan_rsp_len, u8 *scan_rsp_data);
int hci_remove_adv_instance(struct hci_dev *hdev, u8 instance);
void hci_adv_instances_set_rpa_expired(struct hci_dev *hdev, bool rpa_expired);
u32 hci_adv_instance_flags(struct hci_dev *hdev, u8 instance);
bool hci_adv_instance_is_scannable(struct hci_dev *hdev, u8 instance);
void hci_adv_monitors_clear(struct hci_dev *hdev);
void hci_free_adv_monitor(struct hci_dev *hdev, struct adv_monitor *monitor);
......@@ -1442,6 +1464,9 @@ void hci_conn_del_sysfs(struct hci_conn *conn);
/* Use LL Privacy based address resolution if supported */
#define use_ll_privacy(dev) ((dev)->le_features[0] & HCI_LE_LL_PRIVACY)
/* Use enhanced synchronous connection if command is supported */
#define enhanced_sco_capable(dev) ((dev)->commands[29] & 0x08)
/* Use ext scanning if set ext scan param and ext scan enable is supported */
#define use_ext_scan(dev) (((dev)->commands[37] & 0x20) && \
((dev)->commands[37] & 0x40))
......@@ -1609,43 +1634,6 @@ static inline void hci_role_switch_cfm(struct hci_conn *conn, __u8 status,
mutex_unlock(&hci_cb_list_lock);
}
static inline void *eir_get_data(u8 *eir, size_t eir_len, u8 type,
size_t *data_len)
{
size_t parsed = 0;
if (eir_len < 2)
return NULL;
while (parsed < eir_len - 1) {
u8 field_len = eir[0];
if (field_len == 0)
break;
parsed += field_len + 1;
if (parsed > eir_len)
break;
if (eir[1] != type) {
eir += field_len + 1;
continue;
}
/* Zero length data */
if (field_len == 1)
return NULL;
if (data_len)
*data_len = field_len - 1;
return &eir[2];
}
return NULL;
}
static inline bool hci_bdaddr_is_rpa(bdaddr_t *bdaddr, u8 addr_type)
{
if (addr_type != ADDR_LE_DEV_RANDOM)
......@@ -1867,4 +1855,9 @@ void hci_copy_identity_address(struct hci_dev *hdev, bdaddr_t *bdaddr,
#define SCO_AIRMODE_CVSD 0x0000
#define SCO_AIRMODE_TRANSP 0x0003
#define LOCAL_CODEC_ACL_MASK BIT(0)
#define LOCAL_CODEC_SCO_MASK BIT(1)
#define TRANSPORT_TYPE_MAX 0x04
#endif /* __HCI_CORE_H */
......@@ -14,7 +14,8 @@ bluetooth_6lowpan-y := 6lowpan.o
bluetooth-y := af_bluetooth.o hci_core.o hci_conn.o hci_event.o mgmt.o \
hci_sock.o hci_sysfs.o l2cap_core.o l2cap_sock.o smp.o lib.o \
ecdh_helper.o hci_request.o mgmt_util.o mgmt_config.o
ecdh_helper.o hci_request.o mgmt_util.o mgmt_config.o hci_codec.o \
eir.o
bluetooth-$(CONFIG_BT_BREDR) += sco.o
bluetooth-$(CONFIG_BT_HS) += a2mp.o amp.o
......
// SPDX-License-Identifier: GPL-2.0
/*
* BlueZ - Bluetooth protocol stack for Linux
*
* Copyright (C) 2021 Intel Corporation
*/
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>
#include <net/bluetooth/mgmt.h>
#include "eir.h"
#define PNP_INFO_SVCLASS_ID 0x1200
u8 eir_append_local_name(struct hci_dev *hdev, u8 *ptr, u8 ad_len)
{
size_t short_len;
size_t complete_len;
/* no space left for name (+ NULL + type + len) */
if ((HCI_MAX_AD_LENGTH - ad_len) < HCI_MAX_SHORT_NAME_LENGTH + 3)
return ad_len;
/* use complete name if present and fits */
complete_len = strlen(hdev->dev_name);
if (complete_len && complete_len <= HCI_MAX_SHORT_NAME_LENGTH)
return eir_append_data(ptr, ad_len, EIR_NAME_COMPLETE,
hdev->dev_name, complete_len + 1);
/* use short name if present */
short_len = strlen(hdev->short_name);
if (short_len)
return eir_append_data(ptr, ad_len, EIR_NAME_SHORT,
hdev->short_name, short_len + 1);
/* use shortened full name if present, we already know that name
* is longer then HCI_MAX_SHORT_NAME_LENGTH
*/
if (complete_len) {
u8 name[HCI_MAX_SHORT_NAME_LENGTH + 1];
memcpy(name, hdev->dev_name, HCI_MAX_SHORT_NAME_LENGTH);
name[HCI_MAX_SHORT_NAME_LENGTH] = '\0';
return eir_append_data(ptr, ad_len, EIR_NAME_SHORT, name,
sizeof(name));
}
return ad_len;
}
u8 eir_append_appearance(struct hci_dev *hdev, u8 *ptr, u8 ad_len)
{
return eir_append_le16(ptr, ad_len, EIR_APPEARANCE, hdev->appearance);
}
static u8 *create_uuid16_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
{
u8 *ptr = data, *uuids_start = NULL;
struct bt_uuid *uuid;
if (len < 4)
return ptr;
list_for_each_entry(uuid, &hdev->uuids, list) {
u16 uuid16;
if (uuid->size != 16)
continue;
uuid16 = get_unaligned_le16(&uuid->uuid[12]);
if (uuid16 < 0x1100)
continue;
if (uuid16 == PNP_INFO_SVCLASS_ID)
continue;
if (!uuids_start) {
uuids_start = ptr;
uuids_start[0] = 1;
uuids_start[1] = EIR_UUID16_ALL;
ptr += 2;
}
/* Stop if not enough space to put next UUID */
if ((ptr - data) + sizeof(u16) > len) {
uuids_start[1] = EIR_UUID16_SOME;
break;
}
*ptr++ = (uuid16 & 0x00ff);
*ptr++ = (uuid16 & 0xff00) >> 8;
uuids_start[0] += sizeof(uuid16);
}
return ptr;
}
static u8 *create_uuid32_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
{
u8 *ptr = data, *uuids_start = NULL;
struct bt_uuid *uuid;
if (len < 6)
return ptr;
list_for_each_entry(uuid, &hdev->uuids, list) {
if (uuid->size != 32)
continue;
if (!uuids_start) {
uuids_start = ptr;
uuids_start[0] = 1;
uuids_start[1] = EIR_UUID32_ALL;
ptr += 2;
}
/* Stop if not enough space to put next UUID */
if ((ptr - data) + sizeof(u32) > len) {
uuids_start[1] = EIR_UUID32_SOME;
break;
}
memcpy(ptr, &uuid->uuid[12], sizeof(u32));
ptr += sizeof(u32);
uuids_start[0] += sizeof(u32);
}
return ptr;
}
static u8 *create_uuid128_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
{
u8 *ptr = data, *uuids_start = NULL;
struct bt_uuid *uuid;
if (len < 18)
return ptr;
list_for_each_entry(uuid, &hdev->uuids, list) {
if (uuid->size != 128)
continue;
if (!uuids_start) {
uuids_start = ptr;
uuids_start[0] = 1;
uuids_start[1] = EIR_UUID128_ALL;
ptr += 2;
}
/* Stop if not enough space to put next UUID */
if ((ptr - data) + 16 > len) {
uuids_start[1] = EIR_UUID128_SOME;
break;
}
memcpy(ptr, uuid->uuid, 16);
ptr += 16;
uuids_start[0] += 16;
}
return ptr;
}
void eir_create(struct hci_dev *hdev, u8 *data)
{
u8 *ptr = data;
size_t name_len;
name_len = strlen(hdev->dev_name);
if (name_len > 0) {
/* EIR Data type */
if (name_len > 48) {
name_len = 48;
ptr[1] = EIR_NAME_SHORT;
} else {
ptr[1] = EIR_NAME_COMPLETE;
}
/* EIR Data length */
ptr[0] = name_len + 1;
memcpy(ptr + 2, hdev->dev_name, name_len);
ptr += (name_len + 2);
}
if (hdev->inq_tx_power != HCI_TX_POWER_INVALID) {
ptr[0] = 2;
ptr[1] = EIR_TX_POWER;
ptr[2] = (u8)hdev->inq_tx_power;
ptr += 3;
}
if (hdev->devid_source > 0) {
ptr[0] = 9;
ptr[1] = EIR_DEVICE_ID;
put_unaligned_le16(hdev->devid_source, ptr + 2);
put_unaligned_le16(hdev->devid_vendor, ptr + 4);
put_unaligned_le16(hdev->devid_product, ptr + 6);
put_unaligned_le16(hdev->devid_version, ptr + 8);
ptr += 10;
}
ptr = create_uuid16_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
ptr = create_uuid32_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
ptr = create_uuid128_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
}
u8 eir_create_adv_data(struct hci_dev *hdev, u8 instance, u8 *ptr)
{
struct adv_info *adv = NULL;
u8 ad_len = 0, flags = 0;
u32 instance_flags;
/* Return 0 when the current instance identifier is invalid. */
if (instance) {
adv = hci_find_adv_instance(hdev, instance);
if (!adv)
return 0;
}
instance_flags = hci_adv_instance_flags(hdev, instance);
/* If instance already has the flags set skip adding it once
* again.
*/
if (adv && eir_get_data(adv->adv_data, adv->adv_data_len, EIR_FLAGS,
NULL))
goto skip_flags;
/* The Add Advertising command allows userspace to set both the general
* and limited discoverable flags.
*/
if (instance_flags & MGMT_ADV_FLAG_DISCOV)
flags |= LE_AD_GENERAL;
if (instance_flags & MGMT_ADV_FLAG_LIMITED_DISCOV)
flags |= LE_AD_LIMITED;
if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
flags |= LE_AD_NO_BREDR;
if (flags || (instance_flags & MGMT_ADV_FLAG_MANAGED_FLAGS)) {
/* If a discovery flag wasn't provided, simply use the global
* settings.
*/
if (!flags)
flags |= mgmt_get_adv_discov_flags(hdev);
/* If flags would still be empty, then there is no need to
* include the "Flags" AD field".
*/
if (flags) {
ptr[0] = 0x02;
ptr[1] = EIR_FLAGS;
ptr[2] = flags;
ad_len += 3;
ptr += 3;
}
}
skip_flags:
if (adv) {
memcpy(ptr, adv->adv_data, adv->adv_data_len);
ad_len += adv->adv_data_len;
ptr += adv->adv_data_len;
}
if (instance_flags & MGMT_ADV_FLAG_TX_POWER) {
s8 adv_tx_power;
if (ext_adv_capable(hdev)) {
if (adv)
adv_tx_power = adv->tx_power;
else
adv_tx_power = hdev->adv_tx_power;
} else {
adv_tx_power = hdev->adv_tx_power;
}
/* Provide Tx Power only if we can provide a valid value for it */
if (adv_tx_power != HCI_TX_POWER_INVALID) {
ptr[0] = 0x02;
ptr[1] = EIR_TX_POWER;
ptr[2] = (u8)adv_tx_power;
ad_len += 3;
ptr += 3;
}
}
return ad_len;
}
static u8 create_default_scan_rsp(struct hci_dev *hdev, u8 *ptr)
{
u8 scan_rsp_len = 0;
if (hdev->appearance)
scan_rsp_len = eir_append_appearance(hdev, ptr, scan_rsp_len);
return eir_append_local_name(hdev, ptr, scan_rsp_len);
}
u8 eir_create_scan_rsp(struct hci_dev *hdev, u8 instance, u8 *ptr)
{
struct adv_info *adv;
u8 scan_rsp_len = 0;
if (!instance)
return create_default_scan_rsp(hdev, ptr);
adv = hci_find_adv_instance(hdev, instance);
if (!adv)
return 0;
if ((adv->flags & MGMT_ADV_FLAG_APPEARANCE) && hdev->appearance)
scan_rsp_len = eir_append_appearance(hdev, ptr, scan_rsp_len);
memcpy(&ptr[scan_rsp_len], adv->scan_rsp_data, adv->scan_rsp_len);
scan_rsp_len += adv->scan_rsp_len;
if (adv->flags & MGMT_ADV_FLAG_LOCAL_NAME)
scan_rsp_len = eir_append_local_name(hdev, ptr, scan_rsp_len);
return scan_rsp_len;
}
/* SPDX-License-Identifier: GPL-2.0 */
/*
* BlueZ - Bluetooth protocol stack for Linux
*
* Copyright (C) 2021 Intel Corporation
*/
void eir_create(struct hci_dev *hdev, u8 *data);
u8 eir_create_adv_data(struct hci_dev *hdev, u8 instance, u8 *ptr);
u8 eir_create_scan_rsp(struct hci_dev *hdev, u8 instance, u8 *ptr);
u8 eir_append_local_name(struct hci_dev *hdev, u8 *eir, u8 ad_len);
u8 eir_append_appearance(struct hci_dev *hdev, u8 *ptr, u8 ad_len);
static inline u16 eir_append_data(u8 *eir, u16 eir_len, u8 type,
u8 *data, u8 data_len)
{
eir[eir_len++] = sizeof(type) + data_len;
eir[eir_len++] = type;
memcpy(&eir[eir_len], data, data_len);
eir_len += data_len;
return eir_len;
}
static inline u16 eir_append_le16(u8 *eir, u16 eir_len, u8 type, u16 data)
{
eir[eir_len++] = sizeof(type) + sizeof(data);
eir[eir_len++] = type;
put_unaligned_le16(data, &eir[eir_len]);
eir_len += sizeof(data);
return eir_len;
}
static inline void *eir_get_data(u8 *eir, size_t eir_len, u8 type,
size_t *data_len)
{
size_t parsed = 0;
if (eir_len < 2)
return NULL;
while (parsed < eir_len - 1) {
u8 field_len = eir[0];
if (field_len == 0)
break;
parsed += field_len + 1;
if (parsed > eir_len)
break;
if (eir[1] != type) {
eir += field_len + 1;
continue;
}
/* Zero length data */
if (field_len == 1)
return NULL;
if (data_len)
*data_len = field_len - 1;
return &eir[2];
}
return NULL;
}
// SPDX-License-Identifier: GPL-2.0
/* Copyright (C) 2021 Intel Corporation */
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>
#include "hci_codec.h"
static int hci_codec_list_add(struct list_head *list,
struct hci_op_read_local_codec_caps *sent,
struct hci_rp_read_local_codec_caps *rp,
void *caps,
__u32 len)
{
struct codec_list *entry;
entry = kzalloc(sizeof(*entry) + len, GFP_KERNEL);
if (!entry)
return -ENOMEM;
entry->id = sent->id;
if (sent->id == 0xFF) {
entry->cid = __le16_to_cpu(sent->cid);
entry->vid = __le16_to_cpu(sent->vid);
}
entry->transport = sent->transport;
entry->len = len;
entry->num_caps = rp->num_caps;
if (rp->num_caps)
memcpy(entry->caps, caps, len);
list_add(&entry->list, list);
return 0;
}
void hci_codec_list_clear(struct list_head *codec_list)
{
struct codec_list *c, *n;
list_for_each_entry_safe(c, n, codec_list, list) {
list_del(&c->list);
kfree(c);
}
}
static void hci_read_codec_capabilities(struct hci_dev *hdev, __u8 transport,
struct hci_op_read_local_codec_caps
*cmd)
{
__u8 i;
for (i = 0; i < TRANSPORT_TYPE_MAX; i++) {
if (transport & BIT(i)) {
struct hci_rp_read_local_codec_caps *rp;
struct hci_codec_caps *caps;
struct sk_buff *skb;
__u8 j;
__u32 len;
cmd->transport = i;
skb = __hci_cmd_sync(hdev, HCI_OP_READ_LOCAL_CODEC_CAPS,
sizeof(*cmd), cmd,
HCI_CMD_TIMEOUT);
if (IS_ERR(skb)) {
bt_dev_err(hdev, "Failed to read codec capabilities (%ld)",
PTR_ERR(skb));
continue;
}
if (skb->len < sizeof(*rp))
goto error;
rp = (void *)skb->data;
if (rp->status)
goto error;
if (!rp->num_caps) {
len = 0;
/* this codec doesn't have capabilities */
goto skip_caps_parse;
}
skb_pull(skb, sizeof(*rp));
for (j = 0, len = 0; j < rp->num_caps; j++) {
caps = (void *)skb->data;
if (skb->len < sizeof(*caps))
goto error;
if (skb->len < caps->len)
goto error;
len += sizeof(caps->len) + caps->len;
skb_pull(skb, sizeof(caps->len) + caps->len);
}
skip_caps_parse:
hci_dev_lock(hdev);
hci_codec_list_add(&hdev->local_codecs, cmd, rp,
(__u8 *)rp + sizeof(*rp), len);
hci_dev_unlock(hdev);
error:
kfree_skb(skb);
}
}
}
void hci_read_supported_codecs(struct hci_dev *hdev)
{
struct sk_buff *skb;
struct hci_rp_read_local_supported_codecs *rp;
struct hci_std_codecs *std_codecs;
struct hci_vnd_codecs *vnd_codecs;
struct hci_op_read_local_codec_caps caps;
__u8 i;
skb = __hci_cmd_sync(hdev, HCI_OP_READ_LOCAL_CODECS, 0, NULL,
HCI_CMD_TIMEOUT);
if (IS_ERR(skb)) {
bt_dev_err(hdev, "Failed to read local supported codecs (%ld)",
PTR_ERR(skb));
return;
}
if (skb->len < sizeof(*rp))
goto error;
rp = (void *)skb->data;
if (rp->status)
goto error;
skb_pull(skb, sizeof(rp->status));
std_codecs = (void *)skb->data;
/* validate codecs length before accessing */
if (skb->len < flex_array_size(std_codecs, codec, std_codecs->num)
+ sizeof(std_codecs->num))
goto error;
/* enumerate codec capabilities of standard codecs */
memset(&caps, 0, sizeof(caps));
for (i = 0; i < std_codecs->num; i++) {
caps.id = std_codecs->codec[i];
caps.direction = 0x00;
hci_read_codec_capabilities(hdev, LOCAL_CODEC_ACL_MASK, &caps);
}
skb_pull(skb, flex_array_size(std_codecs, codec, std_codecs->num)
+ sizeof(std_codecs->num));
vnd_codecs = (void *)skb->data;
/* validate vendor codecs length before accessing */
if (skb->len <
flex_array_size(vnd_codecs, codec, vnd_codecs->num)
+ sizeof(vnd_codecs->num))
goto error;
/* enumerate vendor codec capabilities */
for (i = 0; i < vnd_codecs->num; i++) {
caps.id = 0xFF;
caps.cid = vnd_codecs->codec[i].cid;
caps.vid = vnd_codecs->codec[i].vid;
caps.direction = 0x00;
hci_read_codec_capabilities(hdev, LOCAL_CODEC_ACL_MASK, &caps);
}
error:
kfree_skb(skb);
}
void hci_read_supported_codecs_v2(struct hci_dev *hdev)
{
struct sk_buff *skb;
struct hci_rp_read_local_supported_codecs_v2 *rp;
struct hci_std_codecs_v2 *std_codecs;
struct hci_vnd_codecs_v2 *vnd_codecs;
struct hci_op_read_local_codec_caps caps;
__u8 i;
skb = __hci_cmd_sync(hdev, HCI_OP_READ_LOCAL_CODECS_V2, 0, NULL,
HCI_CMD_TIMEOUT);
if (IS_ERR(skb)) {
bt_dev_err(hdev, "Failed to read local supported codecs (%ld)",
PTR_ERR(skb));
return;
}
if (skb->len < sizeof(*rp))
goto error;
rp = (void *)skb->data;
if (rp->status)
goto error;
skb_pull(skb, sizeof(rp->status));
std_codecs = (void *)skb->data;
/* check for payload data length before accessing */
if (skb->len < flex_array_size(std_codecs, codec, std_codecs->num)
+ sizeof(std_codecs->num))
goto error;
memset(&caps, 0, sizeof(caps));
for (i = 0; i < std_codecs->num; i++) {
caps.id = std_codecs->codec[i].id;
hci_read_codec_capabilities(hdev, std_codecs->codec[i].transport,
&caps);
}
skb_pull(skb, flex_array_size(std_codecs, codec, std_codecs->num)
+ sizeof(std_codecs->num));
vnd_codecs = (void *)skb->data;
/* check for payload data length before accessing */
if (skb->len <
flex_array_size(vnd_codecs, codec, vnd_codecs->num)
+ sizeof(vnd_codecs->num))
goto error;
for (i = 0; i < vnd_codecs->num; i++) {
caps.id = 0xFF;
caps.cid = vnd_codecs->codec[i].cid;
caps.vid = vnd_codecs->codec[i].vid;
hci_read_codec_capabilities(hdev, vnd_codecs->codec[i].transport,
&caps);
}
error:
kfree_skb(skb);
}
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright (C) 2014 Intel Corporation */
void hci_read_supported_codecs(struct hci_dev *hdev);
void hci_read_supported_codecs_v2(struct hci_dev *hdev);
void hci_codec_list_clear(struct list_head *codec_list);
......@@ -307,13 +307,133 @@ static bool find_next_esco_param(struct hci_conn *conn,
return conn->attempt <= size;
}
bool hci_setup_sync(struct hci_conn *conn, __u16 handle)
static bool hci_enhanced_setup_sync_conn(struct hci_conn *conn, __u16 handle)
{
struct hci_dev *hdev = conn->hdev;
struct hci_cp_enhanced_setup_sync_conn cp;
const struct sco_param *param;
bt_dev_dbg(hdev, "hcon %p", conn);
/* for offload use case, codec needs to configured before opening SCO */
if (conn->codec.data_path)
hci_req_configure_datapath(hdev, &conn->codec);
conn->state = BT_CONNECT;
conn->out = true;
conn->attempt++;
memset(&cp, 0x00, sizeof(cp));
cp.handle = cpu_to_le16(handle);
cp.tx_bandwidth = cpu_to_le32(0x00001f40);
cp.rx_bandwidth = cpu_to_le32(0x00001f40);
switch (conn->codec.id) {
case BT_CODEC_MSBC:
if (!find_next_esco_param(conn, esco_param_msbc,
ARRAY_SIZE(esco_param_msbc)))
return false;
param = &esco_param_msbc[conn->attempt - 1];
cp.tx_coding_format.id = 0x05;
cp.rx_coding_format.id = 0x05;
cp.tx_codec_frame_size = __cpu_to_le16(60);
cp.rx_codec_frame_size = __cpu_to_le16(60);
cp.in_bandwidth = __cpu_to_le32(32000);
cp.out_bandwidth = __cpu_to_le32(32000);
cp.in_coding_format.id = 0x04;
cp.out_coding_format.id = 0x04;
cp.in_coded_data_size = __cpu_to_le16(16);
cp.out_coded_data_size = __cpu_to_le16(16);
cp.in_pcm_data_format = 2;
cp.out_pcm_data_format = 2;
cp.in_pcm_sample_payload_msb_pos = 0;
cp.out_pcm_sample_payload_msb_pos = 0;
cp.in_data_path = conn->codec.data_path;
cp.out_data_path = conn->codec.data_path;
cp.in_transport_unit_size = 1;
cp.out_transport_unit_size = 1;
break;
case BT_CODEC_TRANSPARENT:
if (!find_next_esco_param(conn, esco_param_msbc,
ARRAY_SIZE(esco_param_msbc)))
return false;
param = &esco_param_msbc[conn->attempt - 1];
cp.tx_coding_format.id = 0x03;
cp.rx_coding_format.id = 0x03;
cp.tx_codec_frame_size = __cpu_to_le16(60);
cp.rx_codec_frame_size = __cpu_to_le16(60);
cp.in_bandwidth = __cpu_to_le32(0x1f40);
cp.out_bandwidth = __cpu_to_le32(0x1f40);
cp.in_coding_format.id = 0x03;
cp.out_coding_format.id = 0x03;
cp.in_coded_data_size = __cpu_to_le16(16);
cp.out_coded_data_size = __cpu_to_le16(16);
cp.in_pcm_data_format = 2;
cp.out_pcm_data_format = 2;
cp.in_pcm_sample_payload_msb_pos = 0;
cp.out_pcm_sample_payload_msb_pos = 0;
cp.in_data_path = conn->codec.data_path;
cp.out_data_path = conn->codec.data_path;
cp.in_transport_unit_size = 1;
cp.out_transport_unit_size = 1;
break;
case BT_CODEC_CVSD:
if (lmp_esco_capable(conn->link)) {
if (!find_next_esco_param(conn, esco_param_cvsd,
ARRAY_SIZE(esco_param_cvsd)))
return false;
param = &esco_param_cvsd[conn->attempt - 1];
} else {
if (conn->attempt > ARRAY_SIZE(sco_param_cvsd))
return false;
param = &sco_param_cvsd[conn->attempt - 1];
}
cp.tx_coding_format.id = 2;
cp.rx_coding_format.id = 2;
cp.tx_codec_frame_size = __cpu_to_le16(60);
cp.rx_codec_frame_size = __cpu_to_le16(60);
cp.in_bandwidth = __cpu_to_le32(16000);
cp.out_bandwidth = __cpu_to_le32(16000);
cp.in_coding_format.id = 4;
cp.out_coding_format.id = 4;
cp.in_coded_data_size = __cpu_to_le16(16);
cp.out_coded_data_size = __cpu_to_le16(16);
cp.in_pcm_data_format = 2;
cp.out_pcm_data_format = 2;
cp.in_pcm_sample_payload_msb_pos = 0;
cp.out_pcm_sample_payload_msb_pos = 0;
cp.in_data_path = conn->codec.data_path;
cp.out_data_path = conn->codec.data_path;
cp.in_transport_unit_size = 16;
cp.out_transport_unit_size = 16;
break;
default:
return false;
}
cp.retrans_effort = param->retrans_effort;
cp.pkt_type = __cpu_to_le16(param->pkt_type);
cp.max_latency = __cpu_to_le16(param->max_latency);
if (hci_send_cmd(hdev, HCI_OP_ENHANCED_SETUP_SYNC_CONN, sizeof(cp), &cp) < 0)
return false;
return true;
}
static bool hci_setup_sync_conn(struct hci_conn *conn, __u16 handle)
{
struct hci_dev *hdev = conn->hdev;
struct hci_cp_setup_sync_conn cp;
const struct sco_param *param;
BT_DBG("hcon %p", conn);
bt_dev_dbg(hdev, "hcon %p", conn);
conn->state = BT_CONNECT;
conn->out = true;
......@@ -359,6 +479,14 @@ bool hci_setup_sync(struct hci_conn *conn, __u16 handle)
return true;
}
bool hci_setup_sync(struct hci_conn *conn, __u16 handle)
{
if (enhanced_sco_capable(conn->hdev))
return hci_enhanced_setup_sync_conn(conn, handle);
return hci_setup_sync_conn(conn, handle);
}
u8 hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max, u16 latency,
u16 to_multiplier)
{
......@@ -1040,8 +1168,8 @@ static void hci_req_directed_advertising(struct hci_request *req,
}
struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst,
u8 dst_type, u8 sec_level, u16 conn_timeout,
u8 role, bdaddr_t *direct_rpa)
u8 dst_type, bool dst_resolved, u8 sec_level,
u16 conn_timeout, u8 role, bdaddr_t *direct_rpa)
{
struct hci_conn_params *params;
struct hci_conn *conn;
......@@ -1078,19 +1206,24 @@ struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst,
return ERR_PTR(-EBUSY);
}
/* When given an identity address with existing identity
* resolving key, the connection needs to be established
* to a resolvable random address.
*
* Storing the resolvable random address is required here
* to handle connection failures. The address will later
* be resolved back into the original identity address
* from the connect request.
/* Check if the destination address has been resolved by the controller
* since if it did then the identity address shall be used.
*/
irk = hci_find_irk_by_addr(hdev, dst, dst_type);
if (irk && bacmp(&irk->rpa, BDADDR_ANY)) {
dst = &irk->rpa;
dst_type = ADDR_LE_DEV_RANDOM;
if (!dst_resolved) {
/* When given an identity address with existing identity
* resolving key, the connection needs to be established
* to a resolvable random address.
*
* Storing the resolvable random address is required here
* to handle connection failures. The address will later
* be resolved back into the original identity address
* from the connect request.
*/
irk = hci_find_irk_by_addr(hdev, dst, dst_type);
if (irk && bacmp(&irk->rpa, BDADDR_ANY)) {
dst = &irk->rpa;
dst_type = ADDR_LE_DEV_RANDOM;
}
}
if (conn) {
......@@ -1319,7 +1452,7 @@ struct hci_conn *hci_connect_acl(struct hci_dev *hdev, bdaddr_t *dst,
}
struct hci_conn *hci_connect_sco(struct hci_dev *hdev, int type, bdaddr_t *dst,
__u16 setting)
__u16 setting, struct bt_codec *codec)
{
struct hci_conn *acl;
struct hci_conn *sco;
......@@ -1344,6 +1477,7 @@ struct hci_conn *hci_connect_sco(struct hci_dev *hdev, int type, bdaddr_t *dst,
hci_conn_hold(sco);
sco->setting = setting;
sco->codec = *codec;
if (acl->state == BT_CONNECTED &&
(sco->state == BT_OPEN || sco->state == BT_CLOSED)) {
......
This diff is collapsed.
......@@ -27,6 +27,7 @@
#include <net/bluetooth/hci_core.h>
#include "smp.h"
#include "hci_request.h"
#include "hci_debugfs.h"
#define DEFINE_QUIRK_ATTRIBUTE(__name, __quirk) \
......@@ -1250,3 +1251,125 @@ void hci_debugfs_create_conn(struct hci_conn *conn)
snprintf(name, sizeof(name), "%u", conn->handle);
conn->debugfs = debugfs_create_dir(name, hdev->debugfs);
}
static ssize_t dut_mode_read(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
struct hci_dev *hdev = file->private_data;
char buf[3];
buf[0] = hci_dev_test_flag(hdev, HCI_DUT_MODE) ? 'Y' : 'N';
buf[1] = '\n';
buf[2] = '\0';
return simple_read_from_buffer(user_buf, count, ppos, buf, 2);
}
static ssize_t dut_mode_write(struct file *file, const char __user *user_buf,
size_t count, loff_t *ppos)
{
struct hci_dev *hdev = file->private_data;
struct sk_buff *skb;
bool enable;
int err;
if (!test_bit(HCI_UP, &hdev->flags))
return -ENETDOWN;
err = kstrtobool_from_user(user_buf, count, &enable);
if (err)
return err;
if (enable == hci_dev_test_flag(hdev, HCI_DUT_MODE))
return -EALREADY;
hci_req_sync_lock(hdev);
if (enable)
skb = __hci_cmd_sync(hdev, HCI_OP_ENABLE_DUT_MODE, 0, NULL,
HCI_CMD_TIMEOUT);
else
skb = __hci_cmd_sync(hdev, HCI_OP_RESET, 0, NULL,
HCI_CMD_TIMEOUT);
hci_req_sync_unlock(hdev);
if (IS_ERR(skb))
return PTR_ERR(skb);
kfree_skb(skb);
hci_dev_change_flag(hdev, HCI_DUT_MODE);
return count;
}
static const struct file_operations dut_mode_fops = {
.open = simple_open,
.read = dut_mode_read,
.write = dut_mode_write,
.llseek = default_llseek,
};
static ssize_t vendor_diag_read(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
struct hci_dev *hdev = file->private_data;
char buf[3];
buf[0] = hci_dev_test_flag(hdev, HCI_VENDOR_DIAG) ? 'Y' : 'N';
buf[1] = '\n';
buf[2] = '\0';
return simple_read_from_buffer(user_buf, count, ppos, buf, 2);
}
static ssize_t vendor_diag_write(struct file *file, const char __user *user_buf,
size_t count, loff_t *ppos)
{
struct hci_dev *hdev = file->private_data;
bool enable;
int err;
err = kstrtobool_from_user(user_buf, count, &enable);
if (err)
return err;
/* When the diagnostic flags are not persistent and the transport
* is not active or in user channel operation, then there is no need
* for the vendor callback. Instead just store the desired value and
* the setting will be programmed when the controller gets powered on.
*/
if (test_bit(HCI_QUIRK_NON_PERSISTENT_DIAG, &hdev->quirks) &&
(!test_bit(HCI_RUNNING, &hdev->flags) ||
hci_dev_test_flag(hdev, HCI_USER_CHANNEL)))
goto done;
hci_req_sync_lock(hdev);
err = hdev->set_diag(hdev, enable);
hci_req_sync_unlock(hdev);
if (err < 0)
return err;
done:
if (enable)
hci_dev_set_flag(hdev, HCI_VENDOR_DIAG);
else
hci_dev_clear_flag(hdev, HCI_VENDOR_DIAG);
return count;
}
static const struct file_operations vendor_diag_fops = {
.open = simple_open,
.read = vendor_diag_read,
.write = vendor_diag_write,
.llseek = default_llseek,
};
void hci_debugfs_create_basic(struct hci_dev *hdev)
{
debugfs_create_file("dut_mode", 0644, hdev->debugfs, hdev,
&dut_mode_fops);
if (hdev->set_diag)
debugfs_create_file("vendor_diag", 0644, hdev->debugfs, hdev,
&vendor_diag_fops);
}
......@@ -26,6 +26,7 @@ void hci_debugfs_create_common(struct hci_dev *hdev);
void hci_debugfs_create_bredr(struct hci_dev *hdev);
void hci_debugfs_create_le(struct hci_dev *hdev);
void hci_debugfs_create_conn(struct hci_conn *conn);
void hci_debugfs_create_basic(struct hci_dev *hdev);
#else
......@@ -45,4 +46,8 @@ static inline void hci_debugfs_create_conn(struct hci_conn *conn)
{
}
static inline void hci_debugfs_create_basic(struct hci_dev *hdev)
{
}
#endif
......@@ -36,6 +36,7 @@
#include "amp.h"
#include "smp.h"
#include "msft.h"
#include "eir.h"
#define ZERO_KEY "\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00"
......@@ -2278,6 +2279,41 @@ static void hci_cs_setup_sync_conn(struct hci_dev *hdev, __u8 status)
hci_dev_unlock(hdev);
}
static void hci_cs_enhanced_setup_sync_conn(struct hci_dev *hdev, __u8 status)
{
struct hci_cp_enhanced_setup_sync_conn *cp;
struct hci_conn *acl, *sco;
__u16 handle;
bt_dev_dbg(hdev, "status 0x%2.2x", status);
if (!status)
return;
cp = hci_sent_cmd_data(hdev, HCI_OP_ENHANCED_SETUP_SYNC_CONN);
if (!cp)
return;
handle = __le16_to_cpu(cp->handle);
bt_dev_dbg(hdev, "handle 0x%4.4x", handle);
hci_dev_lock(hdev);
acl = hci_conn_hash_lookup_handle(hdev, handle);
if (acl) {
sco = acl->link;
if (sco) {
sco->state = BT_CLOSED;
hci_connect_cfm(sco, status);
hci_conn_del(sco);
}
}
hci_dev_unlock(hdev);
}
static void hci_cs_sniff_mode(struct hci_dev *hdev, __u8 status)
{
struct hci_cp_sniff_mode *cp;
......@@ -2351,7 +2387,7 @@ static void hci_cs_disconnect(struct hci_dev *hdev, u8 status)
mgmt_disconnect_failed(hdev, &conn->dst, conn->type,
conn->dst_type, status);
if (conn->type == LE_LINK) {
if (conn->type == LE_LINK && conn->role == HCI_ROLE_SLAVE) {
hdev->cur_adv_instance = conn->adv_instance;
hci_req_reenable_advertising(hdev);
}
......@@ -2367,6 +2403,28 @@ static void hci_cs_disconnect(struct hci_dev *hdev, u8 status)
hci_dev_unlock(hdev);
}
static u8 ev_bdaddr_type(struct hci_dev *hdev, u8 type, bool *resolved)
{
/* When using controller based address resolution, then the new
* address types 0x02 and 0x03 are used. These types need to be
* converted back into either public address or random address type
*/
switch (type) {
case ADDR_LE_DEV_PUBLIC_RESOLVED:
if (resolved)
*resolved = true;
return ADDR_LE_DEV_PUBLIC;
case ADDR_LE_DEV_RANDOM_RESOLVED:
if (resolved)
*resolved = true;
return ADDR_LE_DEV_RANDOM;
}
if (resolved)
*resolved = false;
return type;
}
static void cs_le_create_conn(struct hci_dev *hdev, bdaddr_t *peer_addr,
u8 peer_addr_type, u8 own_address_type,
u8 filter_policy)
......@@ -2378,21 +2436,7 @@ static void cs_le_create_conn(struct hci_dev *hdev, bdaddr_t *peer_addr,
if (!conn)
return;
/* When using controller based address resolution, then the new
* address types 0x02 and 0x03 are used. These types need to be
* converted back into either public address or random address type
*/
if (use_ll_privacy(hdev) &&
hci_dev_test_flag(hdev, HCI_LL_RPA_RESOLUTION)) {
switch (own_address_type) {
case ADDR_LE_DEV_PUBLIC_RESOLVED:
own_address_type = ADDR_LE_DEV_PUBLIC;
break;
case ADDR_LE_DEV_RANDOM_RESOLVED:
own_address_type = ADDR_LE_DEV_RANDOM;
break;
}
}
own_address_type = ev_bdaddr_type(hdev, own_address_type, NULL);
/* Store the initiator and responder address information which
* is needed for SMP. These values will not change during the
......@@ -2961,7 +3005,7 @@ static void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
* or until a connection is created or until the Advertising
* is timed out due to Directed Advertising."
*/
if (conn->type == LE_LINK) {
if (conn->type == LE_LINK && conn->role == HCI_ROLE_SLAVE) {
hdev->cur_adv_instance = conn->adv_instance;
hci_req_reenable_advertising(hdev);
}
......@@ -3756,6 +3800,10 @@ static void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb,
hci_cs_setup_sync_conn(hdev, ev->status);
break;
case HCI_OP_ENHANCED_SETUP_SYNC_CONN:
hci_cs_enhanced_setup_sync_conn(hdev, ev->status);
break;
case HCI_OP_SNIFF_MODE:
hci_cs_sniff_mode(hdev, ev->status);
break;
......@@ -4397,6 +4445,7 @@ static void hci_sync_conn_complete_evt(struct hci_dev *hdev,
{
struct hci_ev_sync_conn_complete *ev = (void *) skb->data;
struct hci_conn *conn;
unsigned int notify_evt;
BT_DBG("%s status 0x%2.2x", hdev->name, ev->status);
......@@ -4471,15 +4520,21 @@ static void hci_sync_conn_complete_evt(struct hci_dev *hdev,
switch (ev->air_mode) {
case 0x02:
if (hdev->notify)
hdev->notify(hdev, HCI_NOTIFY_ENABLE_SCO_CVSD);
notify_evt = HCI_NOTIFY_ENABLE_SCO_CVSD;
break;
case 0x03:
if (hdev->notify)
hdev->notify(hdev, HCI_NOTIFY_ENABLE_SCO_TRANSP);
notify_evt = HCI_NOTIFY_ENABLE_SCO_TRANSP;
break;
}
/* Notify only in case of SCO over HCI transport data path which
* is zero and non-zero value shall be non-HCI transport data path
*/
if (conn->codec.data_path == 0) {
if (hdev->notify)
hdev->notify(hdev, notify_evt);
}
hci_connect_cfm(conn, ev->status);
if (ev->status)
hci_conn_del(conn);
......@@ -5282,22 +5337,7 @@ static void le_conn_complete_evt(struct hci_dev *hdev, u8 status,
conn->dst_type = irk->addr_type;
}
/* When using controller based address resolution, then the new
* address types 0x02 and 0x03 are used. These types need to be
* converted back into either public address or random address type
*/
if (use_ll_privacy(hdev) &&
hci_dev_test_flag(hdev, HCI_ENABLE_LL_PRIVACY) &&
hci_dev_test_flag(hdev, HCI_LL_RPA_RESOLUTION)) {
switch (conn->dst_type) {
case ADDR_LE_DEV_PUBLIC_RESOLVED:
conn->dst_type = ADDR_LE_DEV_PUBLIC;
break;
case ADDR_LE_DEV_RANDOM_RESOLVED:
conn->dst_type = ADDR_LE_DEV_RANDOM;
break;
}
}
conn->dst_type = ev_bdaddr_type(hdev, conn->dst_type, NULL);
if (status) {
hci_le_conn_failed(conn, status);
......@@ -5479,8 +5519,8 @@ static void hci_le_conn_update_complete_evt(struct hci_dev *hdev,
/* This function requires the caller holds hdev->lock */
static struct hci_conn *check_pending_le_conn(struct hci_dev *hdev,
bdaddr_t *addr,
u8 addr_type, u8 adv_type,
bdaddr_t *direct_rpa)
u8 addr_type, bool addr_resolved,
u8 adv_type, bdaddr_t *direct_rpa)
{
struct hci_conn *conn;
struct hci_conn_params *params;
......@@ -5532,9 +5572,9 @@ static struct hci_conn *check_pending_le_conn(struct hci_dev *hdev,
}
}
conn = hci_connect_le(hdev, addr, addr_type, BT_SECURITY_LOW,
hdev->def_le_autoconnect_timeout, HCI_ROLE_MASTER,
direct_rpa);
conn = hci_connect_le(hdev, addr, addr_type, addr_resolved,
BT_SECURITY_LOW, hdev->def_le_autoconnect_timeout,
HCI_ROLE_MASTER, direct_rpa);
if (!IS_ERR(conn)) {
/* If HCI_AUTO_CONN_EXPLICIT is set, conn is already owned
* by higher layer that tried to connect, if no then
......@@ -5575,7 +5615,7 @@ static void process_adv_report(struct hci_dev *hdev, u8 type, bdaddr_t *bdaddr,
struct discovery_state *d = &hdev->discovery;
struct smp_irk *irk;
struct hci_conn *conn;
bool match;
bool match, bdaddr_resolved;
u32 flags;
u8 *ptr;
......@@ -5619,6 +5659,9 @@ static void process_adv_report(struct hci_dev *hdev, u8 type, bdaddr_t *bdaddr,
* controller address.
*/
if (direct_addr) {
direct_addr_type = ev_bdaddr_type(hdev, direct_addr_type,
&bdaddr_resolved);
/* Only resolvable random addresses are valid for these
* kind of reports and others can be ignored.
*/
......@@ -5646,13 +5689,15 @@ static void process_adv_report(struct hci_dev *hdev, u8 type, bdaddr_t *bdaddr,
bdaddr_type = irk->addr_type;
}
bdaddr_type = ev_bdaddr_type(hdev, bdaddr_type, &bdaddr_resolved);
/* Check if we have been requested to connect to this device.
*
* direct_addr is set only for directed advertising reports (it is NULL
* for advertising reports) and is already verified to be RPA above.
*/
conn = check_pending_le_conn(hdev, bdaddr, bdaddr_type, type,
direct_addr);
conn = check_pending_le_conn(hdev, bdaddr, bdaddr_type, bdaddr_resolved,
type, direct_addr);
if (!ext_adv && conn && type == LE_ADV_IND && len <= HCI_MAX_AD_LENGTH) {
/* Store report for later inclusion by
* mgmt_device_connected
......
This diff is collapsed.
......@@ -101,6 +101,8 @@ void __hci_req_update_class(struct hci_request *req);
/* Returns true if HCI commands were queued */
bool hci_req_stop_discovery(struct hci_request *req);
int hci_req_configure_datapath(struct hci_dev *hdev, struct bt_codec *codec);
static inline void hci_req_update_scan(struct hci_dev *hdev)
{
queue_work(hdev->req_workqueue, &hdev->scan_update);
......@@ -122,26 +124,3 @@ static inline void hci_update_background_scan(struct hci_dev *hdev)
void hci_request_setup(struct hci_dev *hdev);
void hci_request_cancel_all(struct hci_dev *hdev);
u8 append_local_name(struct hci_dev *hdev, u8 *ptr, u8 ad_len);
static inline u16 eir_append_data(u8 *eir, u16 eir_len, u8 type,
u8 *data, u8 data_len)
{
eir[eir_len++] = sizeof(type) + data_len;
eir[eir_len++] = type;
memcpy(&eir[eir_len], data, data_len);
eir_len += data_len;
return eir_len;
}
static inline u16 eir_append_le16(u8 *eir, u16 eir_len, u8 type, u16 data)
{
eir[eir_len++] = sizeof(type) + sizeof(data);
eir[eir_len++] = type;
put_unaligned_le16(data, &eir[eir_len]);
eir_len += sizeof(data);
return eir_len;
}
......@@ -57,6 +57,7 @@ struct hci_pinfo {
unsigned long flags;
__u32 cookie;
char comm[TASK_COMM_LEN];
__u16 mtu;
};
static struct hci_dev *hci_hdev_from_sock(struct sock *sk)
......@@ -1374,6 +1375,10 @@ static int hci_sock_bind(struct socket *sock, struct sockaddr *addr,
break;
}
/* Default MTU to HCI_MAX_FRAME_SIZE if not set */
if (!hci_pi(sk)->mtu)
hci_pi(sk)->mtu = HCI_MAX_FRAME_SIZE;
sk->sk_state = BT_BOUND;
done:
......@@ -1506,9 +1511,8 @@ static int hci_sock_recvmsg(struct socket *sock, struct msghdr *msg,
}
static int hci_mgmt_cmd(struct hci_mgmt_chan *chan, struct sock *sk,
struct msghdr *msg, size_t msglen)
struct sk_buff *skb)
{
void *buf;
u8 *cp;
struct mgmt_hdr *hdr;
u16 opcode, index, len;
......@@ -1517,40 +1521,31 @@ static int hci_mgmt_cmd(struct hci_mgmt_chan *chan, struct sock *sk,
bool var_len, no_hdev;
int err;
BT_DBG("got %zu bytes", msglen);
BT_DBG("got %d bytes", skb->len);
if (msglen < sizeof(*hdr))
if (skb->len < sizeof(*hdr))
return -EINVAL;
buf = kmalloc(msglen, GFP_KERNEL);
if (!buf)
return -ENOMEM;
if (memcpy_from_msg(buf, msg, msglen)) {
err = -EFAULT;
goto done;
}
hdr = buf;
hdr = (void *)skb->data;
opcode = __le16_to_cpu(hdr->opcode);
index = __le16_to_cpu(hdr->index);
len = __le16_to_cpu(hdr->len);
if (len != msglen - sizeof(*hdr)) {
if (len != skb->len - sizeof(*hdr)) {
err = -EINVAL;
goto done;
}
if (chan->channel == HCI_CHANNEL_CONTROL) {
struct sk_buff *skb;
struct sk_buff *cmd;
/* Send event to monitor */
skb = create_monitor_ctrl_command(sk, index, opcode, len,
buf + sizeof(*hdr));
if (skb) {
hci_send_to_channel(HCI_CHANNEL_MONITOR, skb,
cmd = create_monitor_ctrl_command(sk, index, opcode, len,
skb->data + sizeof(*hdr));
if (cmd) {
hci_send_to_channel(HCI_CHANNEL_MONITOR, cmd,
HCI_SOCK_TRUSTED, NULL);
kfree_skb(skb);
kfree_skb(cmd);
}
}
......@@ -1615,26 +1610,25 @@ static int hci_mgmt_cmd(struct hci_mgmt_chan *chan, struct sock *sk,
if (hdev && chan->hdev_init)
chan->hdev_init(sk, hdev);
cp = buf + sizeof(*hdr);
cp = skb->data + sizeof(*hdr);
err = handler->func(sk, hdev, cp, len);
if (err < 0)
goto done;
err = msglen;
err = skb->len;
done:
if (hdev)
hci_dev_put(hdev);
kfree(buf);
return err;
}
static int hci_logging_frame(struct sock *sk, struct msghdr *msg, int len)
static int hci_logging_frame(struct sock *sk, struct sk_buff *skb,
unsigned int flags)
{
struct hci_mon_hdr *hdr;
struct sk_buff *skb;
struct hci_dev *hdev;
u16 index;
int err;
......@@ -1643,24 +1637,13 @@ static int hci_logging_frame(struct sock *sk, struct msghdr *msg, int len)
* the priority byte, the ident length byte and at least one string
* terminator NUL byte. Anything shorter are invalid packets.
*/
if (len < sizeof(*hdr) + 3)
if (skb->len < sizeof(*hdr) + 3)
return -EINVAL;
skb = bt_skb_send_alloc(sk, len, msg->msg_flags & MSG_DONTWAIT, &err);
if (!skb)
return err;
if (memcpy_from_msg(skb_put(skb, len), msg, len)) {
err = -EFAULT;
goto drop;
}
hdr = (void *)skb->data;
if (__le16_to_cpu(hdr->len) != len - sizeof(*hdr)) {
err = -EINVAL;
goto drop;
}
if (__le16_to_cpu(hdr->len) != skb->len - sizeof(*hdr))
return -EINVAL;
if (__le16_to_cpu(hdr->opcode) == 0x0000) {
__u8 priority = skb->data[sizeof(*hdr)];
......@@ -1679,25 +1662,20 @@ static int hci_logging_frame(struct sock *sk, struct msghdr *msg, int len)
* The message follows the ident string (if present) and
* must be NUL terminated. Otherwise it is not a valid packet.
*/
if (priority > 7 || skb->data[len - 1] != 0x00 ||
ident_len > len - sizeof(*hdr) - 3 ||
skb->data[sizeof(*hdr) + ident_len + 1] != 0x00) {
err = -EINVAL;
goto drop;
}
if (priority > 7 || skb->data[skb->len - 1] != 0x00 ||
ident_len > skb->len - sizeof(*hdr) - 3 ||
skb->data[sizeof(*hdr) + ident_len + 1] != 0x00)
return -EINVAL;
} else {
err = -EINVAL;
goto drop;
return -EINVAL;
}
index = __le16_to_cpu(hdr->index);
if (index != MGMT_INDEX_NONE) {
hdev = hci_dev_get(index);
if (!hdev) {
err = -ENODEV;
goto drop;
}
if (!hdev)
return -ENODEV;
} else {
hdev = NULL;
}
......@@ -1705,13 +1683,11 @@ static int hci_logging_frame(struct sock *sk, struct msghdr *msg, int len)
hdr->opcode = cpu_to_le16(HCI_MON_USER_LOGGING);
hci_send_to_channel(HCI_CHANNEL_MONITOR, skb, HCI_SOCK_TRUSTED, NULL);
err = len;
err = skb->len;
if (hdev)
hci_dev_put(hdev);
drop:
kfree_skb(skb);
return err;
}
......@@ -1723,19 +1699,23 @@ static int hci_sock_sendmsg(struct socket *sock, struct msghdr *msg,
struct hci_dev *hdev;
struct sk_buff *skb;
int err;
const unsigned int flags = msg->msg_flags;
BT_DBG("sock %p sk %p", sock, sk);
if (msg->msg_flags & MSG_OOB)
if (flags & MSG_OOB)
return -EOPNOTSUPP;
if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_NOSIGNAL|MSG_ERRQUEUE|
MSG_CMSG_COMPAT))
if (flags & ~(MSG_DONTWAIT | MSG_NOSIGNAL | MSG_ERRQUEUE | MSG_CMSG_COMPAT))
return -EINVAL;
if (len < 4 || len > HCI_MAX_FRAME_SIZE)
if (len < 4 || len > hci_pi(sk)->mtu)
return -EINVAL;
skb = bt_skb_sendmsg(sk, msg, len, len, 0, 0);
if (IS_ERR(skb))
return PTR_ERR(skb);
lock_sock(sk);
switch (hci_pi(sk)->channel) {
......@@ -1744,39 +1724,30 @@ static int hci_sock_sendmsg(struct socket *sock, struct msghdr *msg,
break;
case HCI_CHANNEL_MONITOR:
err = -EOPNOTSUPP;
goto done;
goto drop;
case HCI_CHANNEL_LOGGING:
err = hci_logging_frame(sk, msg, len);
goto done;
err = hci_logging_frame(sk, skb, flags);
goto drop;
default:
mutex_lock(&mgmt_chan_list_lock);
chan = __hci_mgmt_chan_find(hci_pi(sk)->channel);
if (chan)
err = hci_mgmt_cmd(chan, sk, msg, len);
err = hci_mgmt_cmd(chan, sk, skb);
else
err = -EINVAL;
mutex_unlock(&mgmt_chan_list_lock);
goto done;
goto drop;
}
hdev = hci_hdev_from_sock(sk);
if (IS_ERR(hdev)) {
err = PTR_ERR(hdev);
goto done;
goto drop;
}
if (!test_bit(HCI_UP, &hdev->flags)) {
err = -ENETDOWN;
goto done;
}
skb = bt_skb_send_alloc(sk, len, msg->msg_flags & MSG_DONTWAIT, &err);
if (!skb)
goto done;
if (memcpy_from_msg(skb_put(skb, len), msg, len)) {
err = -EFAULT;
goto drop;
}
......@@ -1857,8 +1828,8 @@ static int hci_sock_sendmsg(struct socket *sock, struct msghdr *msg,
goto done;
}
static int hci_sock_setsockopt(struct socket *sock, int level, int optname,
sockptr_t optval, unsigned int len)
static int hci_sock_setsockopt_old(struct socket *sock, int level, int optname,
sockptr_t optval, unsigned int len)
{
struct hci_ufilter uf = { .opcode = 0 };
struct sock *sk = sock->sk;
......@@ -1866,9 +1837,6 @@ static int hci_sock_setsockopt(struct socket *sock, int level, int optname,
BT_DBG("sk %p, opt %d", sk, optname);
if (level != SOL_HCI)
return -ENOPROTOOPT;
lock_sock(sk);
if (hci_pi(sk)->channel != HCI_CHANNEL_RAW) {
......@@ -1943,18 +1911,63 @@ static int hci_sock_setsockopt(struct socket *sock, int level, int optname,
return err;
}
static int hci_sock_getsockopt(struct socket *sock, int level, int optname,
char __user *optval, int __user *optlen)
static int hci_sock_setsockopt(struct socket *sock, int level, int optname,
sockptr_t optval, unsigned int len)
{
struct hci_ufilter uf;
struct sock *sk = sock->sk;
int len, opt, err = 0;
int err = 0, opt = 0;
BT_DBG("sk %p, opt %d", sk, optname);
if (level != SOL_HCI)
if (level == SOL_HCI)
return hci_sock_setsockopt_old(sock, level, optname, optval,
len);
if (level != SOL_BLUETOOTH)
return -ENOPROTOOPT;
lock_sock(sk);
switch (optname) {
case BT_SNDMTU:
case BT_RCVMTU:
switch (hci_pi(sk)->channel) {
/* Don't allow changing MTU for channels that are meant for HCI
* traffic only.
*/
case HCI_CHANNEL_RAW:
case HCI_CHANNEL_USER:
err = -ENOPROTOOPT;
goto done;
}
if (copy_from_sockptr(&opt, optval, sizeof(u16))) {
err = -EFAULT;
break;
}
hci_pi(sk)->mtu = opt;
break;
default:
err = -ENOPROTOOPT;
break;
}
done:
release_sock(sk);
return err;
}
static int hci_sock_getsockopt_old(struct socket *sock, int level, int optname,
char __user *optval, int __user *optlen)
{
struct hci_ufilter uf;
struct sock *sk = sock->sk;
int len, opt, err = 0;
BT_DBG("sk %p, opt %d", sk, optname);
if (get_user(len, optlen))
return -EFAULT;
......@@ -2012,6 +2025,39 @@ static int hci_sock_getsockopt(struct socket *sock, int level, int optname,
return err;
}
static int hci_sock_getsockopt(struct socket *sock, int level, int optname,
char __user *optval, int __user *optlen)
{
struct sock *sk = sock->sk;
int err = 0;
BT_DBG("sk %p, opt %d", sk, optname);
if (level == SOL_HCI)
return hci_sock_getsockopt_old(sock, level, optname, optval,
optlen);
if (level != SOL_BLUETOOTH)
return -ENOPROTOOPT;
lock_sock(sk);
switch (optname) {
case BT_SNDMTU:
case BT_RCVMTU:
if (put_user(hci_pi(sk)->mtu, (u16 __user *)optval))
err = -EFAULT;
break;
default:
err = -ENOPROTOOPT;
break;
}
release_sock(sk);
return err;
}
static const struct proto_ops hci_sock_ops = {
.family = PF_BLUETOOTH,
.owner = THIS_MODULE,
......
......@@ -7902,7 +7902,7 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid,
dst_type = ADDR_LE_DEV_RANDOM;
if (hci_dev_test_flag(hdev, HCI_ADVERTISING))
hcon = hci_connect_le(hdev, dst, dst_type,
hcon = hci_connect_le(hdev, dst, dst_type, false,
chan->sec_level,
HCI_LE_CONN_TIMEOUT,
HCI_ROLE_SLAVE, NULL);
......
......@@ -1508,6 +1508,9 @@ static void l2cap_sock_close_cb(struct l2cap_chan *chan)
{
struct sock *sk = chan->data;
if (!sk)
return;
l2cap_sock_kill(sk);
}
......@@ -1516,6 +1519,9 @@ static void l2cap_sock_teardown_cb(struct l2cap_chan *chan, int err)
struct sock *sk = chan->data;
struct sock *parent;
if (!sk)
return;
BT_DBG("chan %p state %s", chan, state_to_string(chan->state));
/* This callback can be called both for server (BT_LISTEN)
......@@ -1707,8 +1713,10 @@ static void l2cap_sock_destruct(struct sock *sk)
{
BT_DBG("sk %p", sk);
if (l2cap_pi(sk)->chan)
if (l2cap_pi(sk)->chan) {
l2cap_pi(sk)->chan->data = NULL;
l2cap_chan_put(l2cap_pi(sk)->chan);
}
if (l2cap_pi(sk)->rx_busy_skb) {
kfree_skb(l2cap_pi(sk)->rx_busy_skb);
......
This diff is collapsed.
......@@ -94,11 +94,14 @@ struct msft_data {
__u16 pending_add_handle;
__u16 pending_remove_handle;
__u8 reregistering;
__u8 suspending;
__u8 filter_enabled;
};
static int __msft_add_monitor_pattern(struct hci_dev *hdev,
struct adv_monitor *monitor);
static int __msft_remove_monitor(struct hci_dev *hdev,
struct adv_monitor *monitor, u16 handle);
bool msft_monitor_supported(struct hci_dev *hdev)
{
......@@ -154,7 +157,7 @@ static bool read_supported_features(struct hci_dev *hdev,
}
/* This function requires the caller holds hdev->lock */
static void reregister_monitor_on_restart(struct hci_dev *hdev, int handle)
static void reregister_monitor(struct hci_dev *hdev, int handle)
{
struct adv_monitor *monitor;
struct msft_data *msft = hdev->msft_data;
......@@ -182,31 +185,102 @@ static void reregister_monitor_on_restart(struct hci_dev *hdev, int handle)
}
}
/* This function requires the caller holds hdev->lock */
static void remove_monitor_on_suspend(struct hci_dev *hdev, int handle)
{
struct adv_monitor *monitor;
struct msft_data *msft = hdev->msft_data;
int err;
while (1) {
monitor = idr_get_next(&hdev->adv_monitors_idr, &handle);
if (!monitor) {
/* All monitors have been removed */
msft->suspending = false;
hci_update_background_scan(hdev);
return;
}
msft->pending_remove_handle = (u16)handle;
err = __msft_remove_monitor(hdev, monitor, handle);
/* If success, return and wait for monitor removed callback */
if (!err)
return;
/* Otherwise free the monitor and keep removing */
hci_free_adv_monitor(hdev, monitor);
handle++;
}
}
/* This function requires the caller holds hdev->lock */
void msft_suspend(struct hci_dev *hdev)
{
struct msft_data *msft = hdev->msft_data;
if (!msft)
return;
if (msft_monitor_supported(hdev)) {
msft->suspending = true;
/* Quitely remove all monitors on suspend to avoid waking up
* the system.
*/
remove_monitor_on_suspend(hdev, 0);
}
}
/* This function requires the caller holds hdev->lock */
void msft_resume(struct hci_dev *hdev)
{
struct msft_data *msft = hdev->msft_data;
if (!msft)
return;
if (msft_monitor_supported(hdev)) {
msft->reregistering = true;
/* Monitors are removed on suspend, so we need to add all
* monitors on resume.
*/
reregister_monitor(hdev, 0);
}
}
void msft_do_open(struct hci_dev *hdev)
{
struct msft_data *msft;
struct msft_data *msft = hdev->msft_data;
if (hdev->msft_opcode == HCI_OP_NOP)
return;
if (!msft) {
bt_dev_err(hdev, "MSFT extension not registered");
return;
}
bt_dev_dbg(hdev, "Initialize MSFT extension");
msft = kzalloc(sizeof(*msft), GFP_KERNEL);
if (!msft)
return;
/* Reset existing MSFT data before re-reading */
kfree(msft->evt_prefix);
msft->evt_prefix = NULL;
msft->evt_prefix_len = 0;
msft->features = 0;
if (!read_supported_features(hdev, msft)) {
hdev->msft_data = NULL;
kfree(msft);
return;
}
INIT_LIST_HEAD(&msft->handle_map);
hdev->msft_data = msft;
if (msft_monitor_supported(hdev)) {
msft->reregistering = true;
msft_set_filter_enable(hdev, true);
reregister_monitor_on_restart(hdev, 0);
/* Monitors get removed on power off, so we need to explicitly
* tell the controller to re-monitor.
*/
reregister_monitor(hdev, 0);
}
}
......@@ -221,8 +295,9 @@ void msft_do_close(struct hci_dev *hdev)
bt_dev_dbg(hdev, "Cleanup of MSFT extension");
hdev->msft_data = NULL;
/* The controller will silently remove all monitors on power off.
* Therefore, remove handle_data mapping and reset monitor state.
*/
list_for_each_entry_safe(handle_data, tmp, &msft->handle_map, list) {
monitor = idr_find(&hdev->adv_monitors_idr,
handle_data->mgmt_handle);
......@@ -233,6 +308,34 @@ void msft_do_close(struct hci_dev *hdev)
list_del(&handle_data->list);
kfree(handle_data);
}
}
void msft_register(struct hci_dev *hdev)
{
struct msft_data *msft = NULL;
bt_dev_dbg(hdev, "Register MSFT extension");
msft = kzalloc(sizeof(*msft), GFP_KERNEL);
if (!msft) {
bt_dev_err(hdev, "Failed to register MSFT extension");
return;
}
INIT_LIST_HEAD(&msft->handle_map);
hdev->msft_data = msft;
}
void msft_unregister(struct hci_dev *hdev)
{
struct msft_data *msft = hdev->msft_data;
if (!msft)
return;
bt_dev_dbg(hdev, "Unregister MSFT extension");
hdev->msft_data = NULL;
kfree(msft->evt_prefix);
kfree(msft);
......@@ -345,8 +448,7 @@ static void msft_le_monitor_advertisement_cb(struct hci_dev *hdev,
/* If in restart/reregister sequence, keep registering. */
if (msft->reregistering)
reregister_monitor_on_restart(hdev,
msft->pending_add_handle + 1);
reregister_monitor(hdev, msft->pending_add_handle + 1);
hci_dev_unlock(hdev);
......@@ -383,13 +485,25 @@ static void msft_le_cancel_monitor_advertisement_cb(struct hci_dev *hdev,
if (handle_data) {
monitor = idr_find(&hdev->adv_monitors_idr,
handle_data->mgmt_handle);
if (monitor)
if (monitor && monitor->state == ADV_MONITOR_STATE_OFFLOADED)
monitor->state = ADV_MONITOR_STATE_REGISTERED;
/* Do not free the monitor if it is being removed due to
* suspend. It will be re-monitored on resume.
*/
if (monitor && !msft->suspending)
hci_free_adv_monitor(hdev, monitor);
list_del(&handle_data->list);
kfree(handle_data);
}
/* If in suspend/remove sequence, keep removing. */
if (msft->suspending)
remove_monitor_on_suspend(hdev,
msft->pending_remove_handle + 1);
/* If remove all monitors is required, we need to continue the process
* here because the earlier it was paused when waiting for the
* response from controller.
......@@ -408,7 +522,8 @@ static void msft_le_cancel_monitor_advertisement_cb(struct hci_dev *hdev,
hci_dev_unlock(hdev);
done:
hci_remove_adv_monitor_complete(hdev, status);
if (!msft->suspending)
hci_remove_adv_monitor_complete(hdev, status);
}
static void msft_le_set_advertisement_filter_enable_cb(struct hci_dev *hdev,
......@@ -541,15 +656,15 @@ int msft_add_monitor_pattern(struct hci_dev *hdev, struct adv_monitor *monitor)
if (!msft)
return -EOPNOTSUPP;
if (msft->reregistering)
if (msft->reregistering || msft->suspending)
return -EBUSY;
return __msft_add_monitor_pattern(hdev, monitor);
}
/* This function requires the caller holds hdev->lock */
int msft_remove_monitor(struct hci_dev *hdev, struct adv_monitor *monitor,
u16 handle)
static int __msft_remove_monitor(struct hci_dev *hdev,
struct adv_monitor *monitor, u16 handle)
{
struct msft_cp_le_cancel_monitor_advertisement cp;
struct msft_monitor_advertisement_handle_data *handle_data;
......@@ -557,12 +672,6 @@ int msft_remove_monitor(struct hci_dev *hdev, struct adv_monitor *monitor,
struct msft_data *msft = hdev->msft_data;
int err = 0;
if (!msft)
return -EOPNOTSUPP;
if (msft->reregistering)
return -EBUSY;
handle_data = msft_find_handle_data(hdev, monitor->handle, true);
/* If no matched handle, just remove without telling controller */
......@@ -582,6 +691,21 @@ int msft_remove_monitor(struct hci_dev *hdev, struct adv_monitor *monitor,
return err;
}
/* This function requires the caller holds hdev->lock */
int msft_remove_monitor(struct hci_dev *hdev, struct adv_monitor *monitor,
u16 handle)
{
struct msft_data *msft = hdev->msft_data;
if (!msft)
return -EOPNOTSUPP;
if (msft->reregistering || msft->suspending)
return -EBUSY;
return __msft_remove_monitor(hdev, monitor, handle);
}
void msft_req_add_set_filter_enable(struct hci_request *req, bool enable)
{
struct hci_dev *hdev = req->hdev;
......
......@@ -13,6 +13,8 @@
#if IS_ENABLED(CONFIG_BT_MSFTEXT)
bool msft_monitor_supported(struct hci_dev *hdev);
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);
......@@ -22,6 +24,8 @@ int msft_remove_monitor(struct hci_dev *hdev, struct adv_monitor *monitor,
u16 handle);
void msft_req_add_set_filter_enable(struct hci_request *req, bool enable);
int msft_set_filter_enable(struct hci_dev *hdev, bool enable);
void msft_suspend(struct hci_dev *hdev);
void msft_resume(struct hci_dev *hdev);
bool msft_curve_validity(struct hci_dev *hdev);
#else
......@@ -31,6 +35,8 @@ static inline bool msft_monitor_supported(struct hci_dev *hdev)
return false;
}
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) {}
......@@ -55,6 +61,9 @@ static inline int msft_set_filter_enable(struct hci_dev *hdev, bool enable)
return -EOPNOTSUPP;
}
static inline void msft_suspend(struct hci_dev *hdev) {}
static inline void msft_resume(struct hci_dev *hdev) {}
static inline bool msft_curve_validity(struct hci_dev *hdev)
{
return false;
......
......@@ -549,22 +549,58 @@ struct rfcomm_dlc *rfcomm_dlc_exists(bdaddr_t *src, bdaddr_t *dst, u8 channel)
return dlc;
}
static int rfcomm_dlc_send_frag(struct rfcomm_dlc *d, struct sk_buff *frag)
{
int len = frag->len;
BT_DBG("dlc %p mtu %d len %d", d, d->mtu, len);
if (len > d->mtu)
return -EINVAL;
rfcomm_make_uih(frag, d->addr);
__skb_queue_tail(&d->tx_queue, frag);
return len;
}
int rfcomm_dlc_send(struct rfcomm_dlc *d, struct sk_buff *skb)
{
int len = skb->len;
unsigned long flags;
struct sk_buff *frag, *next;
int len;
if (d->state != BT_CONNECTED)
return -ENOTCONN;
BT_DBG("dlc %p mtu %d len %d", d, d->mtu, len);
frag = skb_shinfo(skb)->frag_list;
skb_shinfo(skb)->frag_list = NULL;
if (len > d->mtu)
return -EINVAL;
/* Queue all fragments atomically. */
spin_lock_irqsave(&d->tx_queue.lock, flags);
rfcomm_make_uih(skb, d->addr);
skb_queue_tail(&d->tx_queue, skb);
len = rfcomm_dlc_send_frag(d, skb);
if (len < 0 || !frag)
goto unlock;
for (; frag; frag = next) {
int ret;
next = frag->next;
ret = rfcomm_dlc_send_frag(d, frag);
if (ret < 0) {
kfree_skb(frag);
goto unlock;
}
len += ret;
}
unlock:
spin_unlock_irqrestore(&d->tx_queue.lock, flags);
if (!test_bit(RFCOMM_TX_THROTTLED, &d->flags))
if (len > 0 && !test_bit(RFCOMM_TX_THROTTLED, &d->flags))
rfcomm_schedule();
return len;
}
......
......@@ -575,46 +575,20 @@ static int rfcomm_sock_sendmsg(struct socket *sock, struct msghdr *msg,
lock_sock(sk);
sent = bt_sock_wait_ready(sk, msg->msg_flags);
if (sent)
goto done;
while (len) {
size_t size = min_t(size_t, len, d->mtu);
int err;
skb = sock_alloc_send_skb(sk, size + RFCOMM_SKB_RESERVE,
msg->msg_flags & MSG_DONTWAIT, &err);
if (!skb) {
if (sent == 0)
sent = err;
break;
}
skb_reserve(skb, RFCOMM_SKB_HEAD_RESERVE);
err = memcpy_from_msg(skb_put(skb, size), msg, size);
if (err) {
kfree_skb(skb);
if (sent == 0)
sent = err;
break;
}
skb->priority = sk->sk_priority;
release_sock(sk);
err = rfcomm_dlc_send(d, skb);
if (err < 0) {
kfree_skb(skb);
if (sent == 0)
sent = err;
break;
}
if (sent)
return sent;
sent += size;
len -= size;
}
skb = bt_skb_sendmmsg(sk, msg, len, d->mtu, RFCOMM_SKB_HEAD_RESERVE,
RFCOMM_SKB_TAIL_RESERVE);
if (IS_ERR(skb))
return PTR_ERR(skb);
done:
release_sock(sk);
sent = rfcomm_dlc_send(d, skb);
if (sent < 0)
kfree_skb(skb);
return sent;
}
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment