diff mbox series

[BlueZ] sco-tester: add test for disconnecting SCO

Message ID b3bf384b8e710156dd2a0f7ee2c21b98da9f4c79.1740684902.git.pav@iki.fi
State New
Headers show
Series [BlueZ] sco-tester: add test for disconnecting SCO | expand

Commit Message

Pauli Virtanen Feb. 27, 2025, 7:36 p.m. UTC
Add test that checks that shutdown(sk) results to
HCI_Disconnection_Complete for the SCO handle:

SCO Disconnect - Success
---

Notes:
    It seems after the following commit closing SCO connections no longer
    works, as kernel does not seem to be sending HCI Disconnect after the
    SCO socket is shutdown & closed:
    
    commit ed9588554943 ("Bluetooth: SCO: remove the redundant sco_conn_put")
    
    The test added here passes with that commit reverted.

 tools/sco-tester.c | 80 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 80 insertions(+)
diff mbox series

Patch

diff --git a/tools/sco-tester.c b/tools/sco-tester.c
index 6fc26b7af..7f37ca5cf 100644
--- a/tools/sco-tester.c
+++ b/tools/sco-tester.c
@@ -45,6 +45,7 @@  struct test_data {
 	bool disable_esco;
 	bool enable_codecs;
 	int step;
+	uint16_t handle;
 	struct tx_tstamp_data tx_ts;
 };
 
@@ -53,6 +54,9 @@  struct sco_client_data {
 	const uint8_t *send_data;
 	uint16_t data_len;
 
+	/* Shutdown socket after connect */
+	bool shutdown;
+
 	/* Enable SO_TIMESTAMPING with these flags */
 	uint32_t so_timestamping;
 
@@ -268,6 +272,11 @@  static const struct sco_client_data connect_success = {
 	.expect_err = 0
 };
 
+static const struct sco_client_data disconnect_success = {
+	.expect_err = 0,
+	.shutdown = true,
+};
+
 static const struct sco_client_data connect_failure = {
 	.expect_err = EOPNOTSUPP
 };
@@ -751,6 +760,11 @@  static gboolean sco_connect_cb(GIOChannel *io, GIOCondition cond,
 		}
 	}
 
+	if (scodata->shutdown) {
+		tester_print("Disconnecting...");
+		shutdown(sk, SHUT_RDWR);
+	}
+
 	if (-err != scodata->expect_err)
 		tester_test_failed();
 	else if (!data->step)
@@ -875,6 +889,69 @@  end:
 	close(sk);
 }
 
+static bool hook_setup_sync_evt(const void *buf, uint16_t len, void *user_data)
+{
+	struct test_data *data = tester_get_data();
+	const struct bt_hci_evt_sync_conn_complete *evt = buf;
+
+	if (len < sizeof(*evt)) {
+		tester_warn("Bad event size");
+		tester_test_failed();
+		return true;
+	}
+
+	data->handle = le16_to_cpu(evt->handle);
+	tester_print("SCO Handle %u", data->handle);
+	return true;
+}
+
+static bool hook_disconnect_evt(const void *buf, uint16_t len, void *user_data)
+{
+	struct test_data *data = tester_get_data();
+	const struct bt_hci_evt_disconnect_complete *evt = buf;
+	uint16_t handle;
+
+	if (len < sizeof(*evt)) {
+		tester_warn("Bad event size");
+		tester_test_failed();
+		return true;
+	}
+
+	handle = le16_to_cpu(evt->handle);
+	tester_print("Disconnected Handle %u", handle);
+
+	if (handle != data->handle)
+		return true;
+
+	if (evt->status) {
+		tester_test_failed();
+		return true;
+	}
+
+	data->step--;
+	if (!data->step)
+		tester_test_passed();
+
+	return true;
+}
+
+static void test_disconnect(const void *test_data)
+{
+	struct test_data *data = tester_get_data();
+
+	data->step++;
+
+	hciemu_add_hook(data->hciemu, HCIEMU_HOOK_POST_EVT,
+					BT_HCI_EVT_SYNC_CONN_COMPLETE,
+					hook_setup_sync_evt, NULL);
+
+	hciemu_add_hook(data->hciemu, HCIEMU_HOOK_POST_EVT,
+					BT_HCI_EVT_DISCONNECT_COMPLETE,
+					hook_disconnect_evt, NULL);
+
+	test_connect(test_data);
+}
+
 static bool hook_simult_disc(const void *msg, uint16_t len, void *user_data)
 {
 	const struct bt_hci_evt_sync_conn_complete *ev = msg;
@@ -972,6 +1049,9 @@  int main(int argc, char *argv[])
 	test_sco("eSCO mSBC - Success", &connect_success, setup_powered,
 							test_connect_transp);
 
+	test_sco("SCO Disconnect - Success", &disconnect_success, setup_powered,
+							test_disconnect);
+
 	test_sco("eSCO Simultaneous Disconnect - Failure",
 					&connect_failure_reset, setup_powered,
 					test_connect_simult_disc);