tools/l2cap-tester: Add test for Ext-Flowctl mode
authorLuiz Augusto von Dentz <luiz.von.dentz@intel.com>
Tue, 10 Mar 2020 20:44:27 +0000 (13:44 -0700)
committerAyush Garg <ayush.garg@samsung.com>
Mon, 12 Apr 2021 09:00:48 +0000 (14:30 +0530)
This adds tests for Ext-Flowctl which uses ECRED PDUs.

Signed-off-by: Anuj Jain <anuj01.jain@samsung.com>
Signed-off-by: Ayush Garg <ayush.garg@samsung.com>
tools/l2cap-tester.c

index 945f82c..844ff2b 100755 (executable)
@@ -61,6 +61,7 @@ struct l2cap_data {
        uint16_t client_psm;
        uint16_t server_psm;
        uint16_t cid;
+       uint8_t mode;
        int expect_err;
 
        uint8_t send_cmd_code;
@@ -91,7 +92,7 @@ struct l2cap_data {
        uint8_t *client_bdaddr;
        bool server_not_advertising;
        bool direct_advertising;
-       bool close_one_socket;
+       bool close_1;
 };
 
 static void mgmt_debug(const char *str, void *user_data)
@@ -474,17 +475,17 @@ static const struct l2cap_data le_client_close_socket_test_2 = {
        .server_not_advertising = true,
 };
 
-static const struct l2cap_data le_client_two_sockets_same_client = {
+static const struct l2cap_data le_client_2_same_client = {
        .client_psm = 0x0080,
        .server_psm = 0x0080,
        .server_not_advertising = true,
 };
 
-static const struct l2cap_data le_client_two_sockets_close_one = {
+static const struct l2cap_data le_client_2_close_1 = {
        .client_psm = 0x0080,
        .server_psm = 0x0080,
        .server_not_advertising = true,
-       .close_one_socket = true,
+       .close_1 = true,
 };
 
 static const struct l2cap_data le_client_connect_nval_psm_test = {
@@ -549,6 +550,49 @@ static const struct l2cap_data le_att_server_success_test_1 = {
        .cid = 0x0004,
 };
 
+static const struct l2cap_data ext_flowctl_client_connect_success_test_1 = {
+       .client_psm = 0x0080,
+       .server_psm = 0x0080,
+       .mode = BT_MODE_EXT_FLOWCTL,
+};
+
+static const struct l2cap_data ext_flowctl_client_connect_adv_success_test_1 = {
+       .client_psm = 0x0080,
+       .server_psm = 0x0080,
+       .mode = BT_MODE_EXT_FLOWCTL,
+       .direct_advertising = true,
+};
+
+static const struct l2cap_data ext_flowctl_client_connect_success_test_2 = {
+       .client_psm = 0x0080,
+       .server_psm = 0x0080,
+       .mode = BT_MODE_EXT_FLOWCTL,
+       .sec_level  = BT_SECURITY_MEDIUM,
+};
+
+static const struct l2cap_data ext_flowctl_client_connect_reject_test_1 = {
+       .client_psm = 0x0080,
+       .mode = BT_MODE_EXT_FLOWCTL,
+       .send_cmd = cmd_reject_rsp,
+       .send_cmd_len = sizeof(cmd_reject_rsp),
+       .expect_err = ECONNREFUSED,
+};
+
+static const struct l2cap_data ext_flowctl_client_2 = {
+       .client_psm = 0x0080,
+       .server_psm = 0x0080,
+       .mode = BT_MODE_EXT_FLOWCTL,
+       .server_not_advertising = true,
+};
+
+static const struct l2cap_data ext_flowctl_client_2_close_1 = {
+       .client_psm = 0x0080,
+       .server_psm = 0x0080,
+       .mode = BT_MODE_EXT_FLOWCTL,
+       .server_not_advertising = true,
+       .close_1 = true,
+};
+
 static void client_cmd_complete(uint16_t opcode, uint8_t status,
                                        const void *param, uint8_t len,
                                        void *user_data)
@@ -1031,7 +1075,7 @@ failed:
 }
 
 static int create_l2cap_sock(struct test_data *data, uint16_t psm,
-                                               uint16_t cid, int sec_level)
+                               uint16_t cid, int sec_level, uint8_t mode)
 {
        const struct l2cap_data *l2data = data->test_data;
        const uint8_t *master_bdaddr;
@@ -1091,6 +1135,17 @@ static int create_l2cap_sock(struct test_data *data, uint16_t psm,
                }
        }
 
+       if (mode) {
+               if (setsockopt(sk, SOL_BLUETOOTH, BT_MODE, &mode,
+                                                       sizeof(mode)) < 0) {
+                       err = -errno;
+                       tester_warn("Can't set mode: %s (%d)", strerror(errno),
+                                                                       errno);
+                       close(sk);
+                       return err;
+               }
+       }
+
        return sk;
 }
 
@@ -1212,9 +1267,13 @@ static void test_connect(const void *test_data)
                hciemu_add_master_post_command_hook(data->hciemu,
                                                direct_adv_cmd_complete, NULL);
 
-       sk = create_l2cap_sock(data, 0, l2data->cid, l2data->sec_level);
+       sk = create_l2cap_sock(data, 0, l2data->cid, l2data->sec_level,
+                                                       l2data->mode);
        if (sk < 0) {
-               tester_test_failed();
+               if (sk == -ENOPROTOOPT)
+                       tester_test_abort();
+               else
+                       tester_test_failed();
                return;
        }
 
@@ -1241,7 +1300,8 @@ static void test_connect_reject(const void *test_data)
        const struct l2cap_data *l2data = data->test_data;
        int sk;
 
-       sk = create_l2cap_sock(data, 0, l2data->cid, l2data->sec_level);
+       sk = create_l2cap_sock(data, 0, l2data->cid, l2data->sec_level,
+                                                       l2data->mode);
        if (sk < 0) {
                tester_test_failed();
                return;
@@ -1256,29 +1316,43 @@ static void test_connect_reject(const void *test_data)
        close(sk);
 }
 
-static void connect_socket(const uint8_t *client_bdaddr, int *sk_holder,
-                                                       GIOFunc connect_cb)
+static int connect_socket(const uint8_t *client_bdaddr, GIOFunc connect_cb,
+                                                               bool defer)
 {
        struct test_data *data = tester_get_data();
        const struct l2cap_data *l2data = data->test_data;
        GIOChannel *io;
        int sk;
 
-       sk = create_l2cap_sock(data, 0, l2data->cid, l2data->sec_level);
+       sk = create_l2cap_sock(data, 0, l2data->cid, l2data->sec_level,
+                                                       l2data->mode);
        if (sk < 0) {
                tester_print("Error in create_l2cap_sock");
-               tester_test_failed();
-               return;
+               if (sk == -ENOPROTOOPT)
+                       tester_test_abort();
+               else
+                       tester_test_failed();
+               return -1;
        }
 
-       *sk_holder = sk;
+       if (defer) {
+               int opt = 1;
+
+               if (setsockopt(sk, SOL_BLUETOOTH, BT_DEFER_SETUP, &opt,
+                                                       sizeof(opt)) < 0) {
+                       tester_print("Can't enable deferred setup: %s (%d)",
+                                               strerror(errno), errno);
+                       tester_test_failed();
+                       return -1;
+               }
+       }
 
        if (connect_l2cap_impl(sk, client_bdaddr, BDADDR_LE_PUBLIC,
                        l2data->client_psm, l2data->cid) < 0) {
                tester_print("Error in connect_l2cap_sock");
                close(sk);
                tester_test_failed();
-               return;
+               return -1;
        }
 
        if (connect_cb) {
@@ -1290,7 +1364,10 @@ static void connect_socket(const uint8_t *client_bdaddr, int *sk_holder,
                g_io_channel_unref(io);
        }
 
-       tester_print("Connect in progress, sk = %d", sk);
+       tester_print("Connect in progress, sk = %d %s", sk,
+                               defer ? "(deferred)" : "");
+
+       return sk;
 }
 
 static gboolean test_close_socket_1_part_3(gpointer arg)
@@ -1457,11 +1534,11 @@ static void test_close_socket(const void *test_data)
        else
                client_bdaddr = hciemu_get_client_bdaddr(data->hciemu);
 
-       connect_socket(client_bdaddr, &data->sk, NULL);
+       data->sk = connect_socket(client_bdaddr, NULL, false);
 }
 
-static uint8_t test_two_sockets_connect_cb_cnt;
-static gboolean test_two_sockets_connect_cb(GIOChannel *io, GIOCondition cond,
+static uint8_t test_2_connect_cb_cnt;
+static gboolean test_2_connect_cb(GIOChannel *io, GIOCondition cond,
                                                        gpointer user_data)
 {
        struct test_data *data = tester_get_data();
@@ -1485,15 +1562,15 @@ static gboolean test_two_sockets_connect_cb(GIOChannel *io, GIOCondition cond,
        }
 
        tester_print("Successfully connected");
-       test_two_sockets_connect_cb_cnt++;
+       test_2_connect_cb_cnt++;
 
-       if (test_two_sockets_connect_cb_cnt == 2) {
+       if (test_2_connect_cb_cnt == 2) {
                close(data->sk);
                close(data->sk2);
                tester_test_passed();
        }
 
-       if (l2data->close_one_socket && test_two_sockets_connect_cb_cnt == 1) {
+       if (l2data->close_1 && test_2_connect_cb_cnt == 1) {
                close(data->sk2);
                tester_test_passed();
        }
@@ -1510,16 +1587,16 @@ static gboolean enable_advertising(gpointer args)
        return FALSE;
 }
 
-static void test_connect_two_sockets_part_2(void)
+static void test_connect_2_part_2(void)
 {
        struct test_data *data = tester_get_data();
        const struct l2cap_data *l2data = data->test_data;
        const uint8_t *client_bdaddr;
 
        client_bdaddr = hciemu_get_client_bdaddr(data->hciemu);
-       connect_socket(client_bdaddr, &data->sk2, test_two_sockets_connect_cb);
+       data->sk2 = connect_socket(client_bdaddr, test_2_connect_cb, false);
 
-       if (l2data->close_one_socket) {
+       if (l2data->close_1) {
                tester_print("Closing first socket! %d", data->sk);
                close(data->sk);
        }
@@ -1528,7 +1605,7 @@ static void test_connect_two_sockets_part_2(void)
 }
 
 static uint8_t test_scan_enable_counter;
-static void test_connect_two_sockets_router(uint16_t opcode, const void *param,
+static void test_connect_2_router(uint16_t opcode, const void *param,
                                        uint8_t length, void *user_data)
 {
        const struct bt_hci_cmd_le_set_scan_enable *scan_params = param;
@@ -1538,23 +1615,24 @@ static void test_connect_two_sockets_router(uint16_t opcode, const void *param,
                                                scan_params->enable == true) {
                test_scan_enable_counter++;
                if (test_scan_enable_counter == 1)
-                       test_connect_two_sockets_part_2();
+                       test_connect_2_part_2();
                else if (test_scan_enable_counter == 2)
                        g_idle_add(enable_advertising, NULL);
        }
 }
 
-static void test_connect_two_sockets(const void *test_data)
+static void test_connect_2(const void *test_data)
 {
        struct test_data *data = tester_get_data();
        const struct l2cap_data *l2data = data->test_data;
        const uint8_t *client_bdaddr;
+       bool defer;
 
-       test_two_sockets_connect_cb_cnt = 0;
+       test_2_connect_cb_cnt = 0;
        test_scan_enable_counter = 0;
 
        hciemu_add_master_post_command_hook(data->hciemu,
-                               test_connect_two_sockets_router, data);
+                               test_connect_2_router, data);
 
        if (l2data->server_psm) {
                struct bthost *bthost = hciemu_client_get_host(data->hciemu);
@@ -1564,12 +1642,14 @@ static void test_connect_two_sockets(const void *test_data)
                                                NULL, NULL);
        }
 
+       defer = (l2data->mode == BT_MODE_EXT_FLOWCTL);
+
        client_bdaddr = hciemu_get_client_bdaddr(data->hciemu);
-       if (l2data->close_one_socket)
-               connect_socket(client_bdaddr, &data->sk, NULL);
+       if (l2data->close_1)
+               data->sk = connect_socket(client_bdaddr, NULL, defer);
        else
-               connect_socket(client_bdaddr, &data->sk,
-                                               test_two_sockets_connect_cb);
+               data->sk = connect_socket(client_bdaddr, test_2_connect_cb,
+                                                               defer);
 }
 
 static gboolean l2cap_listen_cb(GIOChannel *io, GIOCondition cond,
@@ -1727,7 +1807,8 @@ static void test_server(const void *test_data)
 
        if (l2data->server_psm || l2data->cid) {
                sk = create_l2cap_sock(data, l2data->server_psm,
-                                       l2data->cid, l2data->sec_level);
+                                       l2data->cid, l2data->sec_level,
+                                       l2data->mode);
                if (sk < 0) {
                        tester_test_failed();
                        return;
@@ -1776,7 +1857,7 @@ static void test_getpeername_not_connected(const void *test_data)
        socklen_t len;
        int sk;
 
-       sk = create_l2cap_sock(data, 0, 0, 0);
+       sk = create_l2cap_sock(data, 0, 0, 0, 0);
        if (sk < 0) {
                tester_test_failed();
                return;
@@ -1902,14 +1983,14 @@ int main(int argc, char *argv[])
                                test_close_socket);
 
        test_l2cap_le("L2CAP LE Client - Open two sockets",
-                               &le_client_two_sockets_same_client,
+                               &le_client_2_same_client,
                                setup_powered_client,
-                               test_connect_two_sockets);
+                               test_connect_2);
 
        test_l2cap_le("L2CAP LE Client - Open two sockets close one",
-                               &le_client_two_sockets_close_one,
+                               &le_client_2_close_1,
                                setup_powered_client,
-                               test_connect_two_sockets);
+                               test_connect_2);
 
        test_l2cap_le("L2CAP LE Client - Invalid PSM",
                                        &le_client_connect_nval_psm_test,
@@ -1920,6 +2001,29 @@ int main(int argc, char *argv[])
                                        setup_powered_server, test_server);
 
 
+       test_l2cap_le("L2CAP Ext-Flowctl Client - Success",
+                               &ext_flowctl_client_connect_success_test_1,
+                               setup_powered_client, test_connect);
+       test_l2cap_le("L2CAP Ext-Flowctl Client, Direct Advertising - Success",
+                               &ext_flowctl_client_connect_adv_success_test_1,
+                               setup_powered_client, test_connect);
+       test_l2cap_le("L2CAP Ext-Flowctl Client SMP - Success",
+                               &ext_flowctl_client_connect_success_test_2,
+                               setup_powered_client, test_connect);
+       test_l2cap_le("L2CAP Ext-Flowctl Client - Command Reject",
+                               &ext_flowctl_client_connect_reject_test_1,
+                               setup_powered_client, test_connect);
+
+       test_l2cap_le("L2CAP Ext-Flowctl Client - Open two sockets",
+                               &ext_flowctl_client_2,
+                               setup_powered_client,
+                               test_connect_2);
+
+       test_l2cap_le("L2CAP Ext-Flowctl Client - Open two sockets close one",
+                               &ext_flowctl_client_2_close_1,
+                               setup_powered_client,
+                               test_connect_2);
+
        test_l2cap_le("L2CAP LE ATT Client - Success",
                                &le_att_client_connect_success_test_1,
                                setup_powered_client, test_connect);