blob: c245c213197799359431f01e67be8657b5e8ddb9 [file] [log] [blame]
/*
* Copyright (c) 2023 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include <zephyr/kernel.h>
#include <zephyr/sys/printk.h>
#include <zephyr/bluetooth/conn.h>
#include <zephyr/bluetooth/bluetooth.h>
#include <zephyr/logging/log.h>
LOG_MODULE_DECLARE(bt_bsim_privacy, LOG_LEVEL_INF);
#include "bs_types.h"
#include "bs_tracing.h"
#include "bstests.h"
#include "bs_cmd_line.h"
#define CREATE_FLAG(flag) static atomic_t flag = (atomic_t) false
#define SET_FLAG(flag) (void)atomic_set(&flag, (atomic_t) true)
#define GET_FLAG(flag) (bool)atomic_get(&flag)
#define UNSET_FLAG(flag) (void)atomic_set(&flag, (atomic_t) false)
#define WAIT_FOR_FLAG(flag) \
while (!(bool)atomic_get(&flag)) { \
(void)k_sleep(K_MSEC(1)); \
}
#define FAIL(...) \
do { \
bst_result = Failed; \
bs_trace_error_time_line(__VA_ARGS__); \
} while (0)
#define PASS(...) \
do { \
bst_result = Passed; \
bs_trace_info_time(1, __VA_ARGS__); \
} while (0)
extern enum bst_result_t bst_result;
CREATE_FLAG(paired);
CREATE_FLAG(rpa_tested);
CREATE_FLAG(identity_tested);
static void start_scan(void);
static struct bt_conn *default_conn;
static bt_addr_le_t peer_rpa;
static bt_addr_le_t peer_identity;
enum addr_type_t {
RPA,
IDENTITY_ADDR,
};
static enum addr_type_t test_addr_type;
static bool use_active_scan;
static bool connection_test;
static int sim_id;
void central_test_args_parse(int argc, char *argv[])
{
char *addr_type_arg = NULL;
bs_args_struct_t args_struct[] = {
{
.dest = &sim_id,
.type = 'i',
.name = "{positive integer}",
.option = "sim-id",
.descript = "Simulation ID counter",
},
{
.dest = &addr_type_arg,
.type = 's',
.name = "{identity, rpa}",
.option = "addr-type",
.descript = "Address type to test",
},
{
.dest = &use_active_scan,
.type = 'b',
.name = "{0, 1}",
.option = "active-scan",
.descript = "",
},
{
.dest = &connection_test,
.type = 'b',
.name = "{0, 1}",
.option = "connection-test",
.descript = "",
},
};
bs_args_parse_all_cmd_line(argc, argv, args_struct);
if (addr_type_arg != NULL) {
if (!strcmp(addr_type_arg, "identity")) {
test_addr_type = IDENTITY_ADDR;
} else if (!strcmp(addr_type_arg, "rpa")) {
test_addr_type = RPA;
}
}
}
static void wait_check_result(void)
{
if (test_addr_type == IDENTITY_ADDR) {
WAIT_FOR_FLAG(identity_tested);
LOG_INF("Identity address tested");
} else if (test_addr_type == RPA) {
WAIT_FOR_FLAG(rpa_tested);
LOG_INF("Resolvable Private Address tested");
}
}
static void check_addresses(const bt_addr_le_t *peer_addr)
{
LOG_DBG("Check addresses");
bool addr_equal;
if (test_addr_type == IDENTITY_ADDR) {
SET_FLAG(identity_tested);
addr_equal = bt_addr_le_eq(&peer_identity, peer_addr);
if (!addr_equal) {
FAIL("The peer address is not the same as the peer previously paired.\n");
}
} else if (test_addr_type == RPA) {
SET_FLAG(rpa_tested);
addr_equal = bt_addr_le_eq(&peer_identity, peer_addr);
if (!addr_equal) {
FAIL("The resolved address is not the same as the peer previously "
"paired.\n");
}
}
}
static void scan_recv(const struct bt_le_scan_recv_info *info,
struct net_buf_simple *ad)
{
char addr_str[BT_ADDR_LE_STR_LEN];
int err;
if (default_conn) {
return;
}
bt_addr_le_to_str(info->addr, addr_str, sizeof(addr_str));
LOG_INF("Device found: %s (RSSI %d)", addr_str, info->rssi);
/* In the case of extended advertising and active scanning, this
* callback will be called twice: once for the AUX_ADV_IND and
* another time for the AUX_SCAN_RSP.
*
* We have to be careful not to stop the scanner before we have gotten
* the second one, as the peripheral side waits until it gets an
* AUX_SCAN_REQ to end the test.
*
* There is a catch though, since we have to bond, in order to exchange
* the address resolving keys, then this check should only apply after
* the pairing is done.
*/
if (GET_FLAG(paired) &&
info->adv_props == (BT_GAP_ADV_PROP_EXT_ADV | BT_GAP_ADV_PROP_SCANNABLE)) {
LOG_DBG("skipping AUX_ADV_IND report, waiting for AUX_SCAN_REQ "
"(props: 0x%x)", info->adv_props);
return;
}
if (GET_FLAG(paired)) {
check_addresses(info->addr);
}
if (connection_test || !GET_FLAG(paired)) {
if (bt_le_scan_stop()) {
LOG_DBG("Failed to stop scanner");
return;
}
LOG_DBG("Scanner stopped: conn %d paired %d", connection_test, GET_FLAG(paired));
err = bt_conn_le_create(info->addr,
BT_CONN_LE_CREATE_CONN,
BT_LE_CONN_PARAM_DEFAULT,
&default_conn);
if (err) {
LOG_DBG("Create conn to %s failed (%u)", addr_str, err);
start_scan();
}
}
}
static struct bt_le_scan_cb scan_cb = {
.recv = scan_recv,
};
static void start_scan(void)
{
int err;
LOG_DBG("Using %s scan", use_active_scan ? "active" : "passive");
err = bt_le_scan_start(use_active_scan ? BT_LE_SCAN_ACTIVE : BT_LE_SCAN_PASSIVE,
NULL);
if (err) {
FAIL("Scanning failed to start (err %d)\n", err);
}
LOG_DBG("Scanning successfully started");
}
static void connected(struct bt_conn *conn, uint8_t err)
{
char addr[BT_ADDR_LE_STR_LEN];
bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
LOG_DBG("Connected: %s", addr);
}
static void disconnected(struct bt_conn *conn, uint8_t reason)
{
char addr[BT_ADDR_LE_STR_LEN];
if (conn != default_conn) {
return;
}
bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
LOG_DBG("Disconnected: %s (reason 0x%02x)", addr, reason);
bt_conn_unref(default_conn);
default_conn = NULL;
start_scan();
}
static void identity_resolved(struct bt_conn *conn, const bt_addr_le_t *rpa,
const bt_addr_le_t *identity)
{
char addr_identity[BT_ADDR_LE_STR_LEN];
char addr_rpa[BT_ADDR_LE_STR_LEN];
bt_addr_le_to_str(identity, addr_identity, sizeof(addr_identity));
bt_addr_le_to_str(rpa, addr_rpa, sizeof(addr_rpa));
LOG_DBG("Identity resolved %s -> %s", addr_rpa, addr_identity);
bt_addr_le_copy(&peer_rpa, rpa);
bt_addr_le_copy(&peer_identity, identity);
SET_FLAG(paired);
}
static struct bt_conn_cb central_cb;
void test_central(void)
{
int err;
LOG_DBG("Central device");
central_cb.connected = connected;
central_cb.disconnected = disconnected;
central_cb.identity_resolved = identity_resolved;
bt_conn_cb_register(&central_cb);
bt_le_scan_cb_register(&scan_cb);
err = bt_enable(NULL);
if (err) {
FAIL("Bluetooth init failed (err %d)\n", err);
}
UNSET_FLAG(identity_tested);
UNSET_FLAG(rpa_tested);
start_scan();
wait_check_result();
}
void test_central_main(void)
{
char *addr_tested = "";
if (test_addr_type == RPA) {
addr_tested = "RPA";
} else if (test_addr_type == IDENTITY_ADDR) {
addr_tested = "identity address";
}
LOG_INF("Central test START (id: %d: params: %s scan, %sconnectable test, testing %s)\n",
sim_id, use_active_scan ? "active" : "passive", connection_test ? "" : "non-",
addr_tested);
test_central();
PASS("passed\n");
}