bluetooth-next pull request for net-next:

- hci_conn: Only do ACL connections sequentially
  - hci_core: Cancel request on command timeout
  - Remove CONFIG_BT_HS
  - btrtl: Add the support for RTL8852BT/RTL8852BE-VT
  - btusb: Add support Mediatek MT7920
  - btusb: Add new VID/PID 13d3/3602 for MT7925
  - Add new quirk for broken read key length on ATS2851
 -----BEGIN PGP SIGNATURE-----
 
 iQJNBAABCAA3FiEE7E6oRXp8w05ovYr/9JCA4xAyCykFAmXrU9AZHGx1aXoudm9u
 LmRlbnR6QGludGVsLmNvbQAKCRD0kIDjEDILKV4KD/9Ik0EwI4utskMShX9qxnqi
 8i5LBocslSFWN3gqrNUAJTxwlSgYntRK4L4v+566/Y/DISUV7OLx9hRJ8QpzWhWl
 mKweR3kB2HG8/Su6E2VbzjQTriSBuwPiMIeGwP9H5d+bN+6sNLmcl+II9QjapMYQ
 f13ZA/zQzwDlk8A5jTw1N/cOknblvlNNYUwIPlGzJK9COtQqAVSBRz00ugXmR1LG
 +UZqzOgXSNFQ2m4PCsozy4fCAVk/NaXBsdnKrsQurND30MJw1jKd9lRaIkQ+eLNv
 phYfsYLeDDtjMei4j0t23CKOSceMdvFWLtDn3wpBmZbXs8Avd13FRYxf/U88D09g
 FTNhOLbVyZbWSAEqIMuWZv/EuzZvIpOZRSlCn2hJgJTRuqIi6I9mRDF0ZD4LGUzR
 /Es/Ozfxw9CfHFRFsiM46cGgQ01Ddq4SihZnlTQfdkBPjQcAhiJ3GbIUAZs+HHVB
 QFoFLAJWepInGfmyyFHngEzdh9r5zFsA/+PL6duQ1+HqJFZbhPWtgYXijrjuimZo
 IdcmM4KUUaRWwdDivDq9X5s9luQ1BobNxvVIPlpz61QDu2uMlrilXAgNoZJtalTU
 ltQxxE9oPUv5tb8xybBYklKM9keyjTGzL3Y/LluDPgzUoY+w5gTcvEqD8ByhzEw6
 ouE5TO7r0k1h9BhHZSYHzw==
 =Jqow
 -----END PGP SIGNATURE-----

Merge tag 'for-net-next-2024-03-08' 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:

 - hci_conn: Only do ACL connections sequentially
 - hci_core: Cancel request on command timeout
 - Remove CONFIG_BT_HS
 - btrtl: Add the support for RTL8852BT/RTL8852BE-VT
 - btusb: Add support Mediatek MT7920
 - btusb: Add new VID/PID 13d3/3602 for MT7925
 - Add new quirk for broken read key length on ATS2851

* tag 'for-net-next-2024-03-08' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next: (52 commits)
  Bluetooth: hci_sync: Fix UAF in hci_acl_create_conn_sync
  Bluetooth: Fix eir name length
  Bluetooth: ISO: Align broadcast sync_timeout with connection timeout
  Bluetooth: Add new quirk for broken read key length on ATS2851
  Bluetooth: mgmt: remove NULL check in add_ext_adv_params_complete()
  Bluetooth: mgmt: remove NULL check in mgmt_set_connectable_complete()
  Bluetooth: btusb: Add support Mediatek MT7920
  Bluetooth: btmtk: Add MODULE_FIRMWARE() for MT7922
  Bluetooth: btnxpuart: Fix btnxpuart_close
  Bluetooth: ISO: Clean up returns values in iso_connect_ind()
  Bluetooth: fix use-after-free in accessing skb after sending it
  Bluetooth: af_bluetooth: Fix deadlock
  Bluetooth: bnep: Fix out-of-bound access
  Bluetooth: btusb: Fix memory leak
  Bluetooth: msft: Fix memory leak
  Bluetooth: hci_core: Fix possible buffer overflow
  Bluetooth: btrtl: fix out of bounds memory access
  Bluetooth: hci_h5: Add ability to allocate memory for private data
  Bluetooth: hci_sync: Fix overwriting request callback
  Bluetooth: hci_sync: Use QoS to determine which PHY to scan
  ...
====================

Link: https://lore.kernel.org/r/20240308181056.120547-1-luiz.dentz@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Jakub Kicinski 2024-03-08 20:37:32 -08:00
commit 2f901582f0
38 changed files with 1035 additions and 3630 deletions

View File

@ -11,6 +11,7 @@
#include <linux/firmware.h>
#include <linux/dmi.h>
#include <linux/of.h>
#include <linux/string.h>
#include <asm/unaligned.h>
#include <net/bluetooth/bluetooth.h>
@ -543,8 +544,6 @@ static const char *btbcm_get_board_name(struct device *dev)
struct device_node *root;
char *board_type;
const char *tmp;
int len;
int i;
root = of_find_node_by_path("/");
if (!root)
@ -554,13 +553,8 @@ static const char *btbcm_get_board_name(struct device *dev)
return NULL;
/* get rid of any '/' in the compatible string */
len = strlen(tmp) + 1;
board_type = devm_kzalloc(dev, len, GFP_KERNEL);
strscpy(board_type, tmp, len);
for (i = 0; i < len; i++) {
if (board_type[i] == '/')
board_type[i] = '-';
}
board_type = devm_kstrdup(dev, tmp, GFP_KERNEL);
strreplace(board_type, '/', '-');
of_node_put(root);
return board_type;

View File

@ -441,7 +441,7 @@ int btintel_read_version(struct hci_dev *hdev, struct intel_version *ver)
return PTR_ERR(skb);
}
if (skb->len != sizeof(*ver)) {
if (!skb || skb->len != sizeof(*ver)) {
bt_dev_err(hdev, "Intel version event size mismatch");
kfree_skb(skb);
return -EILSEQ;
@ -2670,6 +2670,119 @@ static void btintel_set_msft_opcode(struct hci_dev *hdev, u8 hw_variant)
}
}
static void btintel_print_fseq_info(struct hci_dev *hdev)
{
struct sk_buff *skb;
u8 *p;
u32 val;
const char *str;
skb = __hci_cmd_sync(hdev, 0xfcb3, 0, NULL, HCI_CMD_TIMEOUT);
if (IS_ERR(skb)) {
bt_dev_dbg(hdev, "Reading fseq status command failed (%ld)",
PTR_ERR(skb));
return;
}
if (skb->len < (sizeof(u32) * 16 + 2)) {
bt_dev_dbg(hdev, "Malformed packet of length %u received",
skb->len);
kfree_skb(skb);
return;
}
p = skb_pull_data(skb, 1);
if (*p) {
bt_dev_dbg(hdev, "Failed to get fseq status (0x%2.2x)", *p);
kfree_skb(skb);
return;
}
p = skb_pull_data(skb, 1);
switch (*p) {
case 0:
str = "Success";
break;
case 1:
str = "Fatal error";
break;
case 2:
str = "Semaphore acquire error";
break;
default:
str = "Unknown error";
break;
}
if (*p) {
bt_dev_err(hdev, "Fseq status: %s (0x%2.2x)", str, *p);
kfree_skb(skb);
return;
}
bt_dev_info(hdev, "Fseq status: %s (0x%2.2x)", str, *p);
val = get_unaligned_le32(skb_pull_data(skb, 4));
bt_dev_dbg(hdev, "Reason: 0x%8.8x", val);
val = get_unaligned_le32(skb_pull_data(skb, 4));
bt_dev_dbg(hdev, "Global version: 0x%8.8x", val);
val = get_unaligned_le32(skb_pull_data(skb, 4));
bt_dev_dbg(hdev, "Installed version: 0x%8.8x", val);
p = skb->data;
skb_pull_data(skb, 4);
bt_dev_info(hdev, "Fseq executed: %2.2u.%2.2u.%2.2u.%2.2u", p[0], p[1],
p[2], p[3]);
p = skb->data;
skb_pull_data(skb, 4);
bt_dev_info(hdev, "Fseq BT Top: %2.2u.%2.2u.%2.2u.%2.2u", p[0], p[1],
p[2], p[3]);
val = get_unaligned_le32(skb_pull_data(skb, 4));
bt_dev_dbg(hdev, "Fseq Top init version: 0x%8.8x", val);
val = get_unaligned_le32(skb_pull_data(skb, 4));
bt_dev_dbg(hdev, "Fseq Cnvio init version: 0x%8.8x", val);
val = get_unaligned_le32(skb_pull_data(skb, 4));
bt_dev_dbg(hdev, "Fseq MBX Wifi file version: 0x%8.8x", val);
val = get_unaligned_le32(skb_pull_data(skb, 4));
bt_dev_dbg(hdev, "Fseq BT version: 0x%8.8x", val);
val = get_unaligned_le32(skb_pull_data(skb, 4));
bt_dev_dbg(hdev, "Fseq Top reset address: 0x%8.8x", val);
val = get_unaligned_le32(skb_pull_data(skb, 4));
bt_dev_dbg(hdev, "Fseq MBX timeout: 0x%8.8x", val);
val = get_unaligned_le32(skb_pull_data(skb, 4));
bt_dev_dbg(hdev, "Fseq MBX ack: 0x%8.8x", val);
val = get_unaligned_le32(skb_pull_data(skb, 4));
bt_dev_dbg(hdev, "Fseq CNVi id: 0x%8.8x", val);
val = get_unaligned_le32(skb_pull_data(skb, 4));
bt_dev_dbg(hdev, "Fseq CNVr id: 0x%8.8x", val);
val = get_unaligned_le32(skb_pull_data(skb, 4));
bt_dev_dbg(hdev, "Fseq Error handle: 0x%8.8x", val);
val = get_unaligned_le32(skb_pull_data(skb, 4));
bt_dev_dbg(hdev, "Fseq Magic noalive indication: 0x%8.8x", val);
val = get_unaligned_le32(skb_pull_data(skb, 4));
bt_dev_dbg(hdev, "Fseq OTP version: 0x%8.8x", val);
val = get_unaligned_le32(skb_pull_data(skb, 4));
bt_dev_dbg(hdev, "Fseq MBX otp version: 0x%8.8x", val);
kfree_skb(skb);
}
static int btintel_setup_combined(struct hci_dev *hdev)
{
const u8 param[1] = { 0xFF };
@ -2902,6 +3015,7 @@ static int btintel_setup_combined(struct hci_dev *hdev)
err = btintel_bootloader_setup_tlv(hdev, &ver_tlv);
btintel_register_devcoredump_support(hdev);
btintel_print_fseq_info(hdev);
break;
default:
bt_dev_err(hdev, "Unsupported Intel hw variant (%u)",

View File

@ -372,8 +372,10 @@ int btmtk_process_coredump(struct hci_dev *hdev, struct sk_buff *skb)
struct btmediatek_data *data = hci_get_priv(hdev);
int err;
if (!IS_ENABLED(CONFIG_DEV_COREDUMP))
if (!IS_ENABLED(CONFIG_DEV_COREDUMP)) {
kfree_skb(skb);
return 0;
}
switch (data->cd_info.state) {
case HCI_DEVCOREDUMP_IDLE:
@ -420,5 +422,6 @@ MODULE_LICENSE("GPL");
MODULE_FIRMWARE(FIRMWARE_MT7622);
MODULE_FIRMWARE(FIRMWARE_MT7663);
MODULE_FIRMWARE(FIRMWARE_MT7668);
MODULE_FIRMWARE(FIRMWARE_MT7922);
MODULE_FIRMWARE(FIRMWARE_MT7961);
MODULE_FIRMWARE(FIRMWARE_MT7925);

View File

@ -4,6 +4,7 @@
#define FIRMWARE_MT7622 "mediatek/mt7622pr2h.bin"
#define FIRMWARE_MT7663 "mediatek/mt7663pr2h.bin"
#define FIRMWARE_MT7668 "mediatek/mt7668pr2h.bin"
#define FIRMWARE_MT7922 "mediatek/BT_RAM_CODE_MT7922_1_1_hdr.bin"
#define FIRMWARE_MT7961 "mediatek/BT_RAM_CODE_MT7961_1_2_hdr.bin"
#define FIRMWARE_MT7925 "mediatek/mt7925/BT_RAM_CODE_MT7925_1_1_hdr.bin"

View File

@ -126,6 +126,7 @@ struct ps_data {
struct hci_dev *hdev;
struct work_struct work;
struct timer_list ps_timer;
struct mutex ps_lock;
};
struct wakeup_cmd_payload {
@ -317,6 +318,9 @@ static void ps_start_timer(struct btnxpuart_dev *nxpdev)
if (psdata->cur_psmode == PS_MODE_ENABLE)
mod_timer(&psdata->ps_timer, jiffies + msecs_to_jiffies(psdata->h2c_ps_interval));
if (psdata->ps_state == PS_STATE_AWAKE && psdata->ps_cmd == PS_CMD_ENTER_PS)
cancel_work_sync(&psdata->work);
}
static void ps_cancel_timer(struct btnxpuart_dev *nxpdev)
@ -337,6 +341,7 @@ static void ps_control(struct hci_dev *hdev, u8 ps_state)
!test_bit(BTNXPUART_SERDEV_OPEN, &nxpdev->tx_state))
return;
mutex_lock(&psdata->ps_lock);
switch (psdata->cur_h2c_wakeupmode) {
case WAKEUP_METHOD_DTR:
if (ps_state == PS_STATE_AWAKE)
@ -350,12 +355,15 @@ static void ps_control(struct hci_dev *hdev, u8 ps_state)
status = serdev_device_break_ctl(nxpdev->serdev, 0);
else
status = serdev_device_break_ctl(nxpdev->serdev, -1);
msleep(20); /* Allow chip to detect UART-break and enter sleep */
bt_dev_dbg(hdev, "Set UART break: %s, status=%d",
str_on_off(ps_state == PS_STATE_SLEEP), status);
break;
}
if (!status)
psdata->ps_state = ps_state;
mutex_unlock(&psdata->ps_lock);
if (ps_state == PS_STATE_AWAKE)
btnxpuart_tx_wakeup(nxpdev);
}
@ -391,17 +399,25 @@ static void ps_setup(struct hci_dev *hdev)
psdata->hdev = hdev;
INIT_WORK(&psdata->work, ps_work_func);
mutex_init(&psdata->ps_lock);
timer_setup(&psdata->ps_timer, ps_timeout_func, 0);
}
static void ps_wakeup(struct btnxpuart_dev *nxpdev)
static bool ps_wakeup(struct btnxpuart_dev *nxpdev)
{
struct ps_data *psdata = &nxpdev->psdata;
u8 ps_state;
if (psdata->ps_state != PS_STATE_AWAKE) {
mutex_lock(&psdata->ps_lock);
ps_state = psdata->ps_state;
mutex_unlock(&psdata->ps_lock);
if (ps_state != PS_STATE_AWAKE) {
psdata->ps_cmd = PS_CMD_EXIT_PS;
schedule_work(&psdata->work);
return true;
}
return false;
}
static int send_ps_cmd(struct hci_dev *hdev, void *data)
@ -1171,7 +1187,6 @@ static struct sk_buff *nxp_dequeue(void *data)
{
struct btnxpuart_dev *nxpdev = (struct btnxpuart_dev *)data;
ps_wakeup(nxpdev);
ps_start_timer(nxpdev);
return skb_dequeue(&nxpdev->txq);
}
@ -1186,6 +1201,9 @@ static void btnxpuart_tx_work(struct work_struct *work)
struct sk_buff *skb;
int len;
if (ps_wakeup(nxpdev))
return;
while ((skb = nxp_dequeue(nxpdev))) {
len = serdev_device_write_buf(serdev, skb->data, skb->len);
hdev->stat.byte_tx += len;
@ -1234,6 +1252,9 @@ static int btnxpuart_close(struct hci_dev *hdev)
ps_wakeup(nxpdev);
serdev_device_close(nxpdev->serdev);
skb_queue_purge(&nxpdev->txq);
kfree_skb(nxpdev->rx_skb);
nxpdev->rx_skb = NULL;
clear_bit(BTNXPUART_SERDEV_OPEN, &nxpdev->tx_state);
return 0;
}

View File

@ -69,6 +69,7 @@ enum btrtl_chip_id {
CHIP_ID_8852B = 20,
CHIP_ID_8852C = 25,
CHIP_ID_8851B = 36,
CHIP_ID_8852BT = 47,
};
struct id_table {
@ -307,6 +308,15 @@ static const struct id_table ic_id_table[] = {
.fw_name = "rtl_bt/rtl8851bu_fw",
.cfg_name = "rtl_bt/rtl8851bu_config",
.hw_info = "rtl8851bu" },
/* 8852BT/8852BE-VT */
{ IC_INFO(RTL_ROM_LMP_8852A, 0x87, 0xc, HCI_USB),
.config_needed = false,
.has_rom_version = true,
.has_msft_ext = true,
.fw_name = "rtl_bt/rtl8852btu_fw",
.cfg_name = "rtl_bt/rtl8852btu_config",
.hw_info = "rtl8852btu" },
};
static const struct id_table *btrtl_match_ic(u16 lmp_subver, u16 hci_rev,
@ -645,6 +655,7 @@ static int rtlbt_parse_firmware(struct hci_dev *hdev,
{ RTL_ROM_LMP_8852A, 20 }, /* 8852B */
{ RTL_ROM_LMP_8852A, 25 }, /* 8852C */
{ RTL_ROM_LMP_8851B, 36 }, /* 8851B */
{ RTL_ROM_LMP_8852A, 47 }, /* 8852BT */
};
if (btrtl_dev->fw_len <= 8)
@ -1275,6 +1286,7 @@ void btrtl_set_quirks(struct hci_dev *hdev, struct btrtl_device_info *btrtl_dev)
case CHIP_ID_8852B:
case CHIP_ID_8852C:
case CHIP_ID_8851B:
case CHIP_ID_8852BT:
set_bit(HCI_QUIRK_VALID_LE_STATES, &hdev->quirks);
set_bit(HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED, &hdev->quirks);
@ -1505,6 +1517,8 @@ MODULE_FIRMWARE("rtl_bt/rtl8852bs_fw.bin");
MODULE_FIRMWARE("rtl_bt/rtl8852bs_config.bin");
MODULE_FIRMWARE("rtl_bt/rtl8852bu_fw.bin");
MODULE_FIRMWARE("rtl_bt/rtl8852bu_config.bin");
MODULE_FIRMWARE("rtl_bt/rtl8852btu_fw.bin");
MODULE_FIRMWARE("rtl_bt/rtl8852btu_config.bin");
MODULE_FIRMWARE("rtl_bt/rtl8852cu_fw.bin");
MODULE_FIRMWARE("rtl_bt/rtl8852cu_fw_v2.bin");
MODULE_FIRMWARE("rtl_bt/rtl8852cu_config.bin");

View File

@ -553,6 +553,9 @@ static const struct usb_device_id quirks_table[] = {
{ USB_DEVICE(0x13d3, 0x3572), .driver_info = BTUSB_REALTEK |
BTUSB_WIDEBAND_SPEECH },
/* Realtek 8852BT/8852BE-VT Bluetooth devices */
{ USB_DEVICE(0x0bda, 0x8520), .driver_info = BTUSB_REALTEK |
BTUSB_WIDEBAND_SPEECH },
/* Realtek Bluetooth devices */
{ USB_VENDOR_AND_INTERFACE_INFO(0x0bda, 0xe0, 0x01, 0x01),
.driver_info = BTUSB_REALTEK },
@ -655,6 +658,11 @@ static const struct usb_device_id quirks_table[] = {
BTUSB_WIDEBAND_SPEECH |
BTUSB_VALID_LE_STATES },
/* Additional MediaTek MT7925 Bluetooth devices */
{ USB_DEVICE(0x13d3, 0x3602), .driver_info = BTUSB_MEDIATEK |
BTUSB_WIDEBAND_SPEECH |
BTUSB_VALID_LE_STATES },
/* Additional Realtek 8723AE Bluetooth devices */
{ USB_DEVICE(0x0930, 0x021d), .driver_info = BTUSB_REALTEK },
{ USB_DEVICE(0x13d3, 0x3394), .driver_info = BTUSB_REALTEK },
@ -3080,7 +3088,7 @@ static int btusb_mtk_setup(struct hci_dev *hdev)
int err, status;
u32 dev_id = 0;
char fw_bin_name[64];
u32 fw_version = 0;
u32 fw_version = 0, fw_flavor = 0;
u8 param;
struct btmediatek_data *mediatek;
@ -3103,6 +3111,11 @@ static int btusb_mtk_setup(struct hci_dev *hdev)
bt_dev_err(hdev, "Failed to get fw version (%d)", err);
return err;
}
err = btusb_mtk_id_get(data, 0x70010020, &fw_flavor);
if (err < 0) {
bt_dev_err(hdev, "Failed to get fw flavor (%d)", err);
return err;
}
}
mediatek = hci_get_priv(hdev);
@ -3127,6 +3140,10 @@ static int btusb_mtk_setup(struct hci_dev *hdev)
snprintf(fw_bin_name, sizeof(fw_bin_name),
"mediatek/mt%04x/BT_RAM_CODE_MT%04x_1_%x_hdr.bin",
dev_id & 0xffff, dev_id & 0xffff, (fw_version & 0xff) + 1);
else if (dev_id == 0x7961 && fw_flavor)
snprintf(fw_bin_name, sizeof(fw_bin_name),
"mediatek/BT_RAM_CODE_MT%04x_1a_%x_hdr.bin",
dev_id & 0xffff, (fw_version & 0xff) + 1);
else
snprintf(fw_bin_name, sizeof(fw_bin_name),
"mediatek/BT_RAM_CODE_MT%04x_1_%x_hdr.bin",
@ -3273,7 +3290,6 @@ static int btusb_recv_acl_mtk(struct hci_dev *hdev, struct sk_buff *skb)
{
struct btusb_data *data = hci_get_drvdata(hdev);
u16 handle = le16_to_cpu(hci_acl_hdr(skb)->handle);
struct sk_buff *skb_cd;
switch (handle) {
case 0xfc6f: /* Firmware dump from device */
@ -3286,9 +3302,12 @@ static int btusb_recv_acl_mtk(struct hci_dev *hdev, struct sk_buff *skb)
* for backward compatibility, so we have to clone the packet
* extraly for the in-kernel coredump support.
*/
skb_cd = skb_clone(skb, GFP_ATOMIC);
if (skb_cd)
btmtk_process_coredump(hdev, skb_cd);
if (IS_ENABLED(CONFIG_DEV_COREDUMP)) {
struct sk_buff *skb_cd = skb_clone(skb, GFP_ATOMIC);
if (skb_cd)
btmtk_process_coredump(hdev, skb_cd);
}
fallthrough;
case 0x05ff: /* Firmware debug logging 1 */
@ -4481,6 +4500,7 @@ static int btusb_probe(struct usb_interface *intf,
set_bit(HCI_QUIRK_BROKEN_READ_TRANSMIT_POWER, &hdev->quirks);
set_bit(HCI_QUIRK_BROKEN_SET_RPA_TIMEOUT, &hdev->quirks);
set_bit(HCI_QUIRK_BROKEN_EXT_SCAN, &hdev->quirks);
set_bit(HCI_QUIRK_BROKEN_READ_ENC_KEY_SIZE, &hdev->quirks);
}
if (!reset)

View File

@ -113,6 +113,7 @@ struct h5_vnd {
int (*suspend)(struct h5 *h5);
int (*resume)(struct h5 *h5);
const struct acpi_gpio_mapping *acpi_gpio_map;
int sizeof_priv;
};
struct h5_device_data {
@ -863,7 +864,8 @@ static int h5_serdev_probe(struct serdev_device *serdev)
if (IS_ERR(h5->device_wake_gpio))
return PTR_ERR(h5->device_wake_gpio);
return hci_uart_register_device(&h5->serdev_hu, &h5p);
return hci_uart_register_device_priv(&h5->serdev_hu, &h5p,
h5->vnd->sizeof_priv);
}
static void h5_serdev_remove(struct serdev_device *serdev)
@ -1070,6 +1072,7 @@ static struct h5_vnd rtl_vnd = {
.suspend = h5_btrtl_suspend,
.resume = h5_btrtl_resume,
.acpi_gpio_map = acpi_btrtl_gpios,
.sizeof_priv = sizeof(struct btrealtek_data),
};
static const struct h5_device_data h5_data_rtl8822cs = {

View File

@ -2326,7 +2326,7 @@ static int qca_serdev_probe(struct serdev_device *serdev)
qcadev->bt_en = devm_gpiod_get_optional(&serdev->dev, "enable",
GPIOD_OUT_LOW);
if (IS_ERR_OR_NULL(qcadev->bt_en) &&
if (IS_ERR(qcadev->bt_en) &&
(data->soc_type == QCA_WCN6750 ||
data->soc_type == QCA_WCN6855)) {
dev_err(&serdev->dev, "failed to acquire BT_EN gpio\n");
@ -2335,7 +2335,7 @@ static int qca_serdev_probe(struct serdev_device *serdev)
qcadev->sw_ctrl = devm_gpiod_get_optional(&serdev->dev, "swctrl",
GPIOD_IN);
if (IS_ERR_OR_NULL(qcadev->sw_ctrl) &&
if (IS_ERR(qcadev->sw_ctrl) &&
(data->soc_type == QCA_WCN6750 ||
data->soc_type == QCA_WCN6855 ||
data->soc_type == QCA_WCN7850))
@ -2357,7 +2357,7 @@ static int qca_serdev_probe(struct serdev_device *serdev)
default:
qcadev->bt_en = devm_gpiod_get_optional(&serdev->dev, "enable",
GPIOD_OUT_LOW);
if (IS_ERR_OR_NULL(qcadev->bt_en)) {
if (IS_ERR(qcadev->bt_en)) {
dev_warn(&serdev->dev, "failed to acquire enable gpio\n");
power_ctrl_enabled = false;
}

View File

@ -300,8 +300,9 @@ static const struct serdev_device_ops hci_serdev_client_ops = {
.write_wakeup = hci_uart_write_wakeup,
};
int hci_uart_register_device(struct hci_uart *hu,
const struct hci_uart_proto *p)
int hci_uart_register_device_priv(struct hci_uart *hu,
const struct hci_uart_proto *p,
int sizeof_priv)
{
int err;
struct hci_dev *hdev;
@ -325,7 +326,7 @@ int hci_uart_register_device(struct hci_uart *hu,
set_bit(HCI_UART_PROTO_READY, &hu->flags);
/* Initialize and register HCI device */
hdev = hci_alloc_dev();
hdev = hci_alloc_dev_priv(sizeof_priv);
if (!hdev) {
BT_ERR("Can't allocate HCI device");
err = -ENOMEM;
@ -394,7 +395,7 @@ err_rwsem:
percpu_free_rwsem(&hu->proto_lock);
return err;
}
EXPORT_SYMBOL_GPL(hci_uart_register_device);
EXPORT_SYMBOL_GPL(hci_uart_register_device_priv);
void hci_uart_unregister_device(struct hci_uart *hu)
{

View File

@ -97,7 +97,17 @@ struct hci_uart {
int hci_uart_register_proto(const struct hci_uart_proto *p);
int hci_uart_unregister_proto(const struct hci_uart_proto *p);
int hci_uart_register_device(struct hci_uart *hu, const struct hci_uart_proto *p);
int hci_uart_register_device_priv(struct hci_uart *hu,
const struct hci_uart_proto *p,
int sizeof_priv);
static inline int hci_uart_register_device(struct hci_uart *hu,
const struct hci_uart_proto *p)
{
return hci_uart_register_device_priv(hu, p, 0);
}
void hci_uart_unregister_device(struct hci_uart *hu);
int hci_uart_tx_wakeup(struct hci_uart *hu);

View File

@ -164,6 +164,8 @@ struct bt_voice {
#define BT_ISO_QOS_BIG_UNSET 0xff
#define BT_ISO_QOS_BIS_UNSET 0xff
#define BT_ISO_SYNC_TIMEOUT 0x07d0 /* 20 secs */
struct bt_iso_io_qos {
__u32 interval;
__u16 latency;

View File

@ -330,6 +330,14 @@ enum {
* during the hdev->setup vendor callback.
*/
HCI_QUIRK_BROKEN_LE_CODED,
/*
* When this quirk is set, the HCI_OP_READ_ENC_KEY_SIZE command is
* skipped during an HCI_EV_ENCRYPT_CHANGE event. This is required
* for Actions Semiconductor ATS2851 based controllers, which erroneously
* claim to support it.
*/
HCI_QUIRK_BROKEN_READ_ENC_KEY_SIZE,
};
/* HCI device flags */
@ -372,6 +380,7 @@ enum {
HCI_SETUP,
HCI_CONFIG,
HCI_DEBUGFS_CREATED,
HCI_POWERING_DOWN,
HCI_AUTO_OFF,
HCI_RFKILLED,
HCI_MGMT,
@ -393,7 +402,6 @@ enum {
HCI_LIMITED_PRIVACY,
HCI_RPA_EXPIRED,
HCI_RPA_RESOLVING,
HCI_HS_ENABLED,
HCI_LE_ENABLED,
HCI_ADVERTISING,
HCI_ADVERTISING_CONNECTABLE,
@ -437,7 +445,7 @@ enum {
#define HCI_NCMD_TIMEOUT msecs_to_jiffies(4000) /* 4 seconds */
#define HCI_ACL_TX_TIMEOUT msecs_to_jiffies(45000) /* 45 seconds */
#define HCI_AUTO_OFF_TIMEOUT msecs_to_jiffies(2000) /* 2 seconds */
#define HCI_POWER_OFF_TIMEOUT msecs_to_jiffies(5000) /* 5 seconds */
#define HCI_ACL_CONN_TIMEOUT msecs_to_jiffies(20000) /* 20 seconds */
#define HCI_LE_CONN_TIMEOUT msecs_to_jiffies(20000) /* 20 seconds */
#define HCI_LE_AUTOCONN_TIMEOUT msecs_to_jiffies(4000) /* 4 seconds */
@ -653,6 +661,7 @@ enum {
#define HCI_ERROR_PIN_OR_KEY_MISSING 0x06
#define HCI_ERROR_MEMORY_EXCEEDED 0x07
#define HCI_ERROR_CONNECTION_TIMEOUT 0x08
#define HCI_ERROR_COMMAND_DISALLOWED 0x0c
#define HCI_ERROR_REJ_LIMITED_RESOURCES 0x0d
#define HCI_ERROR_REJ_BAD_ADDR 0x0f
#define HCI_ERROR_INVALID_PARAMETERS 0x12
@ -661,6 +670,7 @@ enum {
#define HCI_ERROR_REMOTE_POWER_OFF 0x15
#define HCI_ERROR_LOCAL_HOST_TERM 0x16
#define HCI_ERROR_PAIRING_NOT_ALLOWED 0x18
#define HCI_ERROR_UNSUPPORTED_REMOTE_FEATURE 0x1e
#define HCI_ERROR_INVALID_LL_PARAMS 0x1e
#define HCI_ERROR_UNSPECIFIED 0x1f
#define HCI_ERROR_ADVERTISING_TIMEOUT 0x3c
@ -2035,6 +2045,7 @@ struct hci_cp_le_set_per_adv_params {
} __packed;
#define HCI_MAX_PER_AD_LENGTH 252
#define HCI_MAX_PER_AD_TOT_LEN 1650
#define HCI_OP_LE_SET_PER_ADV_DATA 0x203f
struct hci_cp_le_set_per_adv_data {
@ -2795,6 +2806,10 @@ struct hci_ev_le_per_adv_report {
__u8 data[];
} __packed;
#define LE_PA_DATA_COMPLETE 0x00
#define LE_PA_DATA_MORE_TO_COME 0x01
#define LE_PA_DATA_TRUNCATED 0x02
#define HCI_EV_LE_EXT_ADV_SET_TERM 0x12
struct hci_evt_le_ext_adv_set_term {
__u8 status;

View File

@ -1,7 +1,7 @@
/*
BlueZ - Bluetooth protocol stack for Linux
Copyright (c) 2000-2001, 2010, Code Aurora Forum. All rights reserved.
Copyright 2023 NXP
Copyright 2023-2024 NXP
Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
@ -552,6 +552,7 @@ struct hci_dev {
__u32 req_status;
__u32 req_result;
struct sk_buff *req_skb;
struct sk_buff *req_rsp;
void *smp_data;
void *smp_bredr_data;
@ -734,8 +735,9 @@ struct hci_conn {
__u16 le_supv_timeout;
__u8 le_adv_data[HCI_MAX_EXT_AD_LENGTH];
__u8 le_adv_data_len;
__u8 le_per_adv_data[HCI_MAX_PER_AD_LENGTH];
__u8 le_per_adv_data_len;
__u8 le_per_adv_data[HCI_MAX_PER_AD_TOT_LEN];
__u16 le_per_adv_data_len;
__u16 le_per_adv_data_offset;
__u8 le_tx_phy;
__u8 le_rx_phy;
__s8 rssi;
@ -1083,6 +1085,24 @@ static inline unsigned int hci_conn_count(struct hci_dev *hdev)
return c->acl_num + c->amp_num + c->sco_num + c->le_num + c->iso_num;
}
static inline bool hci_conn_valid(struct hci_dev *hdev, struct hci_conn *conn)
{
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 == conn) {
rcu_read_unlock();
return true;
}
}
rcu_read_unlock();
return false;
}
static inline __u8 hci_conn_lookup_type(struct hci_dev *hdev, __u16 handle)
{
struct hci_conn_hash *h = &hdev->conn_hash;
@ -1480,7 +1500,6 @@ 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);
struct hci_chan *hci_chan_create(struct hci_conn *conn);
void hci_chan_del(struct hci_chan *chan);
@ -1494,11 +1513,13 @@ struct hci_conn *hci_connect_le_scan(struct hci_dev *hdev, bdaddr_t *dst,
struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst,
u8 dst_type, bool dst_resolved, u8 sec_level,
u16 conn_timeout, u8 role);
void hci_connect_le_scan_cleanup(struct hci_conn *conn, u8 status);
struct hci_conn *hci_connect_acl(struct hci_dev *hdev, bdaddr_t *dst,
u8 sec_level, u8 auth_type,
enum conn_reasons conn_reason);
enum conn_reasons conn_reason, u16 timeout);
struct hci_conn *hci_connect_sco(struct hci_dev *hdev, int type, bdaddr_t *dst,
__u16 setting, struct bt_codec *codec);
__u16 setting, struct bt_codec *codec,
u16 timeout);
struct hci_conn *hci_bind_cis(struct hci_dev *hdev, bdaddr_t *dst,
__u8 dst_type, struct bt_iso_qos *qos);
struct hci_conn *hci_bind_bis(struct hci_dev *hdev, bdaddr_t *dst,
@ -1509,8 +1530,8 @@ struct hci_conn *hci_connect_cis(struct hci_dev *hdev, bdaddr_t *dst,
struct hci_conn *hci_connect_bis(struct hci_dev *hdev, bdaddr_t *dst,
__u8 dst_type, struct bt_iso_qos *qos,
__u8 data_len, __u8 *data);
int hci_pa_create_sync(struct hci_dev *hdev, bdaddr_t *dst, __u8 dst_type,
__u8 sid, struct bt_iso_qos *qos);
struct hci_conn *hci_pa_create_sync(struct hci_dev *hdev, bdaddr_t *dst,
__u8 dst_type, __u8 sid, struct bt_iso_qos *qos);
int hci_le_big_create_sync(struct hci_dev *hdev, struct hci_conn *hcon,
struct bt_iso_qos *qos,
__u16 sync_handle, __u8 num_bis, __u8 bis[]);

View File

@ -42,12 +42,24 @@ int __hci_cmd_sync_status_sk(struct hci_dev *hdev, u16 opcode, u32 plen,
void hci_cmd_sync_init(struct hci_dev *hdev);
void hci_cmd_sync_clear(struct hci_dev *hdev);
void hci_cmd_sync_cancel(struct hci_dev *hdev, int err);
void __hci_cmd_sync_cancel(struct hci_dev *hdev, int err);
void hci_cmd_sync_cancel_sync(struct hci_dev *hdev, int err);
int hci_cmd_sync_submit(struct hci_dev *hdev, hci_cmd_sync_work_func_t func,
void *data, hci_cmd_sync_work_destroy_t destroy);
int hci_cmd_sync_queue(struct hci_dev *hdev, hci_cmd_sync_work_func_t func,
void *data, hci_cmd_sync_work_destroy_t destroy);
int hci_cmd_sync_queue_once(struct hci_dev *hdev, hci_cmd_sync_work_func_t func,
void *data, hci_cmd_sync_work_destroy_t destroy);
struct hci_cmd_sync_work_entry *
hci_cmd_sync_lookup_entry(struct hci_dev *hdev, hci_cmd_sync_work_func_t func,
void *data, hci_cmd_sync_work_destroy_t destroy);
void hci_cmd_sync_cancel_entry(struct hci_dev *hdev,
struct hci_cmd_sync_work_entry *entry);
bool hci_cmd_sync_dequeue(struct hci_dev *hdev, hci_cmd_sync_work_func_t func,
void *data, hci_cmd_sync_work_destroy_t destroy);
bool hci_cmd_sync_dequeue_once(struct hci_dev *hdev,
hci_cmd_sync_work_func_t func, void *data,
hci_cmd_sync_work_destroy_t destroy);
int hci_update_eir_sync(struct hci_dev *hdev);
int hci_update_class_sync(struct hci_dev *hdev);
@ -127,8 +139,6 @@ struct hci_conn;
int hci_abort_conn_sync(struct hci_dev *hdev, struct hci_conn *conn, u8 reason);
int hci_le_create_conn_sync(struct hci_dev *hdev, struct hci_conn *conn);
int hci_le_create_cis_sync(struct hci_dev *hdev);
int hci_le_remove_cig_sync(struct hci_dev *hdev, u8 handle);
@ -138,3 +148,9 @@ int hci_le_terminate_big_sync(struct hci_dev *hdev, u8 handle, u8 reason);
int hci_le_big_terminate_sync(struct hci_dev *hdev, u8 handle);
int hci_le_pa_terminate_sync(struct hci_dev *hdev, u16 handle);
int hci_connect_acl_sync(struct hci_dev *hdev, struct hci_conn *conn);
int hci_connect_le_sync(struct hci_dev *hdev, struct hci_conn *conn);
int hci_cancel_connect_sync(struct hci_dev *hdev, struct hci_conn *conn);

View File

@ -59,8 +59,6 @@
#define L2CAP_WAIT_ACK_POLL_PERIOD msecs_to_jiffies(200)
#define L2CAP_WAIT_ACK_TIMEOUT msecs_to_jiffies(10000)
#define L2CAP_A2MP_DEFAULT_MTU 670
/* L2CAP socket address */
struct sockaddr_l2 {
sa_family_t l2_family;
@ -109,12 +107,6 @@ struct l2cap_conninfo {
#define L2CAP_ECHO_RSP 0x09
#define L2CAP_INFO_REQ 0x0a
#define L2CAP_INFO_RSP 0x0b
#define L2CAP_CREATE_CHAN_REQ 0x0c
#define L2CAP_CREATE_CHAN_RSP 0x0d
#define L2CAP_MOVE_CHAN_REQ 0x0e
#define L2CAP_MOVE_CHAN_RSP 0x0f
#define L2CAP_MOVE_CHAN_CFM 0x10
#define L2CAP_MOVE_CHAN_CFM_RSP 0x11
#define L2CAP_CONN_PARAM_UPDATE_REQ 0x12
#define L2CAP_CONN_PARAM_UPDATE_RSP 0x13
#define L2CAP_LE_CONN_REQ 0x14
@ -144,7 +136,6 @@ struct l2cap_conninfo {
/* L2CAP fixed channels */
#define L2CAP_FC_SIG_BREDR 0x02
#define L2CAP_FC_CONNLESS 0x04
#define L2CAP_FC_A2MP 0x08
#define L2CAP_FC_ATT 0x10
#define L2CAP_FC_SIG_LE 0x20
#define L2CAP_FC_SMP_LE 0x40
@ -267,7 +258,6 @@ struct l2cap_conn_rsp {
/* channel identifier */
#define L2CAP_CID_SIGNALING 0x0001
#define L2CAP_CID_CONN_LESS 0x0002
#define L2CAP_CID_A2MP 0x0003
#define L2CAP_CID_ATT 0x0004
#define L2CAP_CID_LE_SIGNALING 0x0005
#define L2CAP_CID_SMP 0x0006
@ -282,7 +272,6 @@ struct l2cap_conn_rsp {
#define L2CAP_CR_BAD_PSM 0x0002
#define L2CAP_CR_SEC_BLOCK 0x0003
#define L2CAP_CR_NO_MEM 0x0004
#define L2CAP_CR_BAD_AMP 0x0005
#define L2CAP_CR_INVALID_SCID 0x0006
#define L2CAP_CR_SCID_IN_USE 0x0007
@ -404,29 +393,6 @@ struct l2cap_info_rsp {
__u8 data[];
} __packed;
struct l2cap_create_chan_req {
__le16 psm;
__le16 scid;
__u8 amp_id;
} __packed;
struct l2cap_create_chan_rsp {
__le16 dcid;
__le16 scid;
__le16 result;
__le16 status;
} __packed;
struct l2cap_move_chan_req {
__le16 icid;
__u8 dest_amp_id;
} __packed;
struct l2cap_move_chan_rsp {
__le16 icid;
__le16 result;
} __packed;
#define L2CAP_MR_SUCCESS 0x0000
#define L2CAP_MR_PEND 0x0001
#define L2CAP_MR_BAD_ID 0x0002
@ -539,8 +505,6 @@ struct l2cap_seq_list {
struct l2cap_chan {
struct l2cap_conn *conn;
struct hci_conn *hs_hcon;
struct hci_chan *hs_hchan;
struct kref kref;
atomic_t nesting;
@ -591,12 +555,6 @@ struct l2cap_chan {
unsigned long conn_state;
unsigned long flags;
__u8 remote_amp_id;
__u8 local_amp_id;
__u8 move_id;
__u8 move_state;
__u8 move_role;
__u16 next_tx_seq;
__u16 expected_ack_seq;
__u16 expected_tx_seq;
@ -981,7 +939,7 @@ int l2cap_add_scid(struct l2cap_chan *chan, __u16 scid);
struct l2cap_chan *l2cap_chan_create(void);
void l2cap_chan_close(struct l2cap_chan *chan, int reason);
int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid,
bdaddr_t *dst, u8 dst_type);
bdaddr_t *dst, u8 dst_type, u16 timeout);
int l2cap_chan_reconfigure(struct l2cap_chan *chan, __u16 mtu);
int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len);
void l2cap_chan_busy(struct l2cap_chan *chan, int busy);

View File

@ -572,7 +572,7 @@ static void netdev_setup(struct net_device *dev)
dev->needs_free_netdev = true;
}
static struct device_type bt_type = {
static const struct device_type bt_type = {
.name = "bluetooth",
};
@ -892,7 +892,7 @@ static int bt_6lowpan_connect(bdaddr_t *addr, u8 dst_type)
chan->ops = &bt_6lowpan_chan_ops;
err = l2cap_chan_connect(chan, cpu_to_le16(L2CAP_PSM_IPSP), 0,
addr, dst_type);
addr, dst_type, L2CAP_CONN_TIMEOUT);
BT_DBG("chan %p err %d", chan, err);
if (err < 0)

View File

@ -62,14 +62,6 @@ source "net/bluetooth/cmtp/Kconfig"
source "net/bluetooth/hidp/Kconfig"
config BT_HS
bool "Bluetooth High Speed (HS) features"
depends on BT_BREDR
help
Bluetooth High Speed includes support for off-loading
Bluetooth connections via 802.11 (wifi) physical layer
available with Bluetooth version 3.0 or later.
config BT_LE
bool "Bluetooth Low Energy (LE) features"
depends on BT

View File

@ -21,7 +21,6 @@ bluetooth-$(CONFIG_DEV_COREDUMP) += coredump.o
bluetooth-$(CONFIG_BT_BREDR) += sco.o
bluetooth-$(CONFIG_BT_LE) += iso.o
bluetooth-$(CONFIG_BT_HS) += a2mp.o amp.o
bluetooth-$(CONFIG_BT_LEDS) += leds.o
bluetooth-$(CONFIG_BT_MSFTEXT) += msft.o
bluetooth-$(CONFIG_BT_AOSPEXT) += aosp.o

File diff suppressed because it is too large Load Diff

View File

@ -1,154 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
Copyright (c) 2010,2011 Code Aurora Forum. All rights reserved.
Copyright (c) 2011,2012 Intel Corp.
*/
#ifndef __A2MP_H
#define __A2MP_H
#include <net/bluetooth/l2cap.h>
enum amp_mgr_state {
READ_LOC_AMP_INFO,
READ_LOC_AMP_ASSOC,
READ_LOC_AMP_ASSOC_FINAL,
WRITE_REMOTE_AMP_ASSOC,
};
struct amp_mgr {
struct list_head list;
struct l2cap_conn *l2cap_conn;
struct l2cap_chan *a2mp_chan;
struct l2cap_chan *bredr_chan;
struct kref kref;
__u8 ident;
__u8 handle;
unsigned long state;
unsigned long flags;
struct list_head amp_ctrls;
struct mutex amp_ctrls_lock;
};
struct a2mp_cmd {
__u8 code;
__u8 ident;
__le16 len;
__u8 data[];
} __packed;
/* A2MP command codes */
#define A2MP_COMMAND_REJ 0x01
struct a2mp_cmd_rej {
__le16 reason;
__u8 data[];
} __packed;
#define A2MP_DISCOVER_REQ 0x02
struct a2mp_discov_req {
__le16 mtu;
__le16 ext_feat;
} __packed;
struct a2mp_cl {
__u8 id;
__u8 type;
__u8 status;
} __packed;
#define A2MP_DISCOVER_RSP 0x03
struct a2mp_discov_rsp {
__le16 mtu;
__le16 ext_feat;
struct a2mp_cl cl[];
} __packed;
#define A2MP_CHANGE_NOTIFY 0x04
#define A2MP_CHANGE_RSP 0x05
#define A2MP_GETINFO_REQ 0x06
struct a2mp_info_req {
__u8 id;
} __packed;
#define A2MP_GETINFO_RSP 0x07
struct a2mp_info_rsp {
__u8 id;
__u8 status;
__le32 total_bw;
__le32 max_bw;
__le32 min_latency;
__le16 pal_cap;
__le16 assoc_size;
} __packed;
#define A2MP_GETAMPASSOC_REQ 0x08
struct a2mp_amp_assoc_req {
__u8 id;
} __packed;
#define A2MP_GETAMPASSOC_RSP 0x09
struct a2mp_amp_assoc_rsp {
__u8 id;
__u8 status;
__u8 amp_assoc[];
} __packed;
#define A2MP_CREATEPHYSLINK_REQ 0x0A
#define A2MP_DISCONNPHYSLINK_REQ 0x0C
struct a2mp_physlink_req {
__u8 local_id;
__u8 remote_id;
__u8 amp_assoc[];
} __packed;
#define A2MP_CREATEPHYSLINK_RSP 0x0B
#define A2MP_DISCONNPHYSLINK_RSP 0x0D
struct a2mp_physlink_rsp {
__u8 local_id;
__u8 remote_id;
__u8 status;
} __packed;
/* A2MP response status */
#define A2MP_STATUS_SUCCESS 0x00
#define A2MP_STATUS_INVALID_CTRL_ID 0x01
#define A2MP_STATUS_UNABLE_START_LINK_CREATION 0x02
#define A2MP_STATUS_NO_PHYSICAL_LINK_EXISTS 0x02
#define A2MP_STATUS_COLLISION_OCCURED 0x03
#define A2MP_STATUS_DISCONN_REQ_RECVD 0x04
#define A2MP_STATUS_PHYS_LINK_EXISTS 0x05
#define A2MP_STATUS_SECURITY_VIOLATION 0x06
struct amp_mgr *amp_mgr_get(struct amp_mgr *mgr);
#if IS_ENABLED(CONFIG_BT_HS)
int amp_mgr_put(struct amp_mgr *mgr);
struct l2cap_chan *a2mp_channel_create(struct l2cap_conn *conn,
struct sk_buff *skb);
void a2mp_discover_amp(struct l2cap_chan *chan);
#else
static inline int amp_mgr_put(struct amp_mgr *mgr)
{
return 0;
}
static inline struct l2cap_chan *a2mp_channel_create(struct l2cap_conn *conn,
struct sk_buff *skb)
{
return NULL;
}
static inline void a2mp_discover_amp(struct l2cap_chan *chan)
{
}
#endif
void a2mp_send_getinfo_rsp(struct hci_dev *hdev);
void a2mp_send_getampassoc_rsp(struct hci_dev *hdev, u8 status);
void a2mp_send_create_phy_link_req(struct hci_dev *hdev, u8 status);
void a2mp_send_create_phy_link_rsp(struct hci_dev *hdev, u8 status);
#endif /* __A2MP_H */

View File

@ -309,14 +309,11 @@ int bt_sock_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
if (flags & MSG_OOB)
return -EOPNOTSUPP;
lock_sock(sk);
skb = skb_recv_datagram(sk, flags, &err);
if (!skb) {
if (sk->sk_shutdown & RCV_SHUTDOWN)
err = 0;
release_sock(sk);
return err;
}
@ -346,8 +343,6 @@ int bt_sock_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
skb_free_datagram(sk, skb);
release_sock(sk);
if (flags & MSG_TRUNC)
copied = skblen;
@ -570,10 +565,11 @@ int bt_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
if (sk->sk_state == BT_LISTEN)
return -EINVAL;
lock_sock(sk);
spin_lock(&sk->sk_receive_queue.lock);
skb = skb_peek(&sk->sk_receive_queue);
amount = skb ? skb->len : 0;
release_sock(sk);
spin_unlock(&sk->sk_receive_queue.lock);
err = put_user(amount, (int __user *)arg);
break;

View File

@ -1,590 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
Copyright (c) 2011,2012 Intel Corp.
*/
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci.h>
#include <net/bluetooth/hci_core.h>
#include <crypto/hash.h>
#include "hci_request.h"
#include "a2mp.h"
#include "amp.h"
/* Remote AMP Controllers interface */
void amp_ctrl_get(struct amp_ctrl *ctrl)
{
BT_DBG("ctrl %p orig refcnt %d", ctrl,
kref_read(&ctrl->kref));
kref_get(&ctrl->kref);
}
static void amp_ctrl_destroy(struct kref *kref)
{
struct amp_ctrl *ctrl = container_of(kref, struct amp_ctrl, kref);
BT_DBG("ctrl %p", ctrl);
kfree(ctrl->assoc);
kfree(ctrl);
}
int amp_ctrl_put(struct amp_ctrl *ctrl)
{
BT_DBG("ctrl %p orig refcnt %d", ctrl,
kref_read(&ctrl->kref));
return kref_put(&ctrl->kref, &amp_ctrl_destroy);
}
struct amp_ctrl *amp_ctrl_add(struct amp_mgr *mgr, u8 id)
{
struct amp_ctrl *ctrl;
ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL);
if (!ctrl)
return NULL;
kref_init(&ctrl->kref);
ctrl->id = id;
mutex_lock(&mgr->amp_ctrls_lock);
list_add(&ctrl->list, &mgr->amp_ctrls);
mutex_unlock(&mgr->amp_ctrls_lock);
BT_DBG("mgr %p ctrl %p", mgr, ctrl);
return ctrl;
}
void amp_ctrl_list_flush(struct amp_mgr *mgr)
{
struct amp_ctrl *ctrl, *n;
BT_DBG("mgr %p", mgr);
mutex_lock(&mgr->amp_ctrls_lock);
list_for_each_entry_safe(ctrl, n, &mgr->amp_ctrls, list) {
list_del(&ctrl->list);
amp_ctrl_put(ctrl);
}
mutex_unlock(&mgr->amp_ctrls_lock);
}
struct amp_ctrl *amp_ctrl_lookup(struct amp_mgr *mgr, u8 id)
{
struct amp_ctrl *ctrl;
BT_DBG("mgr %p id %u", mgr, id);
mutex_lock(&mgr->amp_ctrls_lock);
list_for_each_entry(ctrl, &mgr->amp_ctrls, list) {
if (ctrl->id == id) {
amp_ctrl_get(ctrl);
mutex_unlock(&mgr->amp_ctrls_lock);
return ctrl;
}
}
mutex_unlock(&mgr->amp_ctrls_lock);
return NULL;
}
/* Physical Link interface */
static u8 __next_handle(struct amp_mgr *mgr)
{
if (++mgr->handle == 0)
mgr->handle = 1;
return mgr->handle;
}
struct hci_conn *phylink_add(struct hci_dev *hdev, struct amp_mgr *mgr,
u8 remote_id, bool out)
{
bdaddr_t *dst = &mgr->l2cap_conn->hcon->dst;
struct hci_conn *hcon;
u8 role = out ? HCI_ROLE_MASTER : HCI_ROLE_SLAVE;
hcon = hci_conn_add(hdev, AMP_LINK, dst, role, __next_handle(mgr));
if (!hcon)
return NULL;
BT_DBG("hcon %p dst %pMR", hcon, dst);
hcon->state = BT_CONNECT;
hcon->attempt++;
hcon->remote_id = remote_id;
hcon->amp_mgr = amp_mgr_get(mgr);
return hcon;
}
/* AMP crypto key generation interface */
static int hmac_sha256(u8 *key, u8 ksize, char *plaintext, u8 psize, u8 *output)
{
struct crypto_shash *tfm;
struct shash_desc *shash;
int ret;
if (!ksize)
return -EINVAL;
tfm = crypto_alloc_shash("hmac(sha256)", 0, 0);
if (IS_ERR(tfm)) {
BT_DBG("crypto_alloc_ahash failed: err %ld", PTR_ERR(tfm));
return PTR_ERR(tfm);
}
ret = crypto_shash_setkey(tfm, key, ksize);
if (ret) {
BT_DBG("crypto_ahash_setkey failed: err %d", ret);
goto failed;
}
shash = kzalloc(sizeof(*shash) + crypto_shash_descsize(tfm),
GFP_KERNEL);
if (!shash) {
ret = -ENOMEM;
goto failed;
}
shash->tfm = tfm;
ret = crypto_shash_digest(shash, plaintext, psize, output);
kfree(shash);
failed:
crypto_free_shash(tfm);
return ret;
}
int phylink_gen_key(struct hci_conn *conn, u8 *data, u8 *len, u8 *type)
{
struct hci_dev *hdev = conn->hdev;
struct link_key *key;
u8 keybuf[HCI_AMP_LINK_KEY_SIZE];
u8 gamp_key[HCI_AMP_LINK_KEY_SIZE];
int err;
if (!hci_conn_check_link_mode(conn))
return -EACCES;
BT_DBG("conn %p key_type %d", conn, conn->key_type);
/* Legacy key */
if (conn->key_type < 3) {
bt_dev_err(hdev, "legacy key type %u", conn->key_type);
return -EACCES;
}
*type = conn->key_type;
*len = HCI_AMP_LINK_KEY_SIZE;
key = hci_find_link_key(hdev, &conn->dst);
if (!key) {
BT_DBG("No Link key for conn %p dst %pMR", conn, &conn->dst);
return -EACCES;
}
/* BR/EDR Link Key concatenated together with itself */
memcpy(&keybuf[0], key->val, HCI_LINK_KEY_SIZE);
memcpy(&keybuf[HCI_LINK_KEY_SIZE], key->val, HCI_LINK_KEY_SIZE);
/* Derive Generic AMP Link Key (gamp) */
err = hmac_sha256(keybuf, HCI_AMP_LINK_KEY_SIZE, "gamp", 4, gamp_key);
if (err) {
bt_dev_err(hdev, "could not derive Generic AMP Key: err %d", err);
return err;
}
if (conn->key_type == HCI_LK_DEBUG_COMBINATION) {
BT_DBG("Use Generic AMP Key (gamp)");
memcpy(data, gamp_key, HCI_AMP_LINK_KEY_SIZE);
return err;
}
/* Derive Dedicated AMP Link Key: "802b" is 802.11 PAL keyID */
return hmac_sha256(gamp_key, HCI_AMP_LINK_KEY_SIZE, "802b", 4, data);
}
static void read_local_amp_assoc_complete(struct hci_dev *hdev, u8 status,
u16 opcode, struct sk_buff *skb)
{
struct hci_rp_read_local_amp_assoc *rp = (void *)skb->data;
struct amp_assoc *assoc = &hdev->loc_assoc;
size_t rem_len, frag_len;
BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
if (rp->status)
goto send_rsp;
frag_len = skb->len - sizeof(*rp);
rem_len = __le16_to_cpu(rp->rem_len);
if (rem_len > frag_len) {
BT_DBG("frag_len %zu rem_len %zu", frag_len, rem_len);
memcpy(assoc->data + assoc->offset, rp->frag, frag_len);
assoc->offset += frag_len;
/* Read other fragments */
amp_read_loc_assoc_frag(hdev, rp->phy_handle);
return;
}
memcpy(assoc->data + assoc->offset, rp->frag, rem_len);
assoc->len = assoc->offset + rem_len;
assoc->offset = 0;
send_rsp:
/* Send A2MP Rsp when all fragments are received */
a2mp_send_getampassoc_rsp(hdev, rp->status);
a2mp_send_create_phy_link_req(hdev, rp->status);
}
void amp_read_loc_assoc_frag(struct hci_dev *hdev, u8 phy_handle)
{
struct hci_cp_read_local_amp_assoc cp;
struct amp_assoc *loc_assoc = &hdev->loc_assoc;
struct hci_request req;
int err;
BT_DBG("%s handle %u", hdev->name, phy_handle);
cp.phy_handle = phy_handle;
cp.max_len = cpu_to_le16(hdev->amp_assoc_size);
cp.len_so_far = cpu_to_le16(loc_assoc->offset);
hci_req_init(&req, hdev);
hci_req_add(&req, HCI_OP_READ_LOCAL_AMP_ASSOC, sizeof(cp), &cp);
err = hci_req_run_skb(&req, read_local_amp_assoc_complete);
if (err < 0)
a2mp_send_getampassoc_rsp(hdev, A2MP_STATUS_INVALID_CTRL_ID);
}
void amp_read_loc_assoc(struct hci_dev *hdev, struct amp_mgr *mgr)
{
struct hci_cp_read_local_amp_assoc cp;
struct hci_request req;
int err;
memset(&hdev->loc_assoc, 0, sizeof(struct amp_assoc));
memset(&cp, 0, sizeof(cp));
cp.max_len = cpu_to_le16(hdev->amp_assoc_size);
set_bit(READ_LOC_AMP_ASSOC, &mgr->state);
hci_req_init(&req, hdev);
hci_req_add(&req, HCI_OP_READ_LOCAL_AMP_ASSOC, sizeof(cp), &cp);
err = hci_req_run_skb(&req, read_local_amp_assoc_complete);
if (err < 0)
a2mp_send_getampassoc_rsp(hdev, A2MP_STATUS_INVALID_CTRL_ID);
}
void amp_read_loc_assoc_final_data(struct hci_dev *hdev,
struct hci_conn *hcon)
{
struct hci_cp_read_local_amp_assoc cp;
struct amp_mgr *mgr = hcon->amp_mgr;
struct hci_request req;
int err;
if (!mgr)
return;
cp.phy_handle = hcon->handle;
cp.len_so_far = cpu_to_le16(0);
cp.max_len = cpu_to_le16(hdev->amp_assoc_size);
set_bit(READ_LOC_AMP_ASSOC_FINAL, &mgr->state);
/* Read Local AMP Assoc final link information data */
hci_req_init(&req, hdev);
hci_req_add(&req, HCI_OP_READ_LOCAL_AMP_ASSOC, sizeof(cp), &cp);
err = hci_req_run_skb(&req, read_local_amp_assoc_complete);
if (err < 0)
a2mp_send_getampassoc_rsp(hdev, A2MP_STATUS_INVALID_CTRL_ID);
}
static void write_remote_amp_assoc_complete(struct hci_dev *hdev, u8 status,
u16 opcode, struct sk_buff *skb)
{
struct hci_rp_write_remote_amp_assoc *rp = (void *)skb->data;
BT_DBG("%s status 0x%2.2x phy_handle 0x%2.2x",
hdev->name, rp->status, rp->phy_handle);
if (rp->status)
return;
amp_write_rem_assoc_continue(hdev, rp->phy_handle);
}
/* Write AMP Assoc data fragments, returns true with last fragment written*/
static bool amp_write_rem_assoc_frag(struct hci_dev *hdev,
struct hci_conn *hcon)
{
struct hci_cp_write_remote_amp_assoc *cp;
struct amp_mgr *mgr = hcon->amp_mgr;
struct amp_ctrl *ctrl;
struct hci_request req;
u16 frag_len, len;
ctrl = amp_ctrl_lookup(mgr, hcon->remote_id);
if (!ctrl)
return false;
if (!ctrl->assoc_rem_len) {
BT_DBG("all fragments are written");
ctrl->assoc_rem_len = ctrl->assoc_len;
ctrl->assoc_len_so_far = 0;
amp_ctrl_put(ctrl);
return true;
}
frag_len = min_t(u16, 248, ctrl->assoc_rem_len);
len = frag_len + sizeof(*cp);
cp = kzalloc(len, GFP_KERNEL);
if (!cp) {
amp_ctrl_put(ctrl);
return false;
}
BT_DBG("hcon %p ctrl %p frag_len %u assoc_len %u rem_len %u",
hcon, ctrl, frag_len, ctrl->assoc_len, ctrl->assoc_rem_len);
cp->phy_handle = hcon->handle;
cp->len_so_far = cpu_to_le16(ctrl->assoc_len_so_far);
cp->rem_len = cpu_to_le16(ctrl->assoc_rem_len);
memcpy(cp->frag, ctrl->assoc, frag_len);
ctrl->assoc_len_so_far += frag_len;
ctrl->assoc_rem_len -= frag_len;
amp_ctrl_put(ctrl);
hci_req_init(&req, hdev);
hci_req_add(&req, HCI_OP_WRITE_REMOTE_AMP_ASSOC, len, cp);
hci_req_run_skb(&req, write_remote_amp_assoc_complete);
kfree(cp);
return false;
}
void amp_write_rem_assoc_continue(struct hci_dev *hdev, u8 handle)
{
struct hci_conn *hcon;
BT_DBG("%s phy handle 0x%2.2x", hdev->name, handle);
hcon = hci_conn_hash_lookup_handle(hdev, handle);
if (!hcon)
return;
/* Send A2MP create phylink rsp when all fragments are written */
if (amp_write_rem_assoc_frag(hdev, hcon))
a2mp_send_create_phy_link_rsp(hdev, 0);
}
void amp_write_remote_assoc(struct hci_dev *hdev, u8 handle)
{
struct hci_conn *hcon;
BT_DBG("%s phy handle 0x%2.2x", hdev->name, handle);
hcon = hci_conn_hash_lookup_handle(hdev, handle);
if (!hcon)
return;
BT_DBG("%s phy handle 0x%2.2x hcon %p", hdev->name, handle, hcon);
amp_write_rem_assoc_frag(hdev, hcon);
}
static void create_phylink_complete(struct hci_dev *hdev, u8 status,
u16 opcode)
{
struct hci_cp_create_phy_link *cp;
BT_DBG("%s status 0x%2.2x", hdev->name, status);
cp = hci_sent_cmd_data(hdev, HCI_OP_CREATE_PHY_LINK);
if (!cp)
return;
hci_dev_lock(hdev);
if (status) {
struct hci_conn *hcon;
hcon = hci_conn_hash_lookup_handle(hdev, cp->phy_handle);
if (hcon)
hci_conn_del(hcon);
} else {
amp_write_remote_assoc(hdev, cp->phy_handle);
}
hci_dev_unlock(hdev);
}
void amp_create_phylink(struct hci_dev *hdev, struct amp_mgr *mgr,
struct hci_conn *hcon)
{
struct hci_cp_create_phy_link cp;
struct hci_request req;
cp.phy_handle = hcon->handle;
BT_DBG("%s hcon %p phy handle 0x%2.2x", hdev->name, hcon,
hcon->handle);
if (phylink_gen_key(mgr->l2cap_conn->hcon, cp.key, &cp.key_len,
&cp.key_type)) {
BT_DBG("Cannot create link key");
return;
}
hci_req_init(&req, hdev);
hci_req_add(&req, HCI_OP_CREATE_PHY_LINK, sizeof(cp), &cp);
hci_req_run(&req, create_phylink_complete);
}
static void accept_phylink_complete(struct hci_dev *hdev, u8 status,
u16 opcode)
{
struct hci_cp_accept_phy_link *cp;
BT_DBG("%s status 0x%2.2x", hdev->name, status);
if (status)
return;
cp = hci_sent_cmd_data(hdev, HCI_OP_ACCEPT_PHY_LINK);
if (!cp)
return;
amp_write_remote_assoc(hdev, cp->phy_handle);
}
void amp_accept_phylink(struct hci_dev *hdev, struct amp_mgr *mgr,
struct hci_conn *hcon)
{
struct hci_cp_accept_phy_link cp;
struct hci_request req;
cp.phy_handle = hcon->handle;
BT_DBG("%s hcon %p phy handle 0x%2.2x", hdev->name, hcon,
hcon->handle);
if (phylink_gen_key(mgr->l2cap_conn->hcon, cp.key, &cp.key_len,
&cp.key_type)) {
BT_DBG("Cannot create link key");
return;
}
hci_req_init(&req, hdev);
hci_req_add(&req, HCI_OP_ACCEPT_PHY_LINK, sizeof(cp), &cp);
hci_req_run(&req, accept_phylink_complete);
}
void amp_physical_cfm(struct hci_conn *bredr_hcon, struct hci_conn *hs_hcon)
{
struct hci_dev *bredr_hdev = hci_dev_hold(bredr_hcon->hdev);
struct amp_mgr *mgr = hs_hcon->amp_mgr;
struct l2cap_chan *bredr_chan;
BT_DBG("bredr_hcon %p hs_hcon %p mgr %p", bredr_hcon, hs_hcon, mgr);
if (!bredr_hdev || !mgr || !mgr->bredr_chan)
return;
bredr_chan = mgr->bredr_chan;
l2cap_chan_lock(bredr_chan);
set_bit(FLAG_EFS_ENABLE, &bredr_chan->flags);
bredr_chan->remote_amp_id = hs_hcon->remote_id;
bredr_chan->local_amp_id = hs_hcon->hdev->id;
bredr_chan->hs_hcon = hs_hcon;
bredr_chan->conn->mtu = hs_hcon->hdev->block_mtu;
__l2cap_physical_cfm(bredr_chan, 0);
l2cap_chan_unlock(bredr_chan);
hci_dev_put(bredr_hdev);
}
void amp_create_logical_link(struct l2cap_chan *chan)
{
struct hci_conn *hs_hcon = chan->hs_hcon;
struct hci_cp_create_accept_logical_link cp;
struct hci_dev *hdev;
BT_DBG("chan %p hs_hcon %p dst %pMR", chan, hs_hcon,
&chan->conn->hcon->dst);
if (!hs_hcon)
return;
hdev = hci_dev_hold(chan->hs_hcon->hdev);
if (!hdev)
return;
cp.phy_handle = hs_hcon->handle;
cp.tx_flow_spec.id = chan->local_id;
cp.tx_flow_spec.stype = chan->local_stype;
cp.tx_flow_spec.msdu = cpu_to_le16(chan->local_msdu);
cp.tx_flow_spec.sdu_itime = cpu_to_le32(chan->local_sdu_itime);
cp.tx_flow_spec.acc_lat = cpu_to_le32(chan->local_acc_lat);
cp.tx_flow_spec.flush_to = cpu_to_le32(chan->local_flush_to);
cp.rx_flow_spec.id = chan->remote_id;
cp.rx_flow_spec.stype = chan->remote_stype;
cp.rx_flow_spec.msdu = cpu_to_le16(chan->remote_msdu);
cp.rx_flow_spec.sdu_itime = cpu_to_le32(chan->remote_sdu_itime);
cp.rx_flow_spec.acc_lat = cpu_to_le32(chan->remote_acc_lat);
cp.rx_flow_spec.flush_to = cpu_to_le32(chan->remote_flush_to);
if (hs_hcon->out)
hci_send_cmd(hdev, HCI_OP_CREATE_LOGICAL_LINK, sizeof(cp),
&cp);
else
hci_send_cmd(hdev, HCI_OP_ACCEPT_LOGICAL_LINK, sizeof(cp),
&cp);
hci_dev_put(hdev);
}
void amp_disconnect_logical_link(struct hci_chan *hchan)
{
struct hci_conn *hcon = hchan->conn;
struct hci_cp_disconn_logical_link cp;
if (hcon->state != BT_CONNECTED) {
BT_DBG("hchan %p not connected", hchan);
return;
}
cp.log_handle = cpu_to_le16(hchan->handle);
hci_send_cmd(hcon->hdev, HCI_OP_DISCONN_LOGICAL_LINK, sizeof(cp), &cp);
}
void amp_destroy_logical_link(struct hci_chan *hchan, u8 reason)
{
BT_DBG("hchan %p", hchan);
hci_chan_del(hchan);
}

View File

@ -1,60 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
Copyright (c) 2011,2012 Intel Corp.
*/
#ifndef __AMP_H
#define __AMP_H
struct amp_ctrl {
struct list_head list;
struct kref kref;
__u8 id;
__u16 assoc_len_so_far;
__u16 assoc_rem_len;
__u16 assoc_len;
__u8 *assoc;
};
int amp_ctrl_put(struct amp_ctrl *ctrl);
void amp_ctrl_get(struct amp_ctrl *ctrl);
struct amp_ctrl *amp_ctrl_add(struct amp_mgr *mgr, u8 id);
struct amp_ctrl *amp_ctrl_lookup(struct amp_mgr *mgr, u8 id);
void amp_ctrl_list_flush(struct amp_mgr *mgr);
struct hci_conn *phylink_add(struct hci_dev *hdev, struct amp_mgr *mgr,
u8 remote_id, bool out);
int phylink_gen_key(struct hci_conn *hcon, u8 *data, u8 *len, u8 *type);
void amp_read_loc_assoc_frag(struct hci_dev *hdev, u8 phy_handle);
void amp_read_loc_assoc(struct hci_dev *hdev, struct amp_mgr *mgr);
void amp_read_loc_assoc_final_data(struct hci_dev *hdev,
struct hci_conn *hcon);
void amp_create_phylink(struct hci_dev *hdev, struct amp_mgr *mgr,
struct hci_conn *hcon);
void amp_accept_phylink(struct hci_dev *hdev, struct amp_mgr *mgr,
struct hci_conn *hcon);
#if IS_ENABLED(CONFIG_BT_HS)
void amp_create_logical_link(struct l2cap_chan *chan);
void amp_disconnect_logical_link(struct hci_chan *hchan);
#else
static inline void amp_create_logical_link(struct l2cap_chan *chan)
{
}
static inline void amp_disconnect_logical_link(struct hci_chan *hchan)
{
}
#endif
void amp_write_remote_assoc(struct hci_dev *hdev, u8 handle);
void amp_write_rem_assoc_continue(struct hci_dev *hdev, u8 handle);
void amp_physical_cfm(struct hci_conn *bredr_hcon, struct hci_conn *hs_hcon);
void amp_create_logical_link(struct l2cap_chan *chan);
void amp_disconnect_logical_link(struct hci_chan *hchan);
void amp_destroy_logical_link(struct hci_chan *hchan, u8 reason);
#endif /* __AMP_H */

View File

@ -385,7 +385,8 @@ static int bnep_rx_frame(struct bnep_session *s, struct sk_buff *skb)
case BNEP_COMPRESSED_DST_ONLY:
__skb_put_data(nskb, skb_mac_header(skb), ETH_ALEN);
__skb_put_data(nskb, s->eh.h_source, ETH_ALEN + 2);
__skb_put_data(nskb, s->eh.h_source, ETH_ALEN);
put_unaligned(s->eh.h_proto, (__be16 *)__skb_put(nskb, 2));
break;
case BNEP_GENERAL:
@ -549,7 +550,7 @@ static struct device *bnep_get_device(struct bnep_session *session)
return &conn->hcon->dev;
}
static struct device_type bnep_type = {
static const struct device_type bnep_type = {
.name = "bluetooth",
};

View File

@ -13,48 +13,33 @@
#define PNP_INFO_SVCLASS_ID 0x1200
static u8 eir_append_name(u8 *eir, u16 eir_len, u8 type, u8 *data, u8 data_len)
{
u8 name[HCI_MAX_SHORT_NAME_LENGTH + 1];
/* If data is already NULL terminated just pass it directly */
if (data[data_len - 1] == '\0')
return eir_append_data(eir, eir_len, type, data, data_len);
memcpy(name, data, HCI_MAX_SHORT_NAME_LENGTH);
name[HCI_MAX_SHORT_NAME_LENGTH] = '\0';
return eir_append_data(eir, eir_len, type, name, sizeof(name));
}
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 ((max_adv_len(hdev) - ad_len) < HCI_MAX_SHORT_NAME_LENGTH + 3)
/* no space left for name (+ type + len) */
if ((max_adv_len(hdev) - ad_len) < HCI_MAX_SHORT_NAME_LENGTH + 2)
return ad_len;
/* use complete name if present and fits */
complete_len = strnlen(hdev->dev_name, sizeof(hdev->dev_name));
if (complete_len && complete_len <= HCI_MAX_SHORT_NAME_LENGTH)
return eir_append_name(ptr, ad_len, EIR_NAME_COMPLETE,
hdev->dev_name, complete_len + 1);
return eir_append_data(ptr, ad_len, EIR_NAME_COMPLETE,
hdev->dev_name, complete_len);
/* use short name if present */
short_len = strnlen(hdev->short_name, sizeof(hdev->short_name));
if (short_len)
return eir_append_name(ptr, ad_len, EIR_NAME_SHORT,
return eir_append_data(ptr, ad_len, EIR_NAME_SHORT,
hdev->short_name,
short_len == HCI_MAX_SHORT_NAME_LENGTH ?
short_len : short_len + 1);
short_len);
/* use shortened full name if present, we already know that name
* is longer then HCI_MAX_SHORT_NAME_LENGTH
*/
if (complete_len)
return eir_append_name(ptr, ad_len, EIR_NAME_SHORT,
return eir_append_data(ptr, ad_len, EIR_NAME_SHORT,
hdev->dev_name,
HCI_MAX_SHORT_NAME_LENGTH);

View File

@ -1,7 +1,7 @@
/*
BlueZ - Bluetooth protocol stack for Linux
Copyright (c) 2000-2001, 2010, Code Aurora Forum. All rights reserved.
Copyright 2023 NXP
Copyright 2023-2024 NXP
Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
@ -36,7 +36,6 @@
#include "hci_request.h"
#include "smp.h"
#include "a2mp.h"
#include "eir.h"
struct sco_param {
@ -69,7 +68,7 @@ static const struct sco_param esco_param_msbc[] = {
};
/* This function requires the caller holds hdev->lock */
static void hci_connect_le_scan_cleanup(struct hci_conn *conn, u8 status)
void hci_connect_le_scan_cleanup(struct hci_conn *conn, u8 status)
{
struct hci_conn_params *params;
struct hci_dev *hdev = conn->hdev;
@ -179,64 +178,6 @@ static void hci_conn_cleanup(struct hci_conn *conn)
hci_dev_put(hdev);
}
static void hci_acl_create_connection(struct hci_conn *conn)
{
struct hci_dev *hdev = conn->hdev;
struct inquiry_entry *ie;
struct hci_cp_create_conn cp;
BT_DBG("hcon %p", conn);
/* Many controllers disallow HCI Create Connection while it is doing
* HCI Inquiry. So we cancel the Inquiry first before issuing HCI Create
* Connection. This may cause the MGMT discovering state to become false
* without user space's request but it is okay since the MGMT Discovery
* APIs do not promise that discovery should be done forever. Instead,
* the user space monitors the status of MGMT discovering and it may
* request for discovery again when this flag becomes false.
*/
if (test_bit(HCI_INQUIRY, &hdev->flags)) {
/* Put this connection to "pending" state so that it will be
* executed after the inquiry cancel command complete event.
*/
conn->state = BT_CONNECT2;
hci_send_cmd(hdev, HCI_OP_INQUIRY_CANCEL, 0, NULL);
return;
}
conn->state = BT_CONNECT;
conn->out = true;
conn->role = HCI_ROLE_MASTER;
conn->attempt++;
conn->link_policy = hdev->link_policy;
memset(&cp, 0, sizeof(cp));
bacpy(&cp.bdaddr, &conn->dst);
cp.pscan_rep_mode = 0x02;
ie = hci_inquiry_cache_lookup(hdev, &conn->dst);
if (ie) {
if (inquiry_entry_age(ie) <= INQUIRY_ENTRY_AGE_MAX) {
cp.pscan_rep_mode = ie->data.pscan_rep_mode;
cp.pscan_mode = ie->data.pscan_mode;
cp.clock_offset = ie->data.clock_offset |
cpu_to_le16(0x8000);
}
memcpy(conn->dev_class, ie->data.dev_class, 3);
}
cp.pkt_type = cpu_to_le16(conn->pkt_type);
if (lmp_rswitch_capable(hdev) && !(hdev->link_mode & HCI_LM_MASTER))
cp.role_switch = 0x01;
else
cp.role_switch = 0x00;
hci_send_cmd(hdev, HCI_OP_CREATE_CONN, sizeof(cp), &cp);
}
int hci_disconnect(struct hci_conn *conn, __u8 reason)
{
BT_DBG("hcon %p", conn);
@ -1175,9 +1116,6 @@ void hci_conn_del(struct hci_conn *conn)
}
}
if (conn->amp_mgr)
amp_mgr_put(conn->amp_mgr);
skb_queue_purge(&conn->data_q);
/* Remove the connection from the list and cleanup its remaining
@ -1186,6 +1124,9 @@ void hci_conn_del(struct hci_conn *conn)
* rest of hci_conn_del.
*/
hci_conn_cleanup(conn);
/* Dequeue callbacks using connection pointer as data */
hci_cmd_sync_dequeue(hdev, NULL, conn, NULL);
}
struct hci_dev *hci_get_route(bdaddr_t *dst, bdaddr_t *src, uint8_t src_type)
@ -1320,53 +1261,6 @@ u8 hci_conn_set_handle(struct hci_conn *conn, u16 handle)
return 0;
}
static void create_le_conn_complete(struct hci_dev *hdev, void *data, int err)
{
struct hci_conn *conn;
u16 handle = PTR_UINT(data);
conn = hci_conn_hash_lookup_handle(hdev, handle);
if (!conn)
return;
bt_dev_dbg(hdev, "err %d", err);
hci_dev_lock(hdev);
if (!err) {
hci_connect_le_scan_cleanup(conn, 0x00);
goto done;
}
/* Check if connection is still pending */
if (conn != hci_lookup_le_connect(hdev))
goto done;
/* Flush to make sure we send create conn cancel command if needed */
flush_delayed_work(&conn->le_conn_timeout);
hci_conn_failed(conn, bt_status(err));
done:
hci_dev_unlock(hdev);
}
static int hci_connect_le_sync(struct hci_dev *hdev, void *data)
{
struct hci_conn *conn;
u16 handle = PTR_UINT(data);
conn = hci_conn_hash_lookup_handle(hdev, handle);
if (!conn)
return 0;
bt_dev_dbg(hdev, "conn %p", conn);
clear_bit(HCI_CONN_SCANNING, &conn->flags);
conn->state = BT_CONNECT;
return hci_le_create_conn_sync(hdev, conn);
}
struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst,
u8 dst_type, bool dst_resolved, u8 sec_level,
u16 conn_timeout, u8 role)
@ -1433,9 +1327,7 @@ struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst,
conn->sec_level = BT_SECURITY_LOW;
conn->conn_timeout = conn_timeout;
err = hci_cmd_sync_queue(hdev, hci_connect_le_sync,
UINT_PTR(conn->handle),
create_le_conn_complete);
err = hci_connect_le_sync(hdev, conn);
if (err) {
hci_conn_del(conn);
return ERR_PTR(err);
@ -1669,7 +1561,7 @@ done:
struct hci_conn *hci_connect_acl(struct hci_dev *hdev, bdaddr_t *dst,
u8 sec_level, u8 auth_type,
enum conn_reasons conn_reason)
enum conn_reasons conn_reason, u16 timeout)
{
struct hci_conn *acl;
@ -1700,10 +1592,18 @@ struct hci_conn *hci_connect_acl(struct hci_dev *hdev, bdaddr_t *dst,
acl->conn_reason = conn_reason;
if (acl->state == BT_OPEN || acl->state == BT_CLOSED) {
int err;
acl->sec_level = BT_SECURITY_LOW;
acl->pending_sec_level = sec_level;
acl->auth_type = auth_type;
hci_acl_create_connection(acl);
acl->conn_timeout = timeout;
err = hci_connect_acl_sync(hdev, acl);
if (err) {
hci_conn_del(acl);
return ERR_PTR(err);
}
}
return acl;
@ -1738,14 +1638,15 @@ static struct hci_link *hci_conn_link(struct hci_conn *parent,
}
struct hci_conn *hci_connect_sco(struct hci_dev *hdev, int type, bdaddr_t *dst,
__u16 setting, struct bt_codec *codec)
__u16 setting, struct bt_codec *codec,
u16 timeout)
{
struct hci_conn *acl;
struct hci_conn *sco;
struct hci_link *link;
acl = hci_connect_acl(hdev, dst, BT_SECURITY_LOW, HCI_AT_NO_BONDING,
CONN_REASON_SCO_CONNECT);
CONN_REASON_SCO_CONNECT, timeout);
if (IS_ERR(acl))
return acl;
@ -2156,18 +2057,31 @@ static int create_pa_sync(struct hci_dev *hdev, void *data)
return hci_update_passive_scan_sync(hdev);
}
int hci_pa_create_sync(struct hci_dev *hdev, bdaddr_t *dst, __u8 dst_type,
__u8 sid, struct bt_iso_qos *qos)
struct hci_conn *hci_pa_create_sync(struct hci_dev *hdev, bdaddr_t *dst,
__u8 dst_type, __u8 sid,
struct bt_iso_qos *qos)
{
struct hci_cp_le_pa_create_sync *cp;
struct hci_conn *conn;
int err;
if (hci_dev_test_and_set_flag(hdev, HCI_PA_SYNC))
return -EBUSY;
return ERR_PTR(-EBUSY);
conn = hci_conn_add_unset(hdev, ISO_LINK, dst, HCI_ROLE_SLAVE);
if (!conn)
return ERR_PTR(-ENOMEM);
conn->iso_qos = *qos;
conn->state = BT_LISTEN;
hci_conn_hold(conn);
cp = kzalloc(sizeof(*cp), GFP_KERNEL);
if (!cp) {
hci_dev_clear_flag(hdev, HCI_PA_SYNC);
return -ENOMEM;
hci_conn_drop(conn);
return ERR_PTR(-ENOMEM);
}
cp->options = qos->bcast.options;
@ -2179,7 +2093,14 @@ int hci_pa_create_sync(struct hci_dev *hdev, bdaddr_t *dst, __u8 dst_type,
cp->sync_cte_type = qos->bcast.sync_cte_type;
/* Queue start pa_create_sync and scan */
return hci_cmd_sync_queue(hdev, create_pa_sync, cp, create_pa_complete);
err = hci_cmd_sync_queue(hdev, create_pa_sync, cp, create_pa_complete);
if (err < 0) {
hci_conn_drop(conn);
kfree(cp);
return ERR_PTR(err);
}
return conn;
}
int hci_le_big_create_sync(struct hci_dev *hdev, struct hci_conn *hcon,
@ -2647,22 +2568,6 @@ void hci_conn_hash_flush(struct hci_dev *hdev)
}
}
/* Check pending connect attempts */
void hci_conn_check_pending(struct hci_dev *hdev)
{
struct hci_conn *conn;
BT_DBG("hdev %s", hdev->name);
hci_dev_lock(hdev);
conn = hci_conn_hash_lookup_state(hdev, ACL_LINK, BT_CONNECT2);
if (conn)
hci_acl_create_connection(conn);
hci_dev_unlock(hdev);
}
static u32 get_link_mode(struct hci_conn *conn)
{
u32 link_mode = 0;
@ -2978,12 +2883,10 @@ u32 hci_conn_get_phy(struct hci_conn *conn)
static int abort_conn_sync(struct hci_dev *hdev, void *data)
{
struct hci_conn *conn;
u16 handle = PTR_UINT(data);
struct hci_conn *conn = data;
conn = hci_conn_hash_lookup_handle(hdev, handle);
if (!conn)
return 0;
if (!hci_conn_valid(hdev, conn))
return -ECANCELED;
return hci_abort_conn_sync(hdev, conn, conn->abort_reason);
}
@ -3011,14 +2914,17 @@ int hci_abort_conn(struct hci_conn *conn, u8 reason)
*/
if (conn->state == BT_CONNECT && hdev->req_status == HCI_REQ_PEND) {
switch (hci_skb_event(hdev->sent_cmd)) {
case HCI_EV_CONN_COMPLETE:
case HCI_EV_LE_CONN_COMPLETE:
case HCI_EV_LE_ENHANCED_CONN_COMPLETE:
case HCI_EVT_LE_CIS_ESTABLISHED:
hci_cmd_sync_cancel(hdev, -ECANCELED);
hci_cmd_sync_cancel(hdev, ECANCELED);
break;
}
/* Cancel connect attempt if still queued/pending */
} else if (!hci_cancel_connect_sync(hdev, conn)) {
return 0;
}
return hci_cmd_sync_queue(hdev, abort_conn_sync, UINT_PTR(conn->handle),
NULL);
return hci_cmd_sync_queue_once(hdev, abort_conn_sync, conn, NULL);
}

View File

@ -908,7 +908,7 @@ int hci_get_dev_info(void __user *arg)
else
flags = hdev->flags;
strcpy(di.name, hdev->name);
strscpy(di.name, hdev->name, sizeof(di.name));
di.bdaddr = hdev->bdaddr;
di.type = (hdev->bus & 0x0f) | ((hdev->dev_type & 0x03) << 4);
di.flags = flags;
@ -940,20 +940,51 @@ int hci_get_dev_info(void __user *arg)
/* ---- Interface to HCI drivers ---- */
static int hci_dev_do_poweroff(struct hci_dev *hdev)
{
int err;
BT_DBG("%s %p", hdev->name, hdev);
hci_req_sync_lock(hdev);
err = hci_set_powered_sync(hdev, false);
hci_req_sync_unlock(hdev);
return err;
}
static int hci_rfkill_set_block(void *data, bool blocked)
{
struct hci_dev *hdev = data;
int err;
BT_DBG("%p name %s blocked %d", hdev, hdev->name, blocked);
if (hci_dev_test_flag(hdev, HCI_USER_CHANNEL))
return -EBUSY;
if (blocked == hci_dev_test_flag(hdev, HCI_RFKILLED))
return 0;
if (blocked) {
hci_dev_set_flag(hdev, HCI_RFKILLED);
if (!hci_dev_test_flag(hdev, HCI_SETUP) &&
!hci_dev_test_flag(hdev, HCI_CONFIG))
hci_dev_do_close(hdev);
!hci_dev_test_flag(hdev, HCI_CONFIG)) {
err = hci_dev_do_poweroff(hdev);
if (err) {
bt_dev_err(hdev, "Error when powering off device on rfkill (%d)",
err);
/* Make sure the device is still closed even if
* anything during power off sequence (eg.
* disconnecting devices) failed.
*/
hci_dev_do_close(hdev);
}
}
} else {
hci_dev_clear_flag(hdev, HCI_RFKILLED);
}
@ -1491,11 +1522,12 @@ static void hci_cmd_timeout(struct work_struct *work)
struct hci_dev *hdev = container_of(work, struct hci_dev,
cmd_timer.work);
if (hdev->sent_cmd) {
struct hci_command_hdr *sent = (void *) hdev->sent_cmd->data;
u16 opcode = __le16_to_cpu(sent->opcode);
if (hdev->req_skb) {
u16 opcode = hci_skb_opcode(hdev->req_skb);
bt_dev_err(hdev, "command 0x%4.4x tx timeout", opcode);
hci_cmd_sync_cancel_sync(hdev, ETIMEDOUT);
} else {
bt_dev_err(hdev, "command tx timeout");
}
@ -2608,10 +2640,11 @@ int hci_register_dev(struct hci_dev *hdev)
*/
switch (hdev->dev_type) {
case HCI_PRIMARY:
id = ida_simple_get(&hci_index_ida, 0, HCI_MAX_ID, GFP_KERNEL);
id = ida_alloc_max(&hci_index_ida, HCI_MAX_ID - 1, GFP_KERNEL);
break;
case HCI_AMP:
id = ida_simple_get(&hci_index_ida, 1, HCI_MAX_ID, GFP_KERNEL);
id = ida_alloc_range(&hci_index_ida, 1, HCI_MAX_ID - 1,
GFP_KERNEL);
break;
default:
return -EINVAL;
@ -2710,7 +2743,7 @@ err_wqueue:
destroy_workqueue(hdev->workqueue);
destroy_workqueue(hdev->req_workqueue);
err:
ida_simple_remove(&hci_index_ida, hdev->id);
ida_free(&hci_index_ida, hdev->id);
return error;
}
@ -2793,8 +2826,9 @@ void hci_release_dev(struct hci_dev *hdev)
hci_dev_unlock(hdev);
ida_destroy(&hdev->unset_handle_ida);
ida_simple_remove(&hci_index_ida, hdev->id);
ida_free(&hci_index_ida, hdev->id);
kfree_skb(hdev->sent_cmd);
kfree_skb(hdev->req_skb);
kfree_skb(hdev->recv_event);
kfree(hdev);
}
@ -2826,6 +2860,23 @@ int hci_unregister_suspend_notifier(struct hci_dev *hdev)
return ret;
}
/* Cancel ongoing command synchronously:
*
* - Cancel command timer
* - Reset command counter
* - Cancel command request
*/
static void hci_cancel_cmd_sync(struct hci_dev *hdev, int err)
{
bt_dev_dbg(hdev, "err 0x%2.2x", err);
cancel_delayed_work_sync(&hdev->cmd_timer);
cancel_delayed_work_sync(&hdev->ncmd_timer);
atomic_set(&hdev->cmd_cnt, 1);
hci_cmd_sync_cancel_sync(hdev, -err);
}
/* Suspend HCI device */
int hci_suspend_dev(struct hci_dev *hdev)
{
@ -2843,7 +2894,7 @@ int hci_suspend_dev(struct hci_dev *hdev)
return 0;
/* Cancel potentially blocking sync operation before suspend */
__hci_cmd_sync_cancel(hdev, -EHOSTDOWN);
hci_cancel_cmd_sync(hdev, -EHOSTDOWN);
hci_req_sync_lock(hdev);
ret = hci_suspend_sync(hdev);
@ -3107,21 +3158,33 @@ int __hci_cmd_send(struct hci_dev *hdev, u16 opcode, u32 plen,
EXPORT_SYMBOL(__hci_cmd_send);
/* Get data from the previously sent command */
void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 opcode)
static void *hci_cmd_data(struct sk_buff *skb, __u16 opcode)
{
struct hci_command_hdr *hdr;
if (!hdev->sent_cmd)
if (!skb || skb->len < HCI_COMMAND_HDR_SIZE)
return NULL;
hdr = (void *) hdev->sent_cmd->data;
hdr = (void *)skb->data;
if (hdr->opcode != cpu_to_le16(opcode))
return NULL;
BT_DBG("%s opcode 0x%4.4x", hdev->name, opcode);
return skb->data + HCI_COMMAND_HDR_SIZE;
}
return hdev->sent_cmd->data + HCI_COMMAND_HDR_SIZE;
/* Get data from the previously sent command */
void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 opcode)
{
void *data;
/* Check if opcode matches last sent command */
data = hci_cmd_data(hdev->sent_cmd, opcode);
if (!data)
/* Check if opcode matches last request */
data = hci_cmd_data(hdev->req_skb, opcode);
return data;
}
/* Get data from last received event */
@ -4022,17 +4085,19 @@ void hci_req_cmd_complete(struct hci_dev *hdev, u16 opcode, u8 status,
if (!status && !hci_req_is_complete(hdev))
return;
skb = hdev->req_skb;
/* If this was the last command in a request the complete
* callback would be found in hdev->sent_cmd instead of the
* callback would be found in hdev->req_skb instead of the
* command queue (hdev->cmd_q).
*/
if (bt_cb(hdev->sent_cmd)->hci.req_flags & HCI_REQ_SKB) {
*req_complete_skb = bt_cb(hdev->sent_cmd)->hci.req_complete_skb;
if (skb && bt_cb(skb)->hci.req_flags & HCI_REQ_SKB) {
*req_complete_skb = bt_cb(skb)->hci.req_complete_skb;
return;
}
if (bt_cb(hdev->sent_cmd)->hci.req_complete) {
*req_complete = bt_cb(hdev->sent_cmd)->hci.req_complete;
if (skb && bt_cb(skb)->hci.req_complete) {
*req_complete = bt_cb(skb)->hci.req_complete;
return;
}
@ -4128,6 +4193,36 @@ static void hci_rx_work(struct work_struct *work)
}
}
static void hci_send_cmd_sync(struct hci_dev *hdev, struct sk_buff *skb)
{
int err;
bt_dev_dbg(hdev, "skb %p", skb);
kfree_skb(hdev->sent_cmd);
hdev->sent_cmd = skb_clone(skb, GFP_KERNEL);
if (!hdev->sent_cmd) {
skb_queue_head(&hdev->cmd_q, skb);
queue_work(hdev->workqueue, &hdev->cmd_work);
return;
}
err = hci_send_frame(hdev, skb);
if (err < 0) {
hci_cmd_sync_cancel_sync(hdev, err);
return;
}
if (hci_req_status_pend(hdev) &&
!hci_dev_test_and_set_flag(hdev, HCI_CMD_PENDING)) {
kfree_skb(hdev->req_skb);
hdev->req_skb = skb_clone(hdev->sent_cmd, GFP_KERNEL);
}
atomic_dec(&hdev->cmd_cnt);
}
static void hci_cmd_work(struct work_struct *work)
{
struct hci_dev *hdev = container_of(work, struct hci_dev, cmd_work);
@ -4142,30 +4237,15 @@ static void hci_cmd_work(struct work_struct *work)
if (!skb)
return;
kfree_skb(hdev->sent_cmd);
hci_send_cmd_sync(hdev, skb);
hdev->sent_cmd = skb_clone(skb, GFP_KERNEL);
if (hdev->sent_cmd) {
int res;
if (hci_req_status_pend(hdev))
hci_dev_set_flag(hdev, HCI_CMD_PENDING);
atomic_dec(&hdev->cmd_cnt);
res = hci_send_frame(hdev, skb);
if (res < 0)
__hci_cmd_sync_cancel(hdev, -res);
rcu_read_lock();
if (test_bit(HCI_RESET, &hdev->flags) ||
hci_dev_test_flag(hdev, HCI_CMD_DRAIN_WORKQUEUE))
cancel_delayed_work(&hdev->cmd_timer);
else
queue_delayed_work(hdev->workqueue, &hdev->cmd_timer,
HCI_CMD_TIMEOUT);
rcu_read_unlock();
} else {
skb_queue_head(&hdev->cmd_q, skb);
queue_work(hdev->workqueue, &hdev->cmd_work);
}
rcu_read_lock();
if (test_bit(HCI_RESET, &hdev->flags) ||
hci_dev_test_flag(hdev, HCI_CMD_DRAIN_WORKQUEUE))
cancel_delayed_work(&hdev->cmd_timer);
else
queue_delayed_work(hdev->workqueue, &hdev->cmd_timer,
HCI_CMD_TIMEOUT);
rcu_read_unlock();
}
}

View File

@ -36,8 +36,6 @@
#include "hci_request.h"
#include "hci_debugfs.h"
#include "hci_codec.h"
#include "a2mp.h"
#include "amp.h"
#include "smp.h"
#include "msft.h"
#include "eir.h"
@ -95,11 +93,11 @@ static u8 hci_cc_inquiry_cancel(struct hci_dev *hdev, void *data,
/* It is possible that we receive Inquiry Complete event right
* before we receive Inquiry Cancel Command Complete event, in
* which case the latter event should have status of Command
* Disallowed (0x0c). This should not be treated as error, since
* Disallowed. This should not be treated as error, since
* we actually achieve what Inquiry Cancel wants to achieve,
* which is to end the last Inquiry session.
*/
if (rp->status == 0x0c && !test_bit(HCI_INQUIRY, &hdev->flags)) {
if (rp->status == HCI_ERROR_COMMAND_DISALLOWED && !test_bit(HCI_INQUIRY, &hdev->flags)) {
bt_dev_warn(hdev, "Ignoring error of Inquiry Cancel command");
rp->status = 0x00;
}
@ -120,8 +118,6 @@ static u8 hci_cc_inquiry_cancel(struct hci_dev *hdev, void *data,
hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
hci_dev_unlock(hdev);
hci_conn_check_pending(hdev);
return rp->status;
}
@ -152,8 +148,6 @@ static u8 hci_cc_exit_periodic_inq(struct hci_dev *hdev, void *data,
hci_dev_clear_flag(hdev, HCI_PERIODIC_INQ);
hci_conn_check_pending(hdev);
return rp->status;
}
@ -2314,10 +2308,8 @@ static void hci_cs_inquiry(struct hci_dev *hdev, __u8 status)
{
bt_dev_dbg(hdev, "status 0x%2.2x", status);
if (status) {
hci_conn_check_pending(hdev);
if (status)
return;
}
if (hci_sent_cmd_data(hdev, HCI_OP_INQUIRY))
set_bit(HCI_INQUIRY, &hdev->flags);
@ -2342,12 +2334,9 @@ static void hci_cs_create_conn(struct hci_dev *hdev, __u8 status)
if (status) {
if (conn && conn->state == BT_CONNECT) {
if (status != 0x0c || conn->attempt > 2) {
conn->state = BT_CLOSED;
hci_connect_cfm(conn, status);
hci_conn_del(conn);
} else
conn->state = BT_CONNECT2;
conn->state = BT_CLOSED;
hci_connect_cfm(conn, status);
hci_conn_del(conn);
}
} else {
if (!conn) {
@ -2526,9 +2515,7 @@ static void hci_check_pending_name(struct hci_dev *hdev, struct hci_conn *conn,
* Only those in BT_CONFIG or BT_CONNECTED states can be
* considered connected.
*/
if (conn &&
(conn->state == BT_CONFIG || conn->state == BT_CONNECTED) &&
!test_and_set_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags))
if (conn && (conn->state == BT_CONFIG || conn->state == BT_CONNECTED))
mgmt_device_connected(hdev, conn, name, name_len);
if (discov->state == DISCOVERY_STOPPED)
@ -3039,8 +3026,6 @@ static void hci_inquiry_complete_evt(struct hci_dev *hdev, void *data,
bt_dev_dbg(hdev, "status 0x%2.2x", ev->status);
hci_conn_check_pending(hdev);
if (!test_and_clear_bit(HCI_INQUIRY, &hdev->flags))
return;
@ -3262,8 +3247,6 @@ done:
unlock:
hci_dev_unlock(hdev);
hci_conn_check_pending(hdev);
}
static void hci_reject_conn(struct hci_dev *hdev, bdaddr_t *bdaddr)
@ -3556,8 +3539,6 @@ static void hci_remote_name_evt(struct hci_dev *hdev, void *data,
bt_dev_dbg(hdev, "status 0x%2.2x", ev->status);
hci_conn_check_pending(hdev);
hci_dev_lock(hdev);
conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
@ -3660,7 +3641,8 @@ static void hci_encrypt_change_evt(struct hci_dev *hdev, void *data,
* controller really supports it. If it doesn't, assume
* the default size (16).
*/
if (!(hdev->commands[20] & 0x10)) {
if (!(hdev->commands[20] & 0x10) ||
test_bit(HCI_QUIRK_BROKEN_READ_ENC_KEY_SIZE, &hdev->quirks)) {
conn->enc_key_size = HCI_LINK_KEY_SIZE;
goto notify;
}
@ -3762,8 +3744,9 @@ static void hci_remote_features_evt(struct hci_dev *hdev, void *data,
bacpy(&cp.bdaddr, &conn->dst);
cp.pscan_rep_mode = 0x02;
hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ, sizeof(cp), &cp);
} else if (!test_and_set_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags))
} else {
mgmt_device_connected(hdev, conn, NULL, 0);
}
if (!hci_outgoing_auth_needed(hdev, conn)) {
conn->state = BT_CONNECTED;
@ -3936,6 +3919,11 @@ static u8 hci_cc_le_setup_iso_path(struct hci_dev *hdev, void *data,
* last.
*/
hci_connect_cfm(conn, rp->status);
/* Notify device connected in case it is a BIG Sync */
if (!rp->status && test_bit(HCI_CONN_BIG_SYNC, &conn->flags))
mgmt_device_connected(hdev, conn, NULL, 0);
break;
}
@ -4381,7 +4369,7 @@ static void hci_cmd_status_evt(struct hci_dev *hdev, void *data,
* (since for this kind of commands there will not be a command
* complete event).
*/
if (ev->status || (hdev->sent_cmd && !hci_skb_event(hdev->sent_cmd))) {
if (ev->status || (hdev->req_skb && !hci_skb_event(hdev->req_skb))) {
hci_req_cmd_complete(hdev, *opcode, ev->status, req_complete,
req_complete_skb);
if (hci_dev_test_flag(hdev, HCI_CMD_PENDING)) {
@ -5010,8 +4998,9 @@ static void hci_remote_ext_features_evt(struct hci_dev *hdev, void *data,
bacpy(&cp.bdaddr, &conn->dst);
cp.pscan_rep_mode = 0x02;
hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ, sizeof(cp), &cp);
} else if (!test_and_set_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags))
} else {
mgmt_device_connected(hdev, conn, NULL, 0);
}
if (!hci_outgoing_auth_needed(hdev, conn)) {
conn->state = BT_CONNECTED;
@ -5675,150 +5664,6 @@ unlock:
hci_dev_unlock(hdev);
}
#if IS_ENABLED(CONFIG_BT_HS)
static void hci_chan_selected_evt(struct hci_dev *hdev, void *data,
struct sk_buff *skb)
{
struct hci_ev_channel_selected *ev = data;
struct hci_conn *hcon;
bt_dev_dbg(hdev, "handle 0x%2.2x", ev->phy_handle);
hcon = hci_conn_hash_lookup_handle(hdev, ev->phy_handle);
if (!hcon)
return;
amp_read_loc_assoc_final_data(hdev, hcon);
}
static void hci_phy_link_complete_evt(struct hci_dev *hdev, void *data,
struct sk_buff *skb)
{
struct hci_ev_phy_link_complete *ev = data;
struct hci_conn *hcon, *bredr_hcon;
bt_dev_dbg(hdev, "handle 0x%2.2x status 0x%2.2x", ev->phy_handle,
ev->status);
hci_dev_lock(hdev);
hcon = hci_conn_hash_lookup_handle(hdev, ev->phy_handle);
if (!hcon)
goto unlock;
if (!hcon->amp_mgr)
goto unlock;
if (ev->status) {
hci_conn_del(hcon);
goto unlock;
}
bredr_hcon = hcon->amp_mgr->l2cap_conn->hcon;
hcon->state = BT_CONNECTED;
bacpy(&hcon->dst, &bredr_hcon->dst);
hci_conn_hold(hcon);
hcon->disc_timeout = HCI_DISCONN_TIMEOUT;
hci_conn_drop(hcon);
hci_debugfs_create_conn(hcon);
hci_conn_add_sysfs(hcon);
amp_physical_cfm(bredr_hcon, hcon);
unlock:
hci_dev_unlock(hdev);
}
static void hci_loglink_complete_evt(struct hci_dev *hdev, void *data,
struct sk_buff *skb)
{
struct hci_ev_logical_link_complete *ev = data;
struct hci_conn *hcon;
struct hci_chan *hchan;
struct amp_mgr *mgr;
bt_dev_dbg(hdev, "log_handle 0x%4.4x phy_handle 0x%2.2x status 0x%2.2x",
le16_to_cpu(ev->handle), ev->phy_handle, ev->status);
hcon = hci_conn_hash_lookup_handle(hdev, ev->phy_handle);
if (!hcon)
return;
/* Create AMP hchan */
hchan = hci_chan_create(hcon);
if (!hchan)
return;
hchan->handle = le16_to_cpu(ev->handle);
hchan->amp = true;
BT_DBG("hcon %p mgr %p hchan %p", hcon, hcon->amp_mgr, hchan);
mgr = hcon->amp_mgr;
if (mgr && mgr->bredr_chan) {
struct l2cap_chan *bredr_chan = mgr->bredr_chan;
l2cap_chan_lock(bredr_chan);
bredr_chan->conn->mtu = hdev->block_mtu;
l2cap_logical_cfm(bredr_chan, hchan, 0);
hci_conn_hold(hcon);
l2cap_chan_unlock(bredr_chan);
}
}
static void hci_disconn_loglink_complete_evt(struct hci_dev *hdev, void *data,
struct sk_buff *skb)
{
struct hci_ev_disconn_logical_link_complete *ev = data;
struct hci_chan *hchan;
bt_dev_dbg(hdev, "handle 0x%4.4x status 0x%2.2x",
le16_to_cpu(ev->handle), ev->status);
if (ev->status)
return;
hci_dev_lock(hdev);
hchan = hci_chan_lookup_handle(hdev, le16_to_cpu(ev->handle));
if (!hchan || !hchan->amp)
goto unlock;
amp_destroy_logical_link(hchan, ev->reason);
unlock:
hci_dev_unlock(hdev);
}
static void hci_disconn_phylink_complete_evt(struct hci_dev *hdev, void *data,
struct sk_buff *skb)
{
struct hci_ev_disconn_phy_link_complete *ev = data;
struct hci_conn *hcon;
bt_dev_dbg(hdev, "status 0x%2.2x", ev->status);
if (ev->status)
return;
hci_dev_lock(hdev);
hcon = hci_conn_hash_lookup_handle(hdev, ev->phy_handle);
if (hcon && hcon->type == AMP_LINK) {
hcon->state = BT_CLOSED;
hci_disconn_cfm(hcon, ev->reason);
hci_conn_del(hcon);
}
hci_dev_unlock(hdev);
}
#endif
static void le_conn_update_addr(struct hci_conn *conn, bdaddr_t *bdaddr,
u8 bdaddr_type, bdaddr_t *local_rpa)
{
@ -5984,8 +5829,7 @@ static void le_conn_complete_evt(struct hci_dev *hdev, u8 status,
goto unlock;
}
if (!test_and_set_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags))
mgmt_device_connected(hdev, conn, NULL, 0);
mgmt_device_connected(hdev, conn, NULL, 0);
conn->sec_level = BT_SECURITY_LOW;
conn->state = BT_CONFIG;
@ -6684,7 +6528,7 @@ static void hci_le_remote_feat_complete_evt(struct hci_dev *hdev, void *data,
* transition into connected state and mark it as
* successful.
*/
if (!conn->out && ev->status == 0x1a &&
if (!conn->out && ev->status == HCI_ERROR_UNSUPPORTED_REMOTE_FEATURE &&
(hdev->le_features[0] & HCI_LE_PERIPHERAL_FEATURES))
status = 0x00;
else
@ -7214,6 +7058,9 @@ static void hci_le_big_info_adv_report_evt(struct hci_dev *hdev, void *data,
/* Notify iso layer */
hci_connect_cfm(pa_sync, 0x00);
/* Notify MGMT layer */
mgmt_device_connected(hdev, pa_sync, NULL, 0);
unlock:
hci_dev_unlock(hdev);
}
@ -7324,10 +7171,10 @@ static void hci_le_meta_evt(struct hci_dev *hdev, void *data,
bt_dev_dbg(hdev, "subevent 0x%2.2x", ev->subevent);
/* Only match event if command OGF is for LE */
if (hdev->sent_cmd &&
hci_opcode_ogf(hci_skb_opcode(hdev->sent_cmd)) == 0x08 &&
hci_skb_event(hdev->sent_cmd) == ev->subevent) {
*opcode = hci_skb_opcode(hdev->sent_cmd);
if (hdev->req_skb &&
hci_opcode_ogf(hci_skb_opcode(hdev->req_skb)) == 0x08 &&
hci_skb_event(hdev->req_skb) == ev->subevent) {
*opcode = hci_skb_opcode(hdev->req_skb);
hci_req_cmd_complete(hdev, *opcode, 0x00, req_complete,
req_complete_skb);
}
@ -7626,25 +7473,6 @@ static const struct hci_ev {
/* [0x3e = HCI_EV_LE_META] */
HCI_EV_REQ_VL(HCI_EV_LE_META, hci_le_meta_evt,
sizeof(struct hci_ev_le_meta), HCI_MAX_EVENT_SIZE),
#if IS_ENABLED(CONFIG_BT_HS)
/* [0x40 = HCI_EV_PHY_LINK_COMPLETE] */
HCI_EV(HCI_EV_PHY_LINK_COMPLETE, hci_phy_link_complete_evt,
sizeof(struct hci_ev_phy_link_complete)),
/* [0x41 = HCI_EV_CHANNEL_SELECTED] */
HCI_EV(HCI_EV_CHANNEL_SELECTED, hci_chan_selected_evt,
sizeof(struct hci_ev_channel_selected)),
/* [0x42 = HCI_EV_DISCONN_PHY_LINK_COMPLETE] */
HCI_EV(HCI_EV_DISCONN_LOGICAL_LINK_COMPLETE,
hci_disconn_loglink_complete_evt,
sizeof(struct hci_ev_disconn_logical_link_complete)),
/* [0x45 = HCI_EV_LOGICAL_LINK_COMPLETE] */
HCI_EV(HCI_EV_LOGICAL_LINK_COMPLETE, hci_loglink_complete_evt,
sizeof(struct hci_ev_logical_link_complete)),
/* [0x46 = HCI_EV_DISCONN_LOGICAL_LINK_COMPLETE] */
HCI_EV(HCI_EV_DISCONN_PHY_LINK_COMPLETE,
hci_disconn_phylink_complete_evt,
sizeof(struct hci_ev_disconn_phy_link_complete)),
#endif
/* [0x48 = HCI_EV_NUM_COMP_BLOCKS] */
HCI_EV(HCI_EV_NUM_COMP_BLOCKS, hci_num_comp_blocks_evt,
sizeof(struct hci_ev_num_comp_blocks)),
@ -7714,10 +7542,10 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
}
/* Only match event if command OGF is not for LE */
if (hdev->sent_cmd &&
hci_opcode_ogf(hci_skb_opcode(hdev->sent_cmd)) != 0x08 &&
hci_skb_event(hdev->sent_cmd) == event) {
hci_req_cmd_complete(hdev, hci_skb_opcode(hdev->sent_cmd),
if (hdev->req_skb &&
hci_opcode_ogf(hci_skb_opcode(hdev->req_skb)) != 0x08 &&
hci_skb_event(hdev->req_skb) == event) {
hci_req_cmd_complete(hdev, hci_skb_opcode(hdev->req_skb),
status, &req_complete, &req_complete_skb);
req_evt = event;
}

View File

@ -895,7 +895,7 @@ void hci_request_setup(struct hci_dev *hdev)
void hci_request_cancel_all(struct hci_dev *hdev)
{
__hci_cmd_sync_cancel(hdev, ENODEV);
hci_cmd_sync_cancel_sync(hdev, ENODEV);
cancel_interleave_scan(hdev);
}

View File

@ -101,7 +101,7 @@ static bool hci_sock_gen_cookie(struct sock *sk)
int id = hci_pi(sk)->cookie;
if (!id) {
id = ida_simple_get(&sock_cookie_ida, 1, 0, GFP_KERNEL);
id = ida_alloc_min(&sock_cookie_ida, 1, GFP_KERNEL);
if (id < 0)
id = 0xffffffff;
@ -119,7 +119,7 @@ static void hci_sock_free_cookie(struct sock *sk)
if (id) {
hci_pi(sk)->cookie = 0xffffffff;
ida_simple_remove(&sock_cookie_ida, id);
ida_free(&sock_cookie_ida, id);
}
}

View File

@ -32,6 +32,10 @@ static void hci_cmd_sync_complete(struct hci_dev *hdev, u8 result, u16 opcode,
hdev->req_result = result;
hdev->req_status = HCI_REQ_DONE;
/* Free the request command so it is not used as response */
kfree_skb(hdev->req_skb);
hdev->req_skb = NULL;
if (skb) {
struct sock *sk = hci_skb_sk(skb);
@ -39,7 +43,7 @@ static void hci_cmd_sync_complete(struct hci_dev *hdev, u8 result, u16 opcode,
if (sk)
sock_put(sk);
hdev->req_skb = skb_get(skb);
hdev->req_rsp = skb_get(skb);
}
wake_up_interruptible(&hdev->req_wait_q);
@ -187,8 +191,8 @@ struct sk_buff *__hci_cmd_sync_sk(struct hci_dev *hdev, u16 opcode, u32 plen,
hdev->req_status = 0;
hdev->req_result = 0;
skb = hdev->req_skb;
hdev->req_skb = NULL;
skb = hdev->req_rsp;
hdev->req_rsp = NULL;
bt_dev_dbg(hdev, "end: err %d", err);
@ -566,6 +570,17 @@ void hci_cmd_sync_init(struct hci_dev *hdev)
INIT_DELAYED_WORK(&hdev->adv_instance_expire, adv_timeout_expire);
}
static void _hci_cmd_sync_cancel_entry(struct hci_dev *hdev,
struct hci_cmd_sync_work_entry *entry,
int err)
{
if (entry->destroy)
entry->destroy(hdev, entry->data, err);
list_del(&entry->list);
kfree(entry);
}
void hci_cmd_sync_clear(struct hci_dev *hdev)
{
struct hci_cmd_sync_work_entry *entry, *tmp;
@ -574,32 +589,11 @@ void hci_cmd_sync_clear(struct hci_dev *hdev)
cancel_work_sync(&hdev->reenable_adv_work);
mutex_lock(&hdev->cmd_sync_work_lock);
list_for_each_entry_safe(entry, tmp, &hdev->cmd_sync_work_list, list) {
if (entry->destroy)
entry->destroy(hdev, entry->data, -ECANCELED);
list_del(&entry->list);
kfree(entry);
}
list_for_each_entry_safe(entry, tmp, &hdev->cmd_sync_work_list, list)
_hci_cmd_sync_cancel_entry(hdev, entry, -ECANCELED);
mutex_unlock(&hdev->cmd_sync_work_lock);
}
void __hci_cmd_sync_cancel(struct hci_dev *hdev, int err)
{
bt_dev_dbg(hdev, "err 0x%2.2x", err);
if (hdev->req_status == HCI_REQ_PEND) {
hdev->req_result = err;
hdev->req_status = HCI_REQ_CANCELED;
cancel_delayed_work_sync(&hdev->cmd_timer);
cancel_delayed_work_sync(&hdev->ncmd_timer);
atomic_set(&hdev->cmd_cnt, 1);
wake_up_interruptible(&hdev->req_wait_q);
}
}
void hci_cmd_sync_cancel(struct hci_dev *hdev, int err)
{
bt_dev_dbg(hdev, "err 0x%2.2x", err);
@ -613,6 +607,24 @@ void hci_cmd_sync_cancel(struct hci_dev *hdev, int err)
}
EXPORT_SYMBOL(hci_cmd_sync_cancel);
/* Cancel ongoing command request synchronously:
*
* - Set result and mark status to HCI_REQ_CANCELED
* - Wakeup command sync thread
*/
void hci_cmd_sync_cancel_sync(struct hci_dev *hdev, int err)
{
bt_dev_dbg(hdev, "err 0x%2.2x", err);
if (hdev->req_status == HCI_REQ_PEND) {
hdev->req_result = err;
hdev->req_status = HCI_REQ_CANCELED;
wake_up_interruptible(&hdev->req_wait_q);
}
}
EXPORT_SYMBOL(hci_cmd_sync_cancel_sync);
/* Submit HCI command to be run in as cmd_sync_work:
*
* - hdev must _not_ be unregistered
@ -667,6 +679,115 @@ int hci_cmd_sync_queue(struct hci_dev *hdev, hci_cmd_sync_work_func_t func,
}
EXPORT_SYMBOL(hci_cmd_sync_queue);
static struct hci_cmd_sync_work_entry *
_hci_cmd_sync_lookup_entry(struct hci_dev *hdev, hci_cmd_sync_work_func_t func,
void *data, hci_cmd_sync_work_destroy_t destroy)
{
struct hci_cmd_sync_work_entry *entry, *tmp;
list_for_each_entry_safe(entry, tmp, &hdev->cmd_sync_work_list, list) {
if (func && entry->func != func)
continue;
if (data && entry->data != data)
continue;
if (destroy && entry->destroy != destroy)
continue;
return entry;
}
return NULL;
}
/* Queue HCI command entry once:
*
* - Lookup if an entry already exist and only if it doesn't creates a new entry
* and queue it.
*/
int hci_cmd_sync_queue_once(struct hci_dev *hdev, hci_cmd_sync_work_func_t func,
void *data, hci_cmd_sync_work_destroy_t destroy)
{
if (hci_cmd_sync_lookup_entry(hdev, func, data, destroy))
return 0;
return hci_cmd_sync_queue(hdev, func, data, destroy);
}
EXPORT_SYMBOL(hci_cmd_sync_queue_once);
/* Lookup HCI command entry:
*
* - Return first entry that matches by function callback or data or
* destroy callback.
*/
struct hci_cmd_sync_work_entry *
hci_cmd_sync_lookup_entry(struct hci_dev *hdev, hci_cmd_sync_work_func_t func,
void *data, hci_cmd_sync_work_destroy_t destroy)
{
struct hci_cmd_sync_work_entry *entry;
mutex_lock(&hdev->cmd_sync_work_lock);
entry = _hci_cmd_sync_lookup_entry(hdev, func, data, destroy);
mutex_unlock(&hdev->cmd_sync_work_lock);
return entry;
}
EXPORT_SYMBOL(hci_cmd_sync_lookup_entry);
/* Cancel HCI command entry */
void hci_cmd_sync_cancel_entry(struct hci_dev *hdev,
struct hci_cmd_sync_work_entry *entry)
{
mutex_lock(&hdev->cmd_sync_work_lock);
_hci_cmd_sync_cancel_entry(hdev, entry, -ECANCELED);
mutex_unlock(&hdev->cmd_sync_work_lock);
}
EXPORT_SYMBOL(hci_cmd_sync_cancel_entry);
/* Dequeue one HCI command entry:
*
* - Lookup and cancel first entry that matches.
*/
bool hci_cmd_sync_dequeue_once(struct hci_dev *hdev,
hci_cmd_sync_work_func_t func,
void *data, hci_cmd_sync_work_destroy_t destroy)
{
struct hci_cmd_sync_work_entry *entry;
entry = hci_cmd_sync_lookup_entry(hdev, func, data, destroy);
if (!entry)
return false;
hci_cmd_sync_cancel_entry(hdev, entry);
return true;
}
EXPORT_SYMBOL(hci_cmd_sync_dequeue_once);
/* Dequeue HCI command entry:
*
* - Lookup and cancel any entry that matches by function callback or data or
* destroy callback.
*/
bool hci_cmd_sync_dequeue(struct hci_dev *hdev, hci_cmd_sync_work_func_t func,
void *data, hci_cmd_sync_work_destroy_t destroy)
{
struct hci_cmd_sync_work_entry *entry;
bool ret = false;
mutex_lock(&hdev->cmd_sync_work_lock);
while ((entry = _hci_cmd_sync_lookup_entry(hdev, func, data,
destroy))) {
_hci_cmd_sync_cancel_entry(hdev, entry, -ECANCELED);
ret = true;
}
mutex_unlock(&hdev->cmd_sync_work_lock);
return ret;
}
EXPORT_SYMBOL(hci_cmd_sync_dequeue);
int hci_update_eir_sync(struct hci_dev *hdev)
{
struct hci_cp_write_eir cp;
@ -2445,6 +2566,16 @@ static struct conn_params *conn_params_copy(struct list_head *list, size_t *n)
return p;
}
/* Clear LE Accept List */
static int hci_le_clear_accept_list_sync(struct hci_dev *hdev)
{
if (!(hdev->commands[26] & 0x80))
return 0;
return __hci_cmd_sync_status(hdev, HCI_OP_LE_CLEAR_ACCEPT_LIST, 0, NULL,
HCI_CMD_TIMEOUT);
}
/* Device must not be scanning when updating the accept list.
*
* Update is done using the following sequence:
@ -2493,6 +2624,31 @@ static u8 hci_update_accept_list_sync(struct hci_dev *hdev)
goto done;
}
/* Force address filtering if PA Sync is in progress */
if (hci_dev_test_flag(hdev, HCI_PA_SYNC)) {
struct hci_cp_le_pa_create_sync *sent;
sent = hci_sent_cmd_data(hdev, HCI_OP_LE_PA_CREATE_SYNC);
if (sent) {
struct conn_params pa;
memset(&pa, 0, sizeof(pa));
bacpy(&pa.addr, &sent->addr);
pa.addr_type = sent->addr_type;
/* Clear first since there could be addresses left
* behind.
*/
hci_le_clear_accept_list_sync(hdev);
num_entries = 1;
err = hci_le_add_accept_list_sync(hdev, &pa,
&num_entries);
goto done;
}
}
/* Go through the current accept list programmed into the
* controller one by one and check if that address is connected or is
* still in the list of pending connections or list of devices to
@ -2602,6 +2758,14 @@ done:
return filter_policy;
}
static void hci_le_scan_phy_params(struct hci_cp_le_scan_phy_params *cp,
u8 type, u16 interval, u16 window)
{
cp->type = type;
cp->interval = cpu_to_le16(interval);
cp->window = cpu_to_le16(window);
}
static int hci_le_set_ext_scan_param_sync(struct hci_dev *hdev, u8 type,
u16 interval, u16 window,
u8 own_addr_type, u8 filter_policy)
@ -2609,7 +2773,7 @@ static int hci_le_set_ext_scan_param_sync(struct hci_dev *hdev, u8 type,
struct hci_cp_le_set_ext_scan_params *cp;
struct hci_cp_le_scan_phy_params *phy;
u8 data[sizeof(*cp) + sizeof(*phy) * 2];
u8 num_phy = 0;
u8 num_phy = 0x00;
cp = (void *)data;
phy = (void *)cp->data;
@ -2619,28 +2783,64 @@ static int hci_le_set_ext_scan_param_sync(struct hci_dev *hdev, u8 type,
cp->own_addr_type = own_addr_type;
cp->filter_policy = filter_policy;
/* Check if PA Sync is in progress then select the PHY based on the
* hci_conn.iso_qos.
*/
if (hci_dev_test_flag(hdev, HCI_PA_SYNC)) {
struct hci_cp_le_add_to_accept_list *sent;
sent = hci_sent_cmd_data(hdev, HCI_OP_LE_ADD_TO_ACCEPT_LIST);
if (sent) {
struct hci_conn *conn;
conn = hci_conn_hash_lookup_ba(hdev, ISO_LINK,
&sent->bdaddr);
if (conn) {
struct bt_iso_qos *qos = &conn->iso_qos;
if (qos->bcast.in.phy & BT_ISO_PHY_1M ||
qos->bcast.in.phy & BT_ISO_PHY_2M) {
cp->scanning_phys |= LE_SCAN_PHY_1M;
hci_le_scan_phy_params(phy, type,
interval,
window);
num_phy++;
phy++;
}
if (qos->bcast.in.phy & BT_ISO_PHY_CODED) {
cp->scanning_phys |= LE_SCAN_PHY_CODED;
hci_le_scan_phy_params(phy, type,
interval,
window);
num_phy++;
phy++;
}
if (num_phy)
goto done;
}
}
}
if (scan_1m(hdev) || scan_2m(hdev)) {
cp->scanning_phys |= LE_SCAN_PHY_1M;
phy->type = type;
phy->interval = cpu_to_le16(interval);
phy->window = cpu_to_le16(window);
hci_le_scan_phy_params(phy, type, interval, window);
num_phy++;
phy++;
}
if (scan_coded(hdev)) {
cp->scanning_phys |= LE_SCAN_PHY_CODED;
phy->type = type;
phy->interval = cpu_to_le16(interval);
phy->window = cpu_to_le16(window);
hci_le_scan_phy_params(phy, type, interval, window);
num_phy++;
phy++;
}
done:
if (!num_phy)
return -EINVAL;
return __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_EXT_SCAN_PARAMS,
sizeof(*cp) + sizeof(*phy) * num_phy,
data, HCI_CMD_TIMEOUT);
@ -2879,7 +3079,8 @@ int hci_update_passive_scan(struct hci_dev *hdev)
hci_dev_test_flag(hdev, HCI_UNREGISTER))
return 0;
return hci_cmd_sync_queue(hdev, update_passive_scan_sync, NULL, NULL);
return hci_cmd_sync_queue_once(hdev, update_passive_scan_sync, NULL,
NULL);
}
int hci_write_sc_support_sync(struct hci_dev *hdev, u8 val)
@ -4098,16 +4299,6 @@ static int hci_le_read_accept_list_size_sync(struct hci_dev *hdev)
0, NULL, HCI_CMD_TIMEOUT);
}
/* Clear LE Accept List */
static int hci_le_clear_accept_list_sync(struct hci_dev *hdev)
{
if (!(hdev->commands[26] & 0x80))
return 0;
return __hci_cmd_sync_status(hdev, HCI_OP_LE_CLEAR_ACCEPT_LIST, 0, NULL,
HCI_CMD_TIMEOUT);
}
/* Read LE Resolving List Size */
static int hci_le_read_resolv_list_size_sync(struct hci_dev *hdev)
{
@ -4834,6 +5025,11 @@ int hci_dev_open_sync(struct hci_dev *hdev)
hdev->sent_cmd = NULL;
}
if (hdev->req_skb) {
kfree_skb(hdev->req_skb);
hdev->req_skb = NULL;
}
clear_bit(HCI_RUNNING, &hdev->flags);
hci_sock_dev_event(hdev, HCI_DEV_CLOSE);
@ -4994,6 +5190,12 @@ int hci_dev_close_sync(struct hci_dev *hdev)
hdev->sent_cmd = NULL;
}
/* Drop last request */
if (hdev->req_skb) {
kfree_skb(hdev->req_skb);
hdev->req_skb = NULL;
}
clear_bit(HCI_RUNNING, &hdev->flags);
hci_sock_dev_event(hdev, HCI_DEV_CLOSE);
@ -5403,27 +5605,33 @@ static int hci_power_off_sync(struct hci_dev *hdev)
if (!test_bit(HCI_UP, &hdev->flags))
return 0;
hci_dev_set_flag(hdev, HCI_POWERING_DOWN);
if (test_bit(HCI_ISCAN, &hdev->flags) ||
test_bit(HCI_PSCAN, &hdev->flags)) {
err = hci_write_scan_enable_sync(hdev, 0x00);
if (err)
return err;
goto out;
}
err = hci_clear_adv_sync(hdev, NULL, false);
if (err)
return err;
goto out;
err = hci_stop_discovery_sync(hdev);
if (err)
return err;
goto out;
/* Terminated due to Power Off */
err = hci_disconnect_all_sync(hdev, HCI_ERROR_REMOTE_POWER_OFF);
if (err)
return err;
goto out;
return hci_dev_close_sync(hdev);
err = hci_dev_close_sync(hdev);
out:
hci_dev_clear_flag(hdev, HCI_POWERING_DOWN);
return err;
}
int hci_set_powered_sync(struct hci_dev *hdev, u8 val)
@ -6161,12 +6369,21 @@ static int hci_le_ext_create_conn_sync(struct hci_dev *hdev,
conn->conn_timeout, NULL);
}
int hci_le_create_conn_sync(struct hci_dev *hdev, struct hci_conn *conn)
static int hci_le_create_conn_sync(struct hci_dev *hdev, void *data)
{
struct hci_cp_le_create_conn cp;
struct hci_conn_params *params;
u8 own_addr_type;
int err;
struct hci_conn *conn = data;
if (!hci_conn_valid(hdev, conn))
return -ECANCELED;
bt_dev_dbg(hdev, "conn %p", conn);
clear_bit(HCI_CONN_SCANNING, &conn->flags);
conn->state = BT_CONNECT;
/* If requested to connect as peripheral use directed advertising */
if (conn->role == HCI_ROLE_SLAVE) {
@ -6484,3 +6701,125 @@ int hci_update_adv_data(struct hci_dev *hdev, u8 instance)
return hci_cmd_sync_queue(hdev, _update_adv_data_sync,
UINT_PTR(instance), NULL);
}
static int hci_acl_create_conn_sync(struct hci_dev *hdev, void *data)
{
struct hci_conn *conn = data;
struct inquiry_entry *ie;
struct hci_cp_create_conn cp;
int err;
if (!hci_conn_valid(hdev, conn))
return -ECANCELED;
/* Many controllers disallow HCI Create Connection while it is doing
* HCI Inquiry. So we cancel the Inquiry first before issuing HCI Create
* Connection. This may cause the MGMT discovering state to become false
* without user space's request but it is okay since the MGMT Discovery
* APIs do not promise that discovery should be done forever. Instead,
* the user space monitors the status of MGMT discovering and it may
* request for discovery again when this flag becomes false.
*/
if (test_bit(HCI_INQUIRY, &hdev->flags)) {
err = __hci_cmd_sync_status(hdev, HCI_OP_INQUIRY_CANCEL, 0,
NULL, HCI_CMD_TIMEOUT);
if (err)
bt_dev_warn(hdev, "Failed to cancel inquiry %d", err);
}
conn->state = BT_CONNECT;
conn->out = true;
conn->role = HCI_ROLE_MASTER;
conn->attempt++;
conn->link_policy = hdev->link_policy;
memset(&cp, 0, sizeof(cp));
bacpy(&cp.bdaddr, &conn->dst);
cp.pscan_rep_mode = 0x02;
ie = hci_inquiry_cache_lookup(hdev, &conn->dst);
if (ie) {
if (inquiry_entry_age(ie) <= INQUIRY_ENTRY_AGE_MAX) {
cp.pscan_rep_mode = ie->data.pscan_rep_mode;
cp.pscan_mode = ie->data.pscan_mode;
cp.clock_offset = ie->data.clock_offset |
cpu_to_le16(0x8000);
}
memcpy(conn->dev_class, ie->data.dev_class, 3);
}
cp.pkt_type = cpu_to_le16(conn->pkt_type);
if (lmp_rswitch_capable(hdev) && !(hdev->link_mode & HCI_LM_MASTER))
cp.role_switch = 0x01;
else
cp.role_switch = 0x00;
return __hci_cmd_sync_status_sk(hdev, HCI_OP_CREATE_CONN,
sizeof(cp), &cp,
HCI_EV_CONN_COMPLETE,
conn->conn_timeout, NULL);
}
int hci_connect_acl_sync(struct hci_dev *hdev, struct hci_conn *conn)
{
return hci_cmd_sync_queue_once(hdev, hci_acl_create_conn_sync, conn,
NULL);
}
static void create_le_conn_complete(struct hci_dev *hdev, void *data, int err)
{
struct hci_conn *conn = data;
bt_dev_dbg(hdev, "err %d", err);
if (err == -ECANCELED)
return;
hci_dev_lock(hdev);
if (!hci_conn_valid(hdev, conn))
goto done;
if (!err) {
hci_connect_le_scan_cleanup(conn, 0x00);
goto done;
}
/* Check if connection is still pending */
if (conn != hci_lookup_le_connect(hdev))
goto done;
/* Flush to make sure we send create conn cancel command if needed */
flush_delayed_work(&conn->le_conn_timeout);
hci_conn_failed(conn, bt_status(err));
done:
hci_dev_unlock(hdev);
}
int hci_connect_le_sync(struct hci_dev *hdev, struct hci_conn *conn)
{
return hci_cmd_sync_queue_once(hdev, hci_le_create_conn_sync, conn,
create_le_conn_complete);
}
int hci_cancel_connect_sync(struct hci_dev *hdev, struct hci_conn *conn)
{
if (conn->state != BT_OPEN)
return -EINVAL;
switch (conn->type) {
case ACL_LINK:
return !hci_cmd_sync_dequeue_once(hdev,
hci_acl_create_conn_sync,
conn, NULL);
case LE_LINK:
return !hci_cmd_sync_dequeue_once(hdev, hci_le_create_conn_sync,
conn, create_le_conn_complete);
}
return -ENOENT;
}

View File

@ -3,7 +3,7 @@
* BlueZ - Bluetooth protocol stack for Linux
*
* Copyright (C) 2022 Intel Corporation
* Copyright 2023 NXP
* Copyright 2023-2024 NXP
*/
#include <linux/module.h>
@ -690,11 +690,8 @@ static void iso_sock_cleanup_listen(struct sock *parent)
iso_sock_kill(sk);
}
/* If listening socket stands for a PA sync connection,
* properly disconnect the hcon and socket.
*/
if (iso_pi(parent)->conn && iso_pi(parent)->conn->hcon &&
test_bit(HCI_CONN_PA_SYNC, &iso_pi(parent)->conn->hcon->flags)) {
/* If listening socket has a hcon, properly disconnect it */
if (iso_pi(parent)->conn && iso_pi(parent)->conn->hcon) {
iso_sock_disconn(parent);
return;
}
@ -837,10 +834,10 @@ static struct bt_iso_qos default_qos = {
.bcode = {0x00},
.options = 0x00,
.skip = 0x0000,
.sync_timeout = 0x4000,
.sync_timeout = BT_ISO_SYNC_TIMEOUT,
.sync_cte_type = 0x00,
.mse = 0x00,
.timeout = 0x4000,
.timeout = BT_ISO_SYNC_TIMEOUT,
},
};
@ -1076,6 +1073,8 @@ static int iso_listen_bis(struct sock *sk)
{
struct hci_dev *hdev;
int err = 0;
struct iso_conn *conn;
struct hci_conn *hcon;
BT_DBG("%pMR -> %pMR (SID 0x%2.2x)", &iso_pi(sk)->src,
&iso_pi(sk)->dst, iso_pi(sk)->bc_sid);
@ -1096,18 +1095,40 @@ static int iso_listen_bis(struct sock *sk)
if (!hdev)
return -EHOSTUNREACH;
hci_dev_lock(hdev);
/* Fail if user set invalid QoS */
if (iso_pi(sk)->qos_user_set && !check_bcast_qos(&iso_pi(sk)->qos)) {
iso_pi(sk)->qos = default_qos;
return -EINVAL;
err = -EINVAL;
goto unlock;
}
err = hci_pa_create_sync(hdev, &iso_pi(sk)->dst,
le_addr_type(iso_pi(sk)->dst_type),
iso_pi(sk)->bc_sid, &iso_pi(sk)->qos);
hcon = hci_pa_create_sync(hdev, &iso_pi(sk)->dst,
le_addr_type(iso_pi(sk)->dst_type),
iso_pi(sk)->bc_sid, &iso_pi(sk)->qos);
if (IS_ERR(hcon)) {
err = PTR_ERR(hcon);
goto unlock;
}
conn = iso_conn_add(hcon);
if (!conn) {
hci_conn_drop(hcon);
err = -ENOMEM;
goto unlock;
}
err = iso_chan_add(conn, sk, NULL);
if (err) {
hci_conn_drop(hcon);
goto unlock;
}
hci_dev_put(hdev);
unlock:
hci_dev_unlock(hdev);
return err;
}
@ -1889,7 +1910,6 @@ int iso_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 *flags)
struct hci_evt_le_big_info_adv_report *ev2;
struct hci_ev_le_per_adv_report *ev3;
struct sock *sk;
int lm = 0;
bt_dev_dbg(hdev, "bdaddr %pMR", bdaddr);
@ -1933,7 +1953,7 @@ int iso_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 *flags)
if (sk && test_bit(BT_SK_PA_SYNC_TERM,
&iso_pi(sk)->flags))
return lm;
return 0;
}
if (sk) {
@ -1961,16 +1981,58 @@ 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;
size_t base_len = 0;
u8 *base;
struct hci_conn *hcon;
sk = iso_get_sock_listen(&hdev->bdaddr, bdaddr,
iso_match_sync_handle_pa_report, ev3);
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)) {
if (!sk)
goto done;
hcon = iso_pi(sk)->conn->hcon;
if (!hcon)
goto done;
if (ev3->data_status == LE_PA_DATA_TRUNCATED) {
/* The controller was unable to retrieve PA data. */
memset(hcon->le_per_adv_data, 0,
HCI_MAX_PER_AD_TOT_LEN);
hcon->le_per_adv_data_len = 0;
hcon->le_per_adv_data_offset = 0;
goto done;
}
if (hcon->le_per_adv_data_offset + ev3->length >
HCI_MAX_PER_AD_TOT_LEN)
goto done;
memcpy(hcon->le_per_adv_data + hcon->le_per_adv_data_offset,
ev3->data, ev3->length);
hcon->le_per_adv_data_offset += ev3->length;
if (ev3->data_status == LE_PA_DATA_COMPLETE) {
/* All PA data has been received. */
hcon->le_per_adv_data_len =
hcon->le_per_adv_data_offset;
hcon->le_per_adv_data_offset = 0;
/* Extract BASE */
base = eir_get_service_data(hcon->le_per_adv_data,
hcon->le_per_adv_data_len,
EIR_BAA_SERVICE_UUID,
&base_len);
if (!base || base_len > BASE_MAX_LENGTH)
goto done;
memcpy(iso_pi(sk)->base, base, base_len);
iso_pi(sk)->base_len = base_len;
} else {
/* This is a PA data fragment. Keep pa_data_len set to 0
* until all data has been reassembled.
*/
hcon->le_per_adv_data_len = 0;
}
} else {
sk = iso_get_sock_listen(&hdev->bdaddr, BDADDR_ANY, NULL, NULL);
@ -1978,16 +2040,14 @@ int iso_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 *flags)
done:
if (!sk)
return lm;
lm |= HCI_LM_ACCEPT;
return 0;
if (test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags))
*flags |= HCI_PROTO_DEFER;
sock_put(sk);
return lm;
return HCI_LM_ACCEPT;
}
static void iso_connect_cfm(struct hci_conn *hcon, __u8 status)

File diff suppressed because it is too large Load Diff

View File

@ -254,7 +254,8 @@ static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr,
chan->mode = L2CAP_MODE_LE_FLOWCTL;
err = l2cap_chan_connect(chan, la.l2_psm, __le16_to_cpu(la.l2_cid),
&la.l2_bdaddr, la.l2_bdaddr_type);
&la.l2_bdaddr, la.l2_bdaddr_type,
sk->sk_sndtimeo);
if (err)
return err;
@ -1027,23 +1028,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname,
break;
}
if (opt > BT_CHANNEL_POLICY_AMP_PREFERRED) {
err = -EINVAL;
break;
}
if (chan->mode != L2CAP_MODE_ERTM &&
chan->mode != L2CAP_MODE_STREAMING) {
err = -EOPNOTSUPP;
break;
}
chan->chan_policy = (u8) opt;
if (sk->sk_state == BT_CONNECTED &&
chan->move_role == L2CAP_MOVE_ROLE_NONE)
l2cap_move_start(chan);
err = -EOPNOTSUPP;
break;
case BT_SNDMTU:

View File

@ -835,8 +835,6 @@ static u32 get_supported_settings(struct hci_dev *hdev)
if (lmp_ssp_capable(hdev)) {
settings |= MGMT_SETTING_SSP;
if (IS_ENABLED(CONFIG_BT_HS))
settings |= MGMT_SETTING_HS;
}
if (lmp_sc_capable(hdev))
@ -901,9 +899,6 @@ static u32 get_current_settings(struct hci_dev *hdev)
if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
settings |= MGMT_SETTING_SSP;
if (hci_dev_test_flag(hdev, HCI_HS_ENABLED))
settings |= MGMT_SETTING_HS;
if (hci_dev_test_flag(hdev, HCI_ADVERTISING))
settings |= MGMT_SETTING_ADVERTISING;
@ -1390,6 +1385,14 @@ static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
hci_dev_lock(hdev);
if (!cp->val) {
if (hci_dev_test_flag(hdev, HCI_POWERING_DOWN)) {
err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
MGMT_STATUS_BUSY);
goto failed;
}
}
if (pending_find(MGMT_OP_SET_POWERED, hdev)) {
err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
MGMT_STATUS_BUSY);
@ -1409,7 +1412,7 @@ static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
/* Cancel potentially blocking sync operation before power off */
if (cp->val == 0x00) {
__hci_cmd_sync_cancel(hdev, -EHOSTDOWN);
hci_cmd_sync_cancel_sync(hdev, -EHOSTDOWN);
err = hci_cmd_sync_queue(hdev, set_powered_sync, cmd,
mgmt_set_powered_complete);
} else {
@ -1704,8 +1707,7 @@ static void mgmt_set_connectable_complete(struct hci_dev *hdev, void *data,
new_settings(hdev, cmd->sk);
done:
if (cmd)
mgmt_pending_remove(cmd);
mgmt_pending_remove(cmd);
hci_dev_unlock(hdev);
}
@ -1930,7 +1932,6 @@ static void set_ssp_complete(struct hci_dev *hdev, void *data, int err)
if (enable && hci_dev_test_and_clear_flag(hdev,
HCI_SSP_ENABLED)) {
hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
new_settings(hdev, NULL);
}
@ -1943,12 +1944,6 @@ static void set_ssp_complete(struct hci_dev *hdev, void *data, int err)
changed = !hci_dev_test_and_set_flag(hdev, HCI_SSP_ENABLED);
} else {
changed = hci_dev_test_and_clear_flag(hdev, HCI_SSP_ENABLED);
if (!changed)
changed = hci_dev_test_and_clear_flag(hdev,
HCI_HS_ENABLED);
else
hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
}
mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
@ -2012,11 +2007,6 @@ static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
} else {
changed = hci_dev_test_and_clear_flag(hdev,
HCI_SSP_ENABLED);
if (!changed)
changed = hci_dev_test_and_clear_flag(hdev,
HCI_HS_ENABLED);
else
hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
}
err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
@ -2062,63 +2052,10 @@ failed:
static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
{
struct mgmt_mode *cp = data;
bool changed;
u8 status;
int err;
bt_dev_dbg(hdev, "sock %p", sk);
if (!IS_ENABLED(CONFIG_BT_HS))
return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
MGMT_STATUS_NOT_SUPPORTED);
status = mgmt_bredr_support(hdev);
if (status)
return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS, status);
if (!lmp_ssp_capable(hdev))
return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
MGMT_STATUS_NOT_SUPPORTED);
if (!hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
MGMT_STATUS_REJECTED);
if (cp->val != 0x00 && cp->val != 0x01)
return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
MGMT_STATUS_INVALID_PARAMS);
hci_dev_lock(hdev);
if (pending_find(MGMT_OP_SET_SSP, hdev)) {
err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
MGMT_STATUS_BUSY);
goto unlock;
}
if (cp->val) {
changed = !hci_dev_test_and_set_flag(hdev, HCI_HS_ENABLED);
} else {
if (hdev_is_powered(hdev)) {
err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
MGMT_STATUS_REJECTED);
goto unlock;
}
changed = hci_dev_test_and_clear_flag(hdev, HCI_HS_ENABLED);
}
err = send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
if (err < 0)
goto unlock;
if (changed)
err = new_settings(hdev, sk);
unlock:
hci_dev_unlock(hdev);
return err;
}
static void set_le_complete(struct hci_dev *hdev, void *data, int err)
@ -3188,6 +3125,7 @@ failed:
static u8 link_to_bdaddr(u8 link_type, u8 addr_type)
{
switch (link_type) {
case ISO_LINK:
case LE_LINK:
switch (addr_type) {
case ADDR_LE_DEV_PUBLIC:
@ -3505,7 +3443,8 @@ static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
if (cp->addr.type == BDADDR_BREDR) {
conn = hci_connect_acl(hdev, &cp->addr.bdaddr, sec_level,
auth_type, CONN_REASON_PAIR_DEVICE);
auth_type, CONN_REASON_PAIR_DEVICE,
HCI_ACL_CONN_TIMEOUT);
} else {
u8 addr_type = le_addr_type(cp->addr.type);
struct hci_conn_params *p;
@ -6766,7 +6705,6 @@ static int set_bredr(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
hci_dev_clear_flag(hdev, HCI_SSP_ENABLED);
hci_dev_clear_flag(hdev, HCI_LINK_SECURITY);
hci_dev_clear_flag(hdev, HCI_FAST_CONNECTABLE);
hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
}
hci_dev_change_flag(hdev, HCI_BREDR_ENABLED);
@ -8470,7 +8408,7 @@ static int read_adv_features(struct sock *sk, struct hci_dev *hdev,
static u8 calculate_name_len(struct hci_dev *hdev)
{
u8 buf[HCI_MAX_SHORT_NAME_LENGTH + 3];
u8 buf[HCI_MAX_SHORT_NAME_LENGTH + 2]; /* len + type + name */
return eir_append_local_name(hdev, buf, 0);
}
@ -8829,8 +8767,7 @@ static void add_ext_adv_params_complete(struct hci_dev *hdev, void *data,
}
unlock:
if (cmd)
mgmt_pending_free(cmd);
mgmt_pending_free(cmd);
hci_dev_unlock(hdev);
}
@ -9681,6 +9618,9 @@ void mgmt_device_connected(struct hci_dev *hdev, struct hci_conn *conn,
u16 eir_len = 0;
u32 flags = 0;
if (test_and_set_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags))
return;
/* allocate buff for LE or BR/EDR adv */
if (conn->le_adv_data_len > 0)
skb = mgmt_alloc_skb(hdev, MGMT_EV_DEVICE_CONNECTED,
@ -9748,6 +9688,9 @@ bool mgmt_powering_down(struct hci_dev *hdev)
struct mgmt_pending_cmd *cmd;
struct mgmt_mode *cp;
if (hci_dev_test_flag(hdev, HCI_POWERING_DOWN))
return true;
cmd = pending_find(MGMT_OP_SET_POWERED, hdev);
if (!cmd)
return false;
@ -9766,14 +9709,6 @@ void mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
struct mgmt_ev_device_disconnected ev;
struct sock *sk = NULL;
/* The connection is still in hci_conn_hash so test for 1
* instead of 0 to know if this is the last one.
*/
if (mgmt_powering_down(hdev) && hci_conn_count(hdev) == 1) {
cancel_delayed_work(&hdev->power_off);
queue_work(hdev->req_workqueue, &hdev->power_off.work);
}
if (!mgmt_connected)
return;
@ -9830,14 +9765,6 @@ void mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
{
struct mgmt_ev_connect_failed ev;
/* The connection is still in hci_conn_hash so test for 1
* instead of 0 to know if this is the last one.
*/
if (mgmt_powering_down(hdev) && hci_conn_count(hdev) == 1) {
cancel_delayed_work(&hdev->power_off);
queue_work(hdev->req_workqueue, &hdev->power_off.work);
}
bacpy(&ev.addr.bdaddr, bdaddr);
ev.addr.type = link_to_bdaddr(link_type, addr_type);
ev.status = mgmt_status(status);
@ -10071,6 +9998,9 @@ void mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
/* If this is a HCI command related to powering on the
* HCI dev don't send any mgmt signals.
*/
if (hci_dev_test_flag(hdev, HCI_POWERING_DOWN))
return;
if (pending_find(MGMT_OP_SET_POWERED, hdev))
return;
}

View File

@ -875,6 +875,7 @@ static int msft_add_address_filter_sync(struct hci_dev *hdev, void *data)
remove = true;
goto done;
}
cp->sub_opcode = MSFT_OP_LE_MONITOR_ADVERTISEMENT;
cp->rssi_high = address_filter->rssi_high;
cp->rssi_low = address_filter->rssi_low;
@ -887,6 +888,8 @@ 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);
kfree(cp);
if (IS_ERR(skb)) {
bt_dev_err(hdev, "Failed to enable address %pMR filter",
&address_filter->bdaddr);

View File

@ -264,7 +264,8 @@ static int sco_connect(struct sock *sk)
}
hcon = hci_connect_sco(hdev, type, &sco_pi(sk)->dst,
sco_pi(sk)->setting, &sco_pi(sk)->codec);
sco_pi(sk)->setting, &sco_pi(sk)->codec,
sk->sk_sndtimeo);
if (IS_ERR(hcon)) {
err = PTR_ERR(hcon);
goto unlock;