diff mbox series

[BlueZ,1/5] tools: add tests for RX timestamping

Message ID b4a9c82f09efddcff2e604546c33e3737d8955c5.1745750626.git.pav@iki.fi
State New
Headers show
Series [BlueZ,1/5] tools: add tests for RX timestamping | expand

Commit Message

Pauli Virtanen April 27, 2025, 10:44 a.m. UTC
Add tests:

ISO Receive - RX Timestamping
L2CAP BR/EDR Client - RX Timestamping
L2CAP BR/EDR Client - RX Timestamping 32k
L2CAP LE Client - RX Timestamping
L2CAP LE Client - RX Timestamping 32k
---
 tools/iso-tester.c   | 22 +++++++++++-
 tools/l2cap-tester.c | 60 ++++++++++++++++++++++++++++++++-
 tools/tester.h       | 80 ++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 160 insertions(+), 2 deletions(-)
diff mbox series

Patch

diff --git a/tools/iso-tester.c b/tools/iso-tester.c
index 63f6951e3..ff6418ce9 100644
--- a/tools/iso-tester.c
+++ b/tools/iso-tester.c
@@ -1118,6 +1118,15 @@  static const struct iso_client_data listen_16_2_1_recv_pkt_status = {
 	.pkt_status = 0x02,
 };
 
+static const struct iso_client_data listen_16_2_1_recv_rx_timestamping = {
+	.qos = QOS_16_2_1,
+	.expect_err = 0,
+	.recv = &send_16_2_1,
+	.server = true,
+	.so_timestamping = (SOF_TIMESTAMPING_SOFTWARE |
+					SOF_TIMESTAMPING_RX_SOFTWARE),
+};
+
 static const struct iso_client_data defer_16_2_1 = {
 	.qos = QOS_16_2_1,
 	.expect_err = 0,
@@ -2148,7 +2157,7 @@  static gboolean iso_recv_data(GIOChannel *io, GIOCondition cond,
 	struct test_data *data = user_data;
 	const struct iso_client_data *isodata = data->test_data;
 	int sk = g_io_channel_unix_get_fd(io);
-	unsigned char control[64];
+	unsigned char control[256];
 	ssize_t ret;
 	char buf[1024];
 	struct msghdr msg;
@@ -2202,6 +2211,9 @@  static gboolean iso_recv_data(GIOChannel *io, GIOCondition cond,
 		return FALSE;
 	}
 
+	if (isodata->so_timestamping & SOF_TIMESTAMPING_RX_SOFTWARE)
+		rx_timestamp_check(&msg);
+
 	if (memcmp(buf, isodata->recv->iov_base, ret))
 		tester_test_failed();
 	else
@@ -2224,6 +2236,10 @@  static void iso_recv(struct test_data *data, GIOChannel *io)
 		return;
 	}
 
+	if (rx_timestamping_init(g_io_channel_unix_get_fd(io),
+						isodata->so_timestamping))
+		return;
+
 	host = hciemu_client_get_host(data->hciemu);
 	bthost_send_iso(host, data->handle, isodata->ts, sn++, 0,
 				isodata->pkt_status, isodata->recv, 1);
@@ -3704,6 +3720,10 @@  int main(int argc, char *argv[])
 						&listen_16_2_1_recv_pkt_status,
 						setup_powered, test_listen);
 
+	test_iso("ISO Receive - RX Timestamping",
+					&listen_16_2_1_recv_rx_timestamping,
+					setup_powered, test_listen);
+
 	test_iso("ISO Defer - Success", &defer_16_2_1, setup_powered,
 							test_defer);
 
diff --git a/tools/l2cap-tester.c b/tools/l2cap-tester.c
index 41ef62578..9087d635d 100644
--- a/tools/l2cap-tester.c
+++ b/tools/l2cap-tester.c
@@ -357,6 +357,24 @@  static const struct l2cap_data client_connect_read_32k_success_test = {
 	.data_len = sizeof(l2_data_32k),
 };
 
+static const struct l2cap_data client_connect_rx_timestamping_test = {
+	.client_psm = 0x1001,
+	.server_psm = 0x1001,
+	.read_data = l2_data,
+	.data_len = sizeof(l2_data),
+	.so_timestamping = (SOF_TIMESTAMPING_SOFTWARE |
+					SOF_TIMESTAMPING_RX_SOFTWARE),
+};
+
+static const struct l2cap_data client_connect_rx_timestamping_32k_test = {
+	.client_psm = 0x1001,
+	.server_psm = 0x1001,
+	.read_data = l2_data_32k,
+	.data_len = sizeof(l2_data_32k),
+	.so_timestamping = (SOF_TIMESTAMPING_SOFTWARE |
+					SOF_TIMESTAMPING_RX_SOFTWARE),
+};
+
 static const struct l2cap_data client_connect_write_success_test = {
 	.client_psm = 0x1001,
 	.server_psm = 0x1001,
@@ -575,6 +593,27 @@  static const struct l2cap_data le_client_connect_read_32k_success_test = {
 	.data_len = sizeof(l2_data_32k),
 };
 
+static const struct l2cap_data le_client_connect_rx_timestamping_test = {
+	.client_psm = 0x0080,
+	.server_psm = 0x0080,
+	.read_data = l2_data,
+	.data_len = sizeof(l2_data),
+	.so_timestamping = (SOF_TIMESTAMPING_SOFTWARE |
+					SOF_TIMESTAMPING_RX_SOFTWARE),
+};
+
+static const struct l2cap_data le_client_connect_rx_timestamping_32k_test = {
+	.client_psm = 0x0080,
+	.server_psm = 0x0080,
+	.mtu = 672,
+	.mps = 251,
+	.credits = 147,
+	.read_data = l2_data_32k,
+	.data_len = sizeof(l2_data_32k),
+	.so_timestamping = (SOF_TIMESTAMPING_SOFTWARE |
+					SOF_TIMESTAMPING_RX_SOFTWARE),
+};
+
 static const struct l2cap_data le_client_connect_write_success_test = {
 	.client_psm = 0x0080,
 	.server_psm = 0x0080,
@@ -1227,13 +1266,14 @@  static gboolean sock_received_data(GIOChannel *io, GIOCondition cond,
 {
 	struct test_data *data = tester_get_data();
 	const struct l2cap_data *l2data = data->test_data;
+	bool tstamp = l2data->so_timestamping & SOF_TIMESTAMPING_RX_SOFTWARE;
 	char buf[1024];
 	int sk;
 	ssize_t len;
 
 	sk = g_io_channel_unix_get_fd(io);
 
-	len = read(sk, buf, sizeof(buf));
+	len = recv_tstamp(sk, buf, sizeof(buf), tstamp);
 	if (len < 0) {
 		tester_warn("Unable to read: %s (%d)", strerror(errno), errno);
 		tester_test_failed();
@@ -1430,6 +1470,10 @@  static void l2cap_read_data(struct test_data *data, GIOChannel *io,
 
 	data->step = 0;
 
+	if (rx_timestamping_init(g_io_channel_unix_get_fd(io),
+						l2data->so_timestamping))
+		return;
+
 	bthost = hciemu_client_get_host(data->hciemu);
 	g_io_add_watch(io, G_IO_IN, sock_received_data, NULL);
 
@@ -2535,6 +2579,14 @@  int main(int argc, char *argv[])
 					&client_connect_read_32k_success_test,
 					setup_powered_client, test_connect);
 
+	test_l2cap_bredr("L2CAP BR/EDR Client - RX Timestamping",
+					&client_connect_rx_timestamping_test,
+					setup_powered_client, test_connect);
+
+	test_l2cap_bredr("L2CAP BR/EDR Client - RX Timestamping 32k",
+				&client_connect_rx_timestamping_32k_test,
+				setup_powered_client, test_connect);
+
 	test_l2cap_bredr("L2CAP BR/EDR Client - Write Success",
 					&client_connect_write_success_test,
 					setup_powered_client, test_connect);
@@ -2619,6 +2671,12 @@  int main(int argc, char *argv[])
 	test_l2cap_le("L2CAP LE Client - Read 32k Success",
 				&le_client_connect_read_32k_success_test,
 				setup_powered_client, test_connect);
+	test_l2cap_le("L2CAP LE Client - RX Timestamping",
+				&le_client_connect_rx_timestamping_test,
+				setup_powered_client, test_connect);
+	test_l2cap_le("L2CAP LE Client - RX Timestamping 32k",
+				&le_client_connect_rx_timestamping_32k_test,
+				setup_powered_client, test_connect);
 	test_l2cap_le("L2CAP LE Client - Write Success",
 				&le_client_connect_write_success_test,
 				setup_powered_client, test_connect);
diff --git a/tools/tester.h b/tools/tester.h
index 4e7d7226b..bdfff356f 100644
--- a/tools/tester.h
+++ b/tools/tester.h
@@ -198,3 +198,83 @@  static inline int tx_tstamp_recv(struct tx_tstamp_data *data, int sk, int len)
 
 	return data->count - data->pos;
 }
+
+static inline int rx_timestamp_check(struct msghdr *msg)
+{
+	struct cmsghdr *cmsg;
+	struct timespec now;
+	int64_t t = 0;
+
+	for (cmsg = CMSG_FIRSTHDR(msg); cmsg; cmsg = CMSG_NXTHDR(msg, cmsg)) {
+		struct scm_timestamping *tss;
+
+		if (cmsg->cmsg_level != SOL_SOCKET)
+			continue;
+		if (cmsg->cmsg_type != SCM_TIMESTAMPING)
+			continue;
+
+		tss = (struct scm_timestamping *)CMSG_DATA(cmsg);
+		t = TS_NSEC(&tss->ts[0]);
+		break;
+	}
+	if (!cmsg) {
+		tester_warn("RX timestamp missing");
+		return -EINVAL;
+	}
+
+	clock_gettime(CLOCK_REALTIME, &now);
+
+	if (TS_NSEC(&now) < t || TS_NSEC(&now) > t + SEC_NSEC(10)) {
+		tester_warn("RX timestamp bad time");
+		return -EINVAL;
+	}
+
+	tester_print("Got valid RX timestamp");
+	return 0;
+}
+
+static inline ssize_t recv_tstamp(int sk, void *buf, size_t size, bool tstamp)
+{
+	union {
+		char buf[2 * CMSG_SPACE(sizeof(struct scm_timestamping))];
+		struct cmsghdr align;
+	} control;
+	struct iovec data = {
+		.iov_base = buf,
+		.iov_len = size
+	};
+	struct msghdr msg = {
+		.msg_iov = &data,
+		.msg_iovlen = 1,
+		.msg_control = control.buf,
+		.msg_controllen = sizeof(control.buf),
+	};
+	ssize_t ret;
+
+	ret = recvmsg(sk, &msg, 0);
+	if (ret < 0 || !tstamp)
+		return ret;
+
+	if (rx_timestamp_check(&msg)) {
+		errno = EIO;
+		return -1;
+	}
+
+	return ret;
+}
+
+static inline int rx_timestamping_init(int fd, int flags)
+{
+	socklen_t len = sizeof(flags);
+
+	if (!(flags & SOF_TIMESTAMPING_RX_SOFTWARE))
+		return 0;
+
+	if (setsockopt(fd, SOL_SOCKET, SO_TIMESTAMPING, &flags, len) < 0) {
+		tester_warn("failed to set SO_TIMESTAMPING");
+		tester_test_failed();
+		return -EIO;
+	}
+
+	return 0;
+}