uint16_t client_psm;
uint16_t server_psm;
uint16_t cid;
+ uint8_t mode;
int expect_err;
uint8_t send_cmd_code;
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)
.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 = {
.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)
}
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;
}
}
+ 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;
}
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;
}
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;
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) {
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)
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();
}
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();
}
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);
}
}
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;
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);
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,
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;
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;
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,
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);