2015-05-05 13:55:36

by Szymon Janc

[permalink] [raw]
Subject: [PATCH] User channel issue

Hi,

While working with User Channel I've noticed that it is not possible to
bind to it from 'Index Added' callback. Returned error was EBUSY which
indicates that device is powered on (although mgmt settings show not powered).

The root cause is HCI_AUTO_OFF which keeps transport powered for seconds
after device is plugged.

I'm not quite sure how to fix this properly in kernel. Attached is an initial
version of tester that shows the bug (first test).

Userspace can workaournd the problem by toggling power on/off before
opening user channel (third test) or simply waiting >2 seconds before
opening it.

Comments are welcome.

Szymon Janc (1):
tools: Add initial User Channel tester

.gitignore | 1 +
Makefile.tools | 11 +-
tools/userchannel-tester.c | 333 +++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 344 insertions(+), 1 deletion(-)
create mode 100644 tools/userchannel-tester.c

--
1.9.3



2015-05-18 20:08:08

by Szymon Janc

[permalink] [raw]
Subject: Re: [PATCH] tools: Add initial User Channel tester

On Tuesday 05 of May 2015 15:55:37 Szymon Janc wrote:
> This adds basic tests only.
> ---
> .gitignore | 1 +
> Makefile.tools | 11 +-
> tools/userchannel-tester.c | 333
> +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 344
> insertions(+), 1 deletion(-)
> create mode 100644 tools/userchannel-tester.c
>
> diff --git a/.gitignore b/.gitignore
> index 08eabac..c350f49 100644
> --- a/.gitignore
> +++ b/.gitignore
> @@ -109,6 +109,7 @@ tools/smp-tester
> tools/gap-tester
> tools/rfcomm-tester
> tools/bnep-tester
> +tools/userchannel-tester
> tools/btattach
> tools/btmgmt
> tools/btsnoop
> diff --git a/Makefile.tools b/Makefile.tools
> index 6020b01..9abe07d 100644
> --- a/Makefile.tools
> +++ b/Makefile.tools
> @@ -43,7 +43,8 @@ noinst_PROGRAMS += emulator/btvirt emulator/b1ee
> emulator/hfp \ tools/mgmt-tester tools/gap-tester \
> tools/l2cap-tester tools/sco-tester \
> tools/smp-tester tools/hci-tester \
> - tools/rfcomm-tester tools/bnep-tester
> + tools/rfcomm-tester tools/bnep-tester \
> + tools/userchannel-tester
>
> emulator_btvirt_SOURCES = emulator/main.c monitor/bt.h \
> emulator/serial.h emulator/serial.c \
> @@ -135,6 +136,14 @@ tools_sco_tester_LDADD = lib/libbluetooth-internal.la \
>
> tools_hci_tester_SOURCES = tools/hci-tester.c monitor/bt.h
> tools_hci_tester_LDADD = src/libshared-glib.la @GLIB_LIBS@
> +
> +tools_userchannel_tester_SOURCES = tools/userchannel-tester.c monitor/bt.h
> \ + emulator/hciemu.h emulator/hciemu.c \
> + emulator/btdev.h emulator/btdev.c \
> + emulator/bthost.h emulator/bthost.c \
> + emulator/smp.c
> +tools_userchannel_tester_LDADD = lib/libbluetooth-internal.la \
> + src/libshared-glib.la @GLIB_LIBS@
> endif
>
> if TOOLS
> diff --git a/tools/userchannel-tester.c b/tools/userchannel-tester.c
> new file mode 100644
> index 0000000..ec5dffd
> --- /dev/null
> +++ b/tools/userchannel-tester.c
> @@ -0,0 +1,333 @@
> +/*
> + *
> + * BlueZ - Bluetooth protocol stack for Linux
> + *
> + * Copyright (C) 2014-2015 Intel Corporation. All rights reserved.
> + *
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
> USA + *
> + */
> +
> +#ifdef HAVE_CONFIG_H
> +#include <config.h>
> +#endif
> +
> +#include <stdlib.h>
> +#include <stdint.h>
> +#include <unistd.h>
> +#include <errno.h>
> +#include <stdbool.h>
> +
> +#include <glib.h>
> +
> +#include "lib/bluetooth.h"
> +#include "lib/hci.h"
> +#include "lib/mgmt.h"
> +
> +#include "monitor/bt.h"
> +#include "emulator/bthost.h"
> +#include "emulator/hciemu.h"
> +
> +#include "src/shared/tester.h"
> +#include "src/shared/mgmt.h"
> +#include "src/shared/hci.h"
> +#include "src/shared/util.h"
> +
> +struct test_data {
> + struct mgmt *mgmt;
> + uint16_t mgmt_index;
> + struct hciemu *hciemu;
> + enum hciemu_type hciemu_type;
> + const void *test_data;
> + unsigned int remove_id;
> +};
> +
> +static void mgmt_debug(const char *str, void *user_data)
> +{
> + const char *prefix = user_data;
> +
> + tester_print("%s%s", prefix, str);
> +}
> +
> +static void read_info_callback(uint8_t status, uint16_t length,
> + const void *param, void *user_data)
> +{
> + struct test_data *data = tester_get_data();
> + const struct mgmt_rp_read_info *rp = param;
> + char addr[18];
> + uint16_t manufacturer;
> + uint32_t supported_settings, current_settings;
> +
> + tester_print("Read Info callback");
> + tester_print(" Status: 0x%02x", status);
> +
> + if (status || !param) {
> + tester_pre_setup_failed();
> + return;
> + }
> +
> + ba2str(&rp->bdaddr, addr);
> + manufacturer = btohs(rp->manufacturer);
> + supported_settings = btohl(rp->supported_settings);
> + current_settings = btohl(rp->current_settings);
> +
> + tester_print(" Address: %s", addr);
> + tester_print(" Version: 0x%02x", rp->version);
> + tester_print(" Manufacturer: 0x%04x", manufacturer);
> + tester_print(" Supported settings: 0x%08x", supported_settings);
> + tester_print(" Current settings: 0x%08x", current_settings);
> + tester_print(" Class: 0x%02x%02x%02x",
> + rp->dev_class[2], rp->dev_class[1], rp->dev_class[0]);
> + tester_print(" Name: %s", rp->name);
> + tester_print(" Short name: %s", rp->short_name);
> +
> + if (strcmp(hciemu_get_address(data->hciemu), addr)) {
> + tester_pre_setup_failed();
> + return;
> + }
> +
> + tester_pre_setup_complete();
> +}
> +
> +static void index_added_callback(uint16_t index, uint16_t length,
> + const void *param, void *user_data)
> +{
> + struct test_data *data = tester_get_data();
> +
> + tester_print("Index Added callback");
> + tester_print(" Index: 0x%04x", index);
> +
> + if (data->mgmt_index != MGMT_INDEX_NONE)
> + return;
> +
> + data->mgmt_index = index;
> +
> + mgmt_send(data->mgmt, MGMT_OP_READ_INFO, data->mgmt_index, 0, NULL,
> + read_info_callback, NULL, NULL);
> +}
> +
> +static void index_removed_callback(uint16_t index, uint16_t length,
> + const void *param, void *user_data)
> +{
> + struct test_data *data = tester_get_data();
> +
> + tester_print("Index Removed callback");
> + tester_print(" Index: 0x%04x", index);
> +
> + if (index != data->mgmt_index)
> + return;
> +
> + if (data->remove_id) {
> + mgmt_unregister(data->mgmt, data->remove_id);
> + data->remove_id = 0;
> + tester_test_passed();
> + return;
> + }
> +
> + mgmt_unregister_index(data->mgmt, data->mgmt_index);
> +
> + mgmt_unref(data->mgmt);
> + data->mgmt = NULL;
> +
> + tester_post_teardown_complete();
> +}
> +
> +static void read_index_list_callback(uint8_t status, uint16_t length,
> + const void *param, void *user_data)
> +{
> + struct test_data *data = tester_get_data();
> +
> + tester_print("Read Index List callback");
> + tester_print(" Status: 0x%02x", status);
> +
> + if (status || !param) {
> + tester_pre_setup_failed();
> + return;
> + }
> +
> + mgmt_register(data->mgmt, MGMT_EV_INDEX_ADDED, MGMT_INDEX_NONE,
> + index_added_callback, NULL, NULL);
> +
> + data->hciemu = hciemu_new(data->hciemu_type);
> + if (!data->hciemu) {
> + tester_warn("Failed to setup HCI emulation");
> + tester_pre_setup_failed();
> + }
> +
> + tester_print("New hciemu instance created");
> +}
> +
> +static void test_pre_setup(const void *test_data)
> +{
> + struct test_data *data = tester_get_data();
> +
> + data->mgmt = mgmt_new_default();
> + if (!data->mgmt) {
> + tester_warn("Failed to setup management interface");
> + tester_pre_setup_failed();
> + return;
> + }
> +
> + if (tester_use_debug())
> + mgmt_set_debug(data->mgmt, mgmt_debug, "mgmt: ", NULL);
> +
> + mgmt_send(data->mgmt, MGMT_OP_READ_INDEX_LIST, MGMT_INDEX_NONE, 0, NULL,
> + read_index_list_callback, NULL, NULL);
> +}
> +
> +static void test_post_teardown(const void *test_data)
> +{
> + struct test_data *data = tester_get_data();
> +
> + mgmt_register(data->mgmt, MGMT_EV_INDEX_REMOVED, data->mgmt_index,
> + index_removed_callback,
> + NULL, NULL);
> +
> + hciemu_unref(data->hciemu);
> + data->hciemu = NULL;
> +}
> +
> +static void test_data_free(void *test_data)
> +{
> + struct test_data *data = test_data;
> +
> + free(data);
> +}
> +
> +static void setup_powered_client_callback(uint8_t status, uint16_t length,
> + const void *param, void *user_data)
> +{
> + if (status != MGMT_STATUS_SUCCESS) {
> + tester_setup_failed();
> + return;
> + }
> +
> + tester_print("Controller powered on");
> +
> + tester_setup_complete();
> +}
> +
> +static void setup_powered(const void *test_data)
> +{
> + struct test_data *data = tester_get_data();
> + unsigned char param[] = { 0x01 };
> +
> + tester_print("Powering on controller");
> +
> + mgmt_send(data->mgmt, MGMT_OP_SET_POWERED, data->mgmt_index,
> + sizeof(param), param, setup_powered_client_callback,
> + NULL, NULL);
> +}
> +
> +static void toggle_powered(const void *test_data);
> +
> +static void toggle_powered_client_callback(uint8_t status, uint16_t length,
> + const void *param, void *user_data)
> +{
> + bool power = PTR_TO_INT(user_data);
> +
> + if (status != MGMT_STATUS_SUCCESS) {
> + tester_setup_failed();
> + return;
> + }
> +
> + tester_print("Controller powered %s", power ? "on" : "off");
> +
> + if (power)
> + toggle_powered(false);
> + else
> + tester_setup_complete();
> +}
> +
> +static void toggle_powered(const void *test_data)
> +{
> + struct test_data *data = tester_get_data();
> + bool power = PTR_TO_INT(test_data);
> + unsigned char param[1];
> +
> + param[0] = power ? 0x01 : 0x00;
> +
> + tester_print("Powering %s controller", power ? "on" : "off");
> +
> + mgmt_send(data->mgmt, MGMT_OP_SET_POWERED, data->mgmt_index,
> + sizeof(param), param, toggle_powered_client_callback,
> + INT_TO_PTR(power), NULL);
> +}
> +
> +static void test_open_success(const void *test_data)
> +{
> + struct test_data *data = tester_get_data();
> + struct bt_hci *hci;
> +
> + data->remove_id = mgmt_register(data->mgmt, MGMT_EV_INDEX_REMOVED,
> + data->mgmt_index,
> + index_removed_callback,
> + NULL, NULL);
> +
> + hci = bt_hci_new_user_channel(data->mgmt_index);
> + if (hci) {
> + bt_hci_unref(hci);
> + return;
> + }
> +
> + mgmt_unregister(data->mgmt, data->remove_id);
> + data->remove_id = 0;
> +
> + tester_test_failed();
> +}
> +
> +static void test_open_failed(const void *test_data)
> +{
> + struct test_data *data = tester_get_data();
> + struct bt_hci *hci;
> +
> + hci = bt_hci_new_user_channel(data->mgmt_index);
> + if (!hci) {
> + tester_test_passed();
> + return;
> + }
> +
> + bt_hci_unref(hci);
> + tester_test_failed();
> +}
> +
> +#define test_user(name, data, setup, func) \
> + do { \
> + struct test_data *user; \
> + user = malloc(sizeof(struct test_data)); \
> + if (!user) \
> + break; \
> + user->hciemu_type = HCIEMU_TYPE_BREDR; \
> + user->mgmt_index = MGMT_INDEX_NONE; \
> + user->test_data = data; \
> + tester_add_full(name, data, \
> + test_pre_setup, setup, func, NULL, \
> + test_post_teardown, 2, user, test_data_free); \
> + } while (0)
> +
> +int main(int argc, char *argv[])
> +{
> + tester_init(&argc, &argv);
> +
> + test_user("User channel open - Success", NULL,
> + NULL, test_open_success);
> + test_user("User channel open - Failed", NULL,
> + setup_powered, test_open_failed);
> + test_user("User channel open - Power Toggle Success", INT_TO_PTR(true),
> + toggle_powered, test_open_success);
> +
> + return tester_run();
> +}

