* [PATCH BlueZ 1/2] tools/sco-tester: Add test closing the socket before the link is up
2026-10-08 21:57 [PATCH BlueZ 0/2] Test links completing after their connection was aborted Hitalo Souza
@ 2026-10-08 21:57 ` Hitalo Souza
2026-10-09 2:28 ` Test links completing after their connection was aborted bluez.test.bot
2026-10-08 21:57 ` [PATCH BlueZ 2/2] tools/l2cap-tester: Add tests closing the socket before the link is up Hitalo Souza
1 sibling, 1 reply; 4+ messages in thread
From: Hitalo Souza @ 2026-10-08 21:57 UTC (permalink / raw)
To: linux-bluetooth; +Cc: luiz.dentz, Hitalo Souza
Add a test that closes the socket while the emulator holds the
Synchronous Connection Complete event of its setup, so that the kernel
aborts the connection before the link comes up. No connection takes the
link then, so the test expects the kernel to disconnect it, as the
controller would otherwise keep it and reject further setups for the
device.
eSCO CVSD - Close Before Complete
Assisted-by: Claude:claude-opus-5-5
---
tools/sco-tester.c | 45 +++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 45 insertions(+)
diff --git a/tools/sco-tester.c b/tools/sco-tester.c
index fca99a9..2bc89b5 100644
--- a/tools/sco-tester.c
+++ b/tools/sco-tester.c
@@ -1309,6 +1309,48 @@ static void test_connect_acl_disc(const void *test_data)
test_connect(test_data);
}
+static bool hook_close_sync_conn(const void *msg, uint16_t len,
+ void *user_data)
+{
+ const struct bt_hci_evt_sync_conn_complete *evt = msg;
+ struct test_data *data = tester_get_data();
+
+ if (len < sizeof(*evt) || evt->status) {
+ tester_warn("Bad event");
+ tester_test_failed();
+ return true;
+ }
+
+ data->handle = le16_to_cpu(evt->handle);
+ tester_print("Closing socket before SCO Handle %u is up",
+ data->handle);
+
+ /* Abort the connection while its link is coming up, and let the
+ * kernel process it before the event is sent.
+ */
+ shutdown(data->sk, SHUT_RDWR);
+
+ return hook_delay_evt(msg, len, user_data);
+}
+
+static void test_connect_close_complete(const void *test_data)
+{
+ struct test_data *data = tester_get_data();
+
+ /* The link shall be disconnected, as no connection takes it */
+ data->step++;
+
+ hciemu_add_hook(data->hciemu, HCIEMU_HOOK_POST_EVT,
+ BT_HCI_EVT_SYNC_CONN_COMPLETE,
+ hook_close_sync_conn, NULL);
+
+ hciemu_add_hook(data->hciemu, HCIEMU_HOOK_POST_EVT,
+ BT_HCI_EVT_DISCONNECT_COMPLETE,
+ hook_disconnect_evt, NULL);
+
+ test_connect(test_data);
+}
+
static void test_sco_ethtool_get_ts_info(const void *test_data)
{
struct test_data *data = tester_get_data();
@@ -1512,6 +1554,9 @@ int main(int argc, char *argv[])
test_sco("eSCO CVSD - Close", &connect_close, setup_powered,
test_connect_delayed);
+ test_sco("eSCO CVSD - Close Before Complete", &connect_failure_reset,
+ setup_powered, test_connect_close_complete);
+
test_sco("eSCO mSBC - Success", &connect_success, setup_powered,
test_connect_transp);
--
2.55.0
^ permalink raw reply related [flat|nested] 4+ messages in thread* [PATCH BlueZ 2/2] tools/l2cap-tester: Add tests closing the socket before the link is up
2026-10-08 21:57 [PATCH BlueZ 0/2] Test links completing after their connection was aborted Hitalo Souza
2026-10-08 21:57 ` [PATCH BlueZ 1/2] tools/sco-tester: Add test closing the socket before the link is up Hitalo Souza
@ 2026-10-08 21:57 ` Hitalo Souza
1 sibling, 0 replies; 4+ messages in thread
From: Hitalo Souza @ 2026-10-08 21:57 UTC (permalink / raw)
To: linux-bluetooth; +Cc: luiz.dentz, Hitalo Souza
Add BR/EDR and LE client tests that close the socket while the emulator
holds the Connection Complete or LE Connection Complete event, so that
the kernel aborts the connection before the link comes up. No
connection takes the link then, so the tests expect the kernel to
disconnect it instead of leaving it up in the controller.
L2CAP BR/EDR Client - Close Before Complete
L2CAP LE Client - Close Before Complete
Assisted-by: Claude:claude-opus-5-5
---
tools/l2cap-tester.c | 107 +++++++++++++++++++++++++++++++++++++++++++
1 file changed, 107 insertions(+)
diff --git a/tools/l2cap-tester.c b/tools/l2cap-tester.c
index f2d3e56..41e6721 100644
--- a/tools/l2cap-tester.c
+++ b/tools/l2cap-tester.c
@@ -2571,6 +2571,105 @@ static void test_connect_timeout(const void *test_data)
g_io_channel_unref(io);
}
+static bool close_before_complete(uint8_t status, uint16_t handle)
+{
+ struct test_data *data = tester_get_data();
+
+ if (status || data->sk < 0) {
+ tester_warn("Unexpected connection complete");
+ tester_test_failed();
+ return true;
+ }
+
+ data->handle = handle;
+ tester_print("Closing socket before handle 0x%04x is up", handle);
+
+ /* Abort the connection while its link is coming up, and let the
+ * kernel process it before the event is sent.
+ */
+ close(data->sk);
+ data->sk = -1;
+ g_usleep(500000);
+
+ return true;
+}
+
+static bool hook_close_conn_complete(const void *msg, uint16_t len,
+ void *user_data)
+{
+ const struct bt_hci_evt_conn_complete *ev = msg;
+
+ if (len < sizeof(*ev))
+ return true;
+
+ return close_before_complete(ev->status, le16_to_cpu(ev->handle));
+}
+
+static bool hook_close_le_conn_complete(const void *msg, uint16_t len,
+ void *user_data)
+{
+ const uint8_t *subevent = msg;
+ const struct bt_hci_evt_le_conn_complete *ev = msg + 1;
+
+ if (len < 1 + sizeof(*ev) || *subevent != BT_HCI_EVT_LE_CONN_COMPLETE)
+ return true;
+
+ return close_before_complete(ev->status, le16_to_cpu(ev->handle));
+}
+
+static void close_complete_disconnect(uint16_t opcode, const void *param,
+ uint8_t len, void *user_data)
+{
+ const struct bt_hci_cmd_disconnect *cmd = param;
+ struct test_data *data = user_data;
+
+ if (opcode != BT_HCI_CMD_DISCONNECT || len < sizeof(*cmd))
+ return;
+
+ tester_print("Disconnect handle 0x%04x", le16_to_cpu(cmd->handle));
+
+ /* The link shall be disconnected, as no connection takes it */
+ if (le16_to_cpu(cmd->handle) == data->handle)
+ tester_test_passed();
+}
+
+static void test_connect_close_complete(const void *test_data)
+{
+ struct test_data *data = tester_get_data();
+ const struct l2cap_data *l2data = data->test_data;
+ int sk;
+
+ if (data->hciemu_type == HCIEMU_TYPE_LE)
+ hciemu_add_hook(data->hciemu, HCIEMU_HOOK_POST_EVT,
+ BT_HCI_EVT_LE_META_EVENT,
+ hook_close_le_conn_complete, NULL);
+ else
+ hciemu_add_hook(data->hciemu, HCIEMU_HOOK_POST_EVT,
+ BT_HCI_EVT_CONN_COMPLETE,
+ hook_close_conn_complete, NULL);
+
+ hciemu_add_central_post_command_hook(data->hciemu,
+ close_complete_disconnect, data);
+
+ sk = create_l2cap_sock(data, 0, l2data->cid, l2data->sec_level,
+ l2data->mode);
+ if (sk < 0) {
+ tester_test_failed();
+ return;
+ }
+
+ if (connect_l2cap_sock(data, sk, l2data->client_psm,
+ l2data->cid) < 0) {
+ close(sk);
+ tester_test_failed();
+ return;
+ }
+
+ data->sk = sk;
+
+ tester_print("Connect in progress");
+}
+
static void test_connect_reject(const void *test_data)
{
struct test_data *data = tester_get_data();
@@ -3526,6 +3625,10 @@ int main(int argc, char *argv[])
&client_connect_timeout_test,
setup_powered_client,
test_connect_timeout);
+ test_l2cap_bredr("L2CAP BR/EDR Client - Close Before Complete",
+ &client_connect_close_test,
+ setup_powered_client,
+ test_connect_close_complete);
test_l2cap_bredr("L2CAP BR/EDR Client SSP - Success 1",
&client_connect_ssp_success_test_1,
@@ -3689,6 +3792,10 @@ int main(int argc, char *argv[])
test_l2cap_le("L2CAP LE Client - Timeout",
&le_client_connect_timeout_test_1,
setup_powered_client, test_connect_timeout);
+ test_l2cap_le("L2CAP LE Client - Close Before Complete",
+ &le_client_connect_close_test_1,
+ setup_powered_client,
+ test_connect_close_complete);
test_l2cap_le("L2CAP LE Client - Read Success",
&le_client_connect_read_success_test,
setup_powered_client, test_connect);
--
2.55.0
^ permalink raw reply related [flat|nested] 4+ messages in thread