diff --git a/Makefile.tools b/Makefile.tools
index 1375b95..7a12846 100644
--- a/Makefile.tools
+++ b/Makefile.tools
src/shared/util.h src/shared/util.c \
src/shared/mgmt.h src/shared/mgmt.c \
src/shared/tester.h src/shared/tester.c
-tools_mgmt_tester_LDADD = @GLIB_LIBS@
+tools_mgmt_tester_LDADD = lib/libbluetooth-private.la @GLIB_LIBS@
tools_gap_tester_SOURCES = $(gdbus_sources) \
tools/gap-tester.c \
diff --git a/tools/mgmt-tester.c b/tools/mgmt-tester.c
index b792f29..a99402a 100644
--- a/tools/mgmt-tester.c
+++ b/tools/mgmt-tester.c
#include <config.h>
#endif
+#include <stdlib.h>
+
+#include "lib/bluetooth.h"
+#include "lib/mgmt.h"
+
#include "src/shared/tester.h"
#include "src/shared/mgmt.h"
#include "tools/hciemu.h"
+struct test_data {
+ const void *test_data;
+ uint8_t expected_version;
+ uint16_t expected_manufacturer;
+ uint32_t expected_supported_settings;
+ uint32_t initial_settings;
+ struct mgmt *mgmt;
+ uint8_t mgmt_version;
+ uint16_t mgmt_revision;
+ uint16_t mgmt_index;
+ struct hciemu *hciemu;
+};
+
+static void mgmt_debug(const char *str, void *user_data)
+{
+ const char *prefix = user_data;
+
+ tester_print("%s%s", prefix, str);
+}
+
+static void read_version_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_version *rp = param;
+
+ tester_print("Read Version callback");
+ tester_print(" Status: 0x%02x", status);
+
+ if (status || !param) {
+ tester_pre_setup_failed();
+ return;
+ }
+
+ data->mgmt_version = rp->version;
+ data->mgmt_revision = btohs(rp->revision);
+
+ tester_print(" Version %u.%u",
+ data->mgmt_version, data->mgmt_revision);
+}
+
+static void read_commands_callback(uint8_t status, uint16_t length,
+ const void *param, void *user_data)
+{
+ tester_print("Read Commands callback");
+ tester_print(" Status: 0x%02x", status);
+
+ if (status || !param) {
+ tester_pre_setup_failed();
+ return;
+ }
+}
+
+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;
+ }
+
+ if (rp->version != data->expected_version) {
+ tester_pre_setup_failed();
+ return;
+ }
+
+ if (manufacturer != data->expected_manufacturer) {
+ tester_pre_setup_failed();
+ return;
+ }
+
+ if (supported_settings != data->expected_supported_settings) {
+ tester_pre_setup_failed();
+ return;
+ }
+
+ if (current_settings != data->initial_settings) {
+ tester_pre_setup_failed();
+ return;
+ }
+
+ if (rp->dev_class[0] != 0x00 || rp->dev_class[1] != 0x00 ||
+ rp->dev_class[2] != 0x00) {
+ tester_pre_setup_failed();
+ return;
+ }
+
+ tester_pre_setup_complete();
+}
+
+static void new_settings_callback(uint16_t index, uint16_t length,
+ const void *param, void *user_data)
+{
+ tester_print("New Settings callback");
+}
+
+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);
+
+ data->mgmt_index = index;
+
+ mgmt_register(data->mgmt, MGMT_EV_NEW_SETTINGS, data->mgmt_index,
+ new_settings_callback, NULL, NULL);
+
+ 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;
+
+ 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);
+
+ mgmt_register(data->mgmt, MGMT_EV_INDEX_REMOVED, MGMT_INDEX_NONE,
+ index_removed_callback, NULL, NULL);
+
+ data->hciemu = hciemu_new();
+}
+
+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_VERSION, MGMT_INDEX_NONE, 0, NULL,
+ read_version_callback, NULL, NULL);
+
+ mgmt_send(data->mgmt, MGMT_OP_READ_COMMANDS, MGMT_INDEX_NONE, 0, NULL,
+ read_commands_callback, NULL, 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();
+
+ hciemu_unref(data->hciemu);
+ data->hciemu = NULL;
+}
+
+#define test_bredr(name, data, setup, func) \
+ do { \
+ struct test_data *user; \
+ user = malloc(sizeof(struct test_data)); \
+ if (!user) \
+ break; \
+ user->test_data = data; \
+ user->expected_version = 0x06; \
+ user->expected_manufacturer = 0x003f; \
+ user->expected_supported_settings = 0x000002ff; \
+ user->initial_settings = 0x00000080; \
+ tester_add_full(name, data, \
+ test_pre_setup, setup, func, NULL, \
+ test_post_teardown, user, free); \
+ } while (0)
+
+static void controller_setup(const void *test_data)
+{
+ tester_test_passed();
+}
+
+struct generic_data {
+ bool send_index_none;
+ uint16_t send_opcode;
+ const void *send_param;
+ uint16_t send_len;
+ uint8_t expect_status;
+};
+
+static const char dummy_data[] = { 0x00 };
+
+static const struct generic_data invalid_command_test = {
+ .send_opcode = 0xffff,
+ .expect_status = MGMT_STATUS_UNKNOWN_COMMAND,
+};
+
+static const struct generic_data read_version_invalid_param_test = {
+ .send_index_none = true,
+ .send_opcode = MGMT_OP_READ_VERSION,
+ .send_param = dummy_data,
+ .send_len = sizeof(dummy_data),
+ .expect_status = MGMT_STATUS_INVALID_PARAMS,
+};
+
+static const struct generic_data read_version_invalid_index_test = {
+ .send_opcode = MGMT_OP_READ_VERSION,
+ .expect_status = MGMT_STATUS_INVALID_INDEX,
+};
+
+static const struct generic_data read_commands_invalid_param_test = {
+ .send_index_none = true,
+ .send_opcode = MGMT_OP_READ_COMMANDS,
+ .send_param = dummy_data,
+ .send_len = sizeof(dummy_data),
+ .expect_status = MGMT_STATUS_INVALID_PARAMS,
+};
+
+static const struct generic_data read_commands_invalid_index_test = {
+ .send_opcode = MGMT_OP_READ_COMMANDS,
+ .expect_status = MGMT_STATUS_INVALID_INDEX,
+};
+
+static const struct generic_data read_index_list_invalid_param_test = {
+ .send_index_none = true,
+ .send_opcode = MGMT_OP_READ_INDEX_LIST,
+ .send_param = dummy_data,
+ .send_len = sizeof(dummy_data),
+ .expect_status = MGMT_STATUS_INVALID_PARAMS,
+};
+
+static const struct generic_data read_index_list_invalid_index_test = {
+ .send_opcode = MGMT_OP_READ_INDEX_LIST,
+ .expect_status = MGMT_STATUS_INVALID_INDEX,
+};
+
+static const struct generic_data read_info_invalid_param_test = {
+ .send_opcode = MGMT_OP_READ_INFO,
+ .send_param = dummy_data,
+ .send_len = sizeof(dummy_data),
+ .expect_status = MGMT_STATUS_INVALID_PARAMS,
+};
+
+static const struct generic_data read_info_invalid_index_test = {
+ .send_index_none = true,
+ .send_opcode = MGMT_OP_READ_INFO,
+ .expect_status = MGMT_STATUS_INVALID_INDEX,
+};
+
+static void command_generic_callback(uint8_t status, uint16_t length,
+ const void *param, void *user_data)
+{
+ struct test_data *data = tester_get_data();
+ const struct generic_data *test = data->test_data;
+
+ if (status != test->expect_status) {
+ tester_test_failed();
+ return;
+ }
+
+ tester_test_passed();
+}
+
+static void test_command_generic(const void *test_data)
+{
+ struct test_data *data = tester_get_data();
+ const struct generic_data *test = data->test_data;
+ uint16_t index;
+
+ index = test->send_index_none ? MGMT_INDEX_NONE : data->mgmt_index;
+
+ mgmt_send(data->mgmt, test->send_opcode, index,
+ test->send_len, test->send_param,
+ command_generic_callback, NULL, NULL);
+}
+
int main(int argc, char *argv[])
{
tester_init(&argc, &argv);
+ test_bredr("Controller setup", NULL, NULL, controller_setup);
+ test_bredr("Invalid command", &invalid_command_test,
+ NULL, test_command_generic);
+
+ test_bredr("Read version - Invalid parameters",
+ &read_version_invalid_param_test,
+ NULL, test_command_generic);
+ test_bredr("Read version - Invalid index",
+ &read_version_invalid_index_test,
+ NULL, test_command_generic);
+ test_bredr("Read commands - Invalid parameters",
+ &read_commands_invalid_param_test,
+ NULL, test_command_generic);
+ test_bredr("Read commands - Invalid index",
+ &read_commands_invalid_index_test,
+ NULL, test_command_generic);
+ test_bredr("Read index list - Invalid parameters",
+ &read_index_list_invalid_param_test,
+ NULL, test_command_generic);
+ test_bredr("Read index list - Invalid index",
+ &read_index_list_invalid_index_test,
+ NULL, test_command_generic);
+ test_bredr("Read info - Invalid parameters",
+ &read_info_invalid_param_test,
+ NULL, test_command_generic);
+ test_bredr("Read info - Invalid index",
+ &read_info_invalid_index_test,
+ NULL, test_command_generic);
+
return tester_run();
}