All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3 1/8] emulator: add support for checking le scan state
@ 2015-09-02 17:51 Jakub Pawlowski
  2015-09-02 17:51 ` [PATCH v3 2/8] tools/l2cap-tester: add close socket test Jakub Pawlowski
                   ` (7 more replies)
  0 siblings, 8 replies; 12+ messages in thread
From: Jakub Pawlowski @ 2015-09-02 17:51 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Jakub Pawlowski

---
 emulator/btdev.c  | 5 +++++
 emulator/btdev.h  | 2 ++
 emulator/hciemu.c | 8 ++++++++
 emulator/hciemu.h | 2 ++
 4 files changed, 17 insertions(+)

diff --git a/emulator/btdev.c b/emulator/btdev.c
index ceefd56..60e8e8c 100644
--- a/emulator/btdev.c
+++ b/emulator/btdev.c
@@ -669,6 +669,11 @@ uint8_t *btdev_get_features(struct btdev *btdev)
 	return btdev->features;
 }
 
+bool btdev_is_le_scan_enabled(struct btdev *btdev)
+{
+	return btdev->le_scan_enable;
+}
+
 static bool use_ssp(struct btdev *btdev1, struct btdev *btdev2)
 {
 	if (btdev1->auth_enable || btdev2->auth_enable)
diff --git a/emulator/btdev.h b/emulator/btdev.h
index 4b724a7..8b116e4 100644
--- a/emulator/btdev.h
+++ b/emulator/btdev.h
@@ -80,6 +80,8 @@ void btdev_destroy(struct btdev *btdev);
 const uint8_t *btdev_get_bdaddr(struct btdev *btdev);
 uint8_t *btdev_get_features(struct btdev *btdev);
 
+bool btdev_is_le_scan_enabled(struct btdev *btdev);
+
 void btdev_set_command_handler(struct btdev *btdev, btdev_command_func handler,
 							void *user_data);
 
diff --git a/emulator/hciemu.c b/emulator/hciemu.c
index 4881a24..c04aa6d 100644
--- a/emulator/hciemu.c
+++ b/emulator/hciemu.c
@@ -427,6 +427,14 @@ const uint8_t *hciemu_get_client_bdaddr(struct hciemu *hciemu)
 	return btdev_get_bdaddr(hciemu->client_dev);
 }
 
+const bool hciemu_is_master_le_scan_enabled(struct hciemu *hciemu)
+{
+	if (!hciemu || !hciemu->master_dev)
+		return NULL;
+
+	return btdev_is_le_scan_enabled(hciemu->master_dev);
+}
+
 bool hciemu_add_master_post_command_hook(struct hciemu *hciemu,
 			hciemu_command_func_t function, void *user_data)
 {
diff --git a/emulator/hciemu.h b/emulator/hciemu.h
index 41ca3fc..a526d8c 100644
--- a/emulator/hciemu.h
+++ b/emulator/hciemu.h
@@ -53,6 +53,8 @@ uint8_t *hciemu_get_features(struct hciemu *hciemu);
 const uint8_t *hciemu_get_master_bdaddr(struct hciemu *hciemu);
 const uint8_t *hciemu_get_client_bdaddr(struct hciemu *hciemu);
 
+const bool hciemu_is_master_le_scan_enabled(struct hciemu *hciemu);
+
 typedef void (*hciemu_command_func_t)(uint16_t opcode, const void *data,
 						uint8_t len, void *user_data);
 
-- 
2.1.4


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v3 2/8] tools/l2cap-tester: add close socket test
  2015-09-02 17:51 [PATCH v3 1/8] emulator: add support for checking le scan state Jakub Pawlowski
@ 2015-09-02 17:51 ` Jakub Pawlowski
  2015-09-02 17:51 ` [PATCH v3 3/8] emulator: add BT_HCI_CMD_LE_CREATE_CONN_CANCEL handling Jakub Pawlowski
                   ` (6 subsequent siblings)
  7 siblings, 0 replies; 12+ messages in thread
From: Jakub Pawlowski @ 2015-09-02 17:51 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Jakub Pawlowski

This patch adds test that checks folowing:
1. Try to connect to non-existing remote BLE device using socket.
2. Internally in kernel this adds this device to whitelist and enable scan.
3. At this moment test would try to close socket.
4. That should cause scan to be stopped.
---
 tools/l2cap-tester.c | 184 +++++++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 171 insertions(+), 13 deletions(-)

diff --git a/tools/l2cap-tester.c b/tools/l2cap-tester.c
index 2b89045..bca7f75 100644
--- a/tools/l2cap-tester.c
+++ b/tools/l2cap-tester.c
@@ -53,6 +53,7 @@ struct test_data {
 	uint16_t handle;
 	uint16_t scid;
 	uint16_t dcid;
+	int sk;
 };
 
 struct l2cap_data {
@@ -85,6 +86,8 @@ struct l2cap_data {
 
 	bool addr_type_avail;
 	uint8_t addr_type;
+
+	uint8_t *client_bdaddr;
 };
 
 static void mgmt_debug(const char *str, void *user_data)
@@ -450,6 +453,12 @@ static const struct l2cap_data le_client_connect_reject_test_2 = {
 	.addr_type = BDADDR_LE_PUBLIC,
 };
 
+static uint8_t nonexisting_bdaddr[] = {0x00, 0xAA, 0x01, 0x02, 0x03, 0x00};
+static const struct l2cap_data le_client_close_socket_test_1 = {
+	.client_psm = 0x0080,
+	.client_bdaddr = nonexisting_bdaddr,
+};
+
 static const struct l2cap_data le_client_connect_nval_psm_test = {
 	.client_psm = 0x0080,
 	.expect_err = ECONNREFUSED,
@@ -1013,33 +1022,25 @@ static int create_l2cap_sock(struct test_data *data, uint16_t psm,
 	return sk;
 }
 
-static int connect_l2cap_sock(struct test_data *data, int sk, uint16_t psm,
-								uint16_t cid)
+static int connect_l2cap_impl(int sk, const uint8_t *bdaddr,
+				uint8_t bdaddr_type, uint16_t psm, uint16_t cid)
 {
-	const struct l2cap_data *l2data = data->test_data;
 	const uint8_t *client_bdaddr;
 	struct sockaddr_l2 addr;
 	int err;
 
-	client_bdaddr = hciemu_get_client_bdaddr(data->hciemu);
-	if (!client_bdaddr) {
+	if (!bdaddr) {
 		tester_warn("No client bdaddr");
 		return -ENODEV;
 	}
 
 	memset(&addr, 0, sizeof(addr));
 	addr.l2_family = AF_BLUETOOTH;
-	bacpy(&addr.l2_bdaddr, (void *) client_bdaddr);
+	bacpy(&addr.l2_bdaddr, (void *) bdaddr);
+	addr.l2_bdaddr_type = bdaddr_type;
 	addr.l2_psm = htobs(psm);
 	addr.l2_cid = htobs(cid);
 
-	if (l2data && l2data->addr_type_avail)
-		addr.l2_bdaddr_type = l2data->addr_type;
-	else if (data->hciemu_type == HCIEMU_TYPE_LE)
-		addr.l2_bdaddr_type = BDADDR_LE_PUBLIC;
-	else
-		addr.l2_bdaddr_type = BDADDR_BREDR;
-
 	err = connect(sk, (struct sockaddr *) &addr, sizeof(addr));
 	if (err < 0 && !(errno == EAGAIN || errno == EINPROGRESS)) {
 		err = -errno;
@@ -1051,6 +1052,33 @@ static int connect_l2cap_sock(struct test_data *data, int sk, uint16_t psm,
 	return 0;
 }
 
+static int connect_l2cap_sock(struct test_data *data, int sk, uint16_t psm,
+								uint16_t cid)
+{
+	const struct l2cap_data *l2data = data->test_data;
+	const uint8_t *client_bdaddr;
+	uint8_t bdaddr_type;
+
+	if (l2data->client_bdaddr != NULL)
+		client_bdaddr = l2data->client_bdaddr;
+	else
+		client_bdaddr = hciemu_get_client_bdaddr(data->hciemu);
+
+	if (!client_bdaddr) {
+		tester_warn("No client bdaddr");
+		return -ENODEV;
+	}
+
+	if (l2data && l2data->addr_type_avail)
+		bdaddr_type = l2data->addr_type;
+	else if (data->hciemu_type == HCIEMU_TYPE_LE)
+		bdaddr_type = BDADDR_LE_PUBLIC;
+	else
+		bdaddr_type = BDADDR_BREDR;
+
+	return connect_l2cap_impl(sk, client_bdaddr, bdaddr_type, psm, cid);
+}
+
 static void client_l2cap_connect_cb(uint16_t handle, uint16_t cid,
 							void *user_data)
 {
@@ -1122,6 +1150,130 @@ 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)
+{
+	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);
+	if (sk < 0) {
+		tester_print("Error in create_l2cap_sock");
+		tester_test_failed();
+		return;
+	}
+
+	*sk_holder = sk;
+
+	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;
+	}
+
+	if (connect_cb) {
+		io = g_io_channel_unix_new(sk);
+		g_io_channel_set_close_on_unref(io, TRUE);
+
+		data->io_id = g_io_add_watch(io, G_IO_OUT, connect_cb, NULL);
+
+		g_io_channel_unref(io);
+	}
+
+	tester_print("Connect in progress, sk = %d", sk);
+}
+
+static gboolean test_close_socket_1_part_3(gpointer arg)
+{
+	struct test_data *data = tester_get_data();
+
+	tester_print("Checking wether scan was properly stopped...");
+
+	if (data->sk != -1) {
+		tester_print("Error - scan was not enabled yet");
+		tester_test_failed();
+		return FALSE;
+	}
+
+	if (hciemu_is_master_le_scan_enabled(data->hciemu)) {
+		tester_print("Delayed check wether scann is off failed");
+		tester_test_failed();
+		return FALSE;
+	}
+
+	tester_test_passed();
+	return FALSE;
+}
+
+static gboolean test_close_socket_1_part_2(gpointer args)
+{
+	struct test_data *data = tester_get_data();
+	const struct l2cap_data *l2data = data->test_data;
+	GIOChannel *io;
+	int sk = data->sk;
+
+	tester_print("Will close socket during scan phase...");
+
+	/* We tried to conect to LE device that is not advertising. It was added
+	 * to kernel whitelist, and scan was started. We should be still
+	 * scanning.
+	 */
+	if (!hciemu_is_master_le_scan_enabled(data->hciemu)) {
+		tester_print("Error - should be still scanning");
+		tester_test_failed();
+		return FALSE;
+	}
+
+	/* Calling close() should remove device from  whitelist, and stop
+	 * the scan.
+	 */
+	if (close(sk) < 0) {
+		tester_print("Error when closing socket");
+		tester_test_failed();
+		return FALSE;
+	}
+
+	data->sk = -1;
+	/* tester_test_passed will be called when scan is stopped. */
+	return FALSE;
+}
+
+static void test_close_socket_router(uint16_t opcode, const void *param,
+					uint8_t length, void *user_data)
+{
+	/* tester_print("HCI Command 0x%04x length %u", opcode, length); */
+
+	if (opcode == BT_HCI_CMD_LE_SET_SCAN_ENABLE) {
+		const struct bt_hci_cmd_le_set_scan_enable *scan_params = param;
+
+		if (scan_params->enable == true)
+			g_idle_add(test_close_socket_1_part_2, NULL);
+		else
+			g_idle_add(test_close_socket_1_part_3, NULL);
+	}
+}
+
+static void test_close_socket(const void *test_data)
+{
+	struct test_data *data = tester_get_data();
+	const struct l2cap_data *l2data = data->test_data;
+	const uint8_t *client_bdaddr;
+
+	hciemu_add_master_post_command_hook(data->hciemu,
+					test_close_socket_router, data);
+
+	if (l2data->client_bdaddr != NULL)
+		client_bdaddr = l2data->client_bdaddr;
+	else
+		client_bdaddr = hciemu_get_client_bdaddr(data->hciemu);
+
+	connect_socket(client_bdaddr, &data->sk, NULL);
+}
+
 static gboolean l2cap_listen_cb(GIOChannel *io, GIOCondition cond,
 							gpointer user_data)
 {
@@ -1437,6 +1589,12 @@ int main(int argc, char *argv[])
 	test_l2cap_bredr("L2CAP LE Client - Connection Reject",
 				&le_client_connect_reject_test_2,
 				setup_powered_client, test_connect_reject);
+
+	test_l2cap_le("L2CAP LE Client - Close socket 1",
+				&le_client_close_socket_test_1,
+				setup_powered_client,
+				test_close_socket);
+
 	test_l2cap_le("L2CAP LE Client - Invalid PSM",
 					&le_client_connect_nval_psm_test,
 					setup_powered_client, test_connect);
-- 
2.1.4


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v3 3/8] emulator: add BT_HCI_CMD_LE_CREATE_CONN_CANCEL handling
  2015-09-02 17:51 [PATCH v3 1/8] emulator: add support for checking le scan state Jakub Pawlowski
  2015-09-02 17:51 ` [PATCH v3 2/8] tools/l2cap-tester: add close socket test Jakub Pawlowski
