mirror of
https://github.com/raspberrypi/linux.git
synced 2025-12-06 01:49:46 +00:00
Merge tag 'for-net-2025-11-11' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth
Luiz Augusto von Dentz says: ==================== bluetooth pull request for net: - hci_conn: Fix not cleaning up PA_LINK connections - hci_event: Fix not handling PA Sync Lost event - MGMT: cancel mesh send timer when hdev removed - 6lowpan: reset link-local header on ipv6 recv path - 6lowpan: fix BDADDR_LE vs ADDR_LE_DEV address type confusion - L2CAP: export l2cap_chan_hold for modules - 6lowpan: Don't hold spin lock over sleeping functions - 6lowpan: add missing l2cap_chan_lock() - btusb: reorder cleanup in btusb_disconnect to avoid UAF - btrtl: Avoid loading the config file on security chips * tag 'for-net-2025-11-11' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth: Bluetooth: btrtl: Avoid loading the config file on security chips Bluetooth: hci_event: Fix not handling PA Sync Lost event Bluetooth: hci_conn: Fix not cleaning up PA_LINK connections Bluetooth: 6lowpan: add missing l2cap_chan_lock() Bluetooth: 6lowpan: Don't hold spin lock over sleeping functions Bluetooth: L2CAP: export l2cap_chan_hold for modules Bluetooth: 6lowpan: fix BDADDR_LE vs ADDR_LE_DEV address type confusion Bluetooth: 6lowpan: reset link-local header on ipv6 recv path Bluetooth: btusb: reorder cleanup in btusb_disconnect to avoid UAF Bluetooth: MGMT: cancel mesh send timer when hdev removed ==================== Link: https://patch.msgid.link/20251111141357.1983153-1-luiz.dentz@gmail.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
@@ -50,7 +50,7 @@
|
||||
|
||||
#define RTL_CHIP_SUBVER (&(struct rtl_vendor_cmd) {{0x10, 0x38, 0x04, 0x28, 0x80}})
|
||||
#define RTL_CHIP_REV (&(struct rtl_vendor_cmd) {{0x10, 0x3A, 0x04, 0x28, 0x80}})
|
||||
#define RTL_SEC_PROJ (&(struct rtl_vendor_cmd) {{0x10, 0xA4, 0x0D, 0x00, 0xb0}})
|
||||
#define RTL_SEC_PROJ (&(struct rtl_vendor_cmd) {{0x10, 0xA4, 0xAD, 0x00, 0xb0}})
|
||||
|
||||
#define RTL_PATCH_SNIPPETS 0x01
|
||||
#define RTL_PATCH_DUMMY_HEADER 0x02
|
||||
@@ -534,7 +534,6 @@ static int rtlbt_parse_firmware_v2(struct hci_dev *hdev,
|
||||
{
|
||||
struct rtl_epatch_header_v2 *hdr;
|
||||
int rc;
|
||||
u8 reg_val[2];
|
||||
u8 key_id;
|
||||
u32 num_sections;
|
||||
struct rtl_section *section;
|
||||
@@ -549,14 +548,7 @@ static int rtlbt_parse_firmware_v2(struct hci_dev *hdev,
|
||||
.len = btrtl_dev->fw_len - 7, /* Cut the tail */
|
||||
};
|
||||
|
||||
rc = btrtl_vendor_read_reg16(hdev, RTL_SEC_PROJ, reg_val);
|
||||
if (rc < 0)
|
||||
return -EIO;
|
||||
key_id = reg_val[0];
|
||||
|
||||
rtl_dev_dbg(hdev, "%s: key id %u", __func__, key_id);
|
||||
|
||||
btrtl_dev->key_id = key_id;
|
||||
key_id = btrtl_dev->key_id;
|
||||
|
||||
hdr = rtl_iov_pull_data(&iov, sizeof(*hdr));
|
||||
if (!hdr)
|
||||
@@ -1070,6 +1062,8 @@ struct btrtl_device_info *btrtl_initialize(struct hci_dev *hdev,
|
||||
u16 hci_rev, lmp_subver;
|
||||
u8 hci_ver, lmp_ver, chip_type = 0;
|
||||
int ret;
|
||||
int rc;
|
||||
u8 key_id;
|
||||
u8 reg_val[2];
|
||||
|
||||
btrtl_dev = kzalloc(sizeof(*btrtl_dev), GFP_KERNEL);
|
||||
@@ -1180,6 +1174,14 @@ next:
|
||||
goto err_free;
|
||||
}
|
||||
|
||||
rc = btrtl_vendor_read_reg16(hdev, RTL_SEC_PROJ, reg_val);
|
||||
if (rc < 0)
|
||||
goto err_free;
|
||||
|
||||
key_id = reg_val[0];
|
||||
btrtl_dev->key_id = key_id;
|
||||
rtl_dev_info(hdev, "%s: key id %u", __func__, key_id);
|
||||
|
||||
btrtl_dev->fw_len = -EIO;
|
||||
if (lmp_subver == RTL_ROM_LMP_8852A && hci_rev == 0x000c) {
|
||||
snprintf(fw_name, sizeof(fw_name), "%s_v2.bin",
|
||||
@@ -1202,7 +1204,7 @@ next:
|
||||
goto err_free;
|
||||
}
|
||||
|
||||
if (btrtl_dev->ic_info->cfg_name) {
|
||||
if (btrtl_dev->ic_info->cfg_name && !btrtl_dev->key_id) {
|
||||
if (postfix) {
|
||||
snprintf(cfg_name, sizeof(cfg_name), "%s-%s.bin",
|
||||
btrtl_dev->ic_info->cfg_name, postfix);
|
||||
|
||||
@@ -4361,6 +4361,11 @@ static void btusb_disconnect(struct usb_interface *intf)
|
||||
|
||||
hci_unregister_dev(hdev);
|
||||
|
||||
if (data->oob_wake_irq)
|
||||
device_init_wakeup(&data->udev->dev, false);
|
||||
if (data->reset_gpio)
|
||||
gpiod_put(data->reset_gpio);
|
||||
|
||||
if (intf == data->intf) {
|
||||
if (data->isoc)
|
||||
usb_driver_release_interface(&btusb_driver, data->isoc);
|
||||
@@ -4371,17 +4376,11 @@ static void btusb_disconnect(struct usb_interface *intf)
|
||||
usb_driver_release_interface(&btusb_driver, data->diag);
|
||||
usb_driver_release_interface(&btusb_driver, data->intf);
|
||||
} else if (intf == data->diag) {
|
||||
usb_driver_release_interface(&btusb_driver, data->intf);
|
||||
if (data->isoc)
|
||||
usb_driver_release_interface(&btusb_driver, data->isoc);
|
||||
usb_driver_release_interface(&btusb_driver, data->intf);
|
||||
}
|
||||
|
||||
if (data->oob_wake_irq)
|
||||
device_init_wakeup(&data->udev->dev, false);
|
||||
|
||||
if (data->reset_gpio)
|
||||
gpiod_put(data->reset_gpio);
|
||||
|
||||
hci_free_dev(hdev);
|
||||
}
|
||||
|
||||
|
||||
@@ -2783,6 +2783,11 @@ struct hci_ev_le_per_adv_report {
|
||||
__u8 data[];
|
||||
} __packed;
|
||||
|
||||
#define HCI_EV_LE_PA_SYNC_LOST 0x10
|
||||
struct hci_ev_le_pa_sync_lost {
|
||||
__le16 handle;
|
||||
} __packed;
|
||||
|
||||
#define LE_PA_DATA_COMPLETE 0x00
|
||||
#define LE_PA_DATA_MORE_TO_COME 0x01
|
||||
#define LE_PA_DATA_TRUNCATED 0x02
|
||||
|
||||
@@ -53,6 +53,11 @@ static bool enable_6lowpan;
|
||||
static struct l2cap_chan *listen_chan;
|
||||
static DEFINE_MUTEX(set_lock);
|
||||
|
||||
enum {
|
||||
LOWPAN_PEER_CLOSING,
|
||||
LOWPAN_PEER_MAXBITS
|
||||
};
|
||||
|
||||
struct lowpan_peer {
|
||||
struct list_head list;
|
||||
struct rcu_head rcu;
|
||||
@@ -61,6 +66,8 @@ struct lowpan_peer {
|
||||
/* peer addresses in various formats */
|
||||
unsigned char lladdr[ETH_ALEN];
|
||||
struct in6_addr peer_addr;
|
||||
|
||||
DECLARE_BITMAP(flags, LOWPAN_PEER_MAXBITS);
|
||||
};
|
||||
|
||||
struct lowpan_btle_dev {
|
||||
@@ -289,6 +296,7 @@ static int recv_pkt(struct sk_buff *skb, struct net_device *dev,
|
||||
local_skb->pkt_type = PACKET_HOST;
|
||||
local_skb->dev = dev;
|
||||
|
||||
skb_reset_mac_header(local_skb);
|
||||
skb_set_transport_header(local_skb, sizeof(struct ipv6hdr));
|
||||
|
||||
if (give_skb_to_upper(local_skb, dev) != NET_RX_SUCCESS) {
|
||||
@@ -919,7 +927,9 @@ static int bt_6lowpan_disconnect(struct l2cap_conn *conn, u8 dst_type)
|
||||
|
||||
BT_DBG("peer %p chan %p", peer, peer->chan);
|
||||
|
||||
l2cap_chan_lock(peer->chan);
|
||||
l2cap_chan_close(peer->chan, ENOENT);
|
||||
l2cap_chan_unlock(peer->chan);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -956,10 +966,11 @@ static struct l2cap_chan *bt_6lowpan_listen(void)
|
||||
}
|
||||
|
||||
static int get_l2cap_conn(char *buf, bdaddr_t *addr, u8 *addr_type,
|
||||
struct l2cap_conn **conn)
|
||||
struct l2cap_conn **conn, bool disconnect)
|
||||
{
|
||||
struct hci_conn *hcon;
|
||||
struct hci_dev *hdev;
|
||||
int le_addr_type;
|
||||
int n;
|
||||
|
||||
n = sscanf(buf, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx %hhu",
|
||||
@@ -970,13 +981,32 @@ static int get_l2cap_conn(char *buf, bdaddr_t *addr, u8 *addr_type,
|
||||
if (n < 7)
|
||||
return -EINVAL;
|
||||
|
||||
if (disconnect) {
|
||||
/* The "disconnect" debugfs command has used different address
|
||||
* type constants than "connect" since 2015. Let's retain that
|
||||
* for now even though it's obviously buggy...
|
||||
*/
|
||||
*addr_type += 1;
|
||||
}
|
||||
|
||||
switch (*addr_type) {
|
||||
case BDADDR_LE_PUBLIC:
|
||||
le_addr_type = ADDR_LE_DEV_PUBLIC;
|
||||
break;
|
||||
case BDADDR_LE_RANDOM:
|
||||
le_addr_type = ADDR_LE_DEV_RANDOM;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* The LE_PUBLIC address type is ignored because of BDADDR_ANY */
|
||||
hdev = hci_get_route(addr, BDADDR_ANY, BDADDR_LE_PUBLIC);
|
||||
if (!hdev)
|
||||
return -ENOENT;
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
hcon = hci_conn_hash_lookup_le(hdev, addr, *addr_type);
|
||||
hcon = hci_conn_hash_lookup_le(hdev, addr, le_addr_type);
|
||||
hci_dev_unlock(hdev);
|
||||
hci_dev_put(hdev);
|
||||
|
||||
@@ -993,41 +1023,52 @@ static int get_l2cap_conn(char *buf, bdaddr_t *addr, u8 *addr_type,
|
||||
static void disconnect_all_peers(void)
|
||||
{
|
||||
struct lowpan_btle_dev *entry;
|
||||
struct lowpan_peer *peer, *tmp_peer, *new_peer;
|
||||
struct list_head peers;
|
||||
struct lowpan_peer *peer;
|
||||
int nchans;
|
||||
|
||||
INIT_LIST_HEAD(&peers);
|
||||
|
||||
/* We make a separate list of peers as the close_cb() will
|
||||
* modify the device peers list so it is better not to mess
|
||||
* with the same list at the same time.
|
||||
/* l2cap_chan_close() cannot be called from RCU, and lock ordering
|
||||
* chan->lock > devices_lock prevents taking write side lock, so copy
|
||||
* then close.
|
||||
*/
|
||||
|
||||
rcu_read_lock();
|
||||
list_for_each_entry_rcu(entry, &bt_6lowpan_devices, list)
|
||||
list_for_each_entry_rcu(peer, &entry->peers, list)
|
||||
clear_bit(LOWPAN_PEER_CLOSING, peer->flags);
|
||||
rcu_read_unlock();
|
||||
|
||||
do {
|
||||
struct l2cap_chan *chans[32];
|
||||
int i;
|
||||
|
||||
nchans = 0;
|
||||
|
||||
spin_lock(&devices_lock);
|
||||
|
||||
list_for_each_entry_rcu(entry, &bt_6lowpan_devices, list) {
|
||||
list_for_each_entry_rcu(peer, &entry->peers, list) {
|
||||
new_peer = kmalloc(sizeof(*new_peer), GFP_ATOMIC);
|
||||
if (!new_peer)
|
||||
break;
|
||||
if (test_and_set_bit(LOWPAN_PEER_CLOSING,
|
||||
peer->flags))
|
||||
continue;
|
||||
|
||||
new_peer->chan = peer->chan;
|
||||
INIT_LIST_HEAD(&new_peer->list);
|
||||
l2cap_chan_hold(peer->chan);
|
||||
chans[nchans++] = peer->chan;
|
||||
|
||||
list_add(&new_peer->list, &peers);
|
||||
if (nchans >= ARRAY_SIZE(chans))
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
rcu_read_unlock();
|
||||
|
||||
spin_lock(&devices_lock);
|
||||
list_for_each_entry_safe(peer, tmp_peer, &peers, list) {
|
||||
l2cap_chan_close(peer->chan, ENOENT);
|
||||
|
||||
list_del_rcu(&peer->list);
|
||||
kfree_rcu(peer, rcu);
|
||||
}
|
||||
done:
|
||||
spin_unlock(&devices_lock);
|
||||
|
||||
for (i = 0; i < nchans; ++i) {
|
||||
l2cap_chan_lock(chans[i]);
|
||||
l2cap_chan_close(chans[i], ENOENT);
|
||||
l2cap_chan_unlock(chans[i]);
|
||||
l2cap_chan_put(chans[i]);
|
||||
}
|
||||
} while (nchans);
|
||||
}
|
||||
|
||||
struct set_enable {
|
||||
@@ -1050,7 +1091,9 @@ static void do_enable_set(struct work_struct *work)
|
||||
|
||||
mutex_lock(&set_lock);
|
||||
if (listen_chan) {
|
||||
l2cap_chan_lock(listen_chan);
|
||||
l2cap_chan_close(listen_chan, 0);
|
||||
l2cap_chan_unlock(listen_chan);
|
||||
l2cap_chan_put(listen_chan);
|
||||
}
|
||||
|
||||
@@ -1103,13 +1146,15 @@ static ssize_t lowpan_control_write(struct file *fp,
|
||||
buf[buf_size] = '\0';
|
||||
|
||||
if (memcmp(buf, "connect ", 8) == 0) {
|
||||
ret = get_l2cap_conn(&buf[8], &addr, &addr_type, &conn);
|
||||
ret = get_l2cap_conn(&buf[8], &addr, &addr_type, &conn, false);
|
||||
if (ret == -EINVAL)
|
||||
return ret;
|
||||
|
||||
mutex_lock(&set_lock);
|
||||
if (listen_chan) {
|
||||
l2cap_chan_lock(listen_chan);
|
||||
l2cap_chan_close(listen_chan, 0);
|
||||
l2cap_chan_unlock(listen_chan);
|
||||
l2cap_chan_put(listen_chan);
|
||||
listen_chan = NULL;
|
||||
}
|
||||
@@ -1140,7 +1185,7 @@ static ssize_t lowpan_control_write(struct file *fp,
|
||||
}
|
||||
|
||||
if (memcmp(buf, "disconnect ", 11) == 0) {
|
||||
ret = get_l2cap_conn(&buf[11], &addr, &addr_type, &conn);
|
||||
ret = get_l2cap_conn(&buf[11], &addr, &addr_type, &conn, true);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@@ -1271,7 +1316,9 @@ static void __exit bt_6lowpan_exit(void)
|
||||
debugfs_remove(lowpan_control_debugfs);
|
||||
|
||||
if (listen_chan) {
|
||||
l2cap_chan_lock(listen_chan);
|
||||
l2cap_chan_close(listen_chan, 0);
|
||||
l2cap_chan_unlock(listen_chan);
|
||||
l2cap_chan_put(listen_chan);
|
||||
}
|
||||
|
||||
|
||||
@@ -769,21 +769,23 @@ static void find_bis(struct hci_conn *conn, void *data)
|
||||
d->count++;
|
||||
}
|
||||
|
||||
static int hci_le_big_terminate(struct hci_dev *hdev, u8 big, struct hci_conn *conn)
|
||||
static int hci_le_big_terminate(struct hci_dev *hdev, struct hci_conn *conn)
|
||||
{
|
||||
struct iso_list_data *d;
|
||||
int ret;
|
||||
|
||||
bt_dev_dbg(hdev, "big 0x%2.2x sync_handle 0x%4.4x", big, conn->sync_handle);
|
||||
bt_dev_dbg(hdev, "hcon %p big 0x%2.2x sync_handle 0x%4.4x", conn,
|
||||
conn->iso_qos.bcast.big, conn->sync_handle);
|
||||
|
||||
d = kzalloc(sizeof(*d), GFP_KERNEL);
|
||||
if (!d)
|
||||
return -ENOMEM;
|
||||
|
||||
d->big = big;
|
||||
d->big = conn->iso_qos.bcast.big;
|
||||
d->sync_handle = conn->sync_handle;
|
||||
|
||||
if (test_and_clear_bit(HCI_CONN_PA_SYNC, &conn->flags)) {
|
||||
if (conn->type == PA_LINK &&
|
||||
test_and_clear_bit(HCI_CONN_PA_SYNC, &conn->flags)) {
|
||||
hci_conn_hash_list_flag(hdev, find_bis, PA_LINK,
|
||||
HCI_CONN_PA_SYNC, d);
|
||||
|
||||
@@ -801,6 +803,9 @@ static int hci_le_big_terminate(struct hci_dev *hdev, u8 big, struct hci_conn *c
|
||||
d->big_sync_term = true;
|
||||
}
|
||||
|
||||
if (!d->pa_sync_term && !d->big_sync_term)
|
||||
return 0;
|
||||
|
||||
ret = hci_cmd_sync_queue(hdev, big_terminate_sync, d,
|
||||
terminate_big_destroy);
|
||||
if (ret)
|
||||
@@ -852,8 +857,7 @@ static void bis_cleanup(struct hci_conn *conn)
|
||||
|
||||
hci_le_terminate_big(hdev, conn);
|
||||
} else {
|
||||
hci_le_big_terminate(hdev, conn->iso_qos.bcast.big,
|
||||
conn);
|
||||
hci_le_big_terminate(hdev, conn);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -994,19 +998,20 @@ static struct hci_conn *__hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t
|
||||
conn->mtu = hdev->le_mtu ? hdev->le_mtu : hdev->acl_mtu;
|
||||
break;
|
||||
case CIS_LINK:
|
||||
case BIS_LINK:
|
||||
case PA_LINK:
|
||||
/* conn->src should reflect the local identity address */
|
||||
hci_copy_identity_address(hdev, &conn->src, &conn->src_type);
|
||||
|
||||
/* set proper cleanup function */
|
||||
if (!bacmp(dst, BDADDR_ANY))
|
||||
conn->cleanup = bis_cleanup;
|
||||
else if (conn->role == HCI_ROLE_MASTER)
|
||||
if (conn->role == HCI_ROLE_MASTER)
|
||||
conn->cleanup = cis_cleanup;
|
||||
|
||||
conn->mtu = hdev->iso_mtu ? hdev->iso_mtu :
|
||||
hdev->le_mtu ? hdev->le_mtu : hdev->acl_mtu;
|
||||
conn->mtu = hdev->iso_mtu;
|
||||
break;
|
||||
case PA_LINK:
|
||||
case BIS_LINK:
|
||||
/* conn->src should reflect the local identity address */
|
||||
hci_copy_identity_address(hdev, &conn->src, &conn->src_type);
|
||||
conn->cleanup = bis_cleanup;
|
||||
conn->mtu = hdev->iso_mtu;
|
||||
break;
|
||||
case SCO_LINK:
|
||||
if (lmp_esco_capable(hdev))
|
||||
|
||||
@@ -5843,6 +5843,29 @@ static void hci_le_enh_conn_complete_evt(struct hci_dev *hdev, void *data,
|
||||
le16_to_cpu(ev->supervision_timeout));
|
||||
}
|
||||
|
||||
static void hci_le_pa_sync_lost_evt(struct hci_dev *hdev, void *data,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct hci_ev_le_pa_sync_lost *ev = data;
|
||||
u16 handle = le16_to_cpu(ev->handle);
|
||||
struct hci_conn *conn;
|
||||
|
||||
bt_dev_dbg(hdev, "sync handle 0x%4.4x", handle);
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
|
||||
/* Delete the pa sync connection */
|
||||
conn = hci_conn_hash_lookup_pa_sync_handle(hdev, handle);
|
||||
if (conn) {
|
||||
clear_bit(HCI_CONN_BIG_SYNC, &conn->flags);
|
||||
clear_bit(HCI_CONN_PA_SYNC, &conn->flags);
|
||||
hci_disconn_cfm(conn, HCI_ERROR_REMOTE_USER_TERM);
|
||||
hci_conn_del(conn);
|
||||
}
|
||||
|
||||
hci_dev_unlock(hdev);
|
||||
}
|
||||
|
||||
static void hci_le_ext_adv_term_evt(struct hci_dev *hdev, void *data,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
@@ -7001,14 +7024,9 @@ static void hci_le_big_sync_established_evt(struct hci_dev *hdev, void *data,
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ev->status != 0x42) {
|
||||
if (ev->status != 0x42)
|
||||
/* Mark PA sync as established */
|
||||
set_bit(HCI_CONN_PA_SYNC, &bis->flags);
|
||||
/* Reset cleanup callback of PA Sync so it doesn't
|
||||
* terminate the sync when deleting the connection.
|
||||
*/
|
||||
conn->cleanup = NULL;
|
||||
}
|
||||
|
||||
bis->sync_handle = conn->sync_handle;
|
||||
bis->iso_qos.bcast.big = ev->handle;
|
||||
@@ -7051,29 +7069,24 @@ static void hci_le_big_sync_lost_evt(struct hci_dev *hdev, void *data,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct hci_evt_le_big_sync_lost *ev = data;
|
||||
struct hci_conn *bis, *conn;
|
||||
bool mgmt_conn;
|
||||
struct hci_conn *bis;
|
||||
bool mgmt_conn = false;
|
||||
|
||||
bt_dev_dbg(hdev, "big handle 0x%2.2x", ev->handle);
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
|
||||
/* Delete the pa sync connection */
|
||||
bis = hci_conn_hash_lookup_pa_sync_big_handle(hdev, ev->handle);
|
||||
if (bis) {
|
||||
conn = hci_conn_hash_lookup_pa_sync_handle(hdev,
|
||||
bis->sync_handle);
|
||||
if (conn)
|
||||
hci_conn_del(conn);
|
||||
}
|
||||
|
||||
/* Delete each bis connection */
|
||||
while ((bis = hci_conn_hash_lookup_big_state(hdev, ev->handle,
|
||||
BT_CONNECTED,
|
||||
HCI_ROLE_SLAVE))) {
|
||||
mgmt_conn = test_and_clear_bit(HCI_CONN_MGMT_CONNECTED, &bis->flags);
|
||||
mgmt_device_disconnected(hdev, &bis->dst, bis->type, bis->dst_type,
|
||||
ev->reason, mgmt_conn);
|
||||
if (!mgmt_conn) {
|
||||
mgmt_conn = test_and_clear_bit(HCI_CONN_MGMT_CONNECTED,
|
||||
&bis->flags);
|
||||
mgmt_device_disconnected(hdev, &bis->dst, bis->type,
|
||||
bis->dst_type, ev->reason,
|
||||
mgmt_conn);
|
||||
}
|
||||
|
||||
clear_bit(HCI_CONN_BIG_SYNC, &bis->flags);
|
||||
hci_disconn_cfm(bis, ev->reason);
|
||||
@@ -7187,6 +7200,9 @@ static const struct hci_le_ev {
|
||||
hci_le_per_adv_report_evt,
|
||||
sizeof(struct hci_ev_le_per_adv_report),
|
||||
HCI_MAX_EVENT_SIZE),
|
||||
/* [0x10 = HCI_EV_LE_PA_SYNC_LOST] */
|
||||
HCI_LE_EV(HCI_EV_LE_PA_SYNC_LOST, hci_le_pa_sync_lost_evt,
|
||||
sizeof(struct hci_ev_le_pa_sync_lost)),
|
||||
/* [0x12 = HCI_EV_LE_EXT_ADV_SET_TERM] */
|
||||
HCI_LE_EV(HCI_EV_LE_EXT_ADV_SET_TERM, hci_le_ext_adv_term_evt,
|
||||
sizeof(struct hci_evt_le_ext_adv_set_term)),
|
||||
|
||||
@@ -6999,7 +6999,7 @@ static void create_pa_complete(struct hci_dev *hdev, void *data, int err)
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
|
||||
if (!hci_conn_valid(hdev, conn))
|
||||
if (hci_conn_valid(hdev, conn))
|
||||
clear_bit(HCI_CONN_CREATE_PA_SYNC, &conn->flags);
|
||||
|
||||
if (!err)
|
||||
|
||||
@@ -497,6 +497,7 @@ void l2cap_chan_hold(struct l2cap_chan *c)
|
||||
|
||||
kref_get(&c->kref);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(l2cap_chan_hold);
|
||||
|
||||
struct l2cap_chan *l2cap_chan_hold_unless_zero(struct l2cap_chan *c)
|
||||
{
|
||||
|
||||
@@ -9497,6 +9497,7 @@ void mgmt_index_removed(struct hci_dev *hdev)
|
||||
cancel_delayed_work_sync(&hdev->discov_off);
|
||||
cancel_delayed_work_sync(&hdev->service_cache);
|
||||
cancel_delayed_work_sync(&hdev->rpa_expired);
|
||||
cancel_delayed_work_sync(&hdev->mesh_send_done);
|
||||
}
|
||||
|
||||
void mgmt_power_on(struct hci_dev *hdev, int err)
|
||||
|
||||
Reference in New Issue
Block a user