Commit a507ea32 authored by Jakub Kicinski's avatar Jakub Kicinski

Merge tag 'for-net-next-2022-09-30' of...

Merge tag 'for-net-next-2022-09-30' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next

Luiz Augusto von Dentz says:

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

 - Add RTL8761BUV device (Edimax BT-8500)
 - Add a new PID/VID 13d3/3583 for MT7921
 - Add Realtek RTL8852C support ID 0x13D3:0x3592
 - Add VID/PID 0489/e0e0 for MediaTek MT7921
 - Add a new VID/PID 0e8d/0608 for MT7921
 - Add a new PID/VID 13d3/3578 for MT7921
 - Add BT device 0cb8:c549 from RTW8852AE
 - Add support for Intel Magnetor

* tag 'for-net-next-2022-09-30' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next: (49 commits)
  Bluetooth: hci_sync: Fix not indicating power state
  Bluetooth: L2CAP: Fix user-after-free
  Bluetooth: Call shutdown for HCI_USER_CHANNEL
  Bluetooth: Prevent double register of suspend
  Bluetooth: hci_core: Fix not handling link timeouts propertly
  Bluetooth: hci_event: Make sure ISO events don't affect non-ISO connections
  Bluetooth: hci_debugfs: Fix not checking conn->debugfs
  Bluetooth: hci_sysfs: Fix attempting to call device_add multiple times
  Bluetooth: MGMT: fix zalloc-simple.cocci warnings
  Bluetooth: hci_{ldisc,serdev}: check percpu_init_rwsem() failure
  Bluetooth: use hdev->workqueue when queuing hdev->{cmd,ncmd}_timer works
  Bluetooth: L2CAP: initialize delayed works at l2cap_chan_create()
  Bluetooth: RFCOMM: Fix possible deadlock on socket shutdown/release
  Bluetooth: hci_sync: allow advertise when scan without RPA
  Bluetooth: btusb: Add a new VID/PID 0e8d/0608 for MT7921
  Bluetooth: btusb: Add a new PID/VID 13d3/3583 for MT7921
  Bluetooth: avoid hci_dev_test_and_set_flag() in mgmt_init_hdev()
  Bluetooth: btintel: Mark Intel controller to support LE_STATES quirk
  Bluetooth: btintel: Add support for Magnetor
  Bluetooth: btusb: Add a new PID/VID 13d3/3578 for MT7921
  ...
====================