@ 2015-09-02 17:51 ` Jakub Pawlowski
  2015-10-05  8:21   ` Johan Hedberg
  2015-09-02 17:51 ` [PATCH v3 4/8] tools/l2cap-tester: Disconnect during connect attempt test Jakub Pawlowski
                   ` (5 subsequent siblings)
  7 siblings, 1 reply; 12+ messages in thread
From: Jakub Pawlowski @ 2015-09-02 17:51 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Jakub Pawlowski

This patch adds handling of BT_HCI_CMD_LE_CREATE_CONN_CANCEL command.

If btdev_set_le_noresp_conn_request is called on btdev, other devices that
try to connect to it will stuck on BT_HCI_CMD_LE_CREATE_CONN, by not
sending bt_hci_evt_le_conn_complete event back. Thanks to that,
BT_HCI_CMD_LE_CREATE_CONN_CANCEL can be triggered to cancel connect
attempt.
---
 emulator/btdev.c  | 45 +++++++++++++++++++++++++++++++++++++++++++++
 emulator/btdev.h  |  2 ++
 emulator/hciemu.c |  8 ++++++++
 emulator/hciemu.h |  3 +++
 4 files changed, 58 insertions(+)

diff --git a/emulator/btdev.c b/emulator/btdev.c
index 60e8e8c..1645776 100644
--- a/emulator/btdev.c
+++ b/emulator/btdev.c
@@ -145,6 +145,11 @@ struct btdev {
 	uint16_t sync_train_interval;
 	uint32_t sync_train_timeout;
 	uint8_t  sync_train_service_data;
+
+	bool     le_noresp_conn_request;
+	bool     pending_le_conn;
+	uint8_t  pending_le_conn_addr[6];
+	uint8_t  pending_le_conn_addr_type;
 };
 
 struct inquiry_data {
@@ -674,6 +679,11 @@ bool btdev_is_le_scan_enabled(struct btdev *btdev)
 	return btdev->le_scan_enable;
 }
 
+void btdev_set_le_noresp_conn_request(struct btdev *btdev, bool value)
+{
+	btdev->le_noresp_conn_request = value;
+}
+
 static bool use_ssp(struct btdev *btdev1, struct btdev *btdev2)
 {
 	if (btdev1->auth_enable || btdev2->auth_enable)
@@ -1134,6 +1144,9 @@ static void le_conn_complete(struct btdev *btdev,
 		cc->handle = cpu_to_le16(42);
 	}
 
+	if (btdev->pending_le_conn)
+		btdev->pending_le_conn = false;
+
 	cc->status = status;
 	cc->peer_addr_type = bdaddr_type;
 	memcpy(cc->peer_addr, bdaddr, 6);
@@ -1183,6 +1196,13 @@ static void le_conn_request(struct btdev *btdev, const uint8_t *bdaddr,
 {
 	struct btdev *remote = find_btdev_by_bdaddr_type(bdaddr, bdaddr_type);
 
+	if (remote && remote->le_noresp_conn_request) {
+		btdev->pending_le_conn = true;
+		memcpy(btdev->pending_le_conn_addr, bdaddr, 6);
+		btdev->pending_le_conn_addr_type = bdaddr_type;
+		return;
+	}
+
 	if (remote && adv_connectable(remote) && adv_match(btdev, remote) &&
 					remote->le_adv_own_addr == bdaddr_type)
 		le_conn_complete(btdev, bdaddr, bdaddr_type, 0);
@@ -1191,6 +1211,14 @@ static void le_conn_request(struct btdev *btdev, const uint8_t *bdaddr,
 					BT_HCI_ERR_CONN_FAILED_TO_ESTABLISH);
 }
 
+static void le_conn_cancel_request(struct btdev *btdev)
+{
+	if (btdev->pending_le_conn)
+		le_conn_complete(btdev, btdev->pending_le_conn_addr,
+					btdev->pending_le_conn_addr_type,
+					BT_HCI_ERR_UNKNOWN_CONN_ID);
+}
+
 static void conn_request(struct btdev *btdev, const uint8_t *bdaddr)
 {
 	struct btdev *remote = find_btdev_by_bdaddr(bdaddr);
@@ -2963,6 +2991,17 @@ static void default_cmd(struct btdev *btdev, uint16_t opcode,
 		cmd_status(btdev, BT_HCI_ERR_SUCCESS, opcode);
 		break;
 
+	case BT_HCI_CMD_LE_CREATE_CONN_CANCEL:
+		if (btdev->type == BTDEV_TYPE_BREDR)
+			goto unsupported;
+
+		if (btdev->pending_le_conn)
+			cmd_status(btdev, BT_HCI_ERR_SUCCESS, opcode);
+		else
+			cmd_status(btdev, BT_HCI_ERR_COMMAND_DISALLOWED,
+								opcode);
+		break;
+
 	case BT_HCI_CMD_LE_READ_WHITE_LIST_SIZE:
 		if (btdev->type == BTDEV_TYPE_BREDR)
 			goto unsupported;
@@ -3331,6 +3370,12 @@ static void default_cmd_completion(struct btdev *btdev, uint16_t opcode,
 		le_conn_request(btdev, lecc->peer_addr, lecc->peer_addr_type);
 		break;
 
+	case BT_HCI_CMD_LE_CREATE_CONN_CANCEL:
+		if (btdev->type == BTDEV_TYPE_BREDR)
+			return;
+		le_conn_cancel_request(btdev);
+		break;
+
 	case BT_HCI_CMD_LE_CONN_UPDATE:
 		if (btdev->type == BTDEV_TYPE_BREDR)
 			return;
diff --git a/emulator/btdev.h b/emulator/btdev.h
index 8b116e4..e0e9f15 100644
--- a/emulator/btdev.h
+++ b/emulator/btdev.h
@@ -82,6 +82,8 @@ uint8_t *btdev_get_features(struct btdev *btdev);
 
 bool btdev_is_le_scan_enabled(struct btdev *btdev);
 
+void btdev_set_le_noresp_conn_request(struct btdev *btdev, bool value);
+
 void btdev_set_command_handler(struct btdev *btdev, btdev_command_func handler,
 							void *user_data);
 
diff --git a/emulator/hciemu.c b/emulator/hciemu.c
index c04aa6d..2e57b1f 100644
--- a/emulator/hciemu.c
+++ b/emulator/hciemu.c
@@ -435,6 +435,14 @@ const bool hciemu_is_master_le_scan_enabled(struct hciemu *hciemu)
 	return btdev_is_le_scan_enabled(hciemu->master_dev);
 }
 
+void hciemu_set_client_le_noresp_conn_request(struct hciemu *hciemu, bool value)
+{
+	if (!hciemu || !hciemu->client_dev)
+		return;
+
+	btdev_set_le_noresp_conn_request(hciemu->client_dev, value);
+}
+
 bool hciemu_add_master_post_command_hook(struct hciemu *hciemu,
 			hciemu_command_func_t function, void *user_data)
 {
diff --git a/emulator/hciemu.h b/emulator/hciemu.h
index a526d8c..3c2d098 100644
--- a/emulator/hciemu.h
+++ b/emulator/hciemu.h
@@ -55,6 +55,9 @@ const uint8_t *hciemu_get_client_bdaddr(struct hciemu *hciemu);
 
 const bool hciemu_is_master_le_scan_enabled(struct hciemu *hciemu);
 
+void hciemu_set_client_le_noresp_conn_request(struct hciemu *hciemu,
+								bool value);
+
 typedef void (*hciemu_command_func_t)(uint16_t opcode, const void *data,
 						uint8_t len, void *user_data);
 
-- 
2.1.4


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v3 4/8] tools/l2cap-tester: Disconnect during connect attempt test
  2015-09-02 17:51 [PATCH v3 1/8] emulator: add support for checking le scan state Jakub Pawlowski
  2015-09-02 17:51 ` [PATCH v3 2/8] tools/l2cap-tester: add close socket test Jakub Pawlowski
  2015-09-02 17:51 ` [PATCH v3 3/8] emulator: add BT_HCI_CMD_LE_CREATE_CONN_CANCEL handling Jakub Pawlowski
@ 2015-09-02 17:51 ` Jakub Pawlowski
  2015-09-02 17:51 ` [PATCH v3 5/8] tools/l2cap-tester: Two socket connect test Jakub Pawlowski
                   ` (4 subsequent siblings)
  7 siblings, 0 replies; 12+ messages in thread
From: Jakub Pawlowski @ 2015-09-02 17:51 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Jakub Pawlowski

This patch adds test that checks folowing:
1. Try to connect to existing BLE device that is not advertising.
2. Internally in kernel this adds this device to whitelist and enable scan.
3. Make the device advertise once. That would stop the scan, and trigger
   connect attempt to device.
4. Close socket. This should stop the connect attempt, by sending
   BT_HCI_CMD_LE_CREATE_CONN_CANCEL.
---
 tools/l2cap-tester.c | 103 ++++++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 97 insertions(+), 6 deletions(-)

diff --git a/tools/l2cap-tester.c b/tools/l2cap-tester.c
index bca7f75..1b7ee94 100644
--- a/tools/l2cap-tester.c
+++ b/tools/l2cap-tester.c
@@ -88,6 +88,7 @@ struct l2cap_data {
 	uint8_t addr_type;
 
 	uint8_t *client_bdaddr;
+	bool server_not_advertising;
 };
 
 static void mgmt_debug(const char *str, void *user_data)
@@ -459,6 +460,11 @@ static const struct l2cap_data le_client_close_socket_test_1 = {
 	.client_bdaddr = nonexisting_bdaddr,
 };
 
+static const struct l2cap_data le_client_close_socket_test_2 = {
+	.client_psm = 0x0080,
+	.server_not_advertising = true,
+};
+
 static const struct l2cap_data le_client_connect_nval_psm_test = {
 	.client_psm = 0x0080,
 	.expect_err = ECONNREFUSED,
@@ -543,6 +549,7 @@ static void setup_powered_client_callback(uint8_t status, uint16_t length,
 					const void *param, void *user_data)
 {
 	struct test_data *data = tester_get_data();
+	const struct l2cap_data *l2data = data->test_data;
 	struct bthost *bthost;
 
 	if (status != MGMT_STATUS_SUCCESS) {
@@ -554,10 +561,15 @@ static void setup_powered_client_callback(uint8_t status, uint16_t length,
 
 	bthost = hciemu_client_get_host(data->hciemu);
 	bthost_set_cmd_complete_cb(bthost, client_cmd_complete, user_data);
-	if (data->hciemu_type == HCIEMU_TYPE_LE)
-		bthost_set_adv_enable(bthost, 0x01);
-	else
+
+	if (data->hciemu_type == HCIEMU_TYPE_LE) {
+		if (!l2data || !l2data->server_not_advertising)
+			bthost_set_adv_enable(bthost, 0x01);
+		else
+			tester_setup_complete();
+	} else {
 		bthost_write_scan_enable(bthost, 0x03);
+	}
 }
 
 static void setup_powered_server_callback(uint8_t status, uint16_t length,
@@ -1242,18 +1254,92 @@ static gboolean test_close_socket_1_part_2(gpointer args)
 	return FALSE;
 }
 
+static gboolean test_close_socket_2_part_3(gpointer arg)
+{
+	struct test_data *data = tester_get_data();
+	int sk = data->sk;
+	int err;
+
+	/* Scan should be already over, we're trying to create connection */
+	if (hciemu_is_master_le_scan_enabled(data->hciemu)) {
+		tester_print("Error - should no longer scan");
+		tester_test_failed();
+		return FALSE;
+	}
+
+	/* Calling close() should eventually cause CMD_LE_CREATE_CONN_CANCEL */
+	err = close(sk);
+	if (err < 0) {
+		tester_print("Error when closing socket");
+		tester_test_failed();
+		return FALSE;
+	}
+
+	/* CMD_LE_CREATE_CONN_CANCEL will trigger test pass. */
+	return FALSE;
+}
+
+static gboolean test_close_socket_2_part_2(gpointer arg)
+{
+	struct test_data *data = tester_get_data();
+	struct bthost *bthost = hciemu_client_get_host(data->hciemu);
+
+	/* Make sure CMD_LE_CREATE_CONN will not immediately result in
+	 * BT_HCI_EVT_CONN_COMPLETE.
+	 */
+	hciemu_set_client_le_noresp_conn_request(data->hciemu, true);
+
+	/* Advertise once. After that, kernel should stop scanning, and trigger
+	 * BT_HCI_CMD_LE_CREATE_CONN_CANCEL.
+	 */
+	bthost_set_adv_enable(bthost, 0x01);
+	bthost_set_adv_enable(bthost, 0x00);
+}
+
+static void test_close_socket_scan_enabled(void)
+{
+	struct test_data *data = tester_get_data();
+	const struct l2cap_data *l2data = data->test_data;
+
+	if (l2data == &le_client_close_socket_test_1)
+		g_idle_add(test_close_socket_1_part_2, NULL);
+	else if (l2data == &le_client_close_socket_test_2)
+		g_idle_add(test_close_socket_2_part_2, NULL);
+}
+
+static void test_close_socket_scan_disabled(void)
+{
+	struct test_data *data = tester_get_data();
+	const struct l2cap_data *l2data = data->test_data;
+
+	if (l2data == &le_client_close_socket_test_1)
+		g_idle_add(test_close_socket_1_part_3, NULL);
+	else if (l2data == &le_client_close_socket_test_2)
+		g_idle_add(test_close_socket_2_part_3, NULL);
+}
+
+static void test_close_socket_conn_cancel(void)
+{
+	struct test_data *data = tester_get_data();
+	const struct l2cap_data *l2data = data->test_data;
+
+	if (l2data == &le_client_close_socket_test_2)
+		tester_test_passed();
+}
+
 static void test_close_socket_router(uint16_t opcode, const void *param,
 					uint8_t length, void *user_data)
 {
 	/* tester_print("HCI Command 0x%04x length %u", opcode, length); */
-
 	if (opcode == BT_HCI_CMD_LE_SET_SCAN_ENABLE) {
 		const struct bt_hci_cmd_le_set_scan_enable *scan_params = param;
 
 		if (scan_params->enable == true)
-			g_idle_add(test_close_socket_1_part_2, NULL);
+			test_close_socket_scan_enabled();
 		else
-			g_idle_add(test_close_socket_1_part_3, NULL);
+			test_close_socket_scan_disabled();
+	} else if (opcode == BT_HCI_CMD_LE_CREATE_CONN_CANCEL) {
+		test_close_socket_conn_cancel();
 	}
 }
 
@@ -1595,6 +1681,11 @@ int main(int argc, char *argv[])
 				setup_powered_client,
 				test_close_socket);
 
+	test_l2cap_le("L2CAP LE Client - Close socket 2",
+				&le_client_close_socket_test_2,
+				setup_powered_client,
+				test_close_socket);
+
 	test_l2cap_le("L2CAP LE Client - Invalid PSM",
 					&le_client_connect_nval_psm_test,
 					setup_powered_client, test_connect);
-- 
2.1.4


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v3 5/8] tools/l2cap-tester: Two socket connect test
  2015-09-02 17:51 [PATCH v3 1/8] emulator: add support for checking le scan state Jakub Pawlowski
                   ` (2 preceding siblings ...)
  2015-09-02 17:51 ` [PATCH v3 4/8] tools/l2cap-tester: Disconnect during connect attempt test Jakub Pawlowski
@ 2015-09-02 17:51 ` Jakub Pawlowski
  2015-09-02 17:51 ` [PATCH v3 6/8] tools/l2cap-tester connect two sockets disconnect one test Jakub Pawlowski
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 12+ messages in thread
From: Jakub Pawlowski @ 2015-09-02 17:51 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Jakub Pawlowski

This test tries to open two sockets to same address, to make sure
both would succeed.
---
 tools/l2cap-tester.c | 103 +++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 103 insertions(+)

diff --git a/tools/l2cap-tester.c b/tools/l2cap-tester.c
index 1b7ee94..5e56934 100644
--- a/tools/l2cap-tester.c
+++ b/tools/l2cap-tester.c
@@ -54,6 +54,7 @@ struct test_data {
 	uint16_t scid;
 	uint16_t dcid;
 	int sk;
+	int sk2;
 };
 
 struct l2cap_data {
@@ -465,6 +466,12 @@ 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 = {
+	.client_psm = 0x0080,
+	.server_psm = 0x0080,
+	.server_not_advertising = true,
+};
+
 static const struct l2cap_data le_client_connect_nval_psm_test = {
 	.client_psm = 0x0080,
 	.expect_err = ECONNREFUSED,
@@ -1360,6 +1367,97 @@ static void test_close_socket(const void *test_data)
 	connect_socket(client_bdaddr, &data->sk, NULL);
 }
 
+static uint8_t test_two_sockets_connect_cb_cnt;
+static gboolean test_two_sockets_connect_cb(GIOChannel *io, GIOCondition cond,
+							gpointer user_data)
+{
+	struct test_data *data = tester_get_data();
+	const struct l2cap_data *l2data = data->test_data;
+	int err, sk_err, sk;
+	socklen_t len = sizeof(sk_err);
+
+	data->io_id = 0;
+
+	sk = g_io_channel_unix_get_fd(io);
+
+	if (getsockopt(sk, SOL_SOCKET, SO_ERROR, &sk_err, &len) < 0)
+		err = -errno;
+	else
+		err = -sk_err;
+
+	if (err < 0) {
+		tester_warn("Connect failed: %s (%d)", strerror(-err), -err);
+		tester_test_failed();
+		return FALSE;
+	}
+
+	tester_print("Successfully connected");
+	test_two_sockets_connect_cb_cnt++;
+
+	if (test_two_sockets_connect_cb_cnt == 2) {
+		close(data->sk);
+		close(data->sk2);
+		tester_test_passed();
+	}
+
+	return FALSE;
+}
+
+static gboolean enable_advertising(gpointer args)
+{
+	struct test_data *data = tester_get_data();
+	struct bthost *bthost = hciemu_client_get_host(data->hciemu);
+
+	bthost_set_adv_enable(bthost, 0x01);
+}
+
+void test_connect_two_sockets_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);
+
+	g_idle_add(enable_advertising, NULL);
+}
+
+static void test_connect_two_sockets_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;
+
+	tester_print("HCI Command 0x%04x length %u", opcode, length);
+	if (opcode == BT_HCI_CMD_LE_SET_SCAN_ENABLE &&
+						scan_params->enable == true) {
+		test_connect_two_sockets_part_2();
+	}
+}
+
+static void test_connect_two_sockets(const void *test_data)
+{
+	struct test_data *data = tester_get_data();
+	const struct l2cap_data *l2data = data->test_data;
+	const uint8_t *client_bdaddr;
+
+	test_two_sockets_connect_cb_cnt = 0;
+
+	hciemu_add_master_post_command_hook(data->hciemu,
+				test_connect_two_sockets_router, data);
+
+	if (l2data->server_psm) {
+		struct bthost *bthost = hciemu_client_get_host(data->hciemu);
+
+		if (!l2data->data_len)
+			bthost_add_l2cap_server(bthost, l2data->server_psm,
+						NULL, NULL);
+	}
+
+	client_bdaddr = hciemu_get_client_bdaddr(data->hciemu);
+	connect_socket(client_bdaddr, &data->sk, test_two_sockets_connect_cb);
+}
+
 static gboolean l2cap_listen_cb(GIOChannel *io, GIOCondition cond,
 							gpointer user_data)
 {
@@ -1686,6 +1784,11 @@ int main(int argc, char *argv[])
 				setup_powered_client,
 				test_close_socket);
 
+	test_l2cap_le("L2CAP LE Client - Open two sockets",
+				&le_client_two_sockets_same_client,
+				setup_powered_client,
+				test_connect_two_sockets);
+
 	test_l2cap_le("L2CAP LE Client - Invalid PSM",
 					&le_client_connect_nval_psm_test,
 					setup_powered_client, test_connect);
-- 
2.1.4


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v3 6/8] tools/l2cap-tester connect two sockets disconnect one test
  2015-09-02 17:51 [PATCH v3 1/8] emulator: add support for checking le scan state Jakub Pawlowski
                   ` (3 preceding siblings ...)
  2015-09-02 17:51 ` [PATCH v3 5/8] tools/l2cap-tester: Two socket connect test Jakub Pawlowski
@ 2015-09-02 17:51 ` Jakub Pawlowski
  2015-09-02 17:51 ` [PATCH v3 7/8] emulator/hciemu: add second client Jakub Pawlowski
                   ` (2 subsequent siblings)
  7 siblings, 0 replies; 12+ messages in thread
From: Jakub Pawlowski @ 2015-09-02 17:51 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Jakub Pawlowski

This test open two sockets to same client, then close first one and make
sure second one connect successfully.
---
 tools/l2cap-tester.c | 37 +++++++++++++++++++++++++++++++++++--
 1 file changed, 35 insertions(+), 2 deletions(-)

diff --git a/tools/l2cap-tester.c b/tools/l2cap-tester.c
index 5e56934..46913d2 100644
--- a/tools/l2cap-tester.c
+++ b/tools/l2cap-tester.c
@@ -90,6 +90,7 @@ struct l2cap_data {
 
 	uint8_t *client_bdaddr;
 	bool server_not_advertising;
+	bool close_one_socket;
 };
 
 static void mgmt_debug(const char *str, void *user_data)
@@ -472,6 +473,13 @@ static const struct l2cap_data le_client_two_sockets_same_client = {
 	.server_not_advertising = true,
 };
 
+static const struct l2cap_data le_client_two_sockets_close_one = {
+	.client_psm = 0x0080,
+	.server_psm = 0x0080,
+	.server_not_advertising = true,
+	.close_one_socket = true,
+};
+
 static const struct l2cap_data le_client_connect_nval_psm_test = {
 	.client_psm = 0x0080,
 	.expect_err = ECONNREFUSED,
@@ -1400,6 +1408,11 @@ static gboolean test_two_sockets_connect_cb(GIOChannel *io, GIOCondition cond,
 		tester_test_passed();
 	}
 
+	if (l2data->close_one_socket && test_two_sockets_connect_cb_cnt == 1) {
+		close(data->sk2);
+		tester_test_passed();
+	}
+
 	return FALSE;
 }
 
@@ -1420,9 +1433,15 @@ void test_connect_two_sockets_part_2(void)
 	client_bdaddr = hciemu_get_client_bdaddr(data->hciemu);
 	connect_socket(client_bdaddr, &data->sk2, test_two_sockets_connect_cb);
 
+	if (l2data->close_one_socket) {
+		tester_print("Closing first socket! %d", data->sk);
+		close(data->sk);
+	}
+
 	g_idle_add(enable_advertising, NULL);
 }
 
+static uint8_t test_scan_enable_counter;
 static void test_connect_two_sockets_router(uint16_t opcode, const void *param,
 					uint8_t length, void *user_data)
 {
@@ -1431,7 +1450,11 @@ static void test_connect_two_sockets_router(uint16_t opcode, const void *param,
 	tester_print("HCI Command 0x%04x length %u", opcode, length);
 	if (opcode == BT_HCI_CMD_LE_SET_SCAN_ENABLE &&
 						scan_params->enable == true) {
-		test_connect_two_sockets_part_2();
+		test_scan_enable_counter++;
+		if (test_scan_enable_counter == 1)
+			test_connect_two_sockets_part_2();
+		else if (test_scan_enable_counter == 2)
+			g_idle_add(enable_advertising, NULL);
 	}
 }
 
@@ -1442,6 +1465,7 @@ static void test_connect_two_sockets(const void *test_data)
 	const uint8_t *client_bdaddr;
 
 	test_two_sockets_connect_cb_cnt = 0;
+	test_scan_enable_counter = 0;
 
 	hciemu_add_master_post_command_hook(data->hciemu,
 				test_connect_two_sockets_router, data);
@@ -1455,7 +1479,11 @@ static void test_connect_two_sockets(const void *test_data)
 	}
 
 	client_bdaddr = hciemu_get_client_bdaddr(data->hciemu);
-	connect_socket(client_bdaddr, &data->sk, test_two_sockets_connect_cb);
+	if (l2data->close_one_socket)
+		connect_socket(client_bdaddr, &data->sk, NULL);
+	else
+		connect_socket(client_bdaddr, &data->sk,
+						test_two_sockets_connect_cb);
 }
 
 static gboolean l2cap_listen_cb(GIOChannel *io, GIOCondition cond,
@@ -1789,6 +1817,11 @@ int main(int argc, char *argv[])
 				setup_powered_client,
 				test_connect_two_sockets);
 
+	test_l2cap_le("L2CAP LE Client - Open two sockets close one",
+				&le_client_two_sockets_close_one,
+				setup_powered_client,
+				test_connect_two_sockets);
+
 	test_l2cap_le("L2CAP LE Client - Invalid PSM",
 					&le_client_connect_nval_psm_test,
 					setup_powered_client, test_connect);
-- 
2.1.4


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v3 7/8] emulator/hciemu: add second client
  2015-09-02 17:51 [PATCH v3 1/8] emulator: add support for checking le scan state Jakub Pawlowski
                   ` (4 preceding siblings ...)
  2015-09-02 17:51 ` [PATCH v3 6/8] tools/l2cap-tester connect two sockets disconnect one test Jakub Pawlowski
@ 2015-09-02 17:51 ` Jakub Pawlowski
  2015-09-02 17:51 ` [PATCH v3 8/8] tools/l2cap-tester: Connect to two devices test Jakub Pawlowski
  2015-10-05  8:11 ` [PATCH v3 1/8] emulator: add support for checking le scan state Johan Hedberg
  7 siblings, 0 replies; 12+ messages in thread
From: Jakub Pawlowski @ 2015-09-02 17:51 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Jakub Pawlowski

This patch adds second client in preparation for test that would try to
connect to two devices at same time.
---
 emulator/hciemu.c | 68 +++++++++++++++++++++++++++++++++++++++++++++++++++----
 emulator/hciemu.h |  2 ++
 2 files changed, 66 insertions(+), 4 deletions(-)

diff --git a/emulator/hciemu.c b/emulator/hciemu.c
index 2e57b1f..7e35b00 100644
--- a/emulator/hciemu.c
+++ b/emulator/hciemu.c
@@ -49,12 +49,17 @@
 struct hciemu {
 	int ref_count;
 	enum btdev_type btdev_type;
+	enum btdev_type btdev_2_type;
 	struct bthost *host_stack;
+	struct bthost *host_2_stack;
 	struct btdev *master_dev;
 	struct btdev *client_dev;
+	struct btdev *client_2_dev;
 	guint host_source;
+	guint host_2_source;
 	guint master_source;
 	guint client_source;
+	guint client_2_source;
 	struct queue *post_command_hooks;
 	char bdaddr_str[18];
 };
@@ -252,7 +257,6 @@ static bool create_vhci(struct hciemu *hciemu)
 	}
 
 	hciemu->master_dev = btdev;
-
 	hciemu->master_source = create_source_btdev(fd, btdev);
 
 	return true;
@@ -266,37 +270,80 @@ struct bthost *hciemu_client_get_host(struct hciemu *hciemu)
 	return hciemu->host_stack;
 }
 
+struct bthost *hciemu_client_2_get_host(struct hciemu *hciemu)
+{
+	if (!hciemu)
+		return NULL;
+
+	return hciemu->host_2_stack;
+}
+
 static bool create_stack(struct hciemu *hciemu)
 {
-	struct btdev *btdev;
-	struct bthost *bthost;
-	int sv[2];
+	struct btdev *btdev, *btdev_2;
+	struct bthost *bthost, *bthost_2;
+	int sv[2], sv2[2];
 
 	btdev = btdev_create(hciemu->btdev_type, 0x00);
 	if (!btdev)
 		return false;
 
+
+	btdev_2 = btdev_create(hciemu->btdev_2_type, 0x01);
+	if (!btdev_2) {
+		btdev_destroy(btdev);
+		return false;
+	}
+
 	bthost = bthost_create();
 	if (!bthost) {
 		btdev_destroy(btdev);
+		btdev_destroy(btdev_2);
+		return false;
+	}
+
+	bthost_2 = bthost_create();
+	if (!bthost_2) {
+		bthost_destroy(bthost);
+		btdev_destroy(btdev);
+		btdev_destroy(btdev_2);
 		return false;
 	}
 
 	btdev_set_command_handler(btdev, client_command_callback, hciemu);
+	btdev_set_command_handler(btdev_2, client_command_callback, hciemu);
 
 	if (socketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_NONBLOCK | SOCK_CLOEXEC,
 								0, sv) < 0) {
 		bthost_destroy(bthost);
+		bthost_destroy(bthost_2);
 		btdev_destroy(btdev);
+		btdev_destroy(btdev_2);
+		return false;
+	}
+
+	if (socketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_NONBLOCK | SOCK_CLOEXEC,
+								0, sv2) < 0) {
+		bthost_destroy(bthost);
+		bthost_destroy(bthost_2);
+		btdev_destroy(btdev);
+		btdev_destroy(btdev_2);
+		close(sv[0]);
+		close(sv[1]);
 		return false;
 	}
 
 	hciemu->client_dev = btdev;
+	hciemu->client_2_dev = btdev_2;
 	hciemu->host_stack = bthost;
+	hciemu->host_2_stack = bthost_2;
 
 	hciemu->client_source = create_source_btdev(sv[0], btdev);
 	hciemu->host_source = create_source_bthost(sv[1], bthost);
 
+	hciemu->client_2_source = create_source_btdev(sv2[0], btdev_2);
+	hciemu->host_2_source = create_source_bthost(sv2[1], bthost_2);
+
 	return true;
 }
 
@@ -305,6 +352,7 @@ static gboolean start_stack(gpointer user_data)
 	struct hciemu *hciemu = user_data;
 
 	bthost_start(hciemu->host_stack);
+	bthost_start(hciemu->host_2_stack);
 
 	return FALSE;
 }
@@ -381,10 +429,14 @@ void hciemu_unref(struct hciemu *hciemu)
 
 	g_source_remove(hciemu->host_source);
 	g_source_remove(hciemu->client_source);
+	g_source_remove(hciemu->host_2_source);
+	g_source_remove(hciemu->client_2_source);
 	g_source_remove(hciemu->master_source);
 
 	bthost_destroy(hciemu->host_stack);
+	bthost_destroy(hciemu->host_2_stack);
 	btdev_destroy(hciemu->client_dev);
+	btdev_destroy(hciemu->client_2_dev);
 	btdev_destroy(hciemu->master_dev);
 
 	free(hciemu);
@@ -427,6 +479,14 @@ const uint8_t *hciemu_get_client_bdaddr(struct hciemu *hciemu)
 	return btdev_get_bdaddr(hciemu->client_dev);
 }
 
+const uint8_t *hciemu_get_client_2_bdaddr(struct hciemu *hciemu)
+{
+	if (!hciemu || !hciemu->client_2_dev)
+		return NULL;
+
+	return btdev_get_bdaddr(hciemu->client_2_dev);
+}
+
 const bool hciemu_is_master_le_scan_enabled(struct hciemu *hciemu)
 {
 	if (!hciemu || !hciemu->master_dev)
diff --git a/emulator/hciemu.h b/emulator/hciemu.h
index 3c2d098..525215d 100644
--- a/emulator/hciemu.h
+++ b/emulator/hciemu.h
@@ -46,12 +46,14 @@ struct hciemu *hciemu_ref(struct hciemu *hciemu);
 void hciemu_unref(struct hciemu *hciemu);
 
 struct bthost *hciemu_client_get_host(struct hciemu *hciemu);
+struct bthost *hciemu_client_2_get_host(struct hciemu *hciemu);
 
 const char *hciemu_get_address(struct hciemu *hciemu);
 uint8_t *hciemu_get_features(struct hciemu *hciemu);
 
 const uint8_t *hciemu_get_master_bdaddr(struct hciemu *hciemu);
 const uint8_t *hciemu_get_client_bdaddr(struct hciemu *hciemu);
+const uint8_t *hciemu_get_client_2_bdaddr(struct hciemu *hciemu);
 
 const bool hciemu_is_master_le_scan_enabled(struct hciemu *hciemu);
 
-- 
2.1.4


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v3 8/8] tools/l2cap-tester: Connect to two devices test.
  2015-09-02 17:51 [PATCH v3 1/8] emulator: add support for checking le scan state Jakub Pawlowski
                   ` (5 preceding siblings ...)
  2015-09-02 17:51 ` [PATCH v3 7/8] emulator/hciemu: add second client Jakub Pawlowski
@ 2015-09-02 17:51 ` Jakub Pawlowski
  2015-10-05  8:11 ` [PATCH v3 1/8] emulator: add support for checking le scan state Johan Hedberg
  7 siblings, 0 replies; 12+ messages in thread
From: Jakub Pawlowski @ 2015-09-02 17:51 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Jakub Pawlowski

This test tries to connect to two devices at same device, and makes sure
that both connections are successfull.
---
 tools/l2cap-tester.c | 129 +++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 125 insertions(+), 4 deletions(-)

diff --git a/tools/l2cap-tester.c b/tools/l2cap-tester.c
index 46913d2..4f96494 100644
--- a/tools/l2cap-tester.c
+++ b/tools/l2cap-tester.c
@@ -57,6 +57,13 @@ struct test_data {
 	int sk2;
 };
 
+/* values of second_socket_dest */
+enum {
+	CLIENT_1,
+	CLIENT_2,
+	UNKNOWN_HOST
+};
+
 struct l2cap_data {
 	uint16_t client_psm;
 	uint16_t server_psm;
@@ -91,6 +98,7 @@ struct l2cap_data {
 	uint8_t *client_bdaddr;
 	bool server_not_advertising;
 	bool close_one_socket;
+	uint8_t second_socket_dest;
 };
 
 static void mgmt_debug(const char *str, void *user_data)
@@ -471,6 +479,14 @@ static const struct l2cap_data le_client_two_sockets_same_client = {
 	.client_psm = 0x0080,
 	.server_psm = 0x0080,
 	.server_not_advertising = true,
+	.second_socket_dest = CLIENT_1,
+};
+
+static const struct l2cap_data le_client_two_sockets_2 = {
+	.client_psm = 0x0080,
+	.server_psm = 0x0080,
+	.server_not_advertising = true,
+	.second_socket_dest = CLIENT_2,
 };
 
 static const struct l2cap_data le_client_two_sockets_close_one = {
@@ -478,6 +494,7 @@ static const struct l2cap_data le_client_two_sockets_close_one = {
 	.server_psm = 0x0080,
 	.server_not_advertising = true,
 	.close_one_socket = true,
+	.second_socket_dest = CLIENT_1,
 };
 
 static const struct l2cap_data le_client_connect_nval_psm_test = {
@@ -542,6 +559,39 @@ static void client_cmd_complete(uint16_t opcode, uint8_t status,
 		tester_setup_complete();
 }
 
+static void client_2_cmd_complete(uint16_t opcode, uint8_t status,
+					const void *param, uint8_t len,
+					void *user_data)
+{
+	struct test_data *data = tester_get_data();
+	const struct l2cap_data *test = data->test_data;
+	struct bthost *bthost;
+
+	bthost = hciemu_client_2_get_host(data->hciemu);
+
+	switch (opcode) {
+	case BT_HCI_CMD_WRITE_SCAN_ENABLE:
+	case BT_HCI_CMD_LE_SET_ADV_ENABLE:
+		tester_print("Client 2 set connectable status 0x%02x", status);
+		if (!status && test && test->enable_ssp) {
+			bthost_write_ssp_mode(bthost, 0x01);
+			return;
+		}
+		break;
+	case BT_HCI_CMD_WRITE_SIMPLE_PAIRING_MODE:
+		tester_print("Client enable SSP status 0x%02x", status);
+		break;
+	default:
+		return;
+	}
+
+
+	if (status)
+		tester_setup_failed();
+	else
+		tester_setup_complete();
+}
+
 static void server_cmd_complete(uint16_t opcode, uint8_t status,
 					const void *param, uint8_t len,
 					void *user_data)
@@ -565,7 +615,7 @@ static void setup_powered_client_callback(uint8_t status, uint16_t length,
 {
 	struct test_data *data = tester_get_data();
 	const struct l2cap_data *l2data = data->test_data;
-	struct bthost *bthost;
+	struct bthost *bthost, *bthost_2;
 
 	if (status != MGMT_STATUS_SUCCESS) {
 		tester_setup_failed();
@@ -577,6 +627,9 @@ static void setup_powered_client_callback(uint8_t status, uint16_t length,
 	bthost = hciemu_client_get_host(data->hciemu);
 	bthost_set_cmd_complete_cb(bthost, client_cmd_complete, user_data);
 
+	bthost_2 = hciemu_client_2_get_host(data->hciemu);
+	bthost_set_cmd_complete_cb(bthost_2, client_2_cmd_complete, user_data);
+
 	if (data->hciemu_type == HCIEMU_TYPE_LE) {
 		if (!l2data || !l2data->server_not_advertising)
 			bthost_set_adv_enable(bthost, 0x01);
@@ -702,6 +755,50 @@ static void send_rsp_new_conn(uint16_t handle, void *user_data)
 						bthost_send_rsp, NULL);
 }
 
+static void bthost_send_rsp_2(const void *buf, uint16_t len, void *user_data)
+{
+	struct test_data *data = tester_get_data();
+	const struct l2cap_data *l2data = data->test_data;
+	struct bthost *bthost;
+
+	if (l2data->expect_cmd_len && len != l2data->expect_cmd_len) {
+		tester_test_failed();
+		return;
+	}
+
+	if (l2data->expect_cmd && memcmp(buf, l2data->expect_cmd,
+						l2data->expect_cmd_len)) {
+		tester_test_failed();
+		return;
+	}
+
+	if (!l2data->send_cmd)
+		return;
+
+	bthost = hciemu_client_2_get_host(data->hciemu);
+	bthost_send_cid(bthost, data->handle, data->dcid,
+				l2data->send_cmd, l2data->send_cmd_len);
+}
+
+static void send_rsp_new_conn_2(uint16_t handle, void *user_data)
+{
+	struct test_data *data = user_data;
+	struct bthost *bthost;
+
+	tester_print("New connection with handle 0x%04x", handle);
+
+	data->handle = handle;
+
+	if (data->hciemu_type == HCIEMU_TYPE_LE)
+		data->dcid = 0x0005;
+	else
+		data->dcid = 0x0001;
+
+	bthost = hciemu_client_2_get_host(data->hciemu);
+	bthost_add_cid_hook(bthost, data->handle, data->dcid,
+						bthost_send_rsp_2, NULL);
+}
+
 static void setup_powered_common(void)
 {
 	struct test_data *data = tester_get_data();
@@ -750,8 +847,13 @@ static void setup_powered_client(const void *test_data)
 	tester_print("Powering on controller");
 
 	if (test && (test->expect_cmd || test->send_cmd)) {
-		struct bthost *bthost = hciemu_client_get_host(data->hciemu);
+		struct bthost *bthost, *bthost_2;
+
+		bthost = hciemu_client_get_host(data->hciemu);
+		bthost_2 = hciemu_client_2_get_host(data->hciemu);
+
 		bthost_set_connect_cb(bthost, send_rsp_new_conn, data);
+		bthost_set_connect_cb(bthost_2, send_rsp_new_conn_2, data);
 	}
 
 	mgmt_send(data->mgmt, MGMT_OP_SET_POWERED, data->mgmt_index,
@@ -1388,6 +1490,8 @@ static gboolean test_two_sockets_connect_cb(GIOChannel *io, GIOCondition cond,
 
 	sk = g_io_channel_unix_get_fd(io);
 
+	tester_print("test_two_sockets_connect_cb *******************\n");
+
 	if (getsockopt(sk, SOL_SOCKET, SO_ERROR, &sk_err, &len) < 0)
 		err = -errno;
 	else
@@ -1420,8 +1524,10 @@ static gboolean enable_advertising(gpointer args)
 {
 	struct test_data *data = tester_get_data();
 	struct bthost *bthost = hciemu_client_get_host(data->hciemu);
+	struct bthost *bthost_2 = hciemu_client_2_get_host(data->hciemu);
 
 	bthost_set_adv_enable(bthost, 0x01);
+	bthost_set_adv_enable(bthost_2, 0x01);
 }
 
 void test_connect_two_sockets_part_2(void)
@@ -1431,6 +1537,11 @@ void test_connect_two_sockets_part_2(void)
 	const uint8_t *client_bdaddr;
 
 	client_bdaddr = hciemu_get_client_bdaddr(data->hciemu);
+	if (l2data->second_socket_dest == CLIENT_1)
+		client_bdaddr = hciemu_get_client_bdaddr(data->hciemu);
+	else if (l2data->second_socket_dest == CLIENT_2)
+		client_bdaddr = hciemu_get_client_2_bdaddr(data->hciemu);
+
 	connect_socket(client_bdaddr, &data->sk2, test_two_sockets_connect_cb);
 
 	if (l2data->close_one_socket) {
@@ -1438,7 +1549,8 @@ void test_connect_two_sockets_part_2(void)
 		close(data->sk);
 	}
 
-	g_idle_add(enable_advertising, NULL);
+	if (l2data->second_socket_dest == CLIENT_1)
+		g_idle_add(enable_advertising, NULL);
 }
 
 static uint8_t test_scan_enable_counter;
@@ -1472,10 +1584,14 @@ static void test_connect_two_sockets(const void *test_data)
 
 	if (l2data->server_psm) {
 		struct bthost *bthost = hciemu_client_get_host(data->hciemu);
+		struct bthost *bthost_2 = hciemu_client_get_host(data->hciemu);
 
-		if (!l2data->data_len)
+		if (!l2data->data_len) {
 			bthost_add_l2cap_server(bthost, l2data->server_psm,
 						NULL, NULL);
+			bthost_add_l2cap_server(bthost_2, l2data->server_psm,
+						NULL, NULL);
+		}
 	}
 
 	client_bdaddr = hciemu_get_client_bdaddr(data->hciemu);
@@ -1817,6 +1933,11 @@ int main(int argc, char *argv[])
 				setup_powered_client,
 				test_connect_two_sockets);
 
+	test_l2cap_le("L2CAP LE Client - Open two sockets 2",
+				&le_client_two_sockets_2,
+				setup_powered_client,
+				test_connect_two_sockets);
+
 	test_l2cap_le("L2CAP LE Client - Open two sockets close one",
 				&le_client_two_sockets_close_one,
 				setup_powered_client,
-- 
2.1.4


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: [PATCH v3 1/8] emulator: add support for checking le scan state
  2015-09-02 17:51 [PATCH v3 1/8] emulator: add support for checking le scan state Jakub Pawlowski
                   ` (6 preceding siblings ...)
  2015-09-02 17:51 ` [PATCH v3 8/8] tools/l2cap-tester: Connect to two devices test Jakub Pawlowski
@ 2015-10-05  8:11 ` Johan Hedberg
  7 siblings, 0 replies; 12+ messages in thread
From: Johan Hedberg @ 2015-10-05  8:11 UTC (permalink / raw)
  To: Jakub Pawlowski; +Cc: linux-bluetooth

Hi Jakub,

(sorry for the late review)

On Wed, Sep 02, 2015, Jakub Pawlowski wrote:
> +const bool hciemu_is_master_le_scan_enabled(struct hciemu *hciemu)
> +{
> +	if (!hciemu || !hciemu->master_dev)
> +		return NULL;
> +
> +	return btdev_is_le_scan_enabled(hciemu->master_dev);
> +}
> +
>  bool hciemu_add_master_post_command_hook(struct hciemu *hciemu,
>  			hciemu_command_func_t function, void *user_data)
>  {
> diff --git a/emulator/hciemu.h b/emulator/hciemu.h
> index 41ca3fc..a526d8c 100644
> --- a/emulator/hciemu.h
> +++ b/emulator/hciemu.h
> @@ -53,6 +53,8 @@ uint8_t *hciemu_get_features(struct hciemu *hciemu);
>  const uint8_t *hciemu_get_master_bdaddr(struct hciemu *hciemu);
>  const uint8_t *hciemu_get_client_bdaddr(struct hciemu *hciemu);
>  
> +const bool hciemu_is_master_le_scan_enabled(struct hciemu *hciemu);

The 'const' doesn't make any sense together with 'bool'. With pointers
it means the data behind the pointer is read-only. It also makes the
patch fail to compile:

In file included from tools/mgmt-tester.c:41:0:
./emulator/hciemu.h:56:11: error: type qualifiers ignored on function return type [-Werror=ignored-qualifiers]
 const bool hciemu_is_master_le_scan_enabled(struct hciemu *hciemu);

Johan

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH v3 3/8] emulator: add BT_HCI_CMD_LE_CREATE_CONN_CANCEL handling
  2015-09-02 17:51 ` [PATCH v3 3/8] emulator: add BT_HCI_CMD_LE_CREATE_CONN_CANCEL handling Jakub Pawlowski
@ 2015-10-05  8:21   ` Johan Hedberg
  2015-10-05 18:28     ` Jakub Pawlowski
  0 siblings, 1 reply; 12+ messages in thread
From: Johan Hedberg @ 2015-10-05  8:21 UTC (permalink / raw)
  To: Jakub Pawlowski; +Cc: linux-bluetooth

Hi Jakub,

On Wed, Sep 02, 2015, Jakub Pawlowski wrote:
> This patch adds handling of BT_HCI_CMD_LE_CREATE_CONN_CANCEL command.
> 
> If btdev_set_le_noresp_conn_request is called on btdev, other devices that
> try to connect to it will stuck on BT_HCI_CMD_LE_CREATE_CONN, by not
> sending bt_hci_evt_le_conn_complete event back. Thanks to that,
> BT_HCI_CMD_LE_CREATE_CONN_CANCEL can be triggered to cancel connect
> attempt.
> ---
>  emulator/btdev.c  | 45 +++++++++++++++++++++++++++++++++++++++++++++
>  emulator/btdev.h  |  2 ++
>  emulator/hciemu.c |  8 ++++++++
>  emulator/hciemu.h |  3 +++
>  4 files changed, 58 insertions(+)
> 
> diff --git a/emulator/btdev.c b/emulator/btdev.c
> index 60e8e8c..1645776 100644
> --- a/emulator/btdev.c
> +++ b/emulator/btdev.c
> @@ -145,6 +145,11 @@ struct btdev {
>  	uint16_t sync_train_interval;
>  	uint32_t sync_train_timeout;
>  	uint8_t  sync_train_service_data;
> +
> +	bool     le_noresp_conn_request;
> +	bool     pending_le_conn;
> +	uint8_t  pending_le_conn_addr[6];
> +	uint8_t  pending_le_conn_addr_type;
>  };
>  
>  struct inquiry_data {
> @@ -674,6 +679,11 @@ bool btdev_is_le_scan_enabled(struct btdev *btdev)
>  	return btdev->le_scan_enable;
>  }
>  
> +void btdev_set_le_noresp_conn_request(struct btdev *btdev, bool value)
> +{
> +	btdev->le_noresp_conn_request = value;
> +}
> +
>  static bool use_ssp(struct btdev *btdev1, struct btdev *btdev2)
>  {
>  	if (btdev1->auth_enable || btdev2->auth_enable)
> @@ -1134,6 +1144,9 @@ static void le_conn_complete(struct btdev *btdev,
>  		cc->handle = cpu_to_le16(42);
>  	}
>  
> +	if (btdev->pending_le_conn)
> +		btdev->pending_le_conn = false;
> +
>  	cc->status = status;
>  	cc->peer_addr_type = bdaddr_type;
>  	memcpy(cc->peer_addr, bdaddr, 6);
> @@ -1183,6 +1196,13 @@ static void le_conn_request(struct btdev *btdev, const uint8_t *bdaddr,
>  {
>  	struct btdev *remote = find_btdev_by_bdaddr_type(bdaddr, bdaddr_type);
>  
> +	if (remote && remote->le_noresp_conn_request) {
> +		btdev->pending_le_conn = true;
> +		memcpy(btdev->pending_le_conn_addr, bdaddr, 6);
> +		btdev->pending_le_conn_addr_type = bdaddr_type;
> +		return;
> +	}

btdev.c has a hooks mechanism to avoid adding test-specific complexity
from creeping in by letting the exception handling be in the test code
itself. In this case, couldn't you use command hooks to deal with the
le_create_conn & le_create_conn_cancel commands in the tester and
prevent the default handlers for them from running in btdev.c (by
returning 'false' from the hook callback)?

Johan

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH v3 3/8] emulator: add BT_HCI_CMD_LE_CREATE_CONN_CANCEL handling
  2015-10-05  8:21   ` Johan Hedberg
@ 2015-10-05 18:28     ` Jakub Pawlowski
  0 siblings, 0 replies; 12+ messages in thread
From: Jakub Pawlowski @ 2015-10-05 18:28 UTC (permalink / raw)
  To: Jakub Pawlowski, BlueZ development

On Mon, Oct 5, 2015 at 1:21 AM, Johan Hedberg <johan.hedberg@gmail.com> wrote:
> Hi Jakub,
>
> On Wed, Sep 02, 2015, Jakub Pawlowski wrote:
>> This patch adds handling of BT_HCI_CMD_LE_CREATE_CONN_CANCEL command.
>>
>> If btdev_set_le_noresp_conn_request is called on btdev, other devices that
>> try to connect to it will stuck on BT_HCI_CMD_LE_CREATE_CONN, by not
>> sending bt_hci_evt_le_conn_complete event back. Thanks to that,
>> BT_HCI_CMD_LE_CREATE_CONN_CANCEL can be triggered to cancel connect
>> attempt.
>> ---
>>  emulator/btdev.c  | 45 +++++++++++++++++++++++++++++++++++++++++++++
>>  emulator/btdev.h  |  2 ++
>>  emulator/hciemu.c |  8 ++++++++
>>  emulator/hciemu.h |  3 +++
>>  4 files changed, 58 insertions(+)
>>
>> diff --git a/emulator/btdev.c b/emulator/btdev.c
>> index 60e8e8c..1645776 100644
>> --- a/emulator/btdev.c
>> +++ b/emulator/btdev.c
>> @@ -145,6 +145,11 @@ struct btdev {
>>       uint16_t sync_train_interval;
>>       uint32_t sync_train_timeout;
>>       uint8_t  sync_train_service_data;
>> +
>> +     bool     le_noresp_conn_request;
>> +     bool     pending_le_conn;
>> +     uint8_t  pending_le_conn_addr[6];
>> +     uint8_t  pending_le_conn_addr_type;
>>  };
>>
>>  struct inquiry_data {
>> @@ -674,6 +679,11 @@ bool btdev_is_le_scan_enabled(struct btdev *btdev)
>>       return btdev->le_scan_enable;
>>  }
>>
>> +void btdev_set_le_noresp_conn_request(struct btdev *btdev, bool value)
>> +{
>> +     btdev->le_noresp_conn_request = value;
>> +}
>> +
>>  static bool use_ssp(struct btdev *btdev1, struct btdev *btdev2)
>>  {
>>       if (btdev1->auth_enable || btdev2->auth_enable)
>> @@ -1134,6 +1144,9 @@ static void le_conn_complete(struct btdev *btdev,
>>               cc->handle = cpu_to_le16(42);
>>       }
>>
>> +     if (btdev->pending_le_conn)
>> +             btdev->pending_le_conn = false;
>> +
>>       cc->status = status;
>>       cc->peer_addr_type = bdaddr_type;
>>       memcpy(cc->peer_addr, bdaddr, 6);
>> @@ -1183,6 +1196,13 @@ static void le_conn_request(struct btdev *btdev, const uint8_t *bdaddr,
>>  {
>>       struct btdev *remote = find_btdev_by_bdaddr_type(bdaddr, bdaddr_type);
>>
>> +     if (remote && remote->le_noresp_conn_request) {
>> +             btdev->pending_le_conn = true;
>> +             memcpy(btdev->pending_le_conn_addr, bdaddr, 6);
>> +             btdev->pending_le_conn_addr_type = bdaddr_type;
>> +             return;
>> +     }
>
> btdev.c has a hooks mechanism to avoid adding test-specific complexity
> from creeping in by letting the exception handling be in the test code
> itself. In this case, couldn't you use command hooks to deal with the
> le_create_conn & le_create_conn_cancel commands in the tester and
> prevent the default handlers for them from running in btdev.c (by
> returning 'false' from the hook callback)?

Thanks for pointing me to hooks. It actually made this code shorter.

>
> Johan

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH v3 6/8] tools/l2cap-tester connect two sockets disconnect one test
  2015-08-04 13:20 Jakub Pawlowski
@ 2015-08-04 13:20 ` Jakub Pawlowski
  0 siblings, 0 replies; 12+ messages in thread
From: Jakub Pawlowski @ 2015-08-04 13:20 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Jakub Pawlowski

This test open two sockets to same client, then close first one and make
sure second one connect successfully.
---
 tools/l2cap-tester.c | 37 +++++++++++++++++++++++++++++++++++--
 1 file changed, 35 insertions(+), 2 deletions(-)

diff --git a/tools/l2cap-tester.c b/tools/l2cap-tester.c
index 5e56934..46913d2 100644
--- a/tools/l2cap-tester.c
+++ b/tools/l2cap-tester.c
@@ -90,6 +90,7 @@ struct l2cap_data {
 
 	uint8_t *client_bdaddr;
 	bool server_not_advertising;
+	bool close_one_socket;
 };
 
 static void mgmt_debug(const char *str, void *user_data)
@@ -472,6 +473,13 @@ static const struct l2cap_data le_client_two_sockets_same_client = {
 	.server_not_advertising = true,
 };
 
+static const struct l2cap_data le_client_two_sockets_close_one = {
+	.client_psm = 0x0080,
+	.server_psm = 0x0080,
+	.server_not_advertising = true,
+	.close_one_socket = true,
+};
+
 static const struct l2cap_data le_client_connect_nval_psm_test = {
 	.client_psm = 0x0080,
 	.expect_err = ECONNREFUSED,
@@ -1400,6 +1408,11 @@ static gboolean test_two_sockets_connect_cb(GIOChannel *io, GIOCondition cond,
 		tester_test_passed();
 	}
 
+	if (l2data->close_one_socket && test_two_sockets_connect_cb_cnt == 1) {
+		close(data->sk2);
+		tester_test_passed();
+	}
+
 	return FALSE;
 }
 
@@ -1420,9 +1433,15 @@ void test_connect_two_sockets_part_2(void)
 	client_bdaddr = hciemu_get_client_bdaddr(data->hciemu);
 	connect_socket(client_bdaddr, &data->sk2, test_two_sockets_connect_cb);
 
+	if (l2data->close_one_socket) {
+		tester_print("Closing first socket! %d", data->sk);
+		close(data->sk);
+	}
+
 	g_idle_add(enable_advertising, NULL);
 }
 
+static uint8_t test_scan_enable_counter;
 static void test_connect_two_sockets_router(uint16_t opcode, const void *param,
 					uint8_t length, void *user_data)
 {
@@ -1431,7 +1450,11 @@ static void test_connect_two_sockets_router(uint16_t opcode, const void *param,
 	tester_print("HCI Command 0x%04x length %u", opcode, length);
 	if (opcode == BT_HCI_CMD_LE_SET_SCAN_ENABLE &&
 						scan_params->enable == true) {
-		test_connect_two_sockets_part_2();
+		test_scan_enable_counter++;
+		if (test_scan_enable_counter == 1)
+			test_connect_two_sockets_part_2();
+		else if (test_scan_enable_counter == 2)
+			g_idle_add(enable_advertising, NULL);
 	}
 }
 
@@ -1442,6 +1465,7 @@ static void test_connect_two_sockets(const void *test_data)
 	const uint8_t *client_bdaddr;
 
 	test_two_sockets_connect_cb_cnt = 0;
+	test_scan_enable_counter = 0;
 
 	hciemu_add_master_post_command_hook(data->hciemu,
 				test_connect_two_sockets_router, data);
@@ -1455,7 +1479,11 @@ static void test_connect_two_sockets(const void *test_data)
 	}
 
 	client_bdaddr = hciemu_get_client_bdaddr(data->hciemu);
-	connect_socket(client_bdaddr, &data->sk, test_two_sockets_connect_cb);
+	if (l2data->close_one_socket)
+		connect_socket(client_bdaddr, &data->sk, NULL);
+	else
+		connect_socket(client_bdaddr, &data->sk,
+						test_two_sockets_connect_cb);
 }
 
 static gboolean l2cap_listen_cb(GIOChannel *io, GIOCondition cond,
@@ -1789,6 +1817,11 @@ int main(int argc, char *argv[])
 				setup_powered_client,
 				test_connect_two_sockets);
 
+	test_l2cap_le("L2CAP LE Client - Open two sockets close one",
+				&le_client_two_sockets_close_one,
+				setup_powered_client,
+				test_connect_two_sockets);
+
 	test_l2cap_le("L2CAP LE Client - Invalid PSM",
 					&le_client_connect_nval_psm_test,
 					setup_powered_client, test_connect);
-- 
2.1.4


^ permalink raw reply related	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2015-10-05 18:28 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-09-02 17:51 [PATCH v3 1/8] emulator: add support for checking le scan state Jakub Pawlowski
2015-09-02 17:51 ` [PATCH v3 2/8] tools/l2cap-tester: add close socket test Jakub Pawlowski
2015-09-02 17:51 ` [PATCH v3 3/8] emulator: add BT_HCI_CMD_LE_CREATE_CONN_CANCEL handling Jakub Pawlowski
2015-10-05  8:21   ` Johan Hedberg
2015-10-05 18:28     ` Jakub Pawlowski
2015-09-02 17:51 ` [PATCH v3 4/8] tools/l2cap-tester: Disconnect during connect attempt test Jakub Pawlowski
2015-09-02 17:51 ` [PATCH v3 5/8] tools/l2cap-tester: Two socket connect test Jakub Pawlowski
2015-09-02 17:51 ` [PATCH v3 6/8] tools/l2cap-tester connect two sockets disconnect one test Jakub Pawlowski
2015-09-02 17:51 ` [PATCH v3 7/8] emulator/hciemu: add second client Jakub Pawlowski
2015-09-02 17:51 ` [PATCH v3 8/8] tools/l2cap-tester: Connect to two devices test Jakub Pawlowski
2015-10-05  8:11 ` [PATCH v3 1/8] emulator: add support for checking le scan state Johan Hedberg
  -- strict thread matches above, loose matches on Subject: below --
2015-08-04 13:20 Jakub Pawlowski
2015-08-04 13:20 ` [PATCH v3 6/8] tools/l2cap-tester connect two sockets disconnect one test Jakub Pawlowski

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.