From: Kyle Pepper <cochcoder@proton.me>
To: linux-bluetooth@vger.kernel.org
Cc: luiz.dentz@gmail.com, marcel@holtmann.org
Subject: [RFC PATCH v6 1/2] Bluetooth: L2CAP: Keep credits from completing security upgrades
Date: Fri, 06 Nov 2026 17:40:05 +0000 [thread overview]
Message-ID: <20261106173948.596166-1-cochcoder@proton.me> (raw)
In-Reply-To: <20261106045515.853897-1-cochcoder@proton.me>
Retain LE and ECRED credits without sending queued data or resuming
connected sockets while a security upgrade is pending. Guard the shared
send path and deferred acceptance, and preserve the requested level
until completion or teardown.
Finish pending upgrades from connection work so failed channels and
ECRED batches can be removed outside the security callback's list walk.
Keep a failed upgrade terminal if another confirmation arrives before
the work runs. Report local SMP failure through the same work without
calling security callbacks while the SMP channel is locked.
Wake deferred sockets after successful security even with no initial
credits. Check every sibling's security before an ECRED batch response,
let refusal override pending acceptance, and retry the response after
security completes. Serialize BT_SECURITY with the batch response.
Wake failed senders, preserve disconnect errors through teardown, and
clear security and suspension state when removing the channel.
Assisted-by: LLM
Signed-off-by: Kyle Pepper <cochcoder@proton.me>
---
Changes in v6:
- Finish pending upgrades from referenced connection work.
- Keep failure terminal across later security confirmations.
- Report local SMP failure without taking channel-list locks from SMP.
- Wake deferred sockets even with zero initial credits.
- Wake failed senders and preserve errors through disconnect teardown.
- Clear pending-security and suspension state during teardown.
- Serialize BT_SECURITY with ECRED batch readiness and response handling.
- Let ECRED refusal override pending acceptance and retry after security.
AI review of v5:
https://sashiko.dev/#/patchset/20261106045515.853897-1-cochcoder%40proton.me
GCC/Clang ASan/UBSan fixtures cover the seven reported paths and successful
upgrades, with v5 baseline and isolated mutation controls. GCC/Clang and
ECRED-disabled W=1 objects and a KASAN/lockdep kernel image pass locally.
Native L2CAP/concurrency and hardware behavior remain unverified.
The userspace timeout sanitizer failure and the checker's handling of
required AI attribution remain separate CI infrastructure issues. A remote
CI pass is not claimed.
AI assistance: Codex prepared this revision, descriptions and local tests.
Attribution is retained.
include/net/bluetooth/l2cap.h | 5 ++
net/bluetooth/l2cap_core.c | 161 +++++++++++++++++++++++++++++++++-
net/bluetooth/l2cap_sock.c | 134 +++++++++++++++++-----------
net/bluetooth/smp.c | 1 +
4 files changed, 244 insertions(+), 57 deletions(-)
diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index 2a05bda8a..f09c2696f 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -636,6 +636,8 @@ struct l2cap_conn {
struct sk_buff_head pending_rx;
struct work_struct pending_rx_work;
+ struct work_struct security_work;
+ atomic_t security_failed;
struct delayed_work id_addr_timer;
@@ -758,6 +760,8 @@ enum {
FLAG_ECRED_CONN_REQ_SENT,
FLAG_ECRED_RECONF_REQ_SENT,
FLAG_PENDING_SECURITY,
+ FLAG_SECURITY_CFM,
+ FLAG_SECURITY_FAILED,
FLAG_HOLD_HCI_CONN,
FLAG_DEL,
};
@@ -983,6 +987,7 @@ int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len,
void l2cap_chan_busy(struct l2cap_chan *chan, int busy);
void l2cap_chan_rx_avail(struct l2cap_chan *chan, ssize_t rx_avail);
int l2cap_chan_check_security(struct l2cap_chan *chan, bool initiator);
+void l2cap_security_failed(struct l2cap_conn *conn);
void l2cap_chan_set_defaults(struct l2cap_chan *chan, struct l2cap_chan *pchan);
int l2cap_ertm_init(struct l2cap_chan *chan);
void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan);
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 7dcb0586a..24360d8e1 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -59,6 +59,7 @@ 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_security_work(struct work_struct *work);
static void __l2cap_chan_close(struct l2cap_chan *chan, int reason)
__must_hold(&chan->lock) __must_hold(&chan->conn->lock);
@@ -704,6 +705,9 @@ void l2cap_chan_del(struct l2cap_chan *chan, int err)
lockdep_assert(!chan->conn || lockdep_is_held(&chan->conn->lock));
__clear_chan_timer(chan);
+ clear_bit(FLAG_PENDING_SECURITY, &chan->flags);
+ clear_bit(FLAG_SECURITY_CFM, &chan->flags);
+ clear_bit(FLAG_SECURITY_FAILED, &chan->flags);
BT_DBG("chan %p, err %d, state %s", chan, err,
state_to_string(chan->state));
@@ -2647,6 +2651,9 @@ static void l2cap_le_flowctl_send(struct l2cap_chan *chan)
BT_DBG("chan %p", chan);
+ if (test_bit(FLAG_PENDING_SECURITY, &chan->flags))
+ return;
+
while (chan->tx_credits && !skb_queue_empty(&chan->tx_q)) {
l2cap_do_send(chan, skb_dequeue(&chan->tx_q));
chan->tx_credits--;
@@ -3979,8 +3986,13 @@ static void l2cap_ecred_list_defer(struct l2cap_chan *chan, void *data)
{
int *result = data;
- if (*result || test_bit(FLAG_ECRED_CONN_REQ_SENT, &chan->flags))
+ if (*result < 0 || test_bit(FLAG_ECRED_CONN_REQ_SENT, &chan->flags))
+ return;
+
+ if (test_bit(FLAG_SECURITY_FAILED, &chan->flags)) {
+ *result = -ECONNREFUSED;
return;
+ }
switch (chan->state) {
case BT_CONNECT2:
@@ -3988,6 +4000,8 @@ static void l2cap_ecred_list_defer(struct l2cap_chan *chan, void *data)
(*result)++;
return;
case BT_CONNECTED:
+ if (test_bit(FLAG_PENDING_SECURITY, &chan->flags))
+ (*result)++;
return;
default:
/* If not connected or pending accept it has been refused */
@@ -4079,7 +4093,9 @@ static void l2cap_ecred_rsp_defer(struct l2cap_chan *chan, void *data)
if (!rsp->pdu.rsp.result)
rsp_flex->dcid[rsp->count++] = cpu_to_le16(chan->scid);
else
- l2cap_chan_del(chan, ECONNRESET);
+ l2cap_chan_del(chan, rsp->pdu.rsp.result ==
+ cpu_to_le16(L2CAP_CR_LE_AUTHORIZATION) ?
+ ECONNREFUSED : ECONNRESET);
done:
if (locked)
@@ -5380,6 +5396,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 +5414,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);
@@ -7510,6 +7534,8 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon)
skb_queue_head_init(&conn->pending_rx);
INIT_WORK(&conn->pending_rx_work, process_pending_rx);
+ INIT_WORK(&conn->security_work, l2cap_security_work);
+ atomic_set(&conn->security_failed, 0);
INIT_DELAYED_WORK(&conn->id_addr_timer, l2cap_conn_update_id_addr);
conn->disc_reason = HCI_ERROR_REMOTE_USER_TERM;
@@ -7962,6 +7988,109 @@ static inline void l2cap_check_encryption(struct l2cap_chan *chan, u8 encrypt)
}
}
+static void l2cap_queue_security(struct l2cap_conn *conn)
+{
+ l2cap_conn_get(conn);
+ if (!queue_work(conn->hcon->hdev->workqueue, &conn->security_work))
+ l2cap_conn_put(conn);
+}
+
+void l2cap_security_failed(struct l2cap_conn *conn)
+{
+ if (conn->hcon->type != LE_LINK)
+ return;
+
+ atomic_set(&conn->security_failed, 1);
+ l2cap_queue_security(conn);
+}
+
+static void l2cap_security_work(struct work_struct *work)
+{
+ struct l2cap_conn *conn = container_of(work, struct l2cap_conn,
+ security_work);
+ struct hci_conn *hcon = conn->hcon;
+ struct l2cap_chan *chan, *next;
+
+ hci_dev_lock(hcon->hdev);
+ if (hcon->l2cap_data != conn)
+ goto done;
+
+ mutex_lock(&conn->lock);
+
+ if (atomic_xchg(&conn->security_failed, 0)) {
+ list_for_each_entry(chan, &conn->chan_l, list) {
+ l2cap_chan_lock(chan);
+ if ((chan->mode == L2CAP_MODE_LE_FLOWCTL ||
+ chan->mode == L2CAP_MODE_EXT_FLOWCTL) &&
+ test_bit(FLAG_PENDING_SECURITY, &chan->flags)) {
+ set_bit(FLAG_SECURITY_FAILED, &chan->flags);
+ set_bit(FLAG_SECURITY_CFM, &chan->flags);
+ }
+ l2cap_chan_unlock(chan);
+ }
+ }
+
+ for (;;) {
+ chan = NULL;
+ list_for_each_entry(next, &conn->chan_l, list) {
+ if (test_and_clear_bit(FLAG_SECURITY_CFM, &next->flags)) {
+ chan = next;
+ break;
+ }
+ }
+ if (!chan)
+ break;
+
+ /* Batch rejection may delete siblings, so restart the walk. */
+ l2cap_chan_hold(chan);
+ l2cap_chan_lock(chan);
+ lockdep_assert_held(&chan->conn->lock);
+ if (!test_bit(FLAG_PENDING_SECURITY, &chan->flags) ||
+ (chan->state != BT_CONNECTED && chan->state != BT_CONFIG &&
+ chan->state != BT_CONNECT2))
+ goto next;
+
+ if (test_bit(FLAG_SECURITY_FAILED, &chan->flags) ||
+ !test_bit(HCI_CONN_ENCRYPT, hcon->flags) ||
+ !smp_sufficient_security(hcon, chan->sec_level, SMP_ALLOW_STK) ||
+ !l2cap_check_enc_key_size(hcon, chan)) {
+ set_bit(FLAG_SECURITY_FAILED, &chan->flags);
+ __l2cap_chan_close(chan, ECONNREFUSED);
+ chan->ops->close(chan);
+ goto next;
+ }
+
+ clear_bit(FLAG_PENDING_SECURITY, &chan->flags);
+ chan->sec_level = hcon->sec_level;
+
+ if (chan->state == BT_CONNECT2) {
+ chan->ops->resume(chan);
+ goto next;
+ }
+
+ if (chan->state == BT_CONNECTED &&
+ chan->mode == L2CAP_MODE_EXT_FLOWCTL &&
+ test_bit(FLAG_DEFER_SETUP, &chan->flags)) {
+ __l2cap_ecred_conn_rsp_defer(chan);
+ if (test_bit(FLAG_DEL, &chan->flags))
+ goto next;
+ }
+
+ l2cap_le_flowctl_send(chan);
+ if (chan->tx_credits)
+ chan->ops->resume(chan);
+ l2cap_check_encryption(chan, 1);
+next:
+ l2cap_chan_unlock(chan);
+ l2cap_chan_put(chan);
+ }
+
+ mutex_unlock(&conn->lock);
+done:
+ hci_dev_unlock(hcon->hdev);
+ l2cap_conn_put(conn);
+}
+
static void l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
__must_hold(&hcon->hdev->lock)
{
@@ -7976,6 +8105,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 +8114,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 +8128,25 @@ 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)) {
+ set_bit(FLAG_SECURITY_FAILED, &chan->flags);
+ }
+ set_bit(FLAG_SECURITY_CFM, &chan->flags);
+ l2cap_queue_security(conn);
+ l2cap_chan_unlock(chan);
+ continue;
+ }
+
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..3f4ab80b3 100644
--- a/net/bluetooth/l2cap_sock.c
+++ b/net/bluetooth/l2cap_sock.c
@@ -927,12 +927,70 @@ static int l2cap_set_mode(struct l2cap_chan *chan, u8 mode)
return 0;
}
+static int l2cap_sock_set_security(struct sock *sk, struct l2cap_chan *chan,
+ sockptr_t optval, unsigned int optlen)
+ __must_hold(&chan->lock)
+{
+ struct l2cap_conn *conn;
+ struct bt_security sec = { .level = BT_SECURITY_LOW };
+ int err;
+
+ if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED &&
+ chan->chan_type != L2CAP_CHAN_FIXED &&
+ chan->chan_type != L2CAP_CHAN_RAW)
+ return -EINVAL;
+
+ err = copy_safe_from_sockptr(&sec, sizeof(sec), optval, optlen);
+ if (err)
+ return err;
+
+ if (sec.level < BT_SECURITY_LOW || sec.level > BT_SECURITY_FIPS)
+ return -EINVAL;
+
+ conn = l2cap_chan_conn(chan);
+ if ((chan->mode == L2CAP_MODE_LE_FLOWCTL ||
+ chan->mode == L2CAP_MODE_EXT_FLOWCTL) &&
+ (test_bit(FLAG_PENDING_SECURITY, &chan->flags) ||
+ (conn && atomic_read(&conn->security_failed))))
+ return -EBUSY;
+
+ chan->sec_level = sec.level;
+ if (!conn)
+ return 0;
+
+ lockdep_assert_held(&conn->lock);
+
+ if (chan->scid == L2CAP_CID_ATT) {
+ if (smp_conn_security(conn->hcon, sec.level))
+ return -EINVAL;
+
+ set_bit(FLAG_PENDING_SECURITY, &chan->flags);
+ sk->sk_state = BT_CONFIG;
+ chan->state = BT_CONFIG;
+ } 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 (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 {
+ sk->sk_state_change(sk);
+ }
+ } else {
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname,
sockptr_t optval, unsigned int optlen)
{
struct sock *sk = sock->sk;
struct l2cap_chan *chan = l2cap_pi(sk)->chan;
- struct bt_security sec;
struct bt_power pwr;
struct l2cap_conn *conn;
int err = 0;
@@ -948,60 +1006,20 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname,
if (level != SOL_BLUETOOTH)
return -ENOPROTOOPT;
+ if (optname == BT_SECURITY) {
+ bool have_conn = l2cap_chan_lock_conn(chan);
+
+ lock_sock(sk);
+ err = l2cap_sock_set_security(sk, chan, optval, optlen);
+ release_sock(sk);
+ l2cap_chan_unlock_conn(chan, have_conn);
+ return err;
+ }
+
l2cap_chan_lock(chan);
lock_sock(sk);
switch (optname) {
- case BT_SECURITY:
- if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED &&
- chan->chan_type != L2CAP_CHAN_FIXED &&
- chan->chan_type != L2CAP_CHAN_RAW) {
- err = -EINVAL;
- break;
- }
-
- sec.level = BT_SECURITY_LOW;
-
- err = copy_safe_from_sockptr(&sec, sizeof(sec), optval, optlen);
- if (err)
- break;
-
- if (sec.level < BT_SECURITY_LOW ||
- sec.level > BT_SECURITY_FIPS) {
- err = -EINVAL;
- break;
- }
-
- chan->sec_level = sec.level;
-
- conn = l2cap_chan_conn(chan);
- if (!conn)
- break;
-
- /* change security for LE channels */
- if (chan->scid == L2CAP_CID_ATT) {
- if (smp_conn_security(conn->hcon, sec.level)) {
- err = -EINVAL;
- break;
- }
-
- set_bit(FLAG_PENDING_SECURITY, &chan->flags);
- sk->sk_state = BT_CONFIG;
- chan->state = BT_CONFIG;
-
- /* or for ACL link */
- } 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))
- set_bit(BT_SK_SUSPEND, &bt_sk(sk)->flags);
- else
- sk->sk_state_change(sk);
- } else {
- err = -EINVAL;
- }
- break;
-
case BT_DEFER_SETUP:
if (sk->sk_state != BT_BOUND && sk->sk_state != BT_LISTEN) {
err = -EINVAL;
@@ -1263,6 +1281,11 @@ static int l2cap_sock_defer(struct sock *sk)
if (!have_conn) {
release_sock(sk);
err = -ENOTCONN;
+ } else if ((chan->mode == L2CAP_MODE_LE_FLOWCTL ||
+ chan->mode == L2CAP_MODE_EXT_FLOWCTL) &&
+ test_bit(FLAG_PENDING_SECURITY, &chan->flags)) {
+ release_sock(sk);
+ err = -EAGAIN;
} else if (chan->mode == L2CAP_MODE_EXT_FLOWCTL) {
sk->sk_state = BT_CONNECTED;
chan->state = BT_CONNECTED;
@@ -1736,6 +1759,7 @@ static void l2cap_sock_teardown_cb(struct l2cap_chan *chan, int err)
lock_sock_nested(sk, atomic_read(&chan->nesting));
parent = bt_sk(sk)->parent;
+ clear_bit(BT_SK_SUSPEND, &bt_sk(sk)->flags);
switch (chan->state) {
case BT_OPEN:
@@ -1752,7 +1776,8 @@ static void l2cap_sock_teardown_cb(struct l2cap_chan *chan, int err)
sk->sk_state = BT_CLOSED;
chan->state = BT_CLOSED;
- sk->sk_err = err;
+ if (err)
+ sk->sk_err = err;
if (parent) {
/*
@@ -1788,8 +1813,11 @@ static void l2cap_sock_state_change_cb(struct l2cap_chan *chan, int state,
sk->sk_state = state;
- if (err)
+ if (err) {
sk->sk_err = err;
+ clear_bit(BT_SK_SUSPEND, &bt_sk(sk)->flags);
+ sk->sk_state_change(sk);
+ }
release_sock(sk);
}
diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c
index b7015e37e..b4b761788 100644
--- a/net/bluetooth/smp.c
+++ b/net/bluetooth/smp.c
@@ -785,6 +785,7 @@ static void smp_failure(struct l2cap_conn *conn, u8 reason)
&reason);
mgmt_auth_failed(hcon, HCI_ERROR_AUTH_FAILURE);
+ l2cap_security_failed(conn);
if (chan->data)
smp_chan_destroy(conn);
base-commit: a063a00e6cd9e354aa6d67a154a0527951d7f881
next prev parent reply other threads:[~2026-11-06 17:40 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 ` [RFC PATCH v4 " Kyle Pepper
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 ` Kyle Pepper [this message]
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=20261106173948.596166-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