From: Luiz Augusto von Dentz <luiz.von.dentz@xxxxxxxxx> This adds the following tests which cover the TX/RX of multiple packets (up to 32K): L2CAP BR/EDR Client - Read 32k Success L2CAP BR/EDR Client - Write 32k Success L2CAP BR/EDR Server - Read 32k Success L2CAP BR/EDR Server - Write 32k Success --- tools/l2cap-tester.c | 294 ++++++++++++++++++++++++++----------------- 1 file changed, 180 insertions(+), 114 deletions(-) diff --git a/tools/l2cap-tester.c b/tools/l2cap-tester.c index c34080654ed6..b6b879407115 100644 --- a/tools/l2cap-tester.c +++ b/tools/l2cap-tester.c @@ -45,6 +45,7 @@ struct test_data { uint16_t handle; uint16_t scid; uint16_t dcid; + struct l2cap_options l2o; int sk; int sk2; bool host_disconnected; @@ -332,6 +333,16 @@ static const struct l2cap_data client_connect_pin_success_test = { static uint8_t l2_data[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 }; +const uint8_t l2_data_32k[32768] = { [0 ... 4095] = 0x00, + [4096 ... 8191] = 0x01, + [8192 ... 12287] = 0x02, + [12288 ... 16383] = 0x03, + [16384 ... 20479] = 0x04, + [20480 ... 24575] = 0x05, + [24576 ... 28671] = 0x06, + [28672 ... 32767] = 0x07, +}; + static const struct l2cap_data client_connect_read_success_test = { .client_psm = 0x1001, .server_psm = 0x1001, @@ -339,6 +350,13 @@ static const struct l2cap_data client_connect_read_success_test = { .data_len = sizeof(l2_data), }; +static const struct l2cap_data client_connect_read_32k_success_test = { + .client_psm = 0x1001, + .server_psm = 0x1001, + .read_data = l2_data_32k, + .data_len = sizeof(l2_data_32k), +}; + static const struct l2cap_data client_connect_write_success_test = { .client_psm = 0x1001, .server_psm = 0x1001, @@ -346,6 +364,13 @@ static const struct l2cap_data client_connect_write_success_test = { .data_len = sizeof(l2_data), }; +static const struct l2cap_data client_connect_write_32k_success_test = { + .client_psm = 0x1001, + .server_psm = 0x1001, + .write_data = l2_data_32k, + .data_len = sizeof(l2_data_32k), +}; + static const struct l2cap_data client_connect_tx_timestamping_test = { .client_psm = 0x1001, .server_psm = 0x1001, @@ -399,6 +424,16 @@ static const struct l2cap_data l2cap_server_read_success_test = { .data_len = sizeof(l2_data), }; +static const struct l2cap_data l2cap_server_read_32k_success_test = { + .server_psm = 0x1001, + .send_cmd_code = BT_L2CAP_PDU_CONN_REQ, + .send_cmd = l2cap_connect_req, + .send_cmd_len = sizeof(l2cap_connect_req), + .expect_cmd_code = BT_L2CAP_PDU_CONN_RSP, + .read_data = l2_data_32k, + .data_len = sizeof(l2_data_32k), +}; + static const struct l2cap_data l2cap_server_write_success_test = { .server_psm = 0x1001, .send_cmd_code = BT_L2CAP_PDU_CONN_REQ, @@ -409,6 +444,16 @@ static const struct l2cap_data l2cap_server_write_success_test = { .data_len = sizeof(l2_data), }; +static const struct l2cap_data l2cap_server_write_32k_success_test = { + .server_psm = 0x1001, + .send_cmd_code = BT_L2CAP_PDU_CONN_REQ, + .send_cmd = l2cap_connect_req, + .send_cmd_len = sizeof(l2cap_connect_req), + .expect_cmd_code = BT_L2CAP_PDU_CONN_RSP, + .write_data = l2_data_32k, + .data_len = sizeof(l2_data_32k), +}; + static const uint8_t l2cap_sec_block_rsp[] = { 0x00, 0x00, /* dcid */ 0x41, 0x00, /* scid */ 0x03, 0x00, /* Sec Block */ @@ -1104,50 +1149,54 @@ static void test_basic(const void *test_data) tester_test_passed(); } -static gboolean client_received_data(GIOChannel *io, GIOCondition cond, - gpointer user_data) +static void received_data(struct test_data *tdata, const void *buf, + uint16_t len, const void *data, + uint16_t data_len) { - struct test_data *data = tester_get_data(); - const struct l2cap_data *l2data = data->test_data; - char buf[1024]; - int sk; + static struct iovec iov; - tester_debug("Client received data"); + util_iov_append(&iov, buf, len); - sk = g_io_channel_unix_get_fd(io); - if (read(sk, buf, l2data->data_len) != l2data->data_len) { - tester_warn("Unable to read %u bytes", l2data->data_len); + tester_debug("read: %d/%zu", len, iov.iov_len); + + /* Check if all the data has been received */ + if (iov.iov_len < data_len) + return; + + --tdata->step; + + if (iov.iov_len != data_len || memcmp(iov.iov_base, data, data_len)) tester_test_failed(); - return FALSE; - } - - if (memcmp(buf, l2data->read_data, l2data->data_len)) - tester_test_failed(); - else + else if (!tdata->step) tester_test_passed(); - return FALSE; + free(iov.iov_base); + iov.iov_base = NULL; + iov.iov_len = 0; } -static gboolean server_received_data(GIOChannel *io, GIOCondition cond, +static gboolean sock_received_data(GIOChannel *io, GIOCondition cond, gpointer user_data) { struct test_data *data = tester_get_data(); const struct l2cap_data *l2data = data->test_data; char buf[1024]; int sk; + ssize_t len; sk = g_io_channel_unix_get_fd(io); - if (read(sk, buf, l2data->data_len) != l2data->data_len) { - tester_warn("Unable to read %u bytes", l2data->data_len); + + len = read(sk, buf, sizeof(buf)); + if (len < 0) { + tester_warn("Unable to read: %s (%d)", strerror(errno), errno); tester_test_failed(); return FALSE; } - if (memcmp(buf, l2data->read_data, l2data->data_len)) - tester_test_failed(); - else - tester_test_passed(); + received_data(data, buf, len, l2data->read_data, l2data->data_len); + + if (data->step) + return TRUE; return FALSE; } @@ -1158,36 +1207,7 @@ 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; - tester_debug("BTHost received data: %u bytes", len); - - --data->step; - - if (len != l2data->data_len) { - tester_test_failed(); - return; - } - - if (memcmp(buf, l2data->write_data, l2data->data_len)) - tester_test_failed(); - else if (!data->step) - tester_test_passed(); -} - -static void server_bthost_received_data(const void *buf, uint16_t len, - void *user_data) -{ - struct test_data *data = tester_get_data(); - const struct l2cap_data *l2data = data->test_data; - - if (len != l2data->data_len) { - tester_test_failed(); - return; - } - - if (memcmp(buf, l2data->write_data, l2data->data_len)) - tester_test_failed(); - else - tester_test_passed(); + received_data(data, buf, len, l2data->write_data, l2data->data_len); } static gboolean socket_closed_cb(GIOChannel *io, GIOCondition cond, @@ -1234,27 +1254,26 @@ static gboolean socket_closed_cb(GIOChannel *io, GIOCondition cond, static bool check_mtu(struct test_data *data, int sk) { const struct l2cap_data *l2data = data->test_data; - struct l2cap_options l2o; socklen_t len; - memset(&l2o, 0, sizeof(l2o)); + memset(&data->l2o, 0, sizeof(data->l2o)); if (data->hciemu_type == HCIEMU_TYPE_LE && (l2data->client_psm || l2data->server_psm)) { /* LE CoC enabled kernels should support BT_RCVMTU and * BT_SNDMTU. */ - len = sizeof(l2o.imtu); + len = sizeof(data->l2o.imtu); if (getsockopt(sk, SOL_BLUETOOTH, BT_RCVMTU, - &l2o.imtu, &len) < 0) { + &data->l2o.imtu, &len) < 0) { tester_warn("getsockopt(BT_RCVMTU): %s (%d)", strerror(errno), errno); return false; } - len = sizeof(l2o.omtu); + len = sizeof(data->l2o.omtu); if (getsockopt(sk, SOL_BLUETOOTH, BT_SNDMTU, - &l2o.omtu, &len) < 0) { + &data->l2o.omtu, &len) < 0) { tester_warn("getsockopt(BT_SNDMTU): %s (%d)", strerror(errno), errno); return false; @@ -1262,8 +1281,9 @@ static bool check_mtu(struct test_data *data, int sk) } else { /* For non-LE CoC enabled kernels we need to fall back to * L2CAP_OPTIONS, so test support for it as well */ - len = sizeof(l2o); - if (getsockopt(sk, SOL_L2CAP, L2CAP_OPTIONS, &l2o, &len) < 0) { + len = sizeof(data->l2o); + if (getsockopt(sk, SOL_L2CAP, L2CAP_OPTIONS, &data->l2o, + &len) < 0) { tester_warn("getsockopt(L2CAP_OPTIONS): %s (%d)", strerror(errno), errno); return false; @@ -1326,6 +1346,84 @@ static void l2cap_tx_timestamping(struct test_data *data, GIOChannel *io) data->err_io_id = g_io_add_watch(io, G_IO_ERR, recv_errqueue, data); } +static int l2cap_send(int sk, const void *data, size_t len, uint16_t mtu) +{ + struct iovec iov = { (void *)data, len }; + int err; + size_t total = 0; + + len = MIN(mtu, len); + + while (iov.iov_len) { + size_t l = MIN(iov.iov_len, len); + + err = write(sk, util_iov_pull_mem(&iov, l), l); + if (err < 0) + return -errno; + + total += err; + tester_debug("write: %d/%zu", err, total); + } + + return total; +} + +static void l2cap_read_data(struct test_data *data, GIOChannel *io, + uint16_t cid) +{ + const struct l2cap_data *l2data = data->test_data; + struct bthost *bthost; + struct iovec iov = { (void *)l2data->read_data, l2data->data_len }; + size_t len; + + data->step = 0; + + bthost = hciemu_client_get_host(data->hciemu); + g_io_add_watch(io, G_IO_IN, sock_received_data, NULL); + + len = MIN(iov.iov_len, data->l2o.imtu); + + while (iov.iov_len) { + size_t l = MIN(iov.iov_len, len); + + bthost_send_cid(bthost, data->handle, cid, + util_iov_pull_mem(&iov, l), l); + } + + ++data->step; +} + +static void l2cap_write_data(struct test_data *data, GIOChannel *io, + uint16_t cid) +{ + const struct l2cap_data *l2data = data->test_data; + struct bthost *bthost; + ssize_t ret; + int sk; + unsigned int count; + + sk = g_io_channel_unix_get_fd(io); + + data->step = 0; + + bthost = hciemu_client_get_host(data->hciemu); + bthost_add_cid_hook(bthost, data->handle, cid, bthost_received_data, + NULL); + + l2cap_tx_timestamping(data, io); + + for (count = 0; count < l2data->repeat_send + 1; ++count) { + ret = l2cap_send(sk, l2data->write_data, l2data->data_len, + data->l2o.omtu); + if (ret != l2data->data_len) { + tester_warn("Unable to write all data: " + "%zd != %u", ret, l2data->data_len); + tester_test_failed(); + } + ++data->step; + } +} + static gboolean l2cap_connect_cb(GIOChannel *io, GIOCondition cond, gpointer user_data) { @@ -1356,37 +1454,10 @@ static gboolean l2cap_connect_cb(GIOChannel *io, GIOCondition cond, } if (l2data->read_data) { - struct bthost *bthost; - - bthost = hciemu_client_get_host(data->hciemu); - g_io_add_watch(io, G_IO_IN, client_received_data, NULL); - - bthost_send_cid(bthost, data->handle, data->dcid, - l2data->read_data, l2data->data_len); - + l2cap_read_data(data, io, data->dcid); return FALSE; } 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); - - 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; - } - + l2cap_write_data(data, io, data->dcid); return FALSE; } else if (l2data->shut_sock_wr) { g_io_add_watch(io, G_IO_HUP, socket_closed_cb, NULL); @@ -2087,31 +2158,10 @@ static gboolean l2cap_accept_cb(GIOChannel *io, GIOCondition cond, } if (l2data->read_data) { - struct bthost *bthost; - - bthost = hciemu_client_get_host(data->hciemu); - g_io_add_watch(io, G_IO_IN, server_received_data, NULL); - bthost_send_cid(bthost, data->handle, data->dcid, - l2data->read_data, l2data->data_len); - - g_io_channel_unref(io); - + l2cap_read_data(data, io, data->dcid); return FALSE; } else if (l2data->write_data) { - struct bthost *bthost; - ssize_t ret; - - bthost = hciemu_client_get_host(data->hciemu); - bthost_add_cid_hook(bthost, data->handle, data->scid, - server_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_write_data(data, io, data->scid); return FALSE; } @@ -2405,10 +2455,18 @@ int main(int argc, char *argv[]) &client_connect_read_success_test, setup_powered_client, test_connect); + test_l2cap_bredr("L2CAP BR/EDR Client - Read 32k Success", + &client_connect_read_32k_success_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); + test_l2cap_bredr("L2CAP BR/EDR Client - Write 32k Success", + &client_connect_write_32k_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); @@ -2437,10 +2495,18 @@ int main(int argc, char *argv[]) &l2cap_server_read_success_test, setup_powered_server, test_server); + test_l2cap_bredr("L2CAP BR/EDR Server - Read 32k Success", + &l2cap_server_read_32k_success_test, + setup_powered_server, test_server); + test_l2cap_bredr("L2CAP BR/EDR Server - Write Success", &l2cap_server_write_success_test, setup_powered_server, test_server); + test_l2cap_bredr("L2CAP BR/EDR Server - Write 32k Success", + &l2cap_server_write_32k_success_test, + setup_powered_server, test_server); + test_l2cap_bredr("L2CAP BR/EDR Server - Security Block", &l2cap_server_sec_block_test, setup_powered_server, test_server); -- 2.45.2