blob: 8579e7639b13e0e06b719f8eb392673fcdef6aec [file] [log] [blame]
/*
*
* BlueZ - Bluetooth protocol stack for Linux
*
* Copyright (C) 2012 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 "lib/bluetooth.h"
#include "lib/mgmt.h"
#include "monitor/bt.h"
#include "src/shared/tester.h"
#include "src/shared/mgmt.h"
#include "src/shared/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;
struct mgmt *mgmt_alt;
uint8_t mgmt_version;
uint16_t mgmt_revision;
uint16_t mgmt_index;
struct hciemu *hciemu;
bool hci_commands_complete;
};
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 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_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_unregister_index(data->mgmt_alt, data->mgmt_index);
mgmt_unref(data->mgmt);
data->mgmt = NULL;
mgmt_unref(data->mgmt_alt);
data->mgmt_alt = 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;
}
data->mgmt_alt = mgmt_new_default();
if (!data->mgmt_alt) {
tester_warn("Failed to setup alternate management interface");
tester_pre_setup_failed();
mgmt_unref(data->mgmt);
data->mgmt = NULL;
return;
}
if (tester_use_debug()) {
mgmt_set_debug(data->mgmt, mgmt_debug, "mgmt: ", NULL);
mgmt_set_debug(data->mgmt_alt, mgmt_debug, "mgmt-alt: ", 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; \
user->hci_commands_complete = false; \
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;
const void *expect_param;
uint16_t expect_len;
uint32_t expect_settings_set;
uint16_t expect_hci_command;
const void *expect_hci_param;
uint8_t expect_hci_len;
};
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 const char set_powered_on_param[] = { 0x01 };
static const char set_powered_invalid_param[] = { 0x02 };
static const char set_powered_garbage_param[] = { 0x01, 0x00 };
static const char set_powered_settings_param[] = { 0x81, 0x00, 0x00, 0x00 };
static const struct generic_data set_powered_on_success_test = {
.send_opcode = MGMT_OP_SET_POWERED,
.send_param = set_powered_on_param,
.send_len = sizeof(set_powered_on_param),
.expect_status = MGMT_STATUS_SUCCESS,
.expect_param = set_powered_settings_param,
.expect_len = sizeof(set_powered_settings_param),
.expect_settings_set = MGMT_SETTING_POWERED,
};
static const struct generic_data set_powered_on_invalid_param_test_1 = {
.send_opcode = MGMT_OP_SET_POWERED,
.expect_status = MGMT_STATUS_INVALID_PARAMS,
};
static const struct generic_data set_powered_on_invalid_param_test_2 = {
.send_opcode = MGMT_OP_SET_POWERED,
.send_param = set_powered_invalid_param,
.send_len = sizeof(set_powered_invalid_param),
.expect_status = MGMT_STATUS_INVALID_PARAMS,
};
static const struct generic_data set_powered_on_invalid_param_test_3 = {
.send_opcode = MGMT_OP_SET_POWERED,
.send_param = set_powered_garbage_param,
.send_len = sizeof(set_powered_garbage_param),
.expect_status = MGMT_STATUS_INVALID_PARAMS,
};
static const struct generic_data set_powered_on_invalid_index_test = {
.send_index_none = true,
.send_opcode = MGMT_OP_SET_POWERED,
.send_param = set_powered_on_param,
.send_len = sizeof(set_powered_on_param),
.expect_status = MGMT_STATUS_INVALID_INDEX,
};
static const char set_connectable_on_param[] = { 0x01 };
static const char set_connectable_invalid_param[] = { 0x02 };
static const char set_connectable_garbage_param[] = { 0x01, 0x00 };
static const char set_connectable_settings_param_1[] = { 0x82, 0x00, 0x00, 0x00 };
static const char set_connectable_settings_param_2[] = { 0x83, 0x00, 0x00, 0x00 };
static const char set_connectable_scan_enable_param[] = { 0x02 };
static const struct generic_data set_connectable_on_success_test_1 = {
.send_opcode = MGMT_OP_SET_CONNECTABLE,
.send_param = set_connectable_on_param,
.send_len = sizeof(set_connectable_on_param),
.expect_status = MGMT_STATUS_SUCCESS,
.expect_param = set_connectable_settings_param_1,
.expect_len = sizeof(set_connectable_settings_param_1),
.expect_settings_set = MGMT_SETTING_CONNECTABLE,
};
static const struct generic_data set_connectable_on_success_test_2 = {
.send_opcode = MGMT_OP_SET_CONNECTABLE,
.send_param = set_connectable_on_param,
.send_len = sizeof(set_connectable_on_param),
.expect_status = MGMT_STATUS_SUCCESS,
.expect_param = set_connectable_settings_param_2,
.expect_len = sizeof(set_connectable_settings_param_2),
.expect_settings_set = MGMT_SETTING_CONNECTABLE,
.expect_hci_command = BT_HCI_CMD_WRITE_SCAN_ENABLE,
.expect_hci_param = set_connectable_scan_enable_param,
.expect_hci_len = sizeof(set_connectable_scan_enable_param),
};
static const struct generic_data set_connectable_on_invalid_param_test_1 = {
.send_opcode = MGMT_OP_SET_CONNECTABLE,
.expect_status = MGMT_STATUS_INVALID_PARAMS,
};
static const struct generic_data set_connectable_on_invalid_param_test_2 = {
.send_opcode = MGMT_OP_SET_CONNECTABLE,
.send_param = set_connectable_invalid_param,
.send_len = sizeof(set_connectable_invalid_param),
.expect_status = MGMT_STATUS_INVALID_PARAMS,
};
static const struct generic_data set_connectable_on_invalid_param_test_3 = {
.send_opcode = MGMT_OP_SET_CONNECTABLE,
.send_param = set_connectable_garbage_param,
.send_len = sizeof(set_connectable_garbage_param),
.expect_status = MGMT_STATUS_INVALID_PARAMS,
};
static const struct generic_data set_connectable_on_invalid_index_test = {
.send_index_none = true,
.send_opcode = MGMT_OP_SET_CONNECTABLE,
.send_param = set_connectable_on_param,
.send_len = sizeof(set_connectable_on_param),
.expect_status = MGMT_STATUS_INVALID_INDEX,
};
static const char set_pairable_on_param[] = { 0x01 };
static const char set_pairable_invalid_param[] = { 0x02 };
static const char set_pairable_garbage_param[] = { 0x01, 0x00 };
static const char set_pairable_settings_param[] = { 0x90, 0x00, 0x00, 0x00 };
static const struct generic_data set_pairable_on_success_test = {
.send_opcode = MGMT_OP_SET_PAIRABLE,
.send_param = set_pairable_on_param,
.send_len = sizeof(set_pairable_on_param),
.expect_status = MGMT_STATUS_SUCCESS,
.expect_param = set_pairable_settings_param,
.expect_len = sizeof(set_pairable_settings_param),
.expect_settings_set = MGMT_SETTING_PAIRABLE,
};
static const struct generic_data set_pairable_on_invalid_param_test_1 = {
.send_opcode = MGMT_OP_SET_PAIRABLE,
.expect_status = MGMT_STATUS_INVALID_PARAMS,
};
static const struct generic_data set_pairable_on_invalid_param_test_2 = {
.send_opcode = MGMT_OP_SET_PAIRABLE,
.send_param = set_pairable_invalid_param,
.send_len = sizeof(set_pairable_invalid_param),
.expect_status = MGMT_STATUS_INVALID_PARAMS,
};
static const struct generic_data set_pairable_on_invalid_param_test_3 = {
.send_opcode = MGMT_OP_SET_PAIRABLE,
.send_param = set_pairable_garbage_param,
.send_len = sizeof(set_pairable_garbage_param),
.expect_status = MGMT_STATUS_INVALID_PARAMS,
};
static const struct generic_data set_pairable_on_invalid_index_test = {
.send_index_none = true,
.send_opcode = MGMT_OP_SET_PAIRABLE,
.send_param = set_pairable_on_param,
.send_len = sizeof(set_pairable_on_param),
.expect_status = MGMT_STATUS_INVALID_INDEX,
};
static const uint8_t set_discoverable_on_param[] = { 0x01, 0x00, 0x00 };
static const uint8_t set_discoverable_timeout_param[] = { 0x01, 0x0a, 0x00 };
static const uint8_t set_discoverable_invalid_param[] = { 0x02, 0x00, 0x00 };
static const uint8_t set_discoverable_off_param[] = { 0x00, 0x00, 0x00 };
static const uint8_t set_discoverable_offtimeout_param[] = { 0x00, 0x01, 0x00 };
static const uint8_t set_discoverable_garbage_param[] = { 0x01, 0x00, 0x00, 0x00 };
static const uint8_t set_discoverable_on_settings_param_1[] = { 0x8a, 0x00, 0x00, 0x00 };
static const uint8_t set_discoverable_on_settings_param_2[] = { 0x8b, 0x00, 0x00, 0x00 };
static const uint8_t set_discoverable_off_settings_param_1[] = { 0x82, 0x00, 0x00, 0x00 };
static const uint8_t set_discoverable_off_settings_param_2[] = { 0x83, 0x00, 0x00, 0x00 };
static const uint8_t set_discoverable_on_scan_enable_param[] = { 0x03 };
static const uint8_t set_discoverable_off_scan_enable_param[] = { 0x02 };
static const struct generic_data set_discoverable_on_invalid_param_test_1 = {
.send_opcode = MGMT_OP_SET_DISCOVERABLE,
.expect_status = MGMT_STATUS_INVALID_PARAMS,
};
static const struct generic_data set_discoverable_on_invalid_param_test_2 = {
.send_opcode = MGMT_OP_SET_DISCOVERABLE,
.send_param = set_discoverable_invalid_param,
.send_len = sizeof(set_discoverable_invalid_param),
.expect_status = MGMT_STATUS_INVALID_PARAMS,
};
static const struct generic_data set_discoverable_on_invalid_param_test_3 = {
.send_opcode = MGMT_OP_SET_DISCOVERABLE,
.send_param = set_discoverable_garbage_param,
.send_len = sizeof(set_discoverable_garbage_param),
.expect_status = MGMT_STATUS_INVALID_PARAMS,
};
static const struct generic_data set_discoverable_on_invalid_param_test_4 = {
.send_opcode = MGMT_OP_SET_DISCOVERABLE,
.send_param = set_discoverable_offtimeout_param,
.send_len = sizeof(set_discoverable_offtimeout_param),
.expect_status = MGMT_STATUS_INVALID_PARAMS,
};
static const struct generic_data set_discoverable_on_not_powered_test_1 = {
.send_opcode = MGMT_OP_SET_DISCOVERABLE,
.send_param = set_discoverable_timeout_param,
.send_len = sizeof(set_discoverable_timeout_param),
.expect_status = MGMT_STATUS_NOT_POWERED,
};
static const struct generic_data set_discoverable_on_rejected_test_1 = {
.send_opcode = MGMT_OP_SET_DISCOVERABLE,
.send_param = set_discoverable_on_param,
.send_len = sizeof(set_discoverable_on_param),
.expect_status = MGMT_STATUS_REJECTED,
};
static const struct generic_data set_discoverable_on_rejected_test_2 = {
.send_opcode = MGMT_OP_SET_DISCOVERABLE,
.send_param = set_discoverable_on_param,
.send_len = sizeof(set_discoverable_on_param),
.expect_status = MGMT_STATUS_REJECTED,
};
static const struct generic_data set_discoverable_on_rejected_test_3 = {
.send_opcode = MGMT_OP_SET_DISCOVERABLE,
.send_param = set_discoverable_timeout_param,
.send_len = sizeof(set_discoverable_timeout_param),
.expect_status = MGMT_STATUS_REJECTED,
};
static const struct generic_data set_discoverable_on_success_test_1 = {
.send_opcode = MGMT_OP_SET_DISCOVERABLE,
.send_param = set_discoverable_on_param,
.send_len = sizeof(set_discoverable_on_param),
.expect_status = MGMT_STATUS_SUCCESS,
.expect_param = set_discoverable_on_settings_param_1,
.expect_len = sizeof(set_discoverable_on_settings_param_1),
.expect_settings_set = MGMT_SETTING_DISCOVERABLE,
};
static const struct generic_data set_discoverable_on_success_test_2 = {
.send_opcode = MGMT_OP_SET_DISCOVERABLE,
.send_param = set_discoverable_on_param,
.send_len = sizeof(set_discoverable_on_param),
.expect_status = MGMT_STATUS_SUCCESS,
.expect_param = set_discoverable_on_settings_param_2,
.expect_len = sizeof(set_discoverable_on_settings_param_2),
.expect_settings_set = MGMT_SETTING_DISCOVERABLE,
.expect_hci_command = BT_HCI_CMD_WRITE_SCAN_ENABLE,
.expect_hci_param = set_discoverable_on_scan_enable_param,
.expect_hci_len = sizeof(set_discoverable_on_scan_enable_param),
};
static const struct generic_data set_discoverable_off_success_test_1 = {
.send_opcode = MGMT_OP_SET_DISCOVERABLE,
.send_param = set_discoverable_off_param,
.send_len = sizeof(set_discoverable_off_param),
.expect_status = MGMT_STATUS_SUCCESS,
.expect_param = set_discoverable_off_settings_param_1,
.expect_len = sizeof(set_discoverable_off_settings_param_1),
};
static const struct generic_data set_discoverable_off_success_test_2 = {
.send_opcode = MGMT_OP_SET_DISCOVERABLE,
.send_param = set_discoverable_off_param,
.send_len = sizeof(set_discoverable_off_param),
.expect_status = MGMT_STATUS_SUCCESS,
.expect_param = set_discoverable_off_settings_param_2,
.expect_len = sizeof(set_discoverable_off_settings_param_2),
.expect_hci_command = BT_HCI_CMD_WRITE_SCAN_ENABLE,
.expect_hci_param = set_discoverable_off_scan_enable_param,
.expect_hci_len = sizeof(set_discoverable_off_scan_enable_param),
};
static const char set_link_sec_on_param[] = { 0x01 };
static const char set_link_sec_invalid_param[] = { 0x02 };
static const char set_link_sec_garbage_param[] = { 0x01, 0x00 };
static const char set_link_sec_settings_param_1[] = { 0xa0, 0x00, 0x00, 0x00 };
static const char set_link_sec_settings_param_2[] = { 0xa1, 0x00, 0x00, 0x00 };
static const char set_link_sec_auth_enable_param[] = { 0x01 };
static const struct generic_data set_link_sec_on_success_test_1 = {
.send_opcode = MGMT_OP_SET_LINK_SECURITY,
.send_param = set_link_sec_on_param,
.send_len = sizeof(set_link_sec_on_param),
.expect_status = MGMT_STATUS_SUCCESS,
.expect_param = set_link_sec_settings_param_1,
.expect_len = sizeof(set_link_sec_settings_param_1),
.expect_settings_set = MGMT_SETTING_LINK_SECURITY,
};
static const struct generic_data set_link_sec_on_success_test_2 = {
.send_opcode = MGMT_OP_SET_LINK_SECURITY,
.send_param = set_link_sec_on_param,
.send_len = sizeof(set_link_sec_on_param),
.expect_status = MGMT_STATUS_SUCCESS,
.expect_param = set_link_sec_settings_param_2,
.expect_len = sizeof(set_link_sec_settings_param_2),
.expect_settings_set = MGMT_SETTING_LINK_SECURITY,
.expect_hci_command = BT_HCI_CMD_WRITE_AUTH_ENABLE,
.expect_hci_param = set_link_sec_auth_enable_param,
.expect_hci_len = sizeof(set_link_sec_auth_enable_param),
};
static const struct generic_data set_link_sec_on_invalid_param_test_1 = {
.send_opcode = MGMT_OP_SET_LINK_SECURITY,
.expect_status = MGMT_STATUS_INVALID_PARAMS,
};
static const struct generic_data set_link_sec_on_invalid_param_test_2 = {
.send_opcode = MGMT_OP_SET_LINK_SECURITY,
.send_param = set_link_sec_invalid_param,
.send_len = sizeof(set_link_sec_invalid_param),
.expect_status = MGMT_STATUS_INVALID_PARAMS,
};
static const struct generic_data set_link_sec_on_invalid_param_test_3 = {
.send_opcode = MGMT_OP_SET_LINK_SECURITY,
.send_param = set_link_sec_garbage_param,
.send_len = sizeof(set_link_sec_garbage_param),
.expect_status = MGMT_STATUS_INVALID_PARAMS,
};
static const struct generic_data set_link_sec_on_invalid_index_test = {
.send_index_none = true,
.send_opcode = MGMT_OP_SET_LINK_SECURITY,
.send_param = set_link_sec_on_param,
.send_len = sizeof(set_link_sec_on_param),
.expect_status = MGMT_STATUS_INVALID_INDEX,
};
static void setup_powered_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_discoverable(const void *test_data)
{
struct test_data *data = tester_get_data();
unsigned char param[] = { 0x01 };
unsigned char discov_param[] = { 0x01, 0x00, 0x00 };
tester_print("Powering on connectable controller");
mgmt_send(data->mgmt, MGMT_OP_SET_CONNECTABLE, data->mgmt_index,
sizeof(param), param,
NULL, NULL, NULL);
mgmt_send(data->mgmt, MGMT_OP_SET_DISCOVERABLE, data->mgmt_index,
sizeof(discov_param), discov_param,
NULL, NULL, NULL);
mgmt_send(data->mgmt, MGMT_OP_SET_POWERED, data->mgmt_index,
sizeof(param), param,
setup_powered_callback, NULL, NULL);
}
static void setup_powered_connectable(const void *test_data)
{
struct test_data *data = tester_get_data();
unsigned char param[] = { 0x01 };
tester_print("Powering on connectable controller");
mgmt_send(data->mgmt, MGMT_OP_SET_CONNECTABLE, data->mgmt_index,
sizeof(param), param,
NULL, NULL, NULL);
mgmt_send(data->mgmt, MGMT_OP_SET_POWERED, data->mgmt_index,
sizeof(param), param,
setup_powered_callback, NULL, NULL);
}
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_callback, NULL, NULL);
}
static void setup_connectable_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 connectable on");
tester_setup_complete();
}
static void setup_connectable(const void *test_data)
{
struct test_data *data = tester_get_data();
unsigned char param[] = { 0x01 };
tester_print("Setting controller connectable");
mgmt_send(data->mgmt, MGMT_OP_SET_CONNECTABLE, data->mgmt_index,
sizeof(param), param,
setup_connectable_callback, NULL, NULL);
}
static void command_generic_new_settings(uint16_t index, uint16_t length,
const void *param, void *user_data)
{
struct test_data *data = tester_get_data();
tester_print("New settings event received");
mgmt_unregister_index(data->mgmt, index);
tester_test_failed();
}
static void command_generic_new_settings_alt(uint16_t index, uint16_t length,
const void *param, void *user_data)
{
struct test_data *data = tester_get_data();
const struct generic_data *test = data->test_data;
uint32_t settings;
if (length != 4) {
tester_warn("Invalid parameter size for new settings event");
tester_test_failed();
return;
}
settings = bt_get_le32(param);
tester_print("New settings 0x%08x received", settings);
if (!test->expect_settings_set)
return;
if ((settings & test->expect_settings_set) != test->expect_settings_set)
return;
tester_print("Unregistering new settings notification");
mgmt_unregister_index(data->mgmt_alt, index);
if (test->expect_hci_command && !data->hci_commands_complete) {
tester_warn("Settings received without expected HCI command");
tester_test_failed();
return;
}
tester_test_passed();
}
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;
tester_print("Command 0x%04x finished with status 0x%02x",
test->send_opcode, status);
if (status != test->expect_status) {
tester_test_failed();
return;
}
if (length != test->expect_len) {
tester_test_failed();
return;
}
if (test->expect_param && test->expect_len > 0 &&
memcmp(param, test->expect_param, length)) {
tester_test_failed();
return;
}
if (test->expect_settings_set)
return;
if (test->expect_hci_command && !data->hci_commands_complete) {
tester_warn("Command completed without expected HCI command");
tester_test_failed();
return;
}
tester_test_passed();
}
static void command_hci_callback(uint16_t opcode, const void *param,
uint8_t length, void *user_data)
{
struct test_data *data = user_data;
const struct generic_data *test = data->test_data;
tester_print("HCI Command 0x%04x length %u", opcode, length);
if (opcode != test->expect_hci_command)
return;
if (length != test->expect_hci_len) {
tester_warn("Invalid parameter size for HCI command");
tester_test_failed();
return;
}
if (memcmp(param, test->expect_hci_param, length) != 0) {
tester_warn("Unexpected HCI command parameter value");
tester_test_failed();
return;
}
data->hci_commands_complete = true;
}
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;
if (test->expect_settings_set) {
tester_print("Registering new settings notification");
mgmt_register(data->mgmt, MGMT_EV_NEW_SETTINGS, index,
command_generic_new_settings, NULL, NULL);
mgmt_register(data->mgmt_alt, MGMT_EV_NEW_SETTINGS, index,
command_generic_new_settings_alt, NULL, NULL);
}
if (test->expect_hci_command) {
tester_print("Registering HCI command callback");
hciemu_add_master_post_command_hook(data->hciemu,
command_hci_callback, data);
}
tester_print("Sending command 0x%04x", test->send_opcode);
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);
test_bredr("Set powered on - Success",
&set_powered_on_success_test,
NULL, test_command_generic);
test_bredr("Set powered on - Invalid parameters 1",
&set_powered_on_invalid_param_test_1,
NULL, test_command_generic);
test_bredr("Set powered on - Invalid parameters 2",
&set_powered_on_invalid_param_test_2,
NULL, test_command_generic);
test_bredr("Set powered on - Invalid parameters 3",
&set_powered_on_invalid_param_test_3,
NULL, test_command_generic);
test_bredr("Set powered on - Invalid index",
&set_powered_on_invalid_index_test,
NULL, test_command_generic);
test_bredr("Set connectable on - Success 1",
&set_connectable_on_success_test_1,
NULL, test_command_generic);
test_bredr("Set connectable on - Success 2",
&set_connectable_on_success_test_2,
setup_powered, test_command_generic);
test_bredr("Set connectable on - Invalid parameters 1",
&set_connectable_on_invalid_param_test_1,
NULL, test_command_generic);
test_bredr("Set connectable on - Invalid parameters 2",
&set_connectable_on_invalid_param_test_2,
NULL, test_command_generic);
test_bredr("Set connectable on - Invalid parameters 3",
&set_connectable_on_invalid_param_test_3,
NULL, test_command_generic);
test_bredr("Set connectable on - Invalid index",
&set_connectable_on_invalid_index_test,
NULL, test_command_generic);
test_bredr("Set pairable on - Success",
&set_pairable_on_success_test,
NULL, test_command_generic);
test_bredr("Set pairable on - Invalid parameters 1",
&set_pairable_on_invalid_param_test_1,
NULL, test_command_generic);
test_bredr("Set pairable on - Invalid parameters 2",
&set_pairable_on_invalid_param_test_2,
NULL, test_command_generic);
test_bredr("Set pairable on - Invalid parameters 3",
&set_pairable_on_invalid_param_test_3,
NULL, test_command_generic);
test_bredr("Set pairable on - Invalid index",
&set_pairable_on_invalid_index_test,
NULL, test_command_generic);
test_bredr("Set discoverable on - Invalid parameters 1",
&set_discoverable_on_invalid_param_test_1,
NULL, test_command_generic);
test_bredr("Set discoverable on - Invalid parameters 2",
&set_discoverable_on_invalid_param_test_2,
NULL, test_command_generic);
test_bredr("Set discoverable on - Invalid parameters 3",
&set_discoverable_on_invalid_param_test_3,
NULL, test_command_generic);
test_bredr("Set discoverable on - Invalid parameters 4",
&set_discoverable_on_invalid_param_test_4,
NULL, test_command_generic);
test_bredr("Set discoverable on - Not powered 1",
&set_discoverable_on_not_powered_test_1,
NULL, test_command_generic);
test_bredr("Set discoverable on - Not powered 1",
&set_discoverable_on_not_powered_test_1,
NULL, test_command_generic);
test_bredr("Set discoverable on - Not powered 2",
&set_discoverable_on_not_powered_test_1,
setup_connectable, test_command_generic);
test_bredr("Set discoverable on - Rejected 1",
&set_discoverable_on_rejected_test_1,
setup_powered, test_command_generic);
test_bredr("Set discoverable on - Rejected 2",
&set_discoverable_on_rejected_test_2,
setup_powered, test_command_generic);
test_bredr("Set discoverable on - Rejected 3",
&set_discoverable_on_rejected_test_3,
setup_powered, test_command_generic);
test_bredr("Set discoverable on - Success 1",
&set_discoverable_on_success_test_1,
setup_connectable, test_command_generic);
test_bredr("Set discoverable on - Success 2",
&set_discoverable_on_success_test_2,
setup_powered_connectable, test_command_generic);
test_bredr("Set discoverable off - Success 1",
&set_discoverable_off_success_test_1,
setup_connectable, test_command_generic);
test_bredr("Set discoverable off - Success 2",
&set_discoverable_off_success_test_2,
setup_powered_discoverable,
test_command_generic);
test_bredr("Set link security on - Success 1",
&set_link_sec_on_success_test_1,
NULL, test_command_generic);
test_bredr("Set link security on - Success 2",
&set_link_sec_on_success_test_2,
setup_powered, test_command_generic);
test_bredr("Set link security on - Invalid parameters 1",
&set_link_sec_on_invalid_param_test_1,
NULL, test_command_generic);
test_bredr("Set link security on - Invalid parameters 2",
&set_link_sec_on_invalid_param_test_2,
NULL, test_command_generic);
test_bredr("Set link security on - Invalid parameters 3",
&set_link_sec_on_invalid_param_test_3,
NULL, test_command_generic);
test_bredr("Set link security on - Invalid index",
&set_link_sec_on_invalid_index_test,
NULL, test_command_generic);
return tester_run();
}