From: Kyle Pepper <cochcoder@proton.me>
To: linux-bluetooth@vger.kernel.org
Cc: luiz.dentz@gmail.com, marcel@holtmann.org
Subject: [RFC PATCH v4 1/2] Bluetooth: L2CAP: Keep credits from completing security upgrades
Date: Fri, 06 Nov 2026 02:17:30 +0000 [thread overview]
Message-ID: <20261106021723.631339-1-cochcoder@proton.me> (raw)
In-Reply-To: <20261015181624.48318-1-cochcoder@proton.me>
Validate credit targets and retain credits without sending or resuming
while an LE or ECRED security upgrade is pending. Keep the requested
security level until encryption and key size satisfy it.
Schedule immediate channel timeout work if the upgrade fails. This runs
the normal close path outside the security callback list traversal and
keeps traffic suspended until teardown. Complete deferred security
without accepting the connection or sending queued data.
Drain connected channels after successful security completion. Resume
LE credit-based sockets only when credits remain, including background
encryption changes with no locally pending upgrade.
Fixes: fad5fc89594d ("Bluetooth: Add LE flow control discipline")
Assisted-by: LLM
Signed-off-by: Kyle Pepper <cochcoder@proton.me>
---
v4: Fix failed/deferred security completion and credit-aware wakeups.
AI review: https://sashiko.dev/#/patchset/20261015181624.48318-1-cochcoder%40proton.me
net/bluetooth/l2cap_core.c | 50 ++++++++++++++++++++++++++++++++++++--
net/bluetooth/l2cap_sock.c | 9 +++++--
2 files changed, 55 insertions(+), 4 deletions(-)
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 7dcb0586a..9463ac215 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -5380,6 +5380,11 @@ static inline int l2cap_le_credits(struct l2cap_conn *conn,
l2cap_chan_lock(chan);
+ if (chan->state != BT_CONNECTED ||
+ (chan->mode != L2CAP_MODE_LE_FLOWCTL &&
+ chan->mode != L2CAP_MODE_EXT_FLOWCTL))
+ goto unlock;
+
max_credits = LE_FLOWCTL_MAX_CREDITS - chan->tx_credits;
if (credits > max_credits) {
BT_ERR("LE credits overflow");
@@ -5393,6 +5398,9 @@ static inline int l2cap_le_credits(struct l2cap_conn *conn,
chan->tx_credits += credits;
+ if (test_bit(FLAG_PENDING_SECURITY, &chan->flags))
+ goto unlock;
+
/* Resume sending */
l2cap_le_flowctl_send(chan);
@@ -7976,6 +7984,8 @@ static void l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
mutex_lock(&conn->lock);
list_for_each_entry(chan, &conn->chan_l, list) {
+ bool le_flowctl, pending_le;
+
l2cap_chan_lock(chan);
lockdep_assert_held(&chan->conn->lock);
@@ -7983,7 +7993,13 @@ static void l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
BT_DBG("chan %p scid 0x%4.4x state %s", chan, chan->scid,
state_to_string(chan->state));
- if (!status && encrypt)
+ le_flowctl = hcon->type == LE_LINK &&
+ (chan->mode == L2CAP_MODE_LE_FLOWCTL ||
+ chan->mode == L2CAP_MODE_EXT_FLOWCTL);
+ pending_le = le_flowctl &&
+ test_bit(FLAG_PENDING_SECURITY, &chan->flags);
+
+ if (!status && encrypt && !pending_le)
chan->sec_level = hcon->sec_level;
if (!__l2cap_no_conn_pending(chan)) {
@@ -7991,9 +8007,39 @@ static void l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
continue;
}
+ if (pending_le && (chan->state == BT_CONNECTED ||
+ chan->state == BT_CONFIG ||
+ chan->state == BT_CONNECT2)) {
+ if (status || !encrypt ||
+ !smp_sufficient_security(hcon, chan->sec_level,
+ SMP_ALLOW_STK) ||
+ !l2cap_check_enc_key_size(hcon, chan)) {
+ /* Keep traffic suspended until timeout work closes
+ * the channel outside this list traversal.
+ */
+ __set_chan_timer(chan, 0);
+ l2cap_chan_unlock(chan);
+ continue;
+ }
+
+ clear_bit(FLAG_PENDING_SECURITY, &chan->flags);
+ chan->sec_level = hcon->sec_level;
+
+ /* Security completion must not accept deferred setup. */
+ if (chan->state == BT_CONNECT2) {
+ if (chan->tx_credits)
+ chan->ops->resume(chan);
+ l2cap_chan_unlock(chan);
+ continue;
+ }
+
+ l2cap_le_flowctl_send(chan);
+ }
+
if (!status && (chan->state == BT_CONNECTED ||
chan->state == BT_CONFIG)) {
- chan->ops->resume(chan);
+ if (!le_flowctl || chan->tx_credits)
+ chan->ops->resume(chan);
l2cap_check_encryption(chan, encrypt);
l2cap_chan_unlock(chan);
continue;
diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c
index 7a2551ef7..2cf91d0a0 100644
--- a/net/bluetooth/l2cap_sock.c
+++ b/net/bluetooth/l2cap_sock.c
@@ -993,10 +993,15 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname,
} else if ((sk->sk_state == BT_CONNECT2 &&
test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags)) ||
sk->sk_state == BT_CONNECTED) {
- if (!l2cap_chan_check_security(chan, true))
+ if (!l2cap_chan_check_security(chan, true)) {
+ if (conn->hcon->type == LE_LINK &&
+ (chan->mode == L2CAP_MODE_LE_FLOWCTL ||
+ chan->mode == L2CAP_MODE_EXT_FLOWCTL))
+ set_bit(FLAG_PENDING_SECURITY, &chan->flags);
set_bit(BT_SK_SUSPEND, &bt_sk(sk)->flags);
- else
+ } else {
sk->sk_state_change(sk);
+ }
} else {
err = -EINVAL;
}
base-commit: a063a00e6cd9e354aa6d67a154a0527951d7f881
next prev parent reply other threads:[~2026-11-06 2:17 UTC|newest]
Thread overview: 25+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-13 3:19 [RFC PATCH] Bluetooth: L2CAP: tolerate zero-ident LE credit indications Kyle Pepper
2026-10-13 4:20 ` [RFC] " bluez.test.bot
2026-10-13 14:43 ` [RFC PATCH] " Luiz Augusto von Dentz
2026-10-15 18:31 ` cochcoder
2026-10-15 5:28 ` [RFC PATCH v2] " Kyle Pepper
2026-10-15 6:42 ` [RFC,v2] " bluez.test.bot
2026-10-15 18:16 ` [RFC PATCH v3 1/2] Bluetooth: L2CAP: Keep credits from completing security upgrades Kyle Pepper
2026-10-15 18:17 ` [RFC PATCH v3 2/2] Bluetooth: L2CAP: tolerate zero-ident LE credit indications Kyle Pepper
2026-10-15 20:17 ` [RFC,v3,1/2] Bluetooth: L2CAP: Keep credits from completing security upgrades bluez.test.bot
2026-10-31 18:09 ` [RFC PATCH v3 1/2] " cochcoder
2026-11-06 2:17 ` Kyle Pepper [this message]
2026-11-06 2:18 ` [RFC PATCH v4 2/2] Bluetooth: L2CAP: tolerate zero-ident LE credit indications Kyle Pepper
2026-11-06 3:17 ` [RFC,v4,1/2] Bluetooth: L2CAP: Keep credits from completing security upgrades bluez.test.bot
2026-11-06 4:55 ` [RFC PATCH v5 1/2] " Kyle Pepper
2026-11-06 4:56 ` [RFC PATCH v5 2/2] Bluetooth: L2CAP: tolerate zero-ident LE credit indications Kyle Pepper
2026-11-06 16:30 ` Luiz Augusto von Dentz
2026-11-06 10:40 ` [RFC,v5,1/2] Bluetooth: L2CAP: Keep credits from completing security upgrades bluez.test.bot
2026-11-06 17:40 ` [RFC PATCH v6 1/2] " Kyle Pepper
2026-11-06 17:40 ` [RFC PATCH v6 2/2] Bluetooth: L2CAP: tolerate zero-ident LE credit indications Kyle Pepper
2026-11-06 22:54 ` [RFC,v6,1/2] Bluetooth: L2CAP: Keep credits from completing security upgrades bluez.test.bot
2026-11-07 2:36 ` [RFC PATCH v7 1/2] " Kyle Pepper
2026-11-07 2:36 ` [RFC PATCH v7 2/2] Bluetooth: L2CAP: tolerate zero-ident LE credit indications Kyle Pepper
2026-11-07 7:16 ` [RFC PATCH v8 1/2] Bluetooth: L2CAP: Keep credits from completing security upgrades Kyle Pepper
2026-11-07 7:17 ` [RFC PATCH v8 2/2] Bluetooth: L2CAP: tolerate zero-ident LE credit indications Kyle Pepper
2026-11-07 8:32 ` [RFC,v8,1/2] Bluetooth: L2CAP: Keep credits from completing security upgrades bluez.test.bot
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261106021723.631339-1-cochcoder@proton.me \
--to=cochcoder@proton.me \
--cc=linux-bluetooth@vger.kernel.org \
--cc=luiz.dentz@gmail.com \
--cc=marcel@holtmann.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox