bluetooth-next pull request for net-next:
- Add 0bda:b85b for Fn-Link RTL8852BE - ISO: Many fixes for broadcast support - Mark bcm4378/bcm4387 as BROKEN_LE_CODED - Add support ITTIM PE50-M75C - Add RTW8852BE device 13d3:3570 - Add support for QCA2066 - Add support for Intel Misty Peak - 8087:0038 -----BEGIN PGP SIGNATURE----- iQJNBAABCAA3FiEE7E6oRXp8w05ovYr/9JCA4xAyCykFAmU2uMkZHGx1aXoudm9u LmRlbnR6QGludGVsLmNvbQAKCRD0kIDjEDILKWHJD/9HYFBu6afBYi4vHF1mp6qV m1eGESSddZt50+xnxp/O20zL0U/xmbgabmrsY5oyxRsSapgieU2vt03tUX/RvgPK FIjmdXxNNYe++Uaksg2iJuySpdsPxGj/1EXEMFk8dhQ6PQYtW/w/QK4HDTcLOJMN pfx2NNTTcsuaoCiEPkbRybCrVvtQzcWvyKFfhEpEF4XUtU/bA1OjBJoduLolPRqJ p61Btt+bdgZz75tMwAGyOYJwj+uVJp4lyCdvYtUmu+lWLNqp+1a+xQWoiH1zpZ3P nk1r/GcumO7QSGfA9i8mnkdXGweTn6d84G5ys2JXjppTN3YuvxVy+Sr4u27POO0A Z3EF46BxcG6HEfTUWLBdYlMZLMUZMeSEBg4ubEVad1rEDLahZzV7DZAGyJzBgXH2 rbHt6YTJDOm01s4+Fa92Oy4BCEdA91FCO0AhwcsV022qQ8ynOmWdz5iK7LGDcw/2 QvWCdeCKZ11HtyVzX7SqffVDzmgNtqTtasGrhTdt/SF0pAUobgQvRTh0dx7e1BH4 FZb4DZULu4Fs01/OyUMVNU997WDl5+B0jrrqrbh1k9vgISxisKN5CxltRSKfdYtl HwCmoLoXjovLH935s4AXQ/MWUk3dkgx45nfShp9QjNxfj/yMH2crwVrRUA0BBXzo mSGtOV/pdNyWUNVxR1R7OQ== =jUZj -----END PGP SIGNATURE----- Merge tag 'for-net-next-2023-10-23' 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 0bda:b85b for Fn-Link RTL8852BE - ISO: Many fixes for broadcast support - Mark bcm4378/bcm4387 as BROKEN_LE_CODED - Add support ITTIM PE50-M75C - Add RTW8852BE device 13d3:3570 - Add support for QCA2066 - Add support for Intel Misty Peak - 8087:0038 * tag 'for-net-next-2023-10-23' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next: Bluetooth: hci_sync: Fix Opcode prints in bt_dev_dbg/err Bluetooth: Fix double free in hci_conn_cleanup Bluetooth: btmtksdio: enable bluetooth wakeup in system suspend Bluetooth: btusb: Add 0bda:b85b for Fn-Link RTL8852BE Bluetooth: hci_bcm4377: Mark bcm4378/bcm4387 as BROKEN_LE_CODED Bluetooth: ISO: Copy BASE if service data matches EIR_BAA_SERVICE_UUID Bluetooth: Make handle of hci_conn be unique Bluetooth: btusb: Add date->evt_skb is NULL check Bluetooth: ISO: Fix bcast listener cleanup Bluetooth: msft: __hci_cmd_sync() doesn't return NULL Bluetooth: ISO: Match QoS adv handle with BIG handle Bluetooth: ISO: Allow binding a bcast listener to 0 bises Bluetooth: btusb: Add RTW8852BE device 13d3:3570 to device tables Bluetooth: qca: add support for QCA2066 Bluetooth: ISO: Set CIS bit only for devices with CIS support Bluetooth: Add support for Intel Misty Peak - 8087:0038 Bluetooth: Add support ITTIM PE50-M75C Bluetooth: ISO: Pass BIG encryption info through QoS Bluetooth: ISO: Fix BIS cleanup ==================== Link: https://lore.kernel.org/r/20231023182119.3629194-1-luiz.dentz@gmail.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
commit
f4dbc2bb7a
@ -118,6 +118,7 @@ MODULE_DEVICE_TABLE(sdio, btmtksdio_table);
|
||||
#define BTMTKSDIO_FUNC_ENABLED 3
|
||||
#define BTMTKSDIO_PATCH_ENABLED 4
|
||||
#define BTMTKSDIO_HW_RESET_ACTIVE 5
|
||||
#define BTMTKSDIO_BT_WAKE_ENABLED 6
|
||||
|
||||
struct mtkbtsdio_hdr {
|
||||
__le16 len;
|
||||
@ -554,7 +555,7 @@ static void btmtksdio_txrx_work(struct work_struct *work)
|
||||
sdio_claim_host(bdev->func);
|
||||
|
||||
/* Disable interrupt */
|
||||
sdio_writel(bdev->func, C_INT_EN_CLR, MTK_REG_CHLPCR, 0);
|
||||
sdio_writel(bdev->func, C_INT_EN_CLR, MTK_REG_CHLPCR, NULL);
|
||||
|
||||
txrx_timeout = jiffies + 5 * HZ;
|
||||
|
||||
@ -576,7 +577,7 @@ static void btmtksdio_txrx_work(struct work_struct *work)
|
||||
if ((int_status & FW_MAILBOX_INT) &&
|
||||
bdev->data->chipid == 0x7921) {
|
||||
sdio_writel(bdev->func, PH2DSM0R_DRIVER_OWN,
|
||||
MTK_REG_PH2DSM0R, 0);
|
||||
MTK_REG_PH2DSM0R, NULL);
|
||||
}
|
||||
|
||||
if (int_status & FW_OWN_BACK_INT)
|
||||
@ -608,7 +609,7 @@ static void btmtksdio_txrx_work(struct work_struct *work)
|
||||
} while (int_status || time_is_before_jiffies(txrx_timeout));
|
||||
|
||||
/* Enable interrupt */
|
||||
sdio_writel(bdev->func, C_INT_EN_SET, MTK_REG_CHLPCR, 0);
|
||||
sdio_writel(bdev->func, C_INT_EN_SET, MTK_REG_CHLPCR, NULL);
|
||||
|
||||
sdio_release_host(bdev->func);
|
||||
|
||||
@ -620,8 +621,14 @@ static void btmtksdio_interrupt(struct sdio_func *func)
|
||||
{
|
||||
struct btmtksdio_dev *bdev = sdio_get_drvdata(func);
|
||||
|
||||
if (test_bit(BTMTKSDIO_BT_WAKE_ENABLED, &bdev->tx_state)) {
|
||||
if (bdev->hdev->suspended)
|
||||
pm_wakeup_event(bdev->dev, 0);
|
||||
clear_bit(BTMTKSDIO_BT_WAKE_ENABLED, &bdev->tx_state);
|
||||
}
|
||||
|
||||
/* Disable interrupt */
|
||||
sdio_writel(bdev->func, C_INT_EN_CLR, MTK_REG_CHLPCR, 0);
|
||||
sdio_writel(bdev->func, C_INT_EN_CLR, MTK_REG_CHLPCR, NULL);
|
||||
|
||||
schedule_work(&bdev->txrx_work);
|
||||
}
|
||||
@ -1454,6 +1461,23 @@ static int btmtksdio_runtime_suspend(struct device *dev)
|
||||
return err;
|
||||
}
|
||||
|
||||
static int btmtksdio_system_suspend(struct device *dev)
|
||||
{
|
||||
struct sdio_func *func = dev_to_sdio_func(dev);
|
||||
struct btmtksdio_dev *bdev;
|
||||
|
||||
bdev = sdio_get_drvdata(func);
|
||||
if (!bdev)
|
||||
return 0;
|
||||
|
||||
if (!test_bit(BTMTKSDIO_FUNC_ENABLED, &bdev->tx_state))
|
||||
return 0;
|
||||
|
||||
set_bit(BTMTKSDIO_BT_WAKE_ENABLED, &bdev->tx_state);
|
||||
|
||||
return btmtksdio_runtime_suspend(dev);
|
||||
}
|
||||
|
||||
static int btmtksdio_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct sdio_func *func = dev_to_sdio_func(dev);
|
||||
@ -1474,8 +1498,16 @@ static int btmtksdio_runtime_resume(struct device *dev)
|
||||
return err;
|
||||
}
|
||||
|
||||
static UNIVERSAL_DEV_PM_OPS(btmtksdio_pm_ops, btmtksdio_runtime_suspend,
|
||||
btmtksdio_runtime_resume, NULL);
|
||||
static int btmtksdio_system_resume(struct device *dev)
|
||||
{
|
||||
return btmtksdio_runtime_resume(dev);
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops btmtksdio_pm_ops = {
|
||||
SYSTEM_SLEEP_PM_OPS(btmtksdio_system_suspend, btmtksdio_system_resume)
|
||||
RUNTIME_PM_OPS(btmtksdio_runtime_suspend, btmtksdio_runtime_resume, NULL)
|
||||
};
|
||||
|
||||
#define BTMTKSDIO_PM_OPS (&btmtksdio_pm_ops)
|
||||
#else /* CONFIG_PM */
|
||||
#define BTMTKSDIO_PM_OPS NULL
|
||||
|
@ -205,6 +205,44 @@ static int qca_send_reset(struct hci_dev *hdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int qca_read_fw_board_id(struct hci_dev *hdev, u16 *bid)
|
||||
{
|
||||
u8 cmd;
|
||||
struct sk_buff *skb;
|
||||
struct edl_event_hdr *edl;
|
||||
int err = 0;
|
||||
|
||||
cmd = EDL_GET_BID_REQ_CMD;
|
||||
skb = __hci_cmd_sync_ev(hdev, EDL_PATCH_CMD_OPCODE, EDL_PATCH_CMD_LEN,
|
||||
&cmd, 0, HCI_INIT_TIMEOUT);
|
||||
if (IS_ERR(skb)) {
|
||||
err = PTR_ERR(skb);
|
||||
bt_dev_err(hdev, "Reading QCA board ID failed (%d)", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
edl = skb_pull_data(skb, sizeof(*edl));
|
||||
if (!edl) {
|
||||
bt_dev_err(hdev, "QCA read board ID with no header");
|
||||
err = -EILSEQ;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (edl->cresp != EDL_CMD_REQ_RES_EVT ||
|
||||
edl->rtype != EDL_GET_BID_REQ_CMD) {
|
||||
bt_dev_err(hdev, "QCA Wrong packet: %d %d", edl->cresp, edl->rtype);
|
||||
err = -EIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
*bid = (edl->data[1] << 8) + edl->data[2];
|
||||
bt_dev_dbg(hdev, "%s: bid = %x", __func__, *bid);
|
||||
|
||||
out:
|
||||
kfree_skb(skb);
|
||||
return err;
|
||||
}
|
||||
|
||||
int qca_send_pre_shutdown_cmd(struct hci_dev *hdev)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
@ -574,6 +612,23 @@ int qca_set_bdaddr_rome(struct hci_dev *hdev, const bdaddr_t *bdaddr)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(qca_set_bdaddr_rome);
|
||||
|
||||
static void qca_generate_hsp_nvm_name(char *fwname, size_t max_size,
|
||||
struct qca_btsoc_version ver, u8 rom_ver, u16 bid)
|
||||
{
|
||||
const char *variant;
|
||||
|
||||
/* hsp gf chip */
|
||||
if ((le32_to_cpu(ver.soc_id) & QCA_HSP_GF_SOC_MASK) == QCA_HSP_GF_SOC_ID)
|
||||
variant = "g";
|
||||
else
|
||||
variant = "";
|
||||
|
||||
if (bid == 0x0)
|
||||
snprintf(fwname, max_size, "qca/hpnv%02x%s.bin", rom_ver, variant);
|
||||
else
|
||||
snprintf(fwname, max_size, "qca/hpnv%02x%s.%x", rom_ver, variant, bid);
|
||||
}
|
||||
|
||||
int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
|
||||
enum qca_btsoc_type soc_type, struct qca_btsoc_version ver,
|
||||
const char *firmware_name)
|
||||
@ -582,6 +637,7 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
|
||||
int err;
|
||||
u8 rom_ver = 0;
|
||||
u32 soc_ver;
|
||||
u16 boardid = 0;
|
||||
|
||||
bt_dev_dbg(hdev, "QCA setup on UART");
|
||||
|
||||
@ -615,6 +671,10 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
|
||||
snprintf(config.fwname, sizeof(config.fwname),
|
||||
"qca/apbtfw%02x.tlv", rom_ver);
|
||||
break;
|
||||
case QCA_QCA2066:
|
||||
snprintf(config.fwname, sizeof(config.fwname),
|
||||
"qca/hpbtfw%02x.tlv", rom_ver);
|
||||
break;
|
||||
case QCA_QCA6390:
|
||||
snprintf(config.fwname, sizeof(config.fwname),
|
||||
"qca/htbtfw%02x.tlv", rom_ver);
|
||||
@ -649,6 +709,9 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
|
||||
/* Give the controller some time to get ready to receive the NVM */
|
||||
msleep(10);
|
||||
|
||||
if (soc_type == QCA_QCA2066)
|
||||
qca_read_fw_board_id(hdev, &boardid);
|
||||
|
||||
/* Download NVM configuration */
|
||||
config.type = TLV_TYPE_NVM;
|
||||
if (firmware_name) {
|
||||
@ -671,6 +734,10 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
|
||||
snprintf(config.fwname, sizeof(config.fwname),
|
||||
"qca/apnv%02x.bin", rom_ver);
|
||||
break;
|
||||
case QCA_QCA2066:
|
||||
qca_generate_hsp_nvm_name(config.fwname,
|
||||
sizeof(config.fwname), ver, rom_ver, boardid);
|
||||
break;
|
||||
case QCA_QCA6390:
|
||||
snprintf(config.fwname, sizeof(config.fwname),
|
||||
"qca/htnv%02x.bin", rom_ver);
|
||||
@ -702,6 +769,7 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
|
||||
|
||||
switch (soc_type) {
|
||||
case QCA_WCN3991:
|
||||
case QCA_QCA2066:
|
||||
case QCA_QCA6390:
|
||||
case QCA_WCN6750:
|
||||
case QCA_WCN6855:
|
||||
|
@ -12,6 +12,7 @@
|
||||
#define EDL_PATCH_VER_REQ_CMD (0x19)
|
||||
#define EDL_PATCH_TLV_REQ_CMD (0x1E)
|
||||
#define EDL_GET_BUILD_INFO_CMD (0x20)
|
||||
#define EDL_GET_BID_REQ_CMD (0x23)
|
||||
#define EDL_NVM_ACCESS_SET_REQ_CMD (0x01)
|
||||
#define EDL_PATCH_CONFIG_CMD (0x28)
|
||||
#define MAX_SIZE_PER_TLV_SEGMENT (243)
|
||||
@ -47,7 +48,8 @@
|
||||
((le32_to_cpu(soc_id) << 16) | (le16_to_cpu(rom_ver)))
|
||||
|
||||
#define QCA_FW_BUILD_VER_LEN 255
|
||||
|
||||
#define QCA_HSP_GF_SOC_ID 0x1200
|
||||
#define QCA_HSP_GF_SOC_MASK 0x0000ff00
|
||||
|
||||
enum qca_baudrate {
|
||||
QCA_BAUDRATE_115200 = 0,
|
||||
@ -146,6 +148,7 @@ enum qca_btsoc_type {
|
||||
QCA_WCN3990,
|
||||
QCA_WCN3998,
|
||||
QCA_WCN3991,
|
||||
QCA_QCA2066,
|
||||
QCA_QCA6390,
|
||||
QCA_WCN6750,
|
||||
QCA_WCN6855,
|
||||
|
@ -477,6 +477,7 @@ static const struct usb_device_id quirks_table[] = {
|
||||
{ USB_DEVICE(0x8087, 0x0033), .driver_info = BTUSB_INTEL_COMBINED },
|
||||
{ USB_DEVICE(0x8087, 0x0035), .driver_info = BTUSB_INTEL_COMBINED },
|
||||
{ USB_DEVICE(0x8087, 0x0036), .driver_info = BTUSB_INTEL_COMBINED },
|
||||
{ USB_DEVICE(0x8087, 0x0038), .driver_info = BTUSB_INTEL_COMBINED },
|
||||
{ USB_DEVICE(0x8087, 0x07da), .driver_info = BTUSB_CSR },
|
||||
{ USB_DEVICE(0x8087, 0x07dc), .driver_info = BTUSB_INTEL_COMBINED |
|
||||
BTUSB_INTEL_NO_WBS_SUPPORT |
|
||||
@ -543,6 +544,10 @@ static const struct usb_device_id quirks_table[] = {
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
{ USB_DEVICE(0x0bda, 0x887b), .driver_info = BTUSB_REALTEK |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
{ USB_DEVICE(0x0bda, 0xb85b), .driver_info = BTUSB_REALTEK |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
{ USB_DEVICE(0x13d3, 0x3570), .driver_info = BTUSB_REALTEK |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
{ USB_DEVICE(0x13d3, 0x3571), .driver_info = BTUSB_REALTEK |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
|
||||
@ -644,6 +649,9 @@ static const struct usb_device_id quirks_table[] = {
|
||||
{ USB_DEVICE(0x04ca, 0x3804), .driver_info = BTUSB_MEDIATEK |
|
||||
BTUSB_WIDEBAND_SPEECH |
|
||||
BTUSB_VALID_LE_STATES },
|
||||
{ USB_DEVICE(0x35f5, 0x7922), .driver_info = BTUSB_MEDIATEK |
|
||||
BTUSB_WIDEBAND_SPEECH |
|
||||
BTUSB_VALID_LE_STATES },
|
||||
|
||||
/* Additional Realtek 8723AE Bluetooth devices */
|
||||
{ USB_DEVICE(0x0930, 0x021d), .driver_info = BTUSB_REALTEK },
|
||||
@ -2818,6 +2826,9 @@ static int btusb_mtk_hci_wmt_sync(struct hci_dev *hdev,
|
||||
goto err_free_wc;
|
||||
}
|
||||
|
||||
if (data->evt_skb == NULL)
|
||||
goto err_free_wc;
|
||||
|
||||
/* Parse and handle the return WMT event */
|
||||
wmt_evt = (struct btmtk_hci_wmt_evt *)data->evt_skb->data;
|
||||
if (wmt_evt->whdr.op != hdr->op) {
|
||||
|
@ -512,6 +512,7 @@ struct bcm4377_hw {
|
||||
unsigned long disable_aspm : 1;
|
||||
unsigned long broken_ext_scan : 1;
|
||||
unsigned long broken_mws_transport_config : 1;
|
||||
unsigned long broken_le_coded : 1;
|
||||
|
||||
int (*send_calibration)(struct bcm4377_data *bcm4377);
|
||||
int (*send_ptb)(struct bcm4377_data *bcm4377,
|
||||
@ -2372,6 +2373,8 @@ static int bcm4377_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
||||
set_bit(HCI_QUIRK_BROKEN_MWS_TRANSPORT_CONFIG, &hdev->quirks);
|
||||
if (bcm4377->hw->broken_ext_scan)
|
||||
set_bit(HCI_QUIRK_BROKEN_EXT_SCAN, &hdev->quirks);
|
||||
if (bcm4377->hw->broken_le_coded)
|
||||
set_bit(HCI_QUIRK_BROKEN_LE_CODED, &hdev->quirks);
|
||||
|
||||
pci_set_drvdata(pdev, bcm4377);
|
||||
hci_set_drvdata(hdev, bcm4377);
|
||||
@ -2461,6 +2464,7 @@ static const struct bcm4377_hw bcm4377_hw_variants[] = {
|
||||
.bar0_core2_window2 = 0x18107000,
|
||||
.has_bar0_core2_window2 = true,
|
||||
.broken_mws_transport_config = true,
|
||||
.broken_le_coded = true,
|
||||
.send_calibration = bcm4378_send_calibration,
|
||||
.send_ptb = bcm4378_send_ptb,
|
||||
},
|
||||
@ -2474,6 +2478,7 @@ static const struct bcm4377_hw bcm4377_hw_variants[] = {
|
||||
.has_bar0_core2_window2 = true,
|
||||
.clear_pciecfg_subsystem_ctrl_bit19 = true,
|
||||
.broken_mws_transport_config = true,
|
||||
.broken_le_coded = true,
|
||||
.send_calibration = bcm4387_send_calibration,
|
||||
.send_ptb = bcm4378_send_ptb,
|
||||
},
|
||||
|
@ -1841,6 +1841,10 @@ static int qca_setup(struct hci_uart *hu)
|
||||
set_bit(HCI_QUIRK_SIMULTANEOUS_DISCOVERY, &hdev->quirks);
|
||||
|
||||
switch (soc_type) {
|
||||
case QCA_QCA2066:
|
||||
soc_name = "qca2066";
|
||||
break;
|
||||
|
||||
case QCA_WCN3988:
|
||||
case QCA_WCN3990:
|
||||
case QCA_WCN3991:
|
||||
@ -2032,6 +2036,11 @@ static const struct qca_device_data qca_soc_data_wcn3998 __maybe_unused = {
|
||||
.num_vregs = 4,
|
||||
};
|
||||
|
||||
static const struct qca_device_data qca_soc_data_qca2066 __maybe_unused = {
|
||||
.soc_type = QCA_QCA2066,
|
||||
.num_vregs = 0,
|
||||
};
|
||||
|
||||
static const struct qca_device_data qca_soc_data_qca6390 __maybe_unused = {
|
||||
.soc_type = QCA_QCA6390,
|
||||
.num_vregs = 0,
|
||||
@ -2559,6 +2568,7 @@ static SIMPLE_DEV_PM_OPS(qca_pm_ops, qca_suspend, qca_resume);
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id qca_bluetooth_of_match[] = {
|
||||
{ .compatible = "qcom,qca2066-bt", .data = &qca_soc_data_qca2066},
|
||||
{ .compatible = "qcom,qca6174-bt" },
|
||||
{ .compatible = "qcom,qca6390-bt", .data = &qca_soc_data_qca6390},
|
||||
{ .compatible = "qcom,qca9377-bt" },
|
||||
@ -2576,6 +2586,7 @@ MODULE_DEVICE_TABLE(of, qca_bluetooth_of_match);
|
||||
|
||||
#ifdef CONFIG_ACPI
|
||||
static const struct acpi_device_id qca_bluetooth_acpi_match[] = {
|
||||
{ "QCOM2066", (kernel_ulong_t)&qca_soc_data_qca2066 },
|
||||
{ "QCOM6390", (kernel_ulong_t)&qca_soc_data_qca6390 },
|
||||
{ "DLA16390", (kernel_ulong_t)&qca_soc_data_qca6390 },
|
||||
{ "DLB16390", (kernel_ulong_t)&qca_soc_data_qca6390 },
|
||||
|
@ -1,6 +1,7 @@
|
||||
/*
|
||||
BlueZ - Bluetooth protocol stack for Linux
|
||||
Copyright (C) 2000-2001 Qualcomm Incorporated
|
||||
Copyright 2023 NXP
|
||||
|
||||
Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
|
||||
|
||||
@ -673,6 +674,8 @@ enum {
|
||||
#define HCI_TX_POWER_INVALID 127
|
||||
#define HCI_RSSI_INVALID 127
|
||||
|
||||
#define HCI_SYNC_HANDLE_INVALID 0xffff
|
||||
|
||||
#define HCI_ROLE_MASTER 0x00
|
||||
#define HCI_ROLE_SLAVE 0x01
|
||||
|
||||
|
@ -350,6 +350,8 @@ struct hci_dev {
|
||||
struct list_head list;
|
||||
struct mutex lock;
|
||||
|
||||
struct ida unset_handle_ida;
|
||||
|
||||
const char *name;
|
||||
unsigned long flags;
|
||||
__u16 id;
|
||||
@ -1290,31 +1292,8 @@ static inline struct hci_conn *hci_conn_hash_lookup_big(struct hci_dev *hdev,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline struct hci_conn *hci_conn_hash_lookup_big_any_dst(struct hci_dev *hdev,
|
||||
__u8 handle)
|
||||
{
|
||||
struct hci_conn_hash *h = &hdev->conn_hash;
|
||||
struct hci_conn *c;
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
list_for_each_entry_rcu(c, &h->list, list) {
|
||||
if (c->type != ISO_LINK)
|
||||
continue;
|
||||
|
||||
if (handle != BT_ISO_QOS_BIG_UNSET && handle == c->iso_qos.bcast.big) {
|
||||
rcu_read_unlock();
|
||||
return c;
|
||||
}
|
||||
}
|
||||
|
||||
rcu_read_unlock();
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline struct hci_conn *
|
||||
hci_conn_hash_lookup_pa_sync(struct hci_dev *hdev, __u8 big)
|
||||
hci_conn_hash_lookup_pa_sync_big_handle(struct hci_dev *hdev, __u8 big)
|
||||
{
|
||||
struct hci_conn_hash *h = &hdev->conn_hash;
|
||||
struct hci_conn *c;
|
||||
@ -1336,6 +1315,29 @@ hci_conn_hash_lookup_pa_sync(struct hci_dev *hdev, __u8 big)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline struct hci_conn *
|
||||
hci_conn_hash_lookup_pa_sync_handle(struct hci_dev *hdev, __u16 sync_handle)
|
||||
{
|
||||
struct hci_conn_hash *h = &hdev->conn_hash;
|
||||
struct hci_conn *c;
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
list_for_each_entry_rcu(c, &h->list, list) {
|
||||
if (c->type != ISO_LINK ||
|
||||
!test_bit(HCI_CONN_PA_SYNC, &c->flags))
|
||||
continue;
|
||||
|
||||
if (c->sync_handle == sync_handle) {
|
||||
rcu_read_unlock();
|
||||
return c;
|
||||
}
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline struct hci_conn *hci_conn_hash_lookup_state(struct hci_dev *hdev,
|
||||
__u8 type, __u16 state)
|
||||
{
|
||||
@ -1377,6 +1379,26 @@ static inline void hci_conn_hash_list_state(struct hci_dev *hdev,
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
static inline void hci_conn_hash_list_flag(struct hci_dev *hdev,
|
||||
hci_conn_func_t func, __u8 type,
|
||||
__u8 flag, void *data)
|
||||
{
|
||||
struct hci_conn_hash *h = &hdev->conn_hash;
|
||||
struct hci_conn *c;
|
||||
|
||||
if (!func)
|
||||
return;
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
list_for_each_entry_rcu(c, &h->list, list) {
|
||||
if (c->type == type && test_bit(flag, &c->flags))
|
||||
func(c, data);
|
||||
}
|
||||
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
static inline struct hci_conn *hci_lookup_le_connect(struct hci_dev *hdev)
|
||||
{
|
||||
struct hci_conn_hash *h = &hdev->conn_hash;
|
||||
@ -1426,7 +1448,9 @@ int hci_le_create_cis_pending(struct hci_dev *hdev);
|
||||
int hci_conn_check_create_cis(struct hci_conn *conn);
|
||||
|
||||
struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst,
|
||||
u8 role);
|
||||
u8 role, u16 handle);
|
||||
struct hci_conn *hci_conn_add_unset(struct hci_dev *hdev, int type,
|
||||
bdaddr_t *dst, u8 role);
|
||||
void hci_conn_del(struct hci_conn *conn);
|
||||
void hci_conn_hash_flush(struct hci_dev *hdev);
|
||||
void hci_conn_check_pending(struct hci_dev *hdev);
|
||||
|
@ -80,6 +80,8 @@ int hci_start_per_adv_sync(struct hci_dev *hdev, u8 instance, u8 data_len,
|
||||
u8 *data, u32 flags, u16 min_interval,
|
||||
u16 max_interval, u16 sync_interval);
|
||||
|
||||
int hci_disable_per_advertising_sync(struct hci_dev *hdev, u8 instance);
|
||||
|
||||
int hci_remove_advertising_sync(struct hci_dev *hdev, struct sock *sk,
|
||||
u8 instance, bool force);
|
||||
int hci_disable_advertising_sync(struct hci_dev *hdev);
|
||||
|
@ -109,7 +109,7 @@ struct hci_conn *phylink_add(struct hci_dev *hdev, struct amp_mgr *mgr,
|
||||
struct hci_conn *hcon;
|
||||
u8 role = out ? HCI_ROLE_MASTER : HCI_ROLE_SLAVE;
|
||||
|
||||
hcon = hci_conn_add(hdev, AMP_LINK, dst, role);
|
||||
hcon = hci_conn_add(hdev, AMP_LINK, dst, role, __next_handle(mgr));
|
||||
if (!hcon)
|
||||
return NULL;
|
||||
|
||||
@ -117,7 +117,6 @@ struct hci_conn *phylink_add(struct hci_dev *hdev, struct amp_mgr *mgr,
|
||||
|
||||
hcon->state = BT_CONNECT;
|
||||
hcon->attempt++;
|
||||
hcon->handle = __next_handle(mgr);
|
||||
hcon->remote_id = remote_id;
|
||||
hcon->amp_mgr = amp_mgr_get(mgr);
|
||||
|
||||
|
@ -153,6 +153,9 @@ static void hci_conn_cleanup(struct hci_conn *conn)
|
||||
|
||||
hci_conn_hash_del(hdev, conn);
|
||||
|
||||
if (HCI_CONN_HANDLE_UNSET(conn->handle))
|
||||
ida_free(&hdev->unset_handle_ida, conn->handle);
|
||||
|
||||
if (conn->cleanup)
|
||||
conn->cleanup(conn);
|
||||
|
||||
@ -169,13 +172,11 @@ static void hci_conn_cleanup(struct hci_conn *conn)
|
||||
hdev->notify(hdev, HCI_NOTIFY_CONN_DEL);
|
||||
}
|
||||
|
||||
hci_conn_del_sysfs(conn);
|
||||
|
||||
debugfs_remove_recursive(conn->debugfs);
|
||||
|
||||
hci_dev_put(hdev);
|
||||
hci_conn_del_sysfs(conn);
|
||||
|
||||
hci_conn_put(conn);
|
||||
hci_dev_put(hdev);
|
||||
}
|
||||
|
||||
static void hci_acl_create_connection(struct hci_conn *conn)
|
||||
@ -759,6 +760,7 @@ static int terminate_big_sync(struct hci_dev *hdev, void *data)
|
||||
|
||||
bt_dev_dbg(hdev, "big 0x%2.2x bis 0x%2.2x", d->big, d->bis);
|
||||
|
||||
hci_disable_per_advertising_sync(hdev, d->bis);
|
||||
hci_remove_ext_adv_instance_sync(hdev, d->bis, NULL);
|
||||
|
||||
/* Only terminate BIG if it has been created */
|
||||
@ -814,6 +816,17 @@ static int big_terminate_sync(struct hci_dev *hdev, void *data)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void find_bis(struct hci_conn *conn, void *data)
|
||||
{
|
||||
struct iso_list_data *d = data;
|
||||
|
||||
/* Ignore if BIG doesn't match */
|
||||
if (d->big != conn->iso_qos.bcast.big)
|
||||
return;
|
||||
|
||||
d->count++;
|
||||
}
|
||||
|
||||
static int hci_le_big_terminate(struct hci_dev *hdev, u8 big, struct hci_conn *conn)
|
||||
{
|
||||
struct iso_list_data *d;
|
||||
@ -825,10 +838,27 @@ static int hci_le_big_terminate(struct hci_dev *hdev, u8 big, struct hci_conn *c
|
||||
if (!d)
|
||||
return -ENOMEM;
|
||||
|
||||
memset(d, 0, sizeof(*d));
|
||||
d->big = big;
|
||||
d->sync_handle = conn->sync_handle;
|
||||
d->pa_sync_term = test_and_clear_bit(HCI_CONN_PA_SYNC, &conn->flags);
|
||||
d->big_sync_term = test_and_clear_bit(HCI_CONN_BIG_SYNC, &conn->flags);
|
||||
|
||||
if (test_and_clear_bit(HCI_CONN_PA_SYNC, &conn->flags)) {
|
||||
hci_conn_hash_list_flag(hdev, find_bis, ISO_LINK,
|
||||
HCI_CONN_PA_SYNC, d);
|
||||
|
||||
if (!d->count)
|
||||
d->pa_sync_term = true;
|
||||
|
||||
d->count = 0;
|
||||
}
|
||||
|
||||
if (test_and_clear_bit(HCI_CONN_BIG_SYNC, &conn->flags)) {
|
||||
hci_conn_hash_list_flag(hdev, find_bis, ISO_LINK,
|
||||
HCI_CONN_BIG_SYNC, d);
|
||||
|
||||
if (!d->count)
|
||||
d->big_sync_term = true;
|
||||
}
|
||||
|
||||
ret = hci_cmd_sync_queue(hdev, big_terminate_sync, d,
|
||||
terminate_big_destroy);
|
||||
@ -864,12 +894,6 @@ static void bis_cleanup(struct hci_conn *conn)
|
||||
|
||||
hci_le_terminate_big(hdev, conn);
|
||||
} else {
|
||||
bis = hci_conn_hash_lookup_big_any_dst(hdev,
|
||||
conn->iso_qos.bcast.big);
|
||||
|
||||
if (bis)
|
||||
return;
|
||||
|
||||
hci_le_big_terminate(hdev, conn->iso_qos.bcast.big,
|
||||
conn);
|
||||
}
|
||||
@ -928,31 +952,18 @@ static void cis_cleanup(struct hci_conn *conn)
|
||||
hci_le_remove_cig(hdev, conn->iso_qos.ucast.cig);
|
||||
}
|
||||
|
||||
static u16 hci_conn_hash_alloc_unset(struct hci_dev *hdev)
|
||||
static int hci_conn_hash_alloc_unset(struct hci_dev *hdev)
|
||||
{
|
||||
struct hci_conn_hash *h = &hdev->conn_hash;
|
||||
struct hci_conn *c;
|
||||
u16 handle = HCI_CONN_HANDLE_MAX + 1;
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
list_for_each_entry_rcu(c, &h->list, list) {
|
||||
/* Find the first unused handle */
|
||||
if (handle == 0xffff || c->handle != handle)
|
||||
break;
|
||||
handle++;
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
return handle;
|
||||
return ida_alloc_range(&hdev->unset_handle_ida, HCI_CONN_HANDLE_MAX + 1,
|
||||
U16_MAX, GFP_ATOMIC);
|
||||
}
|
||||
|
||||
struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst,
|
||||
u8 role)
|
||||
u8 role, u16 handle)
|
||||
{
|
||||
struct hci_conn *conn;
|
||||
|
||||
BT_DBG("%s dst %pMR", hdev->name, dst);
|
||||
bt_dev_dbg(hdev, "dst %pMR handle 0x%4.4x", dst, handle);
|
||||
|
||||
conn = kzalloc(sizeof(*conn), GFP_KERNEL);
|
||||
if (!conn)
|
||||
@ -960,7 +971,7 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst,
|
||||
|
||||
bacpy(&conn->dst, dst);
|
||||
bacpy(&conn->src, &hdev->bdaddr);
|
||||
conn->handle = hci_conn_hash_alloc_unset(hdev);
|
||||
conn->handle = handle;
|
||||
conn->hdev = hdev;
|
||||
conn->type = type;
|
||||
conn->role = role;
|
||||
@ -973,6 +984,7 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst,
|
||||
conn->rssi = HCI_RSSI_INVALID;
|
||||
conn->tx_power = HCI_TX_POWER_INVALID;
|
||||
conn->max_tx_power = HCI_TX_POWER_INVALID;
|
||||
conn->sync_handle = HCI_SYNC_HANDLE_INVALID;
|
||||
|
||||
set_bit(HCI_CONN_POWER_SAVE, &conn->flags);
|
||||
conn->disc_timeout = HCI_DISCONN_TIMEOUT;
|
||||
@ -1044,6 +1056,20 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst,
|
||||
return conn;
|
||||
}
|
||||
|
||||
struct hci_conn *hci_conn_add_unset(struct hci_dev *hdev, int type,
|
||||
bdaddr_t *dst, u8 role)
|
||||
{
|
||||
int handle;
|
||||
|
||||
bt_dev_dbg(hdev, "dst %pMR", dst);
|
||||
|
||||
handle = hci_conn_hash_alloc_unset(hdev);
|
||||
if (unlikely(handle < 0))
|
||||
return NULL;
|
||||
|
||||
return hci_conn_add(hdev, type, dst, role, handle);
|
||||
}
|
||||
|
||||
static void hci_conn_cleanup_child(struct hci_conn *conn, u8 reason)
|
||||
{
|
||||
if (!reason)
|
||||
@ -1247,6 +1273,12 @@ void hci_conn_failed(struct hci_conn *conn, u8 status)
|
||||
break;
|
||||
}
|
||||
|
||||
/* In case of BIG/PA sync failed, clear conn flags so that
|
||||
* the conns will be correctly cleaned up by ISO layer
|
||||
*/
|
||||
test_and_clear_bit(HCI_CONN_BIG_SYNC_FAILED, &conn->flags);
|
||||
test_and_clear_bit(HCI_CONN_PA_SYNC_FAILED, &conn->flags);
|
||||
|
||||
conn->state = BT_CLOSED;
|
||||
hci_connect_cfm(conn, status);
|
||||
hci_conn_del(conn);
|
||||
@ -1274,6 +1306,9 @@ u8 hci_conn_set_handle(struct hci_conn *conn, u16 handle)
|
||||
if (conn->abort_reason)
|
||||
return conn->abort_reason;
|
||||
|
||||
if (HCI_CONN_HANDLE_UNSET(conn->handle))
|
||||
ida_free(&hdev->unset_handle_ida, conn->handle);
|
||||
|
||||
conn->handle = handle;
|
||||
|
||||
return 0;
|
||||
@ -1381,7 +1416,7 @@ struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst,
|
||||
if (conn) {
|
||||
bacpy(&conn->dst, dst);
|
||||
} else {
|
||||
conn = hci_conn_add(hdev, LE_LINK, dst, role);
|
||||
conn = hci_conn_add_unset(hdev, LE_LINK, dst, role);
|
||||
if (!conn)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
hci_conn_hold(conn);
|
||||
@ -1486,6 +1521,18 @@ static int qos_set_bis(struct hci_dev *hdev, struct bt_iso_qos *qos)
|
||||
|
||||
/* Allocate BIS if not set */
|
||||
if (qos->bcast.bis == BT_ISO_QOS_BIS_UNSET) {
|
||||
if (qos->bcast.big != BT_ISO_QOS_BIG_UNSET) {
|
||||
conn = hci_conn_hash_lookup_big(hdev, qos->bcast.big);
|
||||
|
||||
if (conn) {
|
||||
/* If the BIG handle is already matched to an advertising
|
||||
* handle, do not allocate a new one.
|
||||
*/
|
||||
qos->bcast.bis = conn->iso_qos.bcast.bis;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Find an unused adv set to advertise BIS, skip instance 0x00
|
||||
* since it is reserved as general purpose set.
|
||||
*/
|
||||
@ -1546,7 +1593,7 @@ static struct hci_conn *hci_add_bis(struct hci_dev *hdev, bdaddr_t *dst,
|
||||
memcmp(conn->le_per_adv_data, base, base_len)))
|
||||
return ERR_PTR(-EADDRINUSE);
|
||||
|
||||
conn = hci_conn_add(hdev, ISO_LINK, dst, HCI_ROLE_MASTER);
|
||||
conn = hci_conn_add_unset(hdev, ISO_LINK, dst, HCI_ROLE_MASTER);
|
||||
if (!conn)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
@ -1590,7 +1637,7 @@ struct hci_conn *hci_connect_le_scan(struct hci_dev *hdev, bdaddr_t *dst,
|
||||
|
||||
BT_DBG("requesting refresh of dst_addr");
|
||||
|
||||
conn = hci_conn_add(hdev, LE_LINK, dst, HCI_ROLE_MASTER);
|
||||
conn = hci_conn_add_unset(hdev, LE_LINK, dst, HCI_ROLE_MASTER);
|
||||
if (!conn)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
@ -1638,7 +1685,7 @@ struct hci_conn *hci_connect_acl(struct hci_dev *hdev, bdaddr_t *dst,
|
||||
|
||||
acl = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst);
|
||||
if (!acl) {
|
||||
acl = hci_conn_add(hdev, ACL_LINK, dst, HCI_ROLE_MASTER);
|
||||
acl = hci_conn_add_unset(hdev, ACL_LINK, dst, HCI_ROLE_MASTER);
|
||||
if (!acl)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
@ -1698,7 +1745,7 @@ struct hci_conn *hci_connect_sco(struct hci_dev *hdev, int type, bdaddr_t *dst,
|
||||
|
||||
sco = hci_conn_hash_lookup_ba(hdev, type, dst);
|
||||
if (!sco) {
|
||||
sco = hci_conn_add(hdev, type, dst, HCI_ROLE_MASTER);
|
||||
sco = hci_conn_add_unset(hdev, type, dst, HCI_ROLE_MASTER);
|
||||
if (!sco) {
|
||||
hci_conn_drop(acl);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
@ -1890,7 +1937,7 @@ struct hci_conn *hci_bind_cis(struct hci_dev *hdev, bdaddr_t *dst,
|
||||
cis = hci_conn_hash_lookup_cis(hdev, dst, dst_type, qos->ucast.cig,
|
||||
qos->ucast.cis);
|
||||
if (!cis) {
|
||||
cis = hci_conn_add(hdev, ISO_LINK, dst, HCI_ROLE_MASTER);
|
||||
cis = hci_conn_add_unset(hdev, ISO_LINK, dst, HCI_ROLE_MASTER);
|
||||
if (!cis)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
cis->cleanup = cis_cleanup;
|
||||
@ -2139,7 +2186,7 @@ int hci_le_big_create_sync(struct hci_dev *hdev, struct hci_conn *hcon,
|
||||
} pdu;
|
||||
int err;
|
||||
|
||||
if (num_bis > sizeof(pdu.bis))
|
||||
if (num_bis < 0x01 || num_bis > sizeof(pdu.bis))
|
||||
return -EINVAL;
|
||||
|
||||
err = qos_set_big(hdev, qos);
|
||||
|
@ -2535,6 +2535,8 @@ struct hci_dev *hci_alloc_dev_priv(int sizeof_priv)
|
||||
mutex_init(&hdev->lock);
|
||||
mutex_init(&hdev->req_lock);
|
||||
|
||||
ida_init(&hdev->unset_handle_ida);
|
||||
|
||||
INIT_LIST_HEAD(&hdev->mesh_pending);
|
||||
INIT_LIST_HEAD(&hdev->mgmt_pending);
|
||||
INIT_LIST_HEAD(&hdev->reject_list);
|
||||
@ -2789,6 +2791,7 @@ void hci_release_dev(struct hci_dev *hdev)
|
||||
hci_codec_list_clear(&hdev->local_codecs);
|
||||
hci_dev_unlock(hdev);
|
||||
|
||||
ida_destroy(&hdev->unset_handle_ida);
|
||||
ida_simple_remove(&hci_index_ida, hdev->id);
|
||||
kfree_skb(hdev->sent_cmd);
|
||||
kfree_skb(hdev->recv_event);
|
||||
|
@ -2335,8 +2335,8 @@ static void hci_cs_create_conn(struct hci_dev *hdev, __u8 status)
|
||||
}
|
||||
} else {
|
||||
if (!conn) {
|
||||
conn = hci_conn_add(hdev, ACL_LINK, &cp->bdaddr,
|
||||
HCI_ROLE_MASTER);
|
||||
conn = hci_conn_add_unset(hdev, ACL_LINK, &cp->bdaddr,
|
||||
HCI_ROLE_MASTER);
|
||||
if (!conn)
|
||||
bt_dev_err(hdev, "no memory for new connection");
|
||||
}
|
||||
@ -3151,8 +3151,8 @@ static void hci_conn_complete_evt(struct hci_dev *hdev, void *data,
|
||||
hci_bdaddr_list_lookup_with_flags(&hdev->accept_list,
|
||||
&ev->bdaddr,
|
||||
BDADDR_BREDR)) {
|
||||
conn = hci_conn_add(hdev, ev->link_type, &ev->bdaddr,
|
||||
HCI_ROLE_SLAVE);
|
||||
conn = hci_conn_add_unset(hdev, ev->link_type,
|
||||
&ev->bdaddr, HCI_ROLE_SLAVE);
|
||||
if (!conn) {
|
||||
bt_dev_err(hdev, "no memory for new conn");
|
||||
goto unlock;
|
||||
@ -3317,8 +3317,8 @@ static void hci_conn_request_evt(struct hci_dev *hdev, void *data,
|
||||
conn = hci_conn_hash_lookup_ba(hdev, ev->link_type,
|
||||
&ev->bdaddr);
|
||||
if (!conn) {
|
||||
conn = hci_conn_add(hdev, ev->link_type, &ev->bdaddr,
|
||||
HCI_ROLE_SLAVE);
|
||||
conn = hci_conn_add_unset(hdev, ev->link_type, &ev->bdaddr,
|
||||
HCI_ROLE_SLAVE);
|
||||
if (!conn) {
|
||||
bt_dev_err(hdev, "no memory for new connection");
|
||||
goto unlock;
|
||||
@ -5890,7 +5890,7 @@ static void le_conn_complete_evt(struct hci_dev *hdev, u8 status,
|
||||
if (status)
|
||||
goto unlock;
|
||||
|
||||
conn = hci_conn_add(hdev, LE_LINK, bdaddr, role);
|
||||
conn = hci_conn_add_unset(hdev, LE_LINK, bdaddr, role);
|
||||
if (!conn) {
|
||||
bt_dev_err(hdev, "no memory for new connection");
|
||||
goto unlock;
|
||||
@ -5952,17 +5952,11 @@ static void le_conn_complete_evt(struct hci_dev *hdev, u8 status,
|
||||
|
||||
conn->dst_type = ev_bdaddr_type(hdev, conn->dst_type, NULL);
|
||||
|
||||
if (handle > HCI_CONN_HANDLE_MAX) {
|
||||
bt_dev_err(hdev, "Invalid handle: 0x%4.4x > 0x%4.4x", handle,
|
||||
HCI_CONN_HANDLE_MAX);
|
||||
status = HCI_ERROR_INVALID_PARAMETERS;
|
||||
}
|
||||
|
||||
/* All connection failure handling is taken care of by the
|
||||
* hci_conn_failed function which is triggered by the HCI
|
||||
* request completion callbacks used for connecting.
|
||||
*/
|
||||
if (status)
|
||||
if (status || hci_conn_set_handle(conn, handle))
|
||||
goto unlock;
|
||||
|
||||
/* Drop the connection if it has been aborted */
|
||||
@ -5986,7 +5980,6 @@ static void le_conn_complete_evt(struct hci_dev *hdev, u8 status,
|
||||
mgmt_device_connected(hdev, conn, NULL, 0);
|
||||
|
||||
conn->sec_level = BT_SECURITY_LOW;
|
||||
conn->handle = handle;
|
||||
conn->state = BT_CONFIG;
|
||||
|
||||
/* Store current advertising instance as connection advertising instance
|
||||
@ -6603,7 +6596,7 @@ static void hci_le_pa_sync_estabilished_evt(struct hci_dev *hdev, void *data,
|
||||
struct hci_ev_le_pa_sync_established *ev = data;
|
||||
int mask = hdev->link_mode;
|
||||
__u8 flags = 0;
|
||||
struct hci_conn *bis;
|
||||
struct hci_conn *pa_sync;
|
||||
|
||||
bt_dev_dbg(hdev, "status 0x%2.2x", ev->status);
|
||||
|
||||
@ -6620,20 +6613,19 @@ static void hci_le_pa_sync_estabilished_evt(struct hci_dev *hdev, void *data,
|
||||
if (!(flags & HCI_PROTO_DEFER))
|
||||
goto unlock;
|
||||
|
||||
/* Add connection to indicate the PA sync event */
|
||||
bis = hci_conn_add(hdev, ISO_LINK, BDADDR_ANY,
|
||||
HCI_ROLE_SLAVE);
|
||||
if (ev->status) {
|
||||
/* Add connection to indicate the failed PA sync event */
|
||||
pa_sync = hci_conn_add_unset(hdev, ISO_LINK, BDADDR_ANY,
|
||||
HCI_ROLE_SLAVE);
|
||||
|
||||
if (!bis)
|
||||
goto unlock;
|
||||
if (!pa_sync)
|
||||
goto unlock;
|
||||
|
||||
if (ev->status)
|
||||
set_bit(HCI_CONN_PA_SYNC_FAILED, &bis->flags);
|
||||
else
|
||||
set_bit(HCI_CONN_PA_SYNC, &bis->flags);
|
||||
set_bit(HCI_CONN_PA_SYNC_FAILED, &pa_sync->flags);
|
||||
|
||||
/* Notify connection to iso layer */
|
||||
hci_connect_cfm(bis, ev->status);
|
||||
/* Notify iso layer */
|
||||
hci_connect_cfm(pa_sync, ev->status);
|
||||
}
|
||||
|
||||
unlock:
|
||||
hci_dev_unlock(hdev);
|
||||
@ -7020,12 +7012,12 @@ static void hci_le_cis_req_evt(struct hci_dev *hdev, void *data,
|
||||
|
||||
cis = hci_conn_hash_lookup_handle(hdev, cis_handle);
|
||||
if (!cis) {
|
||||
cis = hci_conn_add(hdev, ISO_LINK, &acl->dst, HCI_ROLE_SLAVE);
|
||||
cis = hci_conn_add(hdev, ISO_LINK, &acl->dst, HCI_ROLE_SLAVE,
|
||||
cis_handle);
|
||||
if (!cis) {
|
||||
hci_le_reject_cis(hdev, ev->cis_handle);
|
||||
goto unlock;
|
||||
}
|
||||
cis->handle = cis_handle;
|
||||
}
|
||||
|
||||
cis->iso_qos.ucast.cig = ev->cig_id;
|
||||
@ -7113,7 +7105,6 @@ static void hci_le_big_sync_established_evt(struct hci_dev *hdev, void *data,
|
||||
{
|
||||
struct hci_evt_le_big_sync_estabilished *ev = data;
|
||||
struct hci_conn *bis;
|
||||
struct hci_conn *pa_sync;
|
||||
int i;
|
||||
|
||||
bt_dev_dbg(hdev, "status 0x%2.2x", ev->status);
|
||||
@ -7124,15 +7115,6 @@ static void hci_le_big_sync_established_evt(struct hci_dev *hdev, void *data,
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
|
||||
if (!ev->status) {
|
||||
pa_sync = hci_conn_hash_lookup_pa_sync(hdev, ev->handle);
|
||||
if (pa_sync)
|
||||
/* Also mark the BIG sync established event on the
|
||||
* associated PA sync hcon
|
||||
*/
|
||||
set_bit(HCI_CONN_BIG_SYNC, &pa_sync->flags);
|
||||
}
|
||||
|
||||
for (i = 0; i < ev->num_bis; i++) {
|
||||
u16 handle = le16_to_cpu(ev->bis[i]);
|
||||
__le32 interval;
|
||||
@ -7140,10 +7122,9 @@ static void hci_le_big_sync_established_evt(struct hci_dev *hdev, void *data,
|
||||
bis = hci_conn_hash_lookup_handle(hdev, handle);
|
||||
if (!bis) {
|
||||
bis = hci_conn_add(hdev, ISO_LINK, BDADDR_ANY,
|
||||
HCI_ROLE_SLAVE);
|
||||
HCI_ROLE_SLAVE, handle);
|
||||
if (!bis)
|
||||
continue;
|
||||
bis->handle = handle;
|
||||
}
|
||||
|
||||
if (ev->status != 0x42)
|
||||
@ -7186,15 +7167,42 @@ static void hci_le_big_info_adv_report_evt(struct hci_dev *hdev, void *data,
|
||||
struct hci_evt_le_big_info_adv_report *ev = data;
|
||||
int mask = hdev->link_mode;
|
||||
__u8 flags = 0;
|
||||
struct hci_conn *pa_sync;
|
||||
|
||||
bt_dev_dbg(hdev, "sync_handle 0x%4.4x", le16_to_cpu(ev->sync_handle));
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
|
||||
mask |= hci_proto_connect_ind(hdev, BDADDR_ANY, ISO_LINK, &flags);
|
||||
if (!(mask & HCI_LM_ACCEPT))
|
||||
if (!(mask & HCI_LM_ACCEPT)) {
|
||||
hci_le_pa_term_sync(hdev, ev->sync_handle);
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
if (!(flags & HCI_PROTO_DEFER))
|
||||
goto unlock;
|
||||
|
||||
pa_sync = hci_conn_hash_lookup_pa_sync_handle
|
||||
(hdev,
|
||||
le16_to_cpu(ev->sync_handle));
|
||||
|
||||
if (pa_sync)
|
||||
goto unlock;
|
||||
|
||||
/* Add connection to indicate the PA sync event */
|
||||
pa_sync = hci_conn_add_unset(hdev, ISO_LINK, BDADDR_ANY,
|
||||
HCI_ROLE_SLAVE);
|
||||
|
||||
if (!pa_sync)
|
||||
goto unlock;
|
||||
|
||||
pa_sync->sync_handle = le16_to_cpu(ev->sync_handle);
|
||||
set_bit(HCI_CONN_PA_SYNC, &pa_sync->flags);
|
||||
|
||||
/* Notify iso layer */
|
||||
hci_connect_cfm(pa_sync, 0x00);
|
||||
|
||||
unlock:
|
||||
hci_dev_unlock(hdev);
|
||||
}
|
||||
|
||||
|
@ -152,7 +152,7 @@ struct sk_buff *__hci_cmd_sync_sk(struct hci_dev *hdev, u16 opcode, u32 plen,
|
||||
struct sk_buff *skb;
|
||||
int err = 0;
|
||||
|
||||
bt_dev_dbg(hdev, "Opcode 0x%4x", opcode);
|
||||
bt_dev_dbg(hdev, "Opcode 0x%4.4x", opcode);
|
||||
|
||||
hci_req_init(&req, hdev);
|
||||
|
||||
@ -248,7 +248,7 @@ int __hci_cmd_sync_status_sk(struct hci_dev *hdev, u16 opcode, u32 plen,
|
||||
skb = __hci_cmd_sync_sk(hdev, opcode, plen, param, event, timeout, sk);
|
||||
if (IS_ERR(skb)) {
|
||||
if (!event)
|
||||
bt_dev_err(hdev, "Opcode 0x%4x failed: %ld", opcode,
|
||||
bt_dev_err(hdev, "Opcode 0x%4.4x failed: %ld", opcode,
|
||||
PTR_ERR(skb));
|
||||
return PTR_ERR(skb);
|
||||
}
|
||||
@ -1312,7 +1312,7 @@ int hci_start_ext_adv_sync(struct hci_dev *hdev, u8 instance)
|
||||
return hci_enable_ext_advertising_sync(hdev, instance);
|
||||
}
|
||||
|
||||
static int hci_disable_per_advertising_sync(struct hci_dev *hdev, u8 instance)
|
||||
int hci_disable_per_advertising_sync(struct hci_dev *hdev, u8 instance)
|
||||
{
|
||||
struct hci_cp_le_set_per_adv_enable cp;
|
||||
struct adv_info *adv = NULL;
|
||||
@ -4264,12 +4264,12 @@ static int hci_le_set_host_feature_sync(struct hci_dev *hdev)
|
||||
{
|
||||
struct hci_cp_le_set_host_feature cp;
|
||||
|
||||
if (!iso_capable(hdev))
|
||||
if (!cis_capable(hdev))
|
||||
return 0;
|
||||
|
||||
memset(&cp, 0, sizeof(cp));
|
||||
|
||||
/* Isochronous Channels (Host Support) */
|
||||
/* Connected Isochronous Channels (Host Support) */
|
||||
cp.bit_number = 32;
|
||||
cp.bit_value = 1;
|
||||
|
||||
@ -5232,6 +5232,17 @@ static int hci_disconnect_sync(struct hci_dev *hdev, struct hci_conn *conn,
|
||||
if (conn->type == AMP_LINK)
|
||||
return hci_disconnect_phy_link_sync(hdev, conn->handle, reason);
|
||||
|
||||
if (test_bit(HCI_CONN_BIG_CREATED, &conn->flags)) {
|
||||
/* This is a BIS connection, hci_conn_del will
|
||||
* do the necessary cleanup.
|
||||
*/
|
||||
hci_dev_lock(hdev);
|
||||
hci_conn_failed(conn, reason);
|
||||
hci_dev_unlock(hdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
memset(&cp, 0, sizeof(cp));
|
||||
cp.handle = cpu_to_le16(conn->handle);
|
||||
cp.reason = reason;
|
||||
@ -5384,21 +5395,6 @@ int hci_abort_conn_sync(struct hci_dev *hdev, struct hci_conn *conn, u8 reason)
|
||||
err = hci_reject_conn_sync(hdev, conn, reason);
|
||||
break;
|
||||
case BT_OPEN:
|
||||
hci_dev_lock(hdev);
|
||||
|
||||
/* Cleanup bis or pa sync connections */
|
||||
if (test_and_clear_bit(HCI_CONN_BIG_SYNC_FAILED, &conn->flags) ||
|
||||
test_and_clear_bit(HCI_CONN_PA_SYNC_FAILED, &conn->flags)) {
|
||||
hci_conn_failed(conn, reason);
|
||||
} else if (test_bit(HCI_CONN_PA_SYNC, &conn->flags) ||
|
||||
test_bit(HCI_CONN_BIG_SYNC, &conn->flags)) {
|
||||
conn->state = BT_CLOSED;
|
||||
hci_disconn_cfm(conn, reason);
|
||||
hci_conn_del(conn);
|
||||
}
|
||||
|
||||
hci_dev_unlock(hdev);
|
||||
return 0;
|
||||
case BT_BOUND:
|
||||
break;
|
||||
default:
|
||||
|
@ -35,7 +35,7 @@ void hci_conn_init_sysfs(struct hci_conn *conn)
|
||||
{
|
||||
struct hci_dev *hdev = conn->hdev;
|
||||
|
||||
BT_DBG("conn %p", conn);
|
||||
bt_dev_dbg(hdev, "conn %p", conn);
|
||||
|
||||
conn->dev.type = &bt_link;
|
||||
conn->dev.class = &bt_class;
|
||||
@ -48,27 +48,30 @@ void hci_conn_add_sysfs(struct hci_conn *conn)
|
||||
{
|
||||
struct hci_dev *hdev = conn->hdev;
|
||||
|
||||
BT_DBG("conn %p", conn);
|
||||
bt_dev_dbg(hdev, "conn %p", conn);
|
||||
|
||||
if (device_is_registered(&conn->dev))
|
||||
return;
|
||||
|
||||
dev_set_name(&conn->dev, "%s:%d", hdev->name, conn->handle);
|
||||
|
||||
if (device_add(&conn->dev) < 0) {
|
||||
if (device_add(&conn->dev) < 0)
|
||||
bt_dev_err(hdev, "failed to register connection device");
|
||||
return;
|
||||
}
|
||||
|
||||
hci_dev_hold(hdev);
|
||||
}
|
||||
|
||||
void hci_conn_del_sysfs(struct hci_conn *conn)
|
||||
{
|
||||
struct hci_dev *hdev = conn->hdev;
|
||||
|
||||
if (!device_is_registered(&conn->dev))
|
||||
bt_dev_dbg(hdev, "conn %p", conn);
|
||||
|
||||
if (!device_is_registered(&conn->dev)) {
|
||||
/* If device_add() has *not* succeeded, use *only* put_device()
|
||||
* to drop the reference count.
|
||||
*/
|
||||
put_device(&conn->dev);
|
||||
return;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
struct device *dev;
|
||||
@ -80,9 +83,7 @@ void hci_conn_del_sysfs(struct hci_conn *conn)
|
||||
put_device(dev);
|
||||
}
|
||||
|
||||
device_del(&conn->dev);
|
||||
|
||||
hci_dev_put(hdev);
|
||||
device_unregister(&conn->dev);
|
||||
}
|
||||
|
||||
static void bt_host_release(struct device *dev)
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include <net/bluetooth/bluetooth.h>
|
||||
#include <net/bluetooth/hci_core.h>
|
||||
#include <net/bluetooth/iso.h>
|
||||
#include "eir.h"
|
||||
|
||||
static const struct proto_ops iso_sock_ops;
|
||||
|
||||
@ -47,6 +48,7 @@ static void iso_sock_kill(struct sock *sk);
|
||||
|
||||
#define EIR_SERVICE_DATA_LENGTH 4
|
||||
#define BASE_MAX_LENGTH (HCI_MAX_PER_AD_LENGTH - EIR_SERVICE_DATA_LENGTH)
|
||||
#define EIR_BAA_SERVICE_UUID 0x1851
|
||||
|
||||
/* iso_pinfo flags values */
|
||||
enum {
|
||||
@ -77,6 +79,7 @@ static struct bt_iso_qos default_qos;
|
||||
static bool check_ucast_qos(struct bt_iso_qos *qos);
|
||||
static bool check_bcast_qos(struct bt_iso_qos *qos);
|
||||
static bool iso_match_sid(struct sock *sk, void *data);
|
||||
static bool iso_match_sync_handle(struct sock *sk, void *data);
|
||||
static void iso_sock_disconn(struct sock *sk);
|
||||
|
||||
/* ---- ISO timers ---- */
|
||||
@ -789,8 +792,7 @@ static int iso_sock_bind_bc(struct socket *sock, struct sockaddr *addr,
|
||||
BT_DBG("sk %p bc_sid %u bc_num_bis %u", sk, sa->iso_bc->bc_sid,
|
||||
sa->iso_bc->bc_num_bis);
|
||||
|
||||
if (addr_len > sizeof(*sa) + sizeof(*sa->iso_bc) ||
|
||||
sa->iso_bc->bc_num_bis < 0x01 || sa->iso_bc->bc_num_bis > 0x1f)
|
||||
if (addr_len > sizeof(*sa) + sizeof(*sa->iso_bc))
|
||||
return -EINVAL;
|
||||
|
||||
bacpy(&iso_pi(sk)->dst, &sa->iso_bc->bc_bdaddr);
|
||||
@ -1202,7 +1204,6 @@ static int iso_sock_recvmsg(struct socket *sock, struct msghdr *msg,
|
||||
test_bit(HCI_CONN_PA_SYNC, &pi->conn->hcon->flags)) {
|
||||
iso_conn_big_sync(sk);
|
||||
sk->sk_state = BT_LISTEN;
|
||||
set_bit(BT_SK_PA_SYNC, &iso_pi(sk)->flags);
|
||||
} else {
|
||||
iso_conn_defer_accept(pi->conn->hcon);
|
||||
sk->sk_state = BT_CONFIG;
|
||||
@ -1461,6 +1462,8 @@ static int iso_sock_getsockopt(struct socket *sock, int level, int optname,
|
||||
len = min_t(unsigned int, len, base_len);
|
||||
if (copy_to_user(optval, base, len))
|
||||
err = -EFAULT;
|
||||
if (put_user(len, optlen))
|
||||
err = -EFAULT;
|
||||
|
||||
break;
|
||||
|
||||
@ -1579,6 +1582,7 @@ static void iso_conn_ready(struct iso_conn *conn)
|
||||
struct sock *sk = conn->sk;
|
||||
struct hci_ev_le_big_sync_estabilished *ev = NULL;
|
||||
struct hci_ev_le_pa_sync_established *ev2 = NULL;
|
||||
struct hci_evt_le_big_info_adv_report *ev3 = NULL;
|
||||
struct hci_conn *hcon;
|
||||
|
||||
BT_DBG("conn %p", conn);
|
||||
@ -1603,14 +1607,20 @@ static void iso_conn_ready(struct iso_conn *conn)
|
||||
parent = iso_get_sock_listen(&hcon->src,
|
||||
&hcon->dst,
|
||||
iso_match_big, ev);
|
||||
} else if (test_bit(HCI_CONN_PA_SYNC, &hcon->flags) ||
|
||||
test_bit(HCI_CONN_PA_SYNC_FAILED, &hcon->flags)) {
|
||||
} else if (test_bit(HCI_CONN_PA_SYNC_FAILED, &hcon->flags)) {
|
||||
ev2 = hci_recv_event_data(hcon->hdev,
|
||||
HCI_EV_LE_PA_SYNC_ESTABLISHED);
|
||||
if (ev2)
|
||||
parent = iso_get_sock_listen(&hcon->src,
|
||||
&hcon->dst,
|
||||
iso_match_sid, ev2);
|
||||
} else if (test_bit(HCI_CONN_PA_SYNC, &hcon->flags)) {
|
||||
ev3 = hci_recv_event_data(hcon->hdev,
|
||||
HCI_EVT_LE_BIG_INFO_ADV_REPORT);
|
||||
if (ev3)
|
||||
parent = iso_get_sock_listen(&hcon->src,
|
||||
&hcon->dst,
|
||||
iso_match_sync_handle, ev3);
|
||||
}
|
||||
|
||||
if (!parent)
|
||||
@ -1650,11 +1660,13 @@ static void iso_conn_ready(struct iso_conn *conn)
|
||||
hcon->sync_handle = iso_pi(parent)->sync_handle;
|
||||
}
|
||||
|
||||
if (ev2 && !ev2->status) {
|
||||
iso_pi(sk)->sync_handle = iso_pi(parent)->sync_handle;
|
||||
if (ev3) {
|
||||
iso_pi(sk)->qos = iso_pi(parent)->qos;
|
||||
iso_pi(sk)->qos.bcast.encryption = ev3->encryption;
|
||||
hcon->iso_qos = iso_pi(sk)->qos;
|
||||
iso_pi(sk)->bc_num_bis = iso_pi(parent)->bc_num_bis;
|
||||
memcpy(iso_pi(sk)->bc_bis, iso_pi(parent)->bc_bis, ISO_MAX_NUM_BIS);
|
||||
set_bit(BT_SK_PA_SYNC, &iso_pi(sk)->flags);
|
||||
}
|
||||
|
||||
bacpy(&iso_pi(sk)->dst, &hcon->dst);
|
||||
@ -1774,12 +1786,16 @@ int iso_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 *flags)
|
||||
|
||||
ev3 = hci_recv_event_data(hdev, HCI_EV_LE_PER_ADV_REPORT);
|
||||
if (ev3) {
|
||||
size_t base_len = ev3->length;
|
||||
u8 *base;
|
||||
|
||||
sk = iso_get_sock_listen(&hdev->bdaddr, bdaddr,
|
||||
iso_match_sync_handle_pa_report, ev3);
|
||||
|
||||
if (sk) {
|
||||
memcpy(iso_pi(sk)->base, ev3->data, ev3->length);
|
||||
iso_pi(sk)->base_len = ev3->length;
|
||||
base = eir_get_service_data(ev3->data, ev3->length,
|
||||
EIR_BAA_SERVICE_UUID, &base_len);
|
||||
if (base && sk && base_len <= sizeof(iso_pi(sk)->base)) {
|
||||
memcpy(iso_pi(sk)->base, base, base_len);
|
||||
iso_pi(sk)->base_len = base_len;
|
||||
}
|
||||
} else {
|
||||
sk = iso_get_sock_listen(&hdev->bdaddr, BDADDR_ANY, NULL, NULL);
|
||||
|
@ -150,10 +150,7 @@ static bool read_supported_features(struct hci_dev *hdev,
|
||||
|
||||
skb = __hci_cmd_sync(hdev, hdev->msft_opcode, sizeof(cp), &cp,
|
||||
HCI_CMD_TIMEOUT);
|
||||
if (IS_ERR_OR_NULL(skb)) {
|
||||
if (!skb)
|
||||
skb = ERR_PTR(-EIO);
|
||||
|
||||
if (IS_ERR(skb)) {
|
||||
bt_dev_err(hdev, "Failed to read MSFT supported features (%ld)",
|
||||
PTR_ERR(skb));
|
||||
return false;
|
||||
@ -353,7 +350,7 @@ static void msft_remove_addr_filters_sync(struct hci_dev *hdev, u8 handle)
|
||||
|
||||
skb = __hci_cmd_sync(hdev, hdev->msft_opcode, sizeof(cp), &cp,
|
||||
HCI_CMD_TIMEOUT);
|
||||
if (IS_ERR_OR_NULL(skb)) {
|
||||
if (IS_ERR(skb)) {
|
||||
kfree(address_filter);
|
||||
continue;
|
||||
}
|
||||
@ -442,11 +439,8 @@ static int msft_remove_monitor_sync(struct hci_dev *hdev,
|
||||
|
||||
skb = __hci_cmd_sync(hdev, hdev->msft_opcode, sizeof(cp), &cp,
|
||||
HCI_CMD_TIMEOUT);
|
||||
if (IS_ERR_OR_NULL(skb)) {
|
||||
if (!skb)
|
||||
return -EIO;
|
||||
if (IS_ERR(skb))
|
||||
return PTR_ERR(skb);
|
||||
}
|
||||
|
||||
return msft_le_cancel_monitor_advertisement_cb(hdev, hdev->msft_opcode,
|
||||
monitor, skb);
|
||||
@ -559,7 +553,7 @@ static int msft_add_monitor_sync(struct hci_dev *hdev,
|
||||
skb = __hci_cmd_sync(hdev, hdev->msft_opcode, total_size, cp,
|
||||
HCI_CMD_TIMEOUT);
|
||||
|
||||
if (IS_ERR_OR_NULL(skb)) {
|
||||
if (IS_ERR(skb)) {
|
||||
err = PTR_ERR(skb);
|
||||
goto out_free;
|
||||
}
|
||||
@ -740,10 +734,10 @@ static int msft_cancel_address_filter_sync(struct hci_dev *hdev, void *data)
|
||||
|
||||
skb = __hci_cmd_sync(hdev, hdev->msft_opcode, sizeof(cp), &cp,
|
||||
HCI_CMD_TIMEOUT);
|
||||
if (IS_ERR_OR_NULL(skb)) {
|
||||
if (IS_ERR(skb)) {
|
||||
bt_dev_err(hdev, "MSFT: Failed to cancel address (%pMR) filter",
|
||||
&address_filter->bdaddr);
|
||||
err = -EIO;
|
||||
err = PTR_ERR(skb);
|
||||
goto done;
|
||||
}
|
||||
kfree_skb(skb);
|
||||
@ -893,7 +887,7 @@ static int msft_add_address_filter_sync(struct hci_dev *hdev, void *data)
|
||||
|
||||
skb = __hci_cmd_sync(hdev, hdev->msft_opcode, size, cp,
|
||||
HCI_CMD_TIMEOUT);
|
||||
if (IS_ERR_OR_NULL(skb)) {
|
||||
if (IS_ERR(skb)) {
|
||||
bt_dev_err(hdev, "Failed to enable address %pMR filter",
|
||||
&address_filter->bdaddr);
|
||||
skb = NULL;
|
||||
|
Loading…
x
Reference in New Issue
Block a user