* [PATCH BlueZ 1/2] emulator: bthost: add function for sending raw L2CAP sig commands
@ 2026-08-30 17:11 Pauli Virtanen
2026-08-30 17:11 ` [PATCH BlueZ 2/2] tools/l2cap-server: add test for invalid Conn Req on Ext-Flowctl server Pauli Virtanen
2026-08-30 19:09 ` [BlueZ,1/2] emulator: bthost: add function for sending raw L2CAP sig commands bluez.test.bot
0 siblings, 2 replies; 3+ messages in thread
From: Pauli Virtanen @ 2026-08-30 17:11 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Pauli Virtanen
Add bthost_l2cap_sig_raw() that tests can use to send raw L2CAP
signaling commands.
---
emulator/bthost.c | 13 +++++++++++++
emulator/bthost.h | 4 ++++
2 files changed, 17 insertions(+)
diff --git a/emulator/bthost.c b/emulator/bthost.c
index 46c6a52f5..b3d48ffb3 100644
--- a/emulator/bthost.c
+++ b/emulator/bthost.c
@@ -811,6 +811,19 @@ static uint8_t l2cap_sig_send(struct bthost *bthost, struct btconn *conn,
return ident;
}
+uint8_t bthost_l2cap_sig_raw(struct bthost *bthost, uint16_t handle,
+ uint8_t code, uint8_t ident,
+ const void *data, uint16_t len)
+{
+ struct btconn *conn;
+
+ conn = bthost_find_conn(bthost, handle);
+ if (!conn)
+ return 0;
+
+ return l2cap_sig_send(bthost, conn, code, ident, data, len);
+}
+
void bthost_add_cid_hook(struct bthost *bthost, uint16_t handle, uint16_t cid,
bthost_cid_hook_func_t func, void *user_data)
{
diff --git a/emulator/bthost.h b/emulator/bthost.h
index e104e68af..ed924eb99 100644
--- a/emulator/bthost.h
+++ b/emulator/bthost.h
@@ -126,6 +126,10 @@ bool bthost_l2cap_req(struct bthost *bthost, uint16_t handle, uint8_t req,
const void *data, uint16_t len,
bthost_l2cap_rsp_cb cb, void *user_data);
+uint8_t bthost_l2cap_sig_raw(struct bthost *bthost, uint16_t handle,
+ uint8_t req, uint8_t ident,
+ const void *data, uint16_t len);
+
void bthost_write_scan_enable(struct bthost *bthost, uint8_t scan);
void bthost_set_adv_data(struct bthost *bthost, const uint8_t *data,
--
2.55.0
^ permalink raw reply related [flat|nested] 3+ messages in thread
* [PATCH BlueZ 2/2] tools/l2cap-server: add test for invalid Conn Req on Ext-Flowctl server
2026-08-30 17:11 [PATCH BlueZ 1/2] emulator: bthost: add function for sending raw L2CAP sig commands Pauli Virtanen
@ 2026-08-30 17:11 ` Pauli Virtanen
2026-08-30 19:09 ` [BlueZ,1/2] emulator: bthost: add function for sending raw L2CAP sig commands bluez.test.bot
1 sibling, 0 replies; 3+ messages in thread
From: Pauli Virtanen @ 2026-08-30 17:11 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Pauli Virtanen
Add test that checks Ext-Flowctl server handles invalid connection
requests with ident collisions. This triggers null-deref crash / hang on
some kernel versions.
L2CAP Ext-Flowctl Server - Nval Conn Req
---
tools/l2cap-tester.c | 169 ++++++++++++++++++++++++++++++++++++++++---
1 file changed, 160 insertions(+), 9 deletions(-)
diff --git a/tools/l2cap-tester.c b/tools/l2cap-tester.c
index 69c529aa8..efff5c2d8 100644
--- a/tools/l2cap-tester.c
+++ b/tools/l2cap-tester.c
@@ -30,6 +30,7 @@
#include "src/shared/tester.h"
#include "src/shared/mgmt.h"
+#include "src/shared/queue.h"
#include "src/shared/util.h"
#include "tester.h"
@@ -51,6 +52,7 @@ struct test_data {
int sk2;
bool host_disconnected;
int step;
+ struct queue *io_channels;
struct tx_tstamp_data tx_ts;
};
@@ -267,6 +269,11 @@ static void test_pre_setup(const void *test_data)
read_index_list_callback, NULL, NULL);
}
+static void io_channel_unref(void *data)
+{
+ g_io_channel_unref(data);
+}
+
static void test_post_teardown(const void *test_data)
{
struct test_data *data = tester_get_data();
@@ -281,6 +288,9 @@ static void test_post_teardown(const void *test_data)
data->err_io_id = 0;
}
+ queue_destroy(data->io_channels, io_channel_unref);
+ data->io_channels = NULL;
+
hciemu_unref(data->hciemu);
data->hciemu = NULL;
}
@@ -1137,6 +1147,12 @@ static const struct l2cap_data ext_flowctl_server_nval_scid_test = {
.expect_cmd_len = sizeof(nval_ecred_connect_rsp),
};
+static const struct l2cap_data ext_flowctl_server_nval_conn_req_test = {
+ .server_psm = 0x0080,
+ .defer = true,
+ .mode = BT_MODE_EXT_FLOWCTL,
+};
+
static const struct l2cap_data ext_flowctl_server_phy_test = {
.server_psm = 0x0080,
.send_cmd_code = BT_L2CAP_PDU_ECRED_CONN_REQ,
@@ -2897,6 +2913,8 @@ static gboolean l2cap_accept_cb(GIOChannel *io, GIOCondition cond,
const struct l2cap_data *l2data = data->test_data;
int sk, err;
+ data->io_id = 0;
+
sk = g_io_channel_unix_get_fd(io);
if (!check_mtu(data, sk)) {
@@ -2929,7 +2947,8 @@ static gboolean l2cap_accept_cb(GIOChannel *io, GIOCondition cond,
return FALSE;
}
-static bool defer_accept(struct test_data *data, GIOChannel *io)
+static bool defer_accept(struct test_data *data, GIOChannel *io,
+ GIOFunc accept_cb)
{
int sk;
char c;
@@ -2953,11 +2972,12 @@ static bool defer_accept(struct test_data *data, GIOChannel *io)
}
}
- data->io_id = g_io_add_watch(io, G_IO_OUT, l2cap_accept_cb, NULL);
+ if (accept_cb)
+ data->io_id = g_io_add_watch(io, G_IO_OUT, accept_cb, NULL);
g_io_channel_unref(io);
- tester_print("Accept deferred setup");
+ tester_print("Accept deferred setup sk = %d", sk);
return true;
}
@@ -2980,6 +3000,8 @@ static gboolean l2cap_listen_cb(GIOChannel *io, GIOCondition cond,
return FALSE;
}
+ tester_print("Accept sk = %d", new_sk);
+
io = g_io_channel_unix_new(new_sk);
g_io_channel_set_close_on_unref(io, TRUE);
@@ -2989,7 +3011,7 @@ static gboolean l2cap_listen_cb(GIOChannel *io, GIOCondition cond,
return FALSE;
}
- if (!defer_accept(data, io)) {
+ if (!defer_accept(data, io, l2cap_accept_cb)) {
tester_warn("Unable to accept deferred setup");
tester_test_failed();
}
@@ -3098,7 +3120,8 @@ static void send_req_new_conn(uint16_t handle, void *user_data)
}
}
-static void test_server(const void *test_data)
+static void start_test_server(const void *test_data, bthost_new_conn_cb conn_cb,
+ GIOFunc listen_cb)
{
struct test_data *data = tester_get_data();
const struct l2cap_data *l2data = data->test_data;
@@ -3128,7 +3151,7 @@ static void test_server(const void *test_data)
return;
}
- if (listen(sk, 5) < 0) {
+ if (listen(sk, 32) < 0) {
tester_warn("listening on socket failed: %s (%u)",
strerror(errno), errno);
tester_test_failed();
@@ -3139,8 +3162,7 @@ static void test_server(const void *test_data)
io = g_io_channel_unix_new(sk);
g_io_channel_set_close_on_unref(io, TRUE);
- data->io_id = g_io_add_watch(io, G_IO_IN, l2cap_listen_cb,
- NULL);
+ data->io_id = g_io_add_watch(io, G_IO_IN, listen_cb, NULL);
g_io_channel_unref(io);
tester_print("Listening for connections");
@@ -3154,7 +3176,7 @@ static void test_server(const void *test_data)
}
bthost = hciemu_client_get_host(data->hciemu);
- bthost_set_connect_cb(bthost, send_req_new_conn, data);
+ bthost_set_connect_cb(bthost, conn_cb, data);
if (data->hciemu_type == HCIEMU_TYPE_BREDR)
addr_type = BDADDR_BREDR;
@@ -3164,6 +3186,130 @@ static void test_server(const void *test_data)
bthost_hci_connect(bthost, central_bdaddr, addr_type);
}
+static void test_server(const void *test_data)
+{
+ start_test_server(test_data, send_req_new_conn, l2cap_listen_cb);
+}
+
+static gboolean ext_flowctl_nval_conn_req_ready_cb(gpointer ptr)
+{
+ struct test_data *data = tester_get_data();
+ const struct queue_entry *entry;
+ GIOFunc cb = l2cap_accept_cb;
+
+ if (data->io_id) {
+ g_source_remove(data->io_id);
+ data->io_id = 0;
+ }
+
+ data->err_io_id = 0;
+ data->step = 0;
+
+ tester_print("Accepting %d deferred", queue_length(data->io_channels));
+
+ entry = queue_get_entries(data->io_channels);
+ for (; entry; entry = entry->next) {
+ GIOChannel *io = entry->data;
+
+ if (!defer_accept(data, g_io_channel_ref(io), cb)) {
+ g_io_channel_unref(io);
+ tester_warn("Unable to accept deferred setup");
+ tester_test_failed();
+ break;
+ }
+
+ /* Require only the first to connect */
+ cb = NULL;
+ }
+
+ return FALSE;
+}
+
+static gboolean ext_flowctl_nval_conn_req_listen_cb(GIOChannel *io,
+ GIOCondition cond, gpointer user_data)
+{
+ struct test_data *data = tester_get_data();
+ int sk, new_sk;
+ GIOChannel *new_io;
+
+ if (!data->step)
+ return FALSE;
+
+ sk = g_io_channel_unix_get_fd(io);
+
+ new_sk = accept(sk, NULL, NULL);
+ if (new_sk < 0) {
+ tester_warn("accept failed: %s (%u)", strerror(errno), errno);
+ tester_test_failed();
+ return FALSE;
+ }
+
+ tester_print("Accept sk = %d", new_sk);
+
+ new_io = g_io_channel_unix_new(new_sk);
+ g_io_channel_set_close_on_unref(new_io, TRUE);
+
+ if (!data->io_channels)
+ data->io_channels = queue_new();
+ queue_push_tail(data->io_channels, new_io);
+
+ if (data->err_io_id) {
+ g_source_remove(data->err_io_id);
+ data->err_io_id = 0;
+ }
+
+ /* Accept all deferred connections at once, or until timeout */
+ data->step--;
+ if (!data->step) {
+ data->io_id = 0;
+ ext_flowctl_nval_conn_req_ready_cb(NULL);
+ return FALSE;
+ }
+
+ data->err_io_id = g_timeout_add(1000,
+ ext_flowctl_nval_conn_req_ready_cb, NULL);
+
+ return TRUE;
+}
+
+static void ext_flowctl_nval_conn_req_conn_cb(uint16_t handle, void *user_data)
+{
+ struct test_data *data = user_data;
+ struct bthost *bthost;
+ int i;
+
+ tester_print("New client connection with handle 0x%04x", handle);
+
+ bthost = hciemu_client_get_host(data->hciemu);
+
+ tester_print("Sending %d L2CAP_LE_CONN_REQ", data->step);
+
+ /* All L2CAP_LE_CONN_REQ (0x14) use the same PSM, same ident, different
+ * SCID. Receiver may reject some of these due to ident collision,
+ * but at least it should not hang/crash.
+ */
+ for (i = 0; i < data->step; ++i) {
+ uint8_t cmd[] = {
+ /* PSM(2), SCID(2), MTU(2), MPS(2), Crd(2) */
+ 0x80, 0x00, 0x40 + i, 0x00,
+ 0x40, 0x00, 0x40, 0x00,
+ 0x05, 0x00
+ };
+
+ bthost_l2cap_sig_raw(bthost, handle, 0x14, 0x9f,
+ cmd, ARRAY_SIZE(cmd));
+ }
+}
+
+static void test_ext_flowctl_server_nval_conn_req(const void *test_data)
+{
+ struct test_data *data = tester_get_data();
+
+ data->step = 32;
+ start_test_server(test_data, ext_flowctl_nval_conn_req_conn_cb,
+ ext_flowctl_nval_conn_req_listen_cb);
+}
+
static void test_getpeername_not_connected(const void *test_data)
{
struct test_data *data = tester_get_data();
@@ -3550,6 +3696,11 @@ int main(int argc, char *argv[])
&ext_flowctl_server_set_phy_coded_test,
setup_powered_server, test_server);
+ test_l2cap_le_52("L2CAP Ext-Flowctl Server - Nval Conn Req",
+ &ext_flowctl_server_nval_conn_req_test,
+ setup_powered_server,
+ test_ext_flowctl_server_nval_conn_req);
+
test_l2cap_le("L2CAP LE ATT Client - Success",
&le_att_client_connect_success_test_1,
setup_powered_client, test_connect);
--
2.55.0
^ permalink raw reply related [flat|nested] 3+ messages in thread
* RE: [BlueZ,1/2] emulator: bthost: add function for sending raw L2CAP sig commands
2026-08-30 17:11 [PATCH BlueZ 1/2] emulator: bthost: add function for sending raw L2CAP sig commands Pauli Virtanen
2026-08-30 17:11 ` [PATCH BlueZ 2/2] tools/l2cap-server: add test for invalid Conn Req on Ext-Flowctl server Pauli Virtanen
@ 2026-08-30 19:09 ` bluez.test.bot
1 sibling, 0 replies; 3+ messages in thread
From: bluez.test.bot @ 2026-08-30 19:09 UTC (permalink / raw)
To: linux-bluetooth, pav
[-- Attachment #1: Type: text/plain, Size: 1549 bytes --]
This is automated email and please do not reply to this email!
Dear submitter,
Thank you for submitting the patches to the linux bluetooth mailing list.
This is a CI test results with your patch series:
PW Link:https://patchwork.kernel.org/project/bluetooth/list/?series=1153956
---Test result---
Test Summary:
CheckPatch PASS 1.15 seconds
GitLint FAIL 0.68 seconds
BuildEll PASS 20.94 seconds
BluezMake PASS 614.58 seconds
CheckSmatch WARNING 323.01 seconds
bluezmakeextell PASS 103.32 seconds
IncrementalBuild PASS 616.45 seconds
ScanBuild PASS 979.11 seconds
Details
##############################
Test: GitLint - FAIL
Desc: Run gitlint
Output:
[BlueZ,2/2] tools/l2cap-server: add test for invalid Conn Req on Ext-Flowctl server
1: T1 Title exceeds max length (83>80): "[BlueZ,2/2] tools/l2cap-server: add test for invalid Conn Req on Ext-Flowctl server"
##############################
Test: CheckSmatch - WARNING
Desc: Run smatch tool with source
Output:
emulator/bthost.c:703:28: warning: Variable length array is used.emulator/bthost.c:704:32: warning: Variable length array is used.emulator/bthost.c:957:28: warning: Variable length array is used.emulator/bthost.c:991:28: warning: Variable length array is used.emulator/bthost.c:992:32: warning: Variable length array is used.
https://github.com/bluez/bluez/pull/2457
---
Regards,
Linux Bluetooth
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-08-30 19:09 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-30 17:11 [PATCH BlueZ 1/2] emulator: bthost: add function for sending raw L2CAP sig commands Pauli Virtanen
2026-08-30 17:11 ` [PATCH BlueZ 2/2] tools/l2cap-server: add test for invalid Conn Req on Ext-Flowctl server Pauli Virtanen
2026-08-30 19:09 ` [BlueZ,1/2] emulator: bthost: add function for sending raw L2CAP sig commands bluez.test.bot
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.