@@ -30,6 +30,9 @@
#include "src/shared/tester.h"
#include "src/shared/mgmt.h"
+#include "src/shared/util.h"
+
+#include "tester.h"
struct test_data {
const void *test_data;
@@ -38,12 +41,15 @@ struct test_data {
struct hciemu *hciemu;
enum hciemu_type hciemu_type;
unsigned int io_id;
+ unsigned int err_io_id;
uint16_t handle;
uint16_t scid;
uint16_t dcid;
int sk;
int sk2;
bool host_disconnected;
+ int step;
+ struct tx_tstamp_data tx_ts;
};
struct l2cap_data {
@@ -86,6 +92,12 @@ struct l2cap_data {
bool defer;
bool shut_sock_wr;
+
+ /* Enable SO_TIMESTAMPING with these flags */
+ uint32_t so_timestamping;
+
+ /* Number of additional packets to send. */
+ unsigned int repeat_send;
};
static void print_debug(const char *str, void *user_data)
@@ -226,6 +238,11 @@ static void test_post_teardown(const void *test_data)
data->io_id = 0;
}
+ if (data->err_io_id > 0) {
+ g_source_remove(data->err_io_id);
+ data->err_io_id = 0;
+ }
+
hciemu_unref(data->hciemu);
data->hciemu = NULL;
}
@@ -245,6 +262,7 @@ static void test_data_free(void *test_data)
break; \
user->hciemu_type = HCIEMU_TYPE_BREDR; \
user->io_id = 0; \
+ user->err_io_id = 0; \
user->test_data = data; \
tester_add_full(name, data, \
test_pre_setup, setup, func, NULL, \
@@ -259,6 +277,7 @@ static void test_data_free(void *test_data)
break; \
user->hciemu_type = HCIEMU_TYPE_LE; \
user->io_id = 0; \
+ user->err_io_id = 0; \
user->test_data = data; \
tester_add_full(name, data, \
test_pre_setup, setup, func, NULL, \
@@ -321,6 +340,17 @@ static const struct l2cap_data client_connect_write_success_test = {
.data_len = sizeof(l2_data),
};
+static const struct l2cap_data client_connect_tx_timestamping_test = {
+ .client_psm = 0x1001,
+ .server_psm = 0x1001,
+ .write_data = l2_data,
+ .data_len = sizeof(l2_data),
+ .so_timestamping = (SOF_TIMESTAMPING_SOFTWARE |
+ SOF_TIMESTAMPING_OPT_ID |
+ SOF_TIMESTAMPING_TX_SOFTWARE),
+ .repeat_send = 2,
+};
+
static const struct l2cap_data client_connect_shut_wr_success_test = {
.client_psm = 0x1001,
.server_psm = 0x1001,
@@ -1096,6 +1126,8 @@ static void bthost_received_data(const void *buf, uint16_t len,
struct test_data *data = tester_get_data();
const struct l2cap_data *l2data = data->test_data;
+ --data->step;
+
if (len != l2data->data_len) {
tester_test_failed();
return;
@@ -1103,7 +1135,7 @@ static void bthost_received_data(const void *buf, uint16_t len,
if (memcmp(buf, l2data->write_data, l2data->data_len))
tester_test_failed();
- else
+ else if (!data->step)
tester_test_passed();
}
@@ -1207,6 +1239,59 @@ static bool check_mtu(struct test_data *data, int sk)
return true;
}
+static gboolean recv_errqueue(GIOChannel *io, GIOCondition cond,
+ gpointer user_data)
+{
+ struct test_data *data = user_data;
+ const struct l2cap_data *l2data = data->test_data;
+ int sk = g_io_channel_unix_get_fd(io);
+ int err;
+
+ data->step--;
+
+ err = tx_tstamp_recv(&data->tx_ts, sk, l2data->data_len);
+ if (err > 0)
+ return TRUE;
+ else if (!err && !data->step)
+ tester_test_passed();
+ else
+ tester_test_failed();
+
+ data->err_io_id = 0;
+ return FALSE;
+}
+
+static void l2cap_tx_timestamping(struct test_data *data, GIOChannel *io)
+{
+ const struct l2cap_data *l2data = data->test_data;
+ int so = l2data->so_timestamping;
+ int sk;
+ int err;
+ unsigned int count;
+
+ if (!(l2data->so_timestamping & SOF_TIMESTAMPING_TX_RECORD_MASK))
+ return;
+
+ sk = g_io_channel_unix_get_fd(io);
+
+ tester_print("Enabling TX timestamping");
+
+ tx_tstamp_init(&data->tx_ts, l2data->so_timestamping);
+
+ for (count = 0; count < l2data->repeat_send + 1; ++count)
+ data->step += tx_tstamp_expect(&data->tx_ts);
+
+ err = setsockopt(sk, SOL_SOCKET, SO_TIMESTAMPING, &so, sizeof(so));
+ if (err < 0) {
+ tester_warn("setsockopt SO_TIMESTAMPING: %s (%d)",
+ strerror(errno), errno);
+ tester_test_failed();
+ return;
+ }
+
+ data->err_io_id = g_io_add_watch(io, G_IO_ERR, recv_errqueue, data);
+}
+
static gboolean l2cap_connect_cb(GIOChannel *io, GIOCondition cond,
gpointer user_data)
{
@@ -1249,15 +1334,23 @@ static gboolean l2cap_connect_cb(GIOChannel *io, GIOCondition cond,
} else if (l2data->write_data) {
struct bthost *bthost;
ssize_t ret;
+ unsigned int count;
+
+ data->step = 0;
bthost = hciemu_client_get_host(data->hciemu);
bthost_add_cid_hook(bthost, data->handle, data->dcid,
bthost_received_data, NULL);
- ret = write(sk, l2data->write_data, l2data->data_len);
- if (ret != l2data->data_len) {
- tester_warn("Unable to write all data");
- tester_test_failed();
+ l2cap_tx_timestamping(data, io);
+
+ for (count = 0; count < l2data->repeat_send + 1; ++count) {
+ ret = write(sk, l2data->write_data, l2data->data_len);
+ if (ret != l2data->data_len) {
+ tester_warn("Unable to write all data");
+ tester_test_failed();
+ }
+ ++data->step;
}
return FALSE;
@@ -2280,6 +2373,10 @@ int main(int argc, char *argv[])
&client_connect_write_success_test,
setup_powered_client, test_connect);
+ test_l2cap_bredr("L2CAP BR/EDR Client - TX Timestamping",
+ &client_connect_tx_timestamping_test,
+ setup_powered_client, test_connect);
+
test_l2cap_bredr("L2CAP BR/EDR Client - Invalid PSM 1",
&client_connect_nval_psm_test_1,
setup_powered_client, test_connect);