Merge branch 'bluetooth-fixes-from-next'

Cherry-pick what looks like safe fixes from the bluetooth
net-next PR. The other changes will have to wait for 6.6

Link: https://lore.kernel.org/all/20230627191004.2586540-1-luiz.dentz@gmail.com/
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Jakub Kicinski 2023-06-29 10:49:38 -07:00
commit 56f66ce1fd
13 changed files with 130 additions and 66 deletions

View file

@ -637,7 +637,7 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
snprintf(config.fwname, sizeof(config.fwname), snprintf(config.fwname, sizeof(config.fwname),
"qca/%s", firmware_name); "qca/%s", firmware_name);
else if (qca_is_wcn399x(soc_type)) { else if (qca_is_wcn399x(soc_type)) {
if (ver.soc_id == QCA_WCN3991_SOC_ID) { if (le32_to_cpu(ver.soc_id) == QCA_WCN3991_SOC_ID) {
snprintf(config.fwname, sizeof(config.fwname), snprintf(config.fwname, sizeof(config.fwname),
"qca/crnv%02xu.bin", rom_ver); "qca/crnv%02xu.bin", rom_ver);
} else { } else {

View file

@ -1367,14 +1367,30 @@ MODULE_FIRMWARE("rtl_bt/rtl8723cs_vf_fw.bin");
MODULE_FIRMWARE("rtl_bt/rtl8723cs_vf_config.bin"); MODULE_FIRMWARE("rtl_bt/rtl8723cs_vf_config.bin");
MODULE_FIRMWARE("rtl_bt/rtl8723cs_xx_fw.bin"); MODULE_FIRMWARE("rtl_bt/rtl8723cs_xx_fw.bin");
MODULE_FIRMWARE("rtl_bt/rtl8723cs_xx_config.bin"); MODULE_FIRMWARE("rtl_bt/rtl8723cs_xx_config.bin");
MODULE_FIRMWARE("rtl_bt/rtl8723d_fw.bin");
MODULE_FIRMWARE("rtl_bt/rtl8723d_config.bin");
MODULE_FIRMWARE("rtl_bt/rtl8723ds_fw.bin"); MODULE_FIRMWARE("rtl_bt/rtl8723ds_fw.bin");
MODULE_FIRMWARE("rtl_bt/rtl8723ds_config.bin"); MODULE_FIRMWARE("rtl_bt/rtl8723ds_config.bin");
MODULE_FIRMWARE("rtl_bt/rtl8761a_fw.bin"); MODULE_FIRMWARE("rtl_bt/rtl8761a_fw.bin");
MODULE_FIRMWARE("rtl_bt/rtl8761a_config.bin"); MODULE_FIRMWARE("rtl_bt/rtl8761a_config.bin");
MODULE_FIRMWARE("rtl_bt/rtl8761b_fw.bin");
MODULE_FIRMWARE("rtl_bt/rtl8761b_config.bin");
MODULE_FIRMWARE("rtl_bt/rtl8761bu_fw.bin");
MODULE_FIRMWARE("rtl_bt/rtl8761bu_config.bin");
MODULE_FIRMWARE("rtl_bt/rtl8821a_fw.bin"); MODULE_FIRMWARE("rtl_bt/rtl8821a_fw.bin");
MODULE_FIRMWARE("rtl_bt/rtl8821a_config.bin"); MODULE_FIRMWARE("rtl_bt/rtl8821a_config.bin");
MODULE_FIRMWARE("rtl_bt/rtl8821c_fw.bin");
MODULE_FIRMWARE("rtl_bt/rtl8821c_config.bin");
MODULE_FIRMWARE("rtl_bt/rtl8821cs_fw.bin");
MODULE_FIRMWARE("rtl_bt/rtl8821cs_config.bin");
MODULE_FIRMWARE("rtl_bt/rtl8822b_fw.bin"); MODULE_FIRMWARE("rtl_bt/rtl8822b_fw.bin");
MODULE_FIRMWARE("rtl_bt/rtl8822b_config.bin"); MODULE_FIRMWARE("rtl_bt/rtl8822b_config.bin");
MODULE_FIRMWARE("rtl_bt/rtl8822cs_fw.bin");
MODULE_FIRMWARE("rtl_bt/rtl8822cs_config.bin");
MODULE_FIRMWARE("rtl_bt/rtl8822cu_fw.bin");
MODULE_FIRMWARE("rtl_bt/rtl8822cu_config.bin");
MODULE_FIRMWARE("rtl_bt/rtl8851bu_fw.bin");
MODULE_FIRMWARE("rtl_bt/rtl8851bu_config.bin");
MODULE_FIRMWARE("rtl_bt/rtl8852au_fw.bin"); MODULE_FIRMWARE("rtl_bt/rtl8852au_fw.bin");
MODULE_FIRMWARE("rtl_bt/rtl8852au_config.bin"); MODULE_FIRMWARE("rtl_bt/rtl8852au_config.bin");
MODULE_FIRMWARE("rtl_bt/rtl8852bs_fw.bin"); MODULE_FIRMWARE("rtl_bt/rtl8852bs_fw.bin");
@ -1383,5 +1399,3 @@ MODULE_FIRMWARE("rtl_bt/rtl8852bu_fw.bin");
MODULE_FIRMWARE("rtl_bt/rtl8852bu_config.bin"); MODULE_FIRMWARE("rtl_bt/rtl8852bu_config.bin");
MODULE_FIRMWARE("rtl_bt/rtl8852cu_fw.bin"); MODULE_FIRMWARE("rtl_bt/rtl8852cu_fw.bin");
MODULE_FIRMWARE("rtl_bt/rtl8852cu_config.bin"); MODULE_FIRMWARE("rtl_bt/rtl8852cu_config.bin");
MODULE_FIRMWARE("rtl_bt/rtl8851bu_fw.bin");
MODULE_FIRMWARE("rtl_bt/rtl8851bu_config.bin");

View file

@ -613,6 +613,9 @@ static const struct usb_device_id blacklist_table[] = {
{ USB_DEVICE(0x0489, 0xe0d9), .driver_info = BTUSB_MEDIATEK | { USB_DEVICE(0x0489, 0xe0d9), .driver_info = BTUSB_MEDIATEK |
BTUSB_WIDEBAND_SPEECH | BTUSB_WIDEBAND_SPEECH |
BTUSB_VALID_LE_STATES }, BTUSB_VALID_LE_STATES },
{ USB_DEVICE(0x0489, 0xe0f5), .driver_info = BTUSB_MEDIATEK |
BTUSB_WIDEBAND_SPEECH |
BTUSB_VALID_LE_STATES },
{ USB_DEVICE(0x13d3, 0x3568), .driver_info = BTUSB_MEDIATEK | { USB_DEVICE(0x13d3, 0x3568), .driver_info = BTUSB_MEDIATEK |
BTUSB_WIDEBAND_SPEECH | BTUSB_WIDEBAND_SPEECH |
BTUSB_VALID_LE_STATES }, BTUSB_VALID_LE_STATES },
@ -655,6 +658,8 @@ static const struct usb_device_id blacklist_table[] = {
BTUSB_WIDEBAND_SPEECH }, BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x0bda, 0x8771), .driver_info = BTUSB_REALTEK | { USB_DEVICE(0x0bda, 0x8771), .driver_info = BTUSB_REALTEK |
BTUSB_WIDEBAND_SPEECH }, BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x6655, 0x8771), .driver_info = BTUSB_REALTEK |
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x7392, 0xc611), .driver_info = BTUSB_REALTEK | { USB_DEVICE(0x7392, 0xc611), .driver_info = BTUSB_REALTEK |
BTUSB_WIDEBAND_SPEECH }, BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x2b89, 0x8761), .driver_info = BTUSB_REALTEK | { USB_DEVICE(0x2b89, 0x8761), .driver_info = BTUSB_REALTEK |

View file

@ -643,7 +643,8 @@ static int bcm_setup(struct hci_uart *hu)
* Allow the bootloader to set a valid address through the * Allow the bootloader to set a valid address through the
* device tree. * device tree.
*/ */
set_bit(HCI_QUIRK_USE_BDADDR_PROPERTY, &hu->hdev->quirks); if (test_bit(HCI_QUIRK_INVALID_BDADDR, &hu->hdev->quirks))
set_bit(HCI_QUIRK_USE_BDADDR_PROPERTY, &hu->hdev->quirks);
if (!bcm_request_irq(bcm)) if (!bcm_request_irq(bcm))
err = bcm_setup_sleep(hu); err = bcm_setup_sleep(hu);

View file

@ -185,7 +185,7 @@ struct bt_iso_ucast_qos {
struct bt_iso_bcast_qos { struct bt_iso_bcast_qos {
__u8 big; __u8 big;
__u8 bis; __u8 bis;
__u8 sync_interval; __u8 sync_factor;
__u8 packing; __u8 packing;
__u8 framing; __u8 framing;
struct bt_iso_io_qos in; struct bt_iso_io_qos in;

View file

@ -979,6 +979,7 @@ struct mgmt_ev_auth_failed {
#define MGMT_DEV_FOUND_NOT_CONNECTABLE BIT(2) #define MGMT_DEV_FOUND_NOT_CONNECTABLE BIT(2)
#define MGMT_DEV_FOUND_INITIATED_CONN BIT(3) #define MGMT_DEV_FOUND_INITIATED_CONN BIT(3)
#define MGMT_DEV_FOUND_NAME_REQUEST_FAILED BIT(4) #define MGMT_DEV_FOUND_NAME_REQUEST_FAILED BIT(4)
#define MGMT_DEV_FOUND_SCAN_RSP BIT(5)
#define MGMT_EV_DEVICE_FOUND 0x0012 #define MGMT_EV_DEVICE_FOUND 0x0012
struct mgmt_ev_device_found { struct mgmt_ev_device_found {

View file

@ -775,6 +775,11 @@ static void le_conn_timeout(struct work_struct *work)
hci_abort_conn(conn, HCI_ERROR_REMOTE_USER_TERM); hci_abort_conn(conn, HCI_ERROR_REMOTE_USER_TERM);
} }
struct iso_cig_params {
struct hci_cp_le_set_cig_params cp;
struct hci_cis_params cis[0x1f];
};
struct iso_list_data { struct iso_list_data {
union { union {
u8 cig; u8 cig;
@ -786,10 +791,7 @@ struct iso_list_data {
u16 sync_handle; u16 sync_handle;
}; };
int count; int count;
struct { struct iso_cig_params pdu;
struct hci_cp_le_set_cig_params cp;
struct hci_cis_params cis[0x11];
} pdu;
}; };
static void bis_list(struct hci_conn *conn, void *data) static void bis_list(struct hci_conn *conn, void *data)
@ -1764,10 +1766,33 @@ static int hci_le_create_big(struct hci_conn *conn, struct bt_iso_qos *qos)
return hci_send_cmd(hdev, HCI_OP_LE_CREATE_BIG, sizeof(cp), &cp); return hci_send_cmd(hdev, HCI_OP_LE_CREATE_BIG, sizeof(cp), &cp);
} }
static void set_cig_params_complete(struct hci_dev *hdev, void *data, int err)
{
struct iso_cig_params *pdu = data;
bt_dev_dbg(hdev, "");
if (err)
bt_dev_err(hdev, "Unable to set CIG parameters: %d", err);
kfree(pdu);
}
static int set_cig_params_sync(struct hci_dev *hdev, void *data)
{
struct iso_cig_params *pdu = data;
u32 plen;
plen = sizeof(pdu->cp) + pdu->cp.num_cis * sizeof(pdu->cis[0]);
return __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_CIG_PARAMS, plen, pdu,
HCI_CMD_TIMEOUT);
}
static bool hci_le_set_cig_params(struct hci_conn *conn, struct bt_iso_qos *qos) static bool hci_le_set_cig_params(struct hci_conn *conn, struct bt_iso_qos *qos)
{ {
struct hci_dev *hdev = conn->hdev; struct hci_dev *hdev = conn->hdev;
struct iso_list_data data; struct iso_list_data data;
struct iso_cig_params *pdu;
memset(&data, 0, sizeof(data)); memset(&data, 0, sizeof(data));
@ -1837,12 +1862,16 @@ static bool hci_le_set_cig_params(struct hci_conn *conn, struct bt_iso_qos *qos)
if (qos->ucast.cis == BT_ISO_QOS_CIS_UNSET || !data.pdu.cp.num_cis) if (qos->ucast.cis == BT_ISO_QOS_CIS_UNSET || !data.pdu.cp.num_cis)
return false; return false;
if (hci_send_cmd(hdev, HCI_OP_LE_SET_CIG_PARAMS, pdu = kmemdup(&data.pdu, sizeof(*pdu), GFP_KERNEL);
sizeof(data.pdu.cp) + if (!pdu)
(data.pdu.cp.num_cis * sizeof(*data.pdu.cis)),
&data.pdu) < 0)
return false; return false;
if (hci_cmd_sync_queue(hdev, set_cig_params_sync, pdu,
set_cig_params_complete) < 0) {
kfree(pdu);
return false;
}
return true; return true;
} }
@ -2044,10 +2073,10 @@ static int create_big_sync(struct hci_dev *hdev, void *data)
flags |= MGMT_ADV_FLAG_SEC_2M; flags |= MGMT_ADV_FLAG_SEC_2M;
/* Align intervals */ /* Align intervals */
interval = qos->bcast.out.interval / 1250; interval = (qos->bcast.out.interval / 1250) * qos->bcast.sync_factor;
if (qos->bcast.bis) if (qos->bcast.bis)
sync_interval = qos->bcast.sync_interval * 1600; sync_interval = interval * 4;
err = hci_start_per_adv_sync(hdev, qos->bcast.bis, conn->le_per_adv_data_len, err = hci_start_per_adv_sync(hdev, qos->bcast.bis, conn->le_per_adv_data_len,
conn->le_per_adv_data, flags, interval, conn->le_per_adv_data, flags, interval,

View file

@ -3812,7 +3812,8 @@ static u8 hci_cc_le_set_cig_params(struct hci_dev *hdev, void *data,
bt_dev_dbg(hdev, "status 0x%2.2x", rp->status); bt_dev_dbg(hdev, "status 0x%2.2x", rp->status);
cp = hci_sent_cmd_data(hdev, HCI_OP_LE_SET_CIG_PARAMS); cp = hci_sent_cmd_data(hdev, HCI_OP_LE_SET_CIG_PARAMS);
if (!cp || rp->num_handles != cp->num_cis || rp->cig_id != cp->cig_id) { if (!rp->status && (!cp || rp->num_handles != cp->num_cis ||
rp->cig_id != cp->cig_id)) {
bt_dev_err(hdev, "unexpected Set CIG Parameters response data"); bt_dev_err(hdev, "unexpected Set CIG Parameters response data");
status = HCI_ERROR_UNSPECIFIED; status = HCI_ERROR_UNSPECIFIED;
} }
@ -6316,23 +6317,18 @@ static void process_adv_report(struct hci_dev *hdev, u8 type, bdaddr_t *bdaddr,
return; return;
} }
/* When receiving non-connectable or scannable undirected /* When receiving a scan response, then there is no way to
* advertising reports, this means that the remote device is
* not connectable and then clearly indicate this in the
* device found event.
*
* When receiving a scan response, then there is no way to
* know if the remote device is connectable or not. However * know if the remote device is connectable or not. However
* since scan responses are merged with a previously seen * since scan responses are merged with a previously seen
* advertising report, the flags field from that report * advertising report, the flags field from that report
* will be used. * will be used.
* *
* In the really unlikely case that a controller get confused * In the unlikely case that a controller just sends a scan
* and just sends a scan response event, then it is marked as * response event that doesn't match the pending report, then
* not connectable as well. * it is marked as a standalone SCAN_RSP.
*/ */
if (type == LE_ADV_SCAN_RSP) if (type == LE_ADV_SCAN_RSP)
flags = MGMT_DEV_FOUND_NOT_CONNECTABLE; flags = MGMT_DEV_FOUND_SCAN_RSP;
/* If there's nothing pending either store the data from this /* If there's nothing pending either store the data from this
* event or send an immediate device found event if the data * event or send an immediate device found event if the data
@ -6790,6 +6786,7 @@ static void hci_le_cis_estabilished_evt(struct hci_dev *hdev, void *data,
{ {
struct hci_evt_le_cis_established *ev = data; struct hci_evt_le_cis_established *ev = data;
struct hci_conn *conn; struct hci_conn *conn;
struct bt_iso_qos *qos;
u16 handle = __le16_to_cpu(ev->handle); u16 handle = __le16_to_cpu(ev->handle);
bt_dev_dbg(hdev, "status 0x%2.2x", ev->status); bt_dev_dbg(hdev, "status 0x%2.2x", ev->status);
@ -6811,21 +6808,39 @@ static void hci_le_cis_estabilished_evt(struct hci_dev *hdev, void *data,
goto unlock; goto unlock;
} }
if (conn->role == HCI_ROLE_SLAVE) { qos = &conn->iso_qos;
__le32 interval;
memset(&interval, 0, sizeof(interval)); /* Convert ISO Interval (1.25 ms slots) to SDU Interval (us) */
qos->ucast.in.interval = le16_to_cpu(ev->interval) * 1250;
qos->ucast.out.interval = qos->ucast.in.interval;
memcpy(&interval, ev->c_latency, sizeof(ev->c_latency)); switch (conn->role) {
conn->iso_qos.ucast.in.interval = le32_to_cpu(interval); case HCI_ROLE_SLAVE:
memcpy(&interval, ev->p_latency, sizeof(ev->p_latency)); /* Convert Transport Latency (us) to Latency (msec) */
conn->iso_qos.ucast.out.interval = le32_to_cpu(interval); qos->ucast.in.latency =
conn->iso_qos.ucast.in.latency = le16_to_cpu(ev->interval); DIV_ROUND_CLOSEST(get_unaligned_le24(ev->c_latency),
conn->iso_qos.ucast.out.latency = le16_to_cpu(ev->interval); 1000);
conn->iso_qos.ucast.in.sdu = le16_to_cpu(ev->c_mtu); qos->ucast.out.latency =
conn->iso_qos.ucast.out.sdu = le16_to_cpu(ev->p_mtu); DIV_ROUND_CLOSEST(get_unaligned_le24(ev->p_latency),
conn->iso_qos.ucast.in.phy = ev->c_phy; 1000);
conn->iso_qos.ucast.out.phy = ev->p_phy; qos->ucast.in.sdu = le16_to_cpu(ev->c_mtu);
qos->ucast.out.sdu = le16_to_cpu(ev->p_mtu);
qos->ucast.in.phy = ev->c_phy;
qos->ucast.out.phy = ev->p_phy;
break;
case HCI_ROLE_MASTER:
/* Convert Transport Latency (us) to Latency (msec) */
qos->ucast.out.latency =
DIV_ROUND_CLOSEST(get_unaligned_le24(ev->c_latency),
1000);
qos->ucast.in.latency =
DIV_ROUND_CLOSEST(get_unaligned_le24(ev->p_latency),
1000);
qos->ucast.out.sdu = le16_to_cpu(ev->c_mtu);
qos->ucast.in.sdu = le16_to_cpu(ev->p_mtu);
qos->ucast.out.phy = ev->c_phy;
qos->ucast.in.phy = ev->p_phy;
break;
} }
if (!ev->status) { if (!ev->status) {

View file

@ -4623,26 +4623,18 @@ static int hci_dev_setup_sync(struct hci_dev *hdev)
* BD_ADDR invalid before creating the HCI device or in * BD_ADDR invalid before creating the HCI device or in
* its setup callback. * its setup callback.
*/ */
invalid_bdaddr = test_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks); invalid_bdaddr = test_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks) ||
test_bit(HCI_QUIRK_USE_BDADDR_PROPERTY, &hdev->quirks);
if (!ret) { if (!ret) {
if (test_bit(HCI_QUIRK_USE_BDADDR_PROPERTY, &hdev->quirks)) { if (test_bit(HCI_QUIRK_USE_BDADDR_PROPERTY, &hdev->quirks) &&
if (!bacmp(&hdev->public_addr, BDADDR_ANY)) !bacmp(&hdev->public_addr, BDADDR_ANY))
hci_dev_get_bd_addr_from_property(hdev); hci_dev_get_bd_addr_from_property(hdev);
if (bacmp(&hdev->public_addr, BDADDR_ANY) && if (invalid_bdaddr && bacmp(&hdev->public_addr, BDADDR_ANY) &&
hdev->set_bdaddr) { hdev->set_bdaddr) {
ret = hdev->set_bdaddr(hdev, ret = hdev->set_bdaddr(hdev, &hdev->public_addr);
&hdev->public_addr); if (!ret)
invalid_bdaddr = false;
/* If setting of the BD_ADDR from the device
* property succeeds, then treat the address
* as valid even if the invalid BD_ADDR
* quirk indicates otherwise.
*/
if (!ret)
invalid_bdaddr = false;
}
} }
} }

View file

@ -6,7 +6,9 @@
#include <net/bluetooth/bluetooth.h> #include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h> #include <net/bluetooth/hci_core.h>
static struct class *bt_class; static const struct class bt_class = {
.name = "bluetooth",
};
static void bt_link_release(struct device *dev) static void bt_link_release(struct device *dev)
{ {
@ -36,7 +38,7 @@ void hci_conn_init_sysfs(struct hci_conn *conn)
BT_DBG("conn %p", conn); BT_DBG("conn %p", conn);
conn->dev.type = &bt_link; conn->dev.type = &bt_link;
conn->dev.class = bt_class; conn->dev.class = &bt_class;
conn->dev.parent = &hdev->dev; conn->dev.parent = &hdev->dev;
device_initialize(&conn->dev); device_initialize(&conn->dev);
@ -104,7 +106,7 @@ void hci_init_sysfs(struct hci_dev *hdev)
struct device *dev = &hdev->dev; struct device *dev = &hdev->dev;
dev->type = &bt_host; dev->type = &bt_host;
dev->class = bt_class; dev->class = &bt_class;
__module_get(THIS_MODULE); __module_get(THIS_MODULE);
device_initialize(dev); device_initialize(dev);
@ -112,12 +114,10 @@ void hci_init_sysfs(struct hci_dev *hdev)
int __init bt_sysfs_init(void) int __init bt_sysfs_init(void)
{ {
bt_class = class_create("bluetooth"); return class_register(&bt_class);
return PTR_ERR_OR_ZERO(bt_class);
} }
void bt_sysfs_cleanup(void) void bt_sysfs_cleanup(void)
{ {
class_destroy(bt_class); class_unregister(&bt_class);
} }

View file

@ -704,7 +704,7 @@ static struct bt_iso_qos default_qos = {
.bcast = { .bcast = {
.big = BT_ISO_QOS_BIG_UNSET, .big = BT_ISO_QOS_BIG_UNSET,
.bis = BT_ISO_QOS_BIS_UNSET, .bis = BT_ISO_QOS_BIS_UNSET,
.sync_interval = 0x00, .sync_factor = 0x01,
.packing = 0x00, .packing = 0x00,
.framing = 0x00, .framing = 0x00,
.in = DEFAULT_IO_QOS, .in = DEFAULT_IO_QOS,
@ -1213,7 +1213,7 @@ static bool check_ucast_qos(struct bt_iso_qos *qos)
static bool check_bcast_qos(struct bt_iso_qos *qos) static bool check_bcast_qos(struct bt_iso_qos *qos)
{ {
if (qos->bcast.sync_interval > 0x07) if (qos->bcast.sync_factor == 0x00)
return false; return false;
if (qos->bcast.packing > 0x01) if (qos->bcast.packing > 0x01)

View file

@ -6374,9 +6374,14 @@ static inline int l2cap_le_command_rej(struct l2cap_conn *conn,
if (!chan) if (!chan)
goto done; goto done;
chan = l2cap_chan_hold_unless_zero(chan);
if (!chan)
goto done;
l2cap_chan_lock(chan); l2cap_chan_lock(chan);
l2cap_chan_del(chan, ECONNREFUSED); l2cap_chan_del(chan, ECONNREFUSED);
l2cap_chan_unlock(chan); l2cap_chan_unlock(chan);
l2cap_chan_put(chan);
done: done:
mutex_unlock(&conn->chan_lock); mutex_unlock(&conn->chan_lock);

View file

@ -46,6 +46,7 @@ static const struct proto_ops l2cap_sock_ops;
static void l2cap_sock_init(struct sock *sk, struct sock *parent); static void l2cap_sock_init(struct sock *sk, struct sock *parent);
static struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock, static struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock,
int proto, gfp_t prio, int kern); int proto, gfp_t prio, int kern);
static void l2cap_sock_cleanup_listen(struct sock *parent);
bool l2cap_is_socket(struct socket *sock) bool l2cap_is_socket(struct socket *sock)
{ {
@ -1415,6 +1416,7 @@ static int l2cap_sock_release(struct socket *sock)
if (!sk) if (!sk)
return 0; return 0;
l2cap_sock_cleanup_listen(sk);
bt_sock_unlink(&l2cap_sk_list, sk); bt_sock_unlink(&l2cap_sk_list, sk);
err = l2cap_sock_shutdown(sock, SHUT_RDWR); err = l2cap_sock_shutdown(sock, SHUT_RDWR);