mirror of
https://git.kernel.org/pub/scm/bluetooth/bluez.git
synced 2024-12-19 08:53:29 +08:00
0a259dd05b
This patch adds SPDX License Identifier and removes the license text. ------------------------------------- License COUNT ------------------------------------- GPL-2.0-or-later : 97 LGPL-2.1-or-later : 38 GPL-2.0-only : 2 License: GPL-2.0-or-later tools/l2cap-tester.c tools/hcisecfilter.c tools/ciptool.c tools/btsnoop.c tools/check-selftest.c tools/btpclientctl.c tools/hci-tester.c tools/hcitool.c tools/btiotest.c tools/oobtest.c tools/btinfo.c tools/hwdb.c tools/hciattach_bcm43xx.c tools/mgmt-tester.c tools/hex2hcd.c tools/hciattach_st.c tools/smp-tester.c tools/bluetooth-player.c tools/hciattach_tialt.c tools/gap-tester.c tools/bluemoon.c tools/bneptest.c tools/gatt-service.c tools/rctest.c tools/rfcomm-tester.c tools/hcieventmask.c tools/hciattach_ti.c tools/seq2bseq.c tools/scotest.c tools/bcmfw.c tools/hciconfig.c tools/btattach.c tools/l2ping.c tools/obexctl.c tools/l2test.c tools/hciattach_intel.c tools/hciattach.h tools/create-image.c tools/bnep-tester.c tools/userchan-tester.c tools/rfcomm.c tools/btmon-logger.c tools/hcidump.c tools/rtlfw.c tools/hciattach_qualcomm.c tools/btproxy.c tools/nokfw.c tools/hciattach_ath3k.c tools/3dsp.c tools/bdaddr.c tools/sco-tester.c tools/hciattach.c tools/amptest.c tools/btgatt-server.c tools/btgatt-client.c tools/cltest.c tools/ibeacon.c tools/mcaptest.c tools/hid2hci.c tools/btmgmt.c tools/advtest.c tools/eddystone.c tools/avtest.c tools/mpris-proxy.c tools/avinfo.c tools/sdptool.c tools/btconfig.c tools/update_compids.sh tools/parser/parser.h tools/parser/obex.c tools/parser/amp.c tools/parser/sdp.c tools/parser/tcpip.c tools/parser/sap.c tools/parser/cmtp.c tools/parser/avctp.c tools/parser/lmp.c tools/parser/ppp.c tools/parser/rfcomm.h tools/parser/hci.c tools/parser/sdp.h tools/parser/parser.c tools/parser/rfcomm.c tools/parser/avdtp.c tools/parser/avrcp.c tools/parser/ericsson.c tools/parser/hcrp.c tools/parser/bpa.c tools/parser/hidp.c tools/parser/bnep.c tools/parser/capi.c tools/parser/att.c tools/parser/l2cap.c tools/parser/smp.c tools/parser/csr.c tools/parser/l2cap.h tools/parse_companies.pl License: LGPL-2.1-or-later tools/test-runner.c tools/btpclient.c tools/meshctl.c tools/mesh-cfgclient.c tools/mesh/model.h tools/mesh/util.h tools/mesh/config-model.h tools/mesh/cfgcli.h tools/mesh/mesh-db.c tools/mesh/mesh-db.h tools/mesh/keys.c tools/mesh/util.c tools/mesh/agent.h tools/mesh/remote.c tools/mesh/keys.h tools/mesh/agent.c tools/mesh/cfgcli.c tools/mesh/remote.h tools/mesh-gatt/prov.c tools/mesh-gatt/util.h tools/mesh-gatt/prov.h tools/mesh-gatt/net.c tools/mesh-gatt/util.c tools/mesh-gatt/prov-db.h tools/mesh-gatt/crypto.c tools/mesh-gatt/crypto.h tools/mesh-gatt/gatt.c tools/mesh-gatt/config-server.c tools/mesh-gatt/keys.h tools/mesh-gatt/onoff-model.c tools/mesh-gatt/net.h tools/mesh-gatt/gatt.h tools/mesh-gatt/node.c tools/mesh-gatt/config-client.c tools/mesh-gatt/mesh-net.h tools/mesh-gatt/node.h tools/mesh-gatt/onoff-model.h tools/mesh-gatt/prov-db.c License: GPL-2.0-only tools/obex-server-tool.c tools/obex-client-tool.c
974 lines
24 KiB
C
974 lines
24 KiB
C
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
/*
|
|
*
|
|
* BlueZ - Bluetooth protocol stack for Linux
|
|
*
|
|
* Copyright (C) 2013 Intel Corporation. All rights reserved.
|
|
*
|
|
*
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include <config.h>
|
|
#endif
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include "monitor/bt.h"
|
|
#include "src/shared/hci.h"
|
|
#include "src/shared/util.h"
|
|
#include "src/shared/ecc.h"
|
|
#include "src/shared/tester.h"
|
|
|
|
struct user_data {
|
|
const void *test_data;
|
|
uint16_t index_ut;
|
|
uint16_t index_lt;
|
|
struct bt_hci *hci_ut; /* Upper Tester / IUT */
|
|
struct bt_hci *hci_lt; /* Lower Tester / Reference */
|
|
|
|
uint8_t bdaddr_ut[6];
|
|
uint8_t bdaddr_lt[6];
|
|
uint16_t handle_ut;
|
|
};
|
|
|
|
struct le_keys {
|
|
uint8_t remote_sk[32];
|
|
uint8_t local_pk[64];
|
|
} key_test_data;
|
|
|
|
static void swap_buf(const uint8_t *src, uint8_t *dst, uint16_t len)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < len; i++)
|
|
dst[len - 1 - i] = src[i];
|
|
}
|
|
|
|
static void test_debug(const char *str, void *user_data)
|
|
{
|
|
tester_debug("%s", str);
|
|
}
|
|
|
|
static void test_pre_setup_lt_address(const void *data, uint8_t size,
|
|
void *user_data)
|
|
{
|
|
struct user_data *user = tester_get_data();
|
|
const struct bt_hci_rsp_read_bd_addr *rsp = data;
|
|
|
|
if (rsp->status) {
|
|
tester_warn("Read lower tester address failed (0x%02x)",
|
|
rsp->status);
|
|
tester_pre_setup_failed();
|
|
return;
|
|
}
|
|
|
|
memcpy(user->bdaddr_lt, rsp->bdaddr, 6);
|
|
|
|
tester_pre_setup_complete();
|
|
}
|
|
|
|
static void test_pre_setup_lt_complete(const void *data, uint8_t size,
|
|
void *user_data)
|
|
{
|
|
struct user_data *user = tester_get_data();
|
|
uint8_t status = *((uint8_t *) data);
|
|
|
|
if (status) {
|
|
tester_warn("Reset lower tester failed (0x%02x)", status);
|
|
tester_pre_setup_failed();
|
|
return;
|
|
}
|
|
|
|
if (!bt_hci_send(user->hci_lt, BT_HCI_CMD_READ_BD_ADDR, NULL, 0,
|
|
test_pre_setup_lt_address, NULL, NULL)) {
|
|
tester_warn("Failed to read lower tester address");
|
|
tester_pre_setup_failed();
|
|
return;
|
|
}
|
|
}
|
|
|
|
static void test_pre_setup_ut_address(const void *data, uint8_t size,
|
|
void *user_data)
|
|
{
|
|
struct user_data *user = tester_get_data();
|
|
const struct bt_hci_rsp_read_bd_addr *rsp = data;
|
|
|
|
if (rsp->status) {
|
|
tester_warn("Read upper tester address failed (0x%02x)",
|
|
rsp->status);
|
|
tester_pre_setup_failed();
|
|
return;
|
|
}
|
|
|
|
memcpy(user->bdaddr_ut, rsp->bdaddr, 6);
|
|
|
|
user->hci_lt = bt_hci_new_user_channel(user->index_lt);
|
|
if (!user->hci_lt) {
|
|
tester_warn("Failed to setup lower tester user channel");
|
|
tester_pre_setup_failed();
|
|
return;
|
|
}
|
|
|
|
if (!bt_hci_send(user->hci_lt, BT_HCI_CMD_RESET, NULL, 0,
|
|
test_pre_setup_lt_complete, NULL, NULL)) {
|
|
tester_warn("Failed to reset lower tester");
|
|
tester_pre_setup_failed();
|
|
return;
|
|
}
|
|
}
|
|
|
|
static void test_pre_setup_ut_complete(const void *data, uint8_t size,
|
|
void *user_data)
|
|
{
|
|
struct user_data *user = tester_get_data();
|
|
uint8_t status = *((uint8_t *) data);
|
|
|
|
if (status) {
|
|
tester_warn("Reset upper tester failed (0x%02x)", status);
|
|
tester_pre_setup_failed();
|
|
return;
|
|
}
|
|
|
|
if (user->index_lt == 0xffff) {
|
|
tester_pre_setup_complete();
|
|
return;
|
|
}
|
|
|
|
if (!bt_hci_send(user->hci_ut, BT_HCI_CMD_READ_BD_ADDR, NULL, 0,
|
|
test_pre_setup_ut_address, NULL, NULL)) {
|
|
tester_warn("Failed to read upper tester address");
|
|
tester_pre_setup_failed();
|
|
return;
|
|
}
|
|
}
|
|
|
|
static void test_pre_setup(const void *test_data)
|
|
{
|
|
struct user_data *user = tester_get_data();
|
|
|
|
user->hci_ut = bt_hci_new_user_channel(user->index_ut);
|
|
if (!user->hci_ut) {
|
|
tester_warn("Failed to setup upper tester user channel");
|
|
tester_pre_setup_failed();
|
|
return;
|
|
}
|
|
|
|
if (!bt_hci_send(user->hci_ut, BT_HCI_CMD_RESET, NULL, 0,
|
|
test_pre_setup_ut_complete, NULL, NULL)) {
|
|
tester_warn("Failed to reset upper tester");
|
|
tester_pre_setup_failed();
|
|
return;
|
|
}
|
|
}
|
|
|
|
static void test_post_teardown(const void *test_data)
|
|
{
|
|
struct user_data *user = tester_get_data();
|
|
|
|
bt_hci_unref(user->hci_lt);
|
|
user->hci_lt = NULL;
|
|
|
|
bt_hci_unref(user->hci_ut);
|
|
user->hci_ut = NULL;
|
|
|
|
tester_post_teardown_complete();
|
|
}
|
|
|
|
static void user_data_free(void *data)
|
|
{
|
|
struct user_data *user = data;
|
|
|
|
free(user);
|
|
}
|
|
|
|
#define test_hci(name, data, setup, func, teardown) \
|
|
do { \
|
|
struct user_data *user; \
|
|
user = calloc(1, sizeof(struct user_data)); \
|
|
if (!user) \
|
|
break; \
|
|
user->test_data = data; \
|
|
user->index_ut = 0; \
|
|
user->index_lt = 1; \
|
|
tester_add_full(name, data, \
|
|
test_pre_setup, setup, func, teardown, \
|
|
test_post_teardown, 30, user, user_data_free); \
|
|
} while (0)
|
|
|
|
#define test_hci_local(name, data, setup, func) \
|
|
do { \
|
|
struct user_data *user; \
|
|
user = calloc(1, sizeof(struct user_data)); \
|
|
if (!user) \
|
|
break; \
|
|
user->test_data = data; \
|
|
user->index_ut = 0; \
|
|
user->index_lt = 0xffff; \
|
|
tester_add_full(name, data, \
|
|
test_pre_setup, setup, func, NULL, \
|
|
test_post_teardown, 30, user, user_data_free); \
|
|
} while (0)
|
|
|
|
static void setup_features_complete(const void *data, uint8_t size,
|
|
void *user_data)
|
|
{
|
|
const struct bt_hci_rsp_read_local_features *rsp = data;
|
|
|
|
if (rsp->status) {
|
|
tester_warn("Failed to get HCI features (0x%02x)", rsp->status);
|
|
tester_setup_failed();
|
|
return;
|
|
}
|
|
|
|
tester_setup_complete();
|
|
}
|
|
|
|
static void setup_features(const void *test_data)
|
|
{
|
|
struct user_data *user = tester_get_data();
|
|
|
|
if (!bt_hci_send(user->hci_ut, BT_HCI_CMD_READ_LOCAL_FEATURES, NULL, 0,
|
|
setup_features_complete, NULL, NULL)) {
|
|
tester_warn("Failed to send HCI features command");
|
|
tester_setup_failed();
|
|
return;
|
|
}
|
|
}
|
|
|
|
static void test_reset(const void *test_data)
|
|
{
|
|
tester_test_passed();
|
|
}
|
|
|
|
static void test_command_complete(const void *data, uint8_t size,
|
|
void *user_data)
|
|
{
|
|
uint8_t status = *((uint8_t *) data);
|
|
|
|
if (status) {
|
|
tester_warn("HCI command failed (0x%02x)", status);
|
|
tester_test_failed();
|
|
return;
|
|
}
|
|
|
|
tester_test_passed();
|
|
}
|
|
|
|
static void test_command(uint16_t opcode)
|
|
{
|
|
struct user_data *user = tester_get_data();
|
|
|
|
if (!bt_hci_send(user->hci_ut, opcode, NULL, 0,
|
|
test_command_complete, NULL, NULL)) {
|
|
tester_warn("Failed to send HCI command 0x%04x", opcode);
|
|
tester_test_failed();
|
|
return;
|
|
}
|
|
}
|
|
|
|
static void test_read_local_version_information(const void *test_data)
|
|
{
|
|
test_command(BT_HCI_CMD_READ_LOCAL_VERSION);
|
|
}
|
|
|
|
static void test_read_local_supported_commands(const void *test_data)
|
|
{
|
|
test_command(BT_HCI_CMD_READ_LOCAL_COMMANDS);
|
|
}
|
|
|
|
static void test_read_local_supported_features(const void *test_data)
|
|
{
|
|
test_command(BT_HCI_CMD_READ_LOCAL_FEATURES);
|
|
}
|
|
|
|
static void test_local_extended_features_complete(const void *data,
|
|
uint8_t size, void *user_data)
|
|
{
|
|
const struct bt_hci_rsp_read_local_ext_features *rsp = data;
|
|
|
|
if (rsp->status) {
|
|
tester_warn("Failed to get HCI extended features (0x%02x)",
|
|
rsp->status);
|
|
tester_test_failed();
|
|
return;
|
|
}
|
|
|
|
tester_test_passed();
|
|
}
|
|
|
|
static void test_read_local_extended_features(const void *test_data)
|
|
{
|
|
struct user_data *user = tester_get_data();
|
|
struct bt_hci_cmd_read_local_ext_features cmd;
|
|
|
|
cmd.page = 0x00;
|
|
|
|
if (!bt_hci_send(user->hci_ut, BT_HCI_CMD_READ_LOCAL_EXT_FEATURES,
|
|
&cmd, sizeof(cmd),
|
|
test_local_extended_features_complete,
|
|
NULL, NULL)) {
|
|
tester_warn("Failed to send HCI extended features command");
|
|
tester_test_failed();
|
|
return;
|
|
}
|
|
}
|
|
|
|
static void test_read_buffer_size(const void *test_data)
|
|
{
|
|
test_command(BT_HCI_CMD_READ_BUFFER_SIZE);
|
|
}
|
|
|
|
static void test_read_country_code(const void *test_data)
|
|
{
|
|
test_command(BT_HCI_CMD_READ_COUNTRY_CODE);
|
|
}
|
|
|
|
static void test_read_bd_addr(const void *test_data)
|
|
{
|
|
test_command(BT_HCI_CMD_READ_BD_ADDR);
|
|
}
|
|
|
|
static void test_read_local_supported_codecs(const void *test_data)
|
|
{
|
|
test_command(BT_HCI_CMD_READ_LOCAL_CODECS);
|
|
}
|
|
|
|
static void test_le_read_white_list_size(const void *test_data)
|
|
{
|
|
test_command(BT_HCI_CMD_LE_READ_WHITE_LIST_SIZE);
|
|
}
|
|
|
|
static void test_le_clear_white_list(const void *test_data)
|
|
{
|
|
test_command(BT_HCI_CMD_LE_CLEAR_WHITE_LIST);
|
|
}
|
|
|
|
static void test_le_encrypt_complete(const void *data, uint8_t size,
|
|
void *user_data)
|
|
{
|
|
const struct bt_hci_rsp_le_encrypt *rsp = data;
|
|
uint8_t sample[16] = {
|
|
0x7d, 0xf7, 0x6b, 0x0c, 0x1a, 0xb8, 0x99, 0xb3,
|
|
0x3e, 0x42, 0xf0, 0x47, 0xb9, 0x1b, 0x54, 0x6f
|
|
};
|
|
uint8_t enc_data[16];
|
|
|
|
if (rsp->status) {
|
|
tester_warn("Failed HCI LE Encrypt (0x%02x)", rsp->status);
|
|
tester_test_failed();
|
|
return;
|
|
}
|
|
|
|
swap_buf(rsp->data, enc_data, 16);
|
|
util_hexdump('>', enc_data, 16, test_debug, NULL);
|
|
|
|
if (!memcmp(sample, enc_data, 16))
|
|
tester_test_passed();
|
|
else
|
|
tester_test_failed();
|
|
}
|
|
|
|
/* Data are taken from RFC 4493 Test Vectors */
|
|
static void test_le_encrypt(const void *test_data)
|
|
{
|
|
struct user_data *user = tester_get_data();
|
|
struct bt_hci_cmd_le_encrypt cmd;
|
|
uint8_t key[16] = {
|
|
0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
|
|
0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c
|
|
};
|
|
uint8_t plaintext[16] = { 0 };
|
|
|
|
/* Swap bytes since our interface has LE interface, opposed to
|
|
* common crypto interface
|
|
*/
|
|
swap_buf(key, cmd.key, 16);
|
|
swap_buf(plaintext, cmd.plaintext, 16);
|
|
|
|
util_hexdump('<', cmd.key, 16, test_debug, NULL);
|
|
util_hexdump('<', cmd.plaintext, 16, test_debug, NULL);
|
|
|
|
if (!bt_hci_send(user->hci_ut, BT_HCI_CMD_LE_ENCRYPT, &cmd, sizeof(cmd),
|
|
test_le_encrypt_complete, NULL, NULL)) {
|
|
tester_warn("Failed to send HCI LE Encrypt command");
|
|
tester_test_failed();
|
|
return;
|
|
}
|
|
|
|
}
|
|
|
|
static void test_le_rand(const void *test_data)
|
|
{
|
|
test_command(BT_HCI_CMD_LE_RAND);
|
|
}
|
|
|
|
static void test_le_read_local_pk_complete(const void *data, uint8_t size,
|
|
void *user_data)
|
|
{
|
|
const uint8_t *event = data;
|
|
const struct bt_hci_evt_le_read_local_pk256_complete *evt;
|
|
struct le_keys *keys = user_data;
|
|
|
|
if (*event != BT_HCI_EVT_LE_READ_LOCAL_PK256_COMPLETE) {
|
|
tester_warn("Failed Read Local PK256 command");
|
|
tester_test_failed();
|
|
return;
|
|
}
|
|
|
|
evt = (void *)(event + 1);
|
|
if (evt->status) {
|
|
tester_warn("HCI Read Local PK complete failed (0x%02x)",
|
|
evt->status);
|
|
tester_test_failed();
|
|
return;
|
|
}
|
|
|
|
memcpy(keys->local_pk, evt->local_pk256, 64);
|
|
|
|
util_hexdump('>', evt->local_pk256, 64, test_debug, NULL);
|
|
|
|
tester_test_passed();
|
|
}
|
|
|
|
static void test_le_read_local_pk_status(const void *data, uint8_t size,
|
|
void *user_data)
|
|
{
|
|
uint8_t status = *((uint8_t *) data);
|
|
|
|
if (status) {
|
|
tester_warn("Failed to send Read Local PK256 cmd (0x%02x)", status);
|
|
tester_test_failed();
|
|
return;
|
|
}
|
|
}
|
|
|
|
static void test_le_read_local_pk(const void *test_data)
|
|
{
|
|
struct user_data *user = tester_get_data();
|
|
struct bt_hci_cmd_set_event_mask sem;
|
|
struct bt_hci_cmd_le_set_event_mask lsem;
|
|
|
|
bt_hci_register(user->hci_ut, BT_HCI_EVT_LE_META_EVENT,
|
|
test_le_read_local_pk_complete,
|
|
(void *)test_data, NULL);
|
|
|
|
memset(sem.mask, 0, 8);
|
|
sem.mask[1] |= 0x20; /* Command Complete */
|
|
sem.mask[1] |= 0x40; /* Command Status */
|
|
sem.mask[7] |= 0x20; /* LE Meta */
|
|
|
|
bt_hci_send(user->hci_ut, BT_HCI_CMD_SET_EVENT_MASK,
|
|
&sem, sizeof(sem), NULL, NULL, NULL);
|
|
|
|
memset(lsem.mask, 0, 8);
|
|
lsem.mask[0] |= 0x80; /* LE Read Local P-256 Public Key Complete */
|
|
|
|
bt_hci_send(user->hci_ut, BT_HCI_CMD_LE_SET_EVENT_MASK,
|
|
&lsem, sizeof(lsem), NULL, NULL, NULL);
|
|
|
|
if (!bt_hci_send(user->hci_ut, BT_HCI_CMD_LE_READ_LOCAL_PK256, NULL,
|
|
0, test_le_read_local_pk_status,
|
|
NULL, NULL)) {
|
|
tester_warn("Failed to send HCI LE Read Local PK256 command");
|
|
tester_test_failed();
|
|
return;
|
|
}
|
|
}
|
|
|
|
static void setup_le_read_local_pk_complete(const void *data, uint8_t size,
|
|
void *user_data)
|
|
{
|
|
const uint8_t *event = data;
|
|
const struct bt_hci_evt_le_read_local_pk256_complete *evt;
|
|
struct le_keys *keys = user_data;
|
|
|
|
if (*event != BT_HCI_EVT_LE_READ_LOCAL_PK256_COMPLETE) {
|
|
tester_warn("Failed Read Local PK256 command");
|
|
tester_setup_failed();
|
|
return;
|
|
}
|
|
|
|
evt = (void *)(event + 1);
|
|
if (evt->status) {
|
|
tester_warn("HCI Read Local PK complete failed (0x%02x)",
|
|
evt->status);
|
|
tester_setup_failed();
|
|
return;
|
|
}
|
|
|
|
memcpy(keys->local_pk, evt->local_pk256, 64);
|
|
|
|
util_hexdump('>', evt->local_pk256, 64, test_debug, NULL);
|
|
|
|
tester_setup_complete();
|
|
}
|
|
|
|
static void setup_le_read_local_pk_status(const void *data, uint8_t size,
|
|
void *user_data)
|
|
{
|
|
uint8_t status = *((uint8_t *) data);
|
|
|
|
if (status) {
|
|
tester_warn("Failed to send DHKey gen cmd (0x%02x)", status);
|
|
tester_setup_failed();
|
|
return;
|
|
}
|
|
}
|
|
|
|
static void setup_le_generate_dhkey(const void *test_data)
|
|
{
|
|
struct user_data *user = tester_get_data();
|
|
struct bt_hci_cmd_set_event_mask sem;
|
|
struct bt_hci_cmd_le_set_event_mask lsem;
|
|
|
|
bt_hci_register(user->hci_ut, BT_HCI_EVT_LE_META_EVENT,
|
|
setup_le_read_local_pk_complete,
|
|
(void *)test_data, NULL);
|
|
|
|
memset(sem.mask, 0, 8);
|
|
sem.mask[1] |= 0x20; /* Command Complete */
|
|
sem.mask[1] |= 0x40; /* Command Status */
|
|
sem.mask[7] |= 0x20; /* LE Meta */
|
|
|
|
bt_hci_send(user->hci_ut, BT_HCI_CMD_SET_EVENT_MASK,
|
|
&sem, sizeof(sem), NULL, NULL, NULL);
|
|
|
|
memset(lsem.mask, 0, 8);
|
|
lsem.mask[0] |= 0x80; /* LE Read Local P-256 Public Key Complete */
|
|
lsem.mask[1] |= 0x01; /* LE Generate DHKey Complete */
|
|
|
|
bt_hci_send(user->hci_ut, BT_HCI_CMD_LE_SET_EVENT_MASK,
|
|
&lsem, sizeof(lsem), NULL, NULL, NULL);
|
|
|
|
if (!bt_hci_send(user->hci_ut, BT_HCI_CMD_LE_READ_LOCAL_PK256, NULL,
|
|
0, setup_le_read_local_pk_status,
|
|
NULL, NULL)) {
|
|
tester_warn("Failed to send HCI LE Read Local PK256 command");
|
|
tester_setup_failed();
|
|
return;
|
|
}
|
|
}
|
|
|
|
static void test_le_generate_dhkey_complete(const void *data, uint8_t size,
|
|
void *user_data)
|
|
{
|
|
const uint8_t *event = data;
|
|
const struct bt_hci_evt_le_generate_dhkey_complete *evt;
|
|
struct le_keys *keys = user_data;
|
|
uint8_t dhkey[32];
|
|
|
|
if (*event != BT_HCI_EVT_LE_GENERATE_DHKEY_COMPLETE) {
|
|
tester_warn("Failed DHKey generation command");
|
|
tester_test_failed();
|
|
return;
|
|
}
|
|
|
|
evt = (void *)(event + 1);
|
|
if (evt->status) {
|
|
tester_warn("HCI Generate DHKey complete failed (0x%02x)",
|
|
evt->status);
|
|
tester_test_failed();
|
|
return;
|
|
}
|
|
|
|
util_hexdump('>', evt->dhkey, 32, test_debug, NULL);
|
|
|
|
|
|
util_hexdump('S', keys->remote_sk, 32, test_debug, NULL);
|
|
util_hexdump('P', keys->local_pk, 64, test_debug, NULL);
|
|
|
|
/* Generate DHKey ourself with local public key and remote
|
|
* private key we got when generated public / private key
|
|
* pair for BT_HCI_CMD_LE_GENERATE_DHKEY argument.
|
|
*/
|
|
ecdh_shared_secret(keys->local_pk, keys->remote_sk, dhkey);
|
|
|
|
util_hexdump('D', dhkey, 32, test_debug, NULL);
|
|
|
|
if (!memcmp(dhkey, evt->dhkey, 32))
|
|
tester_test_passed();
|
|
else
|
|
tester_test_failed();
|
|
}
|
|
|
|
static void test_le_generate_dhkey_status(const void *data, uint8_t size,
|
|
void *user_data)
|
|
{
|
|
uint8_t status = *((uint8_t *) data);
|
|
|
|
if (status) {
|
|
tester_warn("Failed to send DHKey gen cmd (0x%02x)", status);
|
|
tester_test_failed();
|
|
return;
|
|
}
|
|
}
|
|
|
|
static void test_le_generate_dhkey(const void *test_data)
|
|
{
|
|
struct user_data *user = tester_get_data();
|
|
struct bt_hci_cmd_le_generate_dhkey cmd;
|
|
struct le_keys *keys = (void *)test_data;
|
|
|
|
ecc_make_key(cmd.remote_pk256, keys->remote_sk);
|
|
|
|
/* Unregister handler for META event */
|
|
bt_hci_unregister(user->hci_ut, 1);
|
|
|
|
bt_hci_register(user->hci_ut, BT_HCI_EVT_LE_META_EVENT,
|
|
test_le_generate_dhkey_complete, keys,
|
|
NULL);
|
|
|
|
if (!bt_hci_send(user->hci_ut, BT_HCI_CMD_LE_GENERATE_DHKEY, &cmd,
|
|
sizeof(cmd), test_le_generate_dhkey_status,
|
|
NULL, NULL)) {
|
|
tester_warn("Failed to send HCI LE Encrypt command");
|
|
tester_test_failed();
|
|
return;
|
|
}
|
|
|
|
}
|
|
|
|
static void test_inquiry_complete(const void *data, uint8_t size,
|
|
void *user_data)
|
|
{
|
|
const struct bt_hci_evt_inquiry_complete *evt = data;
|
|
|
|
if (evt->status) {
|
|
tester_warn("HCI inquiry complete failed (0x%02x)",
|
|
evt->status);
|
|
tester_test_failed();
|
|
return;
|
|
}
|
|
|
|
tester_test_passed();
|
|
}
|
|
|
|
static void test_inquiry_status(const void *data, uint8_t size,
|
|
void *user_data)
|
|
{
|
|
uint8_t status = *((uint8_t *) data);
|
|
|
|
if (status) {
|
|
tester_warn("HCI inquiry command failed (0x%02x)", status);
|
|
tester_test_failed();
|
|
return;
|
|
}
|
|
}
|
|
|
|
static void test_inquiry_liac(const void *test_data)
|
|
{
|
|
struct user_data *user = tester_get_data();
|
|
struct bt_hci_cmd_inquiry cmd;
|
|
|
|
bt_hci_register(user->hci_ut, BT_HCI_EVT_INQUIRY_COMPLETE,
|
|
test_inquiry_complete, NULL, NULL);
|
|
|
|
cmd.lap[0] = 0x00;
|
|
cmd.lap[1] = 0x8b;
|
|
cmd.lap[2] = 0x9e;
|
|
cmd.length = 0x08;
|
|
cmd.num_resp = 0x00;
|
|
|
|
if (!bt_hci_send(user->hci_ut, BT_HCI_CMD_INQUIRY, &cmd, sizeof(cmd),
|
|
test_inquiry_status, NULL, NULL)) {
|
|
tester_warn("Failed to send HCI inquiry command");
|
|
tester_test_failed();
|
|
return;
|
|
}
|
|
}
|
|
|
|
static void setup_lt_connectable_complete(const void *data, uint8_t size,
|
|
void *user_data)
|
|
{
|
|
uint8_t status = *((uint8_t *) data);
|
|
|
|
if (status) {
|
|
tester_warn("Failed to set HCI scan enable (0x%02x)", status);
|
|
tester_setup_failed();
|
|
return;
|
|
}
|
|
|
|
tester_setup_complete();
|
|
}
|
|
|
|
static void setup_lt_connect_request_accept(const void *data, uint8_t size,
|
|
void *user_data)
|
|
{
|
|
struct user_data *user = tester_get_data();
|
|
const struct bt_hci_evt_conn_request *evt = data;
|
|
struct bt_hci_cmd_accept_conn_request cmd;
|
|
|
|
memcpy(cmd.bdaddr, evt->bdaddr, 6);
|
|
cmd.role = 0x01;
|
|
|
|
if (!bt_hci_send(user->hci_lt, BT_HCI_CMD_ACCEPT_CONN_REQUEST,
|
|
&cmd, sizeof(cmd), NULL, NULL, NULL)) {
|
|
tester_warn("Failed to send HCI accept connection command");
|
|
return;
|
|
}
|
|
}
|
|
|
|
static void setup_lt_connectable(const void *test_data)
|
|
{
|
|
struct user_data *user = tester_get_data();
|
|
struct bt_hci_cmd_write_scan_enable cmd;
|
|
|
|
bt_hci_register(user->hci_lt, BT_HCI_EVT_CONN_REQUEST,
|
|
setup_lt_connect_request_accept, NULL, NULL);
|
|
|
|
cmd.enable = 0x02;
|
|
|
|
if (!bt_hci_send(user->hci_lt, BT_HCI_CMD_WRITE_SCAN_ENABLE,
|
|
&cmd, sizeof(cmd),
|
|
setup_lt_connectable_complete, NULL, NULL)) {
|
|
tester_warn("Failed to send HCI scan enable command");
|
|
tester_setup_failed();
|
|
return;
|
|
}
|
|
}
|
|
|
|
static void test_create_connection_disconnect(void *user_data)
|
|
{
|
|
tester_test_passed();
|
|
}
|
|
|
|
static void test_create_connection_complete(const void *data, uint8_t size,
|
|
void *user_data)
|
|
{
|
|
struct user_data *user = tester_get_data();
|
|
const struct bt_hci_evt_conn_complete *evt = data;
|
|
|
|
if (evt->status) {
|
|
tester_warn("HCI create connection complete failed (0x%02x)",
|
|
evt->status);
|
|
tester_test_failed();
|
|
return;
|
|
}
|
|
|
|
user->handle_ut = le16_to_cpu(evt->handle);
|
|
|
|
tester_wait(2, test_create_connection_disconnect, NULL);
|
|
}
|
|
|
|
static void test_create_connection_status(const void *data, uint8_t size,
|
|
void *user_data)
|
|
{
|
|
uint8_t status = *((uint8_t *) data);
|
|
|
|
if (status) {
|
|
tester_warn("HCI create connection command failed (0x%02x)",
|
|
status);
|
|
tester_test_failed();
|
|
return;
|
|
}
|
|
}
|
|
|
|
static void test_create_connection(const void *test_data)
|
|
{
|
|
struct user_data *user = tester_get_data();
|
|
struct bt_hci_cmd_create_conn cmd;
|
|
|
|
bt_hci_register(user->hci_ut, BT_HCI_EVT_CONN_COMPLETE,
|
|
test_create_connection_complete, NULL, NULL);
|
|
|
|
memcpy(cmd.bdaddr, user->bdaddr_lt, 6);
|
|
cmd.pkt_type = cpu_to_le16(0x0008);
|
|
cmd.pscan_rep_mode = 0x02;
|
|
cmd.pscan_mode = 0x00;
|
|
cmd.clock_offset = cpu_to_le16(0x0000);
|
|
cmd.role_switch = 0x01;
|
|
|
|
if (!bt_hci_send(user->hci_ut, BT_HCI_CMD_CREATE_CONN,
|
|
&cmd, sizeof(cmd),
|
|
test_create_connection_status,
|
|
NULL, NULL)) {
|
|
tester_warn("Failed to send HCI create connection command");
|
|
tester_test_failed();
|
|
return;
|
|
}
|
|
}
|
|
|
|
static void teardown_timeout(void *user_data)
|
|
{
|
|
tester_teardown_complete();
|
|
}
|
|
|
|
static void teardown_disconnect_status(const void *data, uint8_t size,
|
|
void *user_data)
|
|
{
|
|
uint8_t status = *((uint8_t *) data);
|
|
|
|
if (status) {
|
|
tester_warn("HCI disconnect failed (0x%02x)", status);
|
|
tester_teardown_failed();
|
|
return;
|
|
}
|
|
|
|
tester_wait(1, teardown_timeout, NULL);
|
|
}
|
|
|
|
static void teardown_connection(const void *test_data)
|
|
{
|
|
struct user_data *user = tester_get_data();
|
|
struct bt_hci_cmd_disconnect cmd;
|
|
|
|
cmd.handle = cpu_to_le16(user->handle_ut);
|
|
cmd.reason = 0x13;
|
|
|
|
if (!bt_hci_send(user->hci_ut, BT_HCI_CMD_DISCONNECT,
|
|
&cmd, sizeof(cmd),
|
|
teardown_disconnect_status,
|
|
NULL, NULL)) {
|
|
tester_warn("Failed to send HCI disconnect command");
|
|
tester_test_failed();
|
|
return;
|
|
}
|
|
}
|
|
|
|
static void test_adv_report(const void *data, uint8_t size, void *user_data)
|
|
{
|
|
struct user_data *user = tester_get_data();
|
|
uint8_t subevent = *((uint8_t *) data);
|
|
const struct bt_hci_evt_le_adv_report *lar = data + 1;
|
|
|
|
switch (subevent) {
|
|
case BT_HCI_EVT_LE_ADV_REPORT:
|
|
if (!memcmp(lar->addr, user->bdaddr_ut, 6))
|
|
tester_setup_complete();
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void setup_advertising_initiated(const void *test_data)
|
|
{
|
|
struct user_data *user = tester_get_data();
|
|
struct bt_hci_cmd_set_event_mask sem;
|
|
struct bt_hci_cmd_le_set_event_mask lsem;
|
|
struct bt_hci_cmd_le_set_scan_enable lsse;
|
|
struct bt_hci_cmd_le_set_adv_parameters lsap;
|
|
struct bt_hci_cmd_le_set_adv_enable lsae;
|
|
|
|
bt_hci_register(user->hci_lt, BT_HCI_EVT_LE_META_EVENT,
|
|
test_adv_report, NULL, NULL);
|
|
|
|
memset(sem.mask, 0, 8);
|
|
sem.mask[1] |= 0x20; /* Command Complete */
|
|
sem.mask[1] |= 0x40; /* Command Status */
|
|
sem.mask[7] |= 0x20; /* LE Meta */
|
|
|
|
bt_hci_send(user->hci_lt, BT_HCI_CMD_SET_EVENT_MASK,
|
|
&sem, sizeof(sem), NULL, NULL, NULL);
|
|
|
|
memset(lsem.mask, 0, 8);
|
|
lsem.mask[0] |= 0x02; /* LE Advertising Report */
|
|
|
|
bt_hci_send(user->hci_lt, BT_HCI_CMD_LE_SET_EVENT_MASK,
|
|
&lsem, sizeof(lsem), NULL, NULL, NULL);
|
|
|
|
lsse.enable = 0x01;
|
|
lsse.filter_dup = 0x00;
|
|
|
|
bt_hci_send(user->hci_lt, BT_HCI_CMD_LE_SET_SCAN_ENABLE,
|
|
&lsse, sizeof(lsse), NULL, NULL, NULL);
|
|
|
|
lsap.min_interval = cpu_to_le16(0x0800);
|
|
lsap.max_interval = cpu_to_le16(0x0800);
|
|
lsap.type = 0x03;
|
|
lsap.own_addr_type = 0x00;
|
|
lsap.direct_addr_type = 0x00;
|
|
memset(lsap.direct_addr, 0, 6);
|
|
lsap.channel_map = 0x07;
|
|
lsap.filter_policy = 0x00;
|
|
|
|
bt_hci_send(user->hci_ut, BT_HCI_CMD_LE_SET_ADV_PARAMETERS,
|
|
&lsap, sizeof(lsap), NULL, NULL, NULL);
|
|
|
|
lsae.enable = 0x01;
|
|
|
|
bt_hci_send(user->hci_ut, BT_HCI_CMD_LE_SET_ADV_ENABLE,
|
|
&lsae, sizeof(lsae), NULL, NULL, NULL);
|
|
}
|
|
|
|
static void test_reset_in_advertising_state_timeout(void *user_data)
|
|
{
|
|
struct user_data *user = tester_get_data();
|
|
struct bt_hci_cmd_le_set_adv_enable lsae;
|
|
struct bt_hci_cmd_le_set_scan_enable lsse;
|
|
|
|
lsae.enable = 0x00;
|
|
|
|
bt_hci_send(user->hci_ut, BT_HCI_CMD_LE_SET_ADV_ENABLE,
|
|
&lsae, sizeof(lsae), NULL, NULL, NULL);
|
|
|
|
lsse.enable = 0x00;
|
|
lsse.filter_dup = 0x00;
|
|
|
|
bt_hci_send(user->hci_lt, BT_HCI_CMD_LE_SET_SCAN_ENABLE,
|
|
&lsse, sizeof(lsse), NULL, NULL, NULL);
|
|
|
|
tester_test_passed();
|
|
}
|
|
|
|
static void test_reset_in_advertising_state(const void *test_data)
|
|
{
|
|
struct user_data *user = tester_get_data();
|
|
|
|
bt_hci_send(user->hci_ut, BT_HCI_CMD_RESET, NULL, 0, NULL, NULL, NULL);
|
|
|
|
tester_wait(5, test_reset_in_advertising_state_timeout, NULL);
|
|
}
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
tester_init(&argc, &argv);
|
|
|
|
test_hci_local("Reset", NULL, NULL, test_reset);
|
|
|
|
test_hci_local("Read Local Version Information", NULL, NULL,
|
|
test_read_local_version_information);
|
|
test_hci_local("Read Local Supported Commands", NULL, NULL,
|
|
test_read_local_supported_commands);
|
|
test_hci_local("Read Local Supported Features", NULL, NULL,
|
|
test_read_local_supported_features);
|
|
test_hci_local("Read Local Extended Features", NULL,
|
|
setup_features,
|
|
test_read_local_extended_features);
|
|
test_hci_local("Read Buffer Size", NULL, NULL,
|
|
test_read_buffer_size);
|
|
test_hci_local("Read Country Code", NULL, NULL,
|
|
test_read_country_code);
|
|
test_hci_local("Read BD_ADDR", NULL, NULL,
|
|
test_read_bd_addr);
|
|
test_hci_local("Read Local Supported Codecs", NULL, NULL,
|
|
test_read_local_supported_codecs);
|
|
|
|
test_hci_local("LE Read White List Size", NULL, NULL,
|
|
test_le_read_white_list_size);
|
|
test_hci_local("LE Clear White List", NULL, NULL,
|
|
test_le_clear_white_list);
|
|
test_hci_local("LE Encrypt", NULL, NULL,
|
|
test_le_encrypt);
|
|
test_hci_local("LE Rand", NULL, NULL,
|
|
test_le_rand);
|
|
test_hci_local("LE Read Local PK", &key_test_data, NULL,
|
|
test_le_read_local_pk);
|
|
test_hci_local("LE Generate DHKey", &key_test_data,
|
|
setup_le_generate_dhkey,
|
|
test_le_generate_dhkey);
|
|
|
|
test_hci_local("Inquiry (LIAC)", NULL, NULL, test_inquiry_liac);
|
|
|
|
test_hci("Create Connection", NULL,
|
|
setup_lt_connectable,
|
|
test_create_connection,
|
|
teardown_connection);
|
|
|
|
test_hci("TP/DSU/BV-02-C Reset in Advertising State", NULL,
|
|
setup_advertising_initiated,
|
|
test_reset_in_advertising_state, NULL);
|
|
|
|
return tester_run();
|
|
}
|