summaryrefslogtreecommitdiff
path: root/net/bluetooth
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2026-10-22 15:58:00 -1000
committerLinus Torvalds <torvalds@linux-foundation.org>2026-10-22 15:58:00 -1000
commit734bef548a96e8774d6eef5dfa2026c6edc4e80b (patch)
treece2520b2602ce3b82f9842490d21836f9838d441 /net/bluetooth
parent864c07de0c7dcbca58b61625dfa2e461ae63b242 (diff)
parent1a2c35c49cc7c6be860038b8442b52424a8f123c (diff)
Merge tag 'net-next-7.4' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next
Pull networking updates from Paolo Abeni: "This includes a significant number of low-priority fixes - especially in the NIC drivers area - that we deferred from the last few RCs in the previous cycle, which can't be easily outlined in the synopsis below. Core & protocols: - Continue the work on removing rtnl_lock dependencies: - per-netns ARP and ND neighbour tables, with the default settings now configurable per netns (inheritance from init_net is controlled by the new net.core.neigh_inherit_init_net sysctl) - RCU-protected configuration and rtnl_lock-less fill_info() for hsr, netkit, sit, vlan and vxlan devices - per-netns device unregistration for ip tunnel and gre devices - use the netdev instance lock instead of rtnl_lock when reading speed and duplex via sysfs - batch the flushing of uncached routes at device unregistration time, relieving rtnl_lock contention on netns dismantle. - Add hardware pacing offload support, admin-controlled via a new rtnetlink attribute, with sch_fq integration (implemented in idpf). - Re-segment BIG TCP GSO packets into GSO packets fitting the egress device limits instead of plain MSS-sized segments, improving throughput for mixed BIG TCP / non-BIG TCP paths by up to 70%. - Generate RSS keys that spread flows over all the RX queues; the previous random keys could leave some queues unused. - Optimize the bridge VLAN forwarding paths: cache the port-VLAN in fdb entries and consider only VLAN members when flooding, for ~10% more Mpps in the fdb forwarding path. - A few TCP/IP performance improvements aimed at efficient cache usage and reducing contention. - Add the TCP ROCCET congestion control, a CUBIC variant aimed at avoiding bufferbloat in cellular networks. - Continue the conversion of getsockopt callbacks to sockopt_t. - Add an ethtool command to list the front-facing ports of an interface, including SFP cages and modules, using the phy_port representation. - Enable BIG TCP support for bareudp tunnels. - Remove the IPV6_ADDRFORM socket option and disallow buggy TCP state transitions (listen() + shutdown() + connect() and connect() + connect(AF_UNSPEC) + listen()). - Remove most BUG_ON()s from core packet processing, replacing them with error paths. Wireless: - Latency improvements, including lockless station get/dump and beacon updates, plus RTNL reduction and locking cleanups. - Infrastructure for non-station TX/RX with MLO. - NAN (Wi-Fi Aware) Instant Communication support and other NAN improvements. - Control frame Integrity Protocol (CIP) and protected TWT support. - Improvements for AP regulatory checks. Netfilter: - Disable br_netfilter in user namespaces and schedule it for removal in 2027. - Restrict the raw table in nft_compat to the specific family, hook and priority. - Prepare the flowtable for mixed IPv4-over-IPv6 tunneling (and vice versa). - Use GFP_KERNEL_ACCOUNT for most netfilter allocations, for better integration with memcg. - Allow discovering conntrack zone filtering support in ctnetlink dumps, and fix nfnetlink_hook handling of large dumps. Deletions: - Move the LLC type 2 sockets out of tree. There are no known users and the code attracts a never-ending stream of LLM-driven fixes. Device drivers: - New drivers: - Meta Platforms NIC (mpnic), the second-generation NIC from Meta - initial skeleton of the Nebula-matrix NICs driver (nbl) - X-Powers AC200/AC300 Fast Ethernet PHYs - Ethernet high-speed NICs: - Intel: - i40e: XDP metadata support for RX hash and VLAN tag - ice: expose the E825 TSPLL state via the DPLL subsystem - nVidia/Mellanox: - move the data direct infrastructure from IB to core, in preparation for netdev support. - reduce the memory used per offloaded TC rule - Meta (fbnic): - support large io_uring zero-copy RX buffers - Microsoft vNIC (mana): - add BQL support - Ethernet NICs consumer, and embedded: - Airoha: - LRO offload support - Cadence (macb): - context swapping for ringparam and MTU changes, avoiding buffer loss under memory pressure - Mucse (rnpgbe): - TX/RX and link status support - NXP (enetc): - SR-IOV improvements and VF support for ENETC v4 - Qualcomm (ppe): - IPQ5424 support - Realtek PCI (r8169): - phylink support - RSS support for RTL8127 - Renesas (ravb): - gPTP support for R-Car Gen4 - Synopsys (stmmac): - XDP multi-buffer support on the TX side - tc mqprio hw queue priority offload - support for RK3568 SGMII, Allwinner H616 EMAC1, UltraRISC DP1000 and Qualcomm sa8255p - Ethernet switches: - Mediatek (mt7530): - fast age and change conduit support - Microchip (ksz): - support for KSZ8995XA/KS8995XA - Microchip (lan966x): - PCIe FDMA support, ~20x throughput increase in PCIe endpoint - Microchip (sparx5): - Time Aware Shaper (taprio) offload - Motorcomm (yt921x): - LED and SerDes PCS support - Realtek (rtl8365mb): - EEE support - Ethernet PHYs: - Broadcom: - enable jumbo frames on BCM54xx - Realtek: - support for RTL8261CE_CG and RTL8261D_VM - MDIO support for RTL838x and RTL839x - WiFi drivers: - Broadcom (brcmfmac): - FT/OKC roaming offload - Intel (iwlwifi): - UHR sniffer support - support for newer UEFI/BIOS tables - MediaTek (mt76): - mt7925 NAN improvements - offchannel/scan improvements and MLO fixes - Morse Micro (mm81x): - monitor mode support - Qualcomm (ath12k): - IPQ5332 platform infrastructure - Realtek (rtw88): - RTL8723BS support - SDIO TX performance improvements - Realtek (rtw89): - P2P_DEVICE support - BT-coex updates for RTL8922D - Bluetooth: - move H:4 reassembly into the Bluetooth core - add generic support for vendor packets - MGMT: add security level changed event - Bluetooth drivers: - btusb: support Bulk Serialization Mode - Intel: support Draco and Titan Lake, allow unsigned firmware - Mediatek: MT7928 support - Qualcomm: QCC2072 support - Broadcom: Synaptics 4384 support" * tag 'net-next-7.4' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next: (2126 commits) Bluetooth: btusb: disable by default Qualcomm multi-subsystem tipc: fix broadcast sender hang on last acker departure tipc: fix use-after-free of broadcast reception link at node release r8169: clear TX LPI on RTL8168h at link up after phylink conversion tun: Require CAP_NET_ADMIN to attach to an ownerless device net/sched/sch_cake: drop dead nla_nest_end() error check net/sched/sch_cake: widen buffer_used to u64 net/sched/sch_cake: reduce parent backlog when clearing a tin net/sched/sch_cake: serialize reconfiguration with the datapath tg3: Add Datto SIRIS 5 1U Server to restart AER quirk table net/mlx5e: Stop asserting for RTNL when closing channels net: shrink the payload-only part of skb dataref to one bit net: wwan: iosm: validate msg_head before indexing msg_ring net: bgmac: rate limit RX error messages selftests: net: veth: test XDP_TX to a peer with GRO enabled veth: schedule the peer's NAPI after XDP_TX when only GRO is enabled pppoe: delete session hash entries by pointer match net: lan969x: don't disable hardirqs in fdma tx clear net: sparx5/lan969x: do not clobber the PSFP cycle timer update period net: lan969x: fix DSM calendar for empty taxis ...
Diffstat (limited to 'net/bluetooth')
-rw-r--r--net/bluetooth/6lowpan.c50
-rw-r--r--net/bluetooth/Makefile2
-rw-r--r--net/bluetooth/bnep/core.c16
-rw-r--r--net/bluetooth/hci_conn.c28
-rw-r--r--net/bluetooth/hci_core.c57
-rw-r--r--net/bluetooth/hci_debugfs.c9
-rw-r--r--net/bluetooth/hci_event.c290
-rw-r--r--net/bluetooth/hci_h4.c160
-rw-r--r--net/bluetooth/hci_sock.c8
-rw-r--r--net/bluetooth/hci_sync.c138
-rw-r--r--net/bluetooth/iso.c18
-rw-r--r--net/bluetooth/l2cap_core.c371
-rw-r--r--net/bluetooth/l2cap_sock.c122
-rw-r--r--net/bluetooth/mgmt.c204
-rw-r--r--net/bluetooth/msft.c6
-rw-r--r--net/bluetooth/rfcomm/core.c6
-rw-r--r--net/bluetooth/rfcomm/sock.c5
-rw-r--r--net/bluetooth/sco.c10
-rw-r--r--net/bluetooth/selftest.c1
-rw-r--r--net/bluetooth/smp.c5
20 files changed, 1208 insertions, 298 deletions
diff --git a/net/bluetooth/6lowpan.c b/net/bluetooth/6lowpan.c
index 30f4afa18bc8..8c51c20f6c4b 100644
--- a/net/bluetooth/6lowpan.c
+++ b/net/bluetooth/6lowpan.c
@@ -515,7 +515,7 @@ static netdev_tx_t bt_xmit(struct sk_buff *skb, struct net_device *netdev)
/* We must take a copy of the skb before we modify/replace the ipv6
* header as the header could be used elsewhere
*/
- skb = skb_unshare(skb, GFP_ATOMIC);
+ skb = skb_unclone_full(skb, GFP_ATOMIC);
if (!skb)
return NET_XMIT_DROP;
@@ -706,6 +706,7 @@ static int setup_netdev(struct l2cap_chan *chan, struct lowpan_btle_dev **dev)
spin_lock(&devices_lock);
list_del_rcu(&(*dev)->list);
spin_unlock(&devices_lock);
+ synchronize_rcu();
free_netdev(netdev);
goto out;
}
@@ -722,6 +723,8 @@ out:
}
static inline void chan_ready_cb(struct l2cap_chan *chan)
+ __must_hold(&chan->lock)
+ __must_hold(&chan->conn->lock)
{
struct lowpan_btle_dev *dev;
bool new_netdev = false;
@@ -912,18 +915,27 @@ static int bt_6lowpan_connect(bdaddr_t *addr, u8 dst_type)
static int bt_6lowpan_disconnect(struct l2cap_conn *conn, u8 dst_type)
{
struct lowpan_peer *peer;
+ struct l2cap_chan *chan;
BT_DBG("conn %p dst type %u", conn, dst_type);
+ spin_lock(&devices_lock);
+
peer = lookup_peer(conn);
- if (!peer)
+ if (!peer) {
+ spin_unlock(&devices_lock);
return -ENOENT;
+ }
+
+ chan = peer->chan;
+ l2cap_chan_hold(chan);
+
+ spin_unlock(&devices_lock);
- BT_DBG("peer %p chan %p", peer, peer->chan);
+ BT_DBG("peer %p chan %p", peer, chan);
- l2cap_chan_lock(peer->chan);
- l2cap_chan_close(peer->chan, ENOENT);
- l2cap_chan_unlock(peer->chan);
+ l2cap_chan_close_unlocked(chan, ENOENT);
+ l2cap_chan_put(chan);
return 0;
}
@@ -1025,9 +1037,9 @@ static void disconnect_all_peers(void)
struct lowpan_peer *peer;
int nchans;
- /* l2cap_chan_close() cannot be called from RCU, and lock ordering
- * chan->lock > devices_lock prevents taking write side lock, so copy
- * then close.
+ /* l2cap_chan_close_unlocked() cannot be called from RCU, and lock
+ * ordering chan->lock > devices_lock prevents taking write side lock,
+ * so copy then close.
*/
rcu_read_lock();
@@ -1062,9 +1074,7 @@ 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_close_unlocked(chans[i], ENOENT);
l2cap_chan_put(chans[i]);
}
} while (nchans);
@@ -1082,9 +1092,7 @@ static void do_enable_set(bool flag)
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_close_unlocked(listen_chan, 0);
l2cap_chan_put(listen_chan);
}
@@ -1132,9 +1140,7 @@ static ssize_t lowpan_control_write(struct file *fp,
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_close_unlocked(listen_chan, 0);
l2cap_chan_put(listen_chan);
listen_chan = NULL;
}
@@ -1209,6 +1215,7 @@ static int lowpan_control_open(struct inode *inode, struct file *file)
}
static const struct file_operations lowpan_control_fops = {
+ .owner = THIS_MODULE,
.open = lowpan_control_open,
.read = seq_read,
.write = lowpan_control_write,
@@ -1269,7 +1276,7 @@ static int device_event(struct notifier_block *unused,
if (entry->netdev == netdev) {
BT_DBG("Unregistered netdev %s %p",
netdev->name, netdev);
- list_del(&entry->list);
+ list_del_rcu(&entry->list);
break;
}
}
@@ -1303,10 +1310,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_close_unlocked(listen_chan, 0);
l2cap_chan_put(listen_chan);
+ listen_chan = NULL;
}
disconnect_devices();
diff --git a/net/bluetooth/Makefile b/net/bluetooth/Makefile
index ff466ea97436..b78ad98864d4 100644
--- a/net/bluetooth/Makefile
+++ b/net/bluetooth/Makefile
@@ -14,7 +14,7 @@ bluetooth_6lowpan-y := 6lowpan.o
bluetooth-y := af_bluetooth.o hci_core.o hci_conn.o hci_event.o mgmt.o \
hci_sock.o hci_sysfs.o l2cap_core.o l2cap_sock.o smp.o lib.o \
ecdh_helper.o mgmt_util.o mgmt_config.o hci_codec.o eir.o hci_sync.o \
- hci_drv.o
+ hci_drv.o hci_h4.o
bluetooth-$(CONFIG_DEV_COREDUMP) += coredump.o
diff --git a/net/bluetooth/bnep/core.c b/net/bluetooth/bnep/core.c
index ad24d2486665..06854f46ba34 100644
--- a/net/bluetooth/bnep/core.c
+++ b/net/bluetooth/bnep/core.c
@@ -495,10 +495,7 @@ send:
iv[il++] = (struct kvec) { skb->data, skb->len };
len += skb->len;
- /* FIXME: linearize skb */
- {
- len = kernel_sendmsg(sock, &s->msg, iv, il, len);
- }
+ len = kernel_sendmsg(sock, &s->msg, iv, il, len);
kfree_skb(skb);
if (len > 0) {
@@ -539,9 +536,12 @@ static int bnep_session(void *arg)
break;
/* TX */
- while ((skb = skb_dequeue(&sk->sk_write_queue)))
- if (bnep_tx_frame(s, skb))
+ while ((skb = skb_dequeue(&sk->sk_write_queue))) {
+ if (skb_linearize(skb))
+ kfree_skb(skb);
+ else if (bnep_tx_frame(s, skb))
break;
+ }
netif_wake_queue(dev);
/*
@@ -685,7 +685,7 @@ int bnep_add_connection(struct bnep_connadd_req *req, struct socket *sock)
goto failed;
}
- strcpy(req->device, dev->name);
+ strscpy(req->device, dev->name, sizeof(req->device));
up_write(&bnep_session_sem);
return 0;
@@ -727,7 +727,7 @@ static void __bnep_copy_ci(struct bnep_conninfo *ci, struct bnep_session *s)
memset(ci, 0, sizeof(*ci));
memcpy(ci->dst, s->eh.h_source, ETH_ALEN);
- strcpy(ci->device, s->dev->name);
+ strscpy(ci->device, s->dev->name, sizeof(ci->device));
ci->flags = s->flags & valid_flags;
ci->state = s->state;
ci->role = s->role;
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index cf44452e0766..29da3fe2b953 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -1233,6 +1233,29 @@ static void hci_conn_unlink(struct hci_conn *conn)
if (!conn->parent) {
struct hci_link *link, *t;
+ conn->sec_level = BT_SECURITY_SDP;
+ clear_bit(HCI_CONN_ENCRYPT, &conn->flags);
+ clear_bit(HCI_CONN_AES_CCM, &conn->flags);
+ /* mgmt_security_level_changed() reports the reset only if
+ * this connection was actually reported to userspace as
+ * connected (it checks HCI_CONN_MGMT_CONNECTED itself), so it
+ * must be called before the flag is cleared below.
+ * Callers that already know whether the connection was
+ * mgmt-connected (e.g. disconnect event handlers) only peek
+ * at the flag, so it is still set here; this is the place
+ * actually clearing it.
+ *
+ * Skip the report if hdev is down: this means
+ * hci_dev_close_sync()/hci_conn_hash_flush() is in progress
+ * and no MGMT_EV_DEVICE_DISCONNECTED was ever sent for this
+ * connection, so sending a security level reset here would
+ * be a spurious, order-less event; the adapter-wide powered
+ * off notification is enough for userspace to reset state.
+ */
+ if (test_bit(HCI_UP, &hdev->flags))
+ mgmt_security_level_changed(conn);
+ clear_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags);
+
list_for_each_entry_safe(link, t, &conn->link_list, list) {
struct hci_conn *child = link->conn;
@@ -1543,6 +1566,11 @@ struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst,
conn->pending_sec_level = sec_level;
}
+ /* Do not report the security level here: conn->dst may still hold
+ * the peer's RPA instead of its identity address, and the connection
+ * is not established yet. le_conn_complete_evt() reports it once the
+ * connection completes and the identity address has been resolved.
+ */
conn->sec_level = BT_SECURITY_LOW;
conn->conn_timeout = conn_timeout;
conn->le_adv_phy = phy;
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 74d9865e08c2..209244fd9391 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -1153,16 +1153,16 @@ struct smp_ltk *hci_find_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr,
continue;
if (smp_ltk_is_sc(k) || ltk_role(k->type) == role) {
- rcu_read_unlock();
-
if (hci_is_blocked_key(hdev, HCI_BLOCKED_KEY_TYPE_LTK,
k->val)) {
bt_dev_warn_ratelimited(hdev,
"LTK blocked for %pMR",
&k->bdaddr);
+ rcu_read_unlock();
return NULL;
}
+ rcu_read_unlock();
return k;
}
}
@@ -1617,7 +1617,7 @@ int hci_remove_adv_instance(struct hci_dev *hdev, u8 instance)
if (hdev->cur_adv_instance == instance) {
if (hdev->adv_instance_timeout) {
cancel_delayed_work(&hdev->adv_instance_expire);
- hdev->adv_instance_timeout = 0;
+ hdev->adv_instance_timeout = false;
}
hdev->cur_adv_instance = 0x00;
}
@@ -1647,7 +1647,7 @@ void hci_adv_instances_clear(struct hci_dev *hdev)
if (hdev->adv_instance_timeout) {
disable_delayed_work(&hdev->adv_instance_expire);
- hdev->adv_instance_timeout = 0;
+ hdev->adv_instance_timeout = false;
}
list_for_each_entry_safe(adv_instance, n, &hdev->adv_instances, list) {
@@ -2437,7 +2437,7 @@ struct hci_dev *hci_alloc_dev_priv(int sizeof_priv)
hdev->adv_tx_power = HCI_TX_POWER_INVALID;
hdev->adv_instance_cnt = 0;
hdev->cur_adv_instance = 0x00;
- hdev->adv_instance_timeout = 0;
+ hdev->adv_instance_timeout = false;
hdev->advmon_allowlist_duration = 300;
hdev->advmon_no_filter_duration = 500;
@@ -2929,6 +2929,8 @@ int hci_recv_frame(struct hci_dev *hdev, struct sk_buff *skb)
break;
case HCI_ISODATA_PKT:
break;
+ case HCI_VENDOR_PKT:
+ break;
case HCI_DRV_PKT:
break;
default:
@@ -3065,6 +3067,41 @@ static int hci_send_conn_frame(struct hci_dev *hdev, struct hci_conn *conn,
return hci_send_frame(hdev, skb);
}
+/**
+ * hci_send_vendor_frame - Send an HCI_VENDOR_PKT frame to the HCI driver
+ * @hdev: The HCI device
+ * @iter: iov_iter carrying the frame
+ *
+ * Return: 0 on success, or a negative errno on failure.
+ */
+int hci_send_vendor_frame(struct hci_dev *hdev, struct iov_iter *iter)
+{
+ struct sk_buff *skb;
+ unsigned int len;
+
+ if (WARN_ON(!iov_iter_is_kvec(iter)))
+ return -EINVAL;
+
+ /* Vendor frames are opaque, the caller guarantees the size. */
+ len = (unsigned int)iov_iter_count(iter);
+ if (!len)
+ return -EINVAL;
+
+ skb = bt_skb_alloc(len, GFP_KERNEL);
+ if (!skb)
+ return -ENOMEM;
+
+ if (!copy_from_iter_full(skb_put(skb, len), len, iter)) {
+ kfree_skb(skb);
+ return -EFAULT;
+ }
+
+ hci_skb_pkt_type(skb) = HCI_VENDOR_PKT;
+
+ return hci_send_frame(hdev, skb);
+}
+EXPORT_SYMBOL(hci_send_vendor_frame);
+
/* Send HCI command */
int hci_send_cmd(struct hci_dev *hdev, __u16 opcode, __u32 plen,
const void *param)
@@ -4102,6 +4139,14 @@ static void hci_rx_work(struct work_struct *work)
hci_isodata_packet(hdev, skb);
break;
+ case HCI_VENDOR_PKT:
+ BT_DBG("%s Vendor packet", hdev->name);
+ if (hdev->recv_vendor_pkt)
+ hdev->recv_vendor_pkt(hdev, skb);
+ else
+ kfree_skb(skb);
+ break;
+
default:
kfree_skb(skb);
break;
@@ -4123,7 +4168,7 @@ static int hci_send_cmd_sync(struct hci_dev *hdev, struct sk_buff *skb)
if (!hdev->sent_cmd) {
skb_queue_head(&hdev->cmd_q, skb);
queue_work(hdev->workqueue, &hdev->cmd_work);
- return -EINVAL;
+ return -ENOMEM;
}
if (hci_skb_opcode(skb) != HCI_OP_NOP) {
diff --git a/net/bluetooth/hci_debugfs.c b/net/bluetooth/hci_debugfs.c
index 2559fb6324d6..cd5ef398f238 100644
--- a/net/bluetooth/hci_debugfs.c
+++ b/net/bluetooth/hci_debugfs.c
@@ -65,6 +65,7 @@ static ssize_t __name ## _write(struct file *file, \
} \
\
static const struct file_operations __name ## _fops = { \
+ .owner = THIS_MODULE, \
.open = simple_open, \
.read = __name ## _read, \
.write = __name ## _write, \
@@ -283,6 +284,7 @@ static ssize_t use_debug_keys_read(struct file *file, char __user *user_buf,
}
static const struct file_operations use_debug_keys_fops = {
+ .owner = THIS_MODULE,
.open = simple_open,
.read = use_debug_keys_read,
.llseek = default_llseek,
@@ -301,6 +303,7 @@ static ssize_t sc_only_mode_read(struct file *file, char __user *user_buf,
}
static const struct file_operations sc_only_mode_fops = {
+ .owner = THIS_MODULE,
.open = simple_open,
.read = sc_only_mode_read,
.llseek = default_llseek,
@@ -437,6 +440,7 @@ static ssize_t ssp_debug_mode_read(struct file *file, char __user *user_buf,
}
static const struct file_operations ssp_debug_mode_fops = {
+ .owner = THIS_MODULE,
.open = simple_open,
.read = ssp_debug_mode_read,
.llseek = default_llseek,
@@ -529,6 +533,7 @@ static ssize_t force_bredr_smp_write(struct file *file,
}
static const struct file_operations force_bredr_smp_fops = {
+ .owner = THIS_MODULE,
.open = simple_open,
.read = force_bredr_smp_read,
.write = force_bredr_smp_write,
@@ -778,6 +783,7 @@ static ssize_t force_static_address_write(struct file *file,
}
static const struct file_operations force_static_address_fops = {
+ .owner = THIS_MODULE,
.open = simple_open,
.read = force_static_address_read,
.write = force_static_address_write,
@@ -1177,6 +1183,7 @@ static ssize_t force_no_mitm_write(struct file *file,
}
static const struct file_operations force_no_mitm_fops = {
+ .owner = THIS_MODULE,
.open = simple_open,
.read = force_no_mitm_read,
.write = force_no_mitm_write,
@@ -1315,6 +1322,7 @@ static ssize_t dut_mode_write(struct file *file, const char __user *user_buf,
}
static const struct file_operations dut_mode_fops = {
+ .owner = THIS_MODULE,
.open = simple_open,
.read = dut_mode_read,
.write = dut_mode_write,
@@ -1371,6 +1379,7 @@ done:
}
static const struct file_operations vendor_diag_fops = {
+ .owner = THIS_MODULE,
.open = simple_open,
.read = vendor_diag_read,
.write = vendor_diag_write,
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 2f5e21ff9752..1f80f2cf6b2c 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -404,10 +404,7 @@ static u8 hci_cc_write_auth_enable(struct hci_dev *hdev, void *data,
if (!rp->status) {
__u8 param = *((__u8 *) sent);
- if (param == AUTH_ENABLED)
- set_bit(HCI_AUTH, &hdev->flags);
- else
- clear_bit(HCI_AUTH, &hdev->flags);
+ assign_bit(HCI_AUTH, &hdev->flags, param == AUTH_ENABLED);
}
if (hci_dev_test_flag(hdev, HCI_MGMT))
@@ -436,10 +433,7 @@ static u8 hci_cc_write_encrypt_mode(struct hci_dev *hdev, void *data,
param = *((__u8 *) sent);
- if (param)
- set_bit(HCI_ENCRYPT, &hdev->flags);
- else
- clear_bit(HCI_ENCRYPT, &hdev->flags);
+ assign_bit(HCI_ENCRYPT, &hdev->flags, param);
return rp->status;
}
@@ -466,15 +460,9 @@ static u8 hci_cc_write_scan_enable(struct hci_dev *hdev, void *data,
goto done;
}
- if (param & SCAN_INQUIRY)
- set_bit(HCI_ISCAN, &hdev->flags);
- else
- clear_bit(HCI_ISCAN, &hdev->flags);
+ assign_bit(HCI_ISCAN, &hdev->flags, param & SCAN_INQUIRY);
- if (param & SCAN_PAGE)
- set_bit(HCI_PSCAN, &hdev->flags);
- else
- clear_bit(HCI_PSCAN, &hdev->flags);
+ assign_bit(HCI_PSCAN, &hdev->flags, param & SCAN_PAGE);
done:
hci_dev_unlock(hdev);
@@ -744,6 +732,14 @@ static u8 hci_cc_read_enc_key_size(struct hci_dev *hdev, void *data,
bt_dev_err(hdev, "failed to read key size for handle %u",
handle);
conn->enc_key_size = 0;
+ clear_bit(HCI_CONN_ENCRYPT, &conn->flags);
+ clear_bit(HCI_CONN_AES_CCM, &conn->flags);
+ /* Downgrade to reflect the connection no longer being
+ * encrypted, instead of advertising a stale elevated
+ * security level alongside MGMT_CONN_SEC_ENCRYPT_NONE.
+ */
+ if (conn->sec_level > BT_SECURITY_LOW)
+ conn->sec_level = BT_SECURITY_LOW;
} else {
u8 *key_enc_size = hci_conn_key_enc_size(conn);
@@ -767,6 +763,25 @@ static u8 hci_cc_read_enc_key_size(struct hci_dev *hdev, void *data,
status = HCI_ERROR_AUTH_FAILURE;
clear_bit(HCI_CONN_ENCRYPT, &conn->flags);
clear_bit(HCI_CONN_AES_CCM, &conn->flags);
+ /* Downgrade to reflect the connection no longer being
+ * encrypted, instead of advertising a stale elevated
+ * security level alongside MGMT_CONN_SEC_ENCRYPT_NONE.
+ */
+ if (conn->sec_level > BT_SECURITY_LOW)
+ conn->sec_level = BT_SECURITY_LOW;
+ } else {
+ /* Pre-apply hci_encrypt_cfm()'s own upgrade rules
+ * here unconditionally on success, so its internal
+ * change check below always finds nothing new: this
+ * function remains the sole place deciding whether
+ * and when to report the change, regardless of
+ * whether the caller already touched conn->sec_level
+ * (e.g. hci_encrypt_change_evt()) or not.
+ */
+ if (conn->sec_level == BT_SECURITY_SDP)
+ conn->sec_level = BT_SECURITY_LOW;
+ if (conn->pending_sec_level > conn->sec_level)
+ conn->sec_level = conn->pending_sec_level;
}
/* Update the key encryption size with the connection one */
@@ -776,6 +791,13 @@ static u8 hci_cc_read_enc_key_size(struct hci_dev *hdev, void *data,
hci_encrypt_cfm(conn, status);
+ /* mgmt_security_level_changed() only reports the change for
+ * connections already announced to userspace (it checks
+ * HCI_CONN_MGMT_CONNECTED itself); otherwise it is a no-op here and
+ * reporting is deferred to mgmt_device_connected().
+ */
+ mgmt_security_level_changed(conn);
+
done:
hci_dev_unlock(hdev);
@@ -1247,8 +1269,6 @@ static u8 hci_cc_le_read_conn_interval(struct hci_dev *hdev, void *data,
struct sk_buff *skb)
{
struct hci_rp_le_read_conn_interval *rp = data;
- u16 min_interval = 0;
- int i;
bt_dev_dbg(hdev, "status 0x%2.2x", rp->status);
@@ -1261,17 +1281,11 @@ static u8 hci_cc_le_read_conn_interval(struct hci_dev *hdev, void *data,
return HCI_ERROR_UNSPECIFIED;
}
- /* Store the smallest minimum supported connection interval reported by
- * the controller so the default rate parameters can be clamped to it.
+ /* Store the minimum supported connection interval so the default rate
+ * parameters can be clamped to it. It is reported on its own rather
+ * than derived from the groups, as there may be none.
*/
- for (i = 0; i < rp->num_grps; i++) {
- u16 min = le16_to_cpu(rp->grps[i].min);
-
- if (!min_interval || min < min_interval)
- min_interval = min;
- }
-
- hdev->le_min_rate_interval = min_interval;
+ hdev->le_min_rate_interval = rp->min;
return rp->status;
}
@@ -1617,6 +1631,39 @@ static u8 hci_cc_le_set_adv_enable(struct hci_dev *hdev, void *data,
return rp->status;
}
+/* Update the enabled state of the instance(s) using the advertising set
+ * identified by handle.
+ *
+ * Instances may share handle 0x00 with instance 0 (Global Advertising), e.g.
+ * when the controller supports a single advertising set, in which case the
+ * set is owned by the instance last enabled (hdev->cur_adv_instance) and any
+ * other instance sharing it shall be considered disabled.
+ */
+static void hci_le_ext_adv_set_enabled(struct hci_dev *hdev, u8 handle,
+ bool enable)
+{
+ struct adv_info *adv;
+ bool owned = false;
+
+ list_for_each_entry(adv, &hdev->adv_instances, list) {
+ if (adv->handle != handle)
+ continue;
+
+ adv->enabled = enable &&
+ (handle ||
+ adv->instance == hdev->cur_adv_instance);
+ owned |= adv->enabled;
+ }
+
+ if (handle)
+ return;
+
+ if (enable && !owned)
+ hci_dev_set_flag(hdev, HCI_LE_ADV_0);
+ else
+ hci_dev_clear_flag(hdev, HCI_LE_ADV_0);
+}
+
static u8 hci_cc_le_set_ext_adv_enable(struct hci_dev *hdev, void *data,
struct sk_buff *skb)
{
@@ -1638,18 +1685,13 @@ static u8 hci_cc_le_set_ext_adv_enable(struct hci_dev *hdev, void *data,
hci_dev_lock(hdev);
- if (cp->num_of_sets)
- adv = hci_find_adv_instance(hdev, set->handle);
-
if (cp->enable) {
struct hci_conn *conn;
hci_dev_set_flag(hdev, HCI_LE_ADV);
- if (adv)
- adv->enabled = true;
- else if (!set->handle)
- hci_dev_set_flag(hdev, HCI_LE_ADV_0);
+ if (cp->num_of_sets)
+ hci_le_ext_adv_set_enabled(hdev, set->handle, true);
conn = hci_lookup_le_connect(hdev);
if (conn)
@@ -1658,21 +1700,25 @@ static u8 hci_cc_le_set_ext_adv_enable(struct hci_dev *hdev, void *data,
conn->conn_timeout);
} else {
if (cp->num_of_sets) {
- if (adv)
- adv->enabled = false;
- else if (!set->handle)
- hci_dev_clear_flag(hdev, HCI_LE_ADV_0);
+ hci_le_ext_adv_set_enabled(hdev, set->handle, false);
/* If just one instance was disabled check if there are
- * any other instance enabled before clearing HCI_LE_ADV
+ * any other instance enabled, including instance 0,
+ * before clearing HCI_LE_ADV
*/
+ if (hci_dev_test_flag(hdev, HCI_LE_ADV_0))
+ goto unlock;
+
list_for_each_entry_safe(adv, n, &hdev->adv_instances,
list) {
if (adv->enabled)
goto unlock;
}
} else {
- /* All instances shall be considered disabled */
+ /* All instances shall be considered disabled, except
+ * instance 0 whose state is preserved so it can be
+ * re-enabled by hci_resume_advertising_sync.
+ */
list_for_each_entry_safe(adv, n, &hdev->adv_instances,
list)
adv->enabled = false;
@@ -2774,7 +2820,11 @@ static void hci_cs_disconnect(struct hci_dev *hdev, u8 status)
if (hdev->suspended)
conn->state = BT_CLOSED;
- mgmt_conn = test_and_clear_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags);
+ /* Only peek at the flag here: hci_conn_del() (via hci_conn_unlink())
+ * still needs it set to know whether to report the security level
+ * reset, so it is consumed there instead of here.
+ */
+ mgmt_conn = test_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags);
if (conn->type == ACL_LINK) {
if (test_and_clear_bit(HCI_CONN_FLUSH_KEY, &conn->flags))
@@ -2957,8 +3007,25 @@ static void hci_cs_le_read_remote_features(struct hci_dev *hdev, u8 status)
hci_dev_lock(hdev);
conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(cp->handle));
- if (conn && conn->state == BT_CONFIG)
+ if (conn && conn->state == BT_CONFIG) {
+ /* If the local controller supports peripheral-initiated
+ * features exchange, but the remote controller does not,
+ * then the controller may already return the error code
+ * 0x1a for unsupported remote feature in the command
+ * status.
+ *
+ * Handle it as hci_le_remote_feat_complete_evt() does and
+ * allow the connection to transition into connected state.
+ */
+ if (!conn->out &&
+ status == HCI_ERROR_UNSUPPORTED_REMOTE_FEATURE &&
+ (hdev->le_features[0] & HCI_LE_PERIPHERAL_FEATURES)) {
+ conn->state = BT_CONNECTED;
+ status = 0x00;
+ }
+
hci_connect_cfm(conn, status);
+ }
hci_dev_unlock(hdev);
}
@@ -3378,6 +3445,16 @@ static void hci_conn_request_evt(struct hci_dev *hdev, void *data,
bt_dev_err(hdev, "connection err: %ld", PTR_ERR(conn));
goto unlock;
}
+
+ /* Unlike outgoing BR/EDR connections, conn->sec_level is not
+ * set at connection request time for incoming connections,
+ * so it is still at its zero-initialized value
+ * (BT_SECURITY_SDP) here. Set it to BT_SECURITY_LOW so
+ * mgmt_device_connected() later reports the correct initial
+ * security level instead of a transient, never-really-in-use
+ * SDP value.
+ */
+ conn->sec_level = BT_SECURITY_LOW;
}
memcpy(conn->dev_class, ev->dev_class, 3);
@@ -3444,7 +3521,11 @@ static void hci_disconn_complete_evt(struct hci_dev *hdev, void *data,
conn->state = BT_CLOSED;
- mgmt_connected = test_and_clear_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags);
+ /* Only peek at the flag here: hci_conn_del() (via hci_conn_unlink())
+ * still needs it set to know whether to report the security level
+ * reset, so it is consumed there instead of here.
+ */
+ mgmt_connected = test_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags);
if (test_bit(HCI_CONN_AUTH_FAILURE, &conn->flags))
reason = MGMT_DEV_DISCONN_AUTH_FAILURE;
@@ -3528,6 +3609,15 @@ static void hci_auth_complete_evt(struct hci_dev *hdev, void *data,
if (!ev->status) {
clear_bit(HCI_CONN_AUTH_FAILURE, &conn->flags);
set_bit(HCI_CONN_AUTH, &conn->flags);
+ /* Authentication alone does not imply encryption: for SSP
+ * capable devices, encryption is only requested below, and
+ * for legacy devices it is requested by a separate
+ * HCI_OP_SET_CONN_ENCRYPT command. Do not report the new
+ * security level yet, to avoid userspace seeing an elevated
+ * level alongside no encryption; hci_encrypt_change_evt()
+ * (possibly via hci_cc_read_enc_key_size() for ACL links)
+ * reports it once encryption is actually confirmed.
+ */
conn->sec_level = conn->pending_sec_level;
} else {
if (ev->status == HCI_ERROR_PIN_OR_KEY_MISSING)
@@ -3644,9 +3734,28 @@ static void hci_encrypt_change_evt(struct hci_dev *hdev, void *data,
if ((conn->type == ACL_LINK && ev->encrypt == 0x02) ||
conn->type == LE_LINK)
set_bit(HCI_CONN_AES_CCM, &conn->flags);
+
+ /* For ACL links the encryption key size is still
+ * validated below via hci_read_enc_key_size(). Its
+ * completion handler, hci_cc_read_enc_key_size(),
+ * reports the final security level so userspace does
+ * not see a transient "encrypted" state that a
+ * key-size downgrade would immediately invalidate.
+ */
+ if (conn->type != ACL_LINK)
+ mgmt_security_level_changed(conn);
} else {
clear_bit(HCI_CONN_ENCRYPT, &conn->flags);
clear_bit(HCI_CONN_AES_CCM, &conn->flags);
+ /* Elevated security levels (MEDIUM and above) require
+ * encryption, so downgrade to reflect the connection
+ * no longer being encrypted before reporting, instead
+ * of advertising a stale elevated level alongside
+ * MGMT_CONN_SEC_ENCRYPT_NONE.
+ */
+ if (conn->sec_level > BT_SECURITY_LOW)
+ conn->sec_level = BT_SECURITY_LOW;
+ mgmt_security_level_changed(conn);
}
}
@@ -3679,8 +3788,14 @@ static void hci_encrypt_change_evt(struct hci_dev *hdev, void *data,
/* Try reading the encryption key size for encrypted ACL links */
if (!ev->status && ev->encrypt && conn->type == ACL_LINK) {
- if (hci_read_enc_key_size(hdev, conn))
+ if (hci_read_enc_key_size(hdev, conn)) {
+ /* Could not even issue the key-size read: report the
+ * security level now since hci_cc_read_enc_key_size()
+ * will not run to do it.
+ */
+ mgmt_security_level_changed(conn);
goto notify;
+ }
goto unlock;
}
@@ -4007,8 +4122,17 @@ static void hci_cs_le_read_all_remote_features(struct hci_dev *hdev, u8 status)
hci_dev_lock(hdev);
conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(cp->handle));
- if (conn && conn->state == BT_CONFIG)
+ if (conn && conn->state == BT_CONFIG) {
+ /* See hci_cs_le_read_remote_features() */
+ if (!conn->out &&
+ status == HCI_ERROR_UNSUPPORTED_REMOTE_FEATURE &&
+ (hdev->le_features[0] & HCI_LE_PERIPHERAL_FEATURES)) {
+ conn->state = BT_CONNECTED;
+ status = 0x00;
+ }
+
hci_connect_cfm(conn, status);
+ }
hci_dev_unlock(hdev);
}
@@ -4099,6 +4223,9 @@ unlock:
#define HCI_CC_STATUS(_op, _func) \
HCI_CC(_op, _func, sizeof(struct hci_ev_status))
+#define HCI_MAX_CC_PLEN \
+ (HCI_MAX_EVENT_PLEN - sizeof(struct hci_ev_cmd_complete))
+
static const struct hci_cc {
u16 op;
u8 (*func)(struct hci_dev *hdev, void *data, struct sk_buff *skb);
@@ -4192,7 +4319,7 @@ static const struct hci_cc {
sizeof(struct hci_rp_le_read_local_features)),
HCI_CC_VL(HCI_OP_LE_READ_CONN_INTERVAL, hci_cc_le_read_conn_interval,
sizeof(struct hci_rp_le_read_conn_interval),
- HCI_MAX_EVENT_SIZE),
+ HCI_MAX_CC_PLEN),
HCI_CC(HCI_OP_LE_READ_ADV_TX_POWER, hci_cc_le_read_adv_tx_power,
sizeof(struct hci_rp_le_read_adv_tx_power)),
HCI_CC(HCI_OP_USER_CONFIRM_REPLY, hci_cc_user_confirm_reply,
@@ -4264,7 +4391,7 @@ static const struct hci_cc {
HCI_CC(HCI_OP_LE_READ_BUFFER_SIZE_V2, hci_cc_le_read_buffer_size_v2,
sizeof(struct hci_rp_le_read_buffer_size_v2)),
HCI_CC_VL(HCI_OP_LE_SET_CIG_PARAMS, hci_cc_le_set_cig_params,
- sizeof(struct hci_rp_le_set_cig_params), HCI_MAX_EVENT_SIZE),
+ sizeof(struct hci_rp_le_set_cig_params), HCI_MAX_CC_PLEN),
HCI_CC(HCI_OP_LE_SETUP_ISO_PATH, hci_cc_le_setup_iso_path,
sizeof(struct hci_rp_le_setup_iso_path)),
HCI_CC(HCI_OP_LE_READ_ALL_LOCAL_FEATURES,
@@ -4611,10 +4738,8 @@ static void hci_mode_change_evt(struct hci_dev *hdev, void *data,
if (!test_and_clear_bit(HCI_CONN_MODE_CHANGE_PEND,
&conn->flags)) {
- if (conn->mode == HCI_CM_ACTIVE)
- set_bit(HCI_CONN_POWER_SAVE, &conn->flags);
- else
- clear_bit(HCI_CONN_POWER_SAVE, &conn->flags);
+ assign_bit(HCI_CONN_POWER_SAVE, &conn->flags,
+ conn->mode == HCI_CM_ACTIVE);
}
if (test_and_clear_bit(HCI_CONN_SCO_SETUP_PEND, &conn->flags))
@@ -4814,10 +4939,7 @@ static void hci_link_key_notify_evt(struct hci_dev *hdev, void *data,
goto unlock;
}
- if (persistent)
- clear_bit(HCI_CONN_FLUSH_KEY, &conn->flags);
- else
- set_bit(HCI_CONN_FLUSH_KEY, &conn->flags);
+ assign_bit(HCI_CONN_FLUSH_KEY, &conn->flags, !persistent);
unlock:
hci_dev_unlock(hdev);
@@ -5242,8 +5364,14 @@ static void hci_key_refresh_complete_evt(struct hci_dev *hdev, void *data,
if (conn->type != LE_LINK)
goto unlock;
- if (!ev->status)
+ if (!ev->status) {
+ bool sec_level_changed =
+ conn->sec_level != conn->pending_sec_level;
+
conn->sec_level = conn->pending_sec_level;
+ if (sec_level_changed)
+ mgmt_security_level_changed(conn);
+ }
clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags);
@@ -5872,9 +6000,16 @@ static void le_conn_complete_evt(struct hci_dev *hdev, u8 status,
goto unlock;
}
+ /* Unlike outgoing BR/EDR connections, conn->sec_level is not set at
+ * connection request time for LE, so it is still at its
+ * zero-initialized value (BT_SECURITY_SDP) here. Set it to
+ * BT_SECURITY_LOW before reporting the connection so
+ * mgmt_device_connected() reports the correct initial security level
+ * instead of a transient, never-really-in-use SDP value.
+ */
+ conn->sec_level = BT_SECURITY_LOW;
mgmt_device_connected(hdev, conn, NULL, 0);
- conn->sec_level = BT_SECURITY_LOW;
conn->state = BT_CONFIG;
/* Store current advertising instance as connection advertising instance
@@ -6311,6 +6446,15 @@ static void process_adv_report(struct hci_dev *hdev, u8 type, bdaddr_t *bdaddr,
if (irk) {
bdaddr = &irk->bdaddr;
bdaddr_type = irk->addr_type;
+ } else {
+ /* The peer is on air with its identity address, so whatever
+ * RPA is cached for it has been abandoned. Drop it, or
+ * hci_connect_le() would swap it back in and dial an address
+ * the peer no longer answers.
+ */
+ irk = hci_find_irk_by_addr(hdev, bdaddr, bdaddr_type);
+ if (irk)
+ bacpy(&irk->rpa, BDADDR_ANY);
}
bdaddr_type = ev_bdaddr_type(hdev, bdaddr_type, &bdaddr_resolved);
@@ -7316,8 +7460,13 @@ static void hci_le_big_sync_lost_evt(struct hci_dev *hdev, void *data,
BT_CONNECTED,
HCI_ROLE_SLAVE))) {
if (!mgmt_conn) {
- mgmt_conn = test_and_clear_bit(HCI_CONN_MGMT_CONNECTED,
- &bis->flags);
+ /* Only peek at the flag here: hci_conn_del() (via
+ * hci_conn_unlink()) still needs it set to know
+ * whether to report the security level reset, so
+ * it is consumed there instead of here.
+ */
+ mgmt_conn = test_bit(HCI_CONN_MGMT_CONNECTED,
+ &bis->flags);
mgmt_device_disconnected(hdev, &bis->dst, bis->type,
bis->dst_type, ev->reason,
mgmt_conn);
@@ -7465,6 +7614,9 @@ static void hci_le_conn_rate_change_evt(struct hci_dev *hdev, void *data,
#define HCI_LE_EV_STATUS(_op, _func) \
HCI_LE_EV(_op, _func, sizeof(struct hci_ev_status))
+#define HCI_MAX_LE_SUBEVT_PLEN \
+ (HCI_MAX_EVENT_PLEN - sizeof(struct hci_ev_le_meta))
+
/* Entries in this table shall have their position according to the subevent
* opcode they handle so the use of the macros above is recommend since it does
* attempt to initialize at its proper index using Designated Initializers that
@@ -7481,7 +7633,7 @@ static const struct hci_le_ev {
/* [0x02 = HCI_EV_LE_ADVERTISING_REPORT] */
HCI_LE_EV_VL(HCI_EV_LE_ADVERTISING_REPORT, hci_le_adv_report_evt,
sizeof(struct hci_ev_le_advertising_report),
- HCI_MAX_EVENT_SIZE),
+ HCI_MAX_LE_SUBEVT_PLEN),
/* [0x03 = HCI_EV_LE_CONN_UPDATE_COMPLETE] */
HCI_LE_EV(HCI_EV_LE_CONN_UPDATE_COMPLETE,
hci_le_conn_update_complete_evt,
@@ -7504,14 +7656,14 @@ static const struct hci_le_ev {
/* [0x0b = HCI_EV_LE_DIRECT_ADV_REPORT] */
HCI_LE_EV_VL(HCI_EV_LE_DIRECT_ADV_REPORT, hci_le_direct_adv_report_evt,
sizeof(struct hci_ev_le_direct_adv_report),
- HCI_MAX_EVENT_SIZE),
+ HCI_MAX_LE_SUBEVT_PLEN),
/* [0x0c = HCI_EV_LE_PHY_UPDATE_COMPLETE] */
HCI_LE_EV(HCI_EV_LE_PHY_UPDATE_COMPLETE, hci_le_phy_update_evt,
sizeof(struct hci_ev_le_phy_update_complete)),
/* [0x0d = HCI_EV_LE_EXT_ADV_REPORT] */
HCI_LE_EV_VL(HCI_EV_LE_EXT_ADV_REPORT, hci_le_ext_adv_report_evt,
sizeof(struct hci_ev_le_ext_adv_report),
- HCI_MAX_EVENT_SIZE),
+ HCI_MAX_LE_SUBEVT_PLEN),
/* [0x0e = HCI_EV_LE_PA_SYNC_ESTABLISHED] */
HCI_LE_EV(HCI_EV_LE_PA_SYNC_ESTABLISHED,
hci_le_pa_sync_established_evt,
@@ -7520,7 +7672,7 @@ static const struct hci_le_ev {
HCI_LE_EV_VL(HCI_EV_LE_PER_ADV_REPORT,
hci_le_per_adv_report_evt,
sizeof(struct hci_ev_le_per_adv_report),
- HCI_MAX_EVENT_SIZE),
+ HCI_MAX_LE_SUBEVT_PLEN),
/* [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)),
@@ -7541,28 +7693,28 @@ static const struct hci_le_ev {
HCI_LE_EV_VL(HCI_EVT_LE_CREATE_BIG_COMPLETE,
hci_le_create_big_complete_evt,
sizeof(struct hci_evt_le_create_big_complete),
- HCI_MAX_EVENT_SIZE),
+ HCI_MAX_LE_SUBEVT_PLEN),
/* [0x1d = HCI_EV_LE_BIG_SYNC_ESTABLISHED] */
HCI_LE_EV_VL(HCI_EVT_LE_BIG_SYNC_ESTABLISHED,
hci_le_big_sync_established_evt,
sizeof(struct hci_evt_le_big_sync_established),
- HCI_MAX_EVENT_SIZE),
+ HCI_MAX_LE_SUBEVT_PLEN),
/* [0x1e = HCI_EVT_LE_BIG_SYNC_LOST] */
HCI_LE_EV_VL(HCI_EVT_LE_BIG_SYNC_LOST,
hci_le_big_sync_lost_evt,
sizeof(struct hci_evt_le_big_sync_lost),
- HCI_MAX_EVENT_SIZE),
+ HCI_MAX_LE_SUBEVT_PLEN),
/* [0x22 = HCI_EVT_LE_BIG_INFO_ADV_REPORT] */
HCI_LE_EV_VL(HCI_EVT_LE_BIG_INFO_ADV_REPORT,
hci_le_big_info_adv_report_evt,
sizeof(struct hci_evt_le_big_info_adv_report),
- HCI_MAX_EVENT_SIZE),
+ HCI_MAX_LE_SUBEVT_PLEN),
/* [0x2b = HCI_EVT_LE_ALL_REMOTE_FEATURES_COMPLETE] */
HCI_LE_EV_VL(HCI_EVT_LE_ALL_REMOTE_FEATURES_COMPLETE,
hci_le_read_all_remote_features_evt,
sizeof(struct
hci_evt_le_read_all_remote_features_complete),
- HCI_MAX_EVENT_SIZE),
+ HCI_MAX_LE_SUBEVT_PLEN),
/* [0x37 = HCI_EVT_LE_CONN_RATE_CHANGE] */
HCI_LE_EV(HCI_EVT_LE_CONN_RATE_CHANGE, hci_le_conn_rate_change_evt,
sizeof(struct hci_evt_le_conn_rate_change)),
diff --git a/net/bluetooth/hci_h4.c b/net/bluetooth/hci_h4.c
new file mode 100644
index 000000000000..86f809018062
--- /dev/null
+++ b/net/bluetooth/hci_h4.c
@@ -0,0 +1,160 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Bluetooth HCI H:4 packet reassembly
+ *
+ * Copyright (C) 2000-2001 Qualcomm Incorporated
+ * Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
+ * Copyright (C) 2004-2005 Marcel Holtmann <marcel@holtmann.org>
+ */
+
+#include <linux/export.h>
+#include <linux/skbuff.h>
+#include <linux/unaligned.h>
+
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci_core.h>
+#include <net/bluetooth/hci_h4.h>
+
+/* h4_recv_skb - Reassemble H:4 framed packets
+ * @hdev: HCI device the packets are received on
+ * @alignment: optional packet alignment, NULL or 0 means no alignment
+ * @padding: optional padding state carried over between calls
+ * @skb: partially received packet from a previous call, may be NULL or an
+ * ERR_PTR returned by a previous call
+ * @buffer: buffer holding the received data
+ * @count: number of bytes in @buffer
+ * @pkts: table of supported packet types
+ * @pkts_count: number of entries in @pkts
+ *
+ * Returns the partially received packet to be passed to the next call, or an
+ * ERR_PTR on error. The returned value can be fed back into this function as
+ * is, but must be checked with IS_ERR() before being freed.
+ */
+struct sk_buff *h4_recv_skb(struct hci_dev *hdev, u8 *alignment, u8 *padding,
+ struct sk_buff *skb, const unsigned char *buffer,
+ int count, const struct h4_recv_pkt *pkts,
+ int pkts_count)
+{
+ u8 align = alignment && *alignment ? *alignment : 1;
+
+ /* Check for error from previous call */
+ if (IS_ERR(skb))
+ skb = NULL;
+
+ while (count) {
+ int i, len;
+
+ /* remove padding bytes from buffer */
+ if (padding) {
+ for (; (*padding) && count > 0; (*padding)--) {
+ count--;
+ buffer++;
+ }
+ }
+
+ if (!count)
+ break;
+
+ if (!skb) {
+ for (i = 0; i < pkts_count; i++) {
+ if (buffer[0] != pkts[i].type)
+ continue;
+
+ skb = bt_skb_alloc(pkts[i].maxlen,
+ GFP_ATOMIC);
+ if (!skb)
+ return ERR_PTR(-ENOMEM);
+
+ hci_skb_pkt_type(skb) = pkts[i].type;
+ hci_skb_expect(skb) = pkts[i].hlen;
+ break;
+ }
+
+ /* Check for invalid packet type */
+ if (!skb)
+ return ERR_PTR(-EILSEQ);
+
+ count -= 1;
+ buffer += 1;
+ }
+
+ len = min_t(uint, hci_skb_expect(skb) - skb->len, count);
+ skb_put_data(skb, buffer, len);
+
+ count -= len;
+ buffer += len;
+
+ /* Check for partial packet */
+ if (skb->len < hci_skb_expect(skb))
+ continue;
+
+ for (i = 0; i < pkts_count; i++) {
+ if (hci_skb_pkt_type(skb) == pkts[i].type)
+ break;
+ }
+
+ if (i >= pkts_count) {
+ kfree_skb(skb);
+ return ERR_PTR(-EILSEQ);
+ }
+
+ if (skb->len == pkts[i].hlen) {
+ u16 dlen;
+
+ switch (pkts[i].lsize) {
+ case 0:
+ /* No variable data length */
+ dlen = 0;
+ break;
+ case 1:
+ /* Single octet variable length */
+ dlen = skb->data[pkts[i].loff];
+ hci_skb_expect(skb) += dlen;
+
+ if (skb_tailroom(skb) < dlen) {
+ kfree_skb(skb);
+ return ERR_PTR(-EMSGSIZE);
+ }
+ break;
+ case 2:
+ /* Double octet variable length */
+ dlen = get_unaligned_le16(skb->data +
+ pkts[i].loff);
+ hci_skb_expect(skb) += dlen;
+
+ if (skb_tailroom(skb) < dlen) {
+ kfree_skb(skb);
+ return ERR_PTR(-EMSGSIZE);
+ }
+ break;
+ default:
+ /* Unsupported variable length */
+ kfree_skb(skb);
+ return ERR_PTR(-EILSEQ);
+ }
+
+ if (!dlen) {
+ if (padding) {
+ *padding = (skb->len + 1) % align;
+ *padding = (align - *padding) % align;
+ }
+
+ /* No more data, complete frame */
+ pkts[i].recv(hdev, skb);
+ skb = NULL;
+ }
+ } else {
+ if (padding) {
+ *padding = (skb->len + 1) % align;
+ *padding = (align - *padding) % align;
+ }
+
+ /* Complete frame */
+ pkts[i].recv(hdev, skb);
+ skb = NULL;
+ }
+ }
+
+ return skb;
+}
+EXPORT_SYMBOL_GPL(h4_recv_skb);
diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c
index ec45b531e387..3da994d1fe65 100644
--- a/net/bluetooth/hci_sock.c
+++ b/net/bluetooth/hci_sock.c
@@ -244,6 +244,7 @@ void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb)
hci_skb_pkt_type(skb) != HCI_ACLDATA_PKT &&
hci_skb_pkt_type(skb) != HCI_SCODATA_PKT &&
hci_skb_pkt_type(skb) != HCI_ISODATA_PKT &&
+ hci_skb_pkt_type(skb) != HCI_VENDOR_PKT &&
hci_skb_pkt_type(skb) != HCI_DRV_PKT)
continue;
} else {
@@ -401,6 +402,12 @@ void hci_send_to_monitor(struct hci_dev *hdev, struct sk_buff *skb)
else
opcode = cpu_to_le16(HCI_MON_ISO_TX_PKT);
break;
+ case HCI_VENDOR_PKT:
+ if (bt_cb(skb)->incoming)
+ opcode = cpu_to_le16(HCI_MON_VENDOR_RX_PKT);
+ else
+ opcode = cpu_to_le16(HCI_MON_VENDOR_TX_PKT);
+ break;
case HCI_DRV_PKT:
if (bt_cb(skb)->incoming)
opcode = cpu_to_le16(HCI_MON_DRV_RX_PKT);
@@ -1881,6 +1888,7 @@ static int hci_sock_sendmsg(struct socket *sock, struct msghdr *msg,
hci_skb_pkt_type(skb) != HCI_ACLDATA_PKT &&
hci_skb_pkt_type(skb) != HCI_SCODATA_PKT &&
hci_skb_pkt_type(skb) != HCI_ISODATA_PKT &&
+ hci_skb_pkt_type(skb) != HCI_VENDOR_PKT &&
hci_skb_pkt_type(skb) != HCI_DRV_PKT) {
err = -EINVAL;
goto drop;
diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c
index a92a81846e9d..03f706c1f815 100644
--- a/net/bluetooth/hci_sync.c
+++ b/net/bluetooth/hci_sync.c
@@ -470,7 +470,7 @@ static void reenable_adv(struct work_struct *work)
static void cancel_adv_timeout(struct hci_dev *hdev)
{
if (hdev->adv_instance_timeout) {
- hdev->adv_instance_timeout = 0;
+ hdev->adv_instance_timeout = false;
cancel_delayed_work(&hdev->adv_instance_expire);
}
}
@@ -570,7 +570,7 @@ static void adv_timeout_expire(struct work_struct *work)
hci_dev_lock(hdev);
- hdev->adv_instance_timeout = 0;
+ hdev->adv_instance_timeout = false;
if (hdev->cur_adv_instance == 0x00)
goto unlock;
@@ -1158,14 +1158,38 @@ int hci_update_random_address_sync(struct hci_dev *hdev, bool require_privacy,
return 0;
}
-static int hci_disable_ext_adv_legacy_instance_sync(struct hci_dev *hdev)
+/* Check if the advertising set with handle 0x00 is in use, either by instance
+ * 0 or by an instance sharing its advertising set.
+ */
+static bool hci_ext_adv_handle_0_enabled(struct hci_dev *hdev)
+{
+ struct adv_info *adv;
+ bool enabled;
+
+ hci_dev_lock(hdev);
+
+ enabled = hci_dev_test_flag(hdev, HCI_LE_ADV_0);
+
+ list_for_each_entry(adv, &hdev->adv_instances, list) {
+ if (!adv->handle && adv->enabled) {
+ enabled = true;
+ break;
+ }
+ }
+
+ hci_dev_unlock(hdev);
+
+ return enabled;
+}
+
+int hci_disable_ext_adv_legacy_instance_sync(struct hci_dev *hdev)
{
struct hci_cp_le_set_ext_adv_enable *cp;
struct hci_cp_ext_adv_set *set;
u8 data[sizeof(*cp) + sizeof(*set) * 1];
u8 size;
- if (!hci_dev_test_flag(hdev, HCI_LE_ADV_0))
+ if (!hci_ext_adv_handle_0_enabled(hdev))
return 0;
memset(data, 0, sizeof(data));
@@ -1411,6 +1435,9 @@ int hci_setup_ext_adv_instance_sync(struct hci_dev *hdev, u8 instance)
return -EINVAL;
}
} else {
+ /* Disable the advertising set with handle 0x00, including any
+ * instance sharing it, since it is going to be overridden.
+ */
err = hci_disable_ext_adv_legacy_instance_sync(hdev);
if (err)
return err;
@@ -1672,12 +1699,19 @@ int hci_enable_ext_advertising_sync(struct hci_dev *hdev, u8 instance)
* scheduling it.
*/
if (adv && adv->timeout) {
- u16 duration = adv->timeout * MSEC_PER_SEC;
+ u16 duration = adv->mesh ? adv->timeout :
+ adv->timeout * MSEC_PER_SEC;
/* Time = N * 10 ms */
set->duration = cpu_to_le16(duration / 10);
}
+ /* Track which instance owns the advertising set since the handle
+ * alone is ambiguous when instances share handle 0x00, see
+ * hci_cc_le_set_ext_adv_enable.
+ */
+ hdev->cur_adv_instance = instance;
+
return __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_EXT_ADV_ENABLE,
sizeof(*cp) +
sizeof(*set) * cp->num_of_sets,
@@ -2100,10 +2134,11 @@ int hci_schedule_adv_instance_sync(struct hci_dev *hdev, u8 instance,
/* Only use work for scheduling instances with legacy advertising */
if (!ext_adv_capable(hdev)) {
- hdev->adv_instance_timeout = timeout;
+ hdev->adv_instance_timeout = true;
queue_delayed_work(hdev->req_workqueue,
&hdev->adv_instance_expire,
- secs_to_jiffies(timeout));
+ adv->mesh ? msecs_to_jiffies(timeout) :
+ secs_to_jiffies(timeout));
}
/* If we're just re-scheduling the same instance again then do not
@@ -2556,13 +2591,19 @@ static int hci_le_set_privacy_mode_sync(struct hci_dev *hdev,
if (!(params->flags & HCI_CONN_FLAG_DEVICE_PRIVACY))
return 0;
+ rcu_read_lock();
+
irk = hci_find_irk_by_addr(hdev, &params->addr, params->addr_type);
- if (!irk)
+ if (!irk) {
+ rcu_read_unlock();
return 0;
+ }
memset(&cp, 0, sizeof(cp));
cp.bdaddr_type = irk->addr_type;
bacpy(&cp.bdaddr, &irk->bdaddr);
+ rcu_read_unlock();
+
cp.mode = HCI_DEVICE_PRIVACY;
/* Note: params->privacy_mode is not updated since it is a copy */
@@ -2577,7 +2618,7 @@ static int hci_le_set_privacy_mode_sync(struct hci_dev *hdev,
*/
static int hci_le_add_accept_list_sync(struct hci_dev *hdev,
struct conn_params *params,
- u8 *num_entries)
+ u8 *num_entries, bool force_filter)
{
struct hci_cp_le_add_to_accept_list cp;
int err;
@@ -2590,6 +2631,11 @@ static int hci_le_add_accept_list_sync(struct hci_dev *hdev,
return 0;
}
+ /* Host-resolved peers need unfiltered scanning while awake. */
+ if (!force_filter && !hdev->suspended && !ll_privacy_capable(hdev) &&
+ hci_find_irk_by_addr(hdev, &params->addr, params->addr_type))
+ return -EINVAL;
+
/* Select filter policy to accept all advertising */
if (*num_entries >= hdev->le_accept_list_size)
return -ENOSPC;
@@ -2915,7 +2961,7 @@ static u8 hci_update_accept_list_sync(struct hci_dev *hdev)
num_entries = 1;
err = hci_le_add_accept_list_sync(hdev, &pa,
- &num_entries);
+ &num_entries, true);
goto done;
} else {
rcu_read_unlock();
@@ -2979,7 +3025,7 @@ static u8 hci_update_accept_list_sync(struct hci_dev *hdev)
for (i = 0; i < n; ++i) {
err = hci_le_add_accept_list_sync(hdev, &params[i],
- &num_entries);
+ &num_entries, false);
if (err) {
kvfree(params);
goto done;
@@ -3001,7 +3047,7 @@ static u8 hci_update_accept_list_sync(struct hci_dev *hdev)
for (i = 0; i < n; ++i) {
err = hci_le_add_accept_list_sync(hdev, &params[i],
- &num_entries);
+ &num_entries, false);
if (err) {
kvfree(params);
goto done;
@@ -5390,6 +5436,30 @@ static int hci_dev_init_sync(struct hci_dev *hdev)
return ret;
}
+static void hci_dev_drop_last_cmd_req_and_close(struct hci_dev *hdev)
+{
+ /* Drop last sent command */
+ if (hdev->sent_cmd) {
+ cancel_delayed_work_sync(&hdev->cmd_timer);
+ kfree_skb(hdev->sent_cmd);
+ hdev->sent_cmd = NULL;
+ }
+
+ /* Drop last request */
+ if (hdev->req_skb) {
+ kfree_skb(hdev->req_skb);
+ hdev->req_skb = NULL;
+ hci_dev_clear_flag(hdev, HCI_CMD_PENDING);
+ }
+
+ clear_bit(HCI_RUNNING, &hdev->flags);
+ hci_sock_dev_event(hdev, HCI_DEV_CLOSE);
+
+ /* After this point our queues are empty and no tasks are scheduled. */
+ hdev->close(hdev);
+ hdev->flags &= BIT(HCI_RAW);
+}
+
int hci_dev_open_sync(struct hci_dev *hdev)
{
int ret;
@@ -5438,7 +5508,9 @@ int hci_dev_open_sync(struct hci_dev *hdev)
goto done;
}
+ hci_dev_lock(hdev);
hci_devcd_reset(hdev);
+ hci_dev_unlock(hdev);
set_bit(HCI_RUNNING, &hdev->flags);
hci_sock_dev_event(hdev, HCI_DEV_OPEN);
@@ -5476,23 +5548,7 @@ int hci_dev_open_sync(struct hci_dev *hdev)
if (hdev->flush)
hdev->flush(hdev);
- if (hdev->sent_cmd) {
- cancel_delayed_work_sync(&hdev->cmd_timer);
- kfree_skb(hdev->sent_cmd);
- hdev->sent_cmd = NULL;
- }
-
- if (hdev->req_skb) {
- kfree_skb(hdev->req_skb);
- hdev->req_skb = NULL;
- hci_dev_clear_flag(hdev, HCI_CMD_PENDING);
- }
-
- clear_bit(HCI_RUNNING, &hdev->flags);
- hci_sock_dev_event(hdev, HCI_DEV_CLOSE);
-
- hdev->close(hdev);
- hdev->flags &= BIT(HCI_RAW);
+ hci_dev_drop_last_cmd_req_and_close(hdev);
}
done:
@@ -5570,7 +5626,7 @@ int hci_dev_close_sync(struct hci_dev *hdev)
if (hdev->adv_instance_timeout) {
cancel_delayed_work_sync(&hdev->adv_instance_expire);
- hdev->adv_instance_timeout = 0;
+ hdev->adv_instance_timeout = false;
}
err = hci_dev_shutdown(hdev);
@@ -5659,28 +5715,10 @@ int hci_dev_close_sync(struct hci_dev *hdev)
skb_queue_purge(&hdev->cmd_q);
skb_queue_purge(&hdev->raw_q);
- /* Drop last sent command */
- if (hdev->sent_cmd) {
- cancel_delayed_work_sync(&hdev->cmd_timer);
- kfree_skb(hdev->sent_cmd);
- hdev->sent_cmd = NULL;
- }
-
- /* Drop last request */
- if (hdev->req_skb) {
- kfree_skb(hdev->req_skb);
- hdev->req_skb = NULL;
- hci_dev_clear_flag(hdev, HCI_CMD_PENDING);
- }
-
- clear_bit(HCI_RUNNING, &hdev->flags);
- hci_sock_dev_event(hdev, HCI_DEV_CLOSE);
-
- /* After this point our queues are empty and no tasks are scheduled. */
- hdev->close(hdev);
+ /* Drop last sent command, last request and close */
+ hci_dev_drop_last_cmd_req_and_close(hdev);
/* Clear flags */
- hdev->flags &= BIT(HCI_RAW);
hci_dev_clear_volatile_flags(hdev);
hci_dev_clear_flag(hdev, HCI_CMD_DRAIN_WORKQUEUE);
diff --git a/net/bluetooth/iso.c b/net/bluetooth/iso.c
index d6ac5b1f49bc..c1fdd9846eeb 100644
--- a/net/bluetooth/iso.c
+++ b/net/bluetooth/iso.c
@@ -287,8 +287,11 @@ static void iso_chan_del(struct sock *sk, int err)
parent = bt_sk(sk)->parent;
if (parent) {
+ /* Unlinking the child allows the parent to be freed. */
+ sock_hold(parent);
bt_accept_unlink(sk);
parent->sk_data_ready(parent);
+ sock_put(parent);
} else {
sk->sk_state_change(sk);
}
@@ -1974,10 +1977,7 @@ static int iso_sock_setsockopt(struct socket *sock, int level, int optname,
if (err)
break;
- if (opt)
- set_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags);
- else
- clear_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags);
+ assign_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags, opt);
break;
case BT_PKT_STATUS:
@@ -1985,10 +1985,7 @@ static int iso_sock_setsockopt(struct socket *sock, int level, int optname,
if (err)
break;
- if (opt)
- set_bit(BT_SK_PKT_STATUS, &bt_sk(sk)->flags);
- else
- clear_bit(BT_SK_PKT_STATUS, &bt_sk(sk)->flags);
+ assign_bit(BT_SK_PKT_STATUS, &bt_sk(sk)->flags, opt);
break;
case BT_PKT_SEQNUM:
@@ -1996,10 +1993,7 @@ static int iso_sock_setsockopt(struct socket *sock, int level, int optname,
if (err)
break;
- if (opt)
- set_bit(BT_SK_PKT_SEQNUM, &bt_sk(sk)->flags);
- else
- clear_bit(BT_SK_PKT_SEQNUM, &bt_sk(sk)->flags);
+ assign_bit(BT_SK_PKT_SEQNUM, &bt_sk(sk)->flags, opt);
break;
case BT_ISO_QOS:
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index aaa2a1cd489a..4dd56e0074fd 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -44,8 +44,8 @@ bool enable_ecred = IS_ENABLED(CONFIG_BT_LE_L2CAP_ECRED);
static u32 l2cap_feat_mask = L2CAP_FEAT_FIXED_CHAN | L2CAP_FEAT_UCD;
-static LIST_HEAD(chan_list);
static DEFINE_RWLOCK(chan_list_lock);
+static __guarded_by(&chan_list_lock) LIST_HEAD(chan_list);
static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn,
u8 code, u8 ident, u16 dlen, void *data);
@@ -59,6 +59,8 @@ static void l2cap_tx(struct l2cap_chan *chan, struct l2cap_ctrl *control,
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 void __l2cap_chan_close(struct l2cap_chan *chan, int reason)
+ __must_hold(&chan->lock) __must_hold(&chan->conn->lock);
static inline u8 bdaddr_type(u8 link_type, u8 bdaddr_type)
{
@@ -86,6 +88,7 @@ static inline u8 bdaddr_dst_type(struct hci_conn *hcon)
static struct l2cap_chan *__l2cap_get_chan_by_dcid(struct l2cap_conn *conn,
u16 cid)
+ __must_hold(&conn->lock)
{
struct l2cap_chan *c;
@@ -98,6 +101,7 @@ static struct l2cap_chan *__l2cap_get_chan_by_dcid(struct l2cap_conn *conn,
static struct l2cap_chan *__l2cap_get_chan_by_scid(struct l2cap_conn *conn,
u16 cid)
+ __must_hold(&conn->lock)
{
struct l2cap_chan *c;
@@ -109,45 +113,40 @@ static struct l2cap_chan *__l2cap_get_chan_by_scid(struct l2cap_conn *conn,
}
/* Find channel with given SCID.
- * Returns a reference locked channel.
+ * Returns a reference.
*/
static struct l2cap_chan *l2cap_get_chan_by_scid(struct l2cap_conn *conn,
u16 cid)
+ __must_hold(&conn->lock)
{
struct l2cap_chan *c;
c = __l2cap_get_chan_by_scid(conn, cid);
- if (c) {
- /* Only lock if chan reference is not 0 */
+ if (c)
c = l2cap_chan_hold_unless_zero(c);
- if (c)
- l2cap_chan_lock(c);
- }
return c;
}
/* Find channel with given DCID.
- * Returns a reference locked channel.
+ * Returns a reference.
*/
static struct l2cap_chan *l2cap_get_chan_by_dcid(struct l2cap_conn *conn,
u16 cid)
+ __must_hold(&conn->lock)
{
struct l2cap_chan *c;
c = __l2cap_get_chan_by_dcid(conn, cid);
- if (c) {
- /* Only lock if chan reference is not 0 */
+ if (c)
c = l2cap_chan_hold_unless_zero(c);
- if (c)
- l2cap_chan_lock(c);
- }
return c;
}
static struct l2cap_chan *__l2cap_get_chan_by_ident(struct l2cap_conn *conn,
u8 ident)
+ __must_hold(&conn->lock)
{
struct l2cap_chan *c;
@@ -158,8 +157,32 @@ static struct l2cap_chan *__l2cap_get_chan_by_ident(struct l2cap_conn *conn,
return NULL;
}
+/* Our connection request has been sent and is still outstanding */
+static bool l2cap_chan_connect_pending(struct l2cap_chan *chan)
+{
+ return chan->state == BT_CONNECT &&
+ test_bit(CONF_CONNECT_PEND, &chan->conf_state);
+}
+
+/* Other channels may hold the same ident for a response they still have
+ * to send, so only look at channels waiting for a connection response.
+ */
+static struct l2cap_chan *__l2cap_get_connect_chan_by_ident(struct l2cap_conn *conn,
+ u8 ident)
+ __must_hold(&conn->lock)
+{
+ struct l2cap_chan *c;
+
+ list_for_each_entry(c, &conn->chan_l, list) {
+ if (c->ident == ident && l2cap_chan_connect_pending(c))
+ return c;
+ }
+ return NULL;
+}
+
static struct l2cap_chan *__l2cap_global_chan_by_addr(__le16 psm, bdaddr_t *src,
u8 src_type)
+ __must_hold_shared(&chan_list_lock)
{
struct l2cap_chan *c;
@@ -237,6 +260,7 @@ int l2cap_add_scid(struct l2cap_chan *chan, __u16 scid)
}
static u16 l2cap_alloc_cid(struct l2cap_conn *conn)
+ __must_hold(&conn->lock)
{
u16 cid, dyn_end;
@@ -320,6 +344,10 @@ static int l2cap_seq_list_init(struct l2cap_seq_list *seq_list, u16 size)
{
size_t alloc_size, i;
+ /* roundup_pow_of_two(0) is undefined */
+ if (!size)
+ return -EINVAL;
+
/* Allocated size is a power of 2 to map sequence numbers
* (which may be up to 14 bits) in to a smaller array that is
* sized for the negotiated ERTM transmit windows.
@@ -430,7 +458,7 @@ static void l2cap_chan_timeout(struct work_struct *work)
else
reason = ETIMEDOUT;
- l2cap_chan_close(chan, reason);
+ __l2cap_chan_close(chan, reason);
chan->ops->close(chan);
@@ -622,6 +650,10 @@ void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
BT_DBG("conn %p, psm 0x%2.2x, dcid 0x%4.4x", conn,
__le16_to_cpu(chan->psm), chan->dcid);
+ /* Caller must ensure l2cap_chan is linked to l2cap_conn only once */
+ if (WARN_ON_ONCE(chan->conn || test_bit(FLAG_DEL, &chan->flags)))
+ return;
+
conn->disc_reason = HCI_ERROR_REMOTE_USER_TERM;
chan->conn = l2cap_conn_get(conn);
@@ -673,12 +705,16 @@ void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
{
mutex_lock(&conn->lock);
+ l2cap_chan_lock(chan);
__l2cap_chan_add(conn, chan);
+ l2cap_chan_unlock(chan);
mutex_unlock(&conn->lock);
}
void l2cap_chan_del(struct l2cap_chan *chan, int err)
{
+ lockdep_assert(!chan->conn || lockdep_is_held(&chan->conn->lock));
+
__clear_chan_timer(chan);
BT_DBG("chan %p, err %d, state %s", chan, err,
@@ -733,6 +769,7 @@ EXPORT_SYMBOL_GPL(l2cap_chan_del);
static void __l2cap_chan_list_id(struct l2cap_conn *conn, u16 id,
l2cap_chan_func_t func, void *data)
+ __must_hold(&conn->lock)
{
struct l2cap_chan *chan, *l;
@@ -744,6 +781,7 @@ static void __l2cap_chan_list_id(struct l2cap_conn *conn, u16 id,
static void __l2cap_chan_list(struct l2cap_conn *conn, l2cap_chan_func_t func,
void *data)
+ __must_hold(&conn->lock)
{
struct l2cap_chan *chan;
@@ -808,6 +846,8 @@ static void l2cap_chan_le_connect_reject(struct l2cap_chan *chan)
}
static void l2cap_chan_ecred_connect_reject(struct l2cap_chan *chan)
+ __must_hold(&chan->lock)
+ __must_hold(&chan->conn->lock)
{
l2cap_state_change(chan, BT_DISCONN);
@@ -835,7 +875,7 @@ static void l2cap_chan_connect_reject(struct l2cap_chan *chan)
l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP, sizeof(rsp), &rsp);
}
-void l2cap_chan_close(struct l2cap_chan *chan, int reason)
+static void __l2cap_chan_close(struct l2cap_chan *chan, int reason)
{
struct l2cap_conn *conn = chan->conn;
@@ -884,7 +924,54 @@ void l2cap_chan_close(struct l2cap_chan *chan, int reason)
break;
}
}
-EXPORT_SYMBOL(l2cap_chan_close);
+
+/* Take chan->lock. If chan->conn is non-NULL, take new reference on it, take
+ * chan->conn->lock, and return true. Otherwise return false.
+ */
+bool l2cap_chan_lock_conn(struct l2cap_chan *chan)
+ __context_unsafe(/* conditional locking */)
+{
+ /* Handle conn->lock > chan->lock ordering + race on chan->conn */
+ for (;;) {
+ struct l2cap_conn *conn;
+
+ l2cap_chan_lock(chan);
+ conn = chan->conn;
+ if (conn)
+ l2cap_conn_get(conn);
+ l2cap_chan_unlock(chan);
+
+ if (conn)
+ mutex_lock(&conn->lock);
+
+ l2cap_chan_lock(chan);
+
+ if (chan->conn != conn) {
+ l2cap_chan_unlock(chan);
+ if (conn) {
+ mutex_unlock(&conn->lock);
+ l2cap_conn_put(conn);
+ }
+ schedule();
+ continue;
+ }
+
+ return chan->conn;
+ }
+}
+
+void l2cap_chan_close_unlocked(struct l2cap_chan *chan, int reason)
+{
+ bool have_conn;
+
+ have_conn = l2cap_chan_lock_conn(chan);
+
+ /* Context analysis: consider chan->conn->lock held also if conn NULL */
+ context_unsafe(__l2cap_chan_close(chan, reason));
+
+ l2cap_chan_unlock_conn(chan, have_conn);
+}
+EXPORT_SYMBOL(l2cap_chan_close_unlocked);
static inline u8 l2cap_get_auth_type(struct l2cap_chan *chan)
{
@@ -1283,6 +1370,8 @@ void l2cap_send_conn_req(struct l2cap_chan *chan)
}
static void l2cap_chan_ready(struct l2cap_chan *chan)
+ __must_hold(&chan->lock)
+ __must_hold(&chan->conn->lock)
{
/* The channel may have already been flagged as connected in
* case of receiving data before the L2CAP info req/rsp
@@ -1384,6 +1473,7 @@ static void l2cap_ecred_defer_connect(struct l2cap_chan *chan, void *data)
}
static void l2cap_ecred_connect(struct l2cap_chan *chan)
+ __must_hold(&chan->conn->lock)
{
struct l2cap_conn *conn = chan->conn;
struct l2cap_ecred_conn_data data;
@@ -1417,6 +1507,8 @@ static void l2cap_ecred_connect(struct l2cap_chan *chan)
}
static void l2cap_le_start(struct l2cap_chan *chan)
+ __must_hold(&chan->lock)
+ __must_hold(&chan->conn->lock)
{
struct l2cap_conn *conn = chan->conn;
@@ -1437,6 +1529,8 @@ static void l2cap_le_start(struct l2cap_chan *chan)
}
static void l2cap_start_connection(struct l2cap_chan *chan)
+ __must_hold(&chan->lock)
+ __must_hold(&chan->conn->lock)
{
if (chan->conn->hcon->type == LE_LINK) {
l2cap_le_start(chan);
@@ -1486,6 +1580,8 @@ static bool l2cap_check_enc_key_size(struct hci_conn *hcon,
}
static void l2cap_do_start(struct l2cap_chan *chan)
+ __must_hold(&chan->lock)
+ __must_hold(&chan->conn->lock)
{
struct l2cap_conn *conn = chan->conn;
@@ -1552,6 +1648,7 @@ static void l2cap_send_disconn_req(struct l2cap_chan *chan, int err)
/* ---- L2CAP connections ---- */
static void l2cap_conn_start(struct l2cap_conn *conn)
+ __must_hold(&conn->lock)
{
struct l2cap_chan *chan, *tmp;
@@ -1560,6 +1657,8 @@ static void l2cap_conn_start(struct l2cap_conn *conn)
list_for_each_entry_safe(chan, tmp, &conn->chan_l, list) {
l2cap_chan_lock(chan);
+ lockdep_assert_held(&chan->conn->lock);
+
if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
l2cap_chan_ready(chan);
l2cap_chan_unlock(chan);
@@ -1576,7 +1675,7 @@ static void l2cap_conn_start(struct l2cap_conn *conn)
if (!l2cap_mode_supported(chan->mode, conn->feat_mask)
&& test_bit(CONF_STATE2_DEVICE,
&chan->conf_state)) {
- l2cap_chan_close(chan, ECONNRESET);
+ __l2cap_chan_close(chan, ECONNRESET);
l2cap_chan_unlock(chan);
continue;
}
@@ -1584,7 +1683,7 @@ static void l2cap_conn_start(struct l2cap_conn *conn)
if (l2cap_check_enc_key_size(conn->hcon, chan))
l2cap_start_connection(chan);
else
- l2cap_chan_close(chan, ECONNREFUSED);
+ __l2cap_chan_close(chan, ECONNREFUSED);
} else if (chan->state == BT_CONNECT2) {
struct l2cap_conn_rsp rsp;
@@ -1676,6 +1775,8 @@ static void l2cap_conn_ready(struct l2cap_conn *conn)
l2cap_chan_lock(chan);
+ lockdep_assert_held(&chan->conn->lock);
+
if (hcon->type == LE_LINK) {
l2cap_le_start(chan);
} else if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
@@ -1698,6 +1799,7 @@ static void l2cap_conn_ready(struct l2cap_conn *conn)
/* Notify sockets that we cannot guaranty reliability anymore */
static void l2cap_conn_unreliable(struct l2cap_conn *conn, int err)
+ __must_hold(&conn->lock)
{
struct l2cap_chan *chan;
@@ -1830,6 +1932,8 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err)
l2cap_chan_hold(chan);
l2cap_chan_lock(chan);
+ lockdep_assert_held(&chan->conn->lock);
+
l2cap_chan_del(chan, err);
chan->ops->close(chan);
@@ -2995,6 +3099,7 @@ static void l2cap_pass_to_tx_fbit(struct l2cap_chan *chan,
/* Copy frame to all raw sockets on that connection */
static void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb)
+ __must_hold(&conn->lock)
{
struct sk_buff *nskb;
struct l2cap_chan *chan;
@@ -3645,18 +3750,29 @@ done:
break;
case L2CAP_MODE_ERTM:
- if (!test_bit(CONF_EWS_RECV, &chan->conf_state))
- chan->remote_tx_win = rfc.txwin_size;
- else
- rfc.txwin_size = L2CAP_DEFAULT_TX_WINDOW;
-
- chan->remote_max_tx = rfc.max_transmit;
-
size = min_t(u16, le16_to_cpu(rfc.max_pdu_size),
chan->conn->mtu - L2CAP_EXT_HDR_SIZE -
L2CAP_SDULEN_SIZE - L2CAP_FCS_SIZE);
rfc.max_pdu_size = cpu_to_le16(size);
- chan->remote_mps = size;
+
+ /* The TxWindow must be within 1 to 63, otherwise
+ * propose the default one and keep the parameters of
+ * an earlier request. This overrides a PENDING result
+ * from the EFS check above, so the request is no
+ * longer pending, nor done if an earlier one was.
+ */
+ if (!rfc.txwin_size ||
+ rfc.txwin_size > L2CAP_DEFAULT_TX_WINDOW) {
+ result = L2CAP_CONF_UNACCEPT;
+ clear_bit(CONF_LOC_CONF_PEND, &chan->conf_state);
+ clear_bit(CONF_OUTPUT_DONE, &chan->conf_state);
+ rfc.txwin_size = L2CAP_DEFAULT_TX_WINDOW;
+ remote_efs = 0;
+ } else {
+ chan->remote_tx_win = rfc.txwin_size;
+ chan->remote_max_tx = rfc.max_transmit;
+ chan->remote_mps = size;
+ }
__l2cap_set_ertm_timeouts(chan, &rfc);
@@ -3798,7 +3914,11 @@ static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len,
}
}
- if (chan->mode == L2CAP_MODE_BASIC && chan->mode != rfc.mode)
+ /* A connected channel cannot change its mode, as the new mode would
+ * not be initialized.
+ */
+ if (chan->mode != rfc.mode &&
+ (chan->mode == L2CAP_MODE_BASIC || chan->state == BT_CONNECTED))
return -ECONNREFUSED;
chan->mode = rfc.mode;
@@ -3888,6 +4008,7 @@ static void l2cap_ecred_list_defer(struct l2cap_chan *chan, void *data)
}
struct l2cap_ecred_rsp_data {
+ struct l2cap_chan *locked_chan;
struct {
struct l2cap_ecred_conn_rsp_hdr rsp;
__le16 scid[L2CAP_ECRED_MAX_CID];
@@ -3895,11 +4016,42 @@ struct l2cap_ecred_rsp_data {
int count;
};
+/* Lock @chan if it is not @locked_chan, and has same or lower nesting level.
+ *
+ * They must have the same chan->conn, and conn->lock must be held.
+ *
+ * Caller must ensure @chan has lock nesting level <= that of @locked_chan, as
+ * nested locking of l2cap_chan of different levels is allowed also without
+ * holding conn->lock.
+ *
+ * See l2cap.h for the global l2cap_chan locking rules.
+ */
+static bool l2cap_chan_try_sibling_lock(struct l2cap_chan *chan,
+ struct l2cap_chan *locked_chan)
+ __must_hold(&locked_chan->lock)
+ __must_hold(&locked_chan->conn->lock)
+ __cond_acquires(true, &chan->lock)
+{
+ if (chan == locked_chan)
+ return false;
+
+ if (WARN_ON_ONCE(locked_chan->conn != chan->conn))
+ return false;
+
+ if (WARN_ON_ONCE(atomic_read(&locked_chan->nesting)
+ < atomic_read(&chan->nesting)))
+ return false;
+
+ mutex_lock_nest_lock(&chan->lock, &locked_chan->conn->lock);
+ return true;
+}
+
static void l2cap_ecred_rsp_defer(struct l2cap_chan *chan, void *data)
{
struct l2cap_ecred_rsp_data *rsp = data;
struct l2cap_ecred_conn_rsp *rsp_flex =
container_of(&rsp->pdu.rsp, struct l2cap_ecred_conn_rsp, hdr);
+ bool locked;
if (chan->mode != L2CAP_MODE_EXT_FLOWCTL)
return;
@@ -3911,6 +4063,22 @@ static void l2cap_ecred_rsp_defer(struct l2cap_chan *chan, void *data)
!test_and_clear_bit(FLAG_DEFER_SETUP, &chan->flags))
return;
+ lockdep_assert_held(&rsp->locked_chan->lock);
+ lockdep_assert_held(&rsp->locked_chan->conn->lock);
+
+ l2cap_chan_hold(chan);
+
+ locked = l2cap_chan_try_sibling_lock(chan, rsp->locked_chan);
+
+ /* Cannot occur: PARENT channels do not appear in chan_l, and SMP
+ * channels never have FLAG_DEFER_SETUP.
+ */
+ if (context_unsafe(!locked && chan != rsp->locked_chan))
+ goto done;
+
+ lockdep_assert_held(&chan->lock);
+ lockdep_assert_held(&chan->conn->lock);
+
/* Reset ident so only one response is sent */
chan->ident = 0;
@@ -3923,6 +4091,12 @@ static void l2cap_ecred_rsp_defer(struct l2cap_chan *chan, void *data)
rsp_flex->dcid[rsp->count++] = cpu_to_le16(chan->scid);
else
l2cap_chan_del(chan, ECONNRESET);
+
+done:
+ if (locked)
+ l2cap_chan_unlock(chan);
+
+ l2cap_chan_put(chan);
}
void __l2cap_ecred_conn_rsp_defer(struct l2cap_chan *chan)
@@ -3934,11 +4108,15 @@ void __l2cap_ecred_conn_rsp_defer(struct l2cap_chan *chan)
if (!id)
return;
+ if (!test_bit(FLAG_DEFER_SETUP, &chan->flags))
+ return;
BT_DBG("chan %p id %d", chan, id);
memset(&data, 0, sizeof(data));
+ data.locked_chan = chan;
+
data.pdu.rsp.mtu = cpu_to_le16(chan->imtu);
data.pdu.rsp.mps = cpu_to_le16(chan->mps);
data.pdu.rsp.credits = cpu_to_le16(chan->rx_credits);
@@ -4048,6 +4226,7 @@ static void l2cap_conf_rfc_get(struct l2cap_chan *chan, void *rsp, int len)
static inline int l2cap_command_rej(struct l2cap_conn *conn,
struct l2cap_cmd_hdr *cmd, u16 cmd_len,
u8 *data)
+ __must_hold(&conn->lock)
{
struct l2cap_cmd_rej_unk *rej = (struct l2cap_cmd_rej_unk *) data;
@@ -4080,6 +4259,8 @@ static inline int l2cap_command_rej(struct l2cap_conn *conn,
*/
static struct l2cap_chan *l2cap_new_connection(struct l2cap_conn *conn,
struct l2cap_chan *pchan)
+ __must_hold(&conn->lock)
+ __must_hold(&pchan->lock)
{
struct l2cap_chan *chan;
@@ -4087,23 +4268,31 @@ static struct l2cap_chan *l2cap_new_connection(struct l2cap_conn *conn,
if (!chan)
return NULL;
+ l2cap_chan_lock(chan);
+
l2cap_chan_set_defaults(chan, pchan);
chan->ops = pchan->ops;
__l2cap_chan_add(conn, chan);
+ lockdep_assert_held(&chan->conn->lock);
+
if (pchan->ops->new_connection &&
pchan->ops->new_connection(pchan, chan) < 0) {
l2cap_chan_del(chan, 0);
+ l2cap_chan_unlock(chan);
l2cap_chan_put(chan);
return NULL;
}
+ l2cap_chan_unlock(chan);
+
return chan;
}
static void l2cap_connect(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd,
u8 *data, u8 rsp_code)
+ __must_hold(&conn->lock)
{
struct l2cap_conn_req *req = (struct l2cap_conn_req *) data;
struct l2cap_conn_rsp rsp;
@@ -4120,7 +4309,13 @@ static void l2cap_connect(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd,
&conn->hcon->dst, ACL_LINK);
if (!pchan) {
result = L2CAP_CR_BAD_PSM;
- goto response;
+
+ rsp.scid = cpu_to_le16(scid);
+ rsp.dcid = cpu_to_le16(dcid);
+ rsp.result = cpu_to_le16(result);
+ rsp.status = cpu_to_le16(status);
+ l2cap_send_cmd(conn, cmd->ident, rsp_code, sizeof(rsp), &rsp);
+ return;
}
l2cap_chan_lock(pchan);
@@ -4202,9 +4397,6 @@ response:
rsp.status = cpu_to_le16(status);
l2cap_send_cmd(conn, cmd->ident, rsp_code, sizeof(rsp), &rsp);
- if (!pchan)
- return;
-
if (result == L2CAP_CR_PEND && status == L2CAP_CS_NO_INFO) {
struct l2cap_info_req info;
info.type = cpu_to_le16(L2CAP_IT_FEAT_MASK);
@@ -4233,6 +4425,7 @@ response:
static int l2cap_connect_req(struct l2cap_conn *conn,
struct l2cap_cmd_hdr *cmd, u16 cmd_len, u8 *data)
+ __must_hold(&conn->lock)
{
if (cmd_len < sizeof(struct l2cap_conn_req))
return -EPROTO;
@@ -4244,6 +4437,7 @@ static int l2cap_connect_req(struct l2cap_conn *conn,
static int l2cap_connect_create_rsp(struct l2cap_conn *conn,
struct l2cap_cmd_hdr *cmd, u16 cmd_len,
u8 *data)
+ __must_hold(&conn->lock)
{
struct l2cap_conn_rsp *rsp = (struct l2cap_conn_rsp *) data;
u16 scid, dcid, result, status;
@@ -4271,7 +4465,7 @@ static int l2cap_connect_create_rsp(struct l2cap_conn *conn,
if (!chan)
return -EBADSLT;
} else {
- chan = __l2cap_get_chan_by_ident(conn, cmd->ident);
+ chan = __l2cap_get_connect_chan_by_ident(conn, cmd->ident);
if (!chan)
return -EBADSLT;
}
@@ -4284,6 +4478,15 @@ static int l2cap_connect_create_rsp(struct l2cap_conn *conn,
l2cap_chan_lock(chan);
+ lockdep_assert_held(&chan->conn->lock);
+
+ /* Only accept a response to a connection request we sent and that
+ * is still outstanding. A channel waiting in BT_CONNECT for security
+ * or the feature mask has not sent one yet.
+ */
+ if (!l2cap_chan_connect_pending(chan))
+ goto done;
+
switch (result) {
case L2CAP_CR_SUCCESS:
if (__l2cap_get_chan_by_dcid(conn, dcid)) {
@@ -4305,7 +4508,7 @@ static int l2cap_connect_create_rsp(struct l2cap_conn *conn,
break;
case L2CAP_CR_PEND:
- set_bit(CONF_CONNECT_PEND, &chan->conf_state);
+ /* Our request is still outstanding */
break;
default:
@@ -4313,6 +4516,7 @@ static int l2cap_connect_create_rsp(struct l2cap_conn *conn,
break;
}
+done:
l2cap_chan_unlock(chan);
l2cap_chan_put(chan);
@@ -4361,6 +4565,7 @@ static void cmd_reject_invalid_cid(struct l2cap_conn *conn, u8 ident,
static inline int l2cap_config_req(struct l2cap_conn *conn,
struct l2cap_cmd_hdr *cmd, u16 cmd_len,
u8 *data)
+ __must_hold(&conn->lock)
{
struct l2cap_conf_req *req = (struct l2cap_conf_req *) data;
u16 dcid, flags;
@@ -4382,6 +4587,10 @@ static inline int l2cap_config_req(struct l2cap_conn *conn,
return 0;
}
+ l2cap_chan_lock(chan);
+
+ lockdep_assert_held(&chan->conn->lock);
+
if (chan->state != BT_CONFIG && chan->state != BT_CONNECT2 &&
chan->state != BT_CONNECTED) {
cmd_reject_invalid_cid(conn, cmd->ident, chan->scid,
@@ -4445,7 +4654,13 @@ static inline int l2cap_config_req(struct l2cap_conn *conn,
goto unlock;
}
- if (!test_and_set_bit(CONF_REQ_SENT, &chan->conf_state)) {
+ /* A channel in BT_CONNECT2 has not passed security or userspace
+ * accept yet. Answer the peer's request, but hold our own until
+ * the channel reaches BT_CONFIG: the CONNECT2 -> CONFIG sites send
+ * it. Connected channels may also need to reconfigure.
+ */
+ if ((chan->state == BT_CONFIG || chan->state == BT_CONNECTED) &&
+ !test_and_set_bit(CONF_REQ_SENT, &chan->conf_state)) {
u8 buf[64];
l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
l2cap_build_conf_req(chan, buf, sizeof(buf)), buf);
@@ -4472,6 +4687,7 @@ unlock:
static inline int l2cap_config_rsp(struct l2cap_conn *conn,
struct l2cap_cmd_hdr *cmd, u16 cmd_len,
u8 *data)
+ __must_hold(&conn->lock)
{
struct l2cap_conf_rsp *rsp = (struct l2cap_conf_rsp *)data;
u16 scid, flags, result;
@@ -4493,6 +4709,14 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn,
if (!chan)
return 0;
+ l2cap_chan_lock(chan);
+
+ lockdep_assert_held(&chan->conn->lock);
+
+ /* Connected channels may also receive reconfiguration responses. */
+ if (chan->state != BT_CONFIG && chan->state != BT_CONNECTED)
+ goto done;
+
switch (result) {
case L2CAP_CONF_SUCCESS:
l2cap_conf_rfc_get(chan, rsp->data, len);
@@ -4560,6 +4784,9 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn,
if (test_bit(CONF_OUTPUT_DONE, &chan->conf_state)) {
set_default_fcs(chan);
+ if (chan->state != BT_CONFIG)
+ goto done;
+
if (chan->mode == L2CAP_MODE_ERTM ||
chan->mode == L2CAP_MODE_STREAMING)
err = l2cap_ertm_init(chan);
@@ -4579,6 +4806,7 @@ done:
static inline int l2cap_disconnect_req(struct l2cap_conn *conn,
struct l2cap_cmd_hdr *cmd, u16 cmd_len,
u8 *data)
+ __must_hold(&conn->lock)
{
struct l2cap_disconn_req *req = (struct l2cap_disconn_req *) data;
struct l2cap_disconn_rsp rsp;
@@ -4599,6 +4827,10 @@ static inline int l2cap_disconnect_req(struct l2cap_conn *conn,
return 0;
}
+ l2cap_chan_lock(chan);
+
+ lockdep_assert_held(&chan->conn->lock);
+
rsp.dcid = cpu_to_le16(chan->scid);
rsp.scid = cpu_to_le16(chan->dcid);
l2cap_send_cmd(conn, cmd->ident, L2CAP_DISCONN_RSP, sizeof(rsp), &rsp);
@@ -4618,6 +4850,7 @@ static inline int l2cap_disconnect_req(struct l2cap_conn *conn,
static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn,
struct l2cap_cmd_hdr *cmd, u16 cmd_len,
u8 *data)
+ __must_hold(&conn->lock)
{
struct l2cap_disconn_rsp *rsp = (struct l2cap_disconn_rsp *) data;
u16 dcid, scid;
@@ -4636,6 +4869,10 @@ static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn,
return 0;
}
+ l2cap_chan_lock(chan);
+
+ lockdep_assert_held(&chan->conn->lock);
+
if (chan->state != BT_DISCONN) {
l2cap_chan_unlock(chan);
l2cap_chan_put(chan);
@@ -4703,6 +4940,7 @@ static inline int l2cap_information_req(struct l2cap_conn *conn,
static inline int l2cap_information_rsp(struct l2cap_conn *conn,
struct l2cap_cmd_hdr *cmd, u16 cmd_len,
u8 *data)
+ __must_hold(&conn->lock)
{
struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) data;
u16 type, result;
@@ -4810,6 +5048,7 @@ static inline int l2cap_conn_param_update_req(struct l2cap_conn *conn,
static int l2cap_le_connect_rsp(struct l2cap_conn *conn,
struct l2cap_cmd_hdr *cmd, u16 cmd_len,
u8 *data)
+ __must_hold(&conn->lock)
{
struct l2cap_le_conn_rsp *rsp = (struct l2cap_le_conn_rsp *) data;
struct hci_conn *hcon = conn->hcon;
@@ -4846,6 +5085,8 @@ static int l2cap_le_connect_rsp(struct l2cap_conn *conn,
l2cap_chan_lock(chan);
+ lockdep_assert_held(&chan->conn->lock);
+
switch (result) {
case L2CAP_CR_LE_SUCCESS:
if (__l2cap_get_chan_by_dcid(conn, dcid)) {
@@ -4916,6 +5157,7 @@ static void l2cap_put_ident(struct l2cap_conn *conn, u8 code, u8 id)
static inline int l2cap_bredr_sig_cmd(struct l2cap_conn *conn,
struct l2cap_cmd_hdr *cmd, u16 cmd_len,
u8 *data)
+ __must_hold(&conn->lock)
{
int err = 0;
@@ -4977,6 +5219,7 @@ static inline int l2cap_bredr_sig_cmd(struct l2cap_conn *conn,
static int l2cap_le_connect_req(struct l2cap_conn *conn,
struct l2cap_cmd_hdr *cmd, u16 cmd_len,
u8 *data)
+ __must_hold(&conn->lock)
{
struct l2cap_le_conn_req *req = (struct l2cap_le_conn_req *) data;
struct l2cap_le_conn_rsp rsp;
@@ -5060,6 +5303,10 @@ static int l2cap_le_connect_req(struct l2cap_conn *conn,
goto response_unlock;
}
+ l2cap_chan_lock(chan);
+
+ lockdep_assert_held(&chan->conn->lock);
+
bacpy(&chan->src, &conn->hcon->src);
bacpy(&chan->dst, &conn->hcon->dst);
chan->src_type = bdaddr_src_type(conn->hcon);
@@ -5093,6 +5340,8 @@ static int l2cap_le_connect_req(struct l2cap_conn *conn,
result = L2CAP_CR_LE_SUCCESS;
}
+ l2cap_chan_unlock(chan);
+
response_unlock:
l2cap_chan_unlock(pchan);
l2cap_chan_put(pchan);
@@ -5121,6 +5370,7 @@ response:
static inline int l2cap_le_credits(struct l2cap_conn *conn,
struct l2cap_cmd_hdr *cmd, u16 cmd_len,
u8 *data)
+ __must_hold(&conn->lock)
{
struct l2cap_le_credits *pkt;
struct l2cap_chan *chan;
@@ -5139,6 +5389,8 @@ static inline int l2cap_le_credits(struct l2cap_conn *conn,
if (!chan)
return -EBADSLT;
+ l2cap_chan_lock(chan);
+
max_credits = LE_FLOWCTL_MAX_CREDITS - chan->tx_credits;
if (credits > max_credits) {
BT_ERR("LE credits overflow");
@@ -5168,6 +5420,7 @@ unlock:
static inline int l2cap_ecred_conn_req(struct l2cap_conn *conn,
struct l2cap_cmd_hdr *cmd, u16 cmd_len,
u8 *data)
+ __must_hold(&conn->lock)
{
struct l2cap_ecred_conn_req *req = (void *) data;
DEFINE_RAW_FLEX(struct l2cap_ecred_conn_rsp, pdu, dcid, L2CAP_ECRED_MAX_CID);
@@ -5283,6 +5536,10 @@ static inline int l2cap_ecred_conn_req(struct l2cap_conn *conn,
continue;
}
+ l2cap_chan_lock(chan);
+
+ lockdep_assert_held(&chan->conn->lock);
+
bacpy(&chan->src, &conn->hcon->src);
bacpy(&chan->dst, &conn->hcon->dst);
chan->src_type = bdaddr_src_type(conn->hcon);
@@ -5315,6 +5572,8 @@ static inline int l2cap_ecred_conn_req(struct l2cap_conn *conn,
} else {
l2cap_chan_ready(chan);
}
+
+ l2cap_chan_unlock(chan);
}
unlock:
@@ -5336,6 +5595,7 @@ response:
static inline int l2cap_ecred_conn_rsp(struct l2cap_conn *conn,
struct l2cap_cmd_hdr *cmd, u16 cmd_len,
u8 *data)
+ __must_hold(&conn->lock)
{
struct l2cap_ecred_conn_rsp *rsp = (void *) data;
struct hci_conn *hcon = conn->hcon;
@@ -5366,12 +5626,16 @@ static inline int l2cap_ecred_conn_rsp(struct l2cap_conn *conn,
chan->state == BT_CONNECTED)
continue;
+ l2cap_chan_hold(chan);
l2cap_chan_lock(chan);
+ lockdep_assert_held(&chan->conn->lock);
+
/* Check that there is a dcid for each pending channel */
if (cmd_len < sizeof(dcid)) {
l2cap_chan_del(chan, ECONNREFUSED);
l2cap_chan_unlock(chan);
+ l2cap_chan_put(chan);
continue;
}
@@ -5410,6 +5674,8 @@ static inline int l2cap_ecred_conn_rsp(struct l2cap_conn *conn,
__set_chan_timer(orig, 0);
l2cap_chan_unlock(orig);
}
+
+ l2cap_chan_put(chan);
continue;
}
@@ -5455,6 +5721,7 @@ static inline int l2cap_ecred_conn_rsp(struct l2cap_conn *conn,
}
l2cap_chan_unlock(chan);
+ l2cap_chan_put(chan);
}
return err;
@@ -5463,6 +5730,7 @@ static inline int l2cap_ecred_conn_rsp(struct l2cap_conn *conn,
static inline int l2cap_ecred_reconf_req(struct l2cap_conn *conn,
struct l2cap_cmd_hdr *cmd, u16 cmd_len,
u8 *data)
+ __must_hold(&conn->lock)
{
struct l2cap_ecred_reconf_req *req = (void *) data;
struct l2cap_ecred_reconf_rsp rsp;
@@ -5561,6 +5829,7 @@ respond:
static inline int l2cap_ecred_reconf_rsp(struct l2cap_conn *conn,
struct l2cap_cmd_hdr *cmd, u16 cmd_len,
u8 *data)
+ __must_hold(&conn->lock)
{
struct l2cap_chan *chan, *tmp;
struct l2cap_ecred_reconf_rsp *rsp = (void *)data;
@@ -5589,6 +5858,8 @@ static inline int l2cap_ecred_reconf_rsp(struct l2cap_conn *conn,
continue;
l2cap_chan_lock(chan);
+ lockdep_assert_held(&chan->conn->lock);
+
l2cap_chan_del(chan, ECONNRESET);
l2cap_chan_unlock(chan);
@@ -5601,6 +5872,7 @@ static inline int l2cap_ecred_reconf_rsp(struct l2cap_conn *conn,
static inline int l2cap_le_command_rej(struct l2cap_conn *conn,
struct l2cap_cmd_hdr *cmd, u16 cmd_len,
u8 *data)
+ __must_hold(&conn->lock)
{
struct l2cap_cmd_rej_unk *rej = (struct l2cap_cmd_rej_unk *) data;
struct l2cap_chan *chan;
@@ -5617,6 +5889,7 @@ static inline int l2cap_le_command_rej(struct l2cap_conn *conn,
goto done;
l2cap_chan_lock(chan);
+ lockdep_assert_held(&chan->conn->lock);
l2cap_chan_del(chan, ECONNREFUSED);
l2cap_chan_unlock(chan);
l2cap_chan_put(chan);
@@ -5628,6 +5901,7 @@ done:
static inline int l2cap_le_sig_cmd(struct l2cap_conn *conn,
struct l2cap_cmd_hdr *cmd, u16 cmd_len,
u8 *data)
+ __must_hold(&conn->lock)
{
int err = 0;
@@ -5692,6 +5966,7 @@ static inline int l2cap_le_sig_cmd(struct l2cap_conn *conn,
static inline void l2cap_le_sig_channel(struct l2cap_conn *conn,
struct sk_buff *skb)
+ __must_hold(&conn->lock)
{
struct hci_conn *hcon = conn->hcon;
struct l2cap_cmd_hdr *cmd;
@@ -5750,6 +6025,7 @@ static inline void l2cap_sig_send_mtu_rej(struct l2cap_conn *conn, u8 ident)
static inline void l2cap_sig_channel(struct l2cap_conn *conn,
struct sk_buff *skb)
+ __must_hold(&conn->lock)
{
struct hci_conn *hcon = conn->hcon;
struct l2cap_cmd_hdr *cmd;
@@ -6995,6 +7271,7 @@ failed:
static void l2cap_data_channel(struct l2cap_conn *conn, u16 cid,
struct sk_buff *skb)
+ __must_hold(&conn->lock)
{
struct l2cap_chan *chan;
@@ -7006,6 +7283,10 @@ static void l2cap_data_channel(struct l2cap_conn *conn, u16 cid,
return;
}
+ l2cap_chan_lock(chan);
+
+ lockdep_assert_held(&chan->conn->lock);
+
BT_DBG("chan %p, len %d", chan, skb->len);
/* If we receive data on a fixed channel before the info req/rsp
@@ -7101,6 +7382,7 @@ free_skb:
}
static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb)
+ __must_hold(&conn->lock)
{
struct l2cap_hdr *lh = (void *) skb->data;
struct hci_conn *hcon = conn->hcon;
@@ -7210,9 +7492,9 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon)
hci_dev_test_flag(hcon->hdev, HCI_FORCE_BREDR_SMP)))
conn->local_fixed_chan |= L2CAP_FC_SMP_BREDR;
- mutex_init(&conn->lock);
-
- INIT_LIST_HEAD(&conn->chan_l);
+ scoped_guard(mutex_init, &conn->lock) {
+ INIT_LIST_HEAD(&conn->chan_l);
+ }
INIT_LIST_HEAD(&conn->users);
INIT_DELAYED_WORK(&conn->info_timer, l2cap_info_timeout);
@@ -7416,7 +7698,8 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid,
}
}
- if (cid && __l2cap_get_chan_by_dcid(conn, cid)) {
+ if ((cid && __l2cap_get_chan_by_dcid(conn, cid)) || chan->conn ||
+ test_bit(FLAG_DEL, &chan->flags)) {
hci_conn_drop(hcon);
err = -EBUSY;
goto chan_unlock;
@@ -7428,6 +7711,8 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid,
__l2cap_chan_add(conn, chan);
+ lockdep_assert_held(&chan->conn->lock);
+
/* l2cap_chan_add takes its own ref so we can drop this one */
hci_conn_drop(hcon);
@@ -7591,6 +7876,8 @@ static void l2cap_connect_cfm(struct hci_conn *hcon, u8 status)
* we left off, because the list lock would prevent calling the
* potentially sleeping l2cap_chan_lock() function.
*/
+ mutex_lock(&conn->lock);
+
pchan = l2cap_global_fixed_chan(NULL, hcon);
while (pchan) {
struct l2cap_chan *chan, *next;
@@ -7615,6 +7902,8 @@ next:
pchan = next;
}
+ mutex_unlock(&conn->lock);
+
l2cap_conn_ready(conn);
}
@@ -7646,6 +7935,8 @@ static void l2cap_disconn_cfm(struct hci_conn *hcon, u8 reason)
}
static inline void l2cap_check_encryption(struct l2cap_chan *chan, u8 encrypt)
+ __must_hold(&chan->lock)
+ __must_hold(&chan->conn->lock)
{
if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED)
return;
@@ -7655,7 +7946,7 @@ static inline void l2cap_check_encryption(struct l2cap_chan *chan, u8 encrypt)
__set_chan_timer(chan, L2CAP_ENC_TIMEOUT);
} else if (chan->sec_level == BT_SECURITY_HIGH ||
chan->sec_level == BT_SECURITY_FIPS)
- l2cap_chan_close(chan, ECONNREFUSED);
+ __l2cap_chan_close(chan, ECONNREFUSED);
} else {
if (chan->sec_level == BT_SECURITY_MEDIUM)
__clear_chan_timer(chan);
@@ -7678,6 +7969,8 @@ static void l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
list_for_each_entry(chan, &conn->chan_l, list) {
l2cap_chan_lock(chan);
+ lockdep_assert_held(&chan->conn->lock);
+
BT_DBG("chan %p scid 0x%4.4x state %s", chan, chan->scid,
state_to_string(chan->state));
diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c
index 872d8fb31b6f..7a2551ef7f50 100644
--- a/net/bluetooth/l2cap_sock.c
+++ b/net/bluetooth/l2cap_sock.c
@@ -109,6 +109,7 @@ static int l2cap_sock_bind(struct socket *sock, struct sockaddr_unsized *addr, i
return -EINVAL;
}
+ l2cap_chan_lock(chan);
lock_sock(sk);
if (sk->sk_state != BT_OPEN) {
@@ -174,6 +175,7 @@ static int l2cap_sock_bind(struct socket *sock, struct sockaddr_unsized *addr, i
done:
release_sock(sk);
+ l2cap_chan_unlock(chan);
return err;
}
@@ -813,6 +815,10 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname,
break;
}
+ /* A zero TxWindow is invalid, use the default instead */
+ if (!opts.txwin_size)
+ opts.txwin_size = L2CAP_DEFAULT_TX_WINDOW;
+
if (!l2cap_valid_mtu(chan, opts.imtu)) {
err = -EINVAL;
break;
@@ -865,15 +871,11 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname,
if (opt & L2CAP_LM_SECURE)
chan->sec_level = BT_SECURITY_HIGH;
- if (opt & L2CAP_LM_MASTER)
- set_bit(FLAG_ROLE_SWITCH, &chan->flags);
- else
- clear_bit(FLAG_ROLE_SWITCH, &chan->flags);
+ assign_bit(FLAG_ROLE_SWITCH, &chan->flags,
+ opt & L2CAP_LM_MASTER);
- if (opt & L2CAP_LM_RELIABLE)
- set_bit(FLAG_FORCE_RELIABLE, &chan->flags);
- else
- clear_bit(FLAG_FORCE_RELIABLE, &chan->flags);
+ assign_bit(FLAG_FORCE_RELIABLE, &chan->flags,
+ opt & L2CAP_LM_RELIABLE);
break;
default:
@@ -1040,10 +1042,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname,
}
}
- if (opt)
- set_bit(FLAG_FLUSHABLE, &chan->flags);
- else
- clear_bit(FLAG_FLUSHABLE, &chan->flags);
+ assign_bit(FLAG_FLUSHABLE, &chan->flags, opt);
break;
case BT_POWER:
@@ -1059,10 +1058,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname,
if (err)
break;
- if (pwr.force_active)
- set_bit(FLAG_FORCE_ACTIVE, &chan->flags);
- else
- clear_bit(FLAG_FORCE_ACTIVE, &chan->flags);
+ assign_bit(FLAG_FORCE_ACTIVE, &chan->flags, pwr.force_active);
break;
case BT_CHANNEL_POLICY:
@@ -1243,40 +1239,68 @@ static void l2cap_publish_rx_avail(struct l2cap_chan *chan)
l2cap_chan_rx_avail(chan, -1);
}
-static int l2cap_sock_recvmsg(struct socket *sock, struct msghdr *msg,
- size_t len, int flags)
+static int l2cap_sock_defer(struct sock *sk)
{
- struct sock *sk = sock->sk;
- struct l2cap_pinfo *pi = l2cap_pi(sk);
- int err;
+ struct l2cap_chan *chan = l2cap_pi(sk)->chan;
+ bool have_conn;
+ int err = 0;
- if (unlikely(flags & MSG_ERRQUEUE))
- return sock_recv_errqueue(sk, msg, len, SOL_BLUETOOTH,
- BT_SCM_ERROR);
+ /* Fast path check */
+ lock_sock(sk);
+ if (sk->sk_state != BT_CONNECT2) {
+ release_sock(sk);
+ return 0;
+ }
+ release_sock(sk);
+ have_conn = l2cap_chan_lock_conn(chan);
lock_sock(sk);
if (sk->sk_state == BT_CONNECT2 && test_bit(BT_SK_DEFER_SETUP,
&bt_sk(sk)->flags)) {
- if (pi->chan->mode == L2CAP_MODE_EXT_FLOWCTL) {
+ err = 1;
+
+ if (!have_conn) {
+ release_sock(sk);
+ err = -ENOTCONN;
+ } else if (chan->mode == L2CAP_MODE_EXT_FLOWCTL) {
sk->sk_state = BT_CONNECTED;
- pi->chan->state = BT_CONNECTED;
- __l2cap_ecred_conn_rsp_defer(pi->chan);
- } else if (bdaddr_type_is_le(pi->chan->src_type)) {
+ chan->state = BT_CONNECTED;
+ release_sock(sk);
+ __l2cap_ecred_conn_rsp_defer(chan);
+ } else if (bdaddr_type_is_le(chan->src_type)) {
sk->sk_state = BT_CONNECTED;
- pi->chan->state = BT_CONNECTED;
- __l2cap_le_connect_rsp_defer(pi->chan);
+ chan->state = BT_CONNECTED;
+ release_sock(sk);
+ __l2cap_le_connect_rsp_defer(chan);
} else {
sk->sk_state = BT_CONFIG;
- pi->chan->state = BT_CONFIG;
- __l2cap_connect_rsp_defer(pi->chan);
+ chan->state = BT_CONFIG;
+ release_sock(sk);
+ __l2cap_connect_rsp_defer(chan);
}
-
- err = 0;
- goto done;
+ } else {
+ release_sock(sk);
}
- release_sock(sk);
+ l2cap_chan_unlock_conn(chan, have_conn);
+ return err;
+}
+
+static int l2cap_sock_recvmsg(struct socket *sock, struct msghdr *msg,
+ size_t len, int flags)
+{
+ struct sock *sk = sock->sk;
+ struct l2cap_pinfo *pi = l2cap_pi(sk);
+ int err;
+
+ if (unlikely(flags & MSG_ERRQUEUE))
+ return sock_recv_errqueue(sk, msg, len, SOL_BLUETOOTH,
+ BT_SCM_ERROR);
+
+ err = l2cap_sock_defer(sk);
+ if (err)
+ return err < 0 ? err : 0;
if (sock->type == SOCK_STREAM)
err = bt_sock_stream_recvmsg(sock, msg, len, flags);
@@ -1406,7 +1430,6 @@ static int l2cap_sock_shutdown(struct socket *sock, int how)
{
struct sock *sk = sock->sk;
struct l2cap_chan *chan;
- struct l2cap_conn *conn;
int err = 0;
BT_DBG("sock %p, sk %p, how %d", sock, sk, how);
@@ -1463,23 +1486,7 @@ static int l2cap_sock_shutdown(struct socket *sock, int how)
sk->sk_shutdown |= SEND_SHUTDOWN;
release_sock(sk);
- l2cap_chan_lock(chan);
- /* prevent conn structure from being freed */
- conn = l2cap_conn_hold_unless_zero(chan->conn);
- l2cap_chan_unlock(chan);
-
- if (conn)
- /* mutex lock must be taken before l2cap_chan_lock() */
- mutex_lock(&conn->lock);
-
- l2cap_chan_lock(chan);
- l2cap_chan_close(chan, 0);
- l2cap_chan_unlock(chan);
-
- if (conn) {
- mutex_unlock(&conn->lock);
- l2cap_conn_put(conn);
- }
+ l2cap_chan_close_unlocked(chan, 0);
lock_sock(sk);
@@ -1748,8 +1755,14 @@ static void l2cap_sock_teardown_cb(struct l2cap_chan *chan, int err)
sk->sk_err = err;
if (parent) {
+ /*
+ * Keep the listener alive after unlinking the
+ * child.
+ */
+ sock_hold(parent);
bt_accept_unlink(sk);
parent->sk_data_ready(parent);
+ sock_put(parent);
} else {
sk->sk_state_change(sk);
}
@@ -1784,6 +1797,7 @@ static void l2cap_sock_state_change_cb(struct l2cap_chan *chan, int state,
static struct sk_buff *l2cap_sock_alloc_skb_cb(struct l2cap_chan *chan,
unsigned long hdr_len,
unsigned long len, int nb)
+ __must_hold(&chan->lock)
{
struct sock *sk = chan->data;
struct sk_buff *skb;
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 251a896babd5..3b9c82bd2f02 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -177,6 +177,7 @@ static const u16 mgmt_events[] = {
MGMT_EV_CONTROLLER_RESUME,
MGMT_EV_ADV_MONITOR_DEVICE_FOUND,
MGMT_EV_ADV_MONITOR_DEVICE_LOST,
+ MGMT_EV_SECURITY_LEVEL_CHANGED,
};
static const u16 mgmt_untrusted_commands[] = {
@@ -301,6 +302,8 @@ static u8 mgmt_errno_status(int err)
return MGMT_STATUS_ALREADY_CONNECTED;
case -ENOTCONN:
return MGMT_STATUS_DISCONNECTED;
+ case -ECANCELED:
+ return MGMT_STATUS_CANCELLED;
}
return MGMT_STATUS_FAILED;
@@ -1296,7 +1299,7 @@ void mgmt_advertising_removed(struct sock *sk, struct hci_dev *hdev,
static void cancel_adv_timeout(struct hci_dev *hdev)
{
if (hdev->adv_instance_timeout) {
- hdev->adv_instance_timeout = 0;
+ hdev->adv_instance_timeout = false;
cancel_delayed_work(&hdev->adv_instance_expire);
}
}
@@ -4906,6 +4909,13 @@ static int set_quality_report_func(struct sock *sk, struct hci_dev *hdev,
hci_req_sync_lock(hdev);
+ if (hci_dev_test_flag(hdev, HCI_UNREGISTER)) {
+ err = mgmt_cmd_status(sk, hdev->id,
+ MGMT_OP_SET_EXP_FEATURE,
+ MGMT_STATUS_INVALID_INDEX);
+ goto unlock_quality_report;
+ }
+
val = !!cp->param[0];
changed = (val != hci_dev_test_flag(hdev, HCI_QUALITY_REPORT));
@@ -5682,8 +5692,18 @@ static void mgmt_remove_adv_monitor_complete(struct hci_dev *hdev,
struct mgmt_pending_cmd *cmd = data;
struct mgmt_cp_remove_adv_monitor *cp;
- if (status == -ECANCELED)
+ /* Reply to a cancelled command so bluetoothd's serialised mgmt queue
+ * is not blocked.
+ */
+ if (status == -ECANCELED) {
+ cp = cmd->param;
+ rp.monitor_handle = cp->monitor_handle;
+
+ mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode,
+ mgmt_status(status), &rp, sizeof(rp));
+ mgmt_pending_free(cmd);
return;
+ }
hci_dev_lock(hdev);
@@ -6533,7 +6553,12 @@ static void set_advertising_complete(struct hci_dev *hdev, void *data, int err)
return;
}
- if (hci_dev_test_flag(hdev, HCI_LE_ADV))
+ /* With extended advertising global advertising (instance 0) has its
+ * own advertising set so only consider its state, other instances may
+ * still be enabled.
+ */
+ if (ext_adv_capable(hdev) ? hci_dev_test_flag(hdev, HCI_LE_ADV_0) :
+ hci_dev_test_flag(hdev, HCI_LE_ADV))
hci_dev_set_flag(hdev, HCI_ADVERTISING);
else
hci_dev_clear_flag(hdev, HCI_ADVERTISING);
@@ -6553,6 +6578,34 @@ static void set_advertising_complete(struct hci_dev *hdev, void *data, int err)
list_empty(&hdev->adv_instances))
return;
+ /* With extended advertising instances are not overridden by global
+ * advertising, except the ones sharing its set, so only (re)start the
+ * instances that are not already enabled.
+ *
+ * Lookup instances by identifier while holding hdev->lock since the
+ * list may change while waiting for the HCI commands to complete.
+ */
+ if (ext_adv_capable(hdev)) {
+ u16 i;
+
+ for (i = 1; i <= hdev->le_num_of_adv_sets + 1; i++) {
+ bool enabled;
+
+ hci_dev_lock(hdev);
+ adv_instance = hci_find_adv_instance(hdev, i);
+ enabled = !adv_instance || adv_instance->enabled;
+ hci_dev_unlock(hdev);
+
+ if (enabled)
+ continue;
+
+ err = hci_schedule_adv_instance_sync(hdev, i, true);
+ enable_advertising_instance(hdev, err);
+ }
+
+ return;
+ }
+
instance = hdev->cur_adv_instance;
if (!instance) {
adv_instance = list_first_entry_or_null(&hdev->adv_instances,
@@ -6608,6 +6661,11 @@ static int set_adv_sync(struct hci_dev *hdev, void *data)
hci_update_scan_rsp_data_sync(hdev, 0x00);
hci_enable_advertising_sync(hdev);
}
+ } else if (ext_adv_capable(hdev)) {
+ /* Only disable global advertising (instance 0) leaving other
+ * instances untouched.
+ */
+ hci_disable_ext_adv_legacy_instance_sync(hdev);
} else {
hci_disable_advertising_sync(hdev);
}
@@ -8289,8 +8347,10 @@ static int load_conn_subrate(struct sock *sk, struct hci_dev *hdev, void *data,
hci_param->cont_num = cont_num;
hci_param->rate_supv_timeout = supv_timeout;
- /* If the device is connected as central check if the
- * connection rate parameters need to be updated.
+ /* If the device is connected check if the connection rate
+ * parameters need to be updated, either role can initiate the
+ * Connection Rate Update procedure, e.g. a HID device acting
+ * as peripheral once the HID host requests a HID SCI mode.
*/
if (!i && param_count == 1) {
struct hci_conn *conn;
@@ -8299,7 +8359,6 @@ static int load_conn_subrate(struct sock *sk, struct hci_dev *hdev, void *data,
&hci_param->addr,
addr_type);
if (conn && conn->state == BT_CONNECTED &&
- conn->role == HCI_ROLE_MASTER &&
(conn->le_rate_interval < min ||
conn->le_rate_interval > max ||
conn->le_subrate < subrate_min ||
@@ -8939,6 +8998,21 @@ static bool adv_busy(struct hci_dev *hdev)
return pending_find(MGMT_OP_SET_LE, hdev);
}
+/* Global advertising, enabled with MGMT_OP_SET_ADVERTISING, uses instance 0
+ * and takes precedence over any instance that would share its advertising
+ * set: with legacy advertising there is only a single set so all instances
+ * are overridden, whereas with extended advertising only an instance using
+ * handle 0x00 is.
+ */
+static bool adv_overridden_by_global(struct hci_dev *hdev,
+ struct adv_info *adv)
+{
+ if (!hci_dev_test_flag(hdev, HCI_ADVERTISING))
+ return false;
+
+ return !ext_adv_capable(hdev) || !adv->handle;
+}
+
static void add_adv_complete(struct hci_dev *hdev, struct sock *sk, u8 instance,
int err)
{
@@ -9100,13 +9174,19 @@ static int add_advertising(struct sock *sk, struct hci_dev *hdev,
schedule_instance = cp->instance;
}
- /* If the HCI_ADVERTISING flag is set or the device isn't powered or
- * there is no instance to be advertised then we have no HCI
- * communication to make. Simply return.
+ /* If the instance is overridden by global advertising or the device
+ * isn't powered or there is no instance to be advertised then we have
+ * no HCI communication to make. Simply return.
*/
if (!hdev_is_powered(hdev) ||
- hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
+ adv_overridden_by_global(hdev, adv) ||
!schedule_instance) {
+ /* Instance has been accepted so it shall no longer be
+ * considered pending, otherwise a later failure in
+ * add_adv_complete would remove it.
+ */
+ adv->pending = false;
+
rp.instance = cp->instance;
err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
@@ -9280,20 +9360,24 @@ static int add_ext_adv_params(struct sock *sk, struct hci_dev *hdev,
goto unlock;
}
- /* Submit request for advertising params if ext adv available */
- if (ext_adv_capable(hdev)) {
+ /* Submit request for advertising params if ext adv available, unless
+ * the set is in use by global advertising in which case the params
+ * will be programmed once the instance is scheduled.
+ */
+ if (ext_adv_capable(hdev) && !adv_overridden_by_global(hdev, adv)) {
cmd = mgmt_pending_new(sk, MGMT_OP_ADD_EXT_ADV_PARAMS, hdev,
data, data_len);
if (!cmd) {
err = -ENOMEM;
- hci_remove_adv_instance(hdev, cp->instance);
- goto unlock;
+ goto remove;
}
err = hci_cmd_sync_queue(hdev, add_ext_adv_params_sync, cmd,
add_ext_adv_params_complete);
- if (err < 0)
+ if (err < 0) {
mgmt_pending_free(cmd);
+ goto remove;
+ }
} else {
rp.instance = cp->instance;
rp.tx_power = HCI_ADV_TX_POWER_NO_PREFERENCE;
@@ -9304,6 +9388,18 @@ static int add_ext_adv_params(struct sock *sk, struct hci_dev *hdev,
MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
}
+ goto unlock;
+
+remove:
+ /* The instance may have been modified already so remove it, like it
+ * is done in add_ext_adv_params_complete, signaling it has been
+ * removed if it was previously added.
+ */
+ if (!adv->pending)
+ mgmt_advertising_removed(sk, hdev, cp->instance);
+
+ hci_remove_adv_instance(hdev, cp->instance);
+
unlock:
hci_dev_unlock(hdev);
@@ -9431,11 +9527,12 @@ static int add_ext_adv_data(struct sock *sk, struct hci_dev *hdev, void *data,
schedule_instance = cp->instance;
}
- /* If the HCI_ADVERTISING flag is set or there is no instance to
- * be advertised then we have no HCI communication to make.
+ /* If the instance is overridden by global advertising or there is no
+ * instance to be advertised then we have no HCI communication to make.
* Simply return.
*/
- if (hci_dev_test_flag(hdev, HCI_ADVERTISING) || !schedule_instance) {
+ if (adv_overridden_by_global(hdev, adv_instance) ||
+ !schedule_instance) {
if (adv_instance->pending) {
mgmt_advertising_added(sk, hdev, cp->instance);
adv_instance->pending = false;
@@ -9511,7 +9608,11 @@ static int remove_advertising_sync(struct hci_dev *hdev, void *data)
if (err)
return err;
- if (list_empty(&hdev->adv_instances))
+ /* Don't disable advertising if global advertising (instance 0) is
+ * enabled since it is not affected by removing instances.
+ */
+ if (list_empty(&hdev->adv_instances) &&
+ !hci_dev_test_flag(hdev, HCI_ADVERTISING))
err = hci_disable_advertising_sync(hdev);
return err;
@@ -10070,6 +10171,14 @@ void mgmt_device_connected(struct hci_dev *hdev, struct hci_conn *conn,
ev->eir_len = cpu_to_le16(eir_len);
mgmt_event_skb(skb, NULL);
+
+ /* Connections that negotiated encryption as part of setup (e.g. via
+ * an existing link key) had their security level change suppressed
+ * since userspace did not know about them yet, so report it now.
+ * Unencrypted connections have no change to report.
+ */
+ if (test_bit(HCI_CONN_ENCRYPT, &conn->flags))
+ mgmt_security_level_changed(conn);
}
static void unpair_device_rsp(struct mgmt_pending_cmd *cmd, void *data)
@@ -10176,7 +10285,11 @@ void mgmt_connect_failed(struct hci_dev *hdev, struct hci_conn *conn, u8 status)
{
struct mgmt_ev_connect_failed ev;
- if (test_and_clear_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags)) {
+ /* Only peek at the flag here: hci_conn_del() (via hci_conn_unlink())
+ * still needs it set to know whether to report the security level
+ * reset, so it is consumed there instead of here.
+ */
+ if (test_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags)) {
mgmt_device_disconnected(hdev, &conn->dst, conn->type,
conn->dst_type,
hci_to_mgmt_reason(status), true);
@@ -10810,6 +10923,57 @@ void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
mgmt_adv_monitor_device_found(hdev, bdaddr, report_device, skb, NULL);
}
+void mgmt_security_level_changed(struct hci_conn *conn)
+{
+ struct mgmt_ev_security_level_changed *ev;
+ struct mgmt_tlv *tlv;
+ u8 *tlv_data;
+ u8 tlv_len;
+
+ if (!test_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags))
+ return;
+
+ /* Only ACL, LE and BIS links are tracked as mgmt connections, so
+ * restrict the event to those link types. Other transports (SCO,
+ * CIS, PA sync, ...) share the parent's address and would otherwise
+ * report a spurious security level change for it.
+ */
+ if (conn->type != ACL_LINK && conn->type != LE_LINK &&
+ conn->type != BIS_LINK)
+ return;
+
+ tlv_len = 2 * (sizeof(*tlv) + sizeof(__u8));
+ ev = kzalloc_flex(*ev, tlv_data, tlv_len, GFP_KERNEL);
+ if (!ev)
+ return;
+
+ bacpy(&ev->addr.bdaddr, &conn->dst);
+ ev->addr.type = link_to_bdaddr(conn->type, conn->dst_type);
+ ev->tlv_length = tlv_len;
+
+ tlv_data = ev->tlv_data;
+ tlv = (void *)tlv_data;
+ tlv->type = cpu_to_le16(MGMT_SEC_LEVEL_CHANGED_PARAM_LEVEL);
+ tlv->length = sizeof(__u8);
+ tlv->value[0] = conn->sec_level;
+
+ tlv_data += sizeof(*tlv) + sizeof(__u8);
+ tlv = (void *)tlv_data;
+ tlv->type = cpu_to_le16(MGMT_SEC_LEVEL_CHANGED_PARAM_ENC_TYPE);
+ tlv->length = sizeof(__u8);
+ if (!test_bit(HCI_CONN_ENCRYPT, &conn->flags))
+ tlv->value[0] = MGMT_CONN_SEC_ENCRYPT_NONE;
+ else if (test_bit(HCI_CONN_AES_CCM, &conn->flags))
+ tlv->value[0] = MGMT_CONN_SEC_ENCRYPT_AES_CCM;
+ else
+ tlv->value[0] = MGMT_CONN_SEC_ENCRYPT_E0;
+
+ mgmt_event(MGMT_EV_SECURITY_LEVEL_CHANGED, conn->hdev, ev,
+ struct_size(ev, tlv_data, tlv_len), NULL);
+
+ kfree(ev);
+}
+
void mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
u8 addr_type, s8 rssi, u8 *name, u8 name_len)
{
diff --git a/net/bluetooth/msft.c b/net/bluetooth/msft.c
index d9dd722db3eb..2559c5b1bef0 100644
--- a/net/bluetooth/msft.c
+++ b/net/bluetooth/msft.c
@@ -654,8 +654,10 @@ void msft_do_open(struct hci_dev *hdev)
msft->features = 0;
if (!read_supported_features(hdev, msft)) {
+ hci_dev_lock(hdev);
hdev->msft_data = NULL;
kfree(msft);
+ hci_dev_unlock(hdev);
return;
}
@@ -681,6 +683,8 @@ void msft_do_close(struct hci_dev *hdev)
bt_dev_dbg(hdev, "Cleanup of MSFT extension");
+ hci_dev_lock(hdev);
+
/* The controller will silently remove all monitors on power off.
* Therefore, remove handle_data mapping and reset monitor state.
*/
@@ -695,6 +699,8 @@ void msft_do_close(struct hci_dev *hdev)
kfree(handle_data);
}
+ hci_dev_unlock(hdev);
+
mutex_lock(&msft->filter_lock);
list_for_each_entry_safe(address_filter, n, &msft->address_filters,
list) {
diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c
index 54ec1136f87e..8a4205347c4a 100644
--- a/net/bluetooth/rfcomm/core.c
+++ b/net/bluetooth/rfcomm/core.c
@@ -1740,10 +1740,8 @@ static int rfcomm_recv_msc(struct rfcomm_session *s, int cr, struct sk_buff *skb
return 0;
if (cr) {
- if (msc->v24_sig & RFCOMM_V24_FC && !d->cfc)
- set_bit(RFCOMM_TX_THROTTLED, &d->flags);
- else
- clear_bit(RFCOMM_TX_THROTTLED, &d->flags);
+ assign_bit(RFCOMM_TX_THROTTLED, &d->flags,
+ msc->v24_sig & RFCOMM_V24_FC && !d->cfc);
rfcomm_dlc_lock(d);
diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c
index b26918dc9e9e..3fb8b5474948 100644
--- a/net/bluetooth/rfcomm/sock.c
+++ b/net/bluetooth/rfcomm/sock.c
@@ -724,10 +724,7 @@ static int rfcomm_sock_setsockopt(struct socket *sock, int level, int optname,
if (err)
break;
- if (opt)
- set_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags);
- else
- clear_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags);
+ assign_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags, opt);
break;
diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c
index f4a20d7b5f9c..8be48ca9f4c5 100644
--- a/net/bluetooth/sco.c
+++ b/net/bluetooth/sco.c
@@ -1037,10 +1037,7 @@ static int sco_sock_setsockopt(struct socket *sock, int level, int optname,
if (err)
break;
- if (opt)
- set_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags);
- else
- clear_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags);
+ assign_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags, opt);
break;
case BT_VOICE:
@@ -1080,10 +1077,7 @@ static int sco_sock_setsockopt(struct socket *sock, int level, int optname,
if (err)
break;
- if (opt)
- set_bit(BT_SK_PKT_STATUS, &bt_sk(sk)->flags);
- else
- clear_bit(BT_SK_PKT_STATUS, &bt_sk(sk)->flags);
+ assign_bit(BT_SK_PKT_STATUS, &bt_sk(sk)->flags, opt);
break;
case BT_CODEC:
diff --git a/net/bluetooth/selftest.c b/net/bluetooth/selftest.c
index ae5b44bb9d3d..cdfc40e0016b 100644
--- a/net/bluetooth/selftest.c
+++ b/net/bluetooth/selftest.c
@@ -188,6 +188,7 @@ static ssize_t test_ecdh_read(struct file *file, char __user *user_buf,
}
static const struct file_operations test_ecdh_fops = {
+ .owner = THIS_MODULE,
.open = simple_open,
.read = test_ecdh_read,
.llseek = default_llseek,
diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c
index 2df303f6a38f..5dac8b2eae42 100644
--- a/net/bluetooth/smp.c
+++ b/net/bluetooth/smp.c
@@ -366,7 +366,7 @@ static int smp_e(const u8 *k, u8 *r)
err = aes_prepareenckey(&aes, tmp, 16);
if (err) {
BT_ERR("cipher setkey failed: %d", err);
- return err;
+ goto out_clear;
}
/* Most significant octet of plaintextData corresponds to data[0] */
@@ -379,6 +379,8 @@ static int smp_e(const u8 *k, u8 *r)
SMP_DBG("r %16phN", r);
+out_clear:
+ memzero_explicit(tmp, sizeof(tmp));
memzero_explicit(&aes, sizeof(aes));
return err;
}
@@ -3696,6 +3698,7 @@ static ssize_t test_smp_read(struct file *file, char __user *user_buf,
}
static const struct file_operations test_smp_fops = {
+ .owner = THIS_MODULE,
.open = simple_open,
.read = test_smp_read,
.llseek = default_llseek,