Applied.

--
BR
Szymon Janc

2015-05-05 13:55:37

by Szymon Janc

[permalink] [raw]
Subject: [PATCH] tools: Add initial User Channel tester

This adds basic tests only.
---
.gitignore | 1 +
Makefile.tools | 11 +-
tools/userchannel-tester.c | 333 +++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 344 insertions(+), 1 deletion(-)
create mode 100644 tools/userchannel-tester.c

diff --git a/.gitignore b/.gitignore
index 08eabac..c350f49 100644
--- a/.gitignore
+++ b/.gitignore
@@ -109,6 +109,7 @@ tools/smp-tester
tools/gap-tester
tools/rfcomm-tester
tools/bnep-tester
+tools/userchannel-tester
tools/btattach
tools/btmgmt
tools/btsnoop
diff --git a/Makefile.tools b/Makefile.tools
index 6020b01..9abe07d 100644
--- a/Makefile.tools
+++ b/Makefile.tools
@@ -43,7 +43,8 @@ noinst_PROGRAMS += emulator/btvirt emulator/b1ee emulator/hfp \
tools/mgmt-tester tools/gap-tester \
tools/l2cap-tester tools/sco-tester \
tools/smp-tester tools/hci-tester \
- tools/rfcomm-tester tools/bnep-tester
+ tools/rfcomm-tester tools/bnep-tester \
+ tools/userchannel-tester