Link: https://lore.kernel.org/r/20221001004602.297366-1-luiz.dentz@gmail.comSigned-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents cff2d762 6abf0dae
...@@ -449,6 +449,7 @@ static int btintel_version_info_tlv(struct hci_dev *hdev, ...@@ -449,6 +449,7 @@ static int btintel_version_info_tlv(struct hci_dev *hdev,
case 0x17: /* TyP */ case 0x17: /* TyP */
case 0x18: /* Slr */ case 0x18: /* Slr */
case 0x19: /* Slr-F */ case 0x19: /* Slr-F */
case 0x1b: /* Mgr */
break; break;
default: default:
bt_dev_err(hdev, "Unsupported Intel hardware variant (0x%x)", bt_dev_err(hdev, "Unsupported Intel hardware variant (0x%x)",
...@@ -2330,6 +2331,7 @@ static void btintel_set_msft_opcode(struct hci_dev *hdev, u8 hw_variant) ...@@ -2330,6 +2331,7 @@ static void btintel_set_msft_opcode(struct hci_dev *hdev, u8 hw_variant)
case 0x17: case 0x17:
case 0x18: case 0x18:
case 0x19: case 0x19:
case 0x1b:
hci_set_msft_opcode(hdev, 0xFC1E); hci_set_msft_opcode(hdev, 0xFC1E);
break; break;
default: default:
...@@ -2439,15 +2441,20 @@ static int btintel_setup_combined(struct hci_dev *hdev) ...@@ -2439,15 +2441,20 @@ static int btintel_setup_combined(struct hci_dev *hdev)
INTEL_ROM_LEGACY_NO_WBS_SUPPORT)) INTEL_ROM_LEGACY_NO_WBS_SUPPORT))
set_bit(HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED, set_bit(HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED,
&hdev->quirks); &hdev->quirks);
if (ver.hw_variant == 0x08 && ver.fw_variant == 0x22)
set_bit(HCI_QUIRK_VALID_LE_STATES,
&hdev->quirks);
err = btintel_legacy_rom_setup(hdev, &ver); err = btintel_legacy_rom_setup(hdev, &ver);
break; break;
case 0x0b: /* SfP */ case 0x0b: /* SfP */
case 0x0c: /* WsP */
case 0x11: /* JfP */ case 0x11: /* JfP */
case 0x12: /* ThP */ case 0x12: /* ThP */
case 0x13: /* HrP */ case 0x13: /* HrP */
case 0x14: /* CcP */ case 0x14: /* CcP */
set_bit(HCI_QUIRK_VALID_LE_STATES, &hdev->quirks);
fallthrough;
case 0x0c: /* WsP */
/* Apply the device specific HCI quirks /* Apply the device specific HCI quirks
* *
* All Legacy bootloader devices support WBS * All Legacy bootloader devices support WBS
...@@ -2455,11 +2462,6 @@ static int btintel_setup_combined(struct hci_dev *hdev) ...@@ -2455,11 +2462,6 @@ static int btintel_setup_combined(struct hci_dev *hdev)
set_bit(HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED, set_bit(HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED,
&hdev->quirks); &hdev->quirks);
/* Valid LE States quirk for JfP/ThP familiy */
if (ver.hw_variant == 0x11 || ver.hw_variant == 0x12)
set_bit(HCI_QUIRK_VALID_LE_STATES,
&hdev->quirks);
/* Setup MSFT Extension support */ /* Setup MSFT Extension support */
btintel_set_msft_opcode(hdev, ver.hw_variant); btintel_set_msft_opcode(hdev, ver.hw_variant);
...@@ -2530,9 +2532,8 @@ static int btintel_setup_combined(struct hci_dev *hdev) ...@@ -2530,9 +2532,8 @@ static int btintel_setup_combined(struct hci_dev *hdev)
*/ */
set_bit(HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED, &hdev->quirks); set_bit(HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED, &hdev->quirks);
/* Valid LE States quirk for JfP/ThP familiy */ /* Set Valid LE States quirk */
if (ver.hw_variant == 0x11 || ver.hw_variant == 0x12) set_bit(HCI_QUIRK_VALID_LE_STATES, &hdev->quirks);
set_bit(HCI_QUIRK_VALID_LE_STATES, &hdev->quirks);
/* Setup MSFT Extension support */ /* Setup MSFT Extension support */
btintel_set_msft_opcode(hdev, ver.hw_variant); btintel_set_msft_opcode(hdev, ver.hw_variant);
...@@ -2542,6 +2543,7 @@ static int btintel_setup_combined(struct hci_dev *hdev) ...@@ -2542,6 +2543,7 @@ static int btintel_setup_combined(struct hci_dev *hdev)
case 0x17: case 0x17:
case 0x18: case 0x18:
case 0x19: case 0x19:
case 0x1b:
/* Display version information of TLV type */ /* Display version information of TLV type */
btintel_version_info_tlv(hdev, &ver_tlv); btintel_version_info_tlv(hdev, &ver_tlv);
......
...@@ -426,6 +426,8 @@ static const struct usb_device_id blacklist_table[] = { ...@@ -426,6 +426,8 @@ static const struct usb_device_id blacklist_table[] = {
BTUSB_WIDEBAND_SPEECH }, BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x04ca, 0x4006), .driver_info = BTUSB_REALTEK | { USB_DEVICE(0x04ca, 0x4006), .driver_info = BTUSB_REALTEK |
BTUSB_WIDEBAND_SPEECH }, BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x0cb8, 0xc549), .driver_info = BTUSB_REALTEK |
BTUSB_WIDEBAND_SPEECH },
/* Realtek 8852CE Bluetooth devices */ /* Realtek 8852CE Bluetooth devices */
{ USB_DEVICE(0x04ca, 0x4007), .driver_info = BTUSB_REALTEK | { USB_DEVICE(0x04ca, 0x4007), .driver_info = BTUSB_REALTEK |
...@@ -438,6 +440,8 @@ static const struct usb_device_id blacklist_table[] = { ...@@ -438,6 +440,8 @@ static const struct usb_device_id blacklist_table[] = {
BTUSB_WIDEBAND_SPEECH }, BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x13d3, 0x3586), .driver_info = BTUSB_REALTEK | { USB_DEVICE(0x13d3, 0x3586), .driver_info = BTUSB_REALTEK |
BTUSB_WIDEBAND_SPEECH }, BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x13d3, 0x3592), .driver_info = BTUSB_REALTEK |
BTUSB_WIDEBAND_SPEECH },
/* Realtek Bluetooth devices */ /* Realtek Bluetooth devices */
{ USB_VENDOR_AND_INTERFACE_INFO(0x0bda, 0xe0, 0x01, 0x01), { USB_VENDOR_AND_INTERFACE_INFO(0x0bda, 0xe0, 0x01, 0x01),
...@@ -466,6 +470,9 @@ static const struct usb_device_id blacklist_table[] = { ...@@ -466,6 +470,9 @@ static const struct usb_device_id blacklist_table[] = {
{ USB_DEVICE(0x0489, 0xe0c8), .driver_info = BTUSB_MEDIATEK | { USB_DEVICE(0x0489, 0xe0c8), .driver_info = BTUSB_MEDIATEK |
BTUSB_WIDEBAND_SPEECH | BTUSB_WIDEBAND_SPEECH |
BTUSB_VALID_LE_STATES }, BTUSB_VALID_LE_STATES },
{ USB_DEVICE(0x0489, 0xe0e0), .driver_info = BTUSB_MEDIATEK |
BTUSB_WIDEBAND_SPEECH |
BTUSB_VALID_LE_STATES },
{ USB_DEVICE(0x04ca, 0x3802), .driver_info = BTUSB_MEDIATEK | { USB_DEVICE(0x04ca, 0x3802), .driver_info = BTUSB_MEDIATEK |
BTUSB_WIDEBAND_SPEECH | BTUSB_WIDEBAND_SPEECH |
BTUSB_VALID_LE_STATES }, BTUSB_VALID_LE_STATES },
...@@ -478,9 +485,18 @@ static const struct usb_device_id blacklist_table[] = { ...@@ -478,9 +485,18 @@ static const struct usb_device_id blacklist_table[] = {
{ USB_DEVICE(0x13d3, 0x3567), .driver_info = BTUSB_MEDIATEK | { USB_DEVICE(0x13d3, 0x3567), .driver_info = BTUSB_MEDIATEK |
BTUSB_WIDEBAND_SPEECH | BTUSB_WIDEBAND_SPEECH |
BTUSB_VALID_LE_STATES }, BTUSB_VALID_LE_STATES },
{ USB_DEVICE(0x13d3, 0x3578), .driver_info = BTUSB_MEDIATEK |
BTUSB_WIDEBAND_SPEECH |
BTUSB_VALID_LE_STATES },
{ USB_DEVICE(0x13d3, 0x3583), .driver_info = BTUSB_MEDIATEK |
BTUSB_WIDEBAND_SPEECH |
BTUSB_VALID_LE_STATES },
{ USB_DEVICE(0x0489, 0xe0cd), .driver_info = BTUSB_MEDIATEK | { USB_DEVICE(0x0489, 0xe0cd), .driver_info = BTUSB_MEDIATEK |
BTUSB_WIDEBAND_SPEECH | BTUSB_WIDEBAND_SPEECH |
BTUSB_VALID_LE_STATES }, BTUSB_VALID_LE_STATES },
{ USB_DEVICE(0x0e8d, 0x0608), .driver_info = BTUSB_MEDIATEK |
BTUSB_WIDEBAND_SPEECH |
BTUSB_VALID_LE_STATES },
/* MediaTek MT7922A Bluetooth devices */ /* MediaTek MT7922A Bluetooth devices */
{ USB_DEVICE(0x0489, 0xe0d8), .driver_info = BTUSB_MEDIATEK | { USB_DEVICE(0x0489, 0xe0d8), .driver_info = BTUSB_MEDIATEK |
...@@ -516,19 +532,17 @@ static const struct usb_device_id blacklist_table[] = { ...@@ -516,19 +532,17 @@ static const struct usb_device_id blacklist_table[] = {
{ USB_DEVICE(0x0bda, 0xb009), .driver_info = BTUSB_REALTEK }, { USB_DEVICE(0x0bda, 0xb009), .driver_info = BTUSB_REALTEK },
{ USB_DEVICE(0x2ff8, 0xb011), .driver_info = BTUSB_REALTEK }, { USB_DEVICE(0x2ff8, 0xb011), .driver_info = BTUSB_REALTEK },
/* Additional Realtek 8761B Bluetooth devices */ /* Additional Realtek 8761BUV Bluetooth devices */
{ USB_DEVICE(0x2357, 0x0604), .driver_info = BTUSB_REALTEK | { USB_DEVICE(0x2357, 0x0604), .driver_info = BTUSB_REALTEK |
BTUSB_WIDEBAND_SPEECH }, BTUSB_WIDEBAND_SPEECH },
/* Additional Realtek 8761BU Bluetooth devices */
{ USB_DEVICE(0x0b05, 0x190e), .driver_info = BTUSB_REALTEK | { USB_DEVICE(0x0b05, 0x190e), .driver_info = BTUSB_REALTEK |
BTUSB_WIDEBAND_SPEECH }, BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x2550, 0x8761), .driver_info = BTUSB_REALTEK | { USB_DEVICE(0x2550, 0x8761), .driver_info = BTUSB_REALTEK |
BTUSB_WIDEBAND_SPEECH }, BTUSB_WIDEBAND_SPEECH },
/* Additional Realtek 8761BUV Bluetooth devices */
{ USB_DEVICE(0x0bda, 0x8771), .driver_info = BTUSB_REALTEK | { USB_DEVICE(0x0bda, 0x8771), .driver_info = BTUSB_REALTEK |
BTUSB_WIDEBAND_SPEECH }, BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x7392, 0xc611), .driver_info = BTUSB_REALTEK |
BTUSB_WIDEBAND_SPEECH },
/* Additional Realtek 8821AE Bluetooth devices */ /* Additional Realtek 8821AE Bluetooth devices */
{ USB_DEVICE(0x0b05, 0x17dc), .driver_info = BTUSB_REALTEK }, { USB_DEVICE(0x0b05, 0x17dc), .driver_info = BTUSB_REALTEK },
...@@ -2477,15 +2491,29 @@ static int btusb_mtk_hci_wmt_sync(struct hci_dev *hdev, ...@@ -2477,15 +2491,29 @@ static int btusb_mtk_hci_wmt_sync(struct hci_dev *hdev,
set_bit(BTUSB_TX_WAIT_VND_EVT, &data->flags); set_bit(BTUSB_TX_WAIT_VND_EVT, &data->flags);
/* WMT cmd/event doesn't follow up the generic HCI cmd/event handling,
* it needs constantly polling control pipe until the host received the
* WMT event, thus, we should require to specifically acquire PM counter
* on the USB to prevent the interface from entering auto suspended
* while WMT cmd/event in progress.
*/
err = usb_autopm_get_interface(data->intf);
if (err < 0)
goto err_free_wc;
err = __hci_cmd_send(hdev, 0xfc6f, hlen, wc); err = __hci_cmd_send(hdev, 0xfc6f, hlen, wc);
if (err < 0) { if (err < 0) {
clear_bit(BTUSB_TX_WAIT_VND_EVT, &data->flags); clear_bit(BTUSB_TX_WAIT_VND_EVT, &data->flags);
usb_autopm_put_interface(data->intf);
goto err_free_wc; goto err_free_wc;
} }
/* Submit control IN URB on demand to process the WMT event */ /* Submit control IN URB on demand to process the WMT event */
err = btusb_mtk_submit_wmt_recv_urb(hdev); err = btusb_mtk_submit_wmt_recv_urb(hdev);
usb_autopm_put_interface(data->intf);
if (err < 0) if (err < 0)
goto err_free_wc; goto err_free_wc;
......
...@@ -493,6 +493,11 @@ static int hci_uart_tty_open(struct tty_struct *tty) ...@@ -493,6 +493,11 @@ static int hci_uart_tty_open(struct tty_struct *tty)
BT_ERR("Can't allocate control structure"); BT_ERR("Can't allocate control structure");
return -ENFILE; return -ENFILE;
} }
if (percpu_init_rwsem(&hu->proto_lock)) {
BT_ERR("Can't allocate semaphore structure");
kfree(hu);
return -ENOMEM;
}
tty->disc_data = hu; tty->disc_data = hu;
hu->tty = tty; hu->tty = tty;
...@@ -505,8 +510,6 @@ static int hci_uart_tty_open(struct tty_struct *tty) ...@@ -505,8 +510,6 @@ static int hci_uart_tty_open(struct tty_struct *tty)
INIT_WORK(&hu->init_ready, hci_uart_init_work); INIT_WORK(&hu->init_ready, hci_uart_init_work);
INIT_WORK(&hu->write_work, hci_uart_write_work); INIT_WORK(&hu->write_work, hci_uart_write_work);
percpu_init_rwsem(&hu->proto_lock);
/* Flush any pending characters in the driver */ /* Flush any pending characters in the driver */
tty_driver_flush_buffer(tty); tty_driver_flush_buffer(tty);
......
...@@ -310,11 +310,12 @@ int hci_uart_register_device(struct hci_uart *hu, ...@@ -310,11 +310,12 @@ int hci_uart_register_device(struct hci_uart *hu,
serdev_device_set_client_ops(hu->serdev, &hci_serdev_client_ops); serdev_device_set_client_ops(hu->serdev, &hci_serdev_client_ops);
if (percpu_init_rwsem(&hu->proto_lock))
return -ENOMEM;
err = serdev_device_open(hu->serdev); err = serdev_device_open(hu->serdev);
if (err) if (err)
return err; goto err_rwsem;
percpu_init_rwsem(&hu->proto_lock);
err = p->open(hu); err = p->open(hu);
if (err) if (err)
...@@ -389,6 +390,8 @@ int hci_uart_register_device(struct hci_uart *hu, ...@@ -389,6 +390,8 @@ int hci_uart_register_device(struct hci_uart *hu,
p->close(hu); p->close(hu);
err_open: err_open:
serdev_device_close(hu->serdev); serdev_device_close(hu->serdev);
err_rwsem:
percpu_free_rwsem(&hu->proto_lock);
return err; return err;
} }
EXPORT_SYMBOL_GPL(hci_uart_register_device); EXPORT_SYMBOL_GPL(hci_uart_register_device);
...@@ -410,5 +413,6 @@ void hci_uart_unregister_device(struct hci_uart *hu) ...@@ -410,5 +413,6 @@ void hci_uart_unregister_device(struct hci_uart *hu)
clear_bit(HCI_UART_PROTO_READY, &hu->flags); clear_bit(HCI_UART_PROTO_READY, &hu->flags);
serdev_device_close(hu->serdev); serdev_device_close(hu->serdev);
} }
percpu_free_rwsem(&hu->proto_lock);
} }
EXPORT_SYMBOL_GPL(hci_uart_unregister_device); EXPORT_SYMBOL_GPL(hci_uart_unregister_device);
...@@ -627,6 +627,7 @@ static inline bool iso_enabled(void) ...@@ -627,6 +627,7 @@ static inline bool iso_enabled(void)
int mgmt_init(void); int mgmt_init(void);
void mgmt_exit(void); void mgmt_exit(void);
void mgmt_cleanup(struct sock *sk);
void bt_sock_reclassify_lock(struct sock *sk, int proto); void bt_sock_reclassify_lock(struct sock *sk, int proto);
......
...@@ -354,6 +354,10 @@ enum { ...@@ -354,6 +354,10 @@ enum {
HCI_LE_SIMULTANEOUS_ROLES, HCI_LE_SIMULTANEOUS_ROLES,
HCI_CMD_DRAIN_WORKQUEUE, HCI_CMD_DRAIN_WORKQUEUE,
HCI_MESH_EXPERIMENTAL,
HCI_MESH,
HCI_MESH_SENDING,
__HCI_NUM_FLAGS, __HCI_NUM_FLAGS,
}; };
......
...@@ -238,6 +238,7 @@ struct adv_info { ...@@ -238,6 +238,7 @@ struct adv_info {
bool enabled; bool enabled;
bool pending; bool pending;
bool periodic; bool periodic;
__u8 mesh;
__u8 instance; __u8 instance;
__u32 flags; __u32 flags;
__u16 timeout; __u16 timeout;
...@@ -372,6 +373,8 @@ struct hci_dev { ...@@ -372,6 +373,8 @@ struct hci_dev {
__u8 le_resolv_list_size; __u8 le_resolv_list_size;
__u8 le_num_of_adv_sets; __u8 le_num_of_adv_sets;
__u8 le_states[8]; __u8 le_states[8];
__u8 mesh_ad_types[16];
__u8 mesh_send_ref;
__u8 commands[64]; __u8 commands[64];
__u8 hci_ver; __u8 hci_ver;
__u16 hci_rev; __u16 hci_rev;
...@@ -511,6 +514,7 @@ struct hci_dev { ...@@ -511,6 +514,7 @@ struct hci_dev {
struct list_head cmd_sync_work_list; struct list_head cmd_sync_work_list;
struct mutex cmd_sync_work_lock; struct mutex cmd_sync_work_lock;
struct work_struct cmd_sync_cancel_work; struct work_struct cmd_sync_cancel_work;
struct work_struct reenable_adv_work;
__u16 discov_timeout; __u16 discov_timeout;
struct delayed_work discov_off; struct delayed_work discov_off;
...@@ -561,6 +565,7 @@ struct hci_dev { ...@@ -561,6 +565,7 @@ struct hci_dev {
struct hci_conn_hash conn_hash; struct hci_conn_hash conn_hash;
struct list_head mesh_pending;
struct list_head mgmt_pending; struct list_head mgmt_pending;
struct list_head reject_list; struct list_head reject_list;
struct list_head accept_list; struct list_head accept_list;
...@@ -614,6 +619,8 @@ struct hci_dev { ...@@ -614,6 +619,8 @@ struct hci_dev {
struct delayed_work rpa_expired; struct delayed_work rpa_expired;
bdaddr_t rpa; bdaddr_t rpa;
struct delayed_work mesh_send_done;
enum { enum {
INTERLEAVE_SCAN_NONE, INTERLEAVE_SCAN_NONE,
INTERLEAVE_SCAN_NO_FILTER, INTERLEAVE_SCAN_NO_FILTER,
...@@ -1576,7 +1583,8 @@ struct adv_info *hci_add_adv_instance(struct hci_dev *hdev, u8 instance, ...@@ -1576,7 +1583,8 @@ struct adv_info *hci_add_adv_instance(struct hci_dev *hdev, u8 instance,
u32 flags, u16 adv_data_len, u8 *adv_data, u32 flags, u16 adv_data_len, u8 *adv_data,
u16 scan_rsp_len, u8 *scan_rsp_data, u16 scan_rsp_len, u8 *scan_rsp_data,
u16 timeout, u16 duration, s8 tx_power, u16 timeout, u16 duration, s8 tx_power,
u32 min_interval, u32 max_interval); u32 min_interval, u32 max_interval,
u8 mesh_handle);
struct adv_info *hci_add_per_instance(struct hci_dev *hdev, u8 instance, struct adv_info *hci_add_per_instance(struct hci_dev *hdev, u8 instance,
u32 flags, u8 data_len, u8 *data, u32 flags, u8 data_len, u8 *data,
u32 min_interval, u32 max_interval); u32 min_interval, u32 max_interval);
...@@ -1997,6 +2005,9 @@ void hci_mgmt_chan_unregister(struct hci_mgmt_chan *c); ...@@ -1997,6 +2005,9 @@ void hci_mgmt_chan_unregister(struct hci_mgmt_chan *c);
#define DISCOV_LE_FAST_ADV_INT_MAX 0x00F0 /* 150 msec */ #define DISCOV_LE_FAST_ADV_INT_MAX 0x00F0 /* 150 msec */
#define DISCOV_LE_PER_ADV_INT_MIN 0x00A0 /* 200 msec */ #define DISCOV_LE_PER_ADV_INT_MIN 0x00A0 /* 200 msec */
#define DISCOV_LE_PER_ADV_INT_MAX 0x00A0 /* 200 msec */ #define DISCOV_LE_PER_ADV_INT_MAX 0x00A0 /* 200 msec */
#define DISCOV_LE_ADV_MESH_MIN 0x00A0 /* 100 msec */
#define DISCOV_LE_ADV_MESH_MAX 0x00A0 /* 100 msec */
#define INTERVAL_TO_MS(x) (((x) * 10) / 0x10)
#define NAME_RESOLVE_DURATION msecs_to_jiffies(10240) /* 10.24 sec */ #define NAME_RESOLVE_DURATION msecs_to_jiffies(10240) /* 10.24 sec */
...@@ -2048,7 +2059,8 @@ void mgmt_start_discovery_complete(struct hci_dev *hdev, u8 status); ...@@ -2048,7 +2059,8 @@ void mgmt_start_discovery_complete(struct hci_dev *hdev, u8 status);
void mgmt_stop_discovery_complete(struct hci_dev *hdev, u8 status); void mgmt_stop_discovery_complete(struct hci_dev *hdev, u8 status);
void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
u8 addr_type, u8 *dev_class, s8 rssi, u32 flags, u8 addr_type, u8 *dev_class, s8 rssi, u32 flags,
u8 *eir, u16 eir_len, u8 *scan_rsp, u8 scan_rsp_len); u8 *eir, u16 eir_len, u8 *scan_rsp, u8 scan_rsp_len,
u64 instant);
void mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, void mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
u8 addr_type, s8 rssi, u8 *name, u8 name_len); u8 addr_type, s8 rssi, u8 *name, u8 name_len);
void mgmt_discovering(struct hci_dev *hdev, u8 discovering); void mgmt_discovering(struct hci_dev *hdev, u8 discovering);
...@@ -2075,6 +2087,7 @@ int mgmt_phy_configuration_changed(struct hci_dev *hdev, struct sock *skip); ...@@ -2075,6 +2087,7 @@ int mgmt_phy_configuration_changed(struct hci_dev *hdev, struct sock *skip);
void mgmt_adv_monitor_device_lost(struct hci_dev *hdev, u16 handle, void mgmt_adv_monitor_device_lost(struct hci_dev *hdev, u16 handle,
bdaddr_t *bdaddr, u8 addr_type); bdaddr_t *bdaddr, u8 addr_type);
int hci_abort_conn(struct hci_conn *conn, u8 reason);
u8 hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max, u16 latency, u8 hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max, u16 latency,
u16 to_multiplier); u16 to_multiplier);
void hci_le_start_enc(struct hci_conn *conn, __le16 ediv, __le64 rand, void hci_le_start_enc(struct hci_conn *conn, __le16 ediv, __le64 rand,
......
...@@ -16,6 +16,7 @@ struct hci_cmd_sync_work_entry { ...@@ -16,6 +16,7 @@ struct hci_cmd_sync_work_entry {
hci_cmd_sync_work_destroy_t destroy; hci_cmd_sync_work_destroy_t destroy;
}; };
struct adv_info;
/* Function with sync suffix shall not be called with hdev->lock held as they /* Function with sync suffix shall not be called with hdev->lock held as they
* wait the command to complete and in the meantime an event could be received * wait the command to complete and in the meantime an event could be received
* which could attempt to acquire hdev->lock causing a deadlock. * which could attempt to acquire hdev->lock causing a deadlock.
...@@ -51,11 +52,16 @@ int hci_update_class_sync(struct hci_dev *hdev); ...@@ -51,11 +52,16 @@ int hci_update_class_sync(struct hci_dev *hdev);
int hci_update_name_sync(struct hci_dev *hdev); int hci_update_name_sync(struct hci_dev *hdev);
int hci_write_ssp_mode_sync(struct hci_dev *hdev, u8 mode); int hci_write_ssp_mode_sync(struct hci_dev *hdev, u8 mode);
int hci_get_random_address(struct hci_dev *hdev, bool require_privacy,
bool use_rpa, struct adv_info *adv_instance,
u8 *own_addr_type, bdaddr_t *rand_addr);
int hci_update_random_address_sync(struct hci_dev *hdev, bool require_privacy, int hci_update_random_address_sync(struct hci_dev *hdev, bool require_privacy,
bool rpa, u8 *own_addr_type); bool rpa, u8 *own_addr_type);
int hci_update_scan_rsp_data_sync(struct hci_dev *hdev, u8 instance); int hci_update_scan_rsp_data_sync(struct hci_dev *hdev, u8 instance);
int hci_update_adv_data_sync(struct hci_dev *hdev, u8 instance); int hci_update_adv_data_sync(struct hci_dev *hdev, u8 instance);
int hci_update_adv_data(struct hci_dev *hdev, u8 instance);
int hci_schedule_adv_instance_sync(struct hci_dev *hdev, u8 instance, int hci_schedule_adv_instance_sync(struct hci_dev *hdev, u8 instance,
bool force); bool force);
...@@ -72,7 +78,8 @@ int hci_start_per_adv_sync(struct hci_dev *hdev, u8 instance, u8 data_len, ...@@ -72,7 +78,8 @@ int hci_start_per_adv_sync(struct hci_dev *hdev, u8 instance, u8 data_len,
int hci_remove_advertising_sync(struct hci_dev *hdev, struct sock *sk, int hci_remove_advertising_sync(struct hci_dev *hdev, struct sock *sk,
u8 instance, bool force); u8 instance, bool force);
int hci_disable_advertising_sync(struct hci_dev *hdev); int hci_disable_advertising_sync(struct hci_dev *hdev);
int hci_clear_adv_instance_sync(struct hci_dev *hdev, struct sock *sk,
u8 instance, bool force);
int hci_update_passive_scan_sync(struct hci_dev *hdev); int hci_update_passive_scan_sync(struct hci_dev *hdev);
int hci_update_passive_scan(struct hci_dev *hdev); int hci_update_passive_scan(struct hci_dev *hdev);
int hci_read_rssi_sync(struct hci_dev *hdev, __le16 handle); int hci_read_rssi_sync(struct hci_dev *hdev, __le16 handle);
......
...@@ -837,6 +837,42 @@ struct mgmt_cp_add_adv_patterns_monitor_rssi { ...@@ -837,6 +837,42 @@ struct mgmt_cp_add_adv_patterns_monitor_rssi {
struct mgmt_adv_pattern patterns[]; struct mgmt_adv_pattern patterns[];
} __packed; } __packed;
#define MGMT_ADD_ADV_PATTERNS_MONITOR_RSSI_SIZE 8 #define MGMT_ADD_ADV_PATTERNS_MONITOR_RSSI_SIZE 8
#define MGMT_OP_SET_MESH_RECEIVER 0x0057
struct mgmt_cp_set_mesh {
__u8 enable;
__le16 window;
__le16 period;
__u8 num_ad_types;
__u8 ad_types[];
} __packed;
#define MGMT_SET_MESH_RECEIVER_SIZE 6
#define MGMT_OP_MESH_READ_FEATURES 0x0058
#define MGMT_MESH_READ_FEATURES_SIZE 0
#define MESH_HANDLES_MAX 3
struct mgmt_rp_mesh_read_features {
__le16 index;
__u8 max_handles;
__u8 used_handles;
__u8 handles[MESH_HANDLES_MAX];
} __packed;
#define MGMT_OP_MESH_SEND 0x0059
struct mgmt_cp_mesh_send {
struct mgmt_addr_info addr;
__le64 instant;
__le16 delay;
__u8 cnt;
__u8 adv_data_len;
__u8 adv_data[];
} __packed;
#define MGMT_MESH_SEND_SIZE 19
#define MGMT_OP_MESH_SEND_CANCEL 0x005A
struct mgmt_cp_mesh_send_cancel {
__u8 handle;
} __packed;
#define MGMT_MESH_SEND_CANCEL_SIZE 1
#define MGMT_EV_CMD_COMPLETE 0x0001 #define MGMT_EV_CMD_COMPLETE 0x0001
struct mgmt_ev_cmd_complete { struct mgmt_ev_cmd_complete {
...@@ -1120,3 +1156,19 @@ struct mgmt_ev_adv_monitor_device_lost { ...@@ -1120,3 +1156,19 @@ struct mgmt_ev_adv_monitor_device_lost {
__le16 monitor_handle; __le16 monitor_handle;
struct mgmt_addr_info addr; struct mgmt_addr_info addr;
} __packed; } __packed;
#define MGMT_EV_MESH_DEVICE_FOUND 0x0031
struct mgmt_ev_mesh_device_found {
struct mgmt_addr_info addr;
__s8 rssi;
__le64 instant;
__le32 flags;
__le16 eir_len;
__u8 eir[];
} __packed;
#define MGMT_EV_MESH_PACKET_CMPLT 0x0032
struct mgmt_ev_mesh_pkt_cmplt {
__u8 handle;
} __packed;
...@@ -44,6 +44,11 @@ struct sco_param { ...@@ -44,6 +44,11 @@ struct sco_param {
u8 retrans_effort; u8 retrans_effort;
}; };
struct conn_handle_t {
struct hci_conn *conn;
__u16 handle;
};
static const struct sco_param esco_param_cvsd[] = { static const struct sco_param esco_param_cvsd[] = {
{ EDR_ESCO_MASK & ~ESCO_2EV3, 0x000a, 0x01 }, /* S3 */ { EDR_ESCO_MASK & ~ESCO_2EV3, 0x000a, 0x01 }, /* S3 */
{ EDR_ESCO_MASK & ~ESCO_2EV3, 0x0007, 0x01 }, /* S2 */ { EDR_ESCO_MASK & ~ESCO_2EV3, 0x0007, 0x01 }, /* S2 */
...@@ -316,17 +321,60 @@ static bool find_next_esco_param(struct hci_conn *conn, ...@@ -316,17 +321,60 @@ static bool find_next_esco_param(struct hci_conn *conn,
return conn->attempt <= size; return conn->attempt <= size;
} }
static bool hci_enhanced_setup_sync_conn(struct hci_conn *conn, __u16 handle) static int configure_datapath_sync(struct hci_dev *hdev, struct bt_codec *codec)
{ {
struct hci_dev *hdev = conn->hdev; int err;
__u8 vnd_len, *vnd_data = NULL;
struct hci_op_configure_data_path *cmd = NULL;
err = hdev->get_codec_config_data(hdev, ESCO_LINK, codec, &vnd_len,
&vnd_data);
if (err < 0)
goto error;
cmd = kzalloc(sizeof(*cmd) + vnd_len, GFP_KERNEL);
if (!cmd) {
err = -ENOMEM;
goto error;
}
err = hdev->get_data_path_id(hdev, &cmd->data_path_id);
if (err < 0)
goto error;
cmd->vnd_len = vnd_len;
memcpy(cmd->vnd_data, vnd_data, vnd_len);
cmd->direction = 0x00;
__hci_cmd_sync_status(hdev, HCI_CONFIGURE_DATA_PATH,
sizeof(*cmd) + vnd_len, cmd, HCI_CMD_TIMEOUT);
cmd->direction = 0x01;
err = __hci_cmd_sync_status(hdev, HCI_CONFIGURE_DATA_PATH,
sizeof(*cmd) + vnd_len, cmd,
HCI_CMD_TIMEOUT);
error:
kfree(cmd);
kfree(vnd_data);
return err;
}
static int hci_enhanced_setup_sync(struct hci_dev *hdev, void *data)
{
struct conn_handle_t *conn_handle = data;
struct hci_conn *conn = conn_handle->conn;
__u16 handle = conn_handle->handle;
struct hci_cp_enhanced_setup_sync_conn cp; struct hci_cp_enhanced_setup_sync_conn cp;
const struct sco_param *param; const struct sco_param *param;
kfree(conn_handle);
bt_dev_dbg(hdev, "hcon %p", conn); bt_dev_dbg(hdev, "hcon %p", conn);
/* for offload use case, codec needs to configured before opening SCO */ /* for offload use case, codec needs to configured before opening SCO */
if (conn->codec.data_path) if (conn->codec.data_path)
hci_req_configure_datapath(hdev, &conn->codec); configure_datapath_sync(hdev, &conn->codec);
conn->state = BT_CONNECT; conn->state = BT_CONNECT;
conn->out = true; conn->out = true;
...@@ -344,7 +392,7 @@ static bool hci_enhanced_setup_sync_conn(struct hci_conn *conn, __u16 handle) ...@@ -344,7 +392,7 @@ static bool hci_enhanced_setup_sync_conn(struct hci_conn *conn, __u16 handle)
case BT_CODEC_MSBC: case BT_CODEC_MSBC:
if (!find_next_esco_param(conn, esco_param_msbc, if (!find_next_esco_param(conn, esco_param_msbc,
ARRAY_SIZE(esco_param_msbc))) ARRAY_SIZE(esco_param_msbc)))
return false; return -EINVAL;
param = &esco_param_msbc[conn->attempt - 1]; param = &esco_param_msbc[conn->attempt - 1];
cp.tx_coding_format.id = 0x05; cp.tx_coding_format.id = 0x05;
...@@ -396,11 +444,11 @@ static bool hci_enhanced_setup_sync_conn(struct hci_conn *conn, __u16 handle) ...@@ -396,11 +444,11 @@ static bool hci_enhanced_setup_sync_conn(struct hci_conn *conn, __u16 handle)
if (lmp_esco_capable(conn->link)) { if (lmp_esco_capable(conn->link)) {
if (!find_next_esco_param(conn, esco_param_cvsd, if (!find_next_esco_param(conn, esco_param_cvsd,
ARRAY_SIZE(esco_param_cvsd))) ARRAY_SIZE(esco_param_cvsd)))
return false; return -EINVAL;
param = &esco_param_cvsd[conn->attempt - 1]; param = &esco_param_cvsd[conn->attempt - 1];
} else { } else {
if (conn->attempt > ARRAY_SIZE(sco_param_cvsd)) if (conn->attempt > ARRAY_SIZE(sco_param_cvsd))
return false; return -EINVAL;
param = &sco_param_cvsd[conn->attempt - 1]; param = &sco_param_cvsd[conn->attempt - 1];
} }
cp.tx_coding_format.id = 2; cp.tx_coding_format.id = 2;
...@@ -423,7 +471,7 @@ static bool hci_enhanced_setup_sync_conn(struct hci_conn *conn, __u16 handle) ...@@ -423,7 +471,7 @@ static bool hci_enhanced_setup_sync_conn(struct hci_conn *conn, __u16 handle)
cp.out_transport_unit_size = 16; cp.out_transport_unit_size = 16;
break; break;
default: default:
return false; return -EINVAL;
} }
cp.retrans_effort = param->retrans_effort; cp.retrans_effort = param->retrans_effort;
...@@ -431,9 +479,9 @@ static bool hci_enhanced_setup_sync_conn(struct hci_conn *conn, __u16 handle) ...@@ -431,9 +479,9 @@ static bool hci_enhanced_setup_sync_conn(struct hci_conn *conn, __u16 handle)
cp.max_latency = __cpu_to_le16(param->max_latency); cp.max_latency = __cpu_to_le16(param->max_latency);
if (hci_send_cmd(hdev, HCI_OP_ENHANCED_SETUP_SYNC_CONN, sizeof(cp), &cp) < 0) if (hci_send_cmd(hdev, HCI_OP_ENHANCED_SETUP_SYNC_CONN, sizeof(cp), &cp) < 0)
return false; return -EIO;
return true; return 0;
} }
static bool hci_setup_sync_conn(struct hci_conn *conn, __u16 handle) static bool hci_setup_sync_conn(struct hci_conn *conn, __u16 handle)
...@@ -490,8 +538,24 @@ static bool hci_setup_sync_conn(struct hci_conn *conn, __u16 handle) ...@@ -490,8 +538,24 @@ static bool hci_setup_sync_conn(struct hci_conn *conn, __u16 handle)
bool hci_setup_sync(struct hci_conn *conn, __u16 handle) bool hci_setup_sync(struct hci_conn *conn, __u16 handle)
{ {
if (enhanced_sync_conn_capable(conn->hdev)) int result;
return hci_enhanced_setup_sync_conn(conn, handle); struct conn_handle_t *conn_handle;
if (enhanced_sync_conn_capable(conn->hdev)) {
conn_handle = kzalloc(sizeof(*conn_handle), GFP_KERNEL);
if (!conn_handle)
return false;
conn_handle->conn = conn;
conn_handle->handle = handle;
result = hci_cmd_sync_queue(conn->hdev, hci_enhanced_setup_sync,
conn_handle, NULL);
if (result < 0)
kfree(conn_handle);
return result == 0;
}
return hci_setup_sync_conn(conn, handle); return hci_setup_sync_conn(conn, handle);
} }
...@@ -2696,3 +2760,79 @@ u32 hci_conn_get_phy(struct hci_conn *conn) ...@@ -2696,3 +2760,79 @@ u32 hci_conn_get_phy(struct hci_conn *conn)
return phys; return phys;
} }
int hci_abort_conn(struct hci_conn *conn, u8 reason)
{
int r = 0;
switch (conn->state) {
case BT_CONNECTED:
case BT_CONFIG:
if (conn->type == AMP_LINK) {
struct hci_cp_disconn_phy_link cp;
cp.phy_handle = HCI_PHY_HANDLE(conn->handle);
cp.reason = reason;
r = hci_send_cmd(conn->hdev, HCI_OP_DISCONN_PHY_LINK,
sizeof(cp), &cp);
} else {
struct hci_cp_disconnect dc;
dc.handle = cpu_to_le16(conn->handle);
dc.reason = reason;
r = hci_send_cmd(conn->hdev, HCI_OP_DISCONNECT,
sizeof(dc), &dc);
}
conn->state = BT_DISCONN;
break;
case BT_CONNECT:
if (conn->type == LE_LINK) {
if (test_bit(HCI_CONN_SCANNING, &conn->flags))
break;
r = hci_send_cmd(conn->hdev,
HCI_OP_LE_CREATE_CONN_CANCEL, 0, NULL);
} else if (conn->type == ACL_LINK) {
if (conn->hdev->hci_ver < BLUETOOTH_VER_1_2)
break;
r = hci_send_cmd(conn->hdev,
HCI_OP_CREATE_CONN_CANCEL,
6, &conn->dst);
}
break;
case BT_CONNECT2:
if (conn->type == ACL_LINK) {
struct hci_cp_reject_conn_req rej;
bacpy(&rej.bdaddr, &conn->dst);
rej.reason = reason;
r = hci_send_cmd(conn->hdev,
HCI_OP_REJECT_CONN_REQ,
sizeof(rej), &rej);
} else if (conn->type == SCO_LINK || conn->type == ESCO_LINK) {
struct hci_cp_reject_sync_conn_req rej;
bacpy(&rej.bdaddr, &conn->dst);
/* SCO rejection has its own limited set of
* allowed error values (0x0D-0x0F) which isn't
* compatible with most values passed to this
* function. To be safe hard-code one of the
* values that's suitable for SCO.
*/
rej.reason = HCI_ERROR_REJ_LIMITED_RESOURCES;
r = hci_send_cmd(conn->hdev,
HCI_OP_REJECT_SYNC_CONN_REQ,
sizeof(rej), &rej);
}
break;
default:
conn->state = BT_CLOSED;
break;
}
return r;
}
...@@ -597,6 +597,15 @@ static int hci_dev_do_reset(struct hci_dev *hdev) ...@@ -597,6 +597,15 @@ static int hci_dev_do_reset(struct hci_dev *hdev)
/* Cancel these to avoid queueing non-chained pending work */ /* Cancel these to avoid queueing non-chained pending work */
hci_dev_set_flag(hdev, HCI_CMD_DRAIN_WORKQUEUE); hci_dev_set_flag(hdev, HCI_CMD_DRAIN_WORKQUEUE);
/* Wait for
*
* if (!hci_dev_test_flag(hdev, HCI_CMD_DRAIN_WORKQUEUE))
* queue_delayed_work(&hdev->{cmd,ncmd}_timer)
*
* inside RCU section to see the flag or complete scheduling.
*/
synchronize_rcu();
/* Explicitly cancel works in case scheduled after setting the flag. */
cancel_delayed_work(&hdev->cmd_timer); cancel_delayed_work(&hdev->cmd_timer);
cancel_delayed_work(&hdev->ncmd_timer); cancel_delayed_work(&hdev->ncmd_timer);
...@@ -714,7 +723,7 @@ static void hci_update_passive_scan_state(struct hci_dev *hdev, u8 scan) ...@@ -714,7 +723,7 @@ static void hci_update_passive_scan_state(struct hci_dev *hdev, u8 scan)
hci_dev_set_flag(hdev, HCI_BREDR_ENABLED); hci_dev_set_flag(hdev, HCI_BREDR_ENABLED);
if (hci_dev_test_flag(hdev, HCI_LE_ENABLED)) if (hci_dev_test_flag(hdev, HCI_LE_ENABLED))
hci_req_update_adv_data(hdev, hdev->cur_adv_instance); hci_update_adv_data(hdev, hdev->cur_adv_instance);
mgmt_new_settings(hdev); mgmt_new_settings(hdev);
} }
...@@ -1706,7 +1715,8 @@ struct adv_info *hci_add_adv_instance(struct hci_dev *hdev, u8 instance, ...@@ -1706,7 +1715,8 @@ struct adv_info *hci_add_adv_instance(struct hci_dev *hdev, u8 instance,
u32 flags, u16 adv_data_len, u8 *adv_data, u32 flags, u16 adv_data_len, u8 *adv_data,
u16 scan_rsp_len, u8 *scan_rsp_data, u16 scan_rsp_len, u8 *scan_rsp_data,
u16 timeout, u16 duration, s8 tx_power, u16 timeout, u16 duration, s8 tx_power,
u32 min_interval, u32 max_interval) u32 min_interval, u32 max_interval,
u8 mesh_handle)
{ {
struct adv_info *adv; struct adv_info *adv;
...@@ -1717,7 +1727,7 @@ struct adv_info *hci_add_adv_instance(struct hci_dev *hdev, u8 instance, ...@@ -1717,7 +1727,7 @@ struct adv_info *hci_add_adv_instance(struct hci_dev *hdev, u8 instance,
memset(adv->per_adv_data, 0, sizeof(adv->per_adv_data)); memset(adv->per_adv_data, 0, sizeof(adv->per_adv_data));
} else { } else {
if (hdev->adv_instance_cnt >= hdev->le_num_of_adv_sets || if (hdev->adv_instance_cnt >= hdev->le_num_of_adv_sets ||
instance < 1 || instance > hdev->le_num_of_adv_sets) instance < 1 || instance > hdev->le_num_of_adv_sets + 1)
return ERR_PTR(-EOVERFLOW); return ERR_PTR(-EOVERFLOW);
adv = kzalloc(sizeof(*adv), GFP_KERNEL); adv = kzalloc(sizeof(*adv), GFP_KERNEL);
...@@ -1734,6 +1744,11 @@ struct adv_info *hci_add_adv_instance(struct hci_dev *hdev, u8 instance, ...@@ -1734,6 +1744,11 @@ struct adv_info *hci_add_adv_instance(struct hci_dev *hdev, u8 instance,
adv->min_interval = min_interval; adv->min_interval = min_interval;
adv->max_interval = max_interval; adv->max_interval = max_interval;
adv->tx_power = tx_power; adv->tx_power = tx_power;
/* Defining a mesh_handle changes the timing units to ms,
* rather than seconds, and ties the instance to the requested
* mesh_tx queue.
*/
adv->mesh = mesh_handle;
hci_set_adv_instance_data(hdev, instance, adv_data_len, adv_data, hci_set_adv_instance_data(hdev, instance, adv_data_len, adv_data,
scan_rsp_len, scan_rsp_data); scan_rsp_len, scan_rsp_data);
...@@ -1762,7 +1777,7 @@ struct adv_info *hci_add_per_instance(struct hci_dev *hdev, u8 instance, ...@@ -1762,7 +1777,7 @@ struct adv_info *hci_add_per_instance(struct hci_dev *hdev, u8 instance,
adv = hci_add_adv_instance(hdev, instance, flags, 0, NULL, 0, NULL, adv = hci_add_adv_instance(hdev, instance, flags, 0, NULL, 0, NULL,
0, 0, HCI_ADV_TX_POWER_NO_PREFERENCE, 0, 0, HCI_ADV_TX_POWER_NO_PREFERENCE,
min_interval, max_interval); min_interval, max_interval, 0);
if (IS_ERR(adv)) if (IS_ERR(adv))
return adv; return adv;
...@@ -2391,6 +2406,10 @@ static int hci_suspend_notifier(struct notifier_block *nb, unsigned long action, ...@@ -2391,6 +2406,10 @@ static int hci_suspend_notifier(struct notifier_block *nb, unsigned long action,
container_of(nb, struct hci_dev, suspend_notifier); container_of(nb, struct hci_dev, suspend_notifier);
int ret = 0; int ret = 0;
/* Userspace has full control of this device. Do nothing. */
if (hci_dev_test_flag(hdev, HCI_USER_CHANNEL))
return NOTIFY_DONE;
if (action == PM_SUSPEND_PREPARE) if (action == PM_SUSPEND_PREPARE)
ret = hci_suspend_dev(hdev); ret = hci_suspend_dev(hdev);
else if (action == PM_POST_SUSPEND) else if (action == PM_POST_SUSPEND)
...@@ -2486,6 +2505,7 @@ struct hci_dev *hci_alloc_dev_priv(int sizeof_priv) ...@@ -2486,6 +2505,7 @@ struct hci_dev *hci_alloc_dev_priv(int sizeof_priv)
mutex_init(&hdev->lock); mutex_init(&hdev->lock);
mutex_init(&hdev->req_lock); mutex_init(&hdev->req_lock);
INIT_LIST_HEAD(&hdev->mesh_pending);
INIT_LIST_HEAD(&hdev->mgmt_pending); INIT_LIST_HEAD(&hdev->mgmt_pending);
INIT_LIST_HEAD(&hdev->reject_list); INIT_LIST_HEAD(&hdev->reject_list);
INIT_LIST_HEAD(&hdev->accept_list); INIT_LIST_HEAD(&hdev->accept_list);
...@@ -3469,15 +3489,27 @@ static inline int __get_blocks(struct hci_dev *hdev, struct sk_buff *skb) ...@@ -3469,15 +3489,27 @@ static inline int __get_blocks(struct hci_dev *hdev, struct sk_buff *skb)
return DIV_ROUND_UP(skb->len - HCI_ACL_HDR_SIZE, hdev->block_len); return DIV_ROUND_UP(skb->len - HCI_ACL_HDR_SIZE, hdev->block_len);
} }
static void __check_timeout(struct hci_dev *hdev, unsigned int cnt) static void __check_timeout(struct hci_dev *hdev, unsigned int cnt, u8 type)
{ {
if (!hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) { unsigned long last_tx;
/* ACL tx timeout must be longer than maximum
* link supervision timeout (40.9 seconds) */ if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED))
if (!cnt && time_after(jiffies, hdev->acl_last_tx + return;
HCI_ACL_TX_TIMEOUT))
hci_link_tx_to(hdev, ACL_LINK); switch (type) {
case LE_LINK:
last_tx = hdev->le_last_tx;
break;
default:
last_tx = hdev->acl_last_tx;
break;
} }
/* tx timeout must be longer than maximum link supervision timeout
* (40.9 seconds)
*/
if (!cnt && time_after(jiffies, last_tx + HCI_ACL_TX_TIMEOUT))
hci_link_tx_to(hdev, type);
} }
/* Schedule SCO */ /* Schedule SCO */
...@@ -3535,7 +3567,7 @@ static void hci_sched_acl_pkt(struct hci_dev *hdev) ...@@ -3535,7 +3567,7 @@ static void hci_sched_acl_pkt(struct hci_dev *hdev)
struct sk_buff *skb; struct sk_buff *skb;
int quote; int quote;
__check_timeout(hdev, cnt); __check_timeout(hdev, cnt, ACL_LINK);
while (hdev->acl_cnt && while (hdev->acl_cnt &&
(chan = hci_chan_sent(hdev, ACL_LINK, &quote))) { (chan = hci_chan_sent(hdev, ACL_LINK, &quote))) {
...@@ -3578,8 +3610,6 @@ static void hci_sched_acl_blk(struct hci_dev *hdev) ...@@ -3578,8 +3610,6 @@ static void hci_sched_acl_blk(struct hci_dev *hdev)
int quote; int quote;
u8 type; u8 type;
__check_timeout(hdev, cnt);
BT_DBG("%s", hdev->name); BT_DBG("%s", hdev->name);
if (hdev->dev_type == HCI_AMP) if (hdev->dev_type == HCI_AMP)
...@@ -3587,6 +3617,8 @@ static void hci_sched_acl_blk(struct hci_dev *hdev) ...@@ -3587,6 +3617,8 @@ static void hci_sched_acl_blk(struct hci_dev *hdev)
else else
type = ACL_LINK; type = ACL_LINK;
__check_timeout(hdev, cnt, type);
while (hdev->block_cnt > 0 && while (hdev->block_cnt > 0 &&
(chan = hci_chan_sent(hdev, type, &quote))) { (chan = hci_chan_sent(hdev, type, &quote))) {
u32 priority = (skb_peek(&chan->data_q))->priority; u32 priority = (skb_peek(&chan->data_q))->priority;
...@@ -3660,7 +3692,7 @@ static void hci_sched_le(struct hci_dev *hdev) ...@@ -3660,7 +3692,7 @@ static void hci_sched_le(struct hci_dev *hdev)
cnt = hdev->le_pkts ? hdev->le_cnt : hdev->acl_cnt; cnt = hdev->le_pkts ? hdev->le_cnt : hdev->acl_cnt;
__check_timeout(hdev, cnt); __check_timeout(hdev, cnt, LE_LINK);
tmp = cnt; tmp = cnt;
while (cnt && (chan = hci_chan_sent(hdev, LE_LINK, &quote))) { while (cnt && (chan = hci_chan_sent(hdev, LE_LINK, &quote))) {
...@@ -4056,12 +4088,14 @@ static void hci_cmd_work(struct work_struct *work) ...@@ -4056,12 +4088,14 @@ static void hci_cmd_work(struct work_struct *work)
if (res < 0) if (res < 0)
__hci_cmd_sync_cancel(hdev, -res); __hci_cmd_sync_cancel(hdev, -res);
rcu_read_lock();
if (test_bit(HCI_RESET, &hdev->flags) || if (test_bit(HCI_RESET, &hdev->flags) ||
hci_dev_test_flag(hdev, HCI_CMD_DRAIN_WORKQUEUE)) hci_dev_test_flag(hdev, HCI_CMD_DRAIN_WORKQUEUE))
cancel_delayed_work(&hdev->cmd_timer); cancel_delayed_work(&hdev->cmd_timer);
else else
schedule_delayed_work(&hdev->cmd_timer, queue_delayed_work(hdev->workqueue, &hdev->cmd_timer,
HCI_CMD_TIMEOUT); HCI_CMD_TIMEOUT);
rcu_read_unlock();
} else { } else {
skb_queue_head(&hdev->cmd_q, skb); skb_queue_head(&hdev->cmd_q, skb);
queue_work(hdev->workqueue, &hdev->cmd_work); queue_work(hdev->workqueue, &hdev->cmd_work);
......
...@@ -1245,7 +1245,7 @@ void hci_debugfs_create_conn(struct hci_conn *conn) ...@@ -1245,7 +1245,7 @@ void hci_debugfs_create_conn(struct hci_conn *conn)
struct hci_dev *hdev = conn->hdev; struct hci_dev *hdev = conn->hdev;
char name[6]; char name[6];
if (IS_ERR_OR_NULL(hdev->debugfs)) if (IS_ERR_OR_NULL(hdev->debugfs) || conn->debugfs)
return; return;
snprintf(name, sizeof(name), "%u", conn->handle); snprintf(name, sizeof(name), "%u", conn->handle);
......
This diff is collapsed.
This diff is collapsed.
...@@ -68,63 +68,10 @@ int __hci_req_sync(struct hci_dev *hdev, int (*func)(struct hci_request *req, ...@@ -68,63 +68,10 @@ int __hci_req_sync(struct hci_dev *hdev, int (*func)(struct hci_request *req,
struct sk_buff *hci_prepare_cmd(struct hci_dev *hdev, u16 opcode, u32 plen, struct sk_buff *hci_prepare_cmd(struct hci_dev *hdev, u16 opcode, u32 plen,
const void *param); const void *param);
void __hci_req_write_fast_connectable(struct hci_request *req, bool enable);
void __hci_req_update_name(struct hci_request *req);
void __hci_req_update_eir(struct hci_request *req);
void hci_req_add_le_scan_disable(struct hci_request *req, bool rpa_le_conn); void hci_req_add_le_scan_disable(struct hci_request *req, bool rpa_le_conn);
void hci_req_add_le_passive_scan(struct hci_request *req); void hci_req_add_le_passive_scan(struct hci_request *req);
void hci_req_prepare_suspend(struct hci_dev *hdev, enum suspended_state next); void hci_req_prepare_suspend(struct hci_dev *hdev, enum suspended_state next);
void hci_req_disable_address_resolution(struct hci_dev *hdev);
void hci_req_reenable_advertising(struct hci_dev *hdev);
void __hci_req_enable_advertising(struct hci_request *req);
void __hci_req_disable_advertising(struct hci_request *req);
void __hci_req_update_adv_data(struct hci_request *req, u8 instance);
int hci_req_update_adv_data(struct hci_dev *hdev, u8 instance);
int hci_req_start_per_adv(struct hci_dev *hdev, u8 instance, u32 flags,
u16 min_interval, u16 max_interval,
u16 sync_interval);
void __hci_req_update_scan_rsp_data(struct hci_request *req, u8 instance);
int __hci_req_schedule_adv_instance(struct hci_request *req, u8 instance,
bool force);
void hci_req_clear_adv_instance(struct hci_dev *hdev, struct sock *sk,
struct hci_request *req, u8 instance,
bool force);
int __hci_req_setup_ext_adv_instance(struct hci_request *req, u8 instance);
int __hci_req_setup_per_adv_instance(struct hci_request *req, u8 instance,
u16 min_interval, u16 max_interval);
int __hci_req_start_ext_adv(struct hci_request *req, u8 instance);
int __hci_req_start_per_adv(struct hci_request *req, u8 instance, u32 flags,
u16 min_interval, u16 max_interval,
u16 sync_interval);
int __hci_req_enable_ext_advertising(struct hci_request *req, u8 instance);
int __hci_req_enable_per_advertising(struct hci_request *req, u8 instance);
int __hci_req_disable_ext_adv_instance(struct hci_request *req, u8 instance);
int __hci_req_remove_ext_adv_instance(struct hci_request *req, u8 instance);
void __hci_req_clear_ext_adv_sets(struct hci_request *req);
int hci_get_random_address(struct hci_dev *hdev, bool require_privacy,
bool use_rpa, struct adv_info *adv_instance,
u8 *own_addr_type, bdaddr_t *rand_addr);
void __hci_req_update_class(struct hci_request *req);
/* Returns true if HCI commands were queued */
bool hci_req_stop_discovery(struct hci_request *req);
int hci_req_configure_datapath(struct hci_dev *hdev, struct bt_codec *codec);
void __hci_req_update_scan(struct hci_request *req);
int hci_update_random_address(struct hci_request *req, bool require_privacy,
bool use_rpa, u8 *own_addr_type);
int hci_abort_conn(struct hci_conn *conn, u8 reason);
void __hci_abort_conn(struct hci_request *req, struct hci_conn *conn,
u8 reason);
void hci_request_setup(struct hci_dev *hdev); void hci_request_setup(struct hci_dev *hdev);
void hci_request_cancel_all(struct hci_dev *hdev); void hci_request_cancel_all(struct hci_dev *hdev);
...@@ -887,7 +887,6 @@ static int hci_sock_release(struct socket *sock) ...@@ -887,7 +887,6 @@ static int hci_sock_release(struct socket *sock)
*/ */
hci_dev_do_close(hdev); hci_dev_do_close(hdev);
hci_dev_clear_flag(hdev, HCI_USER_CHANNEL); hci_dev_clear_flag(hdev, HCI_USER_CHANNEL);
hci_register_suspend_notifier(hdev);
mgmt_index_added(hdev); mgmt_index_added(hdev);
} }
...@@ -1216,7 +1215,6 @@ static int hci_sock_bind(struct socket *sock, struct sockaddr *addr, ...@@ -1216,7 +1215,6 @@ static int hci_sock_bind(struct socket *sock, struct sockaddr *addr,
} }
mgmt_index_removed(hdev); mgmt_index_removed(hdev);
hci_unregister_suspend_notifier(hdev);
err = hci_dev_open(hdev->id); err = hci_dev_open(hdev->id);
if (err) { if (err) {
...@@ -1231,7 +1229,6 @@ static int hci_sock_bind(struct socket *sock, struct sockaddr *addr, ...@@ -1231,7 +1229,6 @@ static int hci_sock_bind(struct socket *sock, struct sockaddr *addr,
err = 0; err = 0;
} else { } else {
hci_dev_clear_flag(hdev, HCI_USER_CHANNEL); hci_dev_clear_flag(hdev, HCI_USER_CHANNEL);
hci_register_suspend_notifier(hdev);
mgmt_index_added(hdev); mgmt_index_added(hdev);
hci_dev_put(hdev); hci_dev_put(hdev);
goto done; goto done;
...@@ -2065,6 +2062,7 @@ static int hci_sock_getsockopt(struct socket *sock, int level, int optname, ...@@ -2065,6 +2062,7 @@ static int hci_sock_getsockopt(struct socket *sock, int level, int optname,
static void hci_sock_destruct(struct sock *sk) static void hci_sock_destruct(struct sock *sk)
{ {
mgmt_cleanup(sk);
skb_queue_purge(&sk->sk_receive_queue); skb_queue_purge(&sk->sk_receive_queue);
skb_queue_purge(&sk->sk_write_queue); skb_queue_purge(&sk->sk_write_queue);
} }
......
This diff is collapsed.
...@@ -48,6 +48,9 @@ void hci_conn_add_sysfs(struct hci_conn *conn) ...@@ -48,6 +48,9 @@ void hci_conn_add_sysfs(struct hci_conn *conn)
BT_DBG("conn %p", conn); BT_DBG("conn %p", conn);
if (device_is_registered(&conn->dev))
return;
dev_set_name(&conn->dev, "%s:%d", hdev->name, conn->handle); dev_set_name(&conn->dev, "%s:%d", hdev->name, conn->handle);
if (device_add(&conn->dev) < 0) { if (device_add(&conn->dev) < 0) {
......
...@@ -61,6 +61,9 @@ static void l2cap_send_disconn_req(struct l2cap_chan *chan, int err); ...@@ -61,6 +61,9 @@ static void l2cap_send_disconn_req(struct l2cap_chan *chan, int err);
static void l2cap_tx(struct l2cap_chan *chan, struct l2cap_ctrl *control, static void l2cap_tx(struct l2cap_chan *chan, struct l2cap_ctrl *control,
struct sk_buff_head *skbs, u8 event); struct sk_buff_head *skbs, u8 event);
static void l2cap_retrans_timeout(struct work_struct *work);
static void l2cap_monitor_timeout(struct work_struct *work);
static void l2cap_ack_timeout(struct work_struct *work);
static inline u8 bdaddr_type(u8 link_type, u8 bdaddr_type) static inline u8 bdaddr_type(u8 link_type, u8 bdaddr_type)
{ {
...@@ -476,6 +479,9 @@ struct l2cap_chan *l2cap_chan_create(void) ...@@ -476,6 +479,9 @@ struct l2cap_chan *l2cap_chan_create(void)
write_unlock(&chan_list_lock); write_unlock(&chan_list_lock);
INIT_DELAYED_WORK(&chan->chan_timer, l2cap_chan_timeout); INIT_DELAYED_WORK(&chan->chan_timer, l2cap_chan_timeout);
INIT_DELAYED_WORK(&chan->retrans_timer, l2cap_retrans_timeout);
INIT_DELAYED_WORK(&chan->monitor_timer, l2cap_monitor_timeout);
INIT_DELAYED_WORK(&chan->ack_timer, l2cap_ack_timeout);
chan->state = BT_OPEN; chan->state = BT_OPEN;
...@@ -3320,10 +3326,6 @@ int l2cap_ertm_init(struct l2cap_chan *chan) ...@@ -3320,10 +3326,6 @@ int l2cap_ertm_init(struct l2cap_chan *chan)
chan->rx_state = L2CAP_RX_STATE_RECV; chan->rx_state = L2CAP_RX_STATE_RECV;
chan->tx_state = L2CAP_TX_STATE_XMIT; chan->tx_state = L2CAP_TX_STATE_XMIT;
INIT_DELAYED_WORK(&chan->retrans_timer, l2cap_retrans_timeout);
INIT_DELAYED_WORK(&chan->monitor_timer, l2cap_monitor_timeout);
INIT_DELAYED_WORK(&chan->ack_timer, l2cap_ack_timeout);
skb_queue_head_init(&chan->srej_q); skb_queue_head_init(&chan->srej_q);
err = l2cap_seq_list_init(&chan->srej_list, chan->tx_win); err = l2cap_seq_list_init(&chan->srej_list, chan->tx_win);
...@@ -4307,6 +4309,12 @@ static int l2cap_connect_create_rsp(struct l2cap_conn *conn, ...@@ -4307,6 +4309,12 @@ static int l2cap_connect_create_rsp(struct l2cap_conn *conn,
} }
} }
chan = l2cap_chan_hold_unless_zero(chan);
if (!chan) {
err = -EBADSLT;
goto unlock;
}
err = 0; err = 0;
l2cap_chan_lock(chan); l2cap_chan_lock(chan);
...@@ -4336,6 +4344,7 @@ static int l2cap_connect_create_rsp(struct l2cap_conn *conn, ...@@ -4336,6 +4344,7 @@ static int l2cap_connect_create_rsp(struct l2cap_conn *conn,
} }
l2cap_chan_unlock(chan); l2cap_chan_unlock(chan);
l2cap_chan_put(chan);
unlock: unlock:
mutex_unlock(&conn->chan_lock); mutex_unlock(&conn->chan_lock);
......
This diff is collapsed.
...@@ -314,3 +314,77 @@ void mgmt_pending_remove(struct mgmt_pending_cmd *cmd) ...@@ -314,3 +314,77 @@ void mgmt_pending_remove(struct mgmt_pending_cmd *cmd)
list_del(&cmd->list); list_del(&cmd->list);
mgmt_pending_free(cmd); mgmt_pending_free(cmd);
} }
void mgmt_mesh_foreach(struct hci_dev *hdev,
void (*cb)(struct mgmt_mesh_tx *mesh_tx, void *data),
void *data, struct sock *sk)
{
struct mgmt_mesh_tx *mesh_tx, *tmp;
list_for_each_entry_safe(mesh_tx, tmp, &hdev->mgmt_pending, list) {
if (!sk || mesh_tx->sk == sk)
cb(mesh_tx, data);
}
}
struct mgmt_mesh_tx *mgmt_mesh_next(struct hci_dev *hdev, struct sock *sk)
{
struct mgmt_mesh_tx *mesh_tx;
if (list_empty(&hdev->mesh_pending))
return NULL;
list_for_each_entry(mesh_tx, &hdev->mesh_pending, list) {
if (!sk || mesh_tx->sk == sk)
return mesh_tx;
}
return NULL;
}
struct mgmt_mesh_tx *mgmt_mesh_find(struct hci_dev *hdev, u8 handle)
{
struct mgmt_mesh_tx *mesh_tx;
if (list_empty(&hdev->mesh_pending))
return NULL;
list_for_each_entry(mesh_tx, &hdev->mesh_pending, list) {
if (mesh_tx->handle == handle)
return mesh_tx;
}
return NULL;
}
struct mgmt_mesh_tx *mgmt_mesh_add(struct sock *sk, struct hci_dev *hdev,
void *data, u16 len)
{
struct mgmt_mesh_tx *mesh_tx;
mesh_tx = kzalloc(sizeof(*mesh_tx), GFP_KERNEL);
if (!mesh_tx)
return NULL;
hdev->mesh_send_ref++;
if (!hdev->mesh_send_ref)
hdev->mesh_send_ref++;
mesh_tx->handle = hdev->mesh_send_ref;
mesh_tx->index = hdev->id;
memcpy(mesh_tx->param, data, len);
mesh_tx->param_len = len;
mesh_tx->sk = sk;
sock_hold(sk);
list_add_tail(&mesh_tx->list, &hdev->mesh_pending);
return mesh_tx;
}
void mgmt_mesh_remove(struct mgmt_mesh_tx *mesh_tx)
{
list_del(&mesh_tx->list);
sock_put(mesh_tx->sk);
kfree(mesh_tx);
}
...@@ -20,6 +20,16 @@ ...@@ -20,6 +20,16 @@
SOFTWARE IS DISCLAIMED. SOFTWARE IS DISCLAIMED.
*/ */
struct mgmt_mesh_tx {
struct list_head list;
int index;
size_t param_len;
struct sock *sk;
u8 handle;
u8 instance;
u8 param[sizeof(struct mgmt_cp_mesh_send) + 29];
};
struct mgmt_pending_cmd { struct mgmt_pending_cmd {
struct list_head list; struct list_head list;
u16 opcode; u16 opcode;
...@@ -59,3 +69,11 @@ struct mgmt_pending_cmd *mgmt_pending_new(struct sock *sk, u16 opcode, ...@@ -59,3 +69,11 @@ struct mgmt_pending_cmd *mgmt_pending_new(struct sock *sk, u16 opcode,
void *data, u16 len); void *data, u16 len);
void mgmt_pending_free(struct mgmt_pending_cmd *cmd); void mgmt_pending_free(struct mgmt_pending_cmd *cmd);
void mgmt_pending_remove(struct mgmt_pending_cmd *cmd); void mgmt_pending_remove(struct mgmt_pending_cmd *cmd);
void mgmt_mesh_foreach(struct hci_dev *hdev,
void (*cb)(struct mgmt_mesh_tx *mesh_tx, void *data),
void *data, struct sock *sk);
struct mgmt_mesh_tx *mgmt_mesh_find(struct hci_dev *hdev, u8 handle);
struct mgmt_mesh_tx *mgmt_mesh_next(struct hci_dev *hdev, struct sock *sk);
struct mgmt_mesh_tx *mgmt_mesh_add(struct sock *sk, struct hci_dev *hdev,
void *data, u16 len);
void mgmt_mesh_remove(struct mgmt_mesh_tx *mesh_tx);
...@@ -902,7 +902,10 @@ static int rfcomm_sock_shutdown(struct socket *sock, int how) ...@@ -902,7 +902,10 @@ static int rfcomm_sock_shutdown(struct socket *sock, int how)
lock_sock(sk); lock_sock(sk);
if (!sk->sk_shutdown) { if (!sk->sk_shutdown) {
sk->sk_shutdown = SHUTDOWN_MASK; sk->sk_shutdown = SHUTDOWN_MASK;
release_sock(sk);
__rfcomm_sock_close(sk); __rfcomm_sock_close(sk);
lock_sock(sk);
if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime && if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime &&
!(current->flags & PF_EXITING)) !(current->flags & PF_EXITING))
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment