@@ -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);
@@ -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);
@@ -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;
+}