emulator_btvirt_SOURCES = emulator/main.c monitor/bt.h \
emulator/serial.h emulator/serial.c \
@@ -135,6 +136,14 @@ tools_sco_tester_LDADD = lib/libbluetooth-internal.la \

tools_hci_tester_SOURCES = tools/hci-tester.c monitor/bt.h
tools_hci_tester_LDADD = src/libshared-glib.la @GLIB_LIBS@
+
+tools_userchannel_tester_SOURCES = tools/userchannel-tester.c monitor/bt.h \
+ emulator/hciemu.h emulator/hciemu.c \
+ emulator/btdev.h emulator/btdev.c \
+ emulator/bthost.h emulator/bthost.c \
+ emulator/smp.c
+tools_userchannel_tester_LDADD = lib/libbluetooth-internal.la \
+ src/libshared-glib.la @GLIB_LIBS@
endif

if TOOLS
diff --git a/tools/userchannel-tester.c b/tools/userchannel-tester.c
new file mode 100644
index 0000000..ec5dffd
--- /dev/null
+++ b/tools/userchannel-tester.c
@@ -0,0 +1,333 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2014-2015 Intel Corporation. All rights reserved.
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdbool.h>
+
+#include <glib.h>
+
+#include "lib/bluetooth.h"
+#include "lib/hci.h"
+#include "lib/mgmt.h"
+
+#include "monitor/bt.h"
+#include "emulator/bthost.h"
+#include "emulator/hciemu.h"
+
+#include "src/shared/tester.h"
+#include "src/shared/mgmt.h"
+#include "src/shared/hci.h"
+#include "src/shared/util.h"
+
+struct test_data {
+ struct mgmt *mgmt;
+ uint16_t mgmt_index;
+ struct hciemu *hciemu;
+ enum hciemu_type hciemu_type;
+ const void *test_data;
+ unsigned int remove_id;
+};
+
+static void mgmt_debug(const char *str, void *user_data)
+{
+ const char *prefix = user_data;
+
+ tester_print("%s%s", prefix, str);
+}
+
+static void read_info_callback(uint8_t status, uint16_t length,
+ const void *param, void *user_data)
+{
+ struct test_data *data = tester_get_data();
+ const struct mgmt_rp_read_info *rp = param;
+ char addr[18];
+ uint16_t manufacturer;
+ uint32_t supported_settings, current_settings;
+
+ tester_print("Read Info callback");
+ tester_print(" Status: 0x%02x", status);
+
+ if (status || !param) {
+ tester_pre_setup_failed();
+ return;
+ }
+
+ ba2str(&rp->bdaddr, addr);
+ manufacturer = btohs(rp->manufacturer);
+ supported_settings = btohl(rp->supported_settings);
+ current_settings = btohl(rp->current_settings);
+
+ tester_print(" Address: %s", addr);
+ tester_print(" Version: 0x%02x", rp->version);
+ tester_print(" Manufacturer: 0x%04x", manufacturer);
+ tester_print(" Supported settings: 0x%08x", supported_settings);
+ tester_print(" Current settings: 0x%08x", current_settings);
+ tester_print(" Class: 0x%02x%02x%02x",
+ rp->dev_class[2], rp->dev_class[1], rp->dev_class[0]);
+ tester_print(" Name: %s", rp->name);
+ tester_print(" Short name: %s", rp->short_name);
+
+ if (strcmp(hciemu_get_address(data->hciemu), addr)) {
+ tester_pre_setup_failed();
+ return;
+ }
+
+ tester_pre_setup_complete();
+}
+
+static void index_added_callback(uint16_t index, uint16_t length,
+ const void *param, void *user_data)
+{
+ struct test_data *data = tester_get_data();
+
+ tester_print("Index Added callback");
+ tester_print(" Index: 0x%04x", index);
+
+ if (data->mgmt_index != MGMT_INDEX_NONE)
+ return;
+
+ data->mgmt_index = index;
+
+ mgmt_send(data->mgmt, MGMT_OP_READ_INFO, data->mgmt_index, 0, NULL,
+ read_info_callback, NULL, NULL);
+}
+
+static void index_removed_callback(uint16_t index, uint16_t length,
+ const void *param, void *user_data)
+{
+ struct test_data *data = tester_get_data();
+
+ tester_print("Index Removed callback");
+ tester_print(" Index: 0x%04x", index);
+
+ if (index != data->mgmt_index)
+ return;
+
+ if (data->remove_id) {
+ mgmt_unregister(data->mgmt, data->remove_id);
+ data->remove_id = 0;
+ tester_test_passed();
+ return;
+ }
+
+ mgmt_unregister_index(data->mgmt, data->mgmt_index);
+
+ mgmt_unref(data->mgmt);
+ data->mgmt = NULL;
+
+ tester_post_teardown_complete();
+}
+
+static void read_index_list_callback(uint8_t status, uint16_t length,
+ const void *param, void *user_data)
+{
+ struct test_data *data = tester_get_data();
+
+ tester_print("Read Index List callback");
+ tester_print(" Status: 0x%02x", status);
+
+ if (status || !param) {
+ tester_pre_setup_failed();
+ return;
+ }
+
+ mgmt_register(data->mgmt, MGMT_EV_INDEX_ADDED, MGMT_INDEX_NONE,
+ index_added_callback, NULL, NULL);
+
+ data->hciemu = hciemu_new(data->hciemu_type);
+ if (!data->hciemu) {
+ tester_warn("Failed to setup HCI emulation");
+ tester_pre_setup_failed();
+ }
+
+ tester_print("New hciemu instance created");
+}
+
+static void test_pre_setup(const void *test_data)
+{
+ struct test_data *data = tester_get_data();
+
+ data->mgmt = mgmt_new_default();
+ if (!data->mgmt) {
+ tester_warn("Failed to setup management interface");
+ tester_pre_setup_failed();
+ return;
+ }
+
+ if (tester_use_debug())
+ mgmt_set_debug(data->mgmt, mgmt_debug, "mgmt: ", NULL);
+
+ mgmt_send(data->mgmt, MGMT_OP_READ_INDEX_LIST, MGMT_INDEX_NONE, 0, NULL,
+ read_index_list_callback, NULL, NULL);
+}
+
+static void test_post_teardown(const void *test_data)
+{
+ struct test_data *data = tester_get_data();
+
+ mgmt_register(data->mgmt, MGMT_EV_INDEX_REMOVED, data->mgmt_index,
+ index_removed_callback,
+ NULL, NULL);
+
+ hciemu_unref(data->hciemu);
+ data->hciemu = NULL;
+}
+
+static void test_data_free(void *test_data)
+{
+ struct test_data *data = test_data;
+
+ free(data);
+}
+
+static void setup_powered_client_callback(uint8_t status, uint16_t length,
+ const void *param, void *user_data)
+{
+ if (status != MGMT_STATUS_SUCCESS) {
+ tester_setup_failed();
+ return;
+ }
+
+ tester_print("Controller powered on");
+
+ tester_setup_complete();
+}
+
+static void setup_powered(const void *test_data)
+{
+ struct test_data *data = tester_get_data();
+ unsigned char param[] = { 0x01 };
+
+ tester_print("Powering on controller");
+
+ mgmt_send(data->mgmt, MGMT_OP_SET_POWERED, data->mgmt_index,
+ sizeof(param), param, setup_powered_client_callback,
+ NULL, NULL);
+}
+
+static void toggle_powered(const void *test_data);
+
+static void toggle_powered_client_callback(uint8_t status, uint16_t length,
+ const void *param, void *user_data)
+{
+ bool power = PTR_TO_INT(user_data);
+
+ if (status != MGMT_STATUS_SUCCESS) {
+ tester_setup_failed();
+ return;
+ }
+
+ tester_print("Controller powered %s", power ? "on" : "off");
+
+ if (power)
+ toggle_powered(false);
+ else
+ tester_setup_complete();
+}
+
+static void toggle_powered(const void *test_data)
+{
+ struct test_data *data = tester_get_data();
+ bool power = PTR_TO_INT(test_data);
+ unsigned char param[1];
+
+ param[0] = power ? 0x01 : 0x00;
+
+ tester_print("Powering %s controller", power ? "on" : "off");
+
+ mgmt_send(data->mgmt, MGMT_OP_SET_POWERED, data->mgmt_index,
+ sizeof(param), param, toggle_powered_client_callback,
+ INT_TO_PTR(power), NULL);
+}
+
+static void test_open_success(const void *test_data)
+{
+ struct test_data *data = tester_get_data();
+ struct bt_hci *hci;
+
+ data->remove_id = mgmt_register(data->mgmt, MGMT_EV_INDEX_REMOVED,
+ data->mgmt_index,
+ index_removed_callback,
+ NULL, NULL);
+
+ hci = bt_hci_new_user_channel(data->mgmt_index);
+ if (hci) {
+ bt_hci_unref(hci);
+ return;
+ }
+
+ mgmt_unregister(data->mgmt, data->remove_id);
+ data->remove_id = 0;
+
+ tester_test_failed();
+}
+
+static void test_open_failed(const void *test_data)
+{
+ struct test_data *data = tester_get_data();
+ struct bt_hci *hci;
+
+ hci = bt_hci_new_user_channel(data->mgmt_index);
+ if (!hci) {
+ tester_test_passed();
+ return;
+ }
+
+ bt_hci_unref(hci);
+ tester_test_failed();
+}
+
+#define test_user(name, data, setup, func) \
+ do { \
+ struct test_data *user; \
+ user = malloc(sizeof(struct test_data)); \
+ if (!user) \
+ break; \
+ user->hciemu_type = HCIEMU_TYPE_BREDR; \
+ user->mgmt_index = MGMT_INDEX_NONE; \
+ user->test_data = data; \
+ tester_add_full(name, data, \
+ test_pre_setup, setup, func, NULL, \
+ test_post_teardown, 2, user, test_data_free); \
+ } while (0)
+
+int main(int argc, char *argv[])
+{
+ tester_init(&argc, &argv);
+
+ test_user("User channel open - Success", NULL,
+ NULL, test_open_success);
+ test_user("User channel open - Failed", NULL,
+ setup_powered, test_open_failed);
+ test_user("User channel open - Power Toggle Success", INT_TO_PTR(true),
+ toggle_powered, test_open_success);
+
+ return tester_run();
+}
--
1.9